-
Notifications
You must be signed in to change notification settings - Fork 5.4k
ext_authz: support modifying and removing query string parameters when using a gRPC authorization server #18009
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Changes from 5 commits
12230f0
a934913
cad93ec
426a467
25b2eeb
5c9c01e
06a6338
b9fc09e
251655e
7686b3c
9edf4c0
591f75a
b2b3dec
e67a46e
43aae44
95872b4
68185f1
2d63f10
08ba422
617f90e
32786f4
46004e6
e740588
427be58
181dcc1
4474842
ddcd3aa
a2674e3
020918e
19383d6
7b52929
8837536
5fe5ee3
a9d7f5a
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.
| Original file line number | Diff line number | Diff line change |
|---|---|---|
|
|
@@ -57,6 +57,18 @@ void GrpcClientImpl::onSuccess(std::unique_ptr<envoy::service::auth::v3::CheckRe | |
| authz_response->headers_to_remove.push_back(Http::LowerCaseString(header)); | ||
| } | ||
| } | ||
| if (response->ok_response().query_parameters_to_set_size() > 0) { | ||
| for (const auto& query_parameter : response->ok_response().query_parameters_to_set()) { | ||
| // TODO(esmet): It might make more sense to store query_parameters_to_set as a vector | ||
| // instead of a map since we will likely only ever iterate them linearly. | ||
|
Member
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. I agree with this, should we go ahead with this PR?
Contributor
Author
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. I'll work on adding QueryParamsVector for this. |
||
| if (query_parameter.remove()) { | ||
| authz_response->query_parameters_to_remove.push_back(query_parameter.key()); | ||
| } else { | ||
| authz_response->query_parameters_to_set[query_parameter.key()] = | ||
| query_parameter.value(); | ||
| } | ||
| } | ||
| } | ||
| if (response->ok_response().response_headers_to_add_size() > 0) { | ||
| for (const auto& header : response->ok_response().response_headers_to_add()) { | ||
| authz_response->response_headers_to_add.emplace_back( | ||
|
|
||
| Original file line number | Diff line number | Diff line change | ||||||||
|---|---|---|---|---|---|---|---|---|---|---|
|
|
@@ -213,12 +213,13 @@ void Filter::onComplete(Filters::Common::ExtAuthz::ResponsePtr&& response) { | |||||||||
|
|
||||||||||
| switch (response->status) { | ||||||||||
| case CheckStatus::OK: { | ||||||||||
| // Any changes to request headers can affect how the request is going to be | ||||||||||
| // Any changes to request headers or query parameters can affect how the request is going to be | ||||||||||
|
Member
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Thanks for this. I totally forgot that we have a route matcher to match query params. envoy/api/envoy/config/route/v3/route_components.proto Lines 1995 to 1998 in 7d3057f
|
||||||||||
| // routed. If we are changing the headers we also need to clear the route | ||||||||||
| // cache. | ||||||||||
| if (config_->clearRouteCache() && | ||||||||||
| (!response->headers_to_set.empty() || !response->headers_to_append.empty() || | ||||||||||
| !response->headers_to_remove.empty())) { | ||||||||||
| !response->headers_to_remove.empty() || !response->query_parameters_to_set.empty() || | ||||||||||
| !response->query_parameters_to_remove.empty())) { | ||||||||||
| ENVOY_STREAM_LOG(debug, "ext_authz is clearing route cache", *decoder_callbacks_); | ||||||||||
| decoder_callbacks_->clearRouteCache(); | ||||||||||
| } | ||||||||||
|
|
@@ -271,6 +272,50 @@ void Filter::onComplete(Filters::Common::ExtAuthz::ResponsePtr&& response) { | |||||||||
| response_headers_to_add_ = std::move(response->response_headers_to_add); | ||||||||||
| } | ||||||||||
|
|
||||||||||
| absl::optional<Http::Utility::QueryParams> modified_query_parameters; | ||||||||||
| if (!response->query_parameters_to_set.empty()) { | ||||||||||
| modified_query_parameters = | ||||||||||
| Http::Utility::parseQueryString(request_headers_->Path()->value().getStringView()); | ||||||||||
| ENVOY_STREAM_LOG( | ||||||||||
| trace, "ext_authz filter set query parameter(s) on the request:", *decoder_callbacks_); | ||||||||||
| for (const auto& [key, value] : response->query_parameters_to_set) { | ||||||||||
| ENVOY_STREAM_LOG(trace, "'{}={}'", *decoder_callbacks_, key, value); | ||||||||||
| // TODO(esmet): Sanitize key/value and/or declare the security posture that we trust the | ||||||||||
| // authorization server. | ||||||||||
|
Contributor
Author
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Trusting the auth server seems obvious but I still need to circle back to this TODO
Member
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. File an issue and link it here will be better I think? |
||||||||||
| (*modified_query_parameters)[key] = value; | ||||||||||
| } | ||||||||||
| } | ||||||||||
|
|
||||||||||
| if (!response->query_parameters_to_remove.empty()) { | ||||||||||
| if (!modified_query_parameters) { | ||||||||||
| modified_query_parameters = | ||||||||||
| Http::Utility::parseQueryString(request_headers_->Path()->value().getStringView()); | ||||||||||
| } | ||||||||||
| ENVOY_STREAM_LOG(trace, "ext_authz filter removed query parameter(s) from the request:", | ||||||||||
| *decoder_callbacks_); | ||||||||||
| for (const auto& key : response->query_parameters_to_remove) { | ||||||||||
| ENVOY_STREAM_LOG(trace, "'{}'", *decoder_callbacks_, key); | ||||||||||
| (*modified_query_parameters).erase(key); | ||||||||||
| } | ||||||||||
| } | ||||||||||
|
|
||||||||||
| // We modified the query parameters in some way, so regenerate the `path` header and set it | ||||||||||
| // here. | ||||||||||
| if (modified_query_parameters) { | ||||||||||
| std::string new_path; | ||||||||||
| const auto path_without_query = | ||||||||||
| Http::Utility::stripQueryString(request_headers_->Path()->value()); | ||||||||||
| // TODO: These two lines should probably be abstracted as | ||||||||||
| // Http::Utility::formatPathAndQueryParams | ||||||||||
|
Contributor
Author
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. I still need to do this. |
||||||||||
| const auto new_query_string = | ||||||||||
| Http::Utility::queryParamsToString(modified_query_parameters.value()); | ||||||||||
| absl::StrAppend(&new_path, path_without_query, new_query_string); | ||||||||||
| ENVOY_STREAM_LOG(trace, | ||||||||||
| "ext_authz filter modified query parameter, using new path for request: {}", | ||||||||||
| *decoder_callbacks_, new_path); | ||||||||||
| request_headers_->setPath(new_path); | ||||||||||
| } | ||||||||||
|
|
||||||||||
| if (cluster_) { | ||||||||||
| config_->incCounter(cluster_->statsScope(), config_->ext_authz_ok_); | ||||||||||
| } | ||||||||||
|
|
||||||||||
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This is an open question. I feel like it could be valuable alongside HeaderValueOption.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Yes, that would be a good location, but I think the
removesemantics are a bit weird. Would it be cleaner to structure this similar to headers, withquery_parameters_to_add,query_parameter_to_remove?There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I think I agree with @htuch, though with introducing a new structure the same as
HeaderValue? But with theQueryParameter(?) as its name. We can do that via what is suggested (addingquery_parameters_to_add,query_parameter_to_remove) by Harvey.There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Will do