diff --git a/docs/root/configuration/http/http_filters/ext_authz_filter.rst b/docs/root/configuration/http/http_filters/ext_authz_filter.rst index 232093c7c8ee..8c3096701ddb 100644 --- a/docs/root/configuration/http/http_filters/ext_authz_filter.rst +++ b/docs/root/configuration/http/http_filters/ext_authz_filter.rst @@ -190,6 +190,9 @@ from the authorization server that match the configured :ref:`dynamic_metadata_from_headers `, if set. For every response header that matches, the filter will emit dynamic metadata whose key is the name of the matched header and whose value is the value of the matched header. +Both the HTTP and gRPC external authorization filters support a dynamic metadata field called ``ext_authz_duration`` which records the time it takes to complete an authorization request in milliseconds. +This field will not be populated if the request does not complete. + Runtime ------- The fraction of requests for which the filter is enabled can be configured via the :ref:`runtime_key diff --git a/source/extensions/filters/http/ext_authz/ext_authz.cc b/source/extensions/filters/http/ext_authz/ext_authz.cc index 9dbb86c01563..f0953903f3b4 100644 --- a/source/extensions/filters/http/ext_authz/ext_authz.cc +++ b/source/extensions/filters/http/ext_authz/ext_authz.cc @@ -1,5 +1,7 @@ #include "source/extensions/filters/http/ext_authz/ext_authz.h" +#include + #include "envoy/config/core/v3/base.pb.h" #include "source/common/common/assert.h" @@ -58,6 +60,9 @@ void Filter::initiateCall(const Http::RequestHeaderMap& headers, config_->includePeerCertificate(), config_->destinationLabels()); ENVOY_STREAM_LOG(trace, "ext_authz filter calling authorization server", *decoder_callbacks_); + // Store start time of ext_authz filter call + start_time_ = decoder_callbacks_->dispatcher().timeSource().monotonicTime(); + state_ = State::Calling; filter_return_ = FilterReturn::StopDecoding; // Don't let the filter chain continue as we are // going to invoke check call. @@ -210,6 +215,16 @@ void Filter::onComplete(Filters::Common::ExtAuthz::ResponsePtr&& response) { Stats::StatName empty_stat_name; if (!response->dynamic_metadata.fields().empty()) { + // Add duration of call to dynamic metadata if applicable + if (start_time_.has_value() && response->status == CheckStatus::OK) { + ProtobufWkt::Value ext_authz_duration_value; + auto duration = + decoder_callbacks_->dispatcher().timeSource().monotonicTime() - start_time_.value(); + ext_authz_duration_value.set_number_value( + std::chrono::duration_cast(duration).count()); + (*response->dynamic_metadata.mutable_fields())["ext_authz_duration"] = + ext_authz_duration_value; + } decoder_callbacks_->streamInfo().setDynamicMetadata("envoy.filters.http.ext_authz", response->dynamic_metadata); } diff --git a/source/extensions/filters/http/ext_authz/ext_authz.h b/source/extensions/filters/http/ext_authz/ext_authz.h index 80c934e48c90..9f25ffb6de0d 100644 --- a/source/extensions/filters/http/ext_authz/ext_authz.h +++ b/source/extensions/filters/http/ext_authz/ext_authz.h @@ -269,6 +269,7 @@ class Filter : public Logger::Loggable, void onComplete(Filters::Common::ExtAuthz::ResponsePtr&&) override; private: + absl::optional start_time_; void addResponseHeaders(Http::HeaderMap& header_map, const Http::HeaderVector& headers); void initiateCall(const Http::RequestHeaderMap& headers, const Router::RouteConstSharedPtr& route); diff --git a/source/extensions/filters/network/ext_authz/ext_authz.cc b/source/extensions/filters/network/ext_authz/ext_authz.cc index 4f9da9175fc1..0cb7c17c4216 100644 --- a/source/extensions/filters/network/ext_authz/ext_authz.cc +++ b/source/extensions/filters/network/ext_authz/ext_authz.cc @@ -1,5 +1,6 @@ #include "source/extensions/filters/network/ext_authz/ext_authz.h" +#include #include #include @@ -24,7 +25,8 @@ void Filter::callCheck() { Filters::Common::ExtAuthz::CheckRequestUtils::createTcpCheck(filter_callbacks_, check_request_, config_->includePeerCertificate(), config_->destinationLabels()); - + // Store start time of ext_authz filter call + start_time_ = filter_callbacks_->connection().dispatcher().timeSource().monotonicTime(); status_ = Status::Calling; config_->stats().active_.inc(); config_->stats().total_.inc(); @@ -74,6 +76,16 @@ void Filter::onComplete(Filters::Common::ExtAuthz::ResponsePtr&& response) { switch (response->status) { case Filters::Common::ExtAuthz::CheckStatus::OK: config_->stats().ok_.inc(); + // Add duration of call to dynamic metadata if applicable + if (start_time_.has_value()) { + ProtobufWkt::Value ext_authz_duration_value; + auto duration = filter_callbacks_->connection().dispatcher().timeSource().monotonicTime() - + start_time_.value(); + ext_authz_duration_value.set_number_value( + std::chrono::duration_cast(duration).count()); + (*response->dynamic_metadata.mutable_fields())["ext_authz_duration"] = + ext_authz_duration_value; + } break; case Filters::Common::ExtAuthz::CheckStatus::Error: config_->stats().error_.inc(); @@ -84,6 +96,7 @@ void Filter::onComplete(Filters::Common::ExtAuthz::ResponsePtr&& response) { } if (!response->dynamic_metadata.fields().empty()) { + filter_callbacks_->connection().streamInfo().setDynamicMetadata( NetworkFilterNames::get().ExtAuthorization, response->dynamic_metadata); } diff --git a/source/extensions/filters/network/ext_authz/ext_authz.h b/source/extensions/filters/network/ext_authz/ext_authz.h index be03b305393c..acf44f3cead8 100644 --- a/source/extensions/filters/network/ext_authz/ext_authz.h +++ b/source/extensions/filters/network/ext_authz/ext_authz.h @@ -134,6 +134,7 @@ class Filter : public Network::ReadFilter, bool filterEnabled(const envoy::config::core::v3::Metadata& metadata) { return config_->filterEnabledMetadata(metadata); } + absl::optional start_time_; ConfigSharedPtr config_; Filters::Common::ExtAuthz::ClientPtr client_; diff --git a/test/extensions/filters/http/ext_authz/ext_authz_test.cc b/test/extensions/filters/http/ext_authz/ext_authz_test.cc index 20ecd4331a11..314a1c9f328a 100644 --- a/test/extensions/filters/http/ext_authz/ext_authz_test.cc +++ b/test/extensions/filters/http/ext_authz/ext_authz_test.cc @@ -1,3 +1,4 @@ +#include #include #include #include @@ -59,13 +60,13 @@ template class HttpFilterTestBase : public T { "ext_authz_prefix", bootstrap_)); client_ = new Filters::Common::ExtAuthz::MockClient(); filter_ = std::make_unique(config_, Filters::Common::ExtAuthz::ClientPtr{client_}); - filter_->setDecoderFilterCallbacks(filter_callbacks_); + filter_->setDecoderFilterCallbacks(decoder_filter_callbacks_); filter_->setEncoderFilterCallbacks(encoder_filter_callbacks_); addr_ = std::make_shared("1.2.3.4", 1111); } void prepareCheck() { - ON_CALL(filter_callbacks_, connection()).WillByDefault(Return(&connection_)); + ON_CALL(decoder_filter_callbacks_, connection()).WillByDefault(Return(&connection_)); connection_.stream_info_.downstream_connection_info_provider_->setRemoteAddress(addr_); connection_.stream_info_.downstream_connection_info_provider_->setLocalAddress(addr_); } @@ -96,7 +97,7 @@ template class HttpFilterTestBase : public T { const StreamInfo::StreamInfo&) -> void { callbacks.onComplete(std::move(response_ptr)); })); - EXPECT_CALL(filter_callbacks_, continueDecoding()).Times(0); + EXPECT_CALL(decoder_filter_callbacks_, continueDecoding()).Times(0); EXPECT_EQ(Http::FilterHeadersStatus::Continue, filter_->decodeHeaders(request_headers_, false)); EXPECT_EQ(Http::FilterDataStatus::Continue, filter_->decodeData(data_, false)); EXPECT_EQ(Http::FilterTrailersStatus::Continue, filter_->decodeTrailers(request_trailers_)); @@ -118,7 +119,7 @@ template class HttpFilterTestBase : public T { FilterConfigSharedPtr config_; Filters::Common::ExtAuthz::MockClient* client_; std::unique_ptr filter_; - NiceMock filter_callbacks_; + NiceMock decoder_filter_callbacks_; NiceMock encoder_filter_callbacks_; Filters::Common::ExtAuthz::RequestCallbacks* request_callbacks_; Http::TestRequestHeaderMapImpl request_headers_; @@ -151,7 +152,7 @@ class HttpFilterTestParam }; template -envoy::extensions::filters::http::ext_authz::v3::ExtAuthz GetFilterConfig() { +envoy::extensions::filters::http::ext_authz::v3::ExtAuthz getFilterConfig() { const std::string http_config = R"EOF( http_service: server_uri: @@ -175,8 +176,8 @@ envoy::extensions::filters::http::ext_authz::v3::ExtAuthz GetFilterConfig() { } INSTANTIATE_TEST_SUITE_P(ParameterizedFilterConfig, HttpFilterTestParam, - Values(&GetFilterConfig, &GetFilterConfig, - &GetFilterConfig, &GetFilterConfig)); + Values(&getFilterConfig, &getFilterConfig, + &getFilterConfig, &getFilterConfig)); // Test that the per route config is properly merged: more specific keys override previous keys. TEST_F(HttpFilterTest, MergeConfig) { @@ -230,11 +231,11 @@ TEST_F(HttpFilterTest, StatsWithPrefix) { )EOF", stat_prefix)); - EXPECT_EQ(0U, filter_callbacks_.clusterInfo() + EXPECT_EQ(0U, decoder_filter_callbacks_.clusterInfo() ->statsScope() .counterFromString(error_counter_name_with_prefix) .value()); - EXPECT_EQ(0U, filter_callbacks_.clusterInfo() + EXPECT_EQ(0U, decoder_filter_callbacks_.clusterInfo() ->statsScope() .counterFromString(error_counter_name_without_prefix) .value()); @@ -247,18 +248,18 @@ TEST_F(HttpFilterTest, StatsWithPrefix) { const StreamInfo::StreamInfo&) -> void { request_callbacks_ = &callbacks; })); EXPECT_EQ(Http::FilterHeadersStatus::StopAllIterationAndWatermark, filter_->decodeHeaders(request_headers_, false)); - EXPECT_CALL(filter_callbacks_, continueDecoding()).Times(0); - EXPECT_CALL(filter_callbacks_, encodeHeaders_(_, _)); + EXPECT_CALL(decoder_filter_callbacks_, continueDecoding()).Times(0); + EXPECT_CALL(decoder_filter_callbacks_, encodeHeaders_(_, _)); Filters::Common::ExtAuthz::Response response{}; response.status = Filters::Common::ExtAuthz::CheckStatus::Error; request_callbacks_->onComplete(std::make_unique(response)); - EXPECT_EQ(1U, filter_callbacks_.clusterInfo() + EXPECT_EQ(1U, decoder_filter_callbacks_.clusterInfo() ->statsScope() .counterFromString(error_counter_name_with_prefix) .value()); // The one without an additional prefix is not incremented, since it is not "defined". - EXPECT_EQ(0U, filter_callbacks_.clusterInfo() + EXPECT_EQ(0U, decoder_filter_callbacks_.clusterInfo() ->statsScope() .counterFromString(error_counter_name_without_prefix) .value()); @@ -277,7 +278,7 @@ TEST_F(HttpFilterTest, ErrorFailClose) { failure_mode_allow: false )EOF"); - ON_CALL(filter_callbacks_, connection()).WillByDefault(Return(&connection_)); + ON_CALL(decoder_filter_callbacks_, connection()).WillByDefault(Return(&connection_)); connection_.stream_info_.downstream_connection_info_provider_->setRemoteAddress(addr_); connection_.stream_info_.downstream_connection_info_provider_->setLocalAddress(addr_); EXPECT_CALL(*client_, check(_, _, _, _)) @@ -287,8 +288,8 @@ TEST_F(HttpFilterTest, ErrorFailClose) { const StreamInfo::StreamInfo&) -> void { request_callbacks_ = &callbacks; })); EXPECT_EQ(Http::FilterHeadersStatus::StopAllIterationAndWatermark, filter_->decodeHeaders(request_headers_, false)); - EXPECT_CALL(filter_callbacks_, continueDecoding()).Times(0); - EXPECT_CALL(filter_callbacks_, encodeHeaders_(_, true)) + EXPECT_CALL(decoder_filter_callbacks_, continueDecoding()).Times(0); + EXPECT_CALL(decoder_filter_callbacks_, encodeHeaders_(_, true)) .WillOnce(Invoke([&](const Http::ResponseHeaderMap& headers, bool) -> void { EXPECT_EQ(headers.getStatusValue(), std::to_string(enumToInt(Http::Code::Forbidden))); })); @@ -296,9 +297,10 @@ TEST_F(HttpFilterTest, ErrorFailClose) { Filters::Common::ExtAuthz::Response response{}; response.status = Filters::Common::ExtAuthz::CheckStatus::Error; request_callbacks_->onComplete(std::make_unique(response)); - EXPECT_EQ( - 1U, - filter_callbacks_.clusterInfo()->statsScope().counterFromString("ext_authz.error").value()); + EXPECT_EQ(1U, decoder_filter_callbacks_.clusterInfo() + ->statsScope() + .counterFromString("ext_authz.error") + .value()); EXPECT_EQ(1U, config_->stats().error_.value()); } @@ -316,7 +318,7 @@ TEST_F(HttpFilterTest, ErrorCustomStatusCode) { code: 503 )EOF"); - ON_CALL(filter_callbacks_, connection()).WillByDefault(Return(&connection_)); + ON_CALL(decoder_filter_callbacks_, connection()).WillByDefault(Return(&connection_)); connection_.stream_info_.downstream_connection_info_provider_->setRemoteAddress(addr_); connection_.stream_info_.downstream_connection_info_provider_->setLocalAddress(addr_); EXPECT_CALL(*client_, check(_, _, _, _)) @@ -326,8 +328,8 @@ TEST_F(HttpFilterTest, ErrorCustomStatusCode) { const StreamInfo::StreamInfo&) -> void { request_callbacks_ = &callbacks; })); EXPECT_EQ(Http::FilterHeadersStatus::StopAllIterationAndWatermark, filter_->decodeHeaders(request_headers_, false)); - EXPECT_CALL(filter_callbacks_, continueDecoding()).Times(0); - EXPECT_CALL(filter_callbacks_, encodeHeaders_(_, true)) + EXPECT_CALL(decoder_filter_callbacks_, continueDecoding()).Times(0); + EXPECT_CALL(decoder_filter_callbacks_, encodeHeaders_(_, true)) .WillOnce(Invoke([&](const Http::ResponseHeaderMap& headers, bool) -> void { EXPECT_EQ(headers.getStatusValue(), std::to_string(enumToInt(Http::Code::ServiceUnavailable))); @@ -336,11 +338,12 @@ TEST_F(HttpFilterTest, ErrorCustomStatusCode) { Filters::Common::ExtAuthz::Response response{}; response.status = Filters::Common::ExtAuthz::CheckStatus::Error; request_callbacks_->onComplete(std::make_unique(response)); - EXPECT_EQ( - 1U, - filter_callbacks_.clusterInfo()->statsScope().counterFromString("ext_authz.error").value()); + EXPECT_EQ(1U, decoder_filter_callbacks_.clusterInfo() + ->statsScope() + .counterFromString("ext_authz.error") + .value()); EXPECT_EQ(1U, config_->stats().error_.value()); - EXPECT_EQ("ext_authz_error", filter_callbacks_.details()); + EXPECT_EQ("ext_authz_error", decoder_filter_callbacks_.details()); } // Test when failure_mode_allow is set and the response from the authorization service is Error that @@ -356,7 +359,7 @@ TEST_F(HttpFilterTest, ErrorOpen) { failure_mode_allow: true )EOF"); - ON_CALL(filter_callbacks_, connection()).WillByDefault(Return(&connection_)); + ON_CALL(decoder_filter_callbacks_, connection()).WillByDefault(Return(&connection_)); connection_.stream_info_.downstream_connection_info_provider_->setRemoteAddress(addr_); connection_.stream_info_.downstream_connection_info_provider_->setLocalAddress(addr_); EXPECT_CALL(*client_, check(_, _, _, _)) @@ -366,14 +369,15 @@ TEST_F(HttpFilterTest, ErrorOpen) { const StreamInfo::StreamInfo&) -> void { request_callbacks_ = &callbacks; })); EXPECT_EQ(Http::FilterHeadersStatus::StopAllIterationAndWatermark, filter_->decodeHeaders(request_headers_, false)); - EXPECT_CALL(filter_callbacks_, continueDecoding()); + EXPECT_CALL(decoder_filter_callbacks_, continueDecoding()); Filters::Common::ExtAuthz::Response response{}; response.status = Filters::Common::ExtAuthz::CheckStatus::Error; request_callbacks_->onComplete(std::make_unique(response)); - EXPECT_EQ( - 1U, - filter_callbacks_.clusterInfo()->statsScope().counterFromString("ext_authz.error").value()); + EXPECT_EQ(1U, decoder_filter_callbacks_.clusterInfo() + ->statsScope() + .counterFromString("ext_authz.error") + .value()); EXPECT_EQ(1U, config_->stats().error_.value()); } @@ -390,7 +394,7 @@ TEST_F(HttpFilterTest, ImmediateErrorOpen) { failure_mode_allow: true )EOF"); - ON_CALL(filter_callbacks_, connection()).WillByDefault(Return(&connection_)); + ON_CALL(decoder_filter_callbacks_, connection()).WillByDefault(Return(&connection_)); connection_.stream_info_.downstream_connection_info_provider_->setRemoteAddress(addr_); connection_.stream_info_.downstream_connection_info_provider_->setLocalAddress(addr_); @@ -403,14 +407,15 @@ TEST_F(HttpFilterTest, ImmediateErrorOpen) { callbacks.onComplete(std::make_unique(response)); })); - EXPECT_CALL(filter_callbacks_, continueDecoding()).Times(0); + EXPECT_CALL(decoder_filter_callbacks_, continueDecoding()).Times(0); EXPECT_EQ(Http::FilterHeadersStatus::Continue, filter_->decodeHeaders(request_headers_, false)); EXPECT_EQ(Http::FilterDataStatus::Continue, filter_->decodeData(data_, false)); EXPECT_EQ(Http::FilterTrailersStatus::Continue, filter_->decodeTrailers(request_trailers_)); - EXPECT_EQ( - 1U, - filter_callbacks_.clusterInfo()->statsScope().counterFromString("ext_authz.error").value()); - EXPECT_EQ(1U, filter_callbacks_.clusterInfo() + EXPECT_EQ(1U, decoder_filter_callbacks_.clusterInfo() + ->statsScope() + .counterFromString("ext_authz.error") + .value()); + EXPECT_EQ(1U, decoder_filter_callbacks_.clusterInfo() ->statsScope() .counterFromString("ext_authz.failure_mode_allowed") .value()); @@ -448,8 +453,8 @@ TEST_F(HttpFilterTest, RequestDataIsTooLarge) { max_request_bytes: 10 )EOF"); - ON_CALL(filter_callbacks_, connection()).WillByDefault(Return(&connection_)); - EXPECT_CALL(filter_callbacks_, setDecoderBufferLimit(_)); + ON_CALL(decoder_filter_callbacks_, connection()).WillByDefault(Return(&connection_)); + EXPECT_CALL(decoder_filter_callbacks_, setDecoderBufferLimit(_)); EXPECT_CALL(*client_, check(_, _, _, _)).Times(0); EXPECT_EQ(Http::FilterHeadersStatus::StopIteration, @@ -478,9 +483,9 @@ TEST_F(HttpFilterTest, RequestDataWithPartialMessage) { allow_partial_message: true )EOF"); - ON_CALL(filter_callbacks_, connection()).WillByDefault(Return(&connection_)); - ON_CALL(filter_callbacks_, decodingBuffer()).WillByDefault(Return(&data_)); - EXPECT_CALL(filter_callbacks_, setDecoderBufferLimit(_)).Times(0); + ON_CALL(decoder_filter_callbacks_, connection()).WillByDefault(Return(&connection_)); + ON_CALL(decoder_filter_callbacks_, decodingBuffer()).WillByDefault(Return(&data_)); + EXPECT_CALL(decoder_filter_callbacks_, setDecoderBufferLimit(_)).Times(0); connection_.stream_info_.downstream_connection_info_provider_->setRemoteAddress(addr_); connection_.stream_info_.downstream_connection_info_provider_->setLocalAddress(addr_); EXPECT_CALL(*client_, check(_, _, _, _)); @@ -520,9 +525,9 @@ TEST_F(HttpFilterTest, RequestDataWithPartialMessageThenContinueDecoding) { allow_partial_message: true )EOF"); - ON_CALL(filter_callbacks_, connection()).WillByDefault(Return(&connection_)); - ON_CALL(filter_callbacks_, decodingBuffer()).WillByDefault(Return(&data_)); - EXPECT_CALL(filter_callbacks_, setDecoderBufferLimit(_)).Times(0); + ON_CALL(decoder_filter_callbacks_, connection()).WillByDefault(Return(&connection_)); + ON_CALL(decoder_filter_callbacks_, decodingBuffer()).WillByDefault(Return(&data_)); + EXPECT_CALL(decoder_filter_callbacks_, setDecoderBufferLimit(_)).Times(0); connection_.stream_info_.downstream_connection_info_provider_->setRemoteAddress(addr_); connection_.stream_info_.downstream_connection_info_provider_->setLocalAddress(addr_); @@ -533,7 +538,7 @@ TEST_F(HttpFilterTest, RequestDataWithPartialMessageThenContinueDecoding) { const envoy::service::auth::v3::CheckRequest&, Tracing::Span&, const StreamInfo::StreamInfo&) -> void { request_callbacks_ = &callbacks; })); - EXPECT_CALL(filter_callbacks_, continueDecoding()); + EXPECT_CALL(decoder_filter_callbacks_, continueDecoding()); EXPECT_EQ(Http::FilterHeadersStatus::StopIteration, filter_->decodeHeaders(request_headers_, false)); @@ -576,9 +581,9 @@ TEST_F(HttpFilterTest, RequestDataWithSmallBuffer) { allow_partial_message: true )EOF"); - ON_CALL(filter_callbacks_, connection()).WillByDefault(Return(&connection_)); - ON_CALL(filter_callbacks_, decodingBuffer()).WillByDefault(Return(&data_)); - EXPECT_CALL(filter_callbacks_, setDecoderBufferLimit(_)).Times(0); + ON_CALL(decoder_filter_callbacks_, connection()).WillByDefault(Return(&connection_)); + ON_CALL(decoder_filter_callbacks_, decodingBuffer()).WillByDefault(Return(&data_)); + EXPECT_CALL(decoder_filter_callbacks_, setDecoderBufferLimit(_)).Times(0); connection_.stream_info_.downstream_connection_info_provider_->setRemoteAddress(addr_); connection_.stream_info_.downstream_connection_info_provider_->setLocalAddress(addr_); EXPECT_CALL(*client_, check(_, _, _, _)); @@ -604,7 +609,7 @@ TEST_F(HttpFilterTest, AuthWithRequestData) { max_request_bytes: 10 )EOF"); - ON_CALL(filter_callbacks_, decodingBuffer()).WillByDefault(Return(&data_)); + ON_CALL(decoder_filter_callbacks_, decodingBuffer()).WillByDefault(Return(&data_)); prepareCheck(); envoy::service::auth::v3::CheckRequest check_request; @@ -642,7 +647,7 @@ TEST_F(HttpFilterTest, AuthWithNonUtf8RequestData) { pack_as_bytes: true )EOF"); - ON_CALL(filter_callbacks_, decodingBuffer()).WillByDefault(Return(&data_)); + ON_CALL(decoder_filter_callbacks_, decodingBuffer()).WillByDefault(Return(&data_)); prepareCheck(); envoy::service::auth::v3::CheckRequest check_request; @@ -814,8 +819,8 @@ TEST_F(HttpFilterTest, HeadersToRemoveRemovesHeadersExceptSpecialHeaders) { filter_->decodeHeaders(request_headers_, false)); EXPECT_EQ(Http::FilterDataStatus::Continue, filter_->decodeData(data_, false)); EXPECT_EQ(Http::FilterTrailersStatus::Continue, filter_->decodeTrailers(request_trailers_)); - EXPECT_CALL(filter_callbacks_, continueDecoding()); - EXPECT_CALL(filter_callbacks_.stream_info_, + EXPECT_CALL(decoder_filter_callbacks_, continueDecoding()); + EXPECT_CALL(decoder_filter_callbacks_.stream_info_, setResponseFlag(Envoy::StreamInfo::ResponseFlag::UnauthorizedExternalService)) .Times(0); @@ -864,13 +869,13 @@ TEST_F(HttpFilterTest, ClearCache) { Invoke([&](Filters::Common::ExtAuthz::RequestCallbacks& callbacks, const envoy::service::auth::v3::CheckRequest&, Tracing::Span&, const StreamInfo::StreamInfo&) -> void { request_callbacks_ = &callbacks; })); - EXPECT_CALL(filter_callbacks_, clearRouteCache()); + EXPECT_CALL(decoder_filter_callbacks_, clearRouteCache()); EXPECT_EQ(Http::FilterHeadersStatus::StopAllIterationAndWatermark, filter_->decodeHeaders(request_headers_, false)); EXPECT_EQ(Http::FilterDataStatus::Continue, filter_->decodeData(data_, false)); EXPECT_EQ(Http::FilterTrailersStatus::Continue, filter_->decodeTrailers(request_trailers_)); - EXPECT_CALL(filter_callbacks_, continueDecoding()); - EXPECT_CALL(filter_callbacks_.stream_info_, + EXPECT_CALL(decoder_filter_callbacks_, continueDecoding()); + EXPECT_CALL(decoder_filter_callbacks_.stream_info_, setResponseFlag(Envoy::StreamInfo::ResponseFlag::UnauthorizedExternalService)) .Times(0); @@ -881,8 +886,10 @@ TEST_F(HttpFilterTest, ClearCache) { response.headers_to_remove = std::vector{Http::LowerCaseString{"remove-me"}}; request_callbacks_->onComplete(std::make_unique(response)); - EXPECT_EQ( - 1U, filter_callbacks_.clusterInfo()->statsScope().counterFromString("ext_authz.ok").value()); + EXPECT_EQ(1U, decoder_filter_callbacks_.clusterInfo() + ->statsScope() + .counterFromString("ext_authz.ok") + .value()); EXPECT_EQ(1U, config_->stats().ok_.value()); } @@ -909,13 +916,13 @@ TEST_F(HttpFilterTest, ClearCacheRouteHeadersToAppendOnly) { Invoke([&](Filters::Common::ExtAuthz::RequestCallbacks& callbacks, const envoy::service::auth::v3::CheckRequest&, Tracing::Span&, const StreamInfo::StreamInfo&) -> void { request_callbacks_ = &callbacks; })); - EXPECT_CALL(filter_callbacks_, clearRouteCache()); + EXPECT_CALL(decoder_filter_callbacks_, clearRouteCache()); EXPECT_EQ(Http::FilterHeadersStatus::StopAllIterationAndWatermark, filter_->decodeHeaders(request_headers_, false)); EXPECT_EQ(Http::FilterDataStatus::Continue, filter_->decodeData(data_, false)); EXPECT_EQ(Http::FilterTrailersStatus::Continue, filter_->decodeTrailers(request_trailers_)); - EXPECT_CALL(filter_callbacks_, continueDecoding()); - EXPECT_CALL(filter_callbacks_.stream_info_, + EXPECT_CALL(decoder_filter_callbacks_, continueDecoding()); + EXPECT_CALL(decoder_filter_callbacks_.stream_info_, setResponseFlag(Envoy::StreamInfo::ResponseFlag::UnauthorizedExternalService)) .Times(0); @@ -923,8 +930,10 @@ TEST_F(HttpFilterTest, ClearCacheRouteHeadersToAppendOnly) { response.status = Filters::Common::ExtAuthz::CheckStatus::OK; response.headers_to_append = Http::HeaderVector{{Http::LowerCaseString{"foo"}, "bar"}}; request_callbacks_->onComplete(std::make_unique(response)); - EXPECT_EQ( - 1U, filter_callbacks_.clusterInfo()->statsScope().counterFromString("ext_authz.ok").value()); + EXPECT_EQ(1U, decoder_filter_callbacks_.clusterInfo() + ->statsScope() + .counterFromString("ext_authz.ok") + .value()); EXPECT_EQ(1U, config_->stats().ok_.value()); } @@ -951,13 +960,13 @@ TEST_F(HttpFilterTest, ClearCacheRouteHeadersToAddOnly) { Invoke([&](Filters::Common::ExtAuthz::RequestCallbacks& callbacks, const envoy::service::auth::v3::CheckRequest&, Tracing::Span&, const StreamInfo::StreamInfo&) -> void { request_callbacks_ = &callbacks; })); - EXPECT_CALL(filter_callbacks_, clearRouteCache()); + EXPECT_CALL(decoder_filter_callbacks_, clearRouteCache()); EXPECT_EQ(Http::FilterHeadersStatus::StopAllIterationAndWatermark, filter_->decodeHeaders(request_headers_, false)); EXPECT_EQ(Http::FilterDataStatus::Continue, filter_->decodeData(data_, false)); EXPECT_EQ(Http::FilterTrailersStatus::Continue, filter_->decodeTrailers(request_trailers_)); - EXPECT_CALL(filter_callbacks_, continueDecoding()); - EXPECT_CALL(filter_callbacks_.stream_info_, + EXPECT_CALL(decoder_filter_callbacks_, continueDecoding()); + EXPECT_CALL(decoder_filter_callbacks_.stream_info_, setResponseFlag(Envoy::StreamInfo::ResponseFlag::UnauthorizedExternalService)) .Times(0); @@ -965,8 +974,10 @@ TEST_F(HttpFilterTest, ClearCacheRouteHeadersToAddOnly) { response.status = Filters::Common::ExtAuthz::CheckStatus::OK; response.headers_to_set = Http::HeaderVector{{Http::LowerCaseString{"foo"}, "bar"}}; request_callbacks_->onComplete(std::make_unique(response)); - EXPECT_EQ( - 1U, filter_callbacks_.clusterInfo()->statsScope().counterFromString("ext_authz.ok").value()); + EXPECT_EQ(1U, decoder_filter_callbacks_.clusterInfo() + ->statsScope() + .counterFromString("ext_authz.ok") + .value()); EXPECT_EQ(1U, config_->stats().ok_.value()); } @@ -993,13 +1004,13 @@ TEST_F(HttpFilterTest, ClearCacheRouteHeadersToRemoveOnly) { Invoke([&](Filters::Common::ExtAuthz::RequestCallbacks& callbacks, const envoy::service::auth::v3::CheckRequest&, Tracing::Span&, const StreamInfo::StreamInfo&) -> void { request_callbacks_ = &callbacks; })); - EXPECT_CALL(filter_callbacks_, clearRouteCache()); + EXPECT_CALL(decoder_filter_callbacks_, clearRouteCache()); EXPECT_EQ(Http::FilterHeadersStatus::StopAllIterationAndWatermark, filter_->decodeHeaders(request_headers_, false)); EXPECT_EQ(Http::FilterDataStatus::Continue, filter_->decodeData(data_, false)); EXPECT_EQ(Http::FilterTrailersStatus::Continue, filter_->decodeTrailers(request_trailers_)); - EXPECT_CALL(filter_callbacks_, continueDecoding()); - EXPECT_CALL(filter_callbacks_.stream_info_, + EXPECT_CALL(decoder_filter_callbacks_, continueDecoding()); + EXPECT_CALL(decoder_filter_callbacks_.stream_info_, setResponseFlag(Envoy::StreamInfo::ResponseFlag::UnauthorizedExternalService)) .Times(0); @@ -1008,8 +1019,10 @@ TEST_F(HttpFilterTest, ClearCacheRouteHeadersToRemoveOnly) { response.headers_to_remove = std::vector{Http::LowerCaseString{"remove-me"}}; request_callbacks_->onComplete(std::make_unique(response)); - EXPECT_EQ( - 1U, filter_callbacks_.clusterInfo()->statsScope().counterFromString("ext_authz.ok").value()); + EXPECT_EQ(1U, decoder_filter_callbacks_.clusterInfo() + ->statsScope() + .counterFromString("ext_authz.ok") + .value()); EXPECT_EQ(1U, config_->stats().ok_.value()); } @@ -1036,21 +1049,23 @@ TEST_F(HttpFilterTest, NoClearCacheRoute) { Invoke([&](Filters::Common::ExtAuthz::RequestCallbacks& callbacks, const envoy::service::auth::v3::CheckRequest&, Tracing::Span&, const StreamInfo::StreamInfo&) -> void { request_callbacks_ = &callbacks; })); - EXPECT_CALL(filter_callbacks_, clearRouteCache()).Times(0); + EXPECT_CALL(decoder_filter_callbacks_, clearRouteCache()).Times(0); EXPECT_EQ(Http::FilterHeadersStatus::StopAllIterationAndWatermark, filter_->decodeHeaders(request_headers_, false)); EXPECT_EQ(Http::FilterDataStatus::Continue, filter_->decodeData(data_, false)); EXPECT_EQ(Http::FilterTrailersStatus::Continue, filter_->decodeTrailers(request_trailers_)); - EXPECT_CALL(filter_callbacks_, continueDecoding()); - EXPECT_CALL(filter_callbacks_.stream_info_, + EXPECT_CALL(decoder_filter_callbacks_, continueDecoding()); + EXPECT_CALL(decoder_filter_callbacks_.stream_info_, setResponseFlag(Envoy::StreamInfo::ResponseFlag::UnauthorizedExternalService)) .Times(0); Filters::Common::ExtAuthz::Response response{}; response.status = Filters::Common::ExtAuthz::CheckStatus::OK; request_callbacks_->onComplete(std::make_unique(response)); - EXPECT_EQ( - 1U, filter_callbacks_.clusterInfo()->statsScope().counterFromString("ext_authz.ok").value()); + EXPECT_EQ(1U, decoder_filter_callbacks_.clusterInfo() + ->statsScope() + .counterFromString("ext_authz.ok") + .value()); EXPECT_EQ(1U, config_->stats().ok_.value()); } @@ -1072,13 +1087,13 @@ TEST_F(HttpFilterTest, NoClearCacheRouteConfig) { Invoke([&](Filters::Common::ExtAuthz::RequestCallbacks& callbacks, const envoy::service::auth::v3::CheckRequest&, Tracing::Span&, const StreamInfo::StreamInfo&) -> void { request_callbacks_ = &callbacks; })); - EXPECT_CALL(filter_callbacks_, clearRouteCache()).Times(0); + EXPECT_CALL(decoder_filter_callbacks_, clearRouteCache()).Times(0); EXPECT_EQ(Http::FilterHeadersStatus::StopAllIterationAndWatermark, filter_->decodeHeaders(request_headers_, false)); EXPECT_EQ(Http::FilterDataStatus::Continue, filter_->decodeData(data_, false)); EXPECT_EQ(Http::FilterTrailersStatus::Continue, filter_->decodeTrailers(request_trailers_)); - EXPECT_CALL(filter_callbacks_, continueDecoding()); - EXPECT_CALL(filter_callbacks_.stream_info_, + EXPECT_CALL(decoder_filter_callbacks_, continueDecoding()); + EXPECT_CALL(decoder_filter_callbacks_.stream_info_, setResponseFlag(Envoy::StreamInfo::ResponseFlag::UnauthorizedExternalService)) .Times(0); @@ -1087,8 +1102,10 @@ TEST_F(HttpFilterTest, NoClearCacheRouteConfig) { response.headers_to_append = Http::HeaderVector{{Http::LowerCaseString{"foo"}, "bar"}}; response.headers_to_set = Http::HeaderVector{{Http::LowerCaseString{"bar"}, "foo"}}; request_callbacks_->onComplete(std::make_unique(response)); - EXPECT_EQ( - 1U, filter_callbacks_.clusterInfo()->statsScope().counterFromString("ext_authz.ok").value()); + EXPECT_EQ(1U, decoder_filter_callbacks_.clusterInfo() + ->statsScope() + .counterFromString("ext_authz.ok") + .value()); EXPECT_EQ(1U, config_->stats().ok_.value()); } @@ -1118,17 +1135,18 @@ TEST_F(HttpFilterTest, NoClearCacheRouteDeniedResponse) { const StreamInfo::StreamInfo&) -> void { callbacks.onComplete(std::move(response_ptr)); })); - EXPECT_CALL(filter_callbacks_, clearRouteCache()).Times(0); - EXPECT_CALL(filter_callbacks_, continueDecoding()).Times(0); + EXPECT_CALL(decoder_filter_callbacks_, clearRouteCache()).Times(0); + EXPECT_CALL(decoder_filter_callbacks_, continueDecoding()).Times(0); EXPECT_EQ(Http::FilterHeadersStatus::StopAllIterationAndWatermark, filter_->decodeHeaders(request_headers_, false)); EXPECT_EQ(Http::FilterDataStatus::Continue, filter_->decodeData(data_, false)); EXPECT_EQ(Http::FilterTrailersStatus::Continue, filter_->decodeTrailers(request_trailers_)); EXPECT_EQ(1U, config_->stats().denied_.value()); - EXPECT_EQ( - 1U, - filter_callbacks_.clusterInfo()->statsScope().counterFromString("ext_authz.denied").value()); - EXPECT_EQ("ext_authz_denied", filter_callbacks_.details()); + EXPECT_EQ(1U, decoder_filter_callbacks_.clusterInfo() + ->statsScope() + .counterFromString("ext_authz.denied") + .value()); + EXPECT_EQ("ext_authz_denied", decoder_filter_callbacks_.details()); } // Verifies that specified metadata is passed along in the check request @@ -1159,7 +1177,8 @@ TEST_F(HttpFilterTest, MetadataContext) { envoy::config::core::v3::Metadata metadata; TestUtility::loadFromYaml(yaml, metadata); - ON_CALL(filter_callbacks_.stream_info_, dynamicMetadata()).WillByDefault(ReturnRef(metadata)); + ON_CALL(decoder_filter_callbacks_.stream_info_, dynamicMetadata()) + .WillByDefault(ReturnRef(metadata)); prepareCheck(); @@ -1273,7 +1292,8 @@ TEST_F(HttpFilterTest, MetadataDisabled) { )EOF"; envoy::config::core::v3::Metadata metadata; TestUtility::loadFromYaml(yaml, metadata); - ON_CALL(filter_callbacks_.stream_info_, dynamicMetadata()).WillByDefault(ReturnRef(metadata)); + ON_CALL(decoder_filter_callbacks_.stream_info_, dynamicMetadata()) + .WillByDefault(ReturnRef(metadata)); // Make sure check is not called. EXPECT_CALL(*client_, check(_, _, _, _)).Times(0); @@ -1305,7 +1325,8 @@ TEST_F(HttpFilterTest, MetadataEnabled) { )EOF"; envoy::config::core::v3::Metadata metadata; TestUtility::loadFromYaml(yaml, metadata); - ON_CALL(filter_callbacks_.stream_info_, dynamicMetadata()).WillByDefault(ReturnRef(metadata)); + ON_CALL(decoder_filter_callbacks_.stream_info_, dynamicMetadata()) + .WillByDefault(ReturnRef(metadata)); prepareCheck(); @@ -1352,7 +1373,8 @@ TEST_F(HttpFilterTest, FilterEnabledButMetadataDisabled) { )EOF"; envoy::config::core::v3::Metadata metadata; TestUtility::loadFromYaml(yaml, metadata); - ON_CALL(filter_callbacks_.stream_info_, dynamicMetadata()).WillByDefault(ReturnRef(metadata)); + ON_CALL(decoder_filter_callbacks_.stream_info_, dynamicMetadata()) + .WillByDefault(ReturnRef(metadata)); // Make sure check is not called. EXPECT_CALL(*client_, check(_, _, _, _)).Times(0); @@ -1396,7 +1418,8 @@ TEST_F(HttpFilterTest, FilterDisabledButMetadataEnabled) { )EOF"; envoy::config::core::v3::Metadata metadata; TestUtility::loadFromYaml(yaml, metadata); - ON_CALL(filter_callbacks_.stream_info_, dynamicMetadata()).WillByDefault(ReturnRef(metadata)); + ON_CALL(decoder_filter_callbacks_.stream_info_, dynamicMetadata()) + .WillByDefault(ReturnRef(metadata)); // Make sure check is not called. EXPECT_CALL(*client_, check(_, _, _, _)).Times(0); @@ -1440,7 +1463,8 @@ TEST_F(HttpFilterTest, FilterEnabledAndMetadataEnabled) { )EOF"; envoy::config::core::v3::Metadata metadata; TestUtility::loadFromYaml(yaml, metadata); - ON_CALL(filter_callbacks_.stream_info_, dynamicMetadata()).WillByDefault(ReturnRef(metadata)); + ON_CALL(decoder_filter_callbacks_.stream_info_, dynamicMetadata()) + .WillByDefault(ReturnRef(metadata)); prepareCheck(); @@ -1539,10 +1563,11 @@ TEST_P(HttpFilterTestParam, ContextExtensions) { // Initialize the route's per filter config. FilterConfigPerRoute auth_per_route(settingsroute); - EXPECT_CALL(*filter_callbacks_.route_, + EXPECT_CALL(*decoder_filter_callbacks_.route_, mostSpecificPerFilterConfig("envoy.filters.http.ext_authz")) .WillOnce(Return(&auth_per_route)); - EXPECT_CALL(*filter_callbacks_.route_, traversePerFilterConfig("envoy.filters.http.ext_authz", _)) + EXPECT_CALL(*decoder_filter_callbacks_.route_, + traversePerFilterConfig("envoy.filters.http.ext_authz", _)) .WillOnce(Invoke([&](const std::string&, std::function cb) { cb(auth_per_vhost); @@ -1576,7 +1601,8 @@ TEST_P(HttpFilterTestParam, DisabledOnRoute) { prepareCheck(); - ON_CALL(*filter_callbacks_.route_, mostSpecificPerFilterConfig("envoy.filters.http.ext_authz")) + ON_CALL(*decoder_filter_callbacks_.route_, + mostSpecificPerFilterConfig("envoy.filters.http.ext_authz")) .WillByDefault(Return(&auth_per_route)); auto test_disable = [&](bool disabled) { @@ -1607,7 +1633,8 @@ TEST_P(HttpFilterTestParam, DisabledOnRouteWithRequestBody) { envoy::extensions::filters::http::ext_authz::v3::ExtAuthzPerRoute settings; FilterConfigPerRoute auth_per_route(settings); - ON_CALL(*filter_callbacks_.route_, mostSpecificPerFilterConfig("envoy.filters.http.ext_authz")) + ON_CALL(*decoder_filter_callbacks_.route_, + mostSpecificPerFilterConfig("envoy.filters.http.ext_authz")) .WillByDefault(Return(&auth_per_route)); auto test_disable = [&](bool disabled) { @@ -1629,9 +1656,9 @@ TEST_P(HttpFilterTestParam, DisabledOnRouteWithRequestBody) { }; test_disable(false); - ON_CALL(filter_callbacks_, connection()).WillByDefault(Return(&connection_)); + ON_CALL(decoder_filter_callbacks_, connection()).WillByDefault(Return(&connection_)); // When filter is not disabled, setDecoderBufferLimit is called. - EXPECT_CALL(filter_callbacks_, setDecoderBufferLimit(_)); + EXPECT_CALL(decoder_filter_callbacks_, setDecoderBufferLimit(_)); EXPECT_CALL(*client_, check(_, _, _, _)).Times(0); EXPECT_EQ(Http::FilterHeadersStatus::StopIteration, filter_->decodeHeaders(request_headers_, false)); @@ -1641,7 +1668,7 @@ TEST_P(HttpFilterTestParam, DisabledOnRouteWithRequestBody) { test_disable(true); EXPECT_CALL(*client_, check(_, _, _, _)).Times(0); // Make sure that setDecoderBufferLimit is skipped. - EXPECT_CALL(filter_callbacks_, setDecoderBufferLimit(_)).Times(0); + EXPECT_CALL(decoder_filter_callbacks_, setDecoderBufferLimit(_)).Times(0); EXPECT_EQ(Http::FilterHeadersStatus::Continue, filter_->decodeHeaders(request_headers_, false)); EXPECT_EQ(Http::FilterDataStatus::Continue, filter_->decodeData(data_, false)); EXPECT_EQ(Http::FilterTrailersStatus::Continue, filter_->decodeTrailers(request_trailers_)); @@ -1650,7 +1677,7 @@ TEST_P(HttpFilterTestParam, DisabledOnRouteWithRequestBody) { // Test that authentication will do when the filter_callbacks has no route.(both // direct response and redirect have no route) TEST_P(HttpFilterTestParam, NoRoute) { - EXPECT_CALL(*filter_callbacks_.route_, routeEntry()).WillRepeatedly(Return(nullptr)); + EXPECT_CALL(*decoder_filter_callbacks_.route_, routeEntry()).WillRepeatedly(Return(nullptr)); prepareCheck(); EXPECT_CALL(*client_, check(_, _, _, _)); EXPECT_EQ(Http::FilterHeadersStatus::StopAllIterationAndWatermark, @@ -1667,7 +1694,7 @@ TEST_P(HttpFilterTestParam, NoRouteWithSkipAuth) { Runtime::LoaderSingleton::getExisting()->mergeValues( {{"envoy.reloadable_features.http_ext_authz_do_not_skip_direct_response_and_redirect", "false"}}); - EXPECT_CALL(*filter_callbacks_.route_, routeEntry()).WillOnce(Return(nullptr)); + EXPECT_CALL(*decoder_filter_callbacks_.route_, routeEntry()).WillOnce(Return(nullptr)); EXPECT_EQ(Http::FilterHeadersStatus::Continue, filter_->decodeHeaders(request_headers_, false)); } @@ -1684,19 +1711,21 @@ TEST_P(HttpFilterTestParam, OkResponse) { const StreamInfo::StreamInfo&) -> void { request_callbacks_ = &callbacks; })); EXPECT_EQ(Http::FilterHeadersStatus::StopAllIterationAndWatermark, filter_->decodeHeaders(request_headers_, false)); - EXPECT_CALL(filter_callbacks_, continueDecoding()); + EXPECT_CALL(decoder_filter_callbacks_, continueDecoding()); - EXPECT_CALL(filter_callbacks_.stream_info_, + EXPECT_CALL(decoder_filter_callbacks_.stream_info_, setResponseFlag(Envoy::StreamInfo::ResponseFlag::UnauthorizedExternalService)) .Times(0); Filters::Common::ExtAuthz::Response response{}; response.status = Filters::Common::ExtAuthz::CheckStatus::OK; // Send an OK response Without setting the dynamic metadata field. - EXPECT_CALL(filter_callbacks_.stream_info_, setDynamicMetadata(_, _)).Times(0); + EXPECT_CALL(decoder_filter_callbacks_.stream_info_, setDynamicMetadata(_, _)).Times(0); request_callbacks_->onComplete(std::make_unique(response)); - EXPECT_EQ( - 1U, filter_callbacks_.clusterInfo()->statsScope().counterFromString("ext_authz.ok").value()); + EXPECT_EQ(1U, decoder_filter_callbacks_.clusterInfo() + ->statsScope() + .counterFromString("ext_authz.ok") + .value()); EXPECT_EQ(1U, config_->stats().ok_.value()); // decodeData() and decodeTrailers() are called after continueDecoding(). EXPECT_EQ(Http::FilterDataStatus::Continue, filter_->decodeData(data_, false)); @@ -1719,12 +1748,14 @@ TEST_P(HttpFilterTestParam, ImmediateOkResponse) { const StreamInfo::StreamInfo&) -> void { callbacks.onComplete(std::make_unique(response)); })); - EXPECT_CALL(filter_callbacks_, continueDecoding()).Times(0); + EXPECT_CALL(decoder_filter_callbacks_, continueDecoding()).Times(0); EXPECT_EQ(Http::FilterHeadersStatus::Continue, filter_->decodeHeaders(request_headers_, false)); EXPECT_EQ(Http::FilterDataStatus::Continue, filter_->decodeData(data_, false)); EXPECT_EQ(Http::FilterTrailersStatus::Continue, filter_->decodeTrailers(request_trailers_)); - EXPECT_EQ( - 1U, filter_callbacks_.clusterInfo()->statsScope().counterFromString("ext_authz.ok").value()); + EXPECT_EQ(1U, decoder_filter_callbacks_.clusterInfo() + ->statsScope() + .counterFromString("ext_authz.ok") + .value()); EXPECT_EQ(1U, config_->stats().ok_.value()); } @@ -1749,12 +1780,13 @@ TEST_P(HttpFilterTestParam, ImmediateDeniedResponseWithHttpAttributes) { const StreamInfo::StreamInfo&) -> void { callbacks.onComplete(std::move(response_ptr)); })); - EXPECT_CALL(filter_callbacks_, continueDecoding()).Times(0); + EXPECT_CALL(decoder_filter_callbacks_, continueDecoding()).Times(0); EXPECT_EQ(Http::FilterHeadersStatus::StopAllIterationAndWatermark, filter_->decodeHeaders(request_headers_, false)); - EXPECT_EQ( - 1U, - filter_callbacks_.clusterInfo()->statsScope().counterFromString("ext_authz.denied").value()); + EXPECT_EQ(1U, decoder_filter_callbacks_.clusterInfo() + ->statsScope() + .counterFromString("ext_authz.denied") + .value()); EXPECT_EQ(1U, config_->stats().denied_.value()); // When request is denied, no call to continueDecoding(). As a result, decodeData() and // decodeTrailer() will not be called. @@ -1803,7 +1835,7 @@ TEST_P(HttpFilterTestParam, ImmediateOkResponseWithHttpAttributes) { const StreamInfo::StreamInfo&) -> void { callbacks.onComplete(std::move(response_ptr)); })); - EXPECT_CALL(filter_callbacks_, continueDecoding()).Times(0); + EXPECT_CALL(decoder_filter_callbacks_, continueDecoding()).Times(0); EXPECT_EQ(Http::FilterHeadersStatus::Continue, filter_->decodeHeaders(request_headers_, false)); EXPECT_EQ(Http::FilterDataStatus::Continue, filter_->decodeData(data_, false)); EXPECT_EQ(Http::FilterTrailersStatus::Continue, filter_->decodeTrailers(request_trailers_)); @@ -1895,12 +1927,13 @@ TEST_P(HttpFilterTestParam, ImmediateDeniedResponse) { const StreamInfo::StreamInfo&) -> void { callbacks.onComplete(std::make_unique(response)); })); - EXPECT_CALL(filter_callbacks_, continueDecoding()).Times(0); + EXPECT_CALL(decoder_filter_callbacks_, continueDecoding()).Times(0); EXPECT_EQ(Http::FilterHeadersStatus::StopAllIterationAndWatermark, filter_->decodeHeaders(request_headers_, false)); - EXPECT_EQ( - 1U, - filter_callbacks_.clusterInfo()->statsScope().counterFromString("ext_authz.denied").value()); + EXPECT_EQ(1U, decoder_filter_callbacks_.clusterInfo() + ->statsScope() + .counterFromString("ext_authz.denied") + .value()); EXPECT_EQ(1U, config_->stats().denied_.value()); // When request is denied, no call to continueDecoding(). As a result, decodeData() and // decodeTrailer() will not be called. @@ -1917,26 +1950,29 @@ TEST_P(HttpFilterTestParam, DeniedResponseWith401) { const envoy::service::auth::v3::CheckRequest&, Tracing::Span&, const StreamInfo::StreamInfo&) -> void { request_callbacks_ = &callbacks; })); - EXPECT_CALL(filter_callbacks_.stream_info_, + EXPECT_CALL(decoder_filter_callbacks_.stream_info_, setResponseFlag(Envoy::StreamInfo::ResponseFlag::UnauthorizedExternalService)); EXPECT_EQ(Http::FilterHeadersStatus::StopAllIterationAndWatermark, filter_->decodeHeaders(request_headers_, false)); Http::TestResponseHeaderMapImpl response_headers{{":status", "401"}}; - EXPECT_CALL(filter_callbacks_, encodeHeaders_(HeaderMapEqualRef(&response_headers), true)); - EXPECT_CALL(filter_callbacks_, continueDecoding()).Times(0); + EXPECT_CALL(decoder_filter_callbacks_, + encodeHeaders_(HeaderMapEqualRef(&response_headers), true)); + EXPECT_CALL(decoder_filter_callbacks_, continueDecoding()).Times(0); Filters::Common::ExtAuthz::Response response{}; response.status = Filters::Common::ExtAuthz::CheckStatus::Denied; response.status_code = Http::Code::Unauthorized; request_callbacks_->onComplete(std::make_unique(response)); - EXPECT_EQ( - 1U, - filter_callbacks_.clusterInfo()->statsScope().counterFromString("ext_authz.denied").value()); + EXPECT_EQ(1U, decoder_filter_callbacks_.clusterInfo() + ->statsScope() + .counterFromString("ext_authz.denied") + .value()); EXPECT_EQ(1U, config_->stats().denied_.value()); - EXPECT_EQ( - 1U, - filter_callbacks_.clusterInfo()->statsScope().counterFromString("upstream_rq_4xx").value()); + EXPECT_EQ(1U, decoder_filter_callbacks_.clusterInfo() + ->statsScope() + .counterFromString("upstream_rq_4xx") + .value()); } // Test that a denied response results in the connection closing with a 403 response to the client. @@ -1950,29 +1986,33 @@ TEST_P(HttpFilterTestParam, DeniedResponseWith403) { const envoy::service::auth::v3::CheckRequest&, Tracing::Span&, const StreamInfo::StreamInfo&) -> void { request_callbacks_ = &callbacks; })); - EXPECT_CALL(filter_callbacks_.stream_info_, + EXPECT_CALL(decoder_filter_callbacks_.stream_info_, setResponseFlag(Envoy::StreamInfo::ResponseFlag::UnauthorizedExternalService)); EXPECT_EQ(Http::FilterHeadersStatus::StopAllIterationAndWatermark, filter_->decodeHeaders(request_headers_, false)); Http::TestResponseHeaderMapImpl response_headers{{":status", "403"}}; - EXPECT_CALL(filter_callbacks_, encodeHeaders_(HeaderMapEqualRef(&response_headers), true)); - EXPECT_CALL(filter_callbacks_, continueDecoding()).Times(0); + EXPECT_CALL(decoder_filter_callbacks_, + encodeHeaders_(HeaderMapEqualRef(&response_headers), true)); + EXPECT_CALL(decoder_filter_callbacks_, continueDecoding()).Times(0); Filters::Common::ExtAuthz::Response response{}; response.status = Filters::Common::ExtAuthz::CheckStatus::Denied; response.status_code = Http::Code::Forbidden; request_callbacks_->onComplete(std::make_unique(response)); - EXPECT_EQ( - 1U, - filter_callbacks_.clusterInfo()->statsScope().counterFromString("ext_authz.denied").value()); + EXPECT_EQ(1U, decoder_filter_callbacks_.clusterInfo() + ->statsScope() + .counterFromString("ext_authz.denied") + .value()); EXPECT_EQ(1U, config_->stats().denied_.value()); - EXPECT_EQ( - 1U, - filter_callbacks_.clusterInfo()->statsScope().counterFromString("upstream_rq_4xx").value()); - EXPECT_EQ( - 1U, - filter_callbacks_.clusterInfo()->statsScope().counterFromString("upstream_rq_403").value()); + EXPECT_EQ(1U, decoder_filter_callbacks_.clusterInfo() + ->statsScope() + .counterFromString("upstream_rq_4xx") + .value()); + EXPECT_EQ(1U, decoder_filter_callbacks_.clusterInfo() + ->statsScope() + .counterFromString("upstream_rq_403") + .value()); } // Verify that authz response memory is not used after free. @@ -2003,9 +2043,10 @@ TEST_P(HttpFilterTestParam, DestroyResponseBeforeSendLocalReply) { {"foo", "bar"}, {"bar", "foo"}}; Http::HeaderMap* saved_headers; - EXPECT_CALL(filter_callbacks_, encodeHeaders_(HeaderMapEqualRef(&response_headers), false)) + EXPECT_CALL(decoder_filter_callbacks_, + encodeHeaders_(HeaderMapEqualRef(&response_headers), false)) .WillOnce(Invoke([&](Http::HeaderMap& headers, bool) { saved_headers = &headers; })); - EXPECT_CALL(filter_callbacks_, encodeData(_, true)) + EXPECT_CALL(decoder_filter_callbacks_, encodeData(_, true)) .WillOnce(Invoke([&](Buffer::Instance& data, bool) { response_ptr.reset(); Http::TestRequestHeaderMapImpl test_headers{*saved_headers}; @@ -2015,16 +2056,19 @@ TEST_P(HttpFilterTestParam, DestroyResponseBeforeSendLocalReply) { })); request_callbacks_->onComplete(std::move(response_ptr)); - EXPECT_EQ( - 1U, - filter_callbacks_.clusterInfo()->statsScope().counterFromString("ext_authz.denied").value()); + EXPECT_EQ(1U, decoder_filter_callbacks_.clusterInfo() + ->statsScope() + .counterFromString("ext_authz.denied") + .value()); EXPECT_EQ(1U, config_->stats().denied_.value()); - EXPECT_EQ( - 1U, - filter_callbacks_.clusterInfo()->statsScope().counterFromString("upstream_rq_4xx").value()); - EXPECT_EQ( - 1U, - filter_callbacks_.clusterInfo()->statsScope().counterFromString("upstream_rq_403").value()); + EXPECT_EQ(1U, decoder_filter_callbacks_.clusterInfo() + ->statsScope() + .counterFromString("upstream_rq_4xx") + .value()); + EXPECT_EQ(1U, decoder_filter_callbacks_.clusterInfo() + ->statsScope() + .counterFromString("upstream_rq_403") + .value()); } // Verify that authz denied response headers overrides the existing encoding headers, @@ -2064,13 +2108,14 @@ TEST_P(HttpFilterTestParam, OverrideEncodingHeaders) { {"set-cookie", "cookie2=value"}, {"accept-encoding", "gzip,deflate"}}; Http::HeaderMap* saved_headers; - EXPECT_CALL(filter_callbacks_, encodeHeaders_(HeaderMapEqualRef(&response_headers), false)) + EXPECT_CALL(decoder_filter_callbacks_, + encodeHeaders_(HeaderMapEqualRef(&response_headers), false)) .WillOnce(Invoke([&](Http::HeaderMap& headers, bool) { headers.addCopy(Http::LowerCaseString{"foo"}, std::string{"OVERRIDE_WITH_bar"}); headers.addCopy(Http::LowerCaseString{"foobar"}, std::string{"DO_NOT_OVERRIDE"}); saved_headers = &headers; })); - EXPECT_CALL(filter_callbacks_, encodeData(_, true)) + EXPECT_CALL(decoder_filter_callbacks_, encodeData(_, true)) .WillOnce(Invoke([&](Buffer::Instance& data, bool) { response_ptr.reset(); Http::TestRequestHeaderMapImpl test_headers{*saved_headers}; @@ -2087,16 +2132,19 @@ TEST_P(HttpFilterTestParam, OverrideEncodingHeaders) { })); request_callbacks_->onComplete(std::move(response_ptr)); - EXPECT_EQ( - 1U, - filter_callbacks_.clusterInfo()->statsScope().counterFromString("ext_authz.denied").value()); + EXPECT_EQ(1U, decoder_filter_callbacks_.clusterInfo() + ->statsScope() + .counterFromString("ext_authz.denied") + .value()); EXPECT_EQ(1U, config_->stats().denied_.value()); - EXPECT_EQ( - 1U, - filter_callbacks_.clusterInfo()->statsScope().counterFromString("upstream_rq_4xx").value()); - EXPECT_EQ( - 1U, - filter_callbacks_.clusterInfo()->statsScope().counterFromString("upstream_rq_403").value()); + EXPECT_EQ(1U, decoder_filter_callbacks_.clusterInfo() + ->statsScope() + .counterFromString("upstream_rq_4xx") + .value()); + EXPECT_EQ(1U, decoder_filter_callbacks_.clusterInfo() + ->statsScope() + .counterFromString("upstream_rq_403") + .value()); } // Verify that when returning an OK response with dynamic_metadata field set, the filter emits @@ -2118,32 +2166,46 @@ TEST_F(HttpFilterTest, EmitDynamicMetadata) { Invoke([&](Filters::Common::ExtAuthz::RequestCallbacks& callbacks, const envoy::service::auth::v3::CheckRequest&, Tracing::Span&, const StreamInfo::StreamInfo&) -> void { request_callbacks_ = &callbacks; })); + EXPECT_EQ(Http::FilterHeadersStatus::StopAllIterationAndWatermark, filter_->decodeHeaders(request_headers_, false)); EXPECT_EQ(Http::FilterDataStatus::Continue, filter_->decodeData(data_, false)); EXPECT_EQ(Http::FilterTrailersStatus::Continue, filter_->decodeTrailers(request_trailers_)); + decoder_filter_callbacks_.dispatcher_.globalTimeSystem().advanceTimeWait( + std::chrono::milliseconds(10)); + ProtobufWkt::Value ext_authz_duration_value; + ext_authz_duration_value.set_number_value(10); + Filters::Common::ExtAuthz::Response response{}; response.status = Filters::Common::ExtAuthz::CheckStatus::OK; response.headers_to_set = Http::HeaderVector{{Http::LowerCaseString{"foo"}, "bar"}}; + (*response.dynamic_metadata.mutable_fields())["ext_authz_duration"] = ext_authz_duration_value; initializeMetadata(response); - EXPECT_CALL(filter_callbacks_.stream_info_, setDynamicMetadata(_, _)) + EXPECT_CALL(decoder_filter_callbacks_.stream_info_, setDynamicMetadata(_, _)) .WillOnce(Invoke([&response](const std::string& ns, const ProtobufWkt::Struct& returned_dynamic_metadata) { EXPECT_EQ(ns, "envoy.filters.http.ext_authz"); + // Check timing metadata correctness + EXPECT_TRUE(returned_dynamic_metadata.fields().at("ext_authz_duration").has_number_value()); + EXPECT_TRUE(TestUtility::protoEqual(returned_dynamic_metadata, response.dynamic_metadata)); + EXPECT_EQ(response.dynamic_metadata.fields().at("ext_authz_duration").number_value(), + returned_dynamic_metadata.fields().at("ext_authz_duration").number_value()); })); - EXPECT_CALL(filter_callbacks_, continueDecoding()); - EXPECT_CALL(filter_callbacks_.stream_info_, + EXPECT_CALL(decoder_filter_callbacks_, continueDecoding()); + EXPECT_CALL(decoder_filter_callbacks_.stream_info_, setResponseFlag(Envoy::StreamInfo::ResponseFlag::UnauthorizedExternalService)) .Times(0); request_callbacks_->onComplete(std::make_unique(response)); - EXPECT_EQ( - 1U, filter_callbacks_.clusterInfo()->statsScope().counterFromString("ext_authz.ok").value()); + EXPECT_EQ(1U, decoder_filter_callbacks_.clusterInfo() + ->statsScope() + .counterFromString("ext_authz.ok") + .value()); EXPECT_EQ(1U, config_->stats().ok_.value()); } @@ -2160,7 +2222,6 @@ TEST_F(HttpFilterTest, EmitDynamicMetadataWhenDenied) { )EOF"); prepareCheck(); - Filters::Common::ExtAuthz::Response response{}; response.status = Filters::Common::ExtAuthz::CheckStatus::Denied; response.status_code = Http::Code::Unauthorized; @@ -2174,26 +2235,32 @@ TEST_F(HttpFilterTest, EmitDynamicMetadataWhenDenied) { .WillOnce(Invoke([&](Filters::Common::ExtAuthz::RequestCallbacks& callbacks, const envoy::service::auth::v3::CheckRequest&, Tracing::Span&, const StreamInfo::StreamInfo&) -> void { + request_callbacks_ = &callbacks; callbacks.onComplete(std::move(response_ptr)); })); - EXPECT_CALL(filter_callbacks_.stream_info_, setDynamicMetadata(_, _)) + EXPECT_CALL(decoder_filter_callbacks_.stream_info_, setDynamicMetadata(_, _)) .WillOnce(Invoke([&response](const std::string& ns, const ProtobufWkt::Struct& returned_dynamic_metadata) { EXPECT_EQ(ns, "envoy.filters.http.ext_authz"); + // Check timing metadata correctness + EXPECT_FALSE(returned_dynamic_metadata.fields().contains("ext_authz_duration")); + EXPECT_FALSE(response.dynamic_metadata.fields().contains("ext_authz_duration")); + EXPECT_TRUE(TestUtility::protoEqual(returned_dynamic_metadata, response.dynamic_metadata)); })); - EXPECT_CALL(filter_callbacks_, continueDecoding()).Times(0); + EXPECT_CALL(decoder_filter_callbacks_, continueDecoding()).Times(0); EXPECT_EQ(Http::FilterHeadersStatus::StopAllIterationAndWatermark, filter_->decodeHeaders(request_headers_, false)); EXPECT_EQ(Http::FilterDataStatus::Continue, filter_->decodeData(data_, false)); EXPECT_EQ(Http::FilterTrailersStatus::Continue, filter_->decodeTrailers(request_trailers_)); EXPECT_EQ(1U, config_->stats().denied_.value()); - EXPECT_EQ( - 1U, - filter_callbacks_.clusterInfo()->statsScope().counterFromString("ext_authz.denied").value()); - EXPECT_EQ("ext_authz_denied", filter_callbacks_.details()); + EXPECT_EQ(1U, decoder_filter_callbacks_.clusterInfo() + ->statsScope() + .counterFromString("ext_authz.denied") + .value()); + EXPECT_EQ("ext_authz_denied", decoder_filter_callbacks_.details()); } // Verify that the filter emits metadata if the ext_authz client responds with an error and provides @@ -2216,12 +2283,12 @@ TEST_F(HttpFilterTest, EmittingMetadataWhenError) { const StreamInfo::StreamInfo&) -> void { request_callbacks_ = &callbacks; })); // When the response check status is error, we skip emitting dynamic metadata. - EXPECT_CALL(filter_callbacks_.stream_info_, setDynamicMetadata(_, _)); + EXPECT_CALL(decoder_filter_callbacks_.stream_info_, setDynamicMetadata(_, _)); EXPECT_EQ(Http::FilterHeadersStatus::StopAllIterationAndWatermark, filter_->decodeHeaders(request_headers_, false)); - EXPECT_CALL(filter_callbacks_, continueDecoding()).Times(0); - EXPECT_CALL(filter_callbacks_, encodeHeaders_(_, _)); + EXPECT_CALL(decoder_filter_callbacks_, continueDecoding()).Times(0); + EXPECT_CALL(decoder_filter_callbacks_, encodeHeaders_(_, _)); Filters::Common::ExtAuthz::Response response{}; response.status = Filters::Common::ExtAuthz::CheckStatus::Error; @@ -2229,9 +2296,10 @@ TEST_F(HttpFilterTest, EmittingMetadataWhenError) { // Set the response metadata. initializeMetadata(response); request_callbacks_->onComplete(std::make_unique(response)); - EXPECT_EQ( - 1U, - filter_callbacks_.clusterInfo()->statsScope().counterFromString("ext_authz.error").value()); + EXPECT_EQ(1U, decoder_filter_callbacks_.clusterInfo() + ->statsScope() + .counterFromString("ext_authz.error") + .value()); } // Test that when a connection awaiting a authorization response is canceled then the @@ -2256,7 +2324,7 @@ TEST_P(HttpFilterTestParam, ResetDuringCall) { // (this could be the case when route is configured with redirect or direct response action). TEST_P(HttpFilterTestParam, NoCluster) { - ON_CALL(filter_callbacks_, clusterInfo()).WillByDefault(Return(nullptr)); + ON_CALL(decoder_filter_callbacks_, clusterInfo()).WillByDefault(Return(nullptr)); // Place something in the context extensions on the route. envoy::extensions::filters::http::ext_authz::v3::ExtAuthzPerRoute settingsroute; @@ -2264,7 +2332,8 @@ TEST_P(HttpFilterTestParam, NoCluster) { "value_route"; // Initialize the route's per filter config. FilterConfigPerRoute auth_per_route(settingsroute); - ON_CALL(*filter_callbacks_.route_, mostSpecificPerFilterConfig("envoy.filters.http.ext_authz")) + ON_CALL(*decoder_filter_callbacks_.route_, + mostSpecificPerFilterConfig("envoy.filters.http.ext_authz")) .WillByDefault(Return(&auth_per_route)); prepareCheck(); @@ -2290,7 +2359,8 @@ TEST_P(HttpFilterTestParam, DisableRequestBodyBufferingOnRoute) { envoy::extensions::filters::http::ext_authz::v3::ExtAuthzPerRoute settings; FilterConfigPerRoute auth_per_route(settings); - ON_CALL(*filter_callbacks_.route_, mostSpecificPerFilterConfig("envoy.filters.http.ext_authz")) + ON_CALL(*decoder_filter_callbacks_.route_, + mostSpecificPerFilterConfig("envoy.filters.http.ext_authz")) .WillByDefault(Return(&auth_per_route)); auto test_disable_request_body_buffering = [&](bool bypass) { @@ -2312,9 +2382,9 @@ TEST_P(HttpFilterTestParam, DisableRequestBodyBufferingOnRoute) { }; test_disable_request_body_buffering(false); - ON_CALL(filter_callbacks_, connection()).WillByDefault(Return(&connection_)); + ON_CALL(decoder_filter_callbacks_, connection()).WillByDefault(Return(&connection_)); // When request body buffering is not skipped, setDecoderBufferLimit is called. - EXPECT_CALL(filter_callbacks_, setDecoderBufferLimit(_)); + EXPECT_CALL(decoder_filter_callbacks_, setDecoderBufferLimit(_)); EXPECT_CALL(*client_, check(_, _, _, _)).Times(0); EXPECT_EQ(Http::FilterHeadersStatus::StopIteration, filter_->decodeHeaders(request_headers_, false)); @@ -2322,7 +2392,7 @@ TEST_P(HttpFilterTestParam, DisableRequestBodyBufferingOnRoute) { test_disable_request_body_buffering(true); // When request body buffering is skipped, setDecoderBufferLimit is not called. - EXPECT_CALL(filter_callbacks_, setDecoderBufferLimit(_)).Times(0); + EXPECT_CALL(decoder_filter_callbacks_, setDecoderBufferLimit(_)).Times(0); connection_.stream_info_.downstream_connection_info_provider_->setRemoteAddress(addr_); connection_.stream_info_.downstream_connection_info_provider_->setLocalAddress(addr_); EXPECT_CALL(*client_, check(_, _, _, _)); diff --git a/test/extensions/filters/network/ext_authz/ext_authz_test.cc b/test/extensions/filters/network/ext_authz/ext_authz_test.cc index 4fa54f5d13ba..2f6432090402 100644 --- a/test/extensions/filters/network/ext_authz/ext_authz_test.cc +++ b/test/extensions/filters/network/ext_authz/ext_authz_test.cc @@ -1,3 +1,4 @@ +#include #include #include #include @@ -89,6 +90,9 @@ class ExtAuthzFilterTest : public testing::Test { 1U, stats_store_.gauge("ext_authz.name.active", Stats::Gauge::ImportMode::Accumulate).value()); + filter_callbacks_.connection_.dispatcher_.globalTimeSystem().advanceTimeWait( + std::chrono::milliseconds(10)); + Filters::Common::ExtAuthz::Response response{}; response.status = Filters::Common::ExtAuthz::CheckStatus::OK; response.headers_to_set = Http::HeaderVector{{Http::LowerCaseString{"foo"}, "bar"}}; @@ -96,13 +100,18 @@ class ExtAuthzFilterTest : public testing::Test { auto* fields = response.dynamic_metadata.mutable_fields(); (*fields)["foo"] = ValueUtil::stringValue("ok"); (*fields)["bar"] = ValueUtil::numberValue(1); + (*fields)["ext_authz_duration"] = ValueUtil::numberValue(10); EXPECT_CALL(filter_callbacks_.connection_.stream_info_, setDynamicMetadata(_, _)) .WillOnce(Invoke([&response](const std::string& ns, const ProtobufWkt::Struct& returned_dynamic_metadata) { EXPECT_EQ(ns, NetworkFilterNames::get().ExtAuthorization); + EXPECT_TRUE( + returned_dynamic_metadata.fields().at("ext_authz_duration").has_number_value()); EXPECT_TRUE( TestUtility::protoEqual(returned_dynamic_metadata, response.dynamic_metadata)); + EXPECT_EQ(response.dynamic_metadata.fields().at("ext_authz_duration").number_value(), + returned_dynamic_metadata.fields().at("ext_authz_duration").number_value()); })); EXPECT_CALL(filter_callbacks_, continueReading()); @@ -376,23 +385,35 @@ TEST_F(ExtAuthzFilterTest, ImmediateOK) { addr_); filter_callbacks_.connection_.stream_info_.downstream_connection_info_provider_->setLocalAddress( addr_); + filter_callbacks_.connection_.dispatcher_.globalTimeSystem().advanceTimeWait( + std::chrono::milliseconds(5)); ProtobufWkt::Struct dynamic_metadata; (*dynamic_metadata.mutable_fields())["baz"] = ValueUtil::stringValue("hello-ok"); (*dynamic_metadata.mutable_fields())["x"] = ValueUtil::numberValue(12); + // Since this is a stack response, duration should be 0; + (*dynamic_metadata.mutable_fields())["ext_authz_duration"] = ValueUtil::numberValue(0); + Filters::Common::ExtAuthz::Response response{}; + response.status = Filters::Common::ExtAuthz::CheckStatus::OK; + response.dynamic_metadata = dynamic_metadata; + EXPECT_CALL(filter_callbacks_, continueReading()).Times(0); EXPECT_CALL(*client_, check(_, _, _, _)) .WillOnce( WithArgs<0>(Invoke([&](Filters::Common::ExtAuthz::RequestCallbacks& callbacks) -> void { - Filters::Common::ExtAuthz::Response response{}; - response.status = Filters::Common::ExtAuthz::CheckStatus::OK; - response.dynamic_metadata = dynamic_metadata; + request_callbacks_ = &callbacks; callbacks.onComplete(std::make_unique(response)); }))); + EXPECT_CALL(filter_callbacks_.connection_.stream_info_, setDynamicMetadata(_, _)) .WillOnce(Invoke([&dynamic_metadata](const std::string& ns, const ProtobufWkt::Struct& returned_dynamic_metadata) { + EXPECT_TRUE(returned_dynamic_metadata.fields().contains("ext_authz_duration")); + EXPECT_TRUE(dynamic_metadata.fields().contains("ext_authz_duration")); EXPECT_EQ(ns, NetworkFilterNames::get().ExtAuthorization); + EXPECT_TRUE(TestUtility::protoEqual(returned_dynamic_metadata, dynamic_metadata)); + EXPECT_EQ(dynamic_metadata.fields().at("ext_authz_duration").number_value(), + returned_dynamic_metadata.fields().at("ext_authz_duration").number_value()); })); EXPECT_EQ(Network::FilterStatus::Continue, filter_->onNewConnection()); Buffer::OwnedImpl data("hello"); @@ -437,6 +458,8 @@ TEST_F(ExtAuthzFilterTest, ImmediateNOK) { .WillOnce(Invoke([&dynamic_metadata](const std::string& ns, const ProtobufWkt::Struct& returned_dynamic_metadata) { EXPECT_EQ(ns, NetworkFilterNames::get().ExtAuthorization); + EXPECT_FALSE(returned_dynamic_metadata.fields().contains("ext_authz_duration")); + EXPECT_FALSE(dynamic_metadata.fields().contains("ext_authz_duration")); EXPECT_TRUE(TestUtility::protoEqual(returned_dynamic_metadata, dynamic_metadata)); })); EXPECT_CALL(filter_callbacks_.connection_.stream_info_,