Skip to content
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

Numerous improvements #16

Open
wants to merge 1 commit into
base: master
Choose a base branch
from
Open

Conversation

dangoscomb
Copy link

Hi

I have made a number of improvements so that this fits in our environment. I have tried to maintain backwards compatibility but lack of unit tests has made it a little difficult so this would probably need a little testing.

Changes made:

  • allow list of audiences to be checked, not just single
  • configure_with_multiple_jwt_issuers() can now be called with a list of dicts for issuers, instead of strings, in the format:
{
  'url': str, # complete url to the jwks file
  'name': str, # should match the iss claim,
  'audience': str|list[str] # audiences to allow from this issuer
}
  • _authorize() (and calling functions) now accept an optional audience parameter allowing checks for a specific aud on decorators, etc
  • claims that are lists can now be checked with _authorize()
  • prevent exception if scope claim is not present

- configure_with_multiple_jwt_issuers() can now be called with a list of dicts for issuers, instead of strings, in the format:
```python
{
  'url': str, # complete url to the jwks file
  'name': str, # should match the iss claim,
  'audience': str|list[str] # audiences to allow from this issuer
}
```
- _authorize() (and calling functions) now accept an optional audience parameter allowing checks for a specific aud on decorators, etc
- claims that are lists can now be checked with _authorize()
- prevent exception if scope claim is not present
if not isinstance(self.aud, list):
self.aud = [self.aud]

if len(set(self.aud)&set(aud)) == 0:
Copy link
Member

Choose a reason for hiding this comment

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

whitespace around the & operator would be preferable IMO

jwks_url = issuer + "/jwks"
self.validators[issuer] = JwtValidator(jwks_url, issuer, audience, self.verify_ssl)
elif isinstance(issuer, dict):
self.validators[issuer['name']] = JwtValidator(issuer['url'], issuer['name'], issuer['audience'],
Copy link
Member

Choose a reason for hiding this comment

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

what says the issuer is in the name entry of the dictionary? Similar question for url and audience.

if not isinstance(token_claims['aud'], list):
token_claims['aud'] = [token_claims['aud']]

if len(set(endpoint_audience)&set(token_claims['aud'])) == 0:
Copy link
Member

Choose a reason for hiding this comment

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

whitespace before/after &.

return False

if endpoint_claims[claim] is not None:
Copy link
Member

Choose a reason for hiding this comment

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

Does it make sense to factor this out? It's getting to be a lot of nesting here.

if endpoint_claims[claim] is not None:
if isinstance(token_claims[claim], list):
if isinstance(endpoint_claims[claim], list):
if len(set(token_claims[claim])&set(endpoint_claims[claim])) == 0:
Copy link
Member

Choose a reason for hiding this comment

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

whitespace &

Copy link
Member

@mtrojanowski mtrojanowski left a comment

Choose a reason for hiding this comment

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

Hey @dangoscomb,

Thanks for your contribution. Some nice additions to the library!

You made a good point about the missing tests so we've recently added some basic coverage. Are you able to add tests for the changes that you've made?

There are some minor comments to the PR left by me and Travis. Can you have a look at these also?

@@ -48,7 +48,7 @@ def configure_with_jwt(self, jwks_url, issuer, audience, scopes=None):
if scopes is not None:
self.scopes = scopes

def configure_with_multiple_jwt_issuers(self, issuers, audience, scopes=None):
def configure_with_multiple_jwt_issuers(self, issuers, audience=None, scopes=None):
Copy link
Member

Choose a reason for hiding this comment

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

Maybe there should be a check that if the issuer is a string, then the audience is required. Currently, the validator can be configured with a None audience.

jwks_url = issuer + "/jwks"
self.validators[issuer] = JwtValidator(jwks_url, issuer, audience, self.verify_ssl)
elif isinstance(issuer, dict):
self.validators[issuer['name']] = JwtValidator(issuer['url'], issuer['name'], issuer['audience'],
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 update the README and describe that structure? I wonder whether there should be some checks if all the necessary elements of the dictionary are present.

Also, I'm not quite sold yet on the idea that the audience is a per-issuer setting. Is it because you have different URLs/identifiers for the same API?

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.

3 participants