Source code for oauth2

"""
=============
oauth2-stateless
=============

oauth2-stateless is a framework that aims at making it easy to provide
authentication via `OAuth 2.0 <http://tools.ietf.org/html/rfc6749>`_ within
an application stack.

Usage
=====

Example:

.. literalinclude:: examples/base_server.py

Installation
============

oauth2-stateless is available on
`PyPI <http://pypi.python.org/pypi/oauth2-stateless/>`_::

    pip install oauth2-stateless
"""

from oauth2.client_authenticator import ClientAuthenticator, request_body
from oauth2.compatibility import json
from oauth2.error import (ClientNotFoundError, OAuthInvalidError,
                          OAuthInvalidNoRedirectError, UnsupportedGrantError)
from oauth2.grant import (AuthorizationCodeGrant, ClientCredentialsGrant,
                          ImplicitGrant, RefreshToken, ResourceOwnerGrant,
                          Scope)
from oauth2.log import app_log
from oauth2.tokengenerator import Uuid4TokenGenerator
from oauth2.web import Response


[docs]class Provider(object): """ Endpoint of requests to the OAuth 2.0 provider. :param access_token_store: An object that implements methods defined by :class:`oauth2.store.AccessTokenStore`. :type access_token_store: oauth2.store.AccessTokenStore :param auth_code_store: An object that implements methods defined by :class:`oauth2.store.AuthCodeStore`. :type auth_code_store: oauth2.store.AuthCodeStore :param client_store: An object that implements methods defined by :class:`oauth2.store.ClientStore`. :type client_store: oauth2.store.ClientStore :param token_generator: Object to generate unique tokens. :type token_generator: oauth2.tokengenerator.TokenGenerator :param client_authentication_source: A callable which when executed, authenticates a client. See :mod:`oauth2.client_authenticator`. :type client_authentication_source: callable :param response_class: Class of the response object. Defaults to :class:`oauth2.web.Response`. :type response_class: oauth2.web.Response """ authorize_path = "/authorize" token_path = "/token" def __init__(self, access_token_store, auth_code_store, client_store, token_generator, client_authentication_source=request_body, response_class=Response): self.grant_types = [] self._input_handler = None self.access_token_store = access_token_store self.auth_code_store = auth_code_store self.client_authenticator = ClientAuthenticator(client_store=client_store, source=client_authentication_source) self.response_class = response_class self.token_generator = token_generator
[docs] def add_grant(self, grant): """ Adds a Grant that the provider should support. :param grant: An instance of a class that extends :class:`oauth2.grant.GrantHandlerFactory` :type grant: oauth2.grant.GrantHandlerFactory """ if hasattr(grant, "expires_in"): self.token_generator.expires_in[grant.grant_type] = grant.expires_in if hasattr(grant, "refresh_expires_in"): self.token_generator.refresh_expires_in = grant.refresh_expires_in self.grant_types.append(grant)
[docs] def dispatch(self, request, environ): """ Checks which Grant supports the current request and dispatches to it. :param request: The incoming request. :type request: :class:`oauth2.web.Request` :param environ: Dict containing variables of the environment. :type environ: dict :return: An instance of ``oauth2.web.Response``. """ try: grant_type = self._determine_grant_type(request) response = self.response_class() grant_type.read_validate_params(request) return grant_type.process(request, response, environ) except OAuthInvalidNoRedirectError: response = self.response_class() response.add_header("Content-Type", "application/json") response.status_code = 400 response.body = json.dumps({ "error": "invalid_redirect_uri", "error_description": "Invalid redirect URI" }) return response except OAuthInvalidError as err: response = self.response_class() return grant_type.handle_error(error=err, response=response) except UnsupportedGrantError: response = self.response_class() response.add_header("Content-Type", "application/json") response.status_code = 400 response.body = json.dumps({ "error": "unsupported_response_type", "error_description": "Grant not supported" }) return response except: app_log.error("Uncaught Exception", exc_info=True) response = self.response_class() return grant_type.handle_error( error=OAuthInvalidError(error="server_error", explanation="Internal server error"), response=response)
[docs] def enable_unique_tokens(self): """ Enable the use of unique access tokens on all grant types that support this option. """ for grant_type in self.grant_types: if hasattr(grant_type, "unique_token"): grant_type.unique_token = True
@property def scope_separator(self, separator): """ Sets the separator of values in the scope query parameter. Defaults to " " (whitespace). The following code makes the Provider use "," instead of " ":: provider = Provider() provider.scope_separator = "," Now the scope parameter in the request of a client can look like this: `scope=foo,bar`. """ Scope.separator = separator def _determine_grant_type(self, request): for grant in self.grant_types: grant_handler = grant(request, self) if grant_handler is not None: return grant_handler raise UnsupportedGrantError