Skip to content

Creating JwksFetcher interface and impl v2#4242

Merged
htuch merged 23 commits intoenvoyproxy:masterfrom
thales-e-security:master
Sep 14, 2018
Merged

Creating JwksFetcher interface and impl v2#4242
htuch merged 23 commits intoenvoyproxy:masterfrom
thales-e-security:master

Conversation

@nickrmc83
Copy link
Contributor

JwksFetcher wraps up HTTP acquisition of JWKS strings converting them into a concrete type on the way.
JwksFetcher is reusable so can be used in a wider context.

Tests updated and fixed where necessary.
Description:
We are in the process of implementing a new Envoy filter based on the design presented here and wish to re-use existing logic in the jwt_authn filter. We've split out the logic we're interested in into a new class called JwksFetcher. Later PRs will re-use the split out logic an OpenID Connect filter.

This is the second crack at this PR (see #4225 which went horribly wrong after following the DCO rebase guidelines).

Risk Level:
Medium
Testing:
Add replacement and additional unit tests for the logic that's been moved.
Docs Changes:
None
Release Notes:
[Optional Fixes #Issue]
[Optional Deprecated:]

Nick A. Smith added 2 commits August 24, 2018 11:24
JwksFetcher wraps up HTTP acquisition of JWKS strings converting them into a concrete type on the way.
JwksFetcher is reusable so can be used in a wider context.

Tests updated and fixed where necessary.

Signed-off-by: Nick A. Smith <nick.a.smith@thales-esecurity.com>
- Changes from PR review.
- Added missing tests for JwksFetcher::cancel().
- Added comment and TODO around a potential bug in jwt_authn::authenticator.

Signed-off-by: Nick A. Smith <nick.a.smith@thales-esecurity.com>
@nickrmc83 nickrmc83 requested a review from lizan as a code owner August 24, 2018 11:12
return;
}

// TODO: Cross-platform-wise the below unix_timestamp code is wrong as the
Copy link
Contributor Author

Choose a reason for hiding this comment

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

@qiwzhang note comment I've added here.

if (jwks_data_->getJwksObj() != nullptr && !jwks_data_->isExpired()) {
auto jwks_obj = jwks_data_->getJwksObj();
if (jwks_obj != nullptr && !jwks_data_->isExpired()) {
// TODO: It would seem there's a window of error whereby if the JWT issuer
Copy link
Contributor Author

Choose a reason for hiding this comment

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

@qiwzhang note the comment I've added here.

Copy link
Member

Choose a reason for hiding this comment

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

Can you assign a TODO owner, e.g. TODO(nickrmc83)?

@nickrmc83
Copy link
Contributor Author

@qiwzhang @lizan I've started this off again and closed the old PR due to my lack of git foo. I've transported all the original comments here. Apologies

Signed-off-by: Nick A. Smith <nick.a.smith@thales-esecurity.com>
@@ -3,7 +3,7 @@
namespace Envoy {
namespace Extensions {
namespace HttpFilters {
namespace JwtAuthn {
Copy link
Contributor

Choose a reason for hiding this comment

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

It seems that data are still specific to jwt_authn. so the file name is still better call "jwt_authn_common"

Copy link
Contributor Author

Choose a reason for hiding this comment

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

My thinking here was that all JWT related test vectors should reside together especially as they all use the same signing keys. Happy to move if necessary but some of the variables are used in the jwks_fetcher_test

Copy link
Member

Choose a reason for hiding this comment

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

Agreed with @qiwzhang, still JWT specific.

Copy link
Contributor

@qiwzhang qiwzhang left a comment

Choose a reason for hiding this comment

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

Looks pretty good. Only some small comments.

@qiwzhang
Copy link
Contributor

LGTM

@lizan lizan self-assigned this Aug 24, 2018
Nick A. Smith added 2 commits August 28, 2018 21:13
- Removed unused response_message variable
- use of std::make_unique
- Fix enum inline with style guide
- Added missing param documentation
- Added comments re: nbf and exp JWT fields and their default values
- Used reference instead of pointer for non-null function param

Signed-off-by: Nick A. Smith <nick.a.smith@thales-esecurity.com>
Signed-off-by: Nick A. Smith <nick.a.smith@thales-esecurity.com>
@@ -3,7 +3,7 @@
namespace Envoy {
namespace Extensions {
namespace HttpFilters {
namespace JwtAuthn {
Copy link
Member

Choose a reason for hiding this comment

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

Agreed with @qiwzhang, still JWT specific.

The most major change is to swap JwksFetcher creation to be just-in-time using a lambda callback.
Moved test_common.h from test/extensions/filters/http/common back to test/extensions/filters/http/jwt_authn.
Most others changes are minor.

Signed-off-by: Nick A. Smith <nick.a.smith@thales-esecurity.com>
@nickrmc83
Copy link
Contributor Author

nickrmc83 commented Aug 30, 2018

@qiwzhang @lizan I think this is now done with all nits picked. There are some outstanding comments from me that I'd like either of you to resolve specifically regarding the comments I've added to the code for potential areas to be addressed as well as an explanation about why there's a new abseil dependency.

Copy link
Member

@lizan lizan left a comment

Choose a reason for hiding this comment

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

LGTM modulo one comment, thanks!

Signed-off-by: Nick A. Smith <nick.a.smith@thales-esecurity.com>
@lizan
Copy link
Member

lizan commented Aug 30, 2018

fix format?

Signed-off-by: Nick A. Smith <nick.a.smith@thales-esecurity.com>
lizan
lizan previously approved these changes Aug 30, 2018
Signed-off-by: Nick A. Smith <nick.a.smith@thales-esecurity.com>
@@ -465,8 +465,8 @@ def _com_google_absl():
actual = "@com_google_absl//absl/debugging:symbolize",
)

Copy link
Member

Choose a reason for hiding this comment

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

run tools/check_format.py fix, it is complaining about trailing whitespace on this line.

Check_format.py made some unwanted changes to certain lines in baxel/repositories.bzl
that had not been modified. I've reverted those lines in the hope they will take.

Signed-off-by: Nick A. Smith <nick.a.smith@thales-esecurity.com>
lizan
lizan previously approved these changes Sep 3, 2018

void fetch(const ::envoy::api::v2::core::HttpUri& uri, JwksFetcher::JwksReceiver& receiver) {
ENVOY_LOG(trace, "{}", __func__);
receiver_ = &receiver;
Copy link
Member

Choose a reason for hiding this comment

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

What if receiver_ is already set? What is the contract on multiple fetches?

Copy link
Contributor Author

@nickrmc83 nickrmc83 Sep 4, 2018

Choose a reason for hiding this comment

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

@htuch There's a description of the use of the Jwksetcher interface just before the definition in the header file. Would you like further commentary closer to the fetch() method?

Just seen your later comment :)

Copy link
Member

Choose a reason for hiding this comment

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

Can you ASSERT here that recever_ == nullptr, i.e. we catch in debug builds violations of the contract.

/**
* JwksFetcher interface can be used to retrieve remote JWKS
* (https://tools.ietf.org/html/rfc7517) data structures returning a concrete,
* type-safe representation. An instance of this interface is designed to
Copy link
Member

Choose a reason for hiding this comment

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

Ah, you answer the above question here. This is a pretty weird pattern; I would call it out by explicitly naming the class/interface JwksSingleUseFetcher or something like that.

Copy link
Contributor Author

Choose a reason for hiding this comment

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

@htuch I've improved the description of the functionality in 8fa1dc8. I've also made this class re-usable but designed to retrieve a single JWKS at a time.

Mainly small fixes and better documentation.

Signed-off-by: Nick A. Smith <nick.a.smith@thales-esecurity.com>
Copy link
Member

@htuch htuch left a comment

Choose a reason for hiding this comment

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

Looks good! Just a few more comments and this should be ready to go.

virtual void cancel() PURE;

/*
* Retrieve a JWKS resource from a remote HTTP host.
Copy link
Member

Choose a reason for hiding this comment

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

Retrieve a JWKS resource from a remote HTTP host. At most one outstanding request may be in-flight, i.e. from the invocation of `fetch()` until either a callback or `cancel()` is invoked, no additional `fetch()` may be issued.

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Done in 2d18a01

class JwksReceiver {
public:
enum class Failure {
Unknown,
Copy link
Member

Choose a reason for hiding this comment

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

Please comment these reason values.


void fetch(const ::envoy::api::v2::core::HttpUri& uri, JwksFetcher::JwksReceiver& receiver) {
ENVOY_LOG(trace, "{}", __func__);
receiver_ = &receiver;
Copy link
Member

Choose a reason for hiding this comment

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

Can you ASSERT here that recever_ == nullptr, i.e. we catch in debug builds violations of the contract.

}
// If the exp claim does *not* appear in the JWT then the exp field is defaulted
// to 0.
if (jwt_.exp_ && jwt_.exp_ < unix_timestamp) {
Copy link
Member

Choose a reason for hiding this comment

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

Prefer maintaining jwt_.exp_ > 0 as before for clarity.

if (jwks_data_->getJwksObj() != nullptr && !jwks_data_->isExpired()) {
auto jwks_obj = jwks_data_->getJwksObj();
if (jwks_obj != nullptr && !jwks_data_->isExpired()) {
// TODO: It would seem there's a window of error whereby if the JWT issuer
Copy link
Member

Choose a reason for hiding this comment

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

Can you assign a TODO owner, e.g. TODO(nickrmc83)?

Nick A. Smith added 4 commits September 5, 2018 06:28
Changes from final PR review to include missing unit testand fix commenting

Signed-off-by: Nick A. Smith <nick.a.smith@thales-esecurity.com>
Signed-off-by: Nick A. Smith <nick.a.smith@thales-esecurity.com>
Signed-off-by: Nick A. Smith <nick.a.smith@thales-esecurity.com>
This should fix any use-after-free errors

Signed-off-by: Nick A. Smith <nick.a.smith@thales-esecurity.com>
@htuch
Copy link
Member

htuch commented Sep 6, 2018

@nickrmc83 is this now ready for another pass? I.e. coverage fixed etc.

@nickrmc83
Copy link
Contributor Author

@htuch This is now ready.

Copy link
Member

@htuch htuch left a comment

Choose a reason for hiding this comment

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

LGTM, thanks! One last tiny nit and we can ship.

* Expectations and assertions should be made on onJwksSuccessImpl in place
* of onJwksSuccess.
*/
void onJwksSuccess(google::jwt_verify::JwksPtr&& jwks) { onJwksSuccessImpl(jwks); }
Copy link
Member

Choose a reason for hiding this comment

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

Nit: can you change this to pass Jwks& and deref the unique_ptr in args? In general, it doesn't make a lot of sense to pass unique_ptr by ref.

Copy link
Contributor Author

Choose a reason for hiding this comment

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

I've changed onJwksSuccessImpl to receive a const Jwks* to avoid the unique_ptr pass-by-reference.

We now pass by const ptr.

Signed-off-by: Nick A. Smith <nick.a.smith@thales-esecurity.com>
htuch
htuch previously approved these changes Sep 7, 2018
Copy link
Member

@htuch htuch left a comment

Choose a reason for hiding this comment

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

Needs to merge master to resolve a conflict.

Signed-off-by: Nick A. Smith <nick.a.smith@thales-esecurity.com>
nickrmc83 and others added 2 commits September 10, 2018 14:56
Signed-off-by: Nick A. Smith <nick.a.smith@thales-esecurity.com>
Signed-off-by: Nick A. Smith <nick.a.smith@thales-esecurity.com>
@qiwzhang
Copy link
Contributor

LGTM

Nick A. Smith added 2 commits September 12, 2018 21:38
Signed-off-by: Nick A. Smith <nick.a.smith@thales-esecurity.com>
Signed-off-by: Nick A. Smith <nick.a.smith@thales-esecurity.com>
@nickrmc83
Copy link
Contributor Author

@htuch I think this is done with the following caveats

  • My local check_format run shows no errors and the CI failure is giving me no hints.
  • The failing ipv6 looks like an intermittent issue completely outside of the changes in this PR.

Can you advise on the format error?

@htuch
Copy link
Member

htuch commented Sep 13, 2018

@nickrmc83 are you using check_format outside of Docker? If so, maybe you have a version mismatch? Ideally you just run ./ci/run_envoy_docker.sh './ci/do_ci.sh fix_format' and you should have the same behavior as CI.

Signed-off-by: Nick A. Smith <nick.a.smith@thales-esecurity.com>
Copy link
Member

@htuch htuch left a comment

Choose a reason for hiding this comment

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

Thanks! Good to merge.

@htuch htuch merged commit b0ff481 into envoyproxy:master Sep 14, 2018
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

4 participants