diff --git a/api/envoy/data/accesslog/v2/accesslog.proto b/api/envoy/data/accesslog/v2/accesslog.proto index 985758bbf9b0d..b387433394e55 100644 --- a/api/envoy/data/accesslog/v2/accesslog.proto +++ b/api/envoy/data/accesslog/v2/accesslog.proto @@ -69,7 +69,6 @@ message AccessLogCommon { // This field is the local/destination address on which the request from the user was received. envoy.api.v2.core.Address downstream_local_address = 3; - // [#not-implemented-hide:] // If the connection is secure,S this field will contain TLS properties. TLSProperties tls_properties = 4; @@ -210,9 +209,9 @@ message ResponseFlags { bool stream_idle_timeout = 17; } -// [#not-implemented-hide:] // Properties of a negotiated TLS connection. message TLSProperties { + // [#not-implemented-hide:] enum TLSVersion { VERSION_UNSPECIFIED = 0; TLSv1 = 1; @@ -220,9 +219,11 @@ message TLSProperties { TLSv1_2 = 3; TLSv1_3 = 4; } + // [#not-implemented-hide:] // Version of TLS that was negotiated. TLSVersion tls_version = 1; + // [#not-implemented-hide:] // TLS cipher suite negotiated during handshake. The value is a // four-digit hex code defined by the IANA TLS Cipher Suite Registry // (e.g. ``009C`` for ``TLS_RSA_WITH_AES_128_GCM_SHA256``). @@ -232,6 +233,28 @@ message TLSProperties { // SNI hostname from handshake. string tls_sni_hostname = 3; + + message CertificateProperties { + message SubjectAltName { + oneof san { + string uri = 1; + // [#not-implemented-hide:] + string dns = 2; + } + } + + // SANs present in the certificate. + repeated SubjectAltName subject_alt_name = 1; + + // The subject field of the certificate. + string subject = 2; + } + + // Properties of the local certificate used to negotiate TLS. + CertificateProperties local_certificate_properties = 4; + + // Properties of the peer certificate used to negotiate TLS. + CertificateProperties peer_certificate_properties = 5; } message HTTPRequestProperties { diff --git a/docs/root/configuration/access_log.rst b/docs/root/configuration/access_log.rst index 705ea7cb730e5..bfc28c108fde2 100644 --- a/docs/root/configuration/access_log.rst +++ b/docs/root/configuration/access_log.rst @@ -323,3 +323,28 @@ The following command operators are supported: TCP String value set on ssl connection socket for Server Name Indication (SNI) +%DOWNSTREAM_LOCAL_URI_SAN% + HTTP + The URIs present in the SAN of the local certificate used to establish the downstream TLS connection. + TCP + The URIs present in the SAN of the local certificate used to establish the downstream TLS connection. + +%DOWNSTREAM_PEER_URI_SAN% + HTTP + The URIs present in the SAN of the peer certificate used to establish the downstream TLS connection. + TCP + The URIs present in the SAN of the peer certificate used to establish the downstream TLS connection. + +%DOWNSTREAM_LOCAL_SUBJECT% + HTTP + The subject present in the local certificate used to establish the downstream TLS connection. + TCP + The subject present in the local certificate used to establish the downstream TLS connection. + +%DOWNSTREAM_PEER_SUBJECT% + HTTP + The subject present in the peer certificate used to establish the downstream TLS connection. + TCP + The subject present in the peer certificate used to establish the downstream TLS connection. + + diff --git a/docs/root/intro/version_history.rst b/docs/root/intro/version_history.rst index d8100ac00adc7..a8e0813cd129c 100644 --- a/docs/root/intro/version_history.rst +++ b/docs/root/intro/version_history.rst @@ -8,6 +8,7 @@ Version history * access log: added a new flag for stream idle timeout. * access log: added a new field for upstream transport failure reason in :ref:`file access logger` and :ref:`gRPC access logger` for HTTP access logs. +* access log: added new fields for downstream x509 information (URI sans and subject) to file and gRPC access logger. * admin: the admin server can now be accessed via HTTP/2 (prior knowledge). * buffer: fix vulnerabilities when allocation fails. * build: releases are built with GCC-7 and linked with LLD. diff --git a/include/envoy/network/connection.h b/include/envoy/network/connection.h index 59ce14bbe71e9..28420a3d5f4a3 100644 --- a/include/envoy/network/connection.h +++ b/include/envoy/network/connection.h @@ -184,7 +184,8 @@ class Connection : public Event::DeferredDeletable, public FilterManager { /** * @return the const SSL connection data if this is an SSL connection, or nullptr if it is not. */ - virtual const Ssl::Connection* ssl() const PURE; + // TODO(snowp): Remove this in favor of StreamInfo::downstreamSslConnection. + virtual const Ssl::ConnectionInfo* ssl() const PURE; /** * @return requested server name (e.g. SNI in TLS), if any. diff --git a/include/envoy/network/transport_socket.h b/include/envoy/network/transport_socket.h index 3ac988d9e00e3..5d8430126949b 100644 --- a/include/envoy/network/transport_socket.h +++ b/include/envoy/network/transport_socket.h @@ -144,7 +144,7 @@ class TransportSocket { /** * @return the const SSL connection data if this is an SSL connection, or nullptr if it is not. */ - virtual const Ssl::Connection* ssl() const PURE; + virtual const Ssl::ConnectionInfo* ssl() const PURE; }; typedef std::unique_ptr TransportSocketPtr; diff --git a/include/envoy/ssl/connection.h b/include/envoy/ssl/connection.h index 3453079466c8c..fb598f560aa12 100644 --- a/include/envoy/ssl/connection.h +++ b/include/envoy/ssl/connection.h @@ -14,9 +14,9 @@ namespace Ssl { /** * Base connection interface for all SSL connections. */ -class Connection { +class ConnectionInfo { public: - virtual ~Connection() {} + virtual ~ConnectionInfo() {} /** * @return bool whether the peer certificate is presented. @@ -24,10 +24,10 @@ class Connection { virtual bool peerCertificatePresented() const PURE; /** - * @return std::string the URI in the SAN field of the local certificate. Returns "" if there is + * @return std::string the URIs in the SAN field of the local certificate. Returns {} if there is * no local certificate, or no SAN field, or no URI. **/ - virtual std::string uriSanLocalCertificate() const PURE; + virtual std::vector uriSanLocalCertificate() const PURE; /** * @return std::string the subject field of the local certificate in RFC 2253 format. Returns "" @@ -54,10 +54,10 @@ class Connection { virtual std::string subjectPeerCertificate() const PURE; /** - * @return std::string the URI in the SAN field of the peer certificate. Returns "" if there is no - * peer certificate, or no SAN field, or no URI. + * @return std::string the URIs in the SAN field of the peer certificate. Returns {} if there is + *no peer certificate, or no SAN field, or no URI. **/ - virtual std::string uriSanPeerCertificate() const PURE; + virtual std::vector uriSanPeerCertificate() const PURE; /** * @return std::string the URL-encoded PEM-encoded representation of the peer certificate. Returns diff --git a/include/envoy/stream_info/BUILD b/include/envoy/stream_info/BUILD index 216d5f80dd5f0..defe80c196a95 100644 --- a/include/envoy/stream_info/BUILD +++ b/include/envoy/stream_info/BUILD @@ -16,6 +16,7 @@ envoy_cc_library( ":filter_state_interface", "//include/envoy/common:time_interface", "//include/envoy/http:protocol_interface", + "//include/envoy/ssl:connection_interface", "//include/envoy/upstream:host_description_interface", "//source/common/common:assert_lib", "//source/common/protobuf", diff --git a/include/envoy/stream_info/stream_info.h b/include/envoy/stream_info/stream_info.h index d37758c18268c..e30218e317554 100644 --- a/include/envoy/stream_info/stream_info.h +++ b/include/envoy/stream_info/stream_info.h @@ -8,6 +8,7 @@ #include "envoy/common/pure.h" #include "envoy/common/time.h" #include "envoy/http/protocol.h" +#include "envoy/ssl/connection.h" #include "envoy/stream_info/filter_state.h" #include "envoy/upstream/host_description.h" @@ -326,6 +327,17 @@ class StreamInfo { */ virtual const Network::Address::InstanceConstSharedPtr& downstreamRemoteAddress() const PURE; + /** + * @param connection_info sets the downstream ssl connection. + */ + virtual void setDownstreamSslConnection(const Ssl::ConnectionInfo* ssl_connection_info) PURE; + + /** + * @return the downstream SSL connection. This will be nullptr if the downstream + * connection does not use SSL. + */ + virtual const Ssl::ConnectionInfo* downstreamSslConnection() const PURE; + /** * @return const Router::RouteEntry* Get the route entry selected for this request. Note: this * will be nullptr if no route was selected. diff --git a/source/common/access_log/access_log_formatter.cc b/source/common/access_log/access_log_formatter.cc index 512e867243eb3..15a9bdb825b99 100644 --- a/source/common/access_log/access_log_formatter.cc +++ b/source/common/access_log/access_log_formatter.cc @@ -21,6 +21,27 @@ namespace AccessLog { static const std::string UnspecifiedValueString = "-"; +namespace { + +// Helper that handles the case when the ConnectionInfo is missing or if the desired value is +// empty. +StreamInfoFormatter::FieldExtractor sslConnectionInfoStringExtractor( + std::function string_extractor) { + return [string_extractor](const StreamInfo::StreamInfo& stream_info) { + if (stream_info.downstreamSslConnection() == nullptr) { + return UnspecifiedValueString; + } + + const auto value = string_extractor(*stream_info.downstreamSslConnection()); + if (value.empty()) { + return UnspecifiedValueString; + } else { + return value; + } + }; +} +} // namespace + const std::string AccessLogFormatUtils::DEFAULT_FORMAT = "[%START_TIME%] \"%REQ(:METHOD)% %REQ(X-ENVOY-ORIGINAL-PATH?:PATH)% %PROTOCOL%\" " "%RESPONSE_CODE% %RESPONSE_FLAGS% %BYTES_RECEIVED% %BYTES_SENT% %DURATION% " @@ -350,6 +371,26 @@ StreamInfoFormatter::StreamInfoFormatter(const std::string& field_name) { return UnspecifiedValueString; } }; + } else if (field_name == "DOWNSTREAM_PEER_URI_SAN") { + field_extractor_ = + sslConnectionInfoStringExtractor([](const Ssl::ConnectionInfo& connection_info) { + return absl::StrJoin(connection_info.uriSanPeerCertificate(), ","); + }); + } else if (field_name == "DOWNSTREAM_LOCAL_URI_SAN") { + field_extractor_ = + sslConnectionInfoStringExtractor([](const Ssl::ConnectionInfo& connection_info) { + return absl::StrJoin(connection_info.uriSanLocalCertificate(), ","); + }); + } else if (field_name == "DOWNSTREAM_PEER_SUBJECT") { + field_extractor_ = + sslConnectionInfoStringExtractor([](const Ssl::ConnectionInfo& connection_info) { + return connection_info.subjectPeerCertificate(); + }); + } else if (field_name == "DOWNSTREAM_LOCAL_SUBJECT") { + field_extractor_ = + sslConnectionInfoStringExtractor([](const Ssl::ConnectionInfo& connection_info) { + return connection_info.subjectLocalCertificate(); + }); } else if (field_name == "UPSTREAM_TRANSPORT_FAILURE_REASON") { field_extractor_ = [](const StreamInfo::StreamInfo& stream_info) { if (!stream_info.upstreamTransportFailureReason().empty()) { diff --git a/source/common/access_log/access_log_formatter.h b/source/common/access_log/access_log_formatter.h index 3c670e9bd9f8b..103657dcb40db 100644 --- a/source/common/access_log/access_log_formatter.h +++ b/source/common/access_log/access_log_formatter.h @@ -198,8 +198,10 @@ class StreamInfoFormatter : public FormatterProvider { std::string format(const Http::HeaderMap&, const Http::HeaderMap&, const Http::HeaderMap&, const StreamInfo::StreamInfo& stream_info) const override; + using FieldExtractor = std::function; + private: - std::function field_extractor_; + FieldExtractor field_extractor_; }; /** diff --git a/source/common/http/conn_manager_impl.cc b/source/common/http/conn_manager_impl.cc index 98ec73b24ad78..2e146102930c3 100644 --- a/source/common/http/conn_manager_impl.cc +++ b/source/common/http/conn_manager_impl.cc @@ -420,6 +420,8 @@ ConnectionManagerImpl::ActiveStream::ActiveStream(ConnectionManagerImpl& connect stream_info_.setDownstreamRemoteAddress( connection_manager_.read_callbacks_->connection().remoteAddress()); + stream_info_.setDownstreamSslConnection(connection_manager_.read_callbacks_->connection().ssl()); + if (connection_manager_.config_.streamIdleTimeout().count()) { idle_timeout_ms_ = connection_manager_.config_.streamIdleTimeout(); stream_idle_timer_ = connection_manager_.read_callbacks_->connection().dispatcher().createTimer( diff --git a/source/common/http/conn_manager_utility.cc b/source/common/http/conn_manager_utility.cc index 004c8cfff3607..f85965cf05cc5 100644 --- a/source/common/http/conn_manager_utility.cc +++ b/source/common/http/conn_manager_utility.cc @@ -279,9 +279,9 @@ void ConnectionManagerUtility::mutateXfccRequestHeader(HeaderMap& request_header // 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 auto uri_sans_local_cert = connection.ssl()->uriSanLocalCertificate(); + if (!uri_sans_local_cert.empty()) { + client_cert_details.push_back("By=" + uri_sans_local_cert[0]); } const std::string cert_digest = connection.ssl()->sha256PeerCertificateDigest(); if (!cert_digest.empty()) { @@ -301,10 +301,13 @@ void ConnectionManagerUtility::mutateXfccRequestHeader(HeaderMap& request_header client_cert_details.push_back("Subject=\"" + connection.ssl()->subjectPeerCertificate() + "\""); break; - case ClientCertDetailsType::URI: + case ClientCertDetailsType::URI: { // The "URI" key still exists even if the URI is empty. - client_cert_details.push_back("URI=" + connection.ssl()->uriSanPeerCertificate()); + const auto sans = connection.ssl()->uriSanPeerCertificate(); + const auto& uri_san = sans.empty() ? "" : sans[0]; + client_cert_details.push_back("URI=" + uri_san); break; + } case ClientCertDetailsType::DNS: { const std::vector dns_sans = connection.ssl()->dnsSansPeerCertificate(); if (!dns_sans.empty()) { diff --git a/source/common/network/connection_impl.h b/source/common/network/connection_impl.h index a00ce5396378d..c2fb2584746d2 100644 --- a/source/common/network/connection_impl.h +++ b/source/common/network/connection_impl.h @@ -81,7 +81,7 @@ class ConnectionImpl : public virtual Connection, return socket_->localAddress(); } void setConnectionStats(const ConnectionStats& stats) override; - const Ssl::Connection* ssl() const override { return transport_socket_->ssl(); } + const Ssl::ConnectionInfo* ssl() const override { return transport_socket_->ssl(); } State state() const override; void write(Buffer::Instance& data, bool end_stream) override; void setBufferLimits(uint32_t limit) override; diff --git a/source/common/network/raw_buffer_socket.h b/source/common/network/raw_buffer_socket.h index 5e7d652da6206..5183ce18fbc9e 100644 --- a/source/common/network/raw_buffer_socket.h +++ b/source/common/network/raw_buffer_socket.h @@ -20,7 +20,7 @@ class RawBufferSocket : public TransportSocket, protected Logger::Loggableconnection().enableHalfClose(true); getStreamInfo().setDownstreamLocalAddress(read_callbacks_->connection().localAddress()); getStreamInfo().setDownstreamRemoteAddress(read_callbacks_->connection().remoteAddress()); + getStreamInfo().setDownstreamSslConnection(read_callbacks_->connection().ssl()); // Need to disable reads so that we don't write to an upstream that might fail // in onData(). This will get re-enabled when the upstream connection is diff --git a/source/extensions/access_loggers/http_grpc/grpc_access_log_impl.cc b/source/extensions/access_loggers/http_grpc/grpc_access_log_impl.cc index 918c2c76953ca..f32feaa20a13c 100644 --- a/source/extensions/access_loggers/http_grpc/grpc_access_log_impl.cc +++ b/source/extensions/access_loggers/http_grpc/grpc_access_log_impl.cc @@ -187,7 +187,6 @@ void HttpGrpcAccessLog::log(const Http::HeaderMap* request_headers, // Common log properties. // TODO(mattklein123): Populate sample_rate field. - // TODO(mattklein123): Populate tls_properties field. auto* common_properties = log_entry->mutable_common_properties(); if (stream_info.downstreamRemoteAddress() != nullptr) { @@ -200,6 +199,28 @@ void HttpGrpcAccessLog::log(const Http::HeaderMap* request_headers, *stream_info.downstreamLocalAddress(), *common_properties->mutable_downstream_local_address()); } + if (stream_info.downstreamSslConnection() != nullptr) { + auto* tls_properties = common_properties->mutable_tls_properties(); + + tls_properties->set_tls_sni_hostname(stream_info.requestedServerName()); + + auto* local_properties = tls_properties->mutable_local_certificate_properties(); + for (const auto& uri_san : stream_info.downstreamSslConnection()->uriSanLocalCertificate()) { + auto* local_san = local_properties->add_subject_alt_name(); + local_san->set_uri(uri_san); + } + local_properties->set_subject(stream_info.downstreamSslConnection()->subjectLocalCertificate()); + + auto* peer_properties = tls_properties->mutable_peer_certificate_properties(); + for (const auto& uri_san : stream_info.downstreamSslConnection()->uriSanPeerCertificate()) { + auto* peer_san = peer_properties->add_subject_alt_name(); + peer_san->set_uri(uri_san); + } + + peer_properties->set_subject(stream_info.downstreamSslConnection()->subjectPeerCertificate()); + + // TODO(snowp): Populate remaining tls_properties fields. + } common_properties->mutable_start_time()->MergeFrom( Protobuf::util::TimeUtil::NanosecondsToTimestamp( std::chrono::duration_cast( diff --git a/source/extensions/filters/common/ext_authz/check_request_utils.cc b/source/extensions/filters/common/ext_authz/check_request_utils.cc index 30474ad1b2962..c887b4954eda1 100644 --- a/source/extensions/filters/common/ext_authz/check_request_utils.cc +++ b/source/extensions/filters/common/ext_authz/check_request_utils.cc @@ -40,19 +40,21 @@ void CheckRequestUtils::setAttrContextPeer(envoy::service::auth::v2::AttributeCo // Set the principal // Preferably the SAN from the peer's cert or // Subject from the peer's cert. - Ssl::Connection* ssl = const_cast(connection.ssl()); + Ssl::ConnectionInfo* ssl = const_cast(connection.ssl()); if (ssl != nullptr) { if (local) { - peer.set_principal(ssl->uriSanLocalCertificate()); - - if (peer.principal().empty()) { + const auto uriSans = ssl->uriSanLocalCertificate(); + if (uriSans.empty()) { peer.set_principal(ssl->subjectLocalCertificate()); + } else { + peer.set_principal(uriSans[0]); } } else { - peer.set_principal(ssl->uriSanPeerCertificate()); - - if (peer.principal().empty()) { + const auto uriSans = ssl->uriSanPeerCertificate(); + if (uriSans.empty()) { peer.set_principal(ssl->subjectPeerCertificate()); + } else { + peer.set_principal(uriSans[0]); } } } diff --git a/source/extensions/filters/common/lua/wrappers.h b/source/extensions/filters/common/lua/wrappers.h index 2019a8887961f..7d8eeebed844a 100644 --- a/source/extensions/filters/common/lua/wrappers.h +++ b/source/extensions/filters/common/lua/wrappers.h @@ -103,11 +103,11 @@ class MetadataMapWrapper : public BaseLuaObject { }; /** - * Lua wrapper for Ssl::Connection. + * Lua wrapper for Ssl::ConnectionInfo. */ class SslConnectionWrapper : public BaseLuaObject { public: - SslConnectionWrapper(const Ssl::Connection*) {} + SslConnectionWrapper(const Ssl::ConnectionInfo*) {} static ExportedFunctions exportedFunctions() { return {}; } // TODO(dio): Add more Lua APIs around Ssl::Connection. diff --git a/source/extensions/filters/common/rbac/matchers.cc b/source/extensions/filters/common/rbac/matchers.cc index 97f859e716773..5d44f09cd7441 100644 --- a/source/extensions/filters/common/rbac/matchers.cc +++ b/source/extensions/filters/common/rbac/matchers.cc @@ -141,8 +141,13 @@ bool AuthenticatedMatcher::matches(const Network::Connection& connection, return true; } - std::string principal = ssl->uriSanPeerCertificate(); - principal = principal.empty() ? ssl->subjectPeerCertificate() : principal; + const auto uriSans = ssl->uriSanPeerCertificate(); + std::string principal; + if (uriSans.empty()) { + principal = ssl->subjectPeerCertificate(); + } else { + principal = uriSans[0]; + } return matcher_.value().match(principal); } diff --git a/source/extensions/filters/http/rbac/rbac_filter.cc b/source/extensions/filters/http/rbac/rbac_filter.cc index 5316d15a77225..f32aceb5cd3c5 100644 --- a/source/extensions/filters/http/rbac/rbac_filter.cc +++ b/source/extensions/filters/http/rbac/rbac_filter.cc @@ -6,6 +6,8 @@ #include "extensions/filters/http/well_known_names.h" +#include "absl/strings/str_join.h" + namespace Envoy { namespace Extensions { namespace HttpFilters { @@ -48,18 +50,18 @@ RoleBasedAccessControlRouteSpecificFilterConfig::RoleBasedAccessControlRouteSpec Http::FilterHeadersStatus RoleBasedAccessControlFilter::decodeHeaders(Http::HeaderMap& headers, bool) { - ENVOY_LOG( - debug, - "checking request: remoteAddress: {}, localAddress: {}, ssl: {}, headers: {}, " - "dynamicMetadata: {}", - callbacks_->connection()->remoteAddress()->asString(), - callbacks_->connection()->localAddress()->asString(), - callbacks_->connection()->ssl() - ? "uriSanPeerCertificate: " + callbacks_->connection()->ssl()->uriSanPeerCertificate() + - ", subjectPeerCertificate: " + - callbacks_->connection()->ssl()->subjectPeerCertificate() - : "none", - headers, callbacks_->streamInfo().dynamicMetadata().DebugString()); + ENVOY_LOG(debug, + "checking request: remoteAddress: {}, localAddress: {}, ssl: {}, headers: {}, " + "dynamicMetadata: {}", + callbacks_->connection()->remoteAddress()->asString(), + callbacks_->connection()->localAddress()->asString(), + callbacks_->connection()->ssl() + ? "uriSanPeerCertificate: " + + absl::StrJoin(callbacks_->connection()->ssl()->uriSanPeerCertificate(), ",") + + ", subjectPeerCertificate: " + + callbacks_->connection()->ssl()->subjectPeerCertificate() + : "none", + headers, callbacks_->streamInfo().dynamicMetadata().DebugString()); std::string effective_policy_id; const auto& shadow_engine = diff --git a/source/extensions/filters/network/rbac/rbac_filter.cc b/source/extensions/filters/network/rbac/rbac_filter.cc index 1267e9cac3872..0c5008c88b1d8 100644 --- a/source/extensions/filters/network/rbac/rbac_filter.cc +++ b/source/extensions/filters/network/rbac/rbac_filter.cc @@ -5,6 +5,8 @@ #include "extensions/filters/network/well_known_names.h" +#include "absl/strings/str_join.h" + namespace Envoy { namespace Extensions { namespace NetworkFilters { @@ -26,7 +28,8 @@ Network::FilterStatus RoleBasedAccessControlFilter::onData(Buffer::Instance&, bo callbacks_->connection().remoteAddress()->asString(), callbacks_->connection().localAddress()->asString(), callbacks_->connection().ssl() - ? "uriSanPeerCertificate: " + callbacks_->connection().ssl()->uriSanPeerCertificate() + + ? "uriSanPeerCertificate: " + + absl::StrJoin(callbacks_->connection().ssl()->uriSanPeerCertificate(), ",") + ", subjectPeerCertificate: " + callbacks_->connection().ssl()->subjectPeerCertificate() : "none", diff --git a/source/extensions/transport_sockets/alts/tsi_socket.h b/source/extensions/transport_sockets/alts/tsi_socket.h index 2c7b2068df5c4..b304b55807251 100644 --- a/source/extensions/transport_sockets/alts/tsi_socket.h +++ b/source/extensions/transport_sockets/alts/tsi_socket.h @@ -59,7 +59,7 @@ class TsiSocket : public Network::TransportSocket, std::string protocol() const override; absl::string_view failureReason() const override; bool canFlushClose() override { return handshake_complete_; } - const Envoy::Ssl::Connection* ssl() const override { return nullptr; } + const Envoy::Ssl::ConnectionInfo* ssl() const override { return nullptr; } Network::IoResult doWrite(Buffer::Instance& buffer, bool end_stream) override; void closeSocket(Network::ConnectionEvent event) override; Network::IoResult doRead(Buffer::Instance& buffer) override; diff --git a/source/extensions/transport_sockets/tap/tap.cc b/source/extensions/transport_sockets/tap/tap.cc index c3a666377c43d..fc34b5ee2c6df 100644 --- a/source/extensions/transport_sockets/tap/tap.cc +++ b/source/extensions/transport_sockets/tap/tap.cc @@ -50,7 +50,7 @@ Network::IoResult TapSocket::doWrite(Buffer::Instance& buffer, bool end_stream) void TapSocket::onConnected() { transport_socket_->onConnected(); } -const Ssl::Connection* TapSocket::ssl() const { return transport_socket_->ssl(); } +const Ssl::ConnectionInfo* TapSocket::ssl() const { return transport_socket_->ssl(); } TapSocketFactory::TapSocketFactory( const envoy::config::transport_socket::tap::v2alpha::Tap& proto_config, diff --git a/source/extensions/transport_sockets/tap/tap.h b/source/extensions/transport_sockets/tap/tap.h index 19f5cee7f043b..eb5f76959d147 100644 --- a/source/extensions/transport_sockets/tap/tap.h +++ b/source/extensions/transport_sockets/tap/tap.h @@ -26,7 +26,7 @@ class TapSocket : public Network::TransportSocket { Network::IoResult doRead(Buffer::Instance& buffer) override; Network::IoResult doWrite(Buffer::Instance& buffer, bool end_stream) override; void onConnected() override; - const Ssl::Connection* ssl() const override; + const Ssl::ConnectionInfo* ssl() const override; private: SocketTapConfigSharedPtr config_; diff --git a/source/extensions/transport_sockets/tls/ssl_socket.cc b/source/extensions/transport_sockets/tls/ssl_socket.cc index f98f842d5e98f..2918c8afff4d4 100644 --- a/source/extensions/transport_sockets/tls/ssl_socket.cc +++ b/source/extensions/transport_sockets/tls/ssl_socket.cc @@ -38,7 +38,7 @@ class NotReadySslSocket : public Network::TransportSocket { return {PostIoAction::Close, 0, false}; } void onConnected() override {} - const Ssl::Connection* ssl() const override { return nullptr; } + const Ssl::ConnectionInfo* ssl() const override { return nullptr; } }; } // namespace @@ -252,15 +252,13 @@ bool SslSocket::peerCertificatePresented() const { return cert != nullptr; } -std::string SslSocket::uriSanLocalCertificate() const { +std::vector SslSocket::uriSanLocalCertificate() const { // The cert object is not owned. X509* cert = SSL_get_certificate(ssl_.get()); if (!cert) { - return ""; + return {}; } - // TODO(PiotrSikora): Figure out if returning only one URI is valid limitation. - const std::vector& san_uris = Utility::getSubjectAltNames(*cert, GEN_URI); - return (san_uris.size() > 0) ? san_uris[0] : ""; + return Utility::getSubjectAltNames(*cert, GEN_URI); } std::vector SslSocket::dnsSansLocalCertificate() const { @@ -341,14 +339,12 @@ const std::string& SslSocket::urlEncodedPemEncodedPeerCertificateChain() const { return cached_url_encoded_pem_encoded_peer_cert_chain_; } -std::string SslSocket::uriSanPeerCertificate() const { +std::vector SslSocket::uriSanPeerCertificate() const { bssl::UniquePtr cert(SSL_get_peer_certificate(ssl_.get())); if (!cert) { - return ""; + return {}; } - // TODO(PiotrSikora): Figure out if returning only one URI is valid limitation. - const std::vector& san_uris = Utility::getSubjectAltNames(*cert, GEN_URI); - return (san_uris.size() > 0) ? san_uris[0] : ""; + return Utility::getSubjectAltNames(*cert, GEN_URI); } std::vector SslSocket::dnsSansPeerCertificate() const { diff --git a/source/extensions/transport_sockets/tls/ssl_socket.h b/source/extensions/transport_sockets/tls/ssl_socket.h index bc9150f187b47..ccae3a144e0be 100644 --- a/source/extensions/transport_sockets/tls/ssl_socket.h +++ b/source/extensions/transport_sockets/tls/ssl_socket.h @@ -40,7 +40,7 @@ struct SslSocketFactoryStats { enum class InitialState { Client, Server }; class SslSocket : public Network::TransportSocket, - public Envoy::Ssl::Connection, + public Envoy::Ssl::ConnectionInfo, protected Logger::Loggable { public: SslSocket(Envoy::Ssl::ContextSharedPtr ctx, InitialState state, @@ -48,12 +48,12 @@ class SslSocket : public Network::TransportSocket, // Ssl::Connection bool peerCertificatePresented() const override; - std::string uriSanLocalCertificate() const override; + std::vector uriSanLocalCertificate() const override; const std::string& sha256PeerCertificateDigest() const override; std::string serialNumberPeerCertificate() const override; std::string subjectPeerCertificate() const override; std::string subjectLocalCertificate() const override; - std::string uriSanPeerCertificate() const override; + std::vector uriSanPeerCertificate() const override; const std::string& urlEncodedPemEncodedPeerCertificate() const override; const std::string& urlEncodedPemEncodedPeerCertificateChain() const override; std::vector dnsSansPeerCertificate() const override; @@ -70,7 +70,7 @@ class SslSocket : public Network::TransportSocket, Network::IoResult doRead(Buffer::Instance& read_buffer) override; Network::IoResult doWrite(Buffer::Instance& write_buffer, bool end_stream) override; void onConnected() override; - const Ssl::Connection* ssl() const override { return this; } + const Ssl::ConnectionInfo* ssl() const override { return this; } SSL* rawSslForTest() const { return ssl_.get(); } diff --git a/test/common/access_log/BUILD b/test/common/access_log/BUILD index b8bfca1d05bff..475884944d7ff 100644 --- a/test/common/access_log/BUILD +++ b/test/common/access_log/BUILD @@ -37,6 +37,7 @@ envoy_cc_test( "//source/common/common:utility_lib", "//source/common/http:header_map_lib", "//test/mocks/http:http_mocks", + "//test/mocks/ssl:ssl_mocks", "//test/mocks/stream_info:stream_info_mocks", "//test/mocks/upstream:upstream_mocks", "//test/test_common:utility_lib", diff --git a/test/common/access_log/access_log_formatter_test.cc b/test/common/access_log/access_log_formatter_test.cc index 4313b136d7801..adcb54a50b659 100644 --- a/test/common/access_log/access_log_formatter_test.cc +++ b/test/common/access_log/access_log_formatter_test.cc @@ -8,6 +8,7 @@ #include "common/http/header_map_impl.h" #include "test/mocks/http/mocks.h" +#include "test/mocks/ssl/mocks.h" #include "test/mocks/stream_info/mocks.h" #include "test/mocks/upstream/mocks.h" #include "test/test_common/printers.h" @@ -203,7 +204,102 @@ TEST(AccessLogFormatterTest, streamInfoFormatter) { .WillRepeatedly(ReturnRef(requested_server_name)); EXPECT_EQ("-", upstream_format.format(header, header, header, stream_info)); } - + { + StreamInfoFormatter upstream_format("DOWNSTREAM_PEER_URI_SAN"); + NiceMock connection_info; + const std::vector sans{"san"}; + ON_CALL(connection_info, uriSanPeerCertificate()).WillByDefault(Return(sans)); + EXPECT_CALL(stream_info, downstreamSslConnection()).WillRepeatedly(Return(&connection_info)); + EXPECT_EQ("san", upstream_format.format(header, header, header, stream_info)); + } + { + StreamInfoFormatter upstream_format("DOWNSTREAM_PEER_URI_SAN"); + NiceMock connection_info; + const std::vector sans{"san1", "san2"}; + ON_CALL(connection_info, uriSanPeerCertificate()).WillByDefault(Return(sans)); + EXPECT_CALL(stream_info, downstreamSslConnection()).WillRepeatedly(Return(&connection_info)); + EXPECT_EQ("san1,san2", upstream_format.format(header, header, header, stream_info)); + } + { + StreamInfoFormatter upstream_format("DOWNSTREAM_PEER_URI_SAN"); + NiceMock connection_info; + ON_CALL(connection_info, uriSanPeerCertificate()) + .WillByDefault(Return(std::vector())); + EXPECT_CALL(stream_info, downstreamSslConnection()).WillRepeatedly(Return(&connection_info)); + EXPECT_EQ("-", upstream_format.format(header, header, header, stream_info)); + } + { + EXPECT_CALL(stream_info, downstreamSslConnection()).WillRepeatedly(Return(nullptr)); + StreamInfoFormatter upstream_format("DOWNSTREAM_PEER_URI_SAN"); + EXPECT_EQ("-", upstream_format.format(header, header, header, stream_info)); + } + { + StreamInfoFormatter upstream_format("DOWNSTREAM_LOCAL_URI_SAN"); + NiceMock connection_info; + const std::vector sans{"san"}; + ON_CALL(connection_info, uriSanLocalCertificate()).WillByDefault(Return(sans)); + EXPECT_CALL(stream_info, downstreamSslConnection()).WillRepeatedly(Return(&connection_info)); + EXPECT_EQ("san", upstream_format.format(header, header, header, stream_info)); + } + { + StreamInfoFormatter upstream_format("DOWNSTREAM_LOCAL_URI_SAN"); + NiceMock connection_info; + const std::vector sans{"san1", "san2"}; + ON_CALL(connection_info, uriSanLocalCertificate()).WillByDefault(Return(sans)); + EXPECT_CALL(stream_info, downstreamSslConnection()).WillRepeatedly(Return(&connection_info)); + EXPECT_EQ("san1,san2", upstream_format.format(header, header, header, stream_info)); + } + { + StreamInfoFormatter upstream_format("DOWNSTREAM_LOCAL_URI_SAN"); + NiceMock connection_info; + ON_CALL(connection_info, uriSanLocalCertificate()) + .WillByDefault(Return(std::vector())); + EXPECT_CALL(stream_info, downstreamSslConnection()).WillRepeatedly(Return(&connection_info)); + EXPECT_EQ("-", upstream_format.format(header, header, header, stream_info)); + } + { + EXPECT_CALL(stream_info, downstreamSslConnection()).WillRepeatedly(Return(nullptr)); + StreamInfoFormatter upstream_format("DOWNSTREAM_LOCAL_URI_SAN"); + EXPECT_EQ("-", upstream_format.format(header, header, header, stream_info)); + } + { + StreamInfoFormatter upstream_format("DOWNSTREAM_LOCAL_SUBJECT"); + NiceMock connection_info; + ON_CALL(connection_info, subjectLocalCertificate()).WillByDefault(Return("subject")); + EXPECT_CALL(stream_info, downstreamSslConnection()).WillRepeatedly(Return(&connection_info)); + EXPECT_EQ("subject", upstream_format.format(header, header, header, stream_info)); + } + { + StreamInfoFormatter upstream_format("DOWNSTREAM_LOCAL_SUBJECT"); + NiceMock connection_info; + ON_CALL(connection_info, subjectLocalCertificate()).WillByDefault(Return("")); + EXPECT_CALL(stream_info, downstreamSslConnection()).WillRepeatedly(Return(&connection_info)); + EXPECT_EQ("-", upstream_format.format(header, header, header, stream_info)); + } + { + EXPECT_CALL(stream_info, downstreamSslConnection()).WillRepeatedly(Return(nullptr)); + StreamInfoFormatter upstream_format("DOWNSTREAM_LOCAL_SUBJECT"); + EXPECT_EQ("-", upstream_format.format(header, header, header, stream_info)); + } + { + StreamInfoFormatter upstream_format("DOWNSTREAM_PEER_SUBJECT"); + NiceMock connection_info; + ON_CALL(connection_info, subjectPeerCertificate()).WillByDefault(Return("subject")); + EXPECT_CALL(stream_info, downstreamSslConnection()).WillRepeatedly(Return(&connection_info)); + EXPECT_EQ("subject", upstream_format.format(header, header, header, stream_info)); + } + { + StreamInfoFormatter upstream_format("DOWNSTREAM_PEER_SUBJECT"); + NiceMock connection_info; + ON_CALL(connection_info, subjectPeerCertificate()).WillByDefault(Return("")); + EXPECT_CALL(stream_info, downstreamSslConnection()).WillRepeatedly(Return(&connection_info)); + EXPECT_EQ("-", upstream_format.format(header, header, header, stream_info)); + } + { + EXPECT_CALL(stream_info, downstreamSslConnection()).WillRepeatedly(Return(nullptr)); + StreamInfoFormatter upstream_format("DOWNSTREAM_PEER_SUBJECT"); + EXPECT_EQ("-", upstream_format.format(header, header, header, stream_info)); + } { StreamInfoFormatter upstream_format("UPSTREAM_TRANSPORT_FAILURE_REASON"); std::string upstream_transport_failure_reason = "SSL error"; diff --git a/test/common/http/conn_manager_impl_fuzz_test.cc b/test/common/http/conn_manager_impl_fuzz_test.cc index f6a7da2851b0f..de312082ff4bd 100644 --- a/test/common/http/conn_manager_impl_fuzz_test.cc +++ b/test/common/http/conn_manager_impl_fuzz_test.cc @@ -389,7 +389,7 @@ DEFINE_PROTO_FUZZER(const test::common::http::ConnManagerImplTestCase& input) { NiceMock local_info; NiceMock cluster_manager; NiceMock filter_callbacks; - std::unique_ptr ssl_connection; + std::unique_ptr ssl_connection; bool connection_alive = true; ON_CALL(filter_callbacks.connection_, ssl()).WillByDefault(Return(ssl_connection.get())); diff --git a/test/common/http/conn_manager_impl_test.cc b/test/common/http/conn_manager_impl_test.cc index 5ca8a80ed6957..d6e59199d3af1 100644 --- a/test/common/http/conn_manager_impl_test.cc +++ b/test/common/http/conn_manager_impl_test.cc @@ -101,7 +101,7 @@ class HttpConnectionManagerImplTest : public testing::Test, public ConnectionMan void setup(bool ssl, const std::string& server_name, bool tracing = true) { if (ssl) { - ssl_connection_ = std::make_unique(); + ssl_connection_ = std::make_unique(); } server_name_ = server_name; @@ -289,7 +289,7 @@ class HttpConnectionManagerImplTest : public testing::Test, public ConnectionMan NiceMock random_; NiceMock local_info_; NiceMock factory_context_; - std::unique_ptr ssl_connection_; + std::unique_ptr ssl_connection_; TracingConnectionManagerConfigPtr tracing_config_; SlowDateProviderImpl date_provider_{test_time_.timeSystem()}; MockStream stream_; @@ -1083,6 +1083,55 @@ TEST_F(HttpConnectionManagerImplTest, TestAccessLogWithInvalidRequest) { conn_manager_->onData(fake_input, false); } +TEST_F(HttpConnectionManagerImplTest, TestAccessLogSsl) { + setup(true, ""); + + std::shared_ptr filter(new NiceMock()); + std::shared_ptr handler(new NiceMock()); + + EXPECT_CALL(filter_factory_, createFilterChain(_)) + .WillOnce(Invoke([&](FilterChainFactoryCallbacks& callbacks) -> void { + callbacks.addStreamDecoderFilter(filter); + callbacks.addAccessLogHandler(handler); + })); + + EXPECT_CALL(*handler, log(_, _, _, _)) + .WillOnce(Invoke([](const HeaderMap*, const HeaderMap*, const HeaderMap*, + const StreamInfo::StreamInfo& stream_info) { + EXPECT_TRUE(stream_info.responseCode()); + EXPECT_EQ(stream_info.responseCode().value(), uint32_t(200)); + EXPECT_NE(nullptr, stream_info.downstreamLocalAddress()); + EXPECT_NE(nullptr, stream_info.downstreamRemoteAddress()); + EXPECT_NE(nullptr, stream_info.downstreamDirectRemoteAddress()); + EXPECT_NE(nullptr, stream_info.downstreamSslConnection()); + EXPECT_NE(nullptr, stream_info.routeEntry()); + })); + + StreamDecoder* decoder = nullptr; + NiceMock encoder; + EXPECT_CALL(*codec_, dispatch(_)).WillRepeatedly(Invoke([&](Buffer::Instance& data) -> void { + decoder = &conn_manager_->newStream(encoder); + + HeaderMapPtr headers{ + new TestHeaderMapImpl{{":method", "GET"}, + {":authority", "host"}, + {":path", "/"}, + {"x-request-id", "125a4afb-6f55-a4ba-ad80-413f09f48a28"}}}; + decoder->decodeHeaders(std::move(headers), true); + + HeaderMapPtr response_headers{new TestHeaderMapImpl{{":status", "200"}}}; + filter->callbacks_->encodeHeaders(std::move(response_headers), false); + + HeaderMapPtr response_trailers{new TestHeaderMapImpl{{"x-trailer", "1"}}}; + filter->callbacks_->encodeTrailers(std::move(response_trailers)); + + data.drain(4); + })); + + Buffer::OwnedImpl fake_input("1234"); + conn_manager_->onData(fake_input, false); +} + TEST_F(HttpConnectionManagerImplTest, DoNotStartSpanIfTracingIsNotEnabled) { setup(false, ""); diff --git a/test/common/http/conn_manager_utility_test.cc b/test/common/http/conn_manager_utility_test.cc index 9368835e1f04c..523cfb01ee9bd 100644 --- a/test/common/http/conn_manager_utility_test.cc +++ b/test/common/http/conn_manager_utility_test.cc @@ -704,7 +704,7 @@ TEST_F(ConnectionManagerUtilityTest, MutateResponseHeadersReturnXRequestId) { // Test full sanitization of x-forwarded-client-cert. TEST_F(ConnectionManagerUtilityTest, MtlsSanitizeClientCert) { - NiceMock ssl; + NiceMock ssl; ON_CALL(ssl, peerCertificatePresented()).WillByDefault(Return(true)); ON_CALL(connection_, ssl()).WillByDefault(Return(&ssl)); ON_CALL(config_, forwardClientCert()) @@ -720,7 +720,7 @@ TEST_F(ConnectionManagerUtilityTest, MtlsSanitizeClientCert) { // Test that we sanitize and set x-forwarded-client-cert. TEST_F(ConnectionManagerUtilityTest, MtlsForwardOnlyClientCert) { - NiceMock ssl; + NiceMock ssl; ON_CALL(ssl, peerCertificatePresented()).WillByDefault(Return(true)); ON_CALL(connection_, ssl()).WillByDefault(Return(&ssl)); ON_CALL(config_, forwardClientCert()) @@ -739,12 +739,14 @@ TEST_F(ConnectionManagerUtilityTest, MtlsForwardOnlyClientCert) { // The server (local) identity is foo.com/be. The client does not set XFCC. TEST_F(ConnectionManagerUtilityTest, MtlsSetForwardClientCert) { - NiceMock ssl; + NiceMock ssl; ON_CALL(ssl, peerCertificatePresented()).WillByDefault(Return(true)); - EXPECT_CALL(ssl, uriSanLocalCertificate()).WillOnce(Return("test://foo.com/be")); + const std::vector local_uri_sans{"test://foo.com/be"}; + EXPECT_CALL(ssl, uriSanLocalCertificate()).WillOnce(Return(local_uri_sans)); std::string expected_sha("abcdefg"); EXPECT_CALL(ssl, sha256PeerCertificateDigest()).WillOnce(ReturnRef(expected_sha)); - EXPECT_CALL(ssl, uriSanPeerCertificate()).WillRepeatedly(Return("test://foo.com/fe")); + const std::vector peer_uri_sans{"test://foo.com/fe"}; + EXPECT_CALL(ssl, uriSanPeerCertificate()).WillRepeatedly(Return(peer_uri_sans)); std::string expected_pem("%3D%3Dabc%0Ade%3D"); EXPECT_CALL(ssl, urlEncodedPemEncodedPeerCertificate()).WillOnce(ReturnRef(expected_pem)); std::vector expected_dns = {"www.example.com"}; @@ -775,12 +777,14 @@ TEST_F(ConnectionManagerUtilityTest, MtlsSetForwardClientCert) { // also sends the XFCC header with the authentication result of the previous hop, (bar.com/be // calling foo.com/fe). TEST_F(ConnectionManagerUtilityTest, MtlsAppendForwardClientCert) { - NiceMock ssl; + NiceMock ssl; ON_CALL(ssl, peerCertificatePresented()).WillByDefault(Return(true)); - EXPECT_CALL(ssl, uriSanLocalCertificate()).WillOnce(Return("test://foo.com/be")); + const std::vector local_uri_sans{"test://foo.com/be"}; + EXPECT_CALL(ssl, uriSanLocalCertificate()).WillOnce(Return(local_uri_sans)); std::string expected_sha("abcdefg"); EXPECT_CALL(ssl, sha256PeerCertificateDigest()).WillOnce(ReturnRef(expected_sha)); - EXPECT_CALL(ssl, uriSanPeerCertificate()).WillRepeatedly(Return("test://foo.com/fe")); + const std::vector peer_uri_sans{"test://foo.com/fe"}; + EXPECT_CALL(ssl, uriSanPeerCertificate()).WillRepeatedly(Return(peer_uri_sans)); std::string expected_pem("%3D%3Dabc%0Ade%3D"); EXPECT_CALL(ssl, urlEncodedPemEncodedPeerCertificate()).WillOnce(ReturnRef(expected_pem)); std::vector expected_dns = {"www.example.com"}; @@ -811,12 +815,13 @@ TEST_F(ConnectionManagerUtilityTest, MtlsAppendForwardClientCert) { // also sends the XFCC header with the authentication result of the previous hop, (bar.com/be // calling foo.com/fe). TEST_F(ConnectionManagerUtilityTest, MtlsAppendForwardClientCertLocalSanEmpty) { - NiceMock ssl; + NiceMock ssl; ON_CALL(ssl, peerCertificatePresented()).WillByDefault(Return(true)); - EXPECT_CALL(ssl, uriSanLocalCertificate()).WillOnce(Return("")); + EXPECT_CALL(ssl, uriSanLocalCertificate()).WillOnce(Return(std::vector())); std::string expected_sha("abcdefg"); EXPECT_CALL(ssl, sha256PeerCertificateDigest()).WillOnce(ReturnRef(expected_sha)); - EXPECT_CALL(ssl, uriSanPeerCertificate()).WillRepeatedly(Return("test://foo.com/fe")); + const std::vector peer_uri_sans{"test://foo.com/fe"}; + EXPECT_CALL(ssl, uriSanPeerCertificate()).WillRepeatedly(Return(peer_uri_sans)); ON_CALL(connection_, ssl()).WillByDefault(Return(&ssl)); ON_CALL(config_, forwardClientCert()) .WillByDefault(Return(Http::ForwardClientCertType::AppendForward)); @@ -839,14 +844,16 @@ TEST_F(ConnectionManagerUtilityTest, MtlsAppendForwardClientCertLocalSanEmpty) { // also sends the XFCC header with the authentication result of the previous hop, (bar.com/be // calling foo.com/fe). TEST_F(ConnectionManagerUtilityTest, MtlsSanitizeSetClientCert) { - NiceMock ssl; + NiceMock ssl; ON_CALL(ssl, peerCertificatePresented()).WillByDefault(Return(true)); - EXPECT_CALL(ssl, uriSanLocalCertificate()).WillOnce(Return("test://foo.com/be")); + const std::vector local_uri_sans{"test://foo.com/be"}; + EXPECT_CALL(ssl, uriSanLocalCertificate()).WillOnce(Return(local_uri_sans)); std::string expected_sha("abcdefg"); EXPECT_CALL(ssl, sha256PeerCertificateDigest()).WillOnce(ReturnRef(expected_sha)); EXPECT_CALL(ssl, subjectPeerCertificate()) .WillOnce(Return("/C=US/ST=CA/L=San Francisco/OU=Lyft/CN=test.lyft.com")); - EXPECT_CALL(ssl, uriSanPeerCertificate()).WillRepeatedly(Return("test://foo.com/fe")); + const std::vector peer_uri_sans{"test://foo.com/fe"}; + EXPECT_CALL(ssl, uriSanPeerCertificate()).WillRepeatedly(Return(peer_uri_sans)); std::string expected_pem("abcde="); EXPECT_CALL(ssl, urlEncodedPemEncodedPeerCertificate()).WillOnce(ReturnRef(expected_pem)); ON_CALL(connection_, ssl()).WillByDefault(Return(&ssl)); @@ -874,14 +881,15 @@ TEST_F(ConnectionManagerUtilityTest, MtlsSanitizeSetClientCert) { // also sends the XFCC header with the authentication result of the previous hop, (bar.com/be // calling foo.com/fe). TEST_F(ConnectionManagerUtilityTest, MtlsSanitizeSetClientCertPeerSanEmpty) { - NiceMock ssl; + NiceMock ssl; ON_CALL(ssl, peerCertificatePresented()).WillByDefault(Return(true)); - EXPECT_CALL(ssl, uriSanLocalCertificate()).WillOnce(Return("test://foo.com/be")); + const std::vector local_uri_sans{"test://foo.com/be"}; + EXPECT_CALL(ssl, uriSanLocalCertificate()).WillOnce(Return(local_uri_sans)); std::string expected_sha("abcdefg"); EXPECT_CALL(ssl, sha256PeerCertificateDigest()).WillOnce(ReturnRef(expected_sha)); EXPECT_CALL(ssl, subjectPeerCertificate()) .WillOnce(Return("/C=US/ST=CA/L=San Francisco/OU=Lyft/CN=test.lyft.com")); - EXPECT_CALL(ssl, uriSanPeerCertificate()).WillRepeatedly(Return("")); + EXPECT_CALL(ssl, uriSanPeerCertificate()).WillRepeatedly(Return(std::vector())); ON_CALL(connection_, ssl()).WillByDefault(Return(&ssl)); ON_CALL(config_, forwardClientCert()) .WillByDefault(Return(Http::ForwardClientCertType::SanitizeSet)); @@ -902,7 +910,7 @@ TEST_F(ConnectionManagerUtilityTest, MtlsSanitizeSetClientCertPeerSanEmpty) { // forward_only, append_forward and sanitize_set are only effective in mTLS connection. TEST_F(ConnectionManagerUtilityTest, TlsSanitizeClientCertWhenForward) { - NiceMock ssl; + NiceMock ssl; ON_CALL(ssl, peerCertificatePresented()).WillByDefault(Return(false)); ON_CALL(connection_, ssl()).WillByDefault(Return(&ssl)); ON_CALL(config_, forwardClientCert()) @@ -918,7 +926,7 @@ TEST_F(ConnectionManagerUtilityTest, TlsSanitizeClientCertWhenForward) { // always_forward_only works regardless whether the connection is TLS/mTLS. TEST_F(ConnectionManagerUtilityTest, TlsAlwaysForwardOnlyClientCert) { - NiceMock ssl; + NiceMock ssl; ON_CALL(ssl, peerCertificatePresented()).WillByDefault(Return(false)); ON_CALL(connection_, ssl()).WillByDefault(Return(&ssl)); ON_CALL(config_, forwardClientCert()) diff --git a/test/common/router/router_test.cc b/test/common/router/router_test.cc index 0810d7ad3dd83..6acab3d43b2ca 100644 --- a/test/common/router/router_test.cc +++ b/test/common/router/router_test.cc @@ -2051,7 +2051,7 @@ TEST_F(RouterTest, HttpInternalRedirectSucceeded) { } TEST_F(RouterTest, HttpsInternalRedirectSucceeded) { - Ssl::MockConnection ssl_connection; + Ssl::MockConnectionInfo ssl_connection; enableRedirects(); sendRequest(); diff --git a/test/common/stream_info/test_util.h b/test/common/stream_info/test_util.h index 8664e3cff2a72..f86acf63f2165 100644 --- a/test/common/stream_info/test_util.h +++ b/test/common/stream_info/test_util.h @@ -79,6 +79,14 @@ class TestStreamInfo : public StreamInfo::StreamInfo { return downstream_remote_address_; } + void setDownstreamSslConnection(const Ssl::ConnectionInfo* connection_info) override { + downstream_connection_info_ = connection_info; + } + + const Ssl::ConnectionInfo* downstreamSslConnection() const override { + return downstream_connection_info_; + } + const Router::RouteEntry* routeEntry() const override { return route_entry_; } absl::optional @@ -187,6 +195,7 @@ class TestStreamInfo : public StreamInfo::StreamInfo { Network::Address::InstanceConstSharedPtr downstream_local_address_; Network::Address::InstanceConstSharedPtr downstream_direct_remote_address_; Network::Address::InstanceConstSharedPtr downstream_remote_address_; + const Ssl::ConnectionInfo* downstream_connection_info_; const Router::RouteEntry* route_entry_{}; envoy::api::v2::core::Metadata metadata_{}; Envoy::StreamInfo::FilterStateImpl filter_state_{}; diff --git a/test/common/tcp_proxy/BUILD b/test/common/tcp_proxy/BUILD index 4563a193ec43b..d820b93414bea 100644 --- a/test/common/tcp_proxy/BUILD +++ b/test/common/tcp_proxy/BUILD @@ -29,6 +29,7 @@ envoy_cc_test( "//test/mocks/network:network_mocks", "//test/mocks/runtime:runtime_mocks", "//test/mocks/server:server_mocks", + "//test/mocks/ssl:ssl_mocks", "//test/mocks/stream_info:stream_info_mocks", "//test/mocks/upstream:host_mocks", "//test/mocks/upstream:upstream_mocks", diff --git a/test/common/tcp_proxy/tcp_proxy_test.cc b/test/common/tcp_proxy/tcp_proxy_test.cc index ce9ac4f683478..1ee04f6b2582f 100644 --- a/test/common/tcp_proxy/tcp_proxy_test.cc +++ b/test/common/tcp_proxy/tcp_proxy_test.cc @@ -20,6 +20,7 @@ #include "test/mocks/network/mocks.h" #include "test/mocks/runtime/mocks.h" #include "test/mocks/server/mocks.h" +#include "test/mocks/ssl/mocks.h" #include "test/mocks/stream_info/mocks.h" #include "test/mocks/tcp/mocks.h" #include "test/mocks/upstream/host.h" @@ -937,6 +938,25 @@ TEST_F(TcpProxyTest, AccessLogUpstreamLocalAddress) { EXPECT_EQ(access_log_data_, "2.2.2.2:50000"); } +// Test that access log fields %DOWNSTREAM_REMOTE_ADDRESS_WITHOUT_PORT% and +// %DOWNSTREAM_LOCAL_ADDRESS% are correctly logged. +TEST_F(TcpProxyTest, AccessLogPeerUriSan) { + filter_callbacks_.connection_.local_address_ = + Network::Utility::resolveUrl("tcp://1.1.1.2:20000"); + filter_callbacks_.connection_.remote_address_ = + Network::Utility::resolveUrl("tcp://1.1.1.1:40000"); + + const std::vector uriSan{"someSan"}; + Ssl::MockConnectionInfo mockConnectionInfo; + EXPECT_CALL(mockConnectionInfo, uriSanPeerCertificate()).WillOnce(Return(uriSan)); + EXPECT_CALL(filter_callbacks_.connection_, ssl()).WillRepeatedly(Return(&mockConnectionInfo)); + + setup(1, accessLogConfig("%DOWNSTREAM_PEER_URI_SAN%")); + filter_callbacks_.connection_.raiseEvent(Network::ConnectionEvent::RemoteClose); + filter_.reset(); + EXPECT_EQ(access_log_data_, "someSan"); +} + // Test that access log fields %DOWNSTREAM_REMOTE_ADDRESS_WITHOUT_PORT% and // %DOWNSTREAM_LOCAL_ADDRESS% are correctly logged. TEST_F(TcpProxyTest, AccessLogDownstreamAddress) { diff --git a/test/extensions/access_loggers/http_grpc/BUILD b/test/extensions/access_loggers/http_grpc/BUILD index 946de36332524..cc3cb25cb2e8d 100644 --- a/test/extensions/access_loggers/http_grpc/BUILD +++ b/test/extensions/access_loggers/http_grpc/BUILD @@ -20,6 +20,7 @@ envoy_extension_cc_test( "//test/mocks/access_log:access_log_mocks", "//test/mocks/grpc:grpc_mocks", "//test/mocks/local_info:local_info_mocks", + "//test/mocks/ssl:ssl_mocks", "//test/mocks/stream_info:stream_info_mocks", "//test/mocks/thread_local:thread_local_mocks", ], diff --git a/test/extensions/access_loggers/http_grpc/grpc_access_log_impl_test.cc b/test/extensions/access_loggers/http_grpc/grpc_access_log_impl_test.cc index c4877b4461a0a..4e3ee8e2761f0 100644 --- a/test/extensions/access_loggers/http_grpc/grpc_access_log_impl_test.cc +++ b/test/extensions/access_loggers/http_grpc/grpc_access_log_impl_test.cc @@ -7,6 +7,7 @@ #include "test/mocks/access_log/mocks.h" #include "test/mocks/grpc/mocks.h" #include "test/mocks/local_info/mocks.h" +#include "test/mocks/ssl/mocks.h" #include "test/mocks/stream_info/mocks.h" #include "test/mocks/thread_local/mocks.h" @@ -331,6 +332,58 @@ TEST_F(HttpGrpcAccessLogTest, Marshalling) { request: request_method: "METHOD_UNSPECIFIED" response: {} +)EOF"); + access_log_->log(nullptr, nullptr, nullptr, stream_info); + } + + { + NiceMock stream_info; + stream_info.host_ = nullptr; + stream_info.start_time_ = SystemTime(1h); + + NiceMock connection_info; + const std::vector peerSans{"peerSan1", "peerSan2"}; + ON_CALL(connection_info, uriSanPeerCertificate()).WillByDefault(Return(peerSans)); + const std::vector localSans{"localSan1", "localSan2"}; + ON_CALL(connection_info, uriSanLocalCertificate()).WillByDefault(Return(localSans)); + ON_CALL(connection_info, subjectPeerCertificate()).WillByDefault(Return("peerSubject")); + ON_CALL(connection_info, subjectLocalCertificate()).WillByDefault(Return("localSubject")); + stream_info.setDownstreamSslConnection(&connection_info); + stream_info.requested_server_name_ = "sni"; + + Http::TestHeaderMapImpl request_headers{ + {":method", "WHACKADOO"}, + }; + + expectLog(R"EOF( +http_logs: + log_entry: + common_properties: + downstream_remote_address: + socket_address: + address: "127.0.0.1" + port_value: 0 + downstream_local_address: + socket_address: + address: "127.0.0.2" + port_value: 0 + start_time: + seconds: 3600 + tls_properties: + tls_sni_hostname: sni + local_certificate_properties: + subject_alt_name: + - uri: localSan1 + - uri: localSan2 + subject: localSubject + peer_certificate_properties: + subject_alt_name: + - uri: peerSan1 + - uri: peerSan2 + subject: peerSubject + request: + request_method: "METHOD_UNSPECIFIED" + response: {} )EOF"); access_log_->log(nullptr, nullptr, nullptr, stream_info); } diff --git a/test/extensions/filters/common/ext_authz/check_request_utils_test.cc b/test/extensions/filters/common/ext_authz/check_request_utils_test.cc index 103ecc58dda4f..338ea03c7278e 100644 --- a/test/extensions/filters/common/ext_authz/check_request_utils_test.cc +++ b/test/extensions/filters/common/ext_authz/check_request_utils_test.cc @@ -35,7 +35,7 @@ class CheckRequestUtilsTest : public testing::Test { NiceMock callbacks_; NiceMock net_callbacks_; NiceMock connection_; - NiceMock ssl_; + NiceMock ssl_; NiceMock req_info_; }; @@ -79,8 +79,9 @@ TEST_F(CheckRequestUtilsTest, CheckAttrContextPeer) { EXPECT_CALL(callbacks_, streamId()).WillRepeatedly(Return(0)); EXPECT_CALL(callbacks_, streamInfo()).WillRepeatedly(ReturnRef(req_info_)); EXPECT_CALL(req_info_, protocol()).WillRepeatedly(ReturnPointee(&protocol_)); - EXPECT_CALL(ssl_, uriSanPeerCertificate()).WillOnce(Return("source")); - EXPECT_CALL(ssl_, uriSanLocalCertificate()).WillOnce(Return("destination")); + EXPECT_CALL(ssl_, uriSanPeerCertificate()).WillOnce(Return(std::vector{"source"})); + EXPECT_CALL(ssl_, uriSanLocalCertificate()) + .WillOnce(Return(std::vector{"destination"})); Protobuf::Map context_extensions; context_extensions["key"] = "value"; diff --git a/test/extensions/filters/common/lua/wrappers_test.cc b/test/extensions/filters/common/lua/wrappers_test.cc index 7bb9ebe59a0d2..b44db05750b28 100644 --- a/test/extensions/filters/common/lua/wrappers_test.cc +++ b/test/extensions/filters/common/lua/wrappers_test.cc @@ -63,7 +63,7 @@ class LuaConnectionWrapperTest : public LuaWrappersTestBase { } NiceMock connection_; - NiceMock ssl_; + NiceMock ssl_; }; // Basic buffer wrapper methods test. diff --git a/test/extensions/filters/common/rbac/matchers_test.cc b/test/extensions/filters/common/rbac/matchers_test.cc index d38b17a86803f..52a51edb237df 100644 --- a/test/extensions/filters/common/rbac/matchers_test.cc +++ b/test/extensions/filters/common/rbac/matchers_test.cc @@ -190,11 +190,13 @@ TEST(PortMatcher, PortMatcher) { TEST(AuthenticatedMatcher, uriSanPeerCertificate) { Envoy::Network::MockConnection conn; - Envoy::Ssl::MockConnection ssl; + Envoy::Ssl::MockConnectionInfo ssl; - EXPECT_CALL(ssl, uriSanPeerCertificate()).WillRepeatedly(Return("foo")); + const std::vector sans{"foo", "baz"}; + EXPECT_CALL(ssl, uriSanPeerCertificate()).WillRepeatedly(Return(sans)); EXPECT_CALL(Const(conn), ssl()).WillRepeatedly(Return(&ssl)); + // We should get the first URI SAN. envoy::config::rbac::v2alpha::Principal_Authenticated auth; auth.mutable_principal_name()->set_exact("foo"); checkMatcher(AuthenticatedMatcher(auth), true, conn); @@ -205,9 +207,10 @@ TEST(AuthenticatedMatcher, uriSanPeerCertificate) { TEST(AuthenticatedMatcher, subjectPeerCertificate) { Envoy::Network::MockConnection conn; - Envoy::Ssl::MockConnection ssl; + Envoy::Ssl::MockConnectionInfo ssl; - EXPECT_CALL(ssl, uriSanPeerCertificate()).WillRepeatedly(Return("")); + const std::vector sans; + EXPECT_CALL(ssl, uriSanPeerCertificate()).WillRepeatedly(Return(sans)); EXPECT_CALL(ssl, subjectPeerCertificate()).WillRepeatedly(Return("bar")); EXPECT_CALL(Const(conn), ssl()).WillRepeatedly(Return(&ssl)); @@ -221,8 +224,9 @@ TEST(AuthenticatedMatcher, subjectPeerCertificate) { TEST(AuthenticatedMatcher, AnySSLSubject) { Envoy::Network::MockConnection conn; - Envoy::Ssl::MockConnection ssl; - EXPECT_CALL(ssl, uriSanPeerCertificate()).WillRepeatedly(Return("foo")); + Envoy::Ssl::MockConnectionInfo ssl; + const std::vector sans{"foo", "baz"}; + EXPECT_CALL(ssl, uriSanPeerCertificate()).WillRepeatedly(Return(sans)); EXPECT_CALL(Const(conn), ssl()).WillRepeatedly(Return(&ssl)); envoy::config::rbac::v2alpha::Principal_Authenticated auth; @@ -269,11 +273,12 @@ TEST(PolicyMatcher, PolicyMatcher) { RBAC::PolicyMatcher matcher(policy); Envoy::Network::MockConnection conn; - Envoy::Ssl::MockConnection ssl; + Envoy::Ssl::MockConnectionInfo ssl; Envoy::Network::Address::InstanceConstSharedPtr addr = Envoy::Network::Utility::parseInternetAddress("1.2.3.4", 456, false); - EXPECT_CALL(ssl, uriSanPeerCertificate()).Times(2).WillRepeatedly(Return("bar")); + const std::vector sans{"bar", "baz"}; + EXPECT_CALL(ssl, uriSanPeerCertificate()).Times(2).WillRepeatedly(Return(sans)); EXPECT_CALL(Const(conn), ssl()).Times(2).WillRepeatedly(Return(&ssl)); EXPECT_CALL(conn, localAddress()).Times(2).WillRepeatedly(ReturnRef(addr)); diff --git a/test/extensions/filters/http/lua/lua_filter_test.cc b/test/extensions/filters/http/lua/lua_filter_test.cc index 2366a3a2e98ff..cebe65610dff0 100644 --- a/test/extensions/filters/http/lua/lua_filter_test.cc +++ b/test/extensions/filters/http/lua/lua_filter_test.cc @@ -96,7 +96,7 @@ class LuaHttpFilterTest : public testing::Test { Http::MockStreamDecoderFilterCallbacks decoder_callbacks_; Http::MockStreamEncoderFilterCallbacks encoder_callbacks_; envoy::api::v2::core::Metadata metadata_; - NiceMock ssl_; + NiceMock ssl_; NiceMock connection_; NiceMock stream_info_; diff --git a/test/extensions/filters/network/client_ssl_auth/client_ssl_auth_test.cc b/test/extensions/filters/network/client_ssl_auth/client_ssl_auth_test.cc index dce254914ad3d..36667d24dc0b4 100644 --- a/test/extensions/filters/network/client_ssl_auth/client_ssl_auth_test.cc +++ b/test/extensions/filters/network/client_ssl_auth/client_ssl_auth_test.cc @@ -115,7 +115,7 @@ class ClientSslAuthFilterTest : public testing::Test { std::unique_ptr instance_; Event::MockTimer* interval_timer_; Http::AsyncClient::Callbacks* callbacks_; - Ssl::MockConnection ssl_; + Ssl::MockConnectionInfo ssl_; Stats::IsolatedStoreImpl stats_store_; NiceMock random_; Api::ApiPtr api_; diff --git a/test/extensions/transport_sockets/tls/ssl_socket_test.cc b/test/extensions/transport_sockets/tls/ssl_socket_test.cc index 0c529582d5795..3851df81a4921 100644 --- a/test/extensions/transport_sockets/tls/ssl_socket_test.cc +++ b/test/extensions/transport_sockets/tls/ssl_socket_test.cc @@ -60,7 +60,9 @@ namespace { */ class TestUtilOptionsBase { public: - const std::string& expectedClientCertUri() const { return expected_client_cert_uri_; } + const std::vector& expectedClientCertUri() const { + return expected_client_cert_uri_; + } const std::string& expectedServerStats() const { return expected_server_stats_; } bool expectSuccess() const { return expect_success_; } Network::Address::IpVersion version() const { return version_; } @@ -70,7 +72,7 @@ class TestUtilOptionsBase { : expect_success_(expect_success), version_(version) {} void setExpectedClientCertUri(const std::string& expected_client_cert_uri) { - expected_client_cert_uri_ = expected_client_cert_uri; + expected_client_cert_uri_ = {expected_client_cert_uri}; } void setExpectedServerStats(const std::string& expected_server_stats) { @@ -82,7 +84,7 @@ class TestUtilOptionsBase { const Network::Address::IpVersion version_; std::string expected_server_stats_; - std::string expected_client_cert_uri_; + std::vector expected_client_cert_uri_; }; /** @@ -136,11 +138,11 @@ class TestUtilOptions : public TestUtilOptionsBase { const std::string& expectedDigest() const { return expected_digest_; } TestUtilOptions& setExpectedLocalUri(const std::string& expected_local_uri) { - expected_local_uri_ = expected_local_uri; + expected_local_uri_ = {expected_local_uri}; return *this; } - const std::string& expectedLocalUri() const { return expected_local_uri_; } + const std::vector& expectedLocalUri() const { return expected_local_uri_; } TestUtilOptions& setExpectedSerialNumber(const std::string& expected_serial_number) { expected_serial_number_ = expected_serial_number; @@ -202,7 +204,7 @@ class TestUtilOptions : public TestUtilOptionsBase { bool expect_no_cert_; bool expect_no_cert_chain_; std::string expected_digest_; - std::string expected_local_uri_; + std::vector expected_local_uri_; std::string expected_serial_number_; std::string expected_subjectl_; std::string expected_local_subject_; diff --git a/test/mocks/network/connection.h b/test/mocks/network/connection.h index 3b258b72aac16..672986a77ebb0 100644 --- a/test/mocks/network/connection.h +++ b/test/mocks/network/connection.h @@ -67,7 +67,7 @@ class MockConnection : public Connection, public MockConnectionBase { MOCK_CONST_METHOD0(remoteAddress, const Address::InstanceConstSharedPtr&()); MOCK_CONST_METHOD0(localAddress, const Address::InstanceConstSharedPtr&()); MOCK_METHOD1(setConnectionStats, void(const ConnectionStats& stats)); - MOCK_CONST_METHOD0(ssl, const Ssl::Connection*()); + MOCK_CONST_METHOD0(ssl, const Ssl::ConnectionInfo*()); MOCK_CONST_METHOD0(requestedServerName, absl::string_view()); MOCK_CONST_METHOD0(state, State()); MOCK_METHOD2(write, void(Buffer::Instance& data, bool end_stream)); @@ -111,7 +111,7 @@ class MockClientConnection : public ClientConnection, public MockConnectionBase MOCK_CONST_METHOD0(remoteAddress, const Address::InstanceConstSharedPtr&()); MOCK_CONST_METHOD0(localAddress, const Address::InstanceConstSharedPtr&()); MOCK_METHOD1(setConnectionStats, void(const ConnectionStats& stats)); - MOCK_CONST_METHOD0(ssl, const Ssl::Connection*()); + MOCK_CONST_METHOD0(ssl, const Ssl::ConnectionInfo*()); MOCK_CONST_METHOD0(requestedServerName, absl::string_view()); MOCK_CONST_METHOD0(state, State()); MOCK_METHOD2(write, void(Buffer::Instance& data, bool end_stream)); diff --git a/test/mocks/network/mocks.h b/test/mocks/network/mocks.h index 56ebfa5b197fd..e2dca03cea268 100644 --- a/test/mocks/network/mocks.h +++ b/test/mocks/network/mocks.h @@ -372,7 +372,7 @@ class MockTransportSocket : public TransportSocket { MOCK_METHOD1(doRead, IoResult(Buffer::Instance& buffer)); MOCK_METHOD2(doWrite, IoResult(Buffer::Instance& buffer, bool end_stream)); MOCK_METHOD0(onConnected, void()); - MOCK_CONST_METHOD0(ssl, const Ssl::Connection*()); + MOCK_CONST_METHOD0(ssl, const Ssl::ConnectionInfo*()); TransportSocketCallbacks* callbacks_{}; }; diff --git a/test/mocks/ssl/mocks.cc b/test/mocks/ssl/mocks.cc index 30da3c11bf3d0..f19c75217d63d 100644 --- a/test/mocks/ssl/mocks.cc +++ b/test/mocks/ssl/mocks.cc @@ -6,8 +6,8 @@ namespace Ssl { MockContextManager::MockContextManager() {} MockContextManager::~MockContextManager() {} -MockConnection::MockConnection() {} -MockConnection::~MockConnection() {} +MockConnectionInfo::MockConnectionInfo() {} +MockConnectionInfo::~MockConnectionInfo() {} MockClientContext::MockClientContext() {} MockClientContext::~MockClientContext() {} diff --git a/test/mocks/ssl/mocks.h b/test/mocks/ssl/mocks.h index bb61c1b6e7ef8..e6dc9b4d13151 100644 --- a/test/mocks/ssl/mocks.h +++ b/test/mocks/ssl/mocks.h @@ -30,17 +30,17 @@ class MockContextManager : public ContextManager { MOCK_METHOD1(iterateContexts, void(std::function callback)); }; -class MockConnection : public Connection { +class MockConnectionInfo : public ConnectionInfo { public: - MockConnection(); - ~MockConnection(); + MockConnectionInfo(); + ~MockConnectionInfo(); MOCK_CONST_METHOD0(peerCertificatePresented, bool()); - MOCK_CONST_METHOD0(uriSanLocalCertificate, std::string()); + MOCK_CONST_METHOD0(uriSanLocalCertificate, std::vector()); MOCK_CONST_METHOD0(sha256PeerCertificateDigest, std::string&()); MOCK_CONST_METHOD0(serialNumberPeerCertificate, std::string()); MOCK_CONST_METHOD0(subjectPeerCertificate, std::string()); - MOCK_CONST_METHOD0(uriSanPeerCertificate, std::string()); + MOCK_CONST_METHOD0(uriSanPeerCertificate, std::vector()); MOCK_CONST_METHOD0(subjectLocalCertificate, std::string()); MOCK_CONST_METHOD0(urlEncodedPemEncodedPeerCertificate, std::string&()); MOCK_CONST_METHOD0(urlEncodedPemEncodedPeerCertificateChain, std::string&()); diff --git a/test/mocks/stream_info/mocks.cc b/test/mocks/stream_info/mocks.cc index 0f8b29d39d7fc..08c0bd556a09f 100644 --- a/test/mocks/stream_info/mocks.cc +++ b/test/mocks/stream_info/mocks.cc @@ -62,6 +62,12 @@ MockStreamInfo::MockStreamInfo() downstream_remote_address_ = downstream_remote_address; })); ON_CALL(*this, downstreamRemoteAddress()).WillByDefault(ReturnRef(downstream_remote_address_)); + ON_CALL(*this, setDownstreamSslConnection(_)) + .WillByDefault(Invoke( + [this](const auto* connection_info) { downstream_connection_info_ = connection_info; })); + ON_CALL(*this, downstreamSslConnection()).WillByDefault(Invoke([this]() { + return downstream_connection_info_; + })); ON_CALL(*this, protocol()).WillByDefault(ReturnPointee(&protocol_)); ON_CALL(*this, responseCode()).WillByDefault(ReturnPointee(&response_code_)); ON_CALL(*this, addBytesReceived(_)).WillByDefault(Invoke([this](uint64_t bytes_received) { diff --git a/test/mocks/stream_info/mocks.h b/test/mocks/stream_info/mocks.h index 8a364f6eaf7c5..a28db9bd865fe 100644 --- a/test/mocks/stream_info/mocks.h +++ b/test/mocks/stream_info/mocks.h @@ -61,6 +61,8 @@ class MockStreamInfo : public StreamInfo { const Network::Address::InstanceConstSharedPtr&()); MOCK_METHOD1(setDownstreamRemoteAddress, void(const Network::Address::InstanceConstSharedPtr&)); MOCK_CONST_METHOD0(downstreamRemoteAddress, const Network::Address::InstanceConstSharedPtr&()); + MOCK_METHOD1(setDownstreamSslConnection, void(const Ssl::ConnectionInfo*)); + MOCK_CONST_METHOD0(downstreamSslConnection, const Ssl::ConnectionInfo*()); MOCK_CONST_METHOD0(routeEntry, const Router::RouteEntry*()); MOCK_METHOD0(dynamicMetadata, envoy::api::v2::core::Metadata&()); MOCK_CONST_METHOD0(dynamicMetadata, const envoy::api::v2::core::Metadata&()); @@ -96,6 +98,7 @@ class MockStreamInfo : public StreamInfo { Network::Address::InstanceConstSharedPtr downstream_local_address_; Network::Address::InstanceConstSharedPtr downstream_direct_remote_address_; Network::Address::InstanceConstSharedPtr downstream_remote_address_; + const Ssl::ConnectionInfo* downstream_connection_info_{}; std::string requested_server_name_; std::string upstream_transport_failure_reason_; }; diff --git a/test/server/listener_manager_impl_test.cc b/test/server/listener_manager_impl_test.cc index b10e139e42df5..5c0cf8bc1ee6e 100644 --- a/test/server/listener_manager_impl_test.cc +++ b/test/server/listener_manager_impl_test.cc @@ -1593,7 +1593,7 @@ TEST_F(ListenerManagerImplWithRealFiltersTest, MultipleFilterChainWithSourceType transport_socket = filter_chain->transportSocketFactory().createTransportSocket(nullptr); ssl_socket = dynamic_cast(transport_socket.get()); auto uri = ssl_socket->uriSanLocalCertificate(); - EXPECT_EQ(uri, "spiffe://lyft.com/test-team"); + EXPECT_EQ(uri[0], "spiffe://lyft.com/test-team"); // EXTERNAL TLS client without "http/1.1" ALPN - using 3nd filter chain. filter_chain = findFilterChain(1234, true, "8.8.8.8", true, "", true, "tls", true, {}, true, @@ -1653,7 +1653,7 @@ TEST_F(ListenerManagerImplWithRealFiltersTest, MultipleFilterChainsWithDestinati auto ssl_socket = dynamic_cast(transport_socket.get()); auto uri = ssl_socket->uriSanLocalCertificate(); - EXPECT_EQ(uri, "spiffe://lyft.com/test-team"); + EXPECT_EQ(uri[0], "spiffe://lyft.com/test-team"); // IPv4 client connects to port 8080 - using 2nd filter chain. filter_chain = findFilterChain(8080, true, "127.0.0.1", true, "", true, "tls", true, {}, true, @@ -1685,7 +1685,7 @@ TEST_F(ListenerManagerImplWithRealFiltersTest, MultipleFilterChainsWithDestinati transport_socket = filter_chain->transportSocketFactory().createTransportSocket(nullptr); ssl_socket = dynamic_cast(transport_socket.get()); uri = ssl_socket->uriSanLocalCertificate(); - EXPECT_EQ(uri, "spiffe://lyft.com/test-team"); + EXPECT_EQ(uri[0], "spiffe://lyft.com/test-team"); } TEST_F(ListenerManagerImplWithRealFiltersTest, MultipleFilterChainsWithDestinationIPMatch) { @@ -1734,7 +1734,7 @@ TEST_F(ListenerManagerImplWithRealFiltersTest, MultipleFilterChainsWithDestinati auto ssl_socket = dynamic_cast(transport_socket.get()); auto uri = ssl_socket->uriSanLocalCertificate(); - EXPECT_EQ(uri, "spiffe://lyft.com/test-team"); + EXPECT_EQ(uri[0], "spiffe://lyft.com/test-team"); // IPv4 client connects to exact IP match - using 2nd filter chain. filter_chain = findFilterChain(1234, true, "192.168.0.1", true, "", true, "tls", true, {}, true, @@ -1766,7 +1766,7 @@ TEST_F(ListenerManagerImplWithRealFiltersTest, MultipleFilterChainsWithDestinati transport_socket = filter_chain->transportSocketFactory().createTransportSocket(nullptr); ssl_socket = dynamic_cast(transport_socket.get()); uri = ssl_socket->uriSanLocalCertificate(); - EXPECT_EQ(uri, "spiffe://lyft.com/test-team"); + EXPECT_EQ(uri[0], "spiffe://lyft.com/test-team"); } TEST_F(ListenerManagerImplWithRealFiltersTest, MultipleFilterChainsWithServerNamesMatch) { @@ -1824,7 +1824,7 @@ TEST_F(ListenerManagerImplWithRealFiltersTest, MultipleFilterChainsWithServerNam auto ssl_socket = dynamic_cast(transport_socket.get()); auto uri = ssl_socket->uriSanLocalCertificate(); - EXPECT_EQ(uri, "spiffe://lyft.com/test-team"); + EXPECT_EQ(uri[0], "spiffe://lyft.com/test-team"); // TLS client with exact SNI match - using 2nd filter chain. filter_chain = findFilterChain(1234, true, "127.0.0.1", true, "server1.example.com", true, "tls",