Skip to content

Add rule requirement feature to jwt_authn filter#4101

Merged
mattklein123 merged 23 commits intoenvoyproxy:masterfrom
potatop:jwt_authn_per_route_filter
Sep 20, 2018
Merged

Add rule requirement feature to jwt_authn filter#4101
mattklein123 merged 23 commits intoenvoyproxy:masterfrom
potatop:jwt_authn_per_route_filter

Conversation

@potatop
Copy link
Contributor

@potatop potatop commented Aug 9, 2018

Title: Add rule requirement feature to jwt_authn filter

Description: Add rule requirement feature based on config proto and discussions in #3381.
Requires type provider_and_audiences, requires_any, and requires_all is not implemented.

Risk Level: Medium

Testing: unit test and manual

@potatop potatop requested a review from lizan as a code owner August 9, 2018 22:24
@lizan lizan self-assigned this Aug 9, 2018
Copy link
Contributor

Choose a reason for hiding this comment

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

matchers_ should be created per filter config, not per request. Here Authenticator is created per-request.

You can move them here https://github.com/envoyproxy/envoy/blob/master/source/extensions/filters/http/jwt_authn/filter_config.h#L59

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.

Thanks for taking this.

Copy link
Member

Choose a reason for hiding this comment

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

You can just ommit the parameter name.

Copy link
Member

Choose a reason for hiding this comment

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

also, make the parameter const reference?

Copy link
Member

Choose a reason for hiding this comment

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

snake_case_ for member variables

Copy link
Member

Choose a reason for hiding this comment

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

const ref

Copy link
Member

Choose a reason for hiding this comment

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

just do issuer_ == iss?

Copy link
Member

Choose a reason for hiding this comment

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

no need c_str

Copy link
Member

Choose a reason for hiding this comment

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

from the comment, you don't need a pair, just return a JwtMatcherConstPtr is enough

Copy link
Member

Choose a reason for hiding this comment

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

ConstSharedPtr

Copy link
Member

Choose a reason for hiding this comment

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

RequirementVerifierConstSharedPtr

Copy link
Contributor

Choose a reason for hiding this comment

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

Ideally, we only need to extract the tokens for required providers. So Extractor should take a list of required_issuers.

Copy link
Contributor

Choose a reason for hiding this comment

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

Current approach will be very difficult to extend to support multiple tokens. Especially with such requirements as

  1. require A and B, or 2) require A or B.

Ideally, for 1), if A fail, not need to verify B. for 2) if A success, not need to verify B

But single token is the most common use case. We can worry about supporting multiple tokens later.
Please add // TODO

Copy link
Contributor

Choose a reason for hiding this comment

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

can we move Matcher into a set of .h, and .cc file, and add some unit-test for them.
Same for Verifier.

Copy link
Contributor

Choose a reason for hiding this comment

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

I think we need two functions:
requiredIssuers() to return required issuers. This one is need for Extractor to only extract required tokens.

staus verify(vector<pair<issuer, status>> issuer_status); // after required token are verified, passed their issuers and verified_status to verify if they satisfy the requirement.

Copy link
Contributor Author

Choose a reason for hiding this comment

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

  1. To do this we need to move jwt parser to extractor?
  2. OK I'll do that.

@qiwzhang
Copy link
Contributor

@potatop thanks for helping out this feature. Here are some high level ideas how it should be done:

  1. Eventually we need to support multiple tokens. For now, it is OK to only supports one token, but we need an approach that can be easily extend to support multiple one. Otherwise, it will be a totally re-write in order to support it.

  2. Ideal data flow may look like this:
    a) find the requirement for a request, if no found, just pass the request.
    b) based on the specific requirement, it will try to extract one token and verify it, and make decision to reject or pass the request or continue to work on the next required token.

Copy link
Contributor

Choose a reason for hiding this comment

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

Not need to list verifier.h here again since this lib depends on verifier_lib which already listed it.

Copy link
Contributor

Choose a reason for hiding this comment

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

per google style guide: https://google.github.io/styleguide/cppguide.html
please add comment for each function in the header file.

Copy link
Contributor

Choose a reason for hiding this comment

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

you could implement it here. move line 42- 47 here

Copy link
Contributor

@qiwzhang qiwzhang Aug 10, 2018

Choose a reason for hiding this comment

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

for is_allow_missing_or_failed, try to see if we don't need to make this as a special case.

Copy link
Contributor

Choose a reason for hiding this comment

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

can we have one static function to create a matcher? hide of the logic of creating different matcher inside the function.

Copy link
Contributor

Choose a reason for hiding this comment

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

This checking will not eliminate anything.

What I means is: when each request come, find its matched requirement, and required provider, only extract token for that provider or providers.

Copy link
Contributor Author

@potatop potatop Aug 10, 2018

Choose a reason for hiding this comment

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

Yeah, I realized that later, so I already changed that. However, I'll probably back out all this With extract only returning tokens with expected issuers, this is probably not needed.

@qiwzhang
Copy link
Contributor

@potatop please try to restructure the data flow to following:

a) find the requirement for a request, if no found, just pass the request.
b) based on the specific requirement, repeat the following:
while (next_provider()) {
extract the token for that provider and verify it,
make decision to reject or pass the request
}

@potatop
Copy link
Contributor Author

potatop commented Aug 13, 2018

I'm working to add more tests.

@potatop potatop force-pushed the jwt_authn_per_route_filter branch from 62754b9 to df53323 Compare August 14, 2018 05:08
@potatop
Copy link
Contributor Author

potatop commented Aug 15, 2018

@qiwzhang I updated the code like you asked. Please take another look. Thanks

Copy link
Contributor

Choose a reason for hiding this comment

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

I don't see it is used.

Copy link
Contributor

Choose a reason for hiding this comment

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

Can we pass in a reference, not to make a copy

Copy link
Contributor

Choose a reason for hiding this comment

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

please move these implementation inside the class, e.g. to line 49. It will be easier to read

Copy link
Contributor

Choose a reason for hiding this comment

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

Ideally, not to check all headers or parameters. only check these headers and parameters specified by the required providers

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.

Copy link
Contributor

Choose a reason for hiding this comment

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

In general, I don't like this implementation. It put all logic inside this class. The code is fairly complicated.

Please take a look rbac implementation in Envoy. https://github.com/envoyproxy/envoy/tree/master/source/extensions/filters/common/rbac

Please try to see if we can implement the matcher like that.

@potatop potatop force-pushed the jwt_authn_per_route_filter branch 4 times, most recently from d105bd8 to 7b3c54c Compare August 19, 2018 15:15
@potatop
Copy link
Contributor Author

potatop commented Aug 19, 2018

@qiwzhang What about this? Matchers are created at start up based on the rules configuration.

@potatop potatop force-pushed the jwt_authn_per_route_filter branch from 7b3c54c to d09300f Compare August 20, 2018 02:04
if (state_ == Responded) {
return;
}
if (context_) {
Copy link
Contributor

@qiwzhang qiwzhang Sep 14, 2018

Choose a reason for hiding this comment

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

This should be done by the Verifier.

The correct way is: in BaseVerifierImpl::completeWithStatus() function, before calling the context->callback, call context->cancel()

Copy link
Contributor Author

@potatop potatop Sep 14, 2018

Choose a reason for hiding this comment

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

Ok.

FilterConfigSharedPtr filter_config_;
MockJwksFetcher* fetcher_;
JwksFetcherPtr fetcherPtr_;
JwksFetcherPtr fetcher_ptr_;
Copy link
Contributor

Choose a reason for hiding this comment

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

how about this one is called fetcher_. the one above it is called raw_fetcher_

auth_->verify(headers, std::move(tokens), std::move(on_complete_cb));
}

// This test verifies that when invalid Jwks is fetched, JwksFetchFail status is returned.
Copy link
Contributor

Choose a reason for hiding this comment

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

comment doesn't match the test

Signed-off-by: Kai Yang <kai.yang@intradiem.com>
@potatop potatop force-pushed the jwt_authn_per_route_filter branch from 9505c79 to c083bbd Compare September 14, 2018 21:54
@qiwzhang
Copy link
Contributor

LGTM

qiwzhang
qiwzhang previously approved these changes Sep 14, 2018
@potatop
Copy link
Contributor Author

potatop commented Sep 14, 2018

@lizan Can this be merged now?

@potatop potatop force-pushed the jwt_authn_per_route_filter branch 2 times, most recently from 8af3414 to 05ce051 Compare September 18, 2018 00:07
Signed-off-by: Kai Yang <kai.yang@intradiem.com>
@potatop potatop force-pushed the jwt_authn_per_route_filter branch from 05ce051 to 0ce1d0b Compare September 18, 2018 00:31
@lizan
Copy link
Member

lizan commented Sep 18, 2018

Sorry I was on vacation last Friday, LGTM and I will take another pass tomorrow since this is huge.

@potatop
Copy link
Contributor Author

potatop commented Sep 18, 2018

Ok. Thanks.

Signed-off-by: Kai Yang <kai.yang@intradiem.com>
lizan
lizan previously approved these changes Sep 19, 2018
@potatop
Copy link
Contributor Author

potatop commented Sep 19, 2018

Many thanks @lizan @qiwzhang. Is there anything else I need to do to get this merged?

@lizan
Copy link
Member

lizan commented Sep 19, 2018

@potatop thanks, waiting one of senior maintainers to take a final pass and merge.

Copy link
Member

@mattklein123 mattklein123 left a comment

Choose a reason for hiding this comment

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

Did a high level skim / sanity check and LGTM.

@mattklein123 mattklein123 merged commit c7b2900 into envoyproxy:master Sep 20, 2018
@potatop potatop deleted the jwt_authn_per_route_filter branch September 21, 2018 13:50
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.

5 participants