void ConnectionManagerUtility::mutateXfccRequestHeader()

in source/common/http/conn_manager_utility.cc [256:331]


void ConnectionManagerUtility::mutateXfccRequestHeader(HeaderMap& request_headers,
                                                       Network::Connection& connection,
                                                       ConnectionManagerConfig& config) {
  // When AlwaysForwardOnly is set, always forward the XFCC header without modification.
  if (config.forwardClientCert() == ForwardClientCertType::AlwaysForwardOnly) {
    return;
  }
  // When Sanitize is set, or the connection is not mutual TLS, remove the XFCC header.
  if (config.forwardClientCert() == ForwardClientCertType::Sanitize ||
      !(connection.ssl() && connection.ssl()->peerCertificatePresented())) {
    request_headers.removeForwardedClientCert();
    return;
  }

  // When ForwardOnly is set, always forward the XFCC header without modification.
  if (config.forwardClientCert() == ForwardClientCertType::ForwardOnly) {
    return;
  }

  // TODO(myidpt): Handle the special characters in By and URI fields.
  // TODO: Optimize client_cert_details based on perf analysis (direct string appending may be more
  // preferable).
  std::vector<std::string> client_cert_details;
  // When AppendForward or SanitizeSet is set, the client certificate information should be set into
  // the XFCC header.
  if (config.forwardClientCert() == ForwardClientCertType::AppendForward ||
      config.forwardClientCert() == ForwardClientCertType::SanitizeSet) {
    const std::string uri_san_local_cert = connection.ssl()->uriSanLocalCertificate();
    if (!uri_san_local_cert.empty()) {
      client_cert_details.push_back("By=" + uri_san_local_cert);
    }
    const std::string cert_digest = connection.ssl()->sha256PeerCertificateDigest();
    if (!cert_digest.empty()) {
      client_cert_details.push_back("Hash=" + cert_digest);
    }
    for (const auto& detail : config.setCurrentClientCertDetails()) {
      switch (detail) {
      case ClientCertDetailsType::Cert: {
        const std::string peer_cert = connection.ssl()->urlEncodedPemEncodedPeerCertificate();
        if (!peer_cert.empty()) {
          client_cert_details.push_back("Cert=\"" + peer_cert + "\"");
        }
        break;
      }
      case ClientCertDetailsType::Subject:
        // The "Subject" key still exists even if the subject is empty.
        client_cert_details.push_back("Subject=\"" + connection.ssl()->subjectPeerCertificate() +
                                      "\"");
        break;
      case ClientCertDetailsType::URI:
        // The "URI" key still exists even if the URI is empty.
        client_cert_details.push_back("URI=" + connection.ssl()->uriSanPeerCertificate());
        break;
      case ClientCertDetailsType::DNS: {
        const std::vector<std::string> dns_sans = connection.ssl()->dnsSansPeerCertificate();
        if (!dns_sans.empty()) {
          for (const std::string& dns : dns_sans) {
            client_cert_details.push_back("DNS=" + dns);
          }
        }
        break;
      }
      }
    }
  }

  const std::string client_cert_details_str = absl::StrJoin(client_cert_details, ";");
  if (config.forwardClientCert() == ForwardClientCertType::AppendForward) {
    HeaderMapImpl::appendToHeader(request_headers.insertForwardedClientCert().value(),
                                  client_cert_details_str);
  } else if (config.forwardClientCert() == ForwardClientCertType::SanitizeSet) {
    request_headers.insertForwardedClientCert().value(client_cert_details_str);
  } else {
    NOT_REACHED_GCOVR_EXCL_LINE;
  }
}