mirror of
https://github.com/Tautulli/Tautulli.git
synced 2025-08-19 21:03:21 -07:00
Include oauthlib module
This commit is contained in:
parent
363d1b07ca
commit
06b684c899
48 changed files with 8620 additions and 704 deletions
19
lib/oauthlib/oauth2/rfc6749/endpoints/__init__.py
Normal file
19
lib/oauthlib/oauth2/rfc6749/endpoints/__init__.py
Normal file
|
@ -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
|
114
lib/oauthlib/oauth2/rfc6749/endpoints/authorization.py
Normal file
114
lib/oauthlib/oauth2/rfc6749/endpoints/authorization.py
Normal file
|
@ -0,0 +1,114 @@
|
|||
# -*- 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 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 = None
|
||||
response_type_handler = self.response_types.get(
|
||||
request.response_type, self.default_response_type_handler)
|
||||
return response_type_handler.validate_authorization_request(request)
|
65
lib/oauthlib/oauth2/rfc6749/endpoints/base.py
Normal file
65
lib/oauthlib/oauth2/rfc6749/endpoints/base.py
Normal file
|
@ -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 TemporarilyUnavailableError, ServerError
|
||||
from ..errors import FatalClientError, OAuth2Error
|
||||
|
||||
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
|
209
lib/oauthlib/oauth2/rfc6749/endpoints/pre_configured.py
Normal file
209
lib/oauthlib/oauth2/rfc6749/endpoints/pre_configured.py
Normal file
|
@ -0,0 +1,209 @@
|
|||
# -*- 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 ..tokens import BearerToken
|
||||
from ..grant_types import AuthorizationCodeGrant
|
||||
from ..grant_types import ImplicitGrant
|
||||
from ..grant_types import ResourceOwnerPasswordCredentialsGrant
|
||||
from ..grant_types import ClientCredentialsGrant
|
||||
from ..grant_types import RefreshTokenGrant
|
||||
|
||||
from .authorization import AuthorizationEndpoint
|
||||
from .token import TokenEndpoint
|
||||
from .resource import ResourceEndpoint
|
||||
from .revocation import RevocationEndpoint
|
||||
|
||||
|
||||
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)
|
||||
bearer = BearerToken(request_validator, token_generator,
|
||||
token_expires_in, refresh_token_generator)
|
||||
AuthorizationEndpoint.__init__(self, default_response_type='code',
|
||||
response_types={
|
||||
'code': auth_grant,
|
||||
'token': implicit_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,
|
||||
},
|
||||
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'])
|
87
lib/oauthlib/oauth2/rfc6749/endpoints/resource.py
Normal file
87
lib/oauthlib/oauth2/rfc6749/endpoints/resource.py
Normal file
|
@ -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
|
130
lib/oauthlib/oauth2/rfc6749/endpoints/revocation.py
Normal file
130
lib/oauthlib/oauth2/rfc6749/endpoints/revocation.py
Normal file
|
@ -0,0 +1,130 @@
|
|||
# -*- 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 .base import BaseEndpoint, catch_errors_and_unavailability
|
||||
from ..errors import InvalidClientError, UnsupportedTokenTypeError
|
||||
from ..errors import InvalidRequestError, OAuth2Error
|
||||
|
||||
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):
|
||||
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)
|
100
lib/oauthlib/oauth2/rfc6749/endpoints/token.py
Normal file
100
lib/oauthlib/oauth2/rfc6749/endpoints/token.py
Normal file
|
@ -0,0 +1,100 @@
|
|||
# -*- 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 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):
|
||||
"""Extract grant_type and route to the designated handler."""
|
||||
request = Request(
|
||||
uri, http_method=http_method, body=body, headers=headers)
|
||||
request.scopes = None
|
||||
request.extra_credentials = credentials
|
||||
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)
|
Loading…
Add table
Add a link
Reference in a new issue