-
-
Notifications
You must be signed in to change notification settings - Fork 491
Openid connect jwt #488
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
Openid connect jwt #488
Conversation
…of token in resource requests
…he valued estimated token handler
@thedrow it would be great to have these changes in the next release. |
I wonder if it is better to unlink ID Tokens from (more general) JWT tokens here... Some providers generate ID Tokens fit for one-time validation with an expiry that cover just the login process. And such providers may want to issue JWT-structured access tokens instead. I'm guessing the validation semantics would be largely the same, but the naming might be confusing in this situation? |
The suggestion is rename |
No, the other way around... |
Can we please get a update on the progress of this? I can see this as helping the transition to supporting OIDC and it looks like a lot of work for adding non-openidconenct JWT support per #50 may be shared by this. |
To be clear: I think this will help to support RFC7519 |
@thedrow Missing time to write the tests (If someone want help feel free). I will get back to openid connect next month as a professional job priority. @duaneking This is part of a effort to add oidc support to django-oauth-toolkit [1] I'm not sure where the code necessary to create JWT should live so for now it's all on django-oauth-toolkit side. [1] jazzband/django-oauth-toolkit@master...wiliamsouza:openid-connect |
Added unittest for JWTToken model
@thedrow tests done. Kudos to @Peter-Slump for the tests! |
@@ -344,6 +344,31 @@ def get_id_token(self, token, token_handler, request): | |||
# the request.scope should be used by the get_id_token() method to determine which claims to include in the resulting id_token | |||
raise NotImplementedError('Subclasses must implement this method.') | |||
|
|||
def validate_id_token(self, token, scopes, request): |
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 still wouldn't tie the naming here to ID Tokens specifically, as I wouldn't expect all JWT-based access tokens to be ID Tokens. Some servers might hand out special purpose JWT access tokens, next to their ID Tokens.
In that light, could this be named validate_jwt_bearer_token
instead and have a companion get_jwt_bearer_token
to create it?
Then people could alias those back to get_id_token
if they want, but also have the option to split them up.
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 effort is to add OpenID connect support and for this use case the name is correct. Add JWT token support to OAuth is a different thing and can be handled in near future and at this point all methods that handle ID token and JWT token can converge but think it's a future refactoring not part of this PR.
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.
Does OIDC specify somewhere how to use ID Tokens as JWT Bearer tokens?
To me it seems that you have in fact implemented generic (OAuth, not OIDC) JWT Bearer token support (as also the generic class name JWTToken
would suggest), except for the token validator functions that have ID Token specific names.
Generalising this later would likely lead to an inconvenient upgrade path, since then JWTToken
is already expected to call the OIDC-specific validators.
Unless I'm missing the point of the PR, I see no reason to keep this OIDC-specific detail in. Or is there?
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.
@skion The OIDC don't say nothing about usage, only:
- http://openid.net/specs/openid-connect-core-1_0.html#TokenResponse
- http://openid.net/specs/openid-connect-core-1_0.html#ImplicitAuthResponse
- https://tools.ietf.org/html/rfc6750
Make sense rename validate_id_token
to validate_jwt_bearer_token
oauthlib/oauth2/rfc6749/tokens.py
Outdated
|
||
request.expires_in = expires_in | ||
|
||
return self.request_validator.get_id_token(None, None, request) |
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.
Similar to my other comment: What if someone wants to hand out JWT access tokens that are different from the ID Tokens they generate?
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 rename this call to get_jwt_bearer_token
and let explicit that for OIDC this should call get_id_token
def validate_request(self, request): | ||
token = None | ||
if 'Authorization' in request.headers: | ||
token = request.headers.get('Authorization')[7:] |
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.
Might be nice to align this with #491 already?
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.
The last to be merged resolve the conflict?
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.
rebased and solved the conflict
oauthlib/oauth2/rfc6749/tokens.py
Outdated
|
||
def estimate_type(self, request): | ||
token = request.headers.get('Authorization', '')[7:] | ||
if token.count('.') in (2, 4): |
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.
Curious: When would there be 4 segment separators?
Also, there's no rule saying a normal access token can't contain dots of course. Wondering if you should include a check for ey
or .ey
here perhaps.
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 really don't remember... Will try to generate every accepted ID tokens by the specification to see a way to improve this tests
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.
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.
Ah, JWE's! 👍
About the non-JWT character set: Yes, that's how oauthlib generates tokens, but another server might still include periods in them. And someone might use oauthlib as a client against a 3rd party server...
That said, I'm not sure what the best way is either, just that checking for .
's feels a bit shallow.
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.
When used as client oauthlib validate tokens before send it to 3rd party server?
It's guaranteed ey
is added to every JWT token?
Can we let this check and see if it is a problem?
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.
When used as client oauthlib validate tokens before send it to 3rd party server?
Exactly
It's guaranteed ey is added to every JWT token?
I tried this yesterday and could not thing of a reason why a JWT would not start with {"
, but haven't thoroughly checked it either.
Can we let this check and see if it is a problem?
Just beware that you'll go wrong with the first example token in the RFC 😨
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.
@skion I'm can't see other approach to solve this than validate the token at it early stage. What you think?
Some thing like:
>>> from jwcrypto import jwt
>>>jwt.JWT(jwt='token')
...
ValueError: Token format unrecognized
>>> jwt.JWT(jwt='t.oke.n')
...
InvalidJWSObject: Invalid JWS Object [Invalid format] {ValueError('Invalid base64 string',)}
>>> jwt.JWT(jwt='t.o.k.e.n')
...
InvalidJWEData: Invalid format {ValueError('Invalid base64 string',)}
>>> jwt.JWT(jwt='eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJzdWIiOiIxMjM0NTY3ODkwIiwibmFtZSI6IkpvaG4gRG9lIiwiYWRtaW4iOnRydWV9.TJVA95OrM7E2cBab30RMHrHDcEfxjoYZgeFONFh7HgQ')
<jwcrypto.jwt.JWT at 0x7f059df786d8>
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.
Yeah, that crossed my mind as well, but the tricky bit with it would be that you'd need to exclude all exceptions that might be raised for valid but expired or otherwise bad tokens.
And I also liked your PR in the way that the JWT logic itself was contained to the request validator, leaving the developer free to use whatever JWT library they might prefer.
Perhaps the following is a reasonable trade off that doesn't pull in a JWT lib as a dependency?
if token.startswith('ey') and token.count('.') in (2, 4):
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.
@skion Done! Thanks.
@thedrow This method is only required for OpenID connect this mean when you use |
…2.RequestValidator and change oauthlib.oauth2.tokens JWTToken to use it
@skion Need your ok here. |
Thanks for the work on this @wiliamsouza ! In your mind how hard would it be to fully support RFC7519 (Per https://tools.ietf.org/html/rfc7519) after this change? I noticed your curl didnt have it, but thats a hard requirment for OIDC and that seems to be your goal here. |
@wiliamsouza About @thedrow's question, I would think that existing code that happens to use Also, is by intention to add the JWT support only to the |
@duaneking What is the way to instruct to OAuth to use JWT? Add settings like |
@skion It will hit My suggestion is to create new issues to add support in |
Someone could intentionally send a JWT though, in which case the Would there be a way to make the PR backward compatible? Perhaps if |
@skion seems to work but the used method is
What is the best use default to |
@wiliamsouza Right now the lib just seems to accept random data as the token. Looking at the code its clear to me there was some assumptions made that will need to be refactored to support other token formats. Your work is helping with that, but because you are doing it, it also means we/you have an opportunity to set the architectural tone for support. My thinking is that the entire idea of a token format or style is something most to the system simply shouldn't care about; it should just be factored out generically so the system can be as agnostic about the token formats it consumes/validates as possible while still actually doing validation and enforcing a default for generation. In the best case, it should support multiple formats at the same time for consumption/validation, depending on whats enabled, so you can do a seamless update/upgrade of token formats and not lose currently logged in users on a redeploy that enables a new token field or something. In my mind JWT via #50 adds the most benefit over the current "simple random string token" format created out of random strings, so simply any effort to enable it is a positive. |
@thedrow, @skion Ping! Don't let this PR die, please! With the OAuthLib new release we have the change o approval of this PR jazzband/django-oauth-toolkit#545 that adds support to django-oauth-toolkit |
Same for me! FWIW: I tested this branch in my environment with good result. |
@skion Thanks! |
@wiliamsouza I just really don't want args to be switched around; if we have backward compatibility needs then args should stay in the same positional index and new ones should have sane but config overridden enabled defaults. |
This pull request adds support to receive JWT token in request in the following form:
Don't find tests for
tokens.py
model. Any clue?