summaryrefslogtreecommitdiff
path: root/oauthlib
diff options
context:
space:
mode:
authorWiliam Souza <wiliamsouza83@gmail.com>2018-06-05 11:33:21 -0300
committerOmer Katz <omer.drow@gmail.com>2018-06-05 17:33:21 +0300
commitd5a4d5ea0eab04ddddefac7d1e7a4902fc469286 (patch)
tree580faf95f8f7bed257b2dac1d29c26c3d9d1b219 /oauthlib
parenta102731c88f496b557dedd4024fb9b82801d134a (diff)
downloadoauthlib-d5a4d5ea0eab04ddddefac7d1e7a4902fc469286.tar.gz
OpenID Connect split (#525)
* Add command to clean up builds to makefile * Fix docs strings for endpoints pre_configured * Chnage grant_types.openid_connect to include a deprecation warning be a backward compatible * Fix doc string for rfc6749.request_validator * Remove unused import * Change import to be explicity * Move JWTTokenTestCase to openid.connect.core.test_token * Move JWTToken to oauthlib.openid.connect.core.tokens * Move to openid connect test * Move openid connect exceptions to its own file * Remove openid connect from oauth2 server * Remove JWTToken from oauth tokens * Remove grant_types.openid_connect file * Add oauthlib/openid estructure and tests
Diffstat (limited to 'oauthlib')
-rw-r--r--oauthlib/oauth2/__init__.py2
-rw-r--r--oauthlib/oauth2/rfc6749/endpoints/pre_configured.py43
-rw-r--r--oauthlib/oauth2/rfc6749/errors.py123
-rw-r--r--oauthlib/oauth2/rfc6749/grant_types/__init__.py8
-rw-r--r--oauthlib/oauth2/rfc6749/request_validator.py4
-rw-r--r--oauthlib/oauth2/rfc6749/tokens.py40
-rw-r--r--oauthlib/openid/__init__.py0
-rw-r--r--oauthlib/openid/connect/__init__.py0
-rw-r--r--oauthlib/openid/connect/core/__init__.py0
-rw-r--r--oauthlib/openid/connect/core/endpoints/pre_configured.py103
-rw-r--r--oauthlib/openid/connect/core/exceptions.py152
-rw-r--r--oauthlib/openid/connect/core/grant_types/__init__.py17
-rw-r--r--oauthlib/openid/connect/core/grant_types/authorization_code.py24
-rw-r--r--oauthlib/openid/connect/core/grant_types/base.py (renamed from oauthlib/oauth2/rfc6749/grant_types/openid_connect.py)176
-rw-r--r--oauthlib/openid/connect/core/grant_types/dispatchers.py86
-rw-r--r--oauthlib/openid/connect/core/grant_types/exceptions.py32
-rw-r--r--oauthlib/openid/connect/core/grant_types/hybrid.py36
-rw-r--r--oauthlib/openid/connect/core/grant_types/implicit.py28
-rw-r--r--oauthlib/openid/connect/core/request_validator.py188
-rw-r--r--oauthlib/openid/connect/core/tokens.py54
20 files changed, 761 insertions, 355 deletions
diff --git a/oauthlib/oauth2/__init__.py b/oauthlib/oauth2/__init__.py
index dc7b431..303c6a1 100644
--- a/oauthlib/oauth2/__init__.py
+++ b/oauthlib/oauth2/__init__.py
@@ -24,7 +24,7 @@ from .rfc6749.endpoints import WebApplicationServer
from .rfc6749.endpoints import MobileApplicationServer
from .rfc6749.endpoints import LegacyApplicationServer
from .rfc6749.endpoints import BackendApplicationServer
-from .rfc6749.errors import AccessDeniedError, AccountSelectionRequired, ConsentRequired, FatalClientError, FatalOpenIDClientError, InsecureTransportError, InteractionRequired, InvalidClientError, InvalidClientIdError, InvalidGrantError, InvalidRedirectURIError, InvalidRequestError, InvalidRequestFatalError, InvalidScopeError, LoginRequired, MismatchingRedirectURIError, MismatchingStateError, MissingClientIdError, MissingCodeError, MissingRedirectURIError, MissingResponseTypeError, MissingTokenError, MissingTokenTypeError, OAuth2Error, OpenIDClientError, ServerError, TemporarilyUnavailableError, TokenExpiredError, UnauthorizedClientError, UnsupportedGrantTypeError, UnsupportedResponseTypeError, UnsupportedTokenTypeError
+from .rfc6749.errors import AccessDeniedError, OAuth2Error, FatalClientError, InsecureTransportError, InvalidClientError, InvalidClientIdError, InvalidGrantError, InvalidRedirectURIError, InvalidRequestError, InvalidRequestFatalError, InvalidScopeError, MismatchingRedirectURIError, MismatchingStateError, MissingClientIdError, MissingCodeError, MissingRedirectURIError, MissingResponseTypeError, MissingTokenError, MissingTokenTypeError, ServerError, TemporarilyUnavailableError, TokenExpiredError, UnauthorizedClientError, UnsupportedGrantTypeError, UnsupportedResponseTypeError, UnsupportedTokenTypeError
from .rfc6749.grant_types import AuthorizationCodeGrant
from .rfc6749.grant_types import ImplicitGrant
from .rfc6749.grant_types import ResourceOwnerPasswordCredentialsGrant
diff --git a/oauthlib/oauth2/rfc6749/endpoints/pre_configured.py b/oauthlib/oauth2/rfc6749/endpoints/pre_configured.py
index 66af516..e2cc9db 100644
--- a/oauthlib/oauth2/rfc6749/endpoints/pre_configured.py
+++ b/oauthlib/oauth2/rfc6749/endpoints/pre_configured.py
@@ -1,22 +1,19 @@
# -*- coding: utf-8 -*-
"""
-oauthlib.oauth2.rfc6749
-~~~~~~~~~~~~~~~~~~~~~~~
+oauthlib.oauth2.rfc6749.endpoints.pre_configured
+~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
-This module is an implementation of various logic needed
-for consuming and providing OAuth 2.0 RFC6749.
+This module is an implementation of various endpoints needed
+for providing OAuth 2.0 RFC6749 servers.
"""
from __future__ import absolute_import, unicode_literals
-from ..grant_types import (AuthCodeGrantDispatcher, AuthorizationCodeGrant,
- AuthTokenGrantDispatcher,
+from ..grant_types import (AuthorizationCodeGrant,
ClientCredentialsGrant,
- ImplicitTokenGrantDispatcher, ImplicitGrant,
- OpenIDConnectAuthCode, OpenIDConnectImplicit,
- OpenIDConnectHybrid,
+ ImplicitGrant,
RefreshTokenGrant,
ResourceOwnerPasswordCredentialsGrant)
-from ..tokens import BearerToken, JWTToken
+from ..tokens import BearerToken
from .authorization import AuthorizationEndpoint
from .introspect import IntrospectEndpoint
from .resource import ResourceEndpoint
@@ -51,46 +48,28 @@ class Server(AuthorizationEndpoint, IntrospectEndpoint, TokenEndpoint,
request_validator)
credentials_grant = ClientCredentialsGrant(request_validator)
refresh_grant = RefreshTokenGrant(request_validator)
- openid_connect_auth = OpenIDConnectAuthCode(request_validator)
- openid_connect_implicit = OpenIDConnectImplicit(request_validator)
- openid_connect_hybrid = OpenIDConnectHybrid(request_validator)
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)
-
- # 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_choice,
- 'token': implicit_grant_choice,
- 'id_token': openid_connect_implicit,
- 'id_token token': openid_connect_implicit,
- 'code token': openid_connect_hybrid,
- 'code id_token': openid_connect_hybrid,
- 'code id_token token': openid_connect_hybrid,
+ 'code': auth_grant,
+ 'token': implicit_grant,
'none': auth_grant
},
default_token_type=bearer)
- token_grant_choice = AuthTokenGrantDispatcher(request_validator, default_token_grant=auth_grant, oidc_token_grant=openid_connect_auth)
-
TokenEndpoint.__init__(self, default_grant_type='authorization_code',
grant_types={
- 'authorization_code': token_grant_choice,
+ 'authorization_code': auth_grant,
'password': password_grant,
'client_credentials': credentials_grant,
'refresh_token': refresh_grant,
},
default_token_type=bearer)
ResourceEndpoint.__init__(self, default_token='Bearer',
- token_types={'Bearer': bearer, 'JWT': jwt})
+ token_types={'Bearer': bearer})
RevocationEndpoint.__init__(self, request_validator)
IntrospectEndpoint.__init__(self, request_validator)
diff --git a/oauthlib/oauth2/rfc6749/errors.py b/oauthlib/oauth2/rfc6749/errors.py
index 1d5e98d..5a0cca2 100644
--- a/oauthlib/oauth2/rfc6749/errors.py
+++ b/oauthlib/oauth2/rfc6749/errors.py
@@ -274,106 +274,6 @@ class UnsupportedTokenTypeError(OAuth2Error):
error = 'unsupported_token_type'
-class FatalOpenIDClientError(FatalClientError):
- pass
-
-
-class OpenIDClientError(OAuth2Error):
- pass
-
-
-class InteractionRequired(OpenIDClientError):
- """
- The Authorization Server requires End-User interaction to proceed.
-
- This error MAY be returned when the prompt parameter value in the
- Authentication Request is none, but the Authentication Request cannot be
- completed without displaying a user interface for End-User interaction.
- """
- error = 'interaction_required'
- status_code = 401
-
-
-class LoginRequired(OpenIDClientError):
- """
- The Authorization Server requires End-User authentication.
-
- This error MAY be returned when the prompt parameter value in the
- Authentication Request is none, but the Authentication Request cannot be
- completed without displaying a user interface for End-User authentication.
- """
- error = 'login_required'
- status_code = 401
-
-
-class AccountSelectionRequired(OpenIDClientError):
- """
- The End-User is REQUIRED to select a session at the Authorization Server.
-
- The End-User MAY be authenticated at the Authorization Server with
- different associated accounts, but the End-User did not select a session.
- This error MAY be returned when the prompt parameter value in the
- Authentication Request is none, but the Authentication Request cannot be
- completed without displaying a user interface to prompt for a session to
- use.
- """
- error = 'account_selection_required'
-
-
-class ConsentRequired(OpenIDClientError):
- """
- The Authorization Server requires End-User consent.
-
- This error MAY be returned when the prompt parameter value in the
- Authentication Request is none, but the Authentication Request cannot be
- completed without displaying a user interface for End-User consent.
- """
- error = 'consent_required'
- status_code = 401
-
-
-class InvalidRequestURI(OpenIDClientError):
- """
- The request_uri in the Authorization Request returns an error or
- contains invalid data.
- """
- error = 'invalid_request_uri'
- description = 'The request_uri in the Authorization Request returns an ' \
- 'error or contains invalid data.'
-
-
-class InvalidRequestObject(OpenIDClientError):
- """
- The request parameter contains an invalid Request Object.
- """
- error = 'invalid_request_object'
- description = 'The request parameter contains an invalid Request Object.'
-
-
-class RequestNotSupported(OpenIDClientError):
- """
- The OP does not support use of the request parameter.
- """
- error = 'request_not_supported'
- description = 'The request parameter is not supported.'
-
-
-class RequestURINotSupported(OpenIDClientError):
- """
- The OP does not support use of the request_uri parameter.
- """
- error = 'request_uri_not_supported'
- description = 'The request_uri parameter is not supported.'
-
-
-class RegistrationNotSupported(OpenIDClientError):
- """
- The OP does not support use of the registration parameter.
- """
- error = 'registration_not_supported'
- description = 'The registration parameter is not supported.'
-
-
class InvalidTokenError(OAuth2Error):
"""
The access token provided is expired, revoked, malformed, or
@@ -402,6 +302,29 @@ class InsufficientScopeError(OAuth2Error):
"the access token.")
+class ConsentRequired(OAuth2Error):
+ """
+ The Authorization Server requires End-User consent.
+
+ This error MAY be returned when the prompt parameter value in the
+ Authentication Request is none, but the Authentication Request cannot be
+ completed without displaying a user interface for End-User consent.
+ """
+ error = 'consent_required'
+ status_code = 401
+
+class LoginRequired(OAuth2Error):
+ """
+ The Authorization Server requires End-User authentication.
+
+ This error MAY be returned when the prompt parameter value in the
+ Authentication Request is none, but the Authentication Request cannot be
+ completed without displaying a user interface for End-User authentication.
+ """
+ error = 'login_required'
+ status_code = 401
+
+
def raise_from_error(error, params=None):
import inspect
import sys
diff --git a/oauthlib/oauth2/rfc6749/grant_types/__init__.py b/oauthlib/oauth2/rfc6749/grant_types/__init__.py
index 2e4bfe4..2ec8e4f 100644
--- a/oauthlib/oauth2/rfc6749/grant_types/__init__.py
+++ b/oauthlib/oauth2/rfc6749/grant_types/__init__.py
@@ -10,11 +10,3 @@ from .implicit import ImplicitGrant
from .resource_owner_password_credentials import ResourceOwnerPasswordCredentialsGrant
from .client_credentials import ClientCredentialsGrant
from .refresh_token import RefreshTokenGrant
-from .openid_connect import OpenIDConnectBase
-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
-from .openid_connect import AuthTokenGrantDispatcher
-from .openid_connect import ImplicitTokenGrantDispatcher
diff --git a/oauthlib/oauth2/rfc6749/request_validator.py b/oauthlib/oauth2/rfc6749/request_validator.py
index 56ecc3d..92edba6 100644
--- a/oauthlib/oauth2/rfc6749/request_validator.py
+++ b/oauthlib/oauth2/rfc6749/request_validator.py
@@ -1,7 +1,7 @@
# -*- coding: utf-8 -*-
"""
-oauthlib.oauth2.rfc6749.grant_types
-~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+oauthlib.oauth2.rfc6749.request_validator
+~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
"""
from __future__ import absolute_import, unicode_literals
diff --git a/oauthlib/oauth2/rfc6749/tokens.py b/oauthlib/oauth2/rfc6749/tokens.py
index a7491f4..1d2b5eb 100644
--- a/oauthlib/oauth2/rfc6749/tokens.py
+++ b/oauthlib/oauth2/rfc6749/tokens.py
@@ -315,43 +315,3 @@ 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 = get_token_from_header(request)
- return self.request_validator.validate_jwt_bearer_token(
- token, request.scopes, request)
-
- def estimate_type(self, request):
- split_header = request.headers.get('Authorization', '').split()
-
- if len(split_header) == 2 and split_header[0] == 'Bearer' and split_header[1].startswith('ey') and split_header[1].count('.') in (2, 4):
- return 10
- return 0
diff --git a/oauthlib/openid/__init__.py b/oauthlib/openid/__init__.py
new file mode 100644
index 0000000..e69de29
--- /dev/null
+++ b/oauthlib/openid/__init__.py
diff --git a/oauthlib/openid/connect/__init__.py b/oauthlib/openid/connect/__init__.py
new file mode 100644
index 0000000..e69de29
--- /dev/null
+++ b/oauthlib/openid/connect/__init__.py
diff --git a/oauthlib/openid/connect/core/__init__.py b/oauthlib/openid/connect/core/__init__.py
new file mode 100644
index 0000000..e69de29
--- /dev/null
+++ b/oauthlib/openid/connect/core/__init__.py
diff --git a/oauthlib/openid/connect/core/endpoints/pre_configured.py b/oauthlib/openid/connect/core/endpoints/pre_configured.py
new file mode 100644
index 0000000..3bcd24d
--- /dev/null
+++ b/oauthlib/openid/connect/core/endpoints/pre_configured.py
@@ -0,0 +1,103 @@
+# -*- coding: utf-8 -*-
+"""
+oauthlib.openid.connect.core.endpoints.pre_configured
+~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+
+This module is an implementation of various endpoints needed
+for providing OpenID Connect servers.
+"""
+from __future__ import absolute_import, unicode_literals
+
+from ..grant_types import (
+ AuthorizationCodeGrant as OAuth2AuthorizationCodeGrant,
+ ClientCredentialsGrant,
+ ImplicitGrant as OAuth2ImplicitGrant,
+ RefreshTokenGrant,
+ ResourceOwnerPasswordCredentialsGrant
+)
+
+from oauthlib.openid.connect.core.grant_types.authorization_code import AuthorizationCodeGrant
+from oauthlib.openid.connect.core.grant_types.dispatchers import (
+ AuthorizationCodeGrantDispatcher,
+ ImplicitTokenGrantDispatcher,
+ AuthorizationTokenGrantDispatcher
+)
+from oauthlib.openid.connect.core.grant_types.implicit import ImplicitGrant
+from oauthlib.openid.connect.core.grant_types.hybrid import HybridGrant
+from oauthlib.openid.connect.core.tokens import JWTToken
+
+from ..tokens import BearerToken
+from .authorization import AuthorizationEndpoint
+from .resource import ResourceEndpoint
+from .revocation import RevocationEndpoint
+from .token import TokenEndpoint
+
+
+class Server(AuthorizationEndpoint, TokenEndpoint, ResourceEndpoint,
+ RevocationEndpoint):
+
+ """An all-in-one endpoint featuring all four major grant types."""
+
+ def __init__(self, request_validator, token_expires_in=None,
+ token_generator=None, refresh_token_generator=None,
+ *args, **kwargs):
+ """Construct a new all-grants-in-one server.
+
+ :param request_validator: An implementation of
+ oauthlib.oauth2.RequestValidator.
+ :param token_expires_in: An int or a function to generate a token
+ expiration offset (in seconds) given a
+ oauthlib.common.Request object.
+ :param token_generator: A function to generate a token from a request.
+ :param refresh_token_generator: A function to generate a token from a
+ request for the refresh token.
+ :param kwargs: Extra parameters to pass to authorization-,
+ token-, resource-, and revocation-endpoint constructors.
+ """
+ auth_grant = OAuth2AuthorizationCodeGrant(request_validator)
+ implicit_grant = OAuth2ImplicitGrant(request_validator)
+ password_grant = ResourceOwnerPasswordCredentialsGrant(
+ request_validator)
+ credentials_grant = ClientCredentialsGrant(request_validator)
+ refresh_grant = RefreshTokenGrant(request_validator)
+ openid_connect_auth = AuthorizationCodeGrant(request_validator)
+ openid_connect_implicit = ImplicitGrant(request_validator)
+ openid_connect_hybrid = HybridGrant(request_validator)
+
+ 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 = AuthorizationCodeGrantDispatcher(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)
+
+ # 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_choice,
+ 'token': implicit_grant_choice,
+ 'id_token': openid_connect_implicit,
+ 'id_token token': openid_connect_implicit,
+ 'code token': openid_connect_hybrid,
+ 'code id_token': openid_connect_hybrid,
+ 'code id_token token': openid_connect_hybrid,
+ 'none': auth_grant
+ },
+ default_token_type=bearer)
+
+ token_grant_choice = AuthorizationTokenGrantDispatcher(request_validator, default_token_grant=auth_grant, oidc_token_grant=openid_connect_auth)
+
+ TokenEndpoint.__init__(self, default_grant_type='authorization_code',
+ grant_types={
+ 'authorization_code': token_grant_choice,
+ 'password': password_grant,
+ 'client_credentials': credentials_grant,
+ 'refresh_token': refresh_grant,
+ },
+ default_token_type=bearer)
+ ResourceEndpoint.__init__(self, default_token='Bearer',
+ token_types={'Bearer': bearer, 'JWT': jwt})
+ RevocationEndpoint.__init__(self, request_validator)
diff --git a/oauthlib/openid/connect/core/exceptions.py b/oauthlib/openid/connect/core/exceptions.py
new file mode 100644
index 0000000..8b08d21
--- /dev/null
+++ b/oauthlib/openid/connect/core/exceptions.py
@@ -0,0 +1,152 @@
+# coding=utf-8
+"""
+oauthlib.oauth2.rfc6749.errors
+~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+
+Error used both by OAuth 2 clients and providers to represent the spec
+defined error responses for all four core grant types.
+"""
+from __future__ import unicode_literals
+
+from oauthlib.oauth2.rfc6749.errors import FatalClientError, OAuth2Error
+
+
+class FatalOpenIDClientError(FatalClientError):
+ pass
+
+
+class OpenIDClientError(OAuth2Error):
+ pass
+
+
+class InteractionRequired(OpenIDClientError):
+ """
+ The Authorization Server requires End-User interaction to proceed.
+
+ This error MAY be returned when the prompt parameter value in the
+ Authentication Request is none, but the Authentication Request cannot be
+ completed without displaying a user interface for End-User interaction.
+ """
+ error = 'interaction_required'
+ status_code = 401
+
+
+class LoginRequired(OpenIDClientError):
+ """
+ The Authorization Server requires End-User authentication.
+
+ This error MAY be returned when the prompt parameter value in the
+ Authentication Request is none, but the Authentication Request cannot be
+ completed without displaying a user interface for End-User authentication.
+ """
+ error = 'login_required'
+ status_code = 401
+
+
+class AccountSelectionRequired(OpenIDClientError):
+ """
+ The End-User is REQUIRED to select a session at the Authorization Server.
+
+ The End-User MAY be authenticated at the Authorization Server with
+ different associated accounts, but the End-User did not select a session.
+ This error MAY be returned when the prompt parameter value in the
+ Authentication Request is none, but the Authentication Request cannot be
+ completed without displaying a user interface to prompt for a session to
+ use.
+ """
+ error = 'account_selection_required'
+
+
+class ConsentRequired(OpenIDClientError):
+ """
+ The Authorization Server requires End-User consent.
+
+ This error MAY be returned when the prompt parameter value in the
+ Authentication Request is none, but the Authentication Request cannot be
+ completed without displaying a user interface for End-User consent.
+ """
+ error = 'consent_required'
+ status_code = 401
+
+
+class InvalidRequestURI(OpenIDClientError):
+ """
+ The request_uri in the Authorization Request returns an error or
+ contains invalid data.
+ """
+ error = 'invalid_request_uri'
+ description = 'The request_uri in the Authorization Request returns an ' \
+ 'error or contains invalid data.'
+
+
+class InvalidRequestObject(OpenIDClientError):
+ """
+ The request parameter contains an invalid Request Object.
+ """
+ error = 'invalid_request_object'
+ description = 'The request parameter contains an invalid Request Object.'
+
+
+class RequestNotSupported(OpenIDClientError):
+ """
+ The OP does not support use of the request parameter.
+ """
+ error = 'request_not_supported'
+ description = 'The request parameter is not supported.'
+
+
+class RequestURINotSupported(OpenIDClientError):
+ """
+ The OP does not support use of the request_uri parameter.
+ """
+ error = 'request_uri_not_supported'
+ description = 'The request_uri parameter is not supported.'
+
+
+class RegistrationNotSupported(OpenIDClientError):
+ """
+ The OP does not support use of the registration parameter.
+ """
+ error = 'registration_not_supported'
+ description = 'The registration parameter is not supported.'
+
+
+class InvalidTokenError(OAuth2Error):
+ """
+ The access token provided is expired, revoked, malformed, or
+ invalid for other reasons. The resource SHOULD respond with
+ the HTTP 401 (Unauthorized) status code. The client MAY
+ request a new access token and retry the protected resource
+ request.
+ """
+ error = 'invalid_token'
+ status_code = 401
+ description = ("The access token provided is expired, revoked, malformed, "
+ "or invalid for other reasons.")
+
+
+class InsufficientScopeError(OAuth2Error):
+ """
+ The request requires higher privileges than provided by the
+ access token. The resource server SHOULD respond with the HTTP
+ 403 (Forbidden) status code and MAY include the "scope"
+ attribute with the scope necessary to access the protected
+ resource.
+ """
+ error = 'insufficient_scope'
+ status_code = 403
+ description = ("The request requires higher privileges than provided by "
+ "the access token.")
+
+
+def raise_from_error(error, params=None):
+ import inspect
+ import sys
+ kwargs = {
+ 'description': params.get('error_description'),
+ 'uri': params.get('error_uri'),
+ 'state': params.get('state')
+ }
+ for _, cls in inspect.getmembers(sys.modules[__name__], inspect.isclass):
+ if cls.error == error:
+ raise cls(**kwargs)
diff --git a/oauthlib/openid/connect/core/grant_types/__init__.py b/oauthlib/openid/connect/core/grant_types/__init__.py
new file mode 100644
index 0000000..7fc183d
--- /dev/null
+++ b/oauthlib/openid/connect/core/grant_types/__init__.py
@@ -0,0 +1,17 @@
+# -*- coding: utf-8 -*-
+"""
+oauthlib.oauth2.rfc6749.grant_types
+~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+"""
+from __future__ import unicode_literals, absolute_import
+
+from .authorization_code import AuthorizationCodeGrant
+from .implicit import ImplicitGrant
+from .base import GrantTypeBase
+from .hybrid import HybridGrant
+from .exceptions import OIDCNoPrompt
+from oauthlib.openid.connect.core.grant_types.dispatchers import (
+ AuthorizationCodeGrantDispatcher,
+ ImplicitTokenGrantDispatcher,
+ AuthorizationTokenGrantDispatcher
+)
diff --git a/oauthlib/openid/connect/core/grant_types/authorization_code.py b/oauthlib/openid/connect/core/grant_types/authorization_code.py
new file mode 100644
index 0000000..b0b1015
--- /dev/null
+++ b/oauthlib/openid/connect/core/grant_types/authorization_code.py
@@ -0,0 +1,24 @@
+# -*- coding: utf-8 -*-
+"""
+oauthlib.openid.connect.core.grant_types
+~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+"""
+from __future__ import absolute_import, unicode_literals
+
+import logging
+
+from oauthlib.oauth2.rfc6749.grant_types.authorization_code import AuthorizationCodeGrant as OAuth2AuthorizationCodeGrant
+
+from .base import GrantTypeBase
+
+log = logging.getLogger(__name__)
+
+
+class AuthorizationCodeGrant(GrantTypeBase):
+
+ def __init__(self, request_validator=None, **kwargs):
+ self.proxy_target = OAuth2AuthorizationCodeGrant(
+ request_validator=request_validator, **kwargs)
+ self.custom_validators.post_auth.append(
+ self.openid_authorization_validator)
+ self.register_token_modifier(self.add_id_token)
diff --git a/oauthlib/oauth2/rfc6749/grant_types/openid_connect.py b/oauthlib/openid/connect/core/grant_types/base.py
index 4371b28..2bb48b1 100644
--- a/oauthlib/oauth2/rfc6749/grant_types/openid_connect.py
+++ b/oauthlib/openid/connect/core/grant_types/base.py
@@ -1,141 +1,15 @@
-# -*- coding: utf-8 -*-
-"""
-oauthlib.oauth2.rfc6749.grant_types.openid_connect
-~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
-"""
-from __future__ import absolute_import, unicode_literals
+from .exceptions import OIDCNoPrompt
import datetime
import logging
from json import loads
-from ..errors import ConsentRequired, InvalidRequestError, LoginRequired
-from ..request_validator import RequestValidator
-from .authorization_code import AuthorizationCodeGrant
-from .implicit import ImplicitGrant
+from oauthlib.oauth2.rfc6749.errors import ConsentRequired, InvalidRequestError, LoginRequired
log = logging.getLogger(__name__)
-class OIDCNoPrompt(Exception):
- """Exception used to inform users that no explicit authorization is needed.
-
- Normally users authorize requests after validation of the request is done.
- Then post-authorization validation is again made and a response containing
- an auth code or token is created. However, when OIDC clients request
- no prompting of user authorization the final response is created directly.
-
- Example (without the shortcut for no prompt)
-
- scopes, req_info = endpoint.validate_authorization_request(url, ...)
- authorization_view = create_fancy_auth_form(scopes, req_info)
- return authorization_view
-
- Example (with the no prompt shortcut)
- try:
- scopes, req_info = endpoint.validate_authorization_request(url, ...)
- authorization_view = create_fancy_auth_form(scopes, req_info)
- return authorization_view
- except OIDCNoPrompt:
- # Note: Location will be set for you
- headers, body, status = endpoint.create_authorization_response(url, ...)
- redirect_view = create_redirect(headers, body, status)
- return redirect_view
- """
-
- def __init__(self):
- msg = ("OIDC request for no user interaction received. Do not ask user "
- "for authorization, it should been done using silent "
- "authentication through create_authorization_response. "
- "See OIDCNoPrompt.__doc__ for more details.")
- super(OIDCNoPrompt, self).__init__(msg)
-
-
-class AuthCodeGrantDispatcher(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_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 request.scopes and "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 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):
+class GrantTypeBase(object):
# Just proxy the majority of method calls through to the
# proxy_target grant type handler, which will usually be either
@@ -406,46 +280,4 @@ class OpenIDConnectBase(object):
return {}
-class OpenIDConnectAuthCode(OpenIDConnectBase):
-
- def __init__(self, request_validator=None, **kwargs):
- self.proxy_target = AuthorizationCodeGrant(
- request_validator=request_validator, **kwargs)
- self.custom_validators.post_auth.append(
- self.openid_authorization_validator)
- self.register_token_modifier(self.add_id_token)
-
-
-class OpenIDConnectImplicit(OpenIDConnectBase):
-
- def __init__(self, request_validator=None, **kwargs):
- self.proxy_target = ImplicitGrant(
- request_validator=request_validator, **kwargs)
- self.register_response_type('id_token')
- self.register_response_type('id_token token')
- self.custom_validators.post_auth.append(
- self.openid_authorization_validator)
- self.custom_validators.post_auth.append(
- self.openid_implicit_authorization_validator)
- self.register_token_modifier(self.add_id_token)
-
-
-class OpenIDConnectHybrid(OpenIDConnectBase):
-
- def __init__(self, request_validator=None, **kwargs):
- self.request_validator = request_validator or RequestValidator()
-
- self.proxy_target = AuthorizationCodeGrant(
- request_validator=request_validator, **kwargs)
- # All hybrid response types should be fragment-encoded.
- self.proxy_target.default_response_mode = "fragment"
- self.register_response_type('code id_token')
- self.register_response_type('code token')
- self.register_response_type('code id_token token')
- self.custom_validators.post_auth.append(
- self.openid_authorization_validator)
- # Hybrid flows can return the id_token from the authorization
- # endpoint as part of the 'code' response
- self.register_code_modifier(self.add_token)
- self.register_code_modifier(self.add_id_token)
- self.register_token_modifier(self.add_id_token)
+OpenIDConnectBase = GrantTypeBase
diff --git a/oauthlib/openid/connect/core/grant_types/dispatchers.py b/oauthlib/openid/connect/core/grant_types/dispatchers.py
new file mode 100644
index 0000000..2c33406
--- /dev/null
+++ b/oauthlib/openid/connect/core/grant_types/dispatchers.py
@@ -0,0 +1,86 @@
+import logging
+log = logging.getLogger(__name__)
+
+
+class AuthorizationCodeGrantDispatcher(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_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 request.scopes and "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 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 AuthorizationTokenGrantDispatcher(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)
diff --git a/oauthlib/openid/connect/core/grant_types/exceptions.py b/oauthlib/openid/connect/core/grant_types/exceptions.py
new file mode 100644
index 0000000..809f1b3
--- /dev/null
+++ b/oauthlib/openid/connect/core/grant_types/exceptions.py
@@ -0,0 +1,32 @@
+class OIDCNoPrompt(Exception):
+ """Exception used to inform users that no explicit authorization is needed.
+
+ Normally users authorize requests after validation of the request is done.
+ Then post-authorization validation is again made and a response containing
+ an auth code or token is created. However, when OIDC clients request
+ no prompting of user authorization the final response is created directly.
+
+ Example (without the shortcut for no prompt)
+
+ scopes, req_info = endpoint.validate_authorization_request(url, ...)
+ authorization_view = create_fancy_auth_form(scopes, req_info)
+ return authorization_view
+
+ Example (with the no prompt shortcut)
+ try:
+ scopes, req_info = endpoint.validate_authorization_request(url, ...)
+ authorization_view = create_fancy_auth_form(scopes, req_info)
+ return authorization_view
+ except OIDCNoPrompt:
+ # Note: Location will be set for you
+ headers, body, status = endpoint.create_authorization_response(url, ...)
+ redirect_view = create_redirect(headers, body, status)
+ return redirect_view
+ """
+
+ def __init__(self):
+ msg = ("OIDC request for no user interaction received. Do not ask user "
+ "for authorization, it should been done using silent "
+ "authentication through create_authorization_response. "
+ "See OIDCNoPrompt.__doc__ for more details.")
+ super(OIDCNoPrompt, self).__init__(msg)
diff --git a/oauthlib/openid/connect/core/grant_types/hybrid.py b/oauthlib/openid/connect/core/grant_types/hybrid.py
new file mode 100644
index 0000000..54669ae
--- /dev/null
+++ b/oauthlib/openid/connect/core/grant_types/hybrid.py
@@ -0,0 +1,36 @@
+# -*- coding: utf-8 -*-
+"""
+oauthlib.openid.connect.core.grant_types
+~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+"""
+from __future__ import absolute_import, unicode_literals
+
+import logging
+
+from oauthlib.oauth2.rfc6749.grant_types.authorization_code import AuthorizationCodeGrant as OAuth2AuthorizationCodeGrant
+
+from .base import GrantTypeBase
+from ..request_validator import RequestValidator
+
+log = logging.getLogger(__name__)
+
+
+class HybridGrant(GrantTypeBase):
+
+ def __init__(self, request_validator=None, **kwargs):
+ self.request_validator = request_validator or RequestValidator()
+
+ self.proxy_target = OAuth2AuthorizationCodeGrant(
+ request_validator=request_validator, **kwargs)
+ # All hybrid response types should be fragment-encoded.
+ self.proxy_target.default_response_mode = "fragment"
+ self.register_response_type('code id_token')
+ self.register_response_type('code token')
+ self.register_response_type('code id_token token')
+ self.custom_validators.post_auth.append(
+ self.openid_authorization_validator)
+ # Hybrid flows can return the id_token from the authorization
+ # endpoint as part of the 'code' response
+ self.register_code_modifier(self.add_token)
+ self.register_code_modifier(self.add_id_token)
+ self.register_token_modifier(self.add_id_token)
diff --git a/oauthlib/openid/connect/core/grant_types/implicit.py b/oauthlib/openid/connect/core/grant_types/implicit.py
new file mode 100644
index 0000000..0eaa5b3
--- /dev/null
+++ b/oauthlib/openid/connect/core/grant_types/implicit.py
@@ -0,0 +1,28 @@
+# -*- coding: utf-8 -*-
+"""
+oauthlib.openid.connect.core.grant_types
+~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+"""
+from __future__ import absolute_import, unicode_literals
+
+import logging
+
+from .base import GrantTypeBase
+
+from oauthlib.oauth2.rfc6749.grant_types.implicit import ImplicitGrant as OAuth2ImplicitGrant
+
+log = logging.getLogger(__name__)
+
+
+class ImplicitGrant(GrantTypeBase):
+
+ def __init__(self, request_validator=None, **kwargs):
+ self.proxy_target = OAuth2ImplicitGrant(
+ request_validator=request_validator, **kwargs)
+ self.register_response_type('id_token')
+ self.register_response_type('id_token token')
+ self.custom_validators.post_auth.append(
+ self.openid_authorization_validator)
+ self.custom_validators.post_auth.append(
+ self.openid_implicit_authorization_validator)
+ self.register_token_modifier(self.add_id_token)
diff --git a/oauthlib/openid/connect/core/request_validator.py b/oauthlib/openid/connect/core/request_validator.py
new file mode 100644
index 0000000..f3bcbdb
--- /dev/null
+++ b/oauthlib/openid/connect/core/request_validator.py
@@ -0,0 +1,188 @@
+# -*- coding: utf-8 -*-
+"""
+oauthlib.openid.connect.core.request_validator
+~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+"""
+from __future__ import absolute_import, unicode_literals
+
+import logging
+
+from oauthlib.oauth2.rfc6749.request_validator import RequestValidator as OAuth2RequestValidator
+
+log = logging.getLogger(__name__)
+
+
+class RequestValidator(OAuth2RequestValidator):
+
+ def get_authorization_code_scopes(self, client_id, code, redirect_uri, request):
+ """ Extracts scopes from saved authorization code.
+
+ The scopes returned by this method is used to route token requests
+ based on scopes passed to Authorization Code requests.
+
+ With that the token endpoint knows when to include OpenIDConnect
+ id_token in token response only based on authorization code scopes.
+
+ Only code param should be sufficient to retrieve grant code from
+ any storage you are using, `client_id` and `redirect_uri` can gave a
+ blank value `""` don't forget to check it before using those values
+ in a select query if a database is used.
+
+ :param client_id: Unicode client identifier
+ :param code: Unicode authorization code grant
+ :param redirect_uri: Unicode absolute URI
+ :return: A list of scope
+
+ Method is used by:
+ - Authorization Token Grant Dispatcher
+ """
+ raise NotImplementedError('Subclasses must implement this method.')
+
+ 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.
+
+ In addition to the standard OAuth2 request properties, the request may also contain
+ these OIDC specific properties which are useful to this method:
+
+ - 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)
+ :return: The ID Token (a JWS signed JWT)
+ """
+ # 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_silent_authorization(self, request):
+ """Ensure the logged in user has authorized silent OpenID authorization.
+
+ Silent OpenID authorization allows access tokens and id tokens to be
+ granted to clients without any user prompt or interaction.
+
+ :param request: The HTTP Request (oauthlib.common.Request)
+ :rtype: True or False
+
+ Method is used by:
+ - OpenIDConnectAuthCode
+ - OpenIDConnectImplicit
+ - OpenIDConnectHybrid
+ """
+ raise NotImplementedError('Subclasses must implement this method.')
+
+ def validate_silent_login(self, request):
+ """Ensure session user has authorized silent OpenID login.
+
+ If no user is logged in or has not authorized silent login, this
+ method should return False.
+
+ If the user is logged in but associated with multiple accounts and
+ not selected which one to link to the token then this method should
+ raise an oauthlib.oauth2.AccountSelectionRequired error.
+
+ :param request: The HTTP Request (oauthlib.common.Request)
+ :rtype: True or False
+
+ Method is used by:
+ - OpenIDConnectAuthCode
+ - OpenIDConnectImplicit
+ - OpenIDConnectHybrid
+ """
+ raise NotImplementedError('Subclasses must implement this method.')
+
+ def validate_user_match(self, id_token_hint, scopes, claims, request):
+ """Ensure client supplied user id hint matches session user.
+
+ If the sub claim or id_token_hint is supplied then the session
+ user must match the given ID.
+
+ :param id_token_hint: User identifier string.
+ :param scopes: List of OAuth 2 scopes and OpenID claims (strings).
+ :param claims: OpenID Connect claims dict.
+ :param request: The HTTP Request (oauthlib.common.Request)
+ :rtype: True or False
+
+ Method is used by:
+ - OpenIDConnectAuthCode
+ - OpenIDConnectImplicit
+ - OpenIDConnectHybrid
+ """
+ raise NotImplementedError('Subclasses must implement this method.')
diff --git a/oauthlib/openid/connect/core/tokens.py b/oauthlib/openid/connect/core/tokens.py
new file mode 100644
index 0000000..6b68891
--- /dev/null
+++ b/oauthlib/openid/connect/core/tokens.py
@@ -0,0 +1,54 @@
+"""
+authlib.openid.connect.core.tokens
+~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+
+This module contains methods for adding JWT tokens to requests.
+"""
+from __future__ import absolute_import, unicode_literals
+
+
+from oauthlib.oauth2.rfc6749.tokens import TokenBase, random_token_generator
+
+
+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