summaryrefslogtreecommitdiff
path: root/oauthlib/oauth2
diff options
context:
space:
mode:
authorPieter Ennes <pieter@ennes.nl>2018-05-26 20:39:09 +0100
committerGitHub <noreply@github.com>2018-05-26 20:39:09 +0100
commite44d5d93dd0d97998a58f1b84cb51119d136fad2 (patch)
treee0afe763750ffa7f608dc82f8a92b396f3be5922 /oauthlib/oauth2
parent296c6bc5931c95f631c1a496dacc523959fc50e9 (diff)
parentfedc1d1b740a0407ec59152750bbbd9dc736b51d (diff)
downloadoauthlib-e44d5d93dd0d97998a58f1b84cb51119d136fad2.tar.gz
Merge branch 'master' into oauth2-introspect
Diffstat (limited to 'oauthlib/oauth2')
-rw-r--r--oauthlib/oauth2/rfc6749/clients/backend_application.py6
-rw-r--r--oauthlib/oauth2/rfc6749/clients/base.py34
-rw-r--r--oauthlib/oauth2/rfc6749/clients/legacy_application.py6
-rw-r--r--oauthlib/oauth2/rfc6749/clients/mobile_application.py16
-rw-r--r--oauthlib/oauth2/rfc6749/clients/service_application.py6
-rw-r--r--oauthlib/oauth2/rfc6749/clients/web_application.py18
-rw-r--r--oauthlib/oauth2/rfc6749/endpoints/authorization.py2
-rw-r--r--oauthlib/oauth2/rfc6749/endpoints/pre_configured.py7
-rw-r--r--oauthlib/oauth2/rfc6749/endpoints/resource.py2
-rw-r--r--oauthlib/oauth2/rfc6749/endpoints/revocation.py12
-rw-r--r--oauthlib/oauth2/rfc6749/endpoints/token.py2
-rw-r--r--oauthlib/oauth2/rfc6749/grant_types/authorization_code.py29
-rw-r--r--oauthlib/oauth2/rfc6749/grant_types/client_credentials.py6
-rw-r--r--oauthlib/oauth2/rfc6749/grant_types/implicit.py34
-rw-r--r--oauthlib/oauth2/rfc6749/grant_types/refresh_token.py8
-rw-r--r--oauthlib/oauth2/rfc6749/grant_types/resource_owner_password_credentials.py10
-rw-r--r--oauthlib/oauth2/rfc6749/parameters.py32
-rw-r--r--oauthlib/oauth2/rfc6749/request_validator.py74
-rw-r--r--oauthlib/oauth2/rfc6749/tokens.py82
19 files changed, 258 insertions, 128 deletions
diff --git a/oauthlib/oauth2/rfc6749/clients/backend_application.py b/oauthlib/oauth2/rfc6749/clients/backend_application.py
index 7505b0d..cbad8b7 100644
--- a/oauthlib/oauth2/rfc6749/clients/backend_application.py
+++ b/oauthlib/oauth2/rfc6749/clients/backend_application.py
@@ -52,9 +52,9 @@ class BackendApplicationClient(Client):
>>> client.prepare_request_body(scope=['hello', 'world'])
'grant_type=client_credentials&scope=hello+world'
- .. _`Appendix B`: http://tools.ietf.org/html/rfc6749#appendix-B
- .. _`Section 3.3`: http://tools.ietf.org/html/rfc6749#section-3.3
- .. _`Section 3.2.1`: http://tools.ietf.org/html/rfc6749#section-3.2.1
+ .. _`Appendix B`: https://tools.ietf.org/html/rfc6749#appendix-B
+ .. _`Section 3.3`: https://tools.ietf.org/html/rfc6749#section-3.3
+ .. _`Section 3.2.1`: https://tools.ietf.org/html/rfc6749#section-3.2.1
"""
return prepare_token_request('client_credentials', body=body,
scope=scope, **kwargs)
diff --git a/oauthlib/oauth2/rfc6749/clients/base.py b/oauthlib/oauth2/rfc6749/clients/base.py
index 5c5acee..406832d 100644
--- a/oauthlib/oauth2/rfc6749/clients/base.py
+++ b/oauthlib/oauth2/rfc6749/clients/base.py
@@ -9,6 +9,7 @@ for consuming OAuth 2.0 RFC6749.
from __future__ import absolute_import, unicode_literals
import time
+import warnings
from oauthlib.common import generate_token
from oauthlib.oauth2.rfc6749 import tokens
@@ -111,8 +112,10 @@ class Client(object):
self.state_generator = state_generator
self.state = state
self.redirect_url = redirect_url
+ self.code = None
+ self.expires_in = None
self._expires_at = None
- self._populate_attributes(self.token)
+ self.populate_token_attributes(self.token)
@property
def token_types(self):
@@ -140,6 +143,7 @@ class Client(object):
def parse_request_uri_response(self, *args, **kwargs):
"""Abstract method used to parse redirection responses."""
+ raise NotImplementedError("Must be implemented by inheriting classes.")
def add_token(self, uri, http_method='GET', body=None, headers=None,
token_placement=None, **kwargs):
@@ -173,8 +177,8 @@ class Client(object):
nonce="274312:dj83hs9s",
mac="kDZvddkndxvhGRXZhvuDjEWhGeE="
- .. _`I-D.ietf-oauth-v2-bearer`: http://tools.ietf.org/html/rfc6749#section-12.2
- .. _`I-D.ietf-oauth-v2-http-mac`: http://tools.ietf.org/html/rfc6749#section-12.2
+ .. _`I-D.ietf-oauth-v2-bearer`: https://tools.ietf.org/html/rfc6749#section-12.2
+ .. _`I-D.ietf-oauth-v2-http-mac`: https://tools.ietf.org/html/rfc6749#section-12.2
"""
if not is_secure_transport(uri):
raise InsecureTransportError()
@@ -401,12 +405,12 @@ class Client(object):
Providers may supply this in all responses but are required to only
if it has changed since the authorization request.
- .. _`Section 5.1`: http://tools.ietf.org/html/rfc6749#section-5.1
- .. _`Section 5.2`: http://tools.ietf.org/html/rfc6749#section-5.2
- .. _`Section 7.1`: http://tools.ietf.org/html/rfc6749#section-7.1
+ .. _`Section 5.1`: https://tools.ietf.org/html/rfc6749#section-5.1
+ .. _`Section 5.2`: https://tools.ietf.org/html/rfc6749#section-5.2
+ .. _`Section 7.1`: https://tools.ietf.org/html/rfc6749#section-7.1
"""
self.token = parse_token_response(body, scope=scope)
- self._populate_attributes(self.token)
+ self.populate_token_attributes(self.token)
return self.token
def prepare_refresh_body(self, body='', refresh_token=None, scope=None, **kwargs):
@@ -460,7 +464,18 @@ class Client(object):
return uri, headers, body
def _populate_attributes(self, response):
- """Add commonly used values such as access_token to self."""
+ warnings.warn("Please switch to the public method "
+ "populate_token_attributes.", DeprecationWarning)
+ return self.populate_token_attributes(response)
+
+ def populate_code_attributes(self, response):
+ """Add attributes from an auth code response to self."""
+
+ if 'code' in response:
+ self.code = response.get('code')
+
+ def populate_token_attributes(self, response):
+ """Add attributes from a token exchange response to self."""
if 'access_token' in response:
self.access_token = response.get('access_token')
@@ -478,9 +493,6 @@ class Client(object):
if 'expires_at' in response:
self._expires_at = int(response.get('expires_at'))
- if 'code' in response:
- self.code = response.get('code')
-
if 'mac_key' in response:
self.mac_key = response.get('mac_key')
diff --git a/oauthlib/oauth2/rfc6749/clients/legacy_application.py b/oauthlib/oauth2/rfc6749/clients/legacy_application.py
index 57fe99e..b16fc9f 100644
--- a/oauthlib/oauth2/rfc6749/clients/legacy_application.py
+++ b/oauthlib/oauth2/rfc6749/clients/legacy_application.py
@@ -64,9 +64,9 @@ class LegacyApplicationClient(Client):
>>> client.prepare_request_body(username='foo', password='bar', scope=['hello', 'world'])
'grant_type=password&username=foo&scope=hello+world&password=bar'
- .. _`Appendix B`: http://tools.ietf.org/html/rfc6749#appendix-B
- .. _`Section 3.3`: http://tools.ietf.org/html/rfc6749#section-3.3
- .. _`Section 3.2.1`: http://tools.ietf.org/html/rfc6749#section-3.2.1
+ .. _`Appendix B`: https://tools.ietf.org/html/rfc6749#appendix-B
+ .. _`Section 3.3`: https://tools.ietf.org/html/rfc6749#section-3.3
+ .. _`Section 3.2.1`: https://tools.ietf.org/html/rfc6749#section-3.2.1
"""
return prepare_token_request('password', body=body, username=username,
password=password, scope=scope, **kwargs)
diff --git a/oauthlib/oauth2/rfc6749/clients/mobile_application.py b/oauthlib/oauth2/rfc6749/clients/mobile_application.py
index 490efcd..aa20daa 100644
--- a/oauthlib/oauth2/rfc6749/clients/mobile_application.py
+++ b/oauthlib/oauth2/rfc6749/clients/mobile_application.py
@@ -85,11 +85,11 @@ class MobileApplicationClient(Client):
>>> client.prepare_request_uri('https://example.com', foo='bar')
'https://example.com?client_id=your_id&response_type=token&foo=bar'
- .. _`Appendix B`: http://tools.ietf.org/html/rfc6749#appendix-B
- .. _`Section 2.2`: http://tools.ietf.org/html/rfc6749#section-2.2
- .. _`Section 3.1.2`: http://tools.ietf.org/html/rfc6749#section-3.1.2
- .. _`Section 3.3`: http://tools.ietf.org/html/rfc6749#section-3.3
- .. _`Section 10.12`: http://tools.ietf.org/html/rfc6749#section-10.12
+ .. _`Appendix B`: https://tools.ietf.org/html/rfc6749#appendix-B
+ .. _`Section 2.2`: https://tools.ietf.org/html/rfc6749#section-2.2
+ .. _`Section 3.1.2`: https://tools.ietf.org/html/rfc6749#section-3.1.2
+ .. _`Section 3.3`: https://tools.ietf.org/html/rfc6749#section-3.3
+ .. _`Section 10.12`: https://tools.ietf.org/html/rfc6749#section-10.12
"""
return prepare_grant_uri(uri, self.client_id, 'token',
redirect_uri=redirect_uri, state=state, scope=scope, **kwargs)
@@ -164,9 +164,9 @@ class MobileApplicationClient(Client):
>>> client.parse_request_body_response(response_body, scope=['other'])
('Scope has changed from "other" to "hello world".', ['other'], ['hello', 'world'])
- .. _`Section 7.1`: http://tools.ietf.org/html/rfc6749#section-7.1
- .. _`Section 3.3`: http://tools.ietf.org/html/rfc6749#section-3.3
+ .. _`Section 7.1`: https://tools.ietf.org/html/rfc6749#section-7.1
+ .. _`Section 3.3`: https://tools.ietf.org/html/rfc6749#section-3.3
"""
self.token = parse_implicit_response(uri, state=state, scope=scope)
- self._populate_attributes(self.token)
+ self.populate_token_attributes(self.token)
return self.token
diff --git a/oauthlib/oauth2/rfc6749/clients/service_application.py b/oauthlib/oauth2/rfc6749/clients/service_application.py
index e6c3270..7f336bb 100644
--- a/oauthlib/oauth2/rfc6749/clients/service_application.py
+++ b/oauthlib/oauth2/rfc6749/clients/service_application.py
@@ -136,7 +136,7 @@ class ServiceApplicationClient(Client):
eyJpc3Mi[...omitted for brevity...].
J9l-ZhwP[...omitted for brevity...]
- .. _`Section 3.2.1`: http://tools.ietf.org/html/rfc6749#section-3.2.1
+ .. _`Section 3.2.1`: https://tools.ietf.org/html/rfc6749#section-3.2.1
"""
import jwt
@@ -146,8 +146,8 @@ class ServiceApplicationClient(Client):
' token requests.')
claim = {
'iss': issuer or self.issuer,
- 'aud': audience or self.issuer,
- 'sub': subject or self.issuer,
+ 'aud': audience or self.audience,
+ 'sub': subject or self.subject,
'exp': int(expires_at or time.time() + 3600),
'iat': int(issued_at or time.time()),
}
diff --git a/oauthlib/oauth2/rfc6749/clients/web_application.py b/oauthlib/oauth2/rfc6749/clients/web_application.py
index c099d99..c14a5f8 100644
--- a/oauthlib/oauth2/rfc6749/clients/web_application.py
+++ b/oauthlib/oauth2/rfc6749/clients/web_application.py
@@ -76,11 +76,11 @@ class WebApplicationClient(Client):
>>> client.prepare_request_uri('https://example.com', foo='bar')
'https://example.com?client_id=your_id&response_type=code&foo=bar'
- .. _`Appendix B`: http://tools.ietf.org/html/rfc6749#appendix-B
- .. _`Section 2.2`: http://tools.ietf.org/html/rfc6749#section-2.2
- .. _`Section 3.1.2`: http://tools.ietf.org/html/rfc6749#section-3.1.2
- .. _`Section 3.3`: http://tools.ietf.org/html/rfc6749#section-3.3
- .. _`Section 10.12`: http://tools.ietf.org/html/rfc6749#section-10.12
+ .. _`Appendix B`: https://tools.ietf.org/html/rfc6749#appendix-B
+ .. _`Section 2.2`: https://tools.ietf.org/html/rfc6749#section-2.2
+ .. _`Section 3.1.2`: https://tools.ietf.org/html/rfc6749#section-3.1.2
+ .. _`Section 3.3`: https://tools.ietf.org/html/rfc6749#section-3.3
+ .. _`Section 10.12`: https://tools.ietf.org/html/rfc6749#section-10.12
"""
return prepare_grant_uri(uri, self.client_id, 'code',
redirect_uri=redirect_uri, scope=scope, state=state, **kwargs)
@@ -120,12 +120,12 @@ class WebApplicationClient(Client):
>>> client.prepare_request_body(code='sh35ksdf09sf', foo='bar')
'grant_type=authorization_code&code=sh35ksdf09sf&foo=bar'
- .. _`Section 4.1.1`: http://tools.ietf.org/html/rfc6749#section-4.1.1
- .. _`Section 3.2.1`: http://tools.ietf.org/html/rfc6749#section-3.2.1
+ .. _`Section 4.1.1`: https://tools.ietf.org/html/rfc6749#section-4.1.1
+ .. _`Section 3.2.1`: https://tools.ietf.org/html/rfc6749#section-3.2.1
"""
code = code or self.code
return prepare_token_request('authorization_code', code=code, body=body,
- client_id=self.client_id, redirect_uri=redirect_uri, **kwargs)
+ client_id=client_id, redirect_uri=redirect_uri, **kwargs)
def parse_request_uri_response(self, uri, state=None):
"""Parse the URI query for code and state.
@@ -172,5 +172,5 @@ class WebApplicationClient(Client):
oauthlib.oauth2.rfc6749.errors.MismatchingStateError
"""
response = parse_authorization_code_response(uri, state=state)
- self._populate_attributes(response)
+ self.populate_code_attributes(response)
return response
diff --git a/oauthlib/oauth2/rfc6749/endpoints/authorization.py b/oauthlib/oauth2/rfc6749/endpoints/authorization.py
index b6e0734..92cde34 100644
--- a/oauthlib/oauth2/rfc6749/endpoints/authorization.py
+++ b/oauthlib/oauth2/rfc6749/endpoints/authorization.py
@@ -59,7 +59,7 @@ class AuthorizationEndpoint(BaseEndpoint):
# Enforced through the design of oauthlib.common.Request
- .. _`Appendix B`: http://tools.ietf.org/html/rfc6749#appendix-B
+ .. _`Appendix B`: https://tools.ietf.org/html/rfc6749#appendix-B
"""
def __init__(self, default_response_type, default_token_type,
diff --git a/oauthlib/oauth2/rfc6749/endpoints/pre_configured.py b/oauthlib/oauth2/rfc6749/endpoints/pre_configured.py
index 378339a..66af516 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 .introspect import IntrospectEndpoint
from .resource import ResourceEndpoint
@@ -58,6 +58,9 @@ class Server(AuthorizationEndpoint, IntrospectEndpoint, TokenEndpoint,
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)
@@ -87,7 +90,7 @@ class Server(AuthorizationEndpoint, IntrospectEndpoint, TokenEndpoint,
},
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)
IntrospectEndpoint.__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/endpoints/revocation.py b/oauthlib/oauth2/rfc6749/endpoints/revocation.py
index 4364b81..d5b5b78 100644
--- a/oauthlib/oauth2/rfc6749/endpoints/revocation.py
+++ b/oauthlib/oauth2/rfc6749/endpoints/revocation.py
@@ -5,7 +5,7 @@ oauthlib.oauth2.rfc6749.endpoint.revocation
An implementation of the OAuth 2 `Token Revocation`_ spec (draft 11).
-.. _`Token Revocation`: http://tools.ietf.org/html/draft-ietf-oauth-revocation-11
+.. _`Token Revocation`: https://tools.ietf.org/html/draft-ietf-oauth-revocation-11
"""
from __future__ import absolute_import, unicode_literals
@@ -110,11 +110,11 @@ class RevocationEndpoint(BaseEndpoint):
The client also includes its authentication credentials as described in
`Section 2.3`_. of [`RFC6749`_].
- .. _`section 1.4`: http://tools.ietf.org/html/rfc6749#section-1.4
- .. _`section 1.5`: http://tools.ietf.org/html/rfc6749#section-1.5
- .. _`section 2.3`: http://tools.ietf.org/html/rfc6749#section-2.3
- .. _`Section 4.1.2`: http://tools.ietf.org/html/draft-ietf-oauth-revocation-11#section-4.1.2
- .. _`RFC6749`: http://tools.ietf.org/html/rfc6749
+ .. _`section 1.4`: https://tools.ietf.org/html/rfc6749#section-1.4
+ .. _`section 1.5`: https://tools.ietf.org/html/rfc6749#section-1.5
+ .. _`section 2.3`: https://tools.ietf.org/html/rfc6749#section-2.3
+ .. _`Section 4.1.2`: https://tools.ietf.org/html/draft-ietf-oauth-revocation-11#section-4.1.2
+ .. _`RFC6749`: https://tools.ietf.org/html/rfc6749
"""
if not request.token:
raise InvalidRequestError(request=request,
diff --git a/oauthlib/oauth2/rfc6749/endpoints/token.py b/oauthlib/oauth2/rfc6749/endpoints/token.py
index ece6325..90fb16f 100644
--- a/oauthlib/oauth2/rfc6749/endpoints/token.py
+++ b/oauthlib/oauth2/rfc6749/endpoints/token.py
@@ -59,7 +59,7 @@ class TokenEndpoint(BaseEndpoint):
# Delegated to each grant type.
- .. _`Appendix B`: http://tools.ietf.org/html/rfc6749#appendix-B
+ .. _`Appendix B`: https://tools.ietf.org/html/rfc6749#appendix-B
"""
def __init__(self, default_grant_type, default_token_type, grant_types):
diff --git a/oauthlib/oauth2/rfc6749/grant_types/authorization_code.py b/oauthlib/oauth2/rfc6749/grant_types/authorization_code.py
index 8661c35..0660263 100644
--- a/oauthlib/oauth2/rfc6749/grant_types/authorization_code.py
+++ b/oauthlib/oauth2/rfc6749/grant_types/authorization_code.py
@@ -91,7 +91,7 @@ class AuthorizationCodeGrant(GrantTypeBase):
step (C). If valid, the authorization server responds back with
an access token and, optionally, a refresh token.
- .. _`Authorization Code Grant`: http://tools.ietf.org/html/rfc6749#section-4.1
+ .. _`Authorization Code Grant`: https://tools.ietf.org/html/rfc6749#section-4.1
"""
default_response_mode = 'query'
@@ -175,11 +175,11 @@ class AuthorizationCodeGrant(GrantTypeBase):
File "oauthlib/oauth2/rfc6749/grant_types.py", line 591, in validate_authorization_request
oauthlib.oauth2.rfc6749.errors.InvalidClientIdError
- .. _`Appendix B`: http://tools.ietf.org/html/rfc6749#appendix-B
- .. _`Section 2.2`: http://tools.ietf.org/html/rfc6749#section-2.2
- .. _`Section 3.1.2`: http://tools.ietf.org/html/rfc6749#section-3.1.2
- .. _`Section 3.3`: http://tools.ietf.org/html/rfc6749#section-3.3
- .. _`Section 10.12`: http://tools.ietf.org/html/rfc6749#section-10.12
+ .. _`Appendix B`: https://tools.ietf.org/html/rfc6749#appendix-B
+ .. _`Section 2.2`: https://tools.ietf.org/html/rfc6749#section-2.2
+ .. _`Section 3.1.2`: https://tools.ietf.org/html/rfc6749#section-3.1.2
+ .. _`Section 3.3`: https://tools.ietf.org/html/rfc6749#section-3.3
+ .. _`Section 10.12`: https://tools.ietf.org/html/rfc6749#section-10.12
"""
try:
# request.scopes is only mandated in post auth and both pre and
@@ -206,7 +206,7 @@ class AuthorizationCodeGrant(GrantTypeBase):
# the authorization server informs the client by adding the following
# parameters to the query component of the redirection URI using the
# "application/x-www-form-urlencoded" format, per Appendix B:
- # http://tools.ietf.org/html/rfc6749#appendix-B
+ # https://tools.ietf.org/html/rfc6749#appendix-B
except errors.OAuth2Error as e:
log.debug('Client error during validation of %r. %r.', request, e)
request.redirect_uri = request.redirect_uri or self.error_uri
@@ -285,7 +285,7 @@ class AuthorizationCodeGrant(GrantTypeBase):
raise errors.InvalidRequestFatalError(description='Duplicate %s parameter.' % param, request=request)
# REQUIRED. The client identifier as described in Section 2.2.
- # http://tools.ietf.org/html/rfc6749#section-2.2
+ # https://tools.ietf.org/html/rfc6749#section-2.2
if not request.client_id:
raise errors.MissingClientIdError(request=request)
@@ -293,7 +293,7 @@ class AuthorizationCodeGrant(GrantTypeBase):
raise errors.InvalidClientIdError(request=request)
# OPTIONAL. As described in Section 3.1.2.
- # http://tools.ietf.org/html/rfc6749#section-3.1.2
+ # https://tools.ietf.org/html/rfc6749#section-3.1.2
log.debug('Validating redirection uri %s for client %s.',
request.redirect_uri, request.client_id)
if request.redirect_uri is not None:
@@ -320,7 +320,7 @@ class AuthorizationCodeGrant(GrantTypeBase):
# the authorization server informs the client by adding the following
# parameters to the query component of the redirection URI using the
# "application/x-www-form-urlencoded" format, per Appendix B.
- # http://tools.ietf.org/html/rfc6749#appendix-B
+ # https://tools.ietf.org/html/rfc6749#appendix-B
# Note that the correct parameters to be added are automatically
# populated through the use of specific exceptions.
@@ -346,7 +346,7 @@ class AuthorizationCodeGrant(GrantTypeBase):
raise errors.UnauthorizedClientError(request=request)
# OPTIONAL. The scope of the access request as described by Section 3.3
- # http://tools.ietf.org/html/rfc6749#section-3.3
+ # https://tools.ietf.org/html/rfc6749#section-3.3
self.validate_scopes(request)
request_info.update({
@@ -384,14 +384,14 @@ class AuthorizationCodeGrant(GrantTypeBase):
# credentials (or assigned other authentication requirements), the
# client MUST authenticate with the authorization server as described
# in Section 3.2.1.
- # http://tools.ietf.org/html/rfc6749#section-3.2.1
+ # https://tools.ietf.org/html/rfc6749#section-3.2.1
if not self.request_validator.authenticate_client(request):
log.debug('Client authentication failed, %r.', request)
raise errors.InvalidClientError(request=request)
elif not self.request_validator.authenticate_client_id(request.client_id, request):
# REQUIRED, if the client is not authenticating with the
# authorization server as described in Section 3.2.1.
- # http://tools.ietf.org/html/rfc6749#section-3.2.1
+ # https://tools.ietf.org/html/rfc6749#section-3.2.1
log.debug('Client authentication failed, %r.', request)
raise errors.InvalidClientError(request=request)
@@ -421,7 +421,8 @@ class AuthorizationCodeGrant(GrantTypeBase):
# authorization request as described in Section 4.1.1, and their
# values MUST be identical.
if not self.request_validator.confirm_redirect_uri(request.client_id, request.code,
- request.redirect_uri, request.client):
+ request.redirect_uri, request.client,
+ request):
log.debug('Redirect_uri (%r) invalid for client %r (%r).',
request.redirect_uri, request.client_id, request.client)
raise errors.MismatchingRedirectURIError(request=request)
diff --git a/oauthlib/oauth2/rfc6749/grant_types/client_credentials.py b/oauthlib/oauth2/rfc6749/grant_types/client_credentials.py
index bf6c87f..4c50a78 100644
--- a/oauthlib/oauth2/rfc6749/grant_types/client_credentials.py
+++ b/oauthlib/oauth2/rfc6749/grant_types/client_credentials.py
@@ -47,7 +47,7 @@ class ClientCredentialsGrant(GrantTypeBase):
(B) The authorization server authenticates the client, and if valid,
issues an access token.
- .. _`Client Credentials Grant`: http://tools.ietf.org/html/rfc6749#section-4.4
+ .. _`Client Credentials Grant`: https://tools.ietf.org/html/rfc6749#section-4.4
"""
def create_token_response(self, request, token_handler):
@@ -59,8 +59,8 @@ class ClientCredentialsGrant(GrantTypeBase):
failed client authentication or is invalid, the authorization server
returns an error response as described in `Section 5.2`_.
- .. _`Section 5.1`: http://tools.ietf.org/html/rfc6749#section-5.1
- .. _`Section 5.2`: http://tools.ietf.org/html/rfc6749#section-5.2
+ .. _`Section 5.1`: https://tools.ietf.org/html/rfc6749#section-5.1
+ .. _`Section 5.2`: https://tools.ietf.org/html/rfc6749#section-5.2
"""
headers = {
'Content-Type': 'application/json',
diff --git a/oauthlib/oauth2/rfc6749/grant_types/implicit.py b/oauthlib/oauth2/rfc6749/grant_types/implicit.py
index 2b9c49d..bdab814 100644
--- a/oauthlib/oauth2/rfc6749/grant_types/implicit.py
+++ b/oauthlib/oauth2/rfc6749/grant_types/implicit.py
@@ -111,9 +111,9 @@ class ImplicitGrant(GrantTypeBase):
See `Section 10.3`_ and `Section 10.16`_ for important security considerations
when using the implicit grant.
- .. _`Implicit Grant`: http://tools.ietf.org/html/rfc6749#section-4.2
- .. _`Section 10.3`: http://tools.ietf.org/html/rfc6749#section-10.3
- .. _`Section 10.16`: http://tools.ietf.org/html/rfc6749#section-10.16
+ .. _`Implicit Grant`: https://tools.ietf.org/html/rfc6749#section-4.2
+ .. _`Section 10.3`: https://tools.ietf.org/html/rfc6749#section-10.3
+ .. _`Section 10.16`: https://tools.ietf.org/html/rfc6749#section-10.16
"""
response_types = ['token']
@@ -152,11 +152,11 @@ class ImplicitGrant(GrantTypeBase):
access token matches a redirection URI registered by the client as
described in `Section 3.1.2`_.
- .. _`Section 2.2`: http://tools.ietf.org/html/rfc6749#section-2.2
- .. _`Section 3.1.2`: http://tools.ietf.org/html/rfc6749#section-3.1.2
- .. _`Section 3.3`: http://tools.ietf.org/html/rfc6749#section-3.3
- .. _`Section 10.12`: http://tools.ietf.org/html/rfc6749#section-10.12
- .. _`Appendix B`: http://tools.ietf.org/html/rfc6749#appendix-B
+ .. _`Section 2.2`: https://tools.ietf.org/html/rfc6749#section-2.2
+ .. _`Section 3.1.2`: https://tools.ietf.org/html/rfc6749#section-3.1.2
+ .. _`Section 3.3`: https://tools.ietf.org/html/rfc6749#section-3.3
+ .. _`Section 10.12`: https://tools.ietf.org/html/rfc6749#section-10.12
+ .. _`Appendix B`: https://tools.ietf.org/html/rfc6749#appendix-B
"""
return self.create_token_response(request, token_handler)
@@ -195,9 +195,9 @@ class ImplicitGrant(GrantTypeBase):
The authorization server MUST NOT issue a refresh token.
- .. _`Appendix B`: http://tools.ietf.org/html/rfc6749#appendix-B
- .. _`Section 3.3`: http://tools.ietf.org/html/rfc6749#section-3.3
- .. _`Section 7.1`: http://tools.ietf.org/html/rfc6749#section-7.1
+ .. _`Appendix B`: https://tools.ietf.org/html/rfc6749#appendix-B
+ .. _`Section 3.3`: https://tools.ietf.org/html/rfc6749#section-3.3
+ .. _`Section 7.1`: https://tools.ietf.org/html/rfc6749#section-7.1
"""
try:
# request.scopes is only mandated in post auth and both pre and
@@ -222,7 +222,7 @@ class ImplicitGrant(GrantTypeBase):
# the authorization server informs the client by adding the following
# parameters to the fragment component of the redirection URI using the
# "application/x-www-form-urlencoded" format, per Appendix B:
- # http://tools.ietf.org/html/rfc6749#appendix-B
+ # https://tools.ietf.org/html/rfc6749#appendix-B
except errors.OAuth2Error as e:
log.debug('Client error during validation of %r. %r.', request, e)
return {'Location': common.add_params_to_uri(request.redirect_uri, e.twotuples,
@@ -285,7 +285,7 @@ class ImplicitGrant(GrantTypeBase):
raise errors.InvalidRequestFatalError(description='Duplicate %s parameter.' % param, request=request)
# REQUIRED. The client identifier as described in Section 2.2.
- # http://tools.ietf.org/html/rfc6749#section-2.2
+ # https://tools.ietf.org/html/rfc6749#section-2.2
if not request.client_id:
raise errors.MissingClientIdError(request=request)
@@ -293,7 +293,7 @@ class ImplicitGrant(GrantTypeBase):
raise errors.InvalidClientIdError(request=request)
# OPTIONAL. As described in Section 3.1.2.
- # http://tools.ietf.org/html/rfc6749#section-3.1.2
+ # https://tools.ietf.org/html/rfc6749#section-3.1.2
if request.redirect_uri is not None:
request.using_default_redirect_uri = False
log.debug('Using provided redirect_uri %s', request.redirect_uri)
@@ -304,7 +304,7 @@ class ImplicitGrant(GrantTypeBase):
# to which it will redirect the access token matches a
# redirection URI registered by the client as described in
# Section 3.1.2.
- # http://tools.ietf.org/html/rfc6749#section-3.1.2
+ # https://tools.ietf.org/html/rfc6749#section-3.1.2
if not self.request_validator.validate_redirect_uri(
request.client_id, request.redirect_uri, request):
raise errors.MismatchingRedirectURIError(request=request)
@@ -328,7 +328,7 @@ class ImplicitGrant(GrantTypeBase):
# the authorization server informs the client by adding the following
# parameters to the fragment component of the redirection URI using the
# "application/x-www-form-urlencoded" format, per Appendix B.
- # http://tools.ietf.org/html/rfc6749#appendix-B
+ # https://tools.ietf.org/html/rfc6749#appendix-B
# Note that the correct parameters to be added are automatically
# populated through the use of specific exceptions
@@ -351,7 +351,7 @@ class ImplicitGrant(GrantTypeBase):
raise errors.UnauthorizedClientError(request=request)
# OPTIONAL. The scope of the access request as described by Section 3.3
- # http://tools.ietf.org/html/rfc6749#section-3.3
+ # https://tools.ietf.org/html/rfc6749#section-3.3
self.validate_scopes(request)
request_info.update({
diff --git a/oauthlib/oauth2/rfc6749/grant_types/refresh_token.py b/oauthlib/oauth2/rfc6749/grant_types/refresh_token.py
index 6233e7c..c2d86f7 100644
--- a/oauthlib/oauth2/rfc6749/grant_types/refresh_token.py
+++ b/oauthlib/oauth2/rfc6749/grant_types/refresh_token.py
@@ -19,7 +19,7 @@ class RefreshTokenGrant(GrantTypeBase):
"""`Refresh token grant`_
- .. _`Refresh token grant`: http://tools.ietf.org/html/rfc6749#section-6
+ .. _`Refresh token grant`: https://tools.ietf.org/html/rfc6749#section-6
"""
def __init__(self, request_validator=None,
@@ -46,8 +46,8 @@ class RefreshTokenGrant(GrantTypeBase):
identical to that of the refresh token included by the client in the
request.
- .. _`Section 5.1`: http://tools.ietf.org/html/rfc6749#section-5.1
- .. _`Section 5.2`: http://tools.ietf.org/html/rfc6749#section-5.2
+ .. _`Section 5.1`: https://tools.ietf.org/html/rfc6749#section-5.1
+ .. _`Section 5.2`: https://tools.ietf.org/html/rfc6749#section-5.2
"""
headers = {
'Content-Type': 'application/json',
@@ -90,7 +90,7 @@ class RefreshTokenGrant(GrantTypeBase):
# the client was issued client credentials (or assigned other
# authentication requirements), the client MUST authenticate with the
# authorization server as described in Section 3.2.1.
- # http://tools.ietf.org/html/rfc6749#section-3.2.1
+ # https://tools.ietf.org/html/rfc6749#section-3.2.1
if self.request_validator.client_authentication_required(request):
log.debug('Authenticating client, %r.', request)
if not self.request_validator.authenticate_client(request):
diff --git a/oauthlib/oauth2/rfc6749/grant_types/resource_owner_password_credentials.py b/oauthlib/oauth2/rfc6749/grant_types/resource_owner_password_credentials.py
index ede779a..e5f04af 100644
--- a/oauthlib/oauth2/rfc6749/grant_types/resource_owner_password_credentials.py
+++ b/oauthlib/oauth2/rfc6749/grant_types/resource_owner_password_credentials.py
@@ -67,7 +67,7 @@ class ResourceOwnerPasswordCredentialsGrant(GrantTypeBase):
the resource owner credentials, and if valid, issues an access
token.
- .. _`Resource Owner Password Credentials Grant`: http://tools.ietf.org/html/rfc6749#section-4.3
+ .. _`Resource Owner Password Credentials Grant`: https://tools.ietf.org/html/rfc6749#section-4.3
"""
def create_token_response(self, request, token_handler):
@@ -79,8 +79,8 @@ class ResourceOwnerPasswordCredentialsGrant(GrantTypeBase):
authentication or is invalid, the authorization server returns an
error response as described in `Section 5.2`_.
- .. _`Section 5.1`: http://tools.ietf.org/html/rfc6749#section-5.1
- .. _`Section 5.2`: http://tools.ietf.org/html/rfc6749#section-5.2
+ .. _`Section 5.1`: https://tools.ietf.org/html/rfc6749#section-5.1
+ .. _`Section 5.2`: https://tools.ietf.org/html/rfc6749#section-5.2
"""
headers = {
'Content-Type': 'application/json',
@@ -153,8 +153,8 @@ class ResourceOwnerPasswordCredentialsGrant(GrantTypeBase):
brute force attacks (e.g., using rate-limitation or generating
alerts).
- .. _`Section 3.3`: http://tools.ietf.org/html/rfc6749#section-3.3
- .. _`Section 3.2.1`: http://tools.ietf.org/html/rfc6749#section-3.2.1
+ .. _`Section 3.3`: https://tools.ietf.org/html/rfc6749#section-3.3
+ .. _`Section 3.2.1`: https://tools.ietf.org/html/rfc6749#section-3.2.1
"""
for validator in self.custom_validators.pre_token:
validator(request)
diff --git a/oauthlib/oauth2/rfc6749/parameters.py b/oauthlib/oauth2/rfc6749/parameters.py
index b87b146..0107933 100644
--- a/oauthlib/oauth2/rfc6749/parameters.py
+++ b/oauthlib/oauth2/rfc6749/parameters.py
@@ -5,7 +5,7 @@ oauthlib.oauth2.rfc6749.parameters
This module contains methods related to `Section 4`_ of the OAuth 2 RFC.
-.. _`Section 4`: http://tools.ietf.org/html/rfc6749#section-4
+.. _`Section 4`: https://tools.ietf.org/html/rfc6749#section-4
"""
from __future__ import absolute_import, unicode_literals
@@ -61,11 +61,11 @@ def prepare_grant_uri(uri, client_id, response_type, redirect_uri=None,
&redirect_uri=https%3A%2F%2Fclient%2Eexample%2Ecom%2Fcb HTTP/1.1
Host: server.example.com
- .. _`W3C.REC-html401-19991224`: http://tools.ietf.org/html/rfc6749#ref-W3C.REC-html401-19991224
- .. _`Section 2.2`: http://tools.ietf.org/html/rfc6749#section-2.2
- .. _`Section 3.1.2`: http://tools.ietf.org/html/rfc6749#section-3.1.2
- .. _`Section 3.3`: http://tools.ietf.org/html/rfc6749#section-3.3
- .. _`section 10.12`: http://tools.ietf.org/html/rfc6749#section-10.12
+ .. _`W3C.REC-html401-19991224`: https://tools.ietf.org/html/rfc6749#ref-W3C.REC-html401-19991224
+ .. _`Section 2.2`: https://tools.ietf.org/html/rfc6749#section-2.2
+ .. _`Section 3.1.2`: https://tools.ietf.org/html/rfc6749#section-3.1.2
+ .. _`Section 3.3`: https://tools.ietf.org/html/rfc6749#section-3.3
+ .. _`section 10.12`: https://tools.ietf.org/html/rfc6749#section-10.12
"""
if not is_secure_transport(uri):
raise InsecureTransportError()
@@ -111,7 +111,7 @@ def prepare_token_request(grant_type, body='', **kwargs):
grant_type=authorization_code&code=SplxlOBeZQQYbYS6WxSbIA
&redirect_uri=https%3A%2F%2Fclient%2Eexample%2Ecom%2Fcb
- .. _`Section 4.1.1`: http://tools.ietf.org/html/rfc6749#section-4.1.1
+ .. _`Section 4.1.1`: https://tools.ietf.org/html/rfc6749#section-4.1.1
"""
params = [('grant_type', grant_type)]
@@ -153,9 +153,9 @@ def prepare_token_revocation_request(url, token, token_type_hint="access_token",
specification MAY define other values for this parameter using the
registry defined in `Section 4.1.2`_.
- .. _`Section 1.4`: http://tools.ietf.org/html/rfc6749#section-1.4
- .. _`Section 1.5`: http://tools.ietf.org/html/rfc6749#section-1.5
- .. _`Section 4.1.2`: http://tools.ietf.org/html/rfc7009#section-4.1.2
+ .. _`Section 1.4`: https://tools.ietf.org/html/rfc6749#section-1.4
+ .. _`Section 1.5`: https://tools.ietf.org/html/rfc6749#section-1.5
+ .. _`Section 4.1.2`: https://tools.ietf.org/html/rfc7009#section-4.1.2
"""
if not is_secure_transport(url):
@@ -348,10 +348,10 @@ def parse_token_response(body, scope=None):
"example_parameter":"example_value"
}
- .. _`Section 7.1`: http://tools.ietf.org/html/rfc6749#section-7.1
- .. _`Section 6`: http://tools.ietf.org/html/rfc6749#section-6
- .. _`Section 3.3`: http://tools.ietf.org/html/rfc6749#section-3.3
- .. _`RFC4627`: http://tools.ietf.org/html/rfc4627
+ .. _`Section 7.1`: https://tools.ietf.org/html/rfc6749#section-7.1
+ .. _`Section 6`: https://tools.ietf.org/html/rfc6749#section-6
+ .. _`Section 3.3`: https://tools.ietf.org/html/rfc6749#section-3.3
+ .. _`RFC4627`: https://tools.ietf.org/html/rfc4627
"""
try:
params = json.loads(body)
@@ -359,7 +359,7 @@ def parse_token_response(body, scope=None):
# Fall back to URL-encoded string, to support old implementations,
# including (at time of writing) Facebook. See:
- # https://github.com/idan/oauthlib/issues/267
+ # https://github.com/oauthlib/oauthlib/issues/267
params = dict(urlparse.parse_qsl(body))
for key in ('expires_in', 'expires'):
@@ -395,7 +395,7 @@ def validate_token_parameters(params):
# If the issued access token scope is different from the one requested by
# the client, the authorization server MUST include the "scope" response
# parameter to inform the client of the actual scope granted.
- # http://tools.ietf.org/html/rfc6749#section-3.3
+ # https://tools.ietf.org/html/rfc6749#section-3.3
if params.scope_changed:
message = 'Scope has changed from "{old}" to "{new}".'.format(
old=params.old_scope, new=params.scope,
diff --git a/oauthlib/oauth2/rfc6749/request_validator.py b/oauthlib/oauth2/rfc6749/request_validator.py
index 4b76b7a..56ecc3d 100644
--- a/oauthlib/oauth2/rfc6749/request_validator.py
+++ b/oauthlib/oauth2/rfc6749/request_validator.py
@@ -34,9 +34,9 @@ class RequestValidator(object):
- Resource Owner Password Credentials Grant
- Refresh Token Grant
- .. _`Section 4.3.2`: http://tools.ietf.org/html/rfc6749#section-4.3.2
- .. _`Section 4.1.3`: http://tools.ietf.org/html/rfc6749#section-4.1.3
- .. _`Section 6`: http://tools.ietf.org/html/rfc6749#section-6
+ .. _`Section 4.3.2`: https://tools.ietf.org/html/rfc6749#section-4.3.2
+ .. _`Section 4.1.3`: https://tools.ietf.org/html/rfc6749#section-4.1.3
+ .. _`Section 6`: https://tools.ietf.org/html/rfc6749#section-6
"""
return True
@@ -60,7 +60,7 @@ class RequestValidator(object):
- Client Credentials Grant
- Refresh Token Grant
- .. _`HTTP Basic Authentication Scheme`: http://tools.ietf.org/html/rfc1945#section-11.1
+ .. _`HTTP Basic Authentication Scheme`: https://tools.ietf.org/html/rfc1945#section-11.1
"""
raise NotImplementedError('Subclasses must implement this method.')
@@ -82,7 +82,7 @@ class RequestValidator(object):
"""
raise NotImplementedError('Subclasses must implement this method.')
- def confirm_redirect_uri(self, client_id, code, redirect_uri, client,
+ def confirm_redirect_uri(self, client_id, code, redirect_uri, client, request,
*args, **kwargs):
"""Ensure that the authorization process represented by this authorization
code began with this 'redirect_uri'.
@@ -352,8 +352,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.
@@ -384,6 +400,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..a7491f4 100644
--- a/oauthlib/oauth2/rfc6749/tokens.py
+++ b/oauthlib/oauth2/rfc6749/tokens.py
@@ -4,8 +4,8 @@ oauthlib.oauth2.rfc6749.tokens
This module contains methods for adding two types of access tokens to requests.
-- Bearer http://tools.ietf.org/html/rfc6750
-- MAC http://tools.ietf.org/html/draft-ietf-oauth-v2-http-mac-01
+- Bearer https://tools.ietf.org/html/rfc6750
+- MAC https://tools.ietf.org/html/draft-ietf-oauth-v2-http-mac-01
"""
from __future__ import absolute_import, unicode_literals
@@ -24,8 +24,6 @@ except ImportError:
from urllib.parse import urlparse
-
-
class OAuth2Token(dict):
def __init__(self, params, old_scope=None):
@@ -95,8 +93,8 @@ def prepare_mac_header(token, uri, key, http_method,
nonce="1336363200:dj83hs9s",
mac="bhCQXTVyfj5cmA9uKkPFx1zeOXM="
- .. _`MAC Access Authentication`: http://tools.ietf.org/html/draft-ietf-oauth-v2-http-mac-01
- .. _`extension algorithms`: http://tools.ietf.org/html/draft-ietf-oauth-v2-http-mac-01#section-7.1
+ .. _`MAC Access Authentication`: https://tools.ietf.org/html/draft-ietf-oauth-v2-http-mac-01
+ .. _`extension algorithms`: https://tools.ietf.org/html/draft-ietf-oauth-v2-http-mac-01#section-7.1
:param uri: Request URI.
:param headers: Request headers as a dictionary.
@@ -182,7 +180,7 @@ def prepare_bearer_uri(token, uri):
http://www.example.com/path?access_token=h480djs93hd8
- .. _`Bearer Token`: http://tools.ietf.org/html/rfc6750
+ .. _`Bearer Token`: https://tools.ietf.org/html/rfc6750
"""
return add_params_to_uri(uri, [(('access_token', token))])
@@ -193,7 +191,7 @@ def prepare_bearer_headers(token, headers=None):
Authorization: Bearer h480djs93hd8
- .. _`Bearer Token`: http://tools.ietf.org/html/rfc6750
+ .. _`Bearer Token`: https://tools.ietf.org/html/rfc6750
"""
headers = headers or {}
headers['Authorization'] = 'Bearer %s' % token
@@ -205,7 +203,7 @@ def prepare_bearer_body(token, body=''):
access_token=h480djs93hd8
- .. _`Bearer Token`: http://tools.ietf.org/html/rfc6750
+ .. _`Bearer Token`: https://tools.ietf.org/html/rfc6750
"""
return add_params_to_qs(body, [(('access_token', token))])
@@ -222,6 +220,24 @@ def signed_token_generator(private_pem, **kwargs):
return signed_token_generator
+def get_token_from_header(request):
+ """
+ Helper function to extract a token from the request header.
+ :param request: The request object
+ :return: Return the token or None if the Authorization header is malformed.
+ """
+ token = None
+
+ if 'Authorization' in request.headers:
+ split_header = request.headers.get('Authorization').split()
+ if len(split_header) == 2 and split_header[0] == 'Bearer':
+ token = split_header[1]
+ else:
+ token = request.access_token
+
+ return token
+
+
class TokenBase(object):
def __call__(self, request, refresh_token=False):
@@ -288,18 +304,54 @@ class BearerToken(TokenBase):
return token
def validate_request(self, request):
- token = None
- if 'Authorization' in request.headers:
- token = request.headers.get('Authorization')[7:]
- else:
- token = request.access_token
+ token = get_token_from_header(request)
return self.request_validator.validate_bearer_token(
token, request.scopes, request)
def estimate_type(self, request):
- if request.headers.get('Authorization', '').startswith('Bearer'):
+ if request.headers.get('Authorization', '').split(' ')[0] == 'Bearer':
return 9
elif request.access_token is not None:
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