diff options
author | Wiliam Souza <wiliamsouza83@gmail.com> | 2017-10-01 03:07:11 -0300 |
---|---|---|
committer | Omer Katz <omer.drow@gmail.com> | 2017-10-01 09:07:11 +0300 |
commit | e575cca3e5d18b1e7051c64f435f2cdea71a29ab (patch) | |
tree | 9034c64194268701ad6c5eada0d4b7b07e980279 /oauthlib/oauth2/rfc6749/grant_types | |
parent | 04959fe009cb2622c7422c736456cdbd36ec43b3 (diff) | |
download | oauthlib-e575cca3e5d18b1e7051c64f435f2cdea71a29ab.tar.gz |
OpenID connect improvements (#484)
* Change create_token_response to only save access_token when it's present in request.response_type
* Remove unused import, fix indentation and improve comment
* Fix AuthorizationEndpoint response_type for OpenID Connect hybrid flow
* Add new ImplicitTokenGrantDispatcher
Changes AuthorizationEndpoint response_type `'token'`, `'id_token'` and
`'id_token token'` to work with OpenID Connect and OAuth2 implicit flow
in a transparent way
* Add new AuthTokenGrantDispatcher
Change AuthorizationEndpoint grant_types `'authorization_code'` to work with
OpenID Connect and OAuth2 authorization flow in a transparent way
* Change tests to include required client_id and redirect_uri
* Remove AuthorizationEndpoint grant_types `'openid'`
Now OpenID Connect and OAuth2 authorization flow can use `authorization_code`
in a transparent way
* Add sone blank lines and fix indentation
* Change AuthorizationEndpoint grant type id_token and id_token token to use openid_connect_implicit direct
* Change default empty value to None and fix a typo
* Add assert called to AuthTokenGrantDispatcher tests
* Add request to get_authorization_code_scopes
Diffstat (limited to 'oauthlib/oauth2/rfc6749/grant_types')
-rw-r--r-- | oauthlib/oauth2/rfc6749/grant_types/__init__.py | 2 | ||||
-rw-r--r-- | oauthlib/oauth2/rfc6749/grant_types/implicit.py | 32 | ||||
-rw-r--r-- | oauthlib/oauth2/rfc6749/grant_types/openid_connect.py | 65 |
3 files changed, 83 insertions, 16 deletions
diff --git a/oauthlib/oauth2/rfc6749/grant_types/__init__.py b/oauthlib/oauth2/rfc6749/grant_types/__init__.py index 1da1281..2e4bfe4 100644 --- a/oauthlib/oauth2/rfc6749/grant_types/__init__.py +++ b/oauthlib/oauth2/rfc6749/grant_types/__init__.py @@ -16,3 +16,5 @@ from .openid_connect import OpenIDConnectImplicit from .openid_connect import OpenIDConnectHybrid from .openid_connect import OIDCNoPrompt from .openid_connect import AuthCodeGrantDispatcher +from .openid_connect import AuthTokenGrantDispatcher +from .openid_connect import ImplicitTokenGrantDispatcher diff --git a/oauthlib/oauth2/rfc6749/grant_types/implicit.py b/oauthlib/oauth2/rfc6749/grant_types/implicit.py index 858ef77..2b9c49d 100644 --- a/oauthlib/oauth2/rfc6749/grant_types/implicit.py +++ b/oauthlib/oauth2/rfc6749/grant_types/implicit.py @@ -11,7 +11,6 @@ from oauthlib import common from oauthlib.uri_validate import is_absolute_uri from .. import errors -from ..request_validator import RequestValidator from .base import GrantTypeBase log = logging.getLogger(__name__) @@ -229,7 +228,7 @@ class ImplicitGrant(GrantTypeBase): return {'Location': common.add_params_to_uri(request.redirect_uri, e.twotuples, fragment=True)}, None, 302 - # In OIDC implicit flow it is possible to have a request_type that does not include the access token! + # In OIDC implicit flow it is possible to have a request_type that does not include the access_token! # "id_token token" - return the access token and the id token # "id_token" - don't return the access token if "token" in request.response_type.split(): @@ -239,7 +238,12 @@ class ImplicitGrant(GrantTypeBase): for modifier in self._token_modifiers: token = modifier(token, token_handler, request) - self.request_validator.save_token(token, request) + + # In OIDC implicit flow it is possible to have a request_type that does + # not include the access_token! In this case there is no need to save a token. + if "token" in request.response_type.split(): + self.request_validator.save_token(token, request) + return self.prepare_authorization_response( request, token, {}, None, 302) @@ -317,8 +321,7 @@ class ImplicitGrant(GrantTypeBase): # Then check for normal errors. request_info = self._run_custom_validators(request, - self.custom_validators.all_pre) - + self.custom_validators.all_pre) # If the resource owner denies the access request or if the request # fails for reasons other than a missing or invalid redirection URI, @@ -352,20 +355,21 @@ class ImplicitGrant(GrantTypeBase): self.validate_scopes(request) request_info.update({ - 'client_id': request.client_id, - 'redirect_uri': request.redirect_uri, - 'response_type': request.response_type, - 'state': request.state, - 'request': request, + 'client_id': request.client_id, + 'redirect_uri': request.redirect_uri, + 'response_type': request.response_type, + 'state': request.state, + 'request': request, }) - request_info = self._run_custom_validators(request, - self.custom_validators.all_post, - request_info) + request_info = self._run_custom_validators( + request, + self.custom_validators.all_post, + request_info + ) return request.scopes, request_info - def _run_custom_validators(self, request, validations, diff --git a/oauthlib/oauth2/rfc6749/grant_types/openid_connect.py b/oauthlib/oauth2/rfc6749/grant_types/openid_connect.py index 4c98864..4371b28 100644 --- a/oauthlib/oauth2/rfc6749/grant_types/openid_connect.py +++ b/oauthlib/oauth2/rfc6749/grant_types/openid_connect.py @@ -12,11 +12,11 @@ from json import loads from ..errors import ConsentRequired, InvalidRequestError, LoginRequired from ..request_validator import RequestValidator from .authorization_code import AuthorizationCodeGrant -from .base import GrantTypeBase from .implicit import ImplicitGrant log = logging.getLogger(__name__) + class OIDCNoPrompt(Exception): """Exception used to inform users that no explicit authorization is needed. @@ -76,6 +76,65 @@ class AuthCodeGrantDispatcher(object): return self._handler_for_request(request).validate_authorization_request(request) +class ImplicitTokenGrantDispatcher(object): + """ + This is an adapter class that will route simple Authorization Code requests, those that have response_type=code and a scope + including 'openid' to either the default_auth_grant or the oidc_auth_grant based on the scopes requested. + """ + def __init__(self, default_implicit_grant=None, oidc_implicit_grant=None): + self.default_implicit_grant = default_implicit_grant + self.oidc_implicit_grant = oidc_implicit_grant + + def _handler_for_request(self, request): + handler = self.default_implicit_grant + + if request.scopes and "openid" in request.scopes and 'id_token' in request.response_type: + handler = self.oidc_implicit_grant + + log.debug('Selecting handler for request %r.', handler) + return handler + + def create_authorization_response(self, request, token_handler): + return self._handler_for_request(request).create_authorization_response(request, token_handler) + + def validate_authorization_request(self, request): + return self._handler_for_request(request).validate_authorization_request(request) + + +class AuthTokenGrantDispatcher(object): + """ + This is an adapter class that will route simple Token requests, those that authorization_code have a scope + including 'openid' to either the default_token_grant or the oidc_token_grant based on the scopes requested. + """ + def __init__(self, request_validator, default_token_grant=None, oidc_token_grant=None): + self.default_token_grant = default_token_grant + self.oidc_token_grant = oidc_token_grant + self.request_validator = request_validator + + def _handler_for_request(self, request): + handler = self.default_token_grant + scopes = () + parameters = dict(request.decoded_body) + client_id = parameters.get('client_id', None) + code = parameters.get('code', None) + redirect_uri = parameters.get('redirect_uri', None) + + # If code is not pressent fallback to `default_token_grant` wich will + # raise an error for the missing `code` in `create_token_response` step. + if code: + scopes = self.request_validator.get_authorization_code_scopes(client_id, code, redirect_uri, request) + + if 'openid' in scopes: + handler = self.oidc_token_grant + + log.debug('Selecting handler for request %r.', handler) + return handler + + def create_token_response(self, request, token_handler): + handler = self._handler_for_request(request) + return handler.create_token_response(request, token_handler) + + class OpenIDConnectBase(object): # Just proxy the majority of method calls through to the @@ -307,7 +366,7 @@ class OpenIDConnectBase(object): self._inflate_claims(request) if not self.request_validator.validate_user_match( - request.id_token_hint, request.scopes, request.claims, request): + request.id_token_hint, request.scopes, request.claims, request): msg = "Session user does not match client supplied user." raise LoginRequired(request=request, description=msg) @@ -356,6 +415,7 @@ class OpenIDConnectAuthCode(OpenIDConnectBase): self.openid_authorization_validator) self.register_token_modifier(self.add_id_token) + class OpenIDConnectImplicit(OpenIDConnectBase): def __init__(self, request_validator=None, **kwargs): @@ -369,6 +429,7 @@ class OpenIDConnectImplicit(OpenIDConnectBase): self.openid_implicit_authorization_validator) self.register_token_modifier(self.add_id_token) + class OpenIDConnectHybrid(OpenIDConnectBase): def __init__(self, request_validator=None, **kwargs): |