diff options
| author | Wiliam Souza <wiliamsouza83@gmail.com> | 2018-01-30 17:30:26 -0200 |
|---|---|---|
| committer | Omer Katz <omer.drow@gmail.com> | 2018-01-30 21:30:26 +0200 |
| commit | 2fe1cdb88e076f624824496c4aba6a8665e991d9 (patch) | |
| tree | 494c371a83c8d23b87d6ea97ba3933a2ca8f5cda /oauthlib | |
| parent | d7fc1336d81b39f3d2193eb3155ff66da6caadd9 (diff) | |
| download | oauthlib-2fe1cdb88e076f624824496c4aba6a8665e991d9.tar.gz | |
Openid connect jwt (#488)
* Add JWT token with it the server knows how to validate this new type of token in resource requests
* Change find_token_type sorted function to reverse result and choose the valued estimated token handler
* Add validate_id_token method to RequestValidator
* Added unittest for JWTToken model
* Updated version of Mock
* Add get_jwt_bearer_token and validate_jwt_bearer_token oauthlib.oauth2.RequestValidator and change oauthlib.oauth2.tokens JWTToken to use it
* Change to improve token type estimate test
* Add a note in RequestValidator.validate_jwt_bearer_token about error 5xx rather 4xx
Diffstat (limited to 'oauthlib')
| -rw-r--r-- | oauthlib/oauth2/rfc6749/endpoints/pre_configured.py | 7 | ||||
| -rw-r--r-- | oauthlib/oauth2/rfc6749/endpoints/resource.py | 2 | ||||
| -rw-r--r-- | oauthlib/oauth2/rfc6749/request_validator.py | 64 | ||||
| -rw-r--r-- | oauthlib/oauth2/rfc6749/tokens.py | 46 |
4 files changed, 113 insertions, 6 deletions
diff --git a/oauthlib/oauth2/rfc6749/endpoints/pre_configured.py b/oauthlib/oauth2/rfc6749/endpoints/pre_configured.py index 07c3715..0c26986 100644 --- a/oauthlib/oauth2/rfc6749/endpoints/pre_configured.py +++ b/oauthlib/oauth2/rfc6749/endpoints/pre_configured.py @@ -16,7 +16,7 @@ from ..grant_types import (AuthCodeGrantDispatcher, AuthorizationCodeGrant, OpenIDConnectHybrid, RefreshTokenGrant, ResourceOwnerPasswordCredentialsGrant) -from ..tokens import BearerToken +from ..tokens import BearerToken, JWTToken from .authorization import AuthorizationEndpoint from .resource import ResourceEndpoint from .revocation import RevocationEndpoint @@ -57,6 +57,9 @@ class Server(AuthorizationEndpoint, TokenEndpoint, ResourceEndpoint, bearer = BearerToken(request_validator, token_generator, token_expires_in, refresh_token_generator) + jwt = JWTToken(request_validator, token_generator, + token_expires_in, refresh_token_generator) + auth_grant_choice = AuthCodeGrantDispatcher(default_auth_grant=auth_grant, oidc_auth_grant=openid_connect_auth) implicit_grant_choice = ImplicitTokenGrantDispatcher(default_implicit_grant=implicit_grant, oidc_implicit_grant=openid_connect_implicit) @@ -86,7 +89,7 @@ class Server(AuthorizationEndpoint, TokenEndpoint, ResourceEndpoint, }, default_token_type=bearer) ResourceEndpoint.__init__(self, default_token='Bearer', - token_types={'Bearer': bearer}) + token_types={'Bearer': bearer, 'JWT': jwt}) RevocationEndpoint.__init__(self, request_validator) diff --git a/oauthlib/oauth2/rfc6749/endpoints/resource.py b/oauthlib/oauth2/rfc6749/endpoints/resource.py index d03ed21..f19c60c 100644 --- a/oauthlib/oauth2/rfc6749/endpoints/resource.py +++ b/oauthlib/oauth2/rfc6749/endpoints/resource.py @@ -83,5 +83,5 @@ class ResourceEndpoint(BaseEndpoint): to give an estimation based on the request. """ estimates = sorted(((t.estimate_type(request), n) - for n, t in self.tokens.items())) + for n, t in self.tokens.items()), reverse=True) return estimates[0][1] if len(estimates) else None diff --git a/oauthlib/oauth2/rfc6749/request_validator.py b/oauthlib/oauth2/rfc6749/request_validator.py index ba129d5..d25a6e0 100644 --- a/oauthlib/oauth2/rfc6749/request_validator.py +++ b/oauthlib/oauth2/rfc6749/request_validator.py @@ -312,8 +312,24 @@ class RequestValidator(object): """ raise NotImplementedError('Subclasses must implement this method.') - def get_id_token(self, token, token_handler, request): + def get_jwt_bearer_token(self, token, token_handler, request): + """Get JWT Bearer token or OpenID Connect ID token + + If using OpenID Connect this SHOULD call `oauthlib.oauth2.RequestValidator.get_id_token` + + :param token: A Bearer token dict + :param token_handler: the token handler (BearerToken class) + :param request: the HTTP Request (oauthlib.common.Request) + :return: The JWT Bearer token or OpenID Connect ID token (a JWS signed JWT) + + Method is used by JWT Bearer and OpenID Connect tokens: + - JWTToken.create_token """ + raise NotImplementedError('Subclasses must implement this method.') + + def get_id_token(self, token, token_handler, request): + """Get OpenID Connect ID token + In the OpenID Connect workflows when an ID Token is requested this method is called. Subclasses should implement the construction, signing and optional encryption of the ID Token as described in the OpenID Connect spec. @@ -344,6 +360,52 @@ class RequestValidator(object): # 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_jwt_bearer_token(self, token, scopes, request): + """Ensure the JWT Bearer token or OpenID Connect ID token are valids and authorized access to scopes. + + If using OpenID Connect this SHOULD call `oauthlib.oauth2.RequestValidator.get_id_token` + + If not using OpenID Connect this can `return None` to avoid 5xx rather 401/3 response. + + OpenID connect core 1.0 describe how to validate an id_token: + - http://openid.net/specs/openid-connect-core-1_0.html#IDTokenValidation + - http://openid.net/specs/openid-connect-core-1_0.html#ImplicitIDTValidation + - http://openid.net/specs/openid-connect-core-1_0.html#HybridIDTValidation + - http://openid.net/specs/openid-connect-core-1_0.html#HybridIDTValidation2 + + :param token: Unicode Bearer token + :param scopes: List of scopes (defined by you) + :param request: The HTTP Request (oauthlib.common.Request) + :rtype: True or False + + Method is indirectly used by all core OpenID connect JWT token issuing grant types: + - Authorization Code Grant + - Implicit Grant + - Hybrid Grant + """ + raise NotImplementedError('Subclasses must implement this method.') + + def validate_id_token(self, token, scopes, request): + """Ensure the id token is valid and authorized access to scopes. + + OpenID connect core 1.0 describe how to validate an id_token: + - http://openid.net/specs/openid-connect-core-1_0.html#IDTokenValidation + - http://openid.net/specs/openid-connect-core-1_0.html#ImplicitIDTValidation + - http://openid.net/specs/openid-connect-core-1_0.html#HybridIDTValidation + - http://openid.net/specs/openid-connect-core-1_0.html#HybridIDTValidation2 + + :param token: Unicode Bearer token + :param scopes: List of scopes (defined by you) + :param request: The HTTP Request (oauthlib.common.Request) + :rtype: True or False + + Method is indirectly used by all core OpenID connect JWT token issuing grant types: + - Authorization Code Grant + - Implicit Grant + - Hybrid Grant + """ + raise NotImplementedError('Subclasses must implement this method.') + def validate_bearer_token(self, token, scopes, request): """Ensure the Bearer token is valid and authorized access to scopes. diff --git a/oauthlib/oauth2/rfc6749/tokens.py b/oauthlib/oauth2/rfc6749/tokens.py index e0ac431..e68ba59 100644 --- a/oauthlib/oauth2/rfc6749/tokens.py +++ b/oauthlib/oauth2/rfc6749/tokens.py @@ -24,8 +24,6 @@ except ImportError: from urllib.parse import urlparse - - class OAuth2Token(dict): def __init__(self, params, old_scope=None): @@ -303,3 +301,47 @@ class BearerToken(TokenBase): return 5 else: return 0 + + +class JWTToken(TokenBase): + __slots__ = ( + 'request_validator', 'token_generator', + 'refresh_token_generator', 'expires_in' + ) + + def __init__(self, request_validator=None, token_generator=None, + expires_in=None, refresh_token_generator=None): + self.request_validator = request_validator + self.token_generator = token_generator or random_token_generator + self.refresh_token_generator = ( + refresh_token_generator or self.token_generator + ) + self.expires_in = expires_in or 3600 + + def create_token(self, request, refresh_token=False, save_token=False): + """Create a JWT Token, using requestvalidator method.""" + + if callable(self.expires_in): + expires_in = self.expires_in(request) + else: + expires_in = self.expires_in + + request.expires_in = expires_in + + return self.request_validator.get_jwt_bearer_token(None, None, request) + + def validate_request(self, request): + token = None + if 'Authorization' in request.headers: + token = request.headers.get('Authorization')[7:] + else: + token = request.access_token + return self.request_validator.validate_jwt_bearer_token( + token, request.scopes, request) + + def estimate_type(self, request): + token = request.headers.get('Authorization', '')[7:] + if token.startswith('ey') and token.count('.') in (2, 4): + return 10 + else: + return 0 |
