diff options
author | Joel Stevenson <jstevenson@bepress.com> | 2016-08-18 15:29:01 -0700 |
---|---|---|
committer | Joel Stevenson <jstevenson@bepress.com> | 2016-08-18 15:29:01 -0700 |
commit | 447465547cc9a14350d024ed25b374614c475eec (patch) | |
tree | db6a1aca50bb431f47412d7272c5aa6e627fcdd3 /oauthlib/oauth2/rfc6749 | |
parent | 9a8f73d2dd088d5ea01313de2a1fe5a877994a79 (diff) | |
download | oauthlib-447465547cc9a14350d024ed25b374614c475eec.tar.gz |
Move the claims handling into OpenIDConnectBase._inflate_claims() and a new AuthCodeGrantDispatcher to route requests to either the default AuthorizationCodeGrant or OpenIDConnectAuthCode depending on scope when the request's response_type is a simple (ambiguous) 'code'.
Include basic docs about OpenID Connect auth flow support
Diffstat (limited to 'oauthlib/oauth2/rfc6749')
5 files changed, 60 insertions, 17 deletions
diff --git a/oauthlib/oauth2/rfc6749/endpoints/pre_configured.py b/oauthlib/oauth2/rfc6749/endpoints/pre_configured.py index 6ad5f5e..7463484 100644 --- a/oauthlib/oauth2/rfc6749/endpoints/pre_configured.py +++ b/oauthlib/oauth2/rfc6749/endpoints/pre_configured.py @@ -16,6 +16,7 @@ from ..grant_types import ResourceOwnerPasswordCredentialsGrant from ..grant_types import ClientCredentialsGrant from ..grant_types import RefreshTokenGrant from ..grant_types import OpenIDConnectImplicit +from ..grant_types import AuthCodeGrantDispatcher from .authorization import AuthorizationEndpoint from .token import TokenEndpoint @@ -56,11 +57,13 @@ class Server(AuthorizationEndpoint, TokenEndpoint, ResourceEndpoint, bearer = BearerToken(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) + # See http://openid.net/specs/oauth-v2-multiple-response-types-1_0.html#Combinations for valid combinations # internally our AuthorizationEndpoint will ensure they can appear in any order for any valid combination AuthorizationEndpoint.__init__(self, default_response_type='code', response_types={ - 'code': auth_grant, + 'code': auth_grant_choice, 'token': implicit_grant, 'id_token': openid_connect_implicit, 'id_token token': openid_connect_implicit, diff --git a/oauthlib/oauth2/rfc6749/grant_types/__init__.py b/oauthlib/oauth2/rfc6749/grant_types/__init__.py index 78cd7ed..1da1281 100644 --- a/oauthlib/oauth2/rfc6749/grant_types/__init__.py +++ b/oauthlib/oauth2/rfc6749/grant_types/__init__.py @@ -15,3 +15,4 @@ from .openid_connect import OpenIDConnectAuthCode from .openid_connect import OpenIDConnectImplicit from .openid_connect import OpenIDConnectHybrid from .openid_connect import OIDCNoPrompt +from .openid_connect import AuthCodeGrantDispatcher diff --git a/oauthlib/oauth2/rfc6749/grant_types/authorization_code.py b/oauthlib/oauth2/rfc6749/grant_types/authorization_code.py index 3a77fd9..d4292cb 100644 --- a/oauthlib/oauth2/rfc6749/grant_types/authorization_code.py +++ b/oauthlib/oauth2/rfc6749/grant_types/authorization_code.py @@ -367,25 +367,12 @@ class AuthorizationCodeGrant(GrantTypeBase): # http://tools.ietf.org/html/rfc6749#section-3.3 self.validate_scopes(request) - # validate_authorization_request may be called multiple times in a single request - # so make sure we only de-serialize the claims once - if request.claims and not isinstance(request.claims, dict) and request.scopes and "openid" in request.scopes: - # specific claims are requested during the Authorization Request and may be requested for inclusion - # in either the id_token or the UserInfo endpoint response - # see http://openid.net/specs/openid-connect-core-1_0.html#ClaimsParameter - try: - request.claims = json.loads(request.claims) - except Exception as ex: - raise errors.InvalidRequestError(description="Malformed claims parameter", - uri="http://openid.net/specs/openid-connect-core-1_0.html#ClaimsParameter") - request_info = { 'client_id': request.client_id, 'redirect_uri': request.redirect_uri, 'response_type': request.response_type, 'state': request.state, - 'request': request, - 'claims': request.claims + 'request': request } for validator in self._authorization_validators: diff --git a/oauthlib/oauth2/rfc6749/grant_types/openid_connect.py b/oauthlib/oauth2/rfc6749/grant_types/openid_connect.py index f9b38ba..3c3deb2 100644 --- a/oauthlib/oauth2/rfc6749/grant_types/openid_connect.py +++ b/oauthlib/oauth2/rfc6749/grant_types/openid_connect.py @@ -52,11 +52,47 @@ class OIDCNoPrompt(Exception): super(OIDCNoPrompt, self).__init__(msg) +class AuthCodeGrantDispatcher(object): + """ + + """ + def __init__(self, default_auth_grant=None, oidc_auth_grant=None): + self.default_auth_grant = default_auth_grant + self.oidc_auth_grant = oidc_auth_grant + + def _handler_for_request(self, request): + handler = self.default_auth_grant + + if "openid" in request.scopes: + handler = self.oidc_auth_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 OpenIDConnectBase(GrantTypeBase): def __init__(self, request_validator=None): self.request_validator = request_validator or RequestValidator() + def _inflate_claims(self, request): + # this may be called multiple times in a single request so make sure we only de-serialize the claims once + if request.claims and not isinstance(request.claims, dict): + # specific claims are requested during the Authorization Request and may be requested for inclusion + # in either the id_token or the UserInfo endpoint response + # see http://openid.net/specs/openid-connect-core-1_0.html#ClaimsParameter + try: + request.claims = loads(request.claims) + except Exception as ex: + raise InvalidRequestError(description="Malformed claims parameter", + uri="http://openid.net/specs/openid-connect-core-1_0.html#ClaimsParameter") + def add_id_token(self, token, token_handler, request): # Treat it as normal OAuth 2 auth code request if openid is not present if not 'openid' in request.scopes: @@ -226,19 +262,21 @@ class OpenIDConnectBase(GrantTypeBase): if not self.request_validator.validate_silent_authorization(request): raise ConsentRequired(request=request) - request.claims = loads(request.claims) if request.claims else {} + self._inflate_claims(request) if not self.request_validator.validate_user_match( request.id_token_hint, request.scopes, request.claims, request): msg = "Session user does not match client supplied user." raise LoginRequired(request=request, description=msg) + request_info = { 'display': request.display, 'prompt': request.prompt.split() if request.prompt else [], 'ui_locales': request.ui_locales.split() if request.ui_locales else [], 'id_token_hint': request.id_token_hint, 'login_hint': request.login_hint, + 'claims': request.claims } return request_info @@ -263,7 +301,9 @@ class OpenIDConnectBase(GrantTypeBase): desc = 'Request is missing mandatory nonce parameter.' raise InvalidRequestError(request=request, description=desc) - return {'nonce': request.nonce} + self._inflate_claims(request) + + return {'nonce': request.nonce, 'claims': request.claims} class OpenIDConnectAuthCode(OpenIDConnectBase): diff --git a/oauthlib/oauth2/rfc6749/request_validator.py b/oauthlib/oauth2/rfc6749/request_validator.py index b1c1bd1..2acd8ec 100644 --- a/oauthlib/oauth2/rfc6749/request_validator.py +++ b/oauthlib/oauth2/rfc6749/request_validator.py @@ -300,6 +300,18 @@ class RequestValidator(object): - nonce, if workflow is implicit or hybrid and it was provided - claims, if provided to the original Authorization Code request + The token parameter is a dict which may contain an ``access_token`` entry, in which + case the resulting ID Token *should* include a calculated ``at_hash`` claim. + + Similarly, when the request parameter has a ``code`` property defined, the ID Token + *should* include a calculated ``c_hash`` claim. + + http://openid.net/specs/openid-connect-core-1_0.html (sections `3.1.3.6`_, `3.2.2.10`_, `3.3.2.11`_) + + .. _`3.1.3.6`: http://openid.net/specs/openid-connect-core-1_0.html#CodeIDToken + .. _`3.2.2.10`: http://openid.net/specs/openid-connect-core-1_0.html#ImplicitIDToken + .. _`3.3.2.11`: http://openid.net/specs/openid-connect-core-1_0.html#HybridIDToken + :param token: A Bearer token dict :param token_handler: the token handler (BearerToken class) :param request: the HTTP Request (oauthlib.common.Request) |