From dee43e8d6613fe909d005fbd17778d237c61934d Mon Sep 17 00:00:00 2001 From: Andrey Prado <43416671+andreyprezotto@users.noreply.github.com> Date: Sat, 23 Jan 2021 01:08:59 -0300 Subject: [PATCH] oauth2 filter: Make OAuth scopes configurable. (#14168) New optional parameter 'auth_scopes' added to the filter. The default value is 'user' (if not provided) to avoid breaking changes to users updating to the latest version. Signed-off-by: andreyprezotto Co-authored-by: Nitin Goyal Signed-off-by: Auni Ahsan --- .../filters/http/oauth2/v3alpha/oauth.proto | 7 +- .../filters/http/oauth2/v4alpha/oauth.proto | 7 +- .../http/http_filters/oauth2_filter.rst | 10 ++ docs/root/version_history/current.rst | 1 + .../filters/http/oauth2/v3alpha/oauth.proto | 7 +- .../filters/http/oauth2/v4alpha/oauth.proto | 7 +- .../extensions/filters/http/oauth2/filter.cc | 30 +++- .../extensions/filters/http/oauth2/filter.h | 2 + .../filters/http/oauth2/oauth_client.cc | 1 + .../filters/http/oauth2/config_test.cc | 8 ++ .../filters/http/oauth2/filter_test.cc | 133 ++++++++++++++---- .../http/oauth2/oauth_integration_test.cc | 4 + 12 files changed, 184 insertions(+), 33 deletions(-) diff --git a/api/envoy/extensions/filters/http/oauth2/v3alpha/oauth.proto b/api/envoy/extensions/filters/http/oauth2/v3alpha/oauth.proto index e4be64167ed2..11fe12695865 100644 --- a/api/envoy/extensions/filters/http/oauth2/v3alpha/oauth.proto +++ b/api/envoy/extensions/filters/http/oauth2/v3alpha/oauth.proto @@ -44,7 +44,7 @@ message OAuth2Credentials { // OAuth config // -// [#next-free-field: 9] +// [#next-free-field: 10] message OAuth2Config { // Endpoint on the authorization server to retrieve the access token from. config.core.v3.HttpUri token_endpoint = 1; @@ -74,6 +74,11 @@ message OAuth2Config { // Any request that matches any of the provided matchers will be passed through without OAuth validation. repeated config.route.v3.HeaderMatcher pass_through_matcher = 8; + + // Optional list of OAuth scopes to be claimed in the authorization request. If not specified, + // defaults to "user" scope. + // OAuth RFC https://tools.ietf.org/html/rfc6749#section-3.3 + repeated string auth_scopes = 9; } // Filter config. diff --git a/api/envoy/extensions/filters/http/oauth2/v4alpha/oauth.proto b/api/envoy/extensions/filters/http/oauth2/v4alpha/oauth.proto index ee51e1f96099..af1f0944ed34 100644 --- a/api/envoy/extensions/filters/http/oauth2/v4alpha/oauth.proto +++ b/api/envoy/extensions/filters/http/oauth2/v4alpha/oauth.proto @@ -47,7 +47,7 @@ message OAuth2Credentials { // OAuth config // -// [#next-free-field: 9] +// [#next-free-field: 10] message OAuth2Config { option (udpa.annotations.versioning).previous_message_type = "envoy.extensions.filters.http.oauth2.v3alpha.OAuth2Config"; @@ -80,6 +80,11 @@ message OAuth2Config { // Any request that matches any of the provided matchers will be passed through without OAuth validation. repeated config.route.v4alpha.HeaderMatcher pass_through_matcher = 8; + + // Optional list of OAuth scopes to be claimed in the authorization request. If not specified, + // defaults to "user" scope. + // OAuth RFC https://tools.ietf.org/html/rfc6749#section-3.3 + repeated string auth_scopes = 9; } // Filter config. diff --git a/docs/root/configuration/http/http_filters/oauth2_filter.rst b/docs/root/configuration/http/http_filters/oauth2_filter.rst index 6b8b9789a5c7..ebd2f9cdff5f 100644 --- a/docs/root/configuration/http/http_filters/oauth2_filter.rst +++ b/docs/root/configuration/http/http_filters/oauth2_filter.rst @@ -71,6 +71,11 @@ The following is an example configuring the filter. name: hmac sds_config: path: "/etc/envoy/hmac.yaml" + # (Optional): defaults to 'user' scope if not provided + auth_scopes: + - user + - openid + - email Below is a complete code example of how we employ the filter as one of :ref:`HttpConnectionManager HTTP filters @@ -114,6 +119,11 @@ Below is a complete code example of how we employ the filter as one of name: hmac sds_config: path: "/etc/envoy/hmac.yaml" + # (Optional): defaults to 'user' scope if not provided + auth_scopes: + - user + - openid + - email - name: envoy.router tracing: {} codec_type: "AUTO" diff --git a/docs/root/version_history/current.rst b/docs/root/version_history/current.rst index 7a3988a42ea8..a043b03f6357 100644 --- a/docs/root/version_history/current.rst +++ b/docs/root/version_history/current.rst @@ -9,6 +9,7 @@ Minor Behavior Changes ---------------------- *Changes that may cause incompatibilities for some users, but should not for most* +* oauth filter: added the optional parameter :ref:`auth_scopes ` with default value of 'user' if not provided. Enables this value to be overridden in the Authorization request to the OAuth provider. * tcp: setting NODELAY in the base connection class. This should have no effect for TCP or HTTP proxying, but may improve throughput in other areas. This behavior can be temporarily reverted by setting `envoy.reloadable_features.always_nodelay` to false. * upstream: host weight changes now cause a full load balancer rebuild as opposed to happening atomically inline. This change has been made to support load balancer pre-computation of data diff --git a/generated_api_shadow/envoy/extensions/filters/http/oauth2/v3alpha/oauth.proto b/generated_api_shadow/envoy/extensions/filters/http/oauth2/v3alpha/oauth.proto index e4be64167ed2..11fe12695865 100644 --- a/generated_api_shadow/envoy/extensions/filters/http/oauth2/v3alpha/oauth.proto +++ b/generated_api_shadow/envoy/extensions/filters/http/oauth2/v3alpha/oauth.proto @@ -44,7 +44,7 @@ message OAuth2Credentials { // OAuth config // -// [#next-free-field: 9] +// [#next-free-field: 10] message OAuth2Config { // Endpoint on the authorization server to retrieve the access token from. config.core.v3.HttpUri token_endpoint = 1; @@ -74,6 +74,11 @@ message OAuth2Config { // Any request that matches any of the provided matchers will be passed through without OAuth validation. repeated config.route.v3.HeaderMatcher pass_through_matcher = 8; + + // Optional list of OAuth scopes to be claimed in the authorization request. If not specified, + // defaults to "user" scope. + // OAuth RFC https://tools.ietf.org/html/rfc6749#section-3.3 + repeated string auth_scopes = 9; } // Filter config. diff --git a/generated_api_shadow/envoy/extensions/filters/http/oauth2/v4alpha/oauth.proto b/generated_api_shadow/envoy/extensions/filters/http/oauth2/v4alpha/oauth.proto index ee51e1f96099..af1f0944ed34 100644 --- a/generated_api_shadow/envoy/extensions/filters/http/oauth2/v4alpha/oauth.proto +++ b/generated_api_shadow/envoy/extensions/filters/http/oauth2/v4alpha/oauth.proto @@ -47,7 +47,7 @@ message OAuth2Credentials { // OAuth config // -// [#next-free-field: 9] +// [#next-free-field: 10] message OAuth2Config { option (udpa.annotations.versioning).previous_message_type = "envoy.extensions.filters.http.oauth2.v3alpha.OAuth2Config"; @@ -80,6 +80,11 @@ message OAuth2Config { // Any request that matches any of the provided matchers will be passed through without OAuth validation. repeated config.route.v4alpha.HeaderMatcher pass_through_matcher = 8; + + // Optional list of OAuth scopes to be claimed in the authorization request. If not specified, + // defaults to "user" scope. + // OAuth RFC https://tools.ietf.org/html/rfc6749#section-3.3 + repeated string auth_scopes = 9; } // Filter config. diff --git a/source/extensions/filters/http/oauth2/filter.cc b/source/extensions/filters/http/oauth2/filter.cc index aa1396ec9302..892ab8a9abcd 100644 --- a/source/extensions/filters/http/oauth2/filter.cc +++ b/source/extensions/filters/http/oauth2/filter.cc @@ -48,7 +48,7 @@ constexpr const char* CookieTailHttpOnlyFormatString = ";version=1;path=/;Max-Age={};secure;HttpOnly"; const char* AuthorizationEndpointFormat = - "{}?client_id={}&scope=user&response_type=code&redirect_uri={}&state={}"; + "{}?client_id={}&scope={}&response_type=code&redirect_uri={}&state={}"; constexpr absl::string_view UnauthorizedBodyMessage = "OAuth flow failed."; @@ -60,6 +60,7 @@ constexpr absl::string_view REDIRECT_RACE = "oauth.race_redirect"; constexpr absl::string_view REDIRECT_LOGGED_IN = "oauth.logged_in"; constexpr absl::string_view REDIRECT_FOR_CREDENTIALS = "oauth.missing_credentials"; constexpr absl::string_view SIGN_OUT = "oauth.sign_out"; +constexpr absl::string_view DEFAULT_AUTH_SCOPE = "user"; template std::vector headerMatchers(const T& matcher_protos) { @@ -73,6 +74,25 @@ std::vector headerMatchers(const T& matcher_pro return matchers; } +// Transforms the proto list of 'auth_scopes' into a vector of std::string, also +// handling the default value logic. +std::vector +authScopesList(const Protobuf::RepeatedPtrField& auth_scopes_protos) { + std::vector scopes; + + // If 'auth_scopes' is empty it must return a list with the default value. + if (auth_scopes_protos.empty()) { + scopes.emplace_back(DEFAULT_AUTH_SCOPE); + } else { + scopes.reserve(auth_scopes_protos.size()); + + for (const auto& scope : auth_scopes_protos) { + scopes.emplace_back(scope); + } + } + return scopes; +} + // Sets the auth token as the Bearer token in the authorization header. void setBearerToken(Http::RequestHeaderMap& headers, const std::string& token) { headers.setInline(authorization_handle.handle(), absl::StrCat("Bearer ", token)); @@ -90,6 +110,8 @@ FilterConfig::FilterConfig( redirect_matcher_(proto_config.redirect_path_matcher()), signout_path_(proto_config.signout_path()), secret_reader_(secret_reader), stats_(FilterConfig::generateStats(stats_prefix, scope)), + encoded_auth_scopes_(Http::Utility::PercentEncoding::encode( + absl::StrJoin(authScopesList(proto_config.auth_scopes()), " "), ":/=&? ")), forward_bearer_token_(proto_config.forward_bearer_token()), pass_through_header_matchers_(headerMatchers(proto_config.pass_through_matcher())) { if (!cluster_manager.clusters().hasCluster(oauth_token_endpoint_.cluster())) { @@ -275,9 +297,9 @@ Http::FilterHeadersStatus OAuth2Filter::decodeHeaders(Http::RequestHeaderMap& he const std::string escaped_redirect_uri = Http::Utility::PercentEncoding::encode(redirect_uri, ":/=&?"); - const std::string new_url = - fmt::format(AuthorizationEndpointFormat, config_->authorizationEndpoint(), - config_->clientId(), escaped_redirect_uri, escaped_state); + const std::string new_url = fmt::format( + AuthorizationEndpointFormat, config_->authorizationEndpoint(), config_->clientId(), + config_->encodedAuthScopes(), escaped_redirect_uri, escaped_state); response_headers->setLocation(new_url); decoder_callbacks_->encodeHeaders(std::move(response_headers), true, REDIRECT_FOR_CREDENTIALS); diff --git a/source/extensions/filters/http/oauth2/filter.h b/source/extensions/filters/http/oauth2/filter.h index eae64214ee09..aa2367ab815f 100644 --- a/source/extensions/filters/http/oauth2/filter.h +++ b/source/extensions/filters/http/oauth2/filter.h @@ -123,6 +123,7 @@ class FilterConfig { std::string clientSecret() const { return secret_reader_->clientSecret(); } std::string tokenSecret() const { return secret_reader_->tokenSecret(); } FilterStats& stats() { return stats_; } + const std::string& encodedAuthScopes() const { return encoded_auth_scopes_; } private: static FilterStats generateStats(const std::string& prefix, Stats::Scope& scope); @@ -135,6 +136,7 @@ class FilterConfig { const Matchers::PathMatcher signout_path_; std::shared_ptr secret_reader_; FilterStats stats_; + const std::string encoded_auth_scopes_; const bool forward_bearer_token_ : 1; const std::vector pass_through_header_matchers_; }; diff --git a/source/extensions/filters/http/oauth2/oauth_client.cc b/source/extensions/filters/http/oauth2/oauth_client.cc index 170d4a9a2c98..ec0793587448 100644 --- a/source/extensions/filters/http/oauth2/oauth_client.cc +++ b/source/extensions/filters/http/oauth2/oauth_client.cc @@ -70,6 +70,7 @@ void OAuth2ClientImpl::onSuccess(const Http::AsyncClient::Request&, const auto response_code = message->headers().Status()->value().getStringView(); if (response_code != "200") { ENVOY_LOG(debug, "Oauth response code: {}", response_code); + ENVOY_LOG(debug, "Oauth response body: {}", message->bodyAsString()); parent_->sendUnauthorizedResponse(); return; } diff --git a/test/extensions/filters/http/oauth2/config_test.cc b/test/extensions/filters/http/oauth2/config_test.cc index 869d917b6e4e..f9f7d24a7978 100644 --- a/test/extensions/filters/http/oauth2/config_test.cc +++ b/test/extensions/filters/http/oauth2/config_test.cc @@ -47,6 +47,10 @@ void expectInvalidSecretConfig(const std::string& failed_secret_name, signout_path: path: exact: /signout + auth_scopes: + - user + - openid + - email )EOF"; OAuth2Config factory; @@ -87,6 +91,10 @@ TEST(ConfigTest, CreateFilter) { signout_path: path: exact: /signout + auth_scopes: + - user + - openid + - email )EOF"; OAuth2Config factory; diff --git a/test/extensions/filters/http/oauth2/filter_test.cc b/test/extensions/filters/http/oauth2/filter_test.cc index dd5fafd64670..c4a04d24c37b 100644 --- a/test/extensions/filters/http/oauth2/filter_test.cc +++ b/test/extensions/filters/http/oauth2/filter_test.cc @@ -35,6 +35,8 @@ static const std::string TEST_CALLBACK = "/_oauth"; static const std::string TEST_CLIENT_ID = "1"; static const std::string TEST_CLIENT_SECRET_ID = "MyClientSecretKnoxID"; static const std::string TEST_TOKEN_SECRET_ID = "MyTokenSecretKnoxID"; +static const std::string TEST_DEFAULT_SCOPE = "user"; +static const std::string TEST_ENCODED_AUTH_SCOPES = "user%20openid%20email"; namespace { Http::RegisterCustomInlineHeader @@ -78,12 +80,22 @@ class OAuth2Test : public testing::Test { init(); } - void init() { - // Set up the OAuth client + void init() { init(getConfig()); } + + void init(FilterConfigSharedPtr config) { + // Set up the OAuth client. oauth_client_ = new MockOAuth2Client(); std::unique_ptr oauth_client_ptr{oauth_client_}; - // Set up proto fields + config_ = config; + filter_ = std::make_shared(config_, std::move(oauth_client_ptr), test_time_); + filter_->setDecoderFilterCallbacks(decoder_callbacks_); + validator_ = std::make_shared(); + filter_->validator_ = validator_; + } + + // Set up proto fields with standard config. + FilterConfigSharedPtr getConfig() { envoy::extensions::filters::http::oauth2::v3alpha::OAuth2Config p; auto* endpoint = p.mutable_token_endpoint(); endpoint->set_cluster("auth.example.com"); @@ -94,10 +106,12 @@ class OAuth2Test : public testing::Test { p.set_authorization_endpoint("https://auth.example.com/oauth/authorize/"); p.mutable_signout_path()->mutable_path()->set_exact("/_signout"); p.set_forward_bearer_token(true); + p.add_auth_scopes("user"); + p.add_auth_scopes("openid"); + p.add_auth_scopes("email"); auto* matcher = p.add_pass_through_matcher(); matcher->set_name(":method"); matcher->set_exact_match("OPTIONS"); - auto credentials = p.mutable_credentials(); credentials->set_client_id(TEST_CLIENT_ID); credentials->mutable_token_secret()->set_name("secret"); @@ -105,15 +119,12 @@ class OAuth2Test : public testing::Test { MessageUtil::validate(p, ProtobufMessage::getStrictValidationVisitor()); - // Create the OAuth config. + // Create filter config. auto secret_reader = std::make_shared(); - config_ = std::make_shared(p, factory_context_.cluster_manager_, secret_reader, - scope_, "test."); + FilterConfigSharedPtr c = std::make_shared(p, factory_context_.cluster_manager_, + secret_reader, scope_, "test."); - filter_ = std::make_shared(config_, std::move(oauth_client_ptr), test_time_); - filter_->setDecoderFilterCallbacks(decoder_callbacks_); - validator_ = std::make_shared(); - filter_->validator_ = validator_; + return c; } Http::AsyncClient::Callbacks* popPendingCallback() { @@ -151,6 +162,73 @@ TEST_F(OAuth2Test, InvalidCluster) { "specify which cluster to direct OAuth requests to."); } +// Verifies that the OAuth config is created with a default value for auth_scopes field when it is +// not set in proto/yaml. +TEST_F(OAuth2Test, DefaultAuthScope) { + + // Set up proto fields with no auth scope set. + envoy::extensions::filters::http::oauth2::v3alpha::OAuth2Config p; + auto* endpoint = p.mutable_token_endpoint(); + endpoint->set_cluster("auth.example.com"); + endpoint->set_uri("auth.example.com/_oauth"); + endpoint->mutable_timeout()->set_seconds(1); + p.set_redirect_uri("%REQ(x-forwarded-proto)%://%REQ(:authority)%" + TEST_CALLBACK); + p.mutable_redirect_path_matcher()->mutable_path()->set_exact(TEST_CALLBACK); + p.set_authorization_endpoint("https://auth.example.com/oauth/authorize/"); + p.mutable_signout_path()->mutable_path()->set_exact("/_signout"); + p.set_forward_bearer_token(true); + auto* matcher = p.add_pass_through_matcher(); + matcher->set_name(":method"); + matcher->set_exact_match("OPTIONS"); + + auto credentials = p.mutable_credentials(); + credentials->set_client_id(TEST_CLIENT_ID); + credentials->mutable_token_secret()->set_name("secret"); + credentials->mutable_hmac_secret()->set_name("hmac"); + + MessageUtil::validate(p, ProtobufMessage::getStrictValidationVisitor()); + + // Create the OAuth config. + auto secret_reader = std::make_shared(); + FilterConfigSharedPtr test_config_; + test_config_ = std::make_shared(p, factory_context_.cluster_manager_, secret_reader, + scope_, "test."); + + // Auth_scopes was not set, should return default value. + EXPECT_EQ(test_config_->encodedAuthScopes(), TEST_DEFAULT_SCOPE); + + // Recreate the filter with current config and test if the scope was added + // as a query parameter in response headers. + init(test_config_); + Http::TestRequestHeaderMapImpl request_headers{ + {Http::Headers::get().Path.get(), "/not/_oauth"}, + {Http::Headers::get().Host.get(), "traffic.example.com"}, + {Http::Headers::get().Method.get(), Http::Headers::get().MethodValues.Get}, + {Http::Headers::get().Scheme.get(), "http"}, + {Http::Headers::get().ForwardedProto.get(), "http"}, + }; + + Http::TestResponseHeaderMapImpl response_headers{ + {Http::Headers::get().Status.get(), "302"}, + {Http::Headers::get().Location.get(), + "https://auth.example.com/oauth/" + "authorize/?client_id=" + + TEST_CLIENT_ID + "&scope=" + TEST_DEFAULT_SCOPE + + "&response_type=code&" + "redirect_uri=http%3A%2F%2Ftraffic.example.com%2F" + "_oauth&state=http%3A%2F%2Ftraffic.example.com%2Fnot%2F_oauth"}, + }; + + // explicitly tell the validator to fail the validation. + EXPECT_CALL(*validator_, setParams(_, _)); + EXPECT_CALL(*validator_, isValid()).WillOnce(Return(false)); + + EXPECT_CALL(decoder_callbacks_, encodeHeaders_(HeaderMapEqualRef(&response_headers), true)); + + EXPECT_EQ(Http::FilterHeadersStatus::StopIteration, + filter_->decodeHeaders(request_headers, false)); +} + /** * Scenario: The OAuth filter receives a sign out request. * @@ -243,8 +321,8 @@ TEST_F(OAuth2Test, OAuthErrorNonOAuthHttpCallback) { {Http::Headers::get().Location.get(), "https://auth.example.com/oauth/" "authorize/?client_id=" + - TEST_CLIENT_ID + - "&scope=user&response_type=code&" + TEST_CLIENT_ID + "&scope=" + TEST_ENCODED_AUTH_SCOPES + + "&response_type=code&" "redirect_uri=http%3A%2F%2Ftraffic.example.com%2F" "_oauth&state=http%3A%2F%2Ftraffic.example.com%2Fnot%2F_oauth"}, }; @@ -397,8 +475,8 @@ TEST_F(OAuth2Test, OAuthTestInvalidUrlInStateQueryParam) { Http::TestRequestHeaderMapImpl request_headers{ {Http::Headers::get().Host.get(), "traffic.example.com"}, {Http::Headers::get().Method.get(), Http::Headers::get().MethodValues.Get}, - {Http::Headers::get().Path.get(), "/_oauth?code=abcdefxyz123&scope=user&" - "state=blah"}, + {Http::Headers::get().Path.get(), + "/_oauth?code=abcdefxyz123&scope=" + TEST_ENCODED_AUTH_SCOPES + "&state=blah"}, {Http::Headers::get().Cookie.get(), "OauthExpires=123;version=test"}, {Http::Headers::get().Cookie.get(), "BearerToken=legit_token;version=test"}, {Http::Headers::get().Cookie.get(), @@ -431,8 +509,10 @@ TEST_F(OAuth2Test, OAuthTestCallbackUrlInStateQueryParam) { Http::TestRequestHeaderMapImpl request_headers{ {Http::Headers::get().Host.get(), "traffic.example.com"}, {Http::Headers::get().Method.get(), Http::Headers::get().MethodValues.Get}, - {Http::Headers::get().Path.get(), "/_oauth?code=abcdefxyz123&scope=user&" - "state=https%3A%2F%2Ftraffic.example.com%2F_oauth"}, + {Http::Headers::get().Path.get(), + "/_oauth?code=abcdefxyz123&scope=" + TEST_ENCODED_AUTH_SCOPES + + "&state=https%3A%2F%2Ftraffic.example.com%2F_oauth"}, + {Http::Headers::get().Cookie.get(), "OauthExpires=123;version=test"}, {Http::Headers::get().Cookie.get(), "BearerToken=legit_token;version=test"}, {Http::Headers::get().Cookie.get(), @@ -462,8 +542,9 @@ TEST_F(OAuth2Test, OAuthTestCallbackUrlInStateQueryParam) { Http::TestRequestHeaderMapImpl final_request_headers{ {Http::Headers::get().Host.get(), "traffic.example.com"}, {Http::Headers::get().Method.get(), Http::Headers::get().MethodValues.Get}, - {Http::Headers::get().Path.get(), "/_oauth?code=abcdefxyz123&scope=user&" - "state=https%3A%2F%2Ftraffic.example.com%2F_oauth"}, + {Http::Headers::get().Path.get(), + "/_oauth?code=abcdefxyz123&scope=" + TEST_ENCODED_AUTH_SCOPES + + "&state=https%3A%2F%2Ftraffic.example.com%2F_oauth"}, {Http::Headers::get().Cookie.get(), "OauthExpires=123;version=test"}, {Http::Headers::get().Cookie.get(), "BearerToken=legit_token;version=test"}, {Http::Headers::get().Cookie.get(), @@ -487,8 +568,9 @@ TEST_F(OAuth2Test, OAuthTestUpdatePathAfterSuccess) { Http::TestRequestHeaderMapImpl request_headers{ {Http::Headers::get().Host.get(), "traffic.example.com"}, {Http::Headers::get().Method.get(), Http::Headers::get().MethodValues.Get}, - {Http::Headers::get().Path.get(), "/_oauth?code=abcdefxyz123&scope=user&" - "state=https%3A%2F%2Ftraffic.example.com%2Foriginal_path"}, + {Http::Headers::get().Path.get(), + "/_oauth?code=abcdefxyz123&scope=" + TEST_ENCODED_AUTH_SCOPES + + "&state=https%3A%2F%2Ftraffic.example.com%2Foriginal_path"}, {Http::Headers::get().Cookie.get(), "OauthExpires=123;version=test"}, {Http::Headers::get().Cookie.get(), "BearerToken=legit_token;version=test"}, {Http::Headers::get().Cookie.get(), @@ -516,8 +598,9 @@ TEST_F(OAuth2Test, OAuthTestUpdatePathAfterSuccess) { Http::TestRequestHeaderMapImpl final_request_headers{ {Http::Headers::get().Host.get(), "traffic.example.com"}, {Http::Headers::get().Method.get(), Http::Headers::get().MethodValues.Get}, - {Http::Headers::get().Path.get(), "/_oauth?code=abcdefxyz123&scope=user&" - "state=https%3A%2F%2Ftraffic.example.com%2Foriginal_path"}, + {Http::Headers::get().Path.get(), + "/_oauth?code=abcdefxyz123&scope=" + TEST_ENCODED_AUTH_SCOPES + + "&state=https%3A%2F%2Ftraffic.example.com%2Foriginal_path"}, {Http::Headers::get().Cookie.get(), "OauthExpires=123;version=test"}, {Http::Headers::get().Cookie.get(), "BearerToken=legit_token;version=test"}, {Http::Headers::get().Cookie.get(), @@ -550,8 +633,8 @@ TEST_F(OAuth2Test, OAuthTestFullFlowPostWithParameters) { {Http::Headers::get().Location.get(), "https://auth.example.com/oauth/" "authorize/?client_id=" + - TEST_CLIENT_ID + - "&scope=user&response_type=code&" + TEST_CLIENT_ID + "&scope=" + TEST_ENCODED_AUTH_SCOPES + + "&response_type=code&" "redirect_uri=https%3A%2F%2Ftraffic.example.com%2F" "_oauth&state=https%3A%2F%2Ftraffic.example.com%2Ftest%" "3Fname%3Dadmin%26level%3Dtrace"}, diff --git a/test/extensions/filters/http/oauth2/oauth_integration_test.cc b/test/extensions/filters/http/oauth2/oauth_integration_test.cc index 565f4349ba94..14ec8dca4bac 100644 --- a/test/extensions/filters/http/oauth2/oauth_integration_test.cc +++ b/test/extensions/filters/http/oauth2/oauth_integration_test.cc @@ -58,6 +58,10 @@ name: oauth name: token hmac_secret: name: hmac + auth_scopes: + - user + - openid + - email )EOF"); // Add the OAuth cluster.