Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
6 changes: 5 additions & 1 deletion api/envoy/extensions/filters/http/oauth2/v3alpha/oauth.proto
Original file line number Diff line number Diff line change
Expand Up @@ -41,7 +41,7 @@ message OAuth2Credentials {

// OAuth config
//
// [#next-free-field: 10]
// [#next-free-field: 11]
message OAuth2Config {
// Endpoint on the authorization server to retrieve the access token from.
config.core.v3.HttpUri token_endpoint = 1;
Expand Down Expand Up @@ -76,6 +76,10 @@ message OAuth2Config {
// defaults to "user" scope.
// OAuth RFC https://tools.ietf.org/html/rfc6749#section-3.3
repeated string auth_scopes = 9;

// Optional resource parameter for authorization request
// RFC: https://tools.ietf.org/html/rfc8707
repeated string resources = 10;
}

// Filter config.
Expand Down
6 changes: 5 additions & 1 deletion api/envoy/extensions/filters/http/oauth2/v4alpha/oauth.proto

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

8 changes: 8 additions & 0 deletions docs/root/configuration/http/http_filters/oauth2_filter.rst
Original file line number Diff line number Diff line change
Expand Up @@ -76,6 +76,10 @@ The following is an example configuring the filter.
- user
- openid
- email
# (Optional): set resource parameter for Authorization request
resources:
- oauth2-resource
- http://example.com

Below is a complete code example of how we employ the filter as one of
:ref:`HttpConnectionManager HTTP filters
Expand Down Expand Up @@ -124,6 +128,10 @@ Below is a complete code example of how we employ the filter as one of
- user
- openid
- email
# (Optional): set resource parameter for Authorization request
resources:
- oauth2-resource
- http://example.com
- name: envoy.router
tracing: {}
codec_type: "AUTO"
Expand Down
1 change: 1 addition & 0 deletions docs/root/version_history/current.rst
Original file line number Diff line number Diff line change
Expand Up @@ -116,6 +116,7 @@ New Features
* json: introduced new JSON parser (https://github.com/nlohmann/json) to replace RapidJSON. The new parser is disabled by default. To test the new RapidJSON parser, enable the runtime feature `envoy.reloadable_features.remove_legacy_json`.
* kill_request: :ref:`Kill Request <config_http_filters_kill_request>` Now supports bidirection killing.
* log: added a new custom flag ``%j`` to the log pattern to print the actual message to log as JSON escaped string.
* oauth filter: added the optional parameter :ref:`resources <envoy_v3_api_field_extensions.filters.http.oauth2.v3alpha.OAuth2Config.resources>`. Set this value to add multiple "resource" parameters in the Authorization request sent to the OAuth provider. This acts as an identifier representing the protected resources the client is requesting a token for.
* original_dst: added support for :ref:`Original Destination <config_listener_filters_original_dst>` on Windows. This enables the use of Envoy as a sidecar proxy on Windows.
* overload: add support for scaling :ref:`transport connection timeouts<envoy_v3_api_enum_value_config.overload.v3.ScaleTimersOverloadActionConfig.TimerType.TRANSPORT_SOCKET_CONNECT>`. This can be used to reduce the TLS handshake timeout in response to overload.
* postgres: added ability to :ref:`terminate SSL<envoy_v3_api_field_extensions.filters.network.postgres_proxy.v3alpha.PostgresProxy.terminate_ssl>`.
Expand Down

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

14 changes: 13 additions & 1 deletion source/extensions/filters/http/oauth2/filter.cc
Original file line number Diff line number Diff line change
Expand Up @@ -93,6 +93,16 @@ authScopesList(const Protobuf::RepeatedPtrField<std::string>& auth_scopes_protos
return scopes;
}

// Transforms the proto list into encoded resource params
// Takes care of percentage encoding http and https is needed
std::string encodeResourceList(const Protobuf::RepeatedPtrField<std::string>& resources_protos) {
std::string result = "";
for (const auto& resource : resources_protos) {
result += "&resource=" + Http::Utility::PercentEncoding::encode(resource, ":/=&? ");
}
return result;
}

// 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));
Expand All @@ -112,6 +122,7 @@ FilterConfig::FilterConfig(
stats_(FilterConfig::generateStats(stats_prefix, scope)),
encoded_auth_scopes_(Http::Utility::PercentEncoding::encode(
absl::StrJoin(authScopesList(proto_config.auth_scopes()), " "), ":/=&? ")),
encoded_resource_query_params_(encodeResourceList(proto_config.resources())),
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())) {
Expand Down Expand Up @@ -300,7 +311,8 @@ Http::FilterHeadersStatus OAuth2Filter::decodeHeaders(Http::RequestHeaderMap& he
const std::string new_url = fmt::format(
AuthorizationEndpointFormat, config_->authorizationEndpoint(), config_->clientId(),
config_->encodedAuthScopes(), escaped_redirect_uri, escaped_state);
response_headers->setLocation(new_url);

response_headers->setLocation(new_url + config_->encodedResourceQueryParams());
decoder_callbacks_->encodeHeaders(std::move(response_headers), true, REDIRECT_FOR_CREDENTIALS);

config_->stats().oauth_unauthorized_rq_.inc();
Expand Down
2 changes: 2 additions & 0 deletions source/extensions/filters/http/oauth2/filter.h
Original file line number Diff line number Diff line change
Expand Up @@ -126,6 +126,7 @@ class FilterConfig {
std::string tokenSecret() const { return secret_reader_->tokenSecret(); }
FilterStats& stats() { return stats_; }
const std::string& encodedAuthScopes() const { return encoded_auth_scopes_; }
const std::string& encodedResourceQueryParams() const { return encoded_resource_query_params_; }

private:
static FilterStats generateStats(const std::string& prefix, Stats::Scope& scope);
Expand All @@ -139,6 +140,7 @@ class FilterConfig {
std::shared_ptr<SecretReader> secret_reader_;
FilterStats stats_;
const std::string encoded_auth_scopes_;
const std::string encoded_resource_query_params_;
const bool forward_bearer_token_ : 1;
const std::vector<Http::HeaderUtility::HeaderData> pass_through_header_matchers_;
};
Expand Down
8 changes: 8 additions & 0 deletions test/extensions/filters/http/oauth2/config_test.cc
Original file line number Diff line number Diff line change
Expand Up @@ -51,6 +51,10 @@ void expectInvalidSecretConfig(const std::string& failed_secret_name,
- user
- openid
- email
resources:
- oauth2-resource
- http://example.com
- https://example.com
)EOF";

OAuth2Config factory;
Expand Down Expand Up @@ -95,6 +99,10 @@ TEST(ConfigTest, CreateFilter) {
- user
- openid
- email
resources:
- oauth2-resource
- http://example.com
- https://example.com
)EOF";

OAuth2Config factory;
Expand Down
14 changes: 12 additions & 2 deletions test/extensions/filters/http/oauth2/filter_test.cc
Original file line number Diff line number Diff line change
Expand Up @@ -109,6 +109,9 @@ class OAuth2Test : public testing::Test {
p.add_auth_scopes("user");
p.add_auth_scopes("openid");
p.add_auth_scopes("email");
p.add_resources("oauth2-resource");
p.add_resources("http://example.com");
p.add_resources("https://example.com");
auto* matcher = p.add_pass_through_matcher();
matcher->set_name(":method");
matcher->set_exact_match("OPTIONS");
Expand Down Expand Up @@ -197,6 +200,9 @@ TEST_F(OAuth2Test, DefaultAuthScope) {
// Auth_scopes was not set, should return default value.
EXPECT_EQ(test_config_->encodedAuthScopes(), TEST_DEFAULT_SCOPE);

// resource is optional
EXPECT_EQ(test_config_->encodedResourceQueryParams(), "");

// Recreate the filter with current config and test if the scope was added
// as a query parameter in response headers.
init(test_config_);
Expand Down Expand Up @@ -324,7 +330,9 @@ TEST_F(OAuth2Test, OAuthErrorNonOAuthHttpCallback) {
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"},
"_oauth&state=http%3A%2F%2Ftraffic.example.com%2Fnot%2F_oauth"
"&resource=oauth2-resource&resource=http%3A%2F%2Fexample.com"
"&resource=https%3A%2F%2Fexample.com"},
};

// explicitly tell the validator to fail the validation
Expand Down Expand Up @@ -634,7 +642,9 @@ TEST_F(OAuth2Test, OAuthTestFullFlowPostWithParameters) {
"&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"},
"3Fname%3Dadmin%26level%3Dtrace"
"&resource=oauth2-resource&resource=http%3A%2F%2Fexample.com"
"&resource=https%3A%2F%2Fexample.com"},
};

// Fail the validation to trigger the OAuth flow.
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -62,6 +62,10 @@ name: oauth
- user
- openid
- email
resources:
- oauth2-resource
- http://example.com
- https://example.com
)EOF");

// Add the OAuth cluster.
Expand Down