Integrated my history into data
This commit is contained in:
@@ -0,0 +1,19 @@
|
||||
# -*- coding: utf-8 -*-
|
||||
"""
|
||||
oauthlib.oauth2.rfc6749
|
||||
~~~~~~~~~~~~~~~~~~~~~~~
|
||||
|
||||
This module is an implementation of various logic needed
|
||||
for consuming and providing OAuth 2.0 RFC6749.
|
||||
"""
|
||||
from __future__ import absolute_import, unicode_literals
|
||||
|
||||
from .authorization import AuthorizationEndpoint
|
||||
from .token import TokenEndpoint
|
||||
from .resource import ResourceEndpoint
|
||||
from .revocation import RevocationEndpoint
|
||||
from .pre_configured import Server
|
||||
from .pre_configured import WebApplicationServer
|
||||
from .pre_configured import MobileApplicationServer
|
||||
from .pre_configured import LegacyApplicationServer
|
||||
from .pre_configured import BackendApplicationServer
|
||||
BIN
Binary file not shown.
BIN
Binary file not shown.
BIN
Binary file not shown.
BIN
Binary file not shown.
BIN
Binary file not shown.
BIN
Binary file not shown.
BIN
Binary file not shown.
@@ -0,0 +1,117 @@
|
||||
# -*- coding: utf-8 -*-
|
||||
"""
|
||||
oauthlib.oauth2.rfc6749
|
||||
~~~~~~~~~~~~~~~~~~~~~~~
|
||||
|
||||
This module is an implementation of various logic needed
|
||||
for consuming and providing OAuth 2.0 RFC6749.
|
||||
"""
|
||||
from __future__ import absolute_import, unicode_literals
|
||||
|
||||
import logging
|
||||
|
||||
from oauthlib.common import Request
|
||||
from oauthlib.oauth2.rfc6749 import utils
|
||||
|
||||
from .base import BaseEndpoint, catch_errors_and_unavailability
|
||||
|
||||
log = logging.getLogger(__name__)
|
||||
|
||||
|
||||
class AuthorizationEndpoint(BaseEndpoint):
|
||||
|
||||
"""Authorization endpoint - used by the client to obtain authorization
|
||||
from the resource owner via user-agent redirection.
|
||||
|
||||
The authorization endpoint is used to interact with the resource
|
||||
owner and obtain an authorization grant. The authorization server
|
||||
MUST first verify the identity of the resource owner. The way in
|
||||
which the authorization server authenticates the resource owner (e.g.
|
||||
username and password login, session cookies) is beyond the scope of
|
||||
this specification.
|
||||
|
||||
The endpoint URI MAY include an "application/x-www-form-urlencoded"
|
||||
formatted (per `Appendix B`_) query component,
|
||||
which MUST be retained when adding additional query parameters. The
|
||||
endpoint URI MUST NOT include a fragment component::
|
||||
|
||||
https://example.com/path?query=component # OK
|
||||
https://example.com/path?query=component#fragment # Not OK
|
||||
|
||||
Since requests to the authorization endpoint result in user
|
||||
authentication and the transmission of clear-text credentials (in the
|
||||
HTTP response), the authorization server MUST require the use of TLS
|
||||
as described in Section 1.6 when sending requests to the
|
||||
authorization endpoint::
|
||||
|
||||
# We will deny any request which URI schema is not with https
|
||||
|
||||
The authorization server MUST support the use of the HTTP "GET"
|
||||
method [RFC2616] for the authorization endpoint, and MAY support the
|
||||
use of the "POST" method as well::
|
||||
|
||||
# HTTP method is currently not enforced
|
||||
|
||||
Parameters sent without a value MUST be treated as if they were
|
||||
omitted from the request. The authorization server MUST ignore
|
||||
unrecognized request parameters. Request and response parameters
|
||||
MUST NOT be included more than once::
|
||||
|
||||
# Enforced through the design of oauthlib.common.Request
|
||||
|
||||
.. _`Appendix B`: http://tools.ietf.org/html/rfc6749#appendix-B
|
||||
"""
|
||||
|
||||
def __init__(self, default_response_type, default_token_type,
|
||||
response_types):
|
||||
BaseEndpoint.__init__(self)
|
||||
self._response_types = response_types
|
||||
self._default_response_type = default_response_type
|
||||
self._default_token_type = default_token_type
|
||||
|
||||
@property
|
||||
def response_types(self):
|
||||
return self._response_types
|
||||
|
||||
@property
|
||||
def default_response_type(self):
|
||||
return self._default_response_type
|
||||
|
||||
@property
|
||||
def default_response_type_handler(self):
|
||||
return self.response_types.get(self.default_response_type)
|
||||
|
||||
@property
|
||||
def default_token_type(self):
|
||||
return self._default_token_type
|
||||
|
||||
@catch_errors_and_unavailability
|
||||
def create_authorization_response(self, uri, http_method='GET', body=None,
|
||||
headers=None, scopes=None, credentials=None):
|
||||
"""Extract response_type and route to the designated handler."""
|
||||
request = Request(
|
||||
uri, http_method=http_method, body=body, headers=headers)
|
||||
request.scopes = scopes
|
||||
# TODO: decide whether this should be a required argument
|
||||
request.user = None # TODO: explain this in docs
|
||||
for k, v in (credentials or {}).items():
|
||||
setattr(request, k, v)
|
||||
response_type_handler = self.response_types.get(
|
||||
request.response_type, self.default_response_type_handler)
|
||||
log.debug('Dispatching response_type %s request to %r.',
|
||||
request.response_type, response_type_handler)
|
||||
return response_type_handler.create_authorization_response(
|
||||
request, self.default_token_type)
|
||||
|
||||
@catch_errors_and_unavailability
|
||||
def validate_authorization_request(self, uri, http_method='GET', body=None,
|
||||
headers=None):
|
||||
"""Extract response_type and route to the designated handler."""
|
||||
request = Request(
|
||||
uri, http_method=http_method, body=body, headers=headers)
|
||||
|
||||
request.scopes = utils.scope_to_list(request.scope)
|
||||
|
||||
response_type_handler = self.response_types.get(
|
||||
request.response_type, self.default_response_type_handler)
|
||||
return response_type_handler.validate_authorization_request(request)
|
||||
@@ -0,0 +1,65 @@
|
||||
# -*- coding: utf-8 -*-
|
||||
"""
|
||||
oauthlib.oauth2.rfc6749
|
||||
~~~~~~~~~~~~~~~~~~~~~~~
|
||||
|
||||
This module is an implementation of various logic needed
|
||||
for consuming and providing OAuth 2.0 RFC6749.
|
||||
"""
|
||||
from __future__ import absolute_import, unicode_literals
|
||||
|
||||
import functools
|
||||
import logging
|
||||
|
||||
from ..errors import (FatalClientError, OAuth2Error, ServerError,
|
||||
TemporarilyUnavailableError)
|
||||
|
||||
log = logging.getLogger(__name__)
|
||||
|
||||
|
||||
class BaseEndpoint(object):
|
||||
|
||||
def __init__(self):
|
||||
self._available = True
|
||||
self._catch_errors = False
|
||||
|
||||
@property
|
||||
def available(self):
|
||||
return self._available
|
||||
|
||||
@available.setter
|
||||
def available(self, available):
|
||||
self._available = available
|
||||
|
||||
@property
|
||||
def catch_errors(self):
|
||||
return self._catch_errors
|
||||
|
||||
@catch_errors.setter
|
||||
def catch_errors(self, catch_errors):
|
||||
self._catch_errors = catch_errors
|
||||
|
||||
|
||||
def catch_errors_and_unavailability(f):
|
||||
@functools.wraps(f)
|
||||
def wrapper(endpoint, uri, *args, **kwargs):
|
||||
if not endpoint.available:
|
||||
e = TemporarilyUnavailableError()
|
||||
log.info('Endpoint unavailable, ignoring request %s.' % uri)
|
||||
return {}, e.json, 503
|
||||
|
||||
if endpoint.catch_errors:
|
||||
try:
|
||||
return f(endpoint, uri, *args, **kwargs)
|
||||
except OAuth2Error:
|
||||
raise
|
||||
except FatalClientError:
|
||||
raise
|
||||
except Exception as e:
|
||||
error = ServerError()
|
||||
log.warning(
|
||||
'Exception caught while processing request, %s.' % e)
|
||||
return {}, error.json, 500
|
||||
else:
|
||||
return f(endpoint, uri, *args, **kwargs)
|
||||
return wrapper
|
||||
@@ -0,0 +1,223 @@
|
||||
# -*- coding: utf-8 -*-
|
||||
"""
|
||||
oauthlib.oauth2.rfc6749
|
||||
~~~~~~~~~~~~~~~~~~~~~~~
|
||||
|
||||
This module is an implementation of various logic needed
|
||||
for consuming and providing OAuth 2.0 RFC6749.
|
||||
"""
|
||||
from __future__ import absolute_import, unicode_literals
|
||||
|
||||
from ..grant_types import (AuthCodeGrantDispatcher, AuthorizationCodeGrant,
|
||||
ClientCredentialsGrant, ImplicitGrant,
|
||||
OpenIDConnectAuthCode, OpenIDConnectImplicit,
|
||||
RefreshTokenGrant,
|
||||
ResourceOwnerPasswordCredentialsGrant)
|
||||
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 = AuthorizationCodeGrant(request_validator)
|
||||
implicit_grant = ImplicitGrant(request_validator)
|
||||
password_grant = ResourceOwnerPasswordCredentialsGrant(
|
||||
request_validator)
|
||||
credentials_grant = ClientCredentialsGrant(request_validator)
|
||||
refresh_grant = RefreshTokenGrant(request_validator)
|
||||
openid_connect_auth = OpenIDConnectAuthCode(request_validator)
|
||||
openid_connect_implicit = OpenIDConnectImplicit(request_validator)
|
||||
|
||||
bearer = BearerToken(request_validator, token_generator,
|
||||
token_expires_in, refresh_token_generator)
|
||||
|
||||
auth_grant_choice = AuthCodeGrantDispatcher( default_auth_grant=auth_grant, oidc_auth_grant=openid_connect_auth)
|
||||
|
||||
# See http://openid.net/specs/oauth-v2-multiple-response-types-1_0.html#Combinations for valid combinations
|
||||
# internally our AuthorizationEndpoint will ensure they can appear in any order for any valid combination
|
||||
AuthorizationEndpoint.__init__(self, default_response_type='code',
|
||||
response_types={
|
||||
'code': auth_grant_choice,
|
||||
'token': implicit_grant,
|
||||
'id_token': openid_connect_implicit,
|
||||
'id_token token': openid_connect_implicit,
|
||||
'code token': openid_connect_auth,
|
||||
'code id_token': openid_connect_auth,
|
||||
'code token id_token': openid_connect_auth,
|
||||
'none': auth_grant
|
||||
},
|
||||
default_token_type=bearer)
|
||||
TokenEndpoint.__init__(self, default_grant_type='authorization_code',
|
||||
grant_types={
|
||||
'authorization_code': auth_grant,
|
||||
'password': password_grant,
|
||||
'client_credentials': credentials_grant,
|
||||
'refresh_token': refresh_grant,
|
||||
'openid': openid_connect_auth
|
||||
},
|
||||
default_token_type=bearer)
|
||||
ResourceEndpoint.__init__(self, default_token='Bearer',
|
||||
token_types={'Bearer': bearer})
|
||||
RevocationEndpoint.__init__(self, request_validator)
|
||||
|
||||
|
||||
class WebApplicationServer(AuthorizationEndpoint, TokenEndpoint, ResourceEndpoint,
|
||||
RevocationEndpoint):
|
||||
|
||||
"""An all-in-one endpoint featuring Authorization code grant and Bearer tokens."""
|
||||
|
||||
def __init__(self, request_validator, token_generator=None,
|
||||
token_expires_in=None, refresh_token_generator=None, **kwargs):
|
||||
"""Construct a new web application 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 = AuthorizationCodeGrant(request_validator)
|
||||
refresh_grant = RefreshTokenGrant(request_validator)
|
||||
bearer = BearerToken(request_validator, token_generator,
|
||||
token_expires_in, refresh_token_generator)
|
||||
AuthorizationEndpoint.__init__(self, default_response_type='code',
|
||||
response_types={'code': auth_grant},
|
||||
default_token_type=bearer)
|
||||
TokenEndpoint.__init__(self, default_grant_type='authorization_code',
|
||||
grant_types={
|
||||
'authorization_code': auth_grant,
|
||||
'refresh_token': refresh_grant,
|
||||
},
|
||||
default_token_type=bearer)
|
||||
ResourceEndpoint.__init__(self, default_token='Bearer',
|
||||
token_types={'Bearer': bearer})
|
||||
RevocationEndpoint.__init__(self, request_validator)
|
||||
|
||||
|
||||
class MobileApplicationServer(AuthorizationEndpoint, ResourceEndpoint,
|
||||
RevocationEndpoint):
|
||||
|
||||
"""An all-in-one endpoint featuring Implicit code grant and Bearer tokens."""
|
||||
|
||||
def __init__(self, request_validator, token_generator=None,
|
||||
token_expires_in=None, refresh_token_generator=None, **kwargs):
|
||||
"""Construct a new implicit grant 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.
|
||||
"""
|
||||
implicit_grant = ImplicitGrant(request_validator)
|
||||
bearer = BearerToken(request_validator, token_generator,
|
||||
token_expires_in, refresh_token_generator)
|
||||
AuthorizationEndpoint.__init__(self, default_response_type='token',
|
||||
response_types={
|
||||
'token': implicit_grant},
|
||||
default_token_type=bearer)
|
||||
ResourceEndpoint.__init__(self, default_token='Bearer',
|
||||
token_types={'Bearer': bearer})
|
||||
RevocationEndpoint.__init__(self, request_validator,
|
||||
supported_token_types=['access_token'])
|
||||
|
||||
|
||||
class LegacyApplicationServer(TokenEndpoint, ResourceEndpoint,
|
||||
RevocationEndpoint):
|
||||
|
||||
"""An all-in-one endpoint featuring Resource Owner Password Credentials grant and Bearer tokens."""
|
||||
|
||||
def __init__(self, request_validator, token_generator=None,
|
||||
token_expires_in=None, refresh_token_generator=None, **kwargs):
|
||||
"""Construct a resource owner password credentials grant 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.
|
||||
"""
|
||||
password_grant = ResourceOwnerPasswordCredentialsGrant(
|
||||
request_validator)
|
||||
refresh_grant = RefreshTokenGrant(request_validator)
|
||||
bearer = BearerToken(request_validator, token_generator,
|
||||
token_expires_in, refresh_token_generator)
|
||||
TokenEndpoint.__init__(self, default_grant_type='password',
|
||||
grant_types={
|
||||
'password': password_grant,
|
||||
'refresh_token': refresh_grant,
|
||||
},
|
||||
default_token_type=bearer)
|
||||
ResourceEndpoint.__init__(self, default_token='Bearer',
|
||||
token_types={'Bearer': bearer})
|
||||
RevocationEndpoint.__init__(self, request_validator)
|
||||
|
||||
|
||||
class BackendApplicationServer(TokenEndpoint, ResourceEndpoint,
|
||||
RevocationEndpoint):
|
||||
|
||||
"""An all-in-one endpoint featuring Client Credentials grant and Bearer tokens."""
|
||||
|
||||
def __init__(self, request_validator, token_generator=None,
|
||||
token_expires_in=None, refresh_token_generator=None, **kwargs):
|
||||
"""Construct a client credentials grant 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.
|
||||
"""
|
||||
credentials_grant = ClientCredentialsGrant(request_validator)
|
||||
bearer = BearerToken(request_validator, token_generator,
|
||||
token_expires_in, refresh_token_generator)
|
||||
TokenEndpoint.__init__(self, default_grant_type='client_credentials',
|
||||
grant_types={
|
||||
'client_credentials': credentials_grant},
|
||||
default_token_type=bearer)
|
||||
ResourceEndpoint.__init__(self, default_token='Bearer',
|
||||
token_types={'Bearer': bearer})
|
||||
RevocationEndpoint.__init__(self, request_validator,
|
||||
supported_token_types=['access_token'])
|
||||
@@ -0,0 +1,87 @@
|
||||
# -*- coding: utf-8 -*-
|
||||
"""
|
||||
oauthlib.oauth2.rfc6749
|
||||
~~~~~~~~~~~~~~~~~~~~~~~
|
||||
|
||||
This module is an implementation of various logic needed
|
||||
for consuming and providing OAuth 2.0 RFC6749.
|
||||
"""
|
||||
from __future__ import absolute_import, unicode_literals
|
||||
|
||||
import logging
|
||||
|
||||
from oauthlib.common import Request
|
||||
|
||||
from .base import BaseEndpoint, catch_errors_and_unavailability
|
||||
|
||||
log = logging.getLogger(__name__)
|
||||
|
||||
|
||||
class ResourceEndpoint(BaseEndpoint):
|
||||
|
||||
"""Authorizes access to protected resources.
|
||||
|
||||
The client accesses protected resources by presenting the access
|
||||
token to the resource server. The resource server MUST validate the
|
||||
access token and ensure that it has not expired and that its scope
|
||||
covers the requested resource. The methods used by the resource
|
||||
server to validate the access token (as well as any error responses)
|
||||
are beyond the scope of this specification but generally involve an
|
||||
interaction or coordination between the resource server and the
|
||||
authorization server::
|
||||
|
||||
# For most cases, returning a 403 should suffice.
|
||||
|
||||
The method in which the client utilizes the access token to
|
||||
authenticate with the resource server depends on the type of access
|
||||
token issued by the authorization server. Typically, it involves
|
||||
using the HTTP "Authorization" request header field [RFC2617] with an
|
||||
authentication scheme defined by the specification of the access
|
||||
token type used, such as [RFC6750]::
|
||||
|
||||
# Access tokens may also be provided in query and body
|
||||
https://example.com/protected?access_token=kjfch2345sdf # Query
|
||||
access_token=sdf23409df # Body
|
||||
"""
|
||||
|
||||
def __init__(self, default_token, token_types):
|
||||
BaseEndpoint.__init__(self)
|
||||
self._tokens = token_types
|
||||
self._default_token = default_token
|
||||
|
||||
@property
|
||||
def default_token(self):
|
||||
return self._default_token
|
||||
|
||||
@property
|
||||
def default_token_type_handler(self):
|
||||
return self.tokens.get(self.default_token)
|
||||
|
||||
@property
|
||||
def tokens(self):
|
||||
return self._tokens
|
||||
|
||||
@catch_errors_and_unavailability
|
||||
def verify_request(self, uri, http_method='GET', body=None, headers=None,
|
||||
scopes=None):
|
||||
"""Validate client, code etc, return body + headers"""
|
||||
request = Request(uri, http_method, body, headers)
|
||||
request.token_type = self.find_token_type(request)
|
||||
request.scopes = scopes
|
||||
token_type_handler = self.tokens.get(request.token_type,
|
||||
self.default_token_type_handler)
|
||||
log.debug('Dispatching token_type %s request to %r.',
|
||||
request.token_type, token_type_handler)
|
||||
return token_type_handler.validate_request(request), request
|
||||
|
||||
def find_token_type(self, request):
|
||||
"""Token type identification.
|
||||
|
||||
RFC 6749 does not provide a method for easily differentiating between
|
||||
different token types during protected resource access. We estimate
|
||||
the most likely token type (if any) by asking each known token type
|
||||
to give an estimation based on the request.
|
||||
"""
|
||||
estimates = sorted(((t.estimate_type(request), n)
|
||||
for n, t in self.tokens.items()))
|
||||
return estimates[0][1] if len(estimates) else None
|
||||
@@ -0,0 +1,134 @@
|
||||
# -*- coding: utf-8 -*-
|
||||
"""
|
||||
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
|
||||
"""
|
||||
from __future__ import absolute_import, unicode_literals
|
||||
|
||||
import logging
|
||||
|
||||
from oauthlib.common import Request
|
||||
|
||||
from ..errors import (InvalidClientError, InvalidRequestError, OAuth2Error,
|
||||
UnsupportedTokenTypeError)
|
||||
from .base import BaseEndpoint, catch_errors_and_unavailability
|
||||
|
||||
log = logging.getLogger(__name__)
|
||||
|
||||
|
||||
class RevocationEndpoint(BaseEndpoint):
|
||||
|
||||
"""Token revocation endpoint.
|
||||
|
||||
Endpoint used by authenticated clients to revoke access and refresh tokens.
|
||||
Commonly this will be part of the Authorization Endpoint.
|
||||
"""
|
||||
|
||||
valid_token_types = ('access_token', 'refresh_token')
|
||||
|
||||
def __init__(self, request_validator, supported_token_types=None,
|
||||
enable_jsonp=False):
|
||||
BaseEndpoint.__init__(self)
|
||||
self.request_validator = request_validator
|
||||
self.supported_token_types = (
|
||||
supported_token_types or self.valid_token_types)
|
||||
self.enable_jsonp = enable_jsonp
|
||||
|
||||
@catch_errors_and_unavailability
|
||||
def create_revocation_response(self, uri, http_method='POST', body=None,
|
||||
headers=None):
|
||||
"""Revoke supplied access or refresh token.
|
||||
|
||||
|
||||
The authorization server responds with HTTP status code 200 if the
|
||||
token has been revoked sucessfully or if the client submitted an
|
||||
invalid token.
|
||||
|
||||
Note: invalid tokens do not cause an error response since the client
|
||||
cannot handle such an error in a reasonable way. Moreover, the purpose
|
||||
of the revocation request, invalidating the particular token, is
|
||||
already achieved.
|
||||
|
||||
The content of the response body is ignored by the client as all
|
||||
necessary information is conveyed in the response code.
|
||||
|
||||
An invalid token type hint value is ignored by the authorization server
|
||||
and does not influence the revocation response.
|
||||
"""
|
||||
request = Request(
|
||||
uri, http_method=http_method, body=body, headers=headers)
|
||||
try:
|
||||
self.validate_revocation_request(request)
|
||||
log.debug('Token revocation valid for %r.', request)
|
||||
except OAuth2Error as e:
|
||||
log.debug('Client error during validation of %r. %r.', request, e)
|
||||
response_body = e.json
|
||||
if self.enable_jsonp and request.callback:
|
||||
response_body = '%s(%s);' % (request.callback, response_body)
|
||||
return {}, response_body, e.status_code
|
||||
|
||||
self.request_validator.revoke_token(request.token,
|
||||
request.token_type_hint, request)
|
||||
|
||||
response_body = ''
|
||||
if self.enable_jsonp and request.callback:
|
||||
response_body = request.callback + '();'
|
||||
return {}, response_body, 200
|
||||
|
||||
def validate_revocation_request(self, request):
|
||||
"""Ensure the request is valid.
|
||||
|
||||
The client constructs the request by including the following parameters
|
||||
using the "application/x-www-form-urlencoded" format in the HTTP
|
||||
request entity-body:
|
||||
|
||||
token (REQUIRED). The token that the client wants to get revoked.
|
||||
|
||||
token_type_hint (OPTIONAL). A hint about the type of the token
|
||||
submitted for revocation. Clients MAY pass this parameter in order to
|
||||
help the authorization server to optimize the token lookup. If the
|
||||
server is unable to locate the token using the given hint, it MUST
|
||||
extend its search accross all of its supported token types. An
|
||||
authorization server MAY ignore this parameter, particularly if it is
|
||||
able to detect the token type automatically. This specification
|
||||
defines two such values:
|
||||
|
||||
* access_token: An Access Token as defined in [RFC6749],
|
||||
`section 1.4`_
|
||||
|
||||
* refresh_token: A Refresh Token as defined in [RFC6749],
|
||||
`section 1.5`_
|
||||
|
||||
Specific implementations, profiles, and extensions of this
|
||||
specification MAY define other values for this parameter using
|
||||
the registry defined in `Section 4.1.2`_.
|
||||
|
||||
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
|
||||
"""
|
||||
if not request.token:
|
||||
raise InvalidRequestError(request=request,
|
||||
description='Missing token parameter.')
|
||||
|
||||
if self.request_validator.client_authentication_required(request):
|
||||
if not self.request_validator.authenticate_client(request):
|
||||
log.debug('Client authentication failed, %r.', request)
|
||||
raise InvalidClientError(request=request)
|
||||
elif not self.request_validator.authenticate_client_id(request.client_id, request):
|
||||
log.debug('Client authentication failed, %r.', request)
|
||||
raise InvalidClientError(request=request)
|
||||
|
||||
if (request.token_type_hint and
|
||||
request.token_type_hint in self.valid_token_types and
|
||||
request.token_type_hint not in self.supported_token_types):
|
||||
raise UnsupportedTokenTypeError(request=request)
|
||||
@@ -0,0 +1,117 @@
|
||||
# -*- coding: utf-8 -*-
|
||||
"""
|
||||
oauthlib.oauth2.rfc6749
|
||||
~~~~~~~~~~~~~~~~~~~~~~~
|
||||
|
||||
This module is an implementation of various logic needed
|
||||
for consuming and providing OAuth 2.0 RFC6749.
|
||||
"""
|
||||
from __future__ import absolute_import, unicode_literals
|
||||
|
||||
import logging
|
||||
|
||||
from oauthlib.common import Request
|
||||
from oauthlib.oauth2.rfc6749 import utils
|
||||
|
||||
from .base import BaseEndpoint, catch_errors_and_unavailability
|
||||
|
||||
log = logging.getLogger(__name__)
|
||||
|
||||
|
||||
class TokenEndpoint(BaseEndpoint):
|
||||
|
||||
"""Token issuing endpoint.
|
||||
|
||||
The token endpoint is used by the client to obtain an access token by
|
||||
presenting its authorization grant or refresh token. The token
|
||||
endpoint is used with every authorization grant except for the
|
||||
implicit grant type (since an access token is issued directly).
|
||||
|
||||
The means through which the client obtains the location of the token
|
||||
endpoint are beyond the scope of this specification, but the location
|
||||
is typically provided in the service documentation.
|
||||
|
||||
The endpoint URI MAY include an "application/x-www-form-urlencoded"
|
||||
formatted (per `Appendix B`_) query component,
|
||||
which MUST be retained when adding additional query parameters. The
|
||||
endpoint URI MUST NOT include a fragment component::
|
||||
|
||||
https://example.com/path?query=component # OK
|
||||
https://example.com/path?query=component#fragment # Not OK
|
||||
|
||||
Since requests to the authorization endpoint result in user
|
||||
Since requests to the token endpoint result in the transmission of
|
||||
clear-text credentials (in the HTTP request and response), the
|
||||
authorization server MUST require the use of TLS as described in
|
||||
Section 1.6 when sending requests to the token endpoint::
|
||||
|
||||
# We will deny any request which URI schema is not with https
|
||||
|
||||
The client MUST use the HTTP "POST" method when making access token
|
||||
requests::
|
||||
|
||||
# HTTP method is currently not enforced
|
||||
|
||||
Parameters sent without a value MUST be treated as if they were
|
||||
omitted from the request. The authorization server MUST ignore
|
||||
unrecognized request parameters. Request and response parameters
|
||||
MUST NOT be included more than once::
|
||||
|
||||
# Delegated to each grant type.
|
||||
|
||||
.. _`Appendix B`: http://tools.ietf.org/html/rfc6749#appendix-B
|
||||
"""
|
||||
|
||||
def __init__(self, default_grant_type, default_token_type, grant_types):
|
||||
BaseEndpoint.__init__(self)
|
||||
self._grant_types = grant_types
|
||||
self._default_token_type = default_token_type
|
||||
self._default_grant_type = default_grant_type
|
||||
|
||||
@property
|
||||
def grant_types(self):
|
||||
return self._grant_types
|
||||
|
||||
@property
|
||||
def default_grant_type(self):
|
||||
return self._default_grant_type
|
||||
|
||||
@property
|
||||
def default_grant_type_handler(self):
|
||||
return self.grant_types.get(self.default_grant_type)
|
||||
|
||||
@property
|
||||
def default_token_type(self):
|
||||
return self._default_token_type
|
||||
|
||||
@catch_errors_and_unavailability
|
||||
def create_token_response(self, uri, http_method='GET', body=None,
|
||||
headers=None, credentials=None, grant_type_for_scope=None,
|
||||
claims=None):
|
||||
"""Extract grant_type and route to the designated handler."""
|
||||
request = Request(
|
||||
uri, http_method=http_method, body=body, headers=headers)
|
||||
|
||||
# 'scope' is an allowed Token Request param in both the "Resource Owner Password Credentials Grant"
|
||||
# and "Client Credentials Grant" flows
|
||||
# https://tools.ietf.org/html/rfc6749#section-4.3.2
|
||||
# https://tools.ietf.org/html/rfc6749#section-4.4.2
|
||||
request.scopes = utils.scope_to_list(request.scope)
|
||||
|
||||
request.extra_credentials = credentials
|
||||
if grant_type_for_scope:
|
||||
request.grant_type = grant_type_for_scope
|
||||
|
||||
# OpenID Connect claims, if provided. The server using oauthlib might choose
|
||||
# to implement the claims parameter of the Authorization Request. In this case
|
||||
# it should retrieve those claims and pass them via the claims argument here,
|
||||
# as a dict.
|
||||
if claims:
|
||||
request.claims = claims
|
||||
|
||||
grant_type_handler = self.grant_types.get(request.grant_type,
|
||||
self.default_grant_type_handler)
|
||||
log.debug('Dispatching grant_type %s request to %r.',
|
||||
request.grant_type, grant_type_handler)
|
||||
return grant_type_handler.create_token_response(
|
||||
request, self.default_token_type)
|
||||
Reference in New Issue
Block a user