Skip to content

jwt_authn: implementation of www-authenticate header#16216

Merged
snowp merged 24 commits intoenvoyproxy:mainfrom
cyran-ryan:add_www_header
Jul 7, 2021
Merged

jwt_authn: implementation of www-authenticate header#16216
snowp merged 24 commits intoenvoyproxy:mainfrom
cyran-ryan:add_www_header

Conversation

@cyran-ryan
Copy link
Copy Markdown
Contributor

@cyran-ryan cyran-ryan commented Apr 28, 2021

For an explanation of how to fill out the fields, please see the relevant section
in PULL_REQUESTS.md

Commit Message: Adds www-authenticate header to jwt_authn responses
Additional Description: Returns a valid www-authenticate header when deny a request with a 401 Unauthorized response, see RFC 7235 and RFC 6750 for information on the spec and error codes this response returns
Risk Level: Medium
Testing:
Docs Changes:
Release Notes:
Platform Specific Features:
[Optional Runtime guard:]
[Optional Fixes #Issue]
[Optional Deprecated:]
[Optional API Considerations:]

@repokitteh-read-only
Copy link
Copy Markdown

Hi @cyran-ryan, welcome and thank you for your contribution.

We will try to review your Pull Request as quickly as possible.

In the meantime, please take a look at the contribution guidelines if you have not done so already.

🐱

Caused by: #16216 was opened by cyran-ryan.

see: more, trace.

@cyran-ryan cyran-ryan changed the title jwt_authn: implementation of www-authenticate header [wip] jwt_authn: implementation of www-authenticate header Apr 28, 2021
Signed-off-by: Ryan Sutton <ryan.sutton@volunteers.acasi.info>
absl::StrJoin(absl::StrSplit(error_msg, ' '), "_"), "}");
}

std::string buildUri(const Http::RequestHeaderMap& request_headers,
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

buildOriginalUri(). This could be move to source/common/http/utility. other modules may need this

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Agreed, I'll put up a change with that shortly

code, ::google::jwt_verify::getStatusString(status), nullptr, absl::nullopt,
code, ::google::jwt_verify::getStatusString(status),
[uri = this->original_uri_](Http::ResponseHeaderMap& headers) {
headers.setCopy(Http::LowerCaseString("www-authenticate"),
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Is it OK to send the same response for "token missing" case?

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

So that's a tough one, it looks like from the OAuth 2.0 RFC (which seems to be the most analogous to this situation) the error field should be included if the token is rejected but not if it's missing. If we think that we just need to follow the 401 Unauthorized RFC, we just need realm to exist.

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

By looking at OAuth 2.0 RFC, for invalid token, server SHOULD add error=.

How about:
for missing we just add "realm=", but for invalid token we also add error=. e.g. "realm=URI, error=invalid_token"

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Agreed! Working on that change today

Signed-off-by: Ryan Sutton <ryan.sutton@volunteers.acasi.info>
@qiwzhang
Copy link
Copy Markdown
Contributor

You need to add some unit-test or integration tests for the change.

@cyran-ryan
Copy link
Copy Markdown
Contributor Author

You need to add some unit-test or integration tests for the change.

Would it be necessary to write an entirely new test for this? Or is it sufficient to add checks in the 401 response integration tests?

@qiwzhang
Copy link
Copy Markdown
Contributor

You need to add some unit-test or integration tests for the change.

Would it be necessary to write an entirely new test for this? Or is it sufficient to add checks in the 401 response integration tests?

The latter is fine. As long as it cover both "missing" and "invalid_token" cases.

Ryan Sutton added 3 commits May 3, 2021 14:33
Signed-off-by: Ryan Sutton <ryan.sutton@volunteers.acasi.info>
Signed-off-by: Ryan Sutton <ryan.sutton@volunteers.acasi.info>
Signed-off-by: Ryan Sutton <ryan.sutton@volunteers.acasi.info>
}
absl::string_view path(request_headers.EnvoyOriginalPath()
? request_headers.getEnvoyOriginalPathValue()
: request_headers.getPathValue());
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

will we have case "envoy-origin-path" exists but not "path"?

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

It appears in the router config_impl, that if envoy-origin-path exists, it is set to the path value. So no, there should not be any possibility of envoy-origin-path existing but path not existing.

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

That code in the router_config runs after headers make it to the router, so I don't think this will have been set at this point. On the other hand I think the check for Path is unnecessary because getPathValue() should return an empty string in that case. Digging into it some more, original-path is only set in for certain route actions, so there might not be a point in reading it at this point at all?

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Ping on this, I think we can simplify this logic

namespace JwtAuthn {

namespace {
const std::string INVALID_TOKEN_ERROR_STRING = "invalid_token";
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

prefer not to use std::string in static, can we use string_view, or char[]

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Swapped to string_view

if (verifier == nullptr) {
onComplete(Status::Ok);
} else {
original_uri_ = Http::Utility::buildOriginalUri(headers, 256);
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Where is 256 coming from? Should we define it somewhere?

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

256 seemed to be a good length limit for URIs in the headers. There are no actual defined limits for how long headers can be, effectively though, many servers will limit the total amount of data headers can use to 8KiB or 16KiB. I'm up for discussion on how long we should allow the generated URI to be. And then yes, I think it's a good idea define the value rather than leaving it as a raw number.

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

It is fine to just const define it.

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Added

if (status != Status::JwtMissed) {
absl::StrAppend(&value, ", error=\"", INVALID_TOKEN_ERROR_STRING, "\"");
}
headers.setCopy(Http::LowerCaseString("www-authenticate"), value);
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

maybe define this LowerCaseString as singleton?

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

How would you go about that? I've looked at a couple solutions but I run into issues with the fact that the filter can be constructed on multiple threads. We could do something with ThreadLocalStorage I suppose.

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

we can use this one directly

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Done

Signed-off-by: Ryan Sutton <ryan.sutton@volunteers.acasi.info>
qiwzhang
qiwzhang previously approved these changes May 7, 2021
@cyran-ryan cyran-ryan marked this pull request as ready for review May 7, 2021 21:36
@cyran-ryan cyran-ryan requested a review from lizan as a code owner May 7, 2021 21:36
Signed-off-by: Ryan Sutton <ryan.sutton@volunteers.acasi.info>
const LowerCaseString Pragma{"pragma"};
const LowerCaseString Referer{"referer"};
const LowerCaseString Vary{"vary"};
const LowerCaseString WwwAuthenticate{"www-authenticate"};
Copy link
Copy Markdown
Contributor

@qiwzhang qiwzhang May 10, 2021

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

You re-defined it. It is defined in line 215.

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Whoops, I looked at the comment on my phone and didn't notice that. Fixing now

Signed-off-by: Ryan Sutton <ryan.sutton@volunteers.acasi.info>
qiwzhang
qiwzhang previously approved these changes May 11, 2021
@repokitteh-read-only
Copy link
Copy Markdown

Retrying Azure Pipelines:
Retried failed jobs in: envoy-presubmit

🐱

Caused by: a #16216 (comment) was created by @snowp.

see: more, trace.

@snowp
Copy link
Copy Markdown
Contributor

snowp commented Jun 23, 2021

Ok the tests passed but I think the refactor of the tracing library caused the coverage % to drop down. Do you think you could add some dummy call to the functions not covered by tests as per https://storage.googleapis.com/envoy-pr/e4f1d82/coverage/source/common/tracing/index.html ? Should be relatively easy and should make CI go green

@snowp snowp added the waiting label Jun 23, 2021
@cyran-ryan
Copy link
Copy Markdown
Contributor Author

Ok the tests passed but I think the refactor of the tracing library caused the coverage % to drop down. Do you think you could add some dummy call to the functions not covered by tests as per https://storage.googleapis.com/envoy-pr/e4f1d82/coverage/source/common/tracing/index.html ? Should be relatively easy and should make CI go green

That's understandable seeing as I removed a good chunk of covered code from those files. I'll work on these today.

Signed-off-by: Ryan Sutton <ryan.sutton@volunteers.acasi.info>
Copy link
Copy Markdown
Contributor

@snowp snowp left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Thanks!

/retest

@repokitteh-read-only
Copy link
Copy Markdown

Retrying Azure Pipelines:
Retried failed jobs in: envoy-presubmit

🐱

Caused by: a #16216 (review) was submitted by @snowp.

see: more, trace.

@cyran-ryan
Copy link
Copy Markdown
Contributor Author

Last question, we would like to cherrypick these changes to 1.18, and 1.17. This is for Istio to pull in for their release 1.9 and 1.10. Is this possible?

@snowp snowp merged commit 9fee580 into envoyproxy:main Jul 7, 2021
@snowp
Copy link
Copy Markdown
Contributor

snowp commented Jul 7, 2021

Current policy limits backports to security and stability fixes I'm afraid. You can try to post an issue about it to discuss, though my knee jerk reaction is that this doesn't qualify.

baojr added a commit to baojr/envoy that referenced this pull request Jul 7, 2021
* main:
  listener: match rebalancer to listener IP family type (envoyproxy#16914)
  jwt_authn: implementation of www-authenticate header (envoyproxy#16216)
  listener: reset the file event in framework instead of listener filter doing itself (envoyproxy#17227)
  Small typo fix (envoyproxy#17247)
  Doc: Clarify request/response attributes are http-only (envoyproxy#17204)
  bazel/README.md: add aspell comment (envoyproxy#17072)
  docs: Fix broken URL links in HTTP upgrades doc (envoyproxy#17225)
  remove the wrong comment on test (envoyproxy#17233)
  upstream: allow clusters to skip waiting on warmup for initialization (envoyproxy#17179)
  JwtAuthn: support completing padding on forward jwt payload header (envoyproxy#16752)
  remove support for v2 UNSUPPORTED_REST_LEGACY (envoyproxy#16968)
  metrics service: fix wrong argument arrange on MetricsServiceSink (envoyproxy#17127)
  deps: update cel-cpp to 0.6.1 (envoyproxy#16293)
  Add ability to filter ConfigDump. (envoyproxy#16774)
  examples: fix Wasm example. (envoyproxy#17218)
  upstream: update host's socket factory when metadata is updated. (envoyproxy#16708)

Signed-off-by: Garrett Bourg <bourg@squareup.com>
@cyran-ryan
Copy link
Copy Markdown
Contributor Author

/backport

@repokitteh-read-only repokitteh-read-only bot added the backport/review Request to backport to stable releases label Jul 14, 2021
cyran-ryan added a commit to cyran-ryan/envoy that referenced this pull request Jul 20, 2021
Signed-off-by: Ryan Sutton <ryan.sutton@volunteers.acasi.info>

Co-authored-by: Lizan Zhou <lizan@tetrate.io>

Signed-off-by: cyran-ryan <58446431+cyran-ryan@users.noreply.github.com>
cyran-ryan added a commit to cyran-ryan/envoy that referenced this pull request Jul 21, 2021
Signed-off-by: Ryan Sutton <ryan.sutton@volunteers.acasi.info>

Co-authored-by: Lizan Zhou <lizan@tetrate.io>

Signed-off-by: cyran-ryan <58446431+cyran-ryan@users.noreply.github.com>
Signed-off-by: Ryan Sutton <ryan.sutton@volunteers.acasi.info>
lizan added a commit that referenced this pull request Jul 28, 2021
Signed-off-by: Ryan Sutton <ryan.sutton@volunteers.acasi.info>
Co-authored-by: Lizan Zhou <lizan@tetrate.io>
lizan added a commit that referenced this pull request Jul 28, 2021
Co-authored-by: Lizan Zhou <lizan@tetrate.io>
Signed-off-by: Ryan Sutton <ryan.sutton@volunteers.acasi.info>
cyran-ryan added a commit to cyran-ryan/envoy that referenced this pull request Aug 10, 2021
… (envoyproxy#17441)

Co-authored-by: Lizan Zhou <lizan@tetrate.io>
Signed-off-by: Ryan Sutton <ryan.sutton@volunteers.acasi.info>
istio-testing added a commit to istio/envoy that referenced this pull request Aug 10, 2021
jwt_authn: implementation of www-authenticate header (envoyproxy#16216) (envoyproxy#17441)
leyao-daily pushed a commit to leyao-daily/envoy that referenced this pull request Sep 30, 2021
Signed-off-by: Ryan Sutton <ryan.sutton@volunteers.acasi.info>

Co-authored-by: Lizan Zhou <lizan@tetrate.io>
@alyssawilk alyssawilk added backport/approved Approved backports to stable releases and removed backport/review Request to backport to stable releases labels Nov 29, 2021
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

backport/approved Approved backports to stable releases

Projects

None yet

Development

Successfully merging this pull request may close these issues.

5 participants