summaryrefslogtreecommitdiff
path: root/oauthlib/oauth2/rfc6749/grant_types
diff options
context:
space:
mode:
authorWiliam Souza <wiliamsouza83@gmail.com>2017-10-01 03:07:11 -0300
committerOmer Katz <omer.drow@gmail.com>2017-10-01 09:07:11 +0300
commite575cca3e5d18b1e7051c64f435f2cdea71a29ab (patch)
tree9034c64194268701ad6c5eada0d4b7b07e980279 /oauthlib/oauth2/rfc6749/grant_types
parent04959fe009cb2622c7422c736456cdbd36ec43b3 (diff)
downloadoauthlib-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__.py2
-rw-r--r--oauthlib/oauth2/rfc6749/grant_types/implicit.py32
-rw-r--r--oauthlib/oauth2/rfc6749/grant_types/openid_connect.py65
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):