From a34fde7f1a846c14ac9daaa318629562b4b565ab Mon Sep 17 00:00:00 2001 From: Chris Roche Date: Tue, 8 May 2018 16:41:22 -0700 Subject: [PATCH] auth: AttributeContext utilities Signed-off-by: Chris Roche --- source/extensions/filters/common/auth/BUILD | 22 ++++ .../filters/common/auth/attribute_context.cc | 91 ++++++++++++++ .../filters/common/auth/attribute_context.h | 38 ++++++ .../extensions/filters/common/ext_authz/BUILD | 3 +- .../common/ext_authz/ext_authz_impl.cc | 114 ++---------------- .../filters/common/ext_authz/ext_authz_impl.h | 13 -- .../common/ext_authz/ext_authz_impl_test.cc | 4 +- 7 files changed, 162 insertions(+), 123 deletions(-) create mode 100644 source/extensions/filters/common/auth/BUILD create mode 100644 source/extensions/filters/common/auth/attribute_context.cc create mode 100644 source/extensions/filters/common/auth/attribute_context.h diff --git a/source/extensions/filters/common/auth/BUILD b/source/extensions/filters/common/auth/BUILD new file mode 100644 index 000000000000..97a3075480b8 --- /dev/null +++ b/source/extensions/filters/common/auth/BUILD @@ -0,0 +1,22 @@ +licenses(["notice"]) # Apache 2 + +load( + "//bazel:envoy_build_system.bzl", + "envoy_cc_library", + "envoy_package", +) + +envoy_package() + +envoy_cc_library( + name = "attribute_context_lib", + hdrs = ["attribute_context.h"], + srcs = ["attribute_context.cc"], + deps = [ + "//include/envoy/http:filter_interface", + "//include/envoy/http:header_map_interface", + "//source/common/http:utility_lib", + "//source/common/network:utility_lib", + "@envoy_api//envoy/service/auth/v2alpha:attribute_context_cc", + ], +) diff --git a/source/extensions/filters/common/auth/attribute_context.cc b/source/extensions/filters/common/auth/attribute_context.cc new file mode 100644 index 000000000000..9ec8ca259adc --- /dev/null +++ b/source/extensions/filters/common/auth/attribute_context.cc @@ -0,0 +1,91 @@ +#include "extensions/filters/common/auth/attribute_context.h" + +#include "common/http/utility.h" +#include "common/network/utility.h" + +namespace Envoy { +namespace Extensions { +namespace Filters { +namespace Common { +namespace Auth { + +void AttributeContextUtils::setSourcePeer(envoy::service::auth::v2alpha::AttributeContext& context, + const Network::Connection& connection, + const std::string& service) { + setPeer(*context.mutable_source(), connection, service, false); +} + +void AttributeContextUtils::setDestinationPeer( + envoy::service::auth::v2alpha::AttributeContext& context, + const Network::Connection& connection) { + setPeer(*context.mutable_destination(), connection, "", true); +} + +void AttributeContextUtils::setPeer(envoy::service::auth::v2alpha::AttributeContext_Peer& peer, + const Network::Connection& connection, + const std::string& service, const bool local) { + + auto addr = local ? connection.localAddress() : connection.remoteAddress(); + Envoy::Network::Utility::addressToProtobufAddress(*addr, *peer.mutable_address()); + + if (!service.empty()) { + peer.set_service(service); + } + + auto ssl = const_cast(connection.ssl()); + if (ssl) { + std::string principal = local ? ssl->uriSanLocalCertificate() : ssl->uriSanPeerCertificate(); + if (principal.empty()) { + principal = local ? ssl->subjectLocalCertificate() : ssl->subjectPeerCertificate(); + } + peer.set_principal(principal); + } +} + +void AttributeContextUtils::setHttpRequest( + envoy::service::auth::v2alpha::AttributeContext& context, + const Envoy::Http::StreamDecoderFilterCallbacks* callbacks, + const Envoy::Http::HeaderMap& headers) { + + auto req = context.mutable_request()->mutable_http(); + auto sdfc = const_cast(callbacks); + + auto start = ProtobufUtil::TimeUtil::MicrosecondsToTimestamp( + sdfc->requestInfo().startTime().time_since_epoch().count()); + context.mutable_request()->mutable_time()->MergeFrom(start); + + auto proto = sdfc->requestInfo().protocol(); + if (proto) { + req->set_protocol(Envoy::Http::Utility::getProtocolString(proto.value())); + } + + req->set_id(std::to_string(sdfc->streamId())); + req->set_size(sdfc->requestInfo().bytesReceived()); + + req->set_method(getHeaderStr(headers.Method())); + req->set_path(getHeaderStr(headers.Path())); + req->set_host(getHeaderStr(headers.Host())); + req->set_scheme(getHeaderStr(headers.Scheme())); + // TODO(rodaine): add query & fragment fields + + auto mutable_headers = req->mutable_headers(); + headers.iterate( + [](const Envoy::Http::HeaderEntry& e, void* ctx) { + auto mutable_headers = static_cast< + Envoy::Protobuf::Map*>(ctx); + (*mutable_headers)[std::string(e.key().getStringView())] = + std::string(e.value().getStringView()); + return Envoy::Http::HeaderMap::Iterate::Continue; + }, + mutable_headers); +} + +std::string AttributeContextUtils::getHeaderStr(const Envoy::Http::HeaderEntry* entry) { + return entry ? std::string(entry->value().getStringView()) : ""; +} + +} // namespace Auth +} // namespace Common +} // namespace Filters +} // namespace Extensions +} // namespace Envoy diff --git a/source/extensions/filters/common/auth/attribute_context.h b/source/extensions/filters/common/auth/attribute_context.h new file mode 100644 index 000000000000..b6867327f8c4 --- /dev/null +++ b/source/extensions/filters/common/auth/attribute_context.h @@ -0,0 +1,38 @@ +#pragma once + +#include + +#include "envoy/http/filter.h" +#include "envoy/http/header_map.h" +#include "envoy/network/connection.h" +#include "envoy/service/auth/v2alpha/attribute_context.pb.h" + +namespace Envoy { +namespace Extensions { +namespace Filters { +namespace Common { +namespace Auth { + +class AttributeContextUtils { +public: + static void setSourcePeer(envoy::service::auth::v2alpha::AttributeContext& context, + const Network::Connection& connection, const std::string& service); + static void setDestinationPeer(envoy::service::auth::v2alpha::AttributeContext& context, + const Network::Connection& connection); + static void setHttpRequest(envoy::service::auth::v2alpha::AttributeContext& context, + const Envoy::Http::StreamDecoderFilterCallbacks* callbacks, + const Envoy::Http::HeaderMap& headers); + +private: + static void setPeer(envoy::service::auth::v2alpha::AttributeContext_Peer& peer, + const Network::Connection& connection, const std::string& service, + const bool local); + + static std::string getHeaderStr(const Envoy::Http::HeaderEntry* entry); +}; + +} // namespace Auth +} // namespace Common +} // namespace Filters +} // namespace Extensions +} // namespace Envoy diff --git a/source/extensions/filters/common/ext_authz/BUILD b/source/extensions/filters/common/ext_authz/BUILD index c43ff4924e8b..67a0be17d89a 100644 --- a/source/extensions/filters/common/ext_authz/BUILD +++ b/source/extensions/filters/common/ext_authz/BUILD @@ -36,9 +36,8 @@ envoy_cc_library( "//source/common/common:assert_lib", "//source/common/grpc:async_client_lib", "//source/common/http:headers_lib", - "//source/common/http:utility_lib", - "//source/common/network:utility_lib", "//source/common/protobuf", "//source/common/tracing:http_tracer_lib", + "//source/extensions/filters/common/auth:attribute_context_lib", ], ) diff --git a/source/extensions/filters/common/ext_authz/ext_authz_impl.cc b/source/extensions/filters/common/ext_authz/ext_authz_impl.cc index 49fe65c1385b..733a439f7112 100644 --- a/source/extensions/filters/common/ext_authz/ext_authz_impl.cc +++ b/source/extensions/filters/common/ext_authz/ext_authz_impl.cc @@ -11,9 +11,8 @@ #include "common/common/assert.h" #include "common/grpc/async_client_impl.h" #include "common/http/headers.h" -#include "common/http/utility.h" -#include "common/network/utility.h" #include "common/protobuf/protobuf.h" +#include "extensions/filters/common/auth/attribute_context.h" namespace Envoy { namespace Extensions { @@ -67,104 +66,6 @@ void GrpcClientImpl::onFailure(Grpc::Status::GrpcStatus status, const std::strin callbacks_ = nullptr; } -void CheckRequestUtils::setAttrContextPeer( - envoy::service::auth::v2alpha::AttributeContext_Peer& peer, - const Network::Connection& connection, const std::string& service, const bool local) { - - // Set the address - auto addr = peer.mutable_address(); - if (local) { - Envoy::Network::Utility::addressToProtobufAddress(*connection.localAddress(), *addr); - } else { - Envoy::Network::Utility::addressToProtobufAddress(*connection.remoteAddress(), *addr); - } - - // 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()); - if (ssl != nullptr) { - if (local) { - peer.set_principal(ssl->uriSanLocalCertificate()); - - if (peer.principal().empty()) { - peer.set_principal(ssl->subjectLocalCertificate()); - } - } else { - peer.set_principal(ssl->uriSanPeerCertificate()); - - if (peer.principal().empty()) { - peer.set_principal(ssl->subjectPeerCertificate()); - } - } - } - - if (!service.empty()) { - peer.set_service(service); - } -} - -std::string CheckRequestUtils::getHeaderStr(const Envoy::Http::HeaderEntry* entry) { - if (entry) { - // TODO(jmarantz): plumb absl::string_view further here; there's no need - // to allocate a temp string in the local uses. - return std::string(entry->value().getStringView()); - } - return ""; -} - -void CheckRequestUtils::setHttpRequest( - ::envoy::service::auth::v2alpha::AttributeContext_HttpRequest& httpreq, - const Envoy::Http::StreamDecoderFilterCallbacks* callbacks, - const Envoy::Http::HeaderMap& headers) { - - // Set id - // The streamId is not qualified as a const. Although it is as it does not modify the object. - Envoy::Http::StreamDecoderFilterCallbacks* sdfc = - const_cast(callbacks); - httpreq.set_id(std::to_string(sdfc->streamId())); - - // Set method - httpreq.set_method(getHeaderStr(headers.Method())); - // Set path - httpreq.set_path(getHeaderStr(headers.Path())); - // Set host - httpreq.set_host(getHeaderStr(headers.Host())); - // Set scheme - httpreq.set_scheme(getHeaderStr(headers.Scheme())); - - // Set size - // need to convert to google buffer 64t; - httpreq.set_size(sdfc->requestInfo().bytesReceived()); - - // Set protocol - if (sdfc->requestInfo().protocol()) { - httpreq.set_protocol( - Envoy::Http::Utility::getProtocolString(sdfc->requestInfo().protocol().value())); - } - - // Fill in the headers - auto mutable_headers = httpreq.mutable_headers(); - headers.iterate( - [](const Envoy::Http::HeaderEntry& e, void* ctx) { - Envoy::Protobuf::Map* - mutable_headers = static_cast< - Envoy::Protobuf::Map*>( - ctx); - (*mutable_headers)[std::string(e.key().getStringView())] = - std::string(e.value().getStringView()); - return Envoy::Http::HeaderMap::Iterate::Continue; - }, - mutable_headers); -} - -void CheckRequestUtils::setAttrContextRequest( - ::envoy::service::auth::v2alpha::AttributeContext_Request& req, - const Envoy::Http::StreamDecoderFilterCallbacks* callbacks, - const Envoy::Http::HeaderMap& headers) { - setHttpRequest(*req.mutable_http(), callbacks, headers); -} - void CheckRequestUtils::createHttpCheck(const Envoy::Http::StreamDecoderFilterCallbacks* callbacks, const Envoy::Http::HeaderMap& headers, envoy::service::auth::v2alpha::CheckRequest& request) { @@ -174,11 +75,12 @@ void CheckRequestUtils::createHttpCheck(const Envoy::Http::StreamDecoderFilterCa Envoy::Http::StreamDecoderFilterCallbacks* cb = const_cast(callbacks); - const std::string service = getHeaderStr(headers.EnvoyDownstreamServiceCluster()); + auto hdr = headers.EnvoyDownstreamServiceCluster(); + std::string service = hdr ? std::string(hdr->value().getStringView()) : ""; - setAttrContextPeer(*attrs->mutable_source(), *cb->connection(), service, false); - setAttrContextPeer(*attrs->mutable_destination(), *cb->connection(), "", true); - setAttrContextRequest(*attrs->mutable_request(), callbacks, headers); + Auth::AttributeContextUtils::setSourcePeer(*attrs, *cb->connection(), service); + Auth::AttributeContextUtils::setDestinationPeer(*attrs, *cb->connection()); + Auth::AttributeContextUtils::setHttpRequest(*attrs, callbacks, headers); } void CheckRequestUtils::createTcpCheck(const Network::ReadFilterCallbacks* callbacks, @@ -187,8 +89,8 @@ void CheckRequestUtils::createTcpCheck(const Network::ReadFilterCallbacks* callb auto attrs = request.mutable_attributes(); Network::ReadFilterCallbacks* cb = const_cast(callbacks); - setAttrContextPeer(*attrs->mutable_source(), cb->connection(), "", false); - setAttrContextPeer(*attrs->mutable_destination(), cb->connection(), "", true); + Auth::AttributeContextUtils::setSourcePeer(*attrs, cb->connection(), ""); + Auth::AttributeContextUtils::setDestinationPeer(*attrs, cb->connection()); } } // namespace ExtAuthz diff --git a/source/extensions/filters/common/ext_authz/ext_authz_impl.h b/source/extensions/filters/common/ext_authz/ext_authz_impl.h index f3266c4875b2..11f635add0da 100644 --- a/source/extensions/filters/common/ext_authz/ext_authz_impl.h +++ b/source/extensions/filters/common/ext_authz/ext_authz_impl.h @@ -98,19 +98,6 @@ class CheckRequestUtils { */ static void createTcpCheck(const Network::ReadFilterCallbacks* callbacks, envoy::service::auth::v2alpha::CheckRequest& request); - -private: - static void setAttrContextPeer(envoy::service::auth::v2alpha::AttributeContext_Peer& peer, - const Network::Connection& connection, const std::string& service, - const bool local); - static void setHttpRequest(::envoy::service::auth::v2alpha::AttributeContext_HttpRequest& httpreq, - const Envoy::Http::StreamDecoderFilterCallbacks* callbacks, - const Envoy::Http::HeaderMap& headers); - static void setAttrContextRequest(::envoy::service::auth::v2alpha::AttributeContext_Request& req, - const Envoy::Http::StreamDecoderFilterCallbacks* callbacks, - const Envoy::Http::HeaderMap& headers); - static std::string getHeaderStr(const Envoy::Http::HeaderEntry* entry); - static Envoy::Http::HeaderMap::Iterate fillHttpHeaders(const Envoy::Http::HeaderEntry&, void*); }; } // namespace ExtAuthz diff --git a/test/extensions/filters/common/ext_authz/ext_authz_impl_test.cc b/test/extensions/filters/common/ext_authz/ext_authz_impl_test.cc index f2f2ded6e23c..2928bf1b0fc8 100644 --- a/test/extensions/filters/common/ext_authz/ext_authz_impl_test.cc +++ b/test/extensions/filters/common/ext_authz/ext_authz_impl_test.cc @@ -21,6 +21,7 @@ #include "gmock/gmock.h" #include "gtest/gtest.h" +using testing::_; using testing::AtLeast; using testing::Invoke; using testing::Ref; @@ -28,7 +29,6 @@ using testing::Return; using testing::ReturnPointee; using testing::ReturnRef; using testing::WithArg; -using testing::_; namespace Envoy { namespace Extensions { @@ -163,7 +163,7 @@ TEST_F(CheckRequestUtilsTest, BasicHttp) { EXPECT_CALL(Const(connection_), ssl()).Times(2).WillRepeatedly(Return(&ssl_)); EXPECT_CALL(callbacks_, streamId()).WillOnce(Return(0)); EXPECT_CALL(callbacks_, requestInfo()).Times(3).WillRepeatedly(ReturnRef(req_info_)); - EXPECT_CALL(req_info_, protocol()).Times(2).WillRepeatedly(ReturnPointee(&protocol_)); + EXPECT_CALL(req_info_, protocol()).WillOnce(ReturnPointee(&protocol_)); CheckRequestUtils::createHttpCheck(&callbacks_, headers, request); }