[Python-modules-commits] [python-oauthlib] 02/06: Import python-oauthlib_2.0.2.orig.tar.gz

Daniele Tricoli eriol-guest at moszumanska.debian.org
Mon Mar 27 22:36:16 UTC 2017


This is an automated email from the git hooks/post-receive script.

eriol-guest pushed a commit to branch master
in repository python-oauthlib.

commit 8d11e88b0966087eda4d28ab855641016c58f635
Author: Daniele Tricoli <eriol at mornie.org>
Date:   Mon Mar 27 23:19:56 2017 +0200

    Import python-oauthlib_2.0.2.orig.tar.gz
---
 CHANGELOG.rst                                      |   8 +
 PKG-INFO                                           |   7 +-
 oauthlib.egg-info/PKG-INFO                         |   7 +-
 oauthlib.egg-info/SOURCES.txt                      |   1 +
 oauthlib/__init__.py                               |   2 +-
 oauthlib/oauth1/rfc5849/__init__.py                |   1 +
 .../rfc6749/grant_types/authorization_code.py      |  45 ++---
 oauthlib/oauth2/rfc6749/grant_types/base.py        |  98 +++++++++++
 .../rfc6749/grant_types/client_credentials.py      |  13 +-
 oauthlib/oauth2/rfc6749/grant_types/implicit.py    |  45 +++--
 .../oauth2/rfc6749/grant_types/openid_connect.py   | 181 +++++++--------------
 .../oauth2/rfc6749/grant_types/refresh_token.py    |  20 ++-
 .../resource_owner_password_credentials.py         |  18 +-
 setup.cfg                                          |   3 +-
 setup.py                                           |   5 +-
 .../rfc6749/endpoints/test_prompt_handling.py      |  50 ++++++
 .../rfc6749/grant_types/test_authorization_code.py |  32 ++++
 .../rfc6749/grant_types/test_client_credentials.py |  25 +++
 tests/oauth2/rfc6749/grant_types/test_implicit.py  |  19 +++
 .../rfc6749/grant_types/test_refresh_token.py      |  25 +++
 .../grant_types/test_resource_owner_password.py    |  28 ++++
 21 files changed, 420 insertions(+), 213 deletions(-)

diff --git a/CHANGELOG.rst b/CHANGELOG.rst
index 933a44a..7afc875 100644
--- a/CHANGELOG.rst
+++ b/CHANGELOG.rst
@@ -1,6 +1,14 @@
 Changelog
 =========
 
+Development
+-----------
+
+2.0.2 (2017-03-19)
+------------------
+* Dropped support for Python 2.6, 3.2 & 3.3.
+* (FIX) `OpenIDConnector` will no longer raise an AttributeError when calling `openid_authorization_validator()` twice.  
+
 2.0.1 (2016-11-23)
 ------------------
 * (FIX) Normalize handling of request.scopes list
diff --git a/PKG-INFO b/PKG-INFO
index 20afd67..7a883ba 100644
--- a/PKG-INFO
+++ b/PKG-INFO
@@ -1,6 +1,6 @@
 Metadata-Version: 1.1
 Name: oauthlib
-Version: 2.0.1
+Version: 2.0.2
 Summary: A generic, spec-compliant, thorough implementation of the OAuth request-signing logic
 Home-page: https://github.com/idan/oauthlib
 Author: Ib Lundgren
@@ -109,7 +109,7 @@ Description: OAuthLib
         For a full changelog see ``CHANGELOG.rst``.
         
 Platform: any
-Classifier: Development Status :: 4 - Beta
+Classifier: Development Status :: 5 - Production/Stable
 Classifier: Environment :: Web Environment
 Classifier: Intended Audience :: Developers
 Classifier: License :: OSI Approved
@@ -118,11 +118,10 @@ Classifier: Operating System :: MacOS
 Classifier: Operating System :: POSIX
 Classifier: Operating System :: POSIX :: Linux
 Classifier: Programming Language :: Python
-Classifier: Programming Language :: Python :: 2.6
 Classifier: Programming Language :: Python :: 2.7
-Classifier: Programming Language :: Python :: 3.2
 Classifier: Programming Language :: Python :: 3.3
 Classifier: Programming Language :: Python :: 3.4
+Classifier: Programming Language :: Python :: 3.5
 Classifier: Programming Language :: Python :: Implementation
 Classifier: Programming Language :: Python :: Implementation :: CPython
 Classifier: Programming Language :: Python :: Implementation :: PyPy
diff --git a/oauthlib.egg-info/PKG-INFO b/oauthlib.egg-info/PKG-INFO
index 20afd67..7a883ba 100644
--- a/oauthlib.egg-info/PKG-INFO
+++ b/oauthlib.egg-info/PKG-INFO
@@ -1,6 +1,6 @@
 Metadata-Version: 1.1
 Name: oauthlib
-Version: 2.0.1
+Version: 2.0.2
 Summary: A generic, spec-compliant, thorough implementation of the OAuth request-signing logic
 Home-page: https://github.com/idan/oauthlib
 Author: Ib Lundgren
@@ -109,7 +109,7 @@ Description: OAuthLib
         For a full changelog see ``CHANGELOG.rst``.
         
 Platform: any
-Classifier: Development Status :: 4 - Beta
+Classifier: Development Status :: 5 - Production/Stable
 Classifier: Environment :: Web Environment
 Classifier: Intended Audience :: Developers
 Classifier: License :: OSI Approved
@@ -118,11 +118,10 @@ Classifier: Operating System :: MacOS
 Classifier: Operating System :: POSIX
 Classifier: Operating System :: POSIX :: Linux
 Classifier: Programming Language :: Python
-Classifier: Programming Language :: Python :: 2.6
 Classifier: Programming Language :: Python :: 2.7
-Classifier: Programming Language :: Python :: 3.2
 Classifier: Programming Language :: Python :: 3.3
 Classifier: Programming Language :: Python :: 3.4
+Classifier: Programming Language :: Python :: 3.5
 Classifier: Programming Language :: Python :: Implementation
 Classifier: Programming Language :: Python :: Implementation :: CPython
 Classifier: Programming Language :: Python :: Implementation :: PyPy
diff --git a/oauthlib.egg-info/SOURCES.txt b/oauthlib.egg-info/SOURCES.txt
index 075ca59..35edb24 100644
--- a/oauthlib.egg-info/SOURCES.txt
+++ b/oauthlib.egg-info/SOURCES.txt
@@ -93,6 +93,7 @@ tests/oauth2/rfc6749/endpoints/test_client_authentication.py
 tests/oauth2/rfc6749/endpoints/test_credentials_preservation.py
 tests/oauth2/rfc6749/endpoints/test_error_responses.py
 tests/oauth2/rfc6749/endpoints/test_extra_credentials.py
+tests/oauth2/rfc6749/endpoints/test_prompt_handling.py
 tests/oauth2/rfc6749/endpoints/test_resource_owner_association.py
 tests/oauth2/rfc6749/endpoints/test_revocation_endpoint.py
 tests/oauth2/rfc6749/endpoints/test_scope_handling.py
diff --git a/oauthlib/__init__.py b/oauthlib/__init__.py
index 93940ec..e5186a3 100644
--- a/oauthlib/__init__.py
+++ b/oauthlib/__init__.py
@@ -10,7 +10,7 @@
 """
 
 __author__ = 'Idan Gazit <idan at gazit.me>'
-__version__ = '2.0.1'
+__version__ = '2.0.2'
 
 
 import logging
diff --git a/oauthlib/oauth1/rfc5849/__init__.py b/oauthlib/oauth1/rfc5849/__init__.py
index 56b8c6f..997251e 100644
--- a/oauthlib/oauth1/rfc5849/__init__.py
+++ b/oauthlib/oauth1/rfc5849/__init__.py
@@ -105,6 +105,7 @@ class Client(object):
     def __repr__(self):
         attrs = vars(self).copy()
         attrs['client_secret'] = '****' if attrs['client_secret'] else None
+        attrs['rsa_key'] = '****' if attrs['rsa_key'] else None
         attrs[
             'resource_owner_secret'] = '****' if attrs['resource_owner_secret'] else None
         attribute_str = ', '.join('%s=%s' % (k, v) for k, v in attrs.items())
diff --git a/oauthlib/oauth2/rfc6749/grant_types/authorization_code.py b/oauthlib/oauth2/rfc6749/grant_types/authorization_code.py
index 25e8816..3d427ab 100644
--- a/oauthlib/oauth2/rfc6749/grant_types/authorization_code.py
+++ b/oauthlib/oauth2/rfc6749/grant_types/authorization_code.py
@@ -13,7 +13,6 @@ from oauthlib.uri_validate import is_absolute_uri
 
 from .base import GrantTypeBase
 from .. import errors
-from ..request_validator import RequestValidator
 
 log = logging.getLogger(__name__)
 
@@ -96,31 +95,7 @@ class AuthorizationCodeGrant(GrantTypeBase):
     """
 
     default_response_mode = 'query'
-
-    def __init__(self, request_validator=None, refresh_token=True):
-        self.request_validator = request_validator or RequestValidator()
-        self.refresh_token = refresh_token
-
-        self._authorization_validators = []
-        self._token_validators = []
-        self._code_modifiers = []
-        self._token_modifiers = []
-        self.response_types = ['code']
-
-    def register_response_type(self, response_type):
-        self.response_types.append(response_type)
-
-    def register_authorization_validator(self, validator):
-        self._authorization_validators.append(validator)
-
-    def register_token_validator(self, validator):
-        self._token_validators.append(validator)
-
-    def register_code_modifier(self, modifier):
-        self._code_modifiers.append(modifier)
-
-    def register_token_modifier(self, modifier):
-        self._token_modifiers.append(modifier)
+    response_types = ['code']
 
     def create_authorization_code(self, request):
         """Generates an authorization grant represented as a dictionary."""
@@ -347,6 +322,10 @@ class AuthorizationCodeGrant(GrantTypeBase):
         # Note that the correct parameters to be added are automatically
         # populated through the use of specific exceptions.
 
+        request_info = {}
+        for validator in self.custom_validators.pre_auth:
+            request_info.update(validator(request))
+
         # REQUIRED.
         if request.response_type is None:
             raise errors.MissingResponseTypeError(request=request)
@@ -367,15 +346,15 @@ class AuthorizationCodeGrant(GrantTypeBase):
         # http://tools.ietf.org/html/rfc6749#section-3.3
         self.validate_scopes(request)
 
-        request_info = {
+        request_info.update({
             'client_id': request.client_id,
             'redirect_uri': request.redirect_uri,
             'response_type': request.response_type,
             'state': request.state,
             'request': request
-        }
+        })
 
-        for validator in self._authorization_validators:
+        for validator in self.custom_validators.post_auth:
             request_info.update(validator(request))
 
         return request.scopes, request_info
@@ -385,6 +364,9 @@ class AuthorizationCodeGrant(GrantTypeBase):
         if request.grant_type not in ('authorization_code', 'openid'):
             raise errors.UnsupportedGrantTypeError(request=request)
 
+        for validator in self.custom_validators.pre_token:
+            validator(request)
+
         if request.code is None:
             raise errors.InvalidRequestError(
                 description='Missing code parameter.', request=request)
@@ -415,6 +397,8 @@ class AuthorizationCodeGrant(GrantTypeBase):
                                       'request.client.client_id attribute '
                                       'in authenticate_client.')
 
+        request.client_id = request.client_id or request.client.client_id
+
         # Ensure client is authorized use of this grant type
         self.validate_grant_type(request)
 
@@ -439,6 +423,5 @@ class AuthorizationCodeGrant(GrantTypeBase):
                       request.redirect_uri, request.client_id, request.client)
             raise errors.AccessDeniedError(request=request)
 
-        for validator in self._token_validators:
+        for validator in self.custom_validators.post_token:
             validator(request)
-
diff --git a/oauthlib/oauth2/rfc6749/grant_types/base.py b/oauthlib/oauth2/rfc6749/grant_types/base.py
index 36b06eb..1128388 100644
--- a/oauthlib/oauth2/rfc6749/grant_types/base.py
+++ b/oauthlib/oauth2/rfc6749/grant_types/base.py
@@ -4,19 +4,117 @@ oauthlib.oauth2.rfc6749.grant_types
 ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
 """
 from __future__ import unicode_literals, absolute_import
+from itertools import chain
 
 import logging
 
 from oauthlib.common import add_params_to_uri
 from oauthlib.oauth2.rfc6749 import errors, utils
+from ..request_validator import RequestValidator
 
 log = logging.getLogger(__name__)
 
+class ValidatorsContainer(object):
+    """
+        Container object for holding custom validator callables to be invoked
+        as part of the grant type `validate_authorization_request()` or
+        `validate_authorization_request()` methods on the various grant types.
+
+        Authorization validators must be callables that take a request object and
+        return a dict, which may contain items to be added to the `request_info`
+        returned from the grant_type after validation.
+
+        Token validators must be callables that take a request object and
+        return None.
+
+        Both authorization validators and token validators may raise OAuth2
+        exceptions if validation conditions fail.
+
+        Authorization validators added to `pre_auth` will be run BEFORE
+        the standard validations (but after the critical ones that raise
+        fatal errors) as part of `validate_authorization_request()`
+
+        Authorization validators added to `post_auth` will be run AFTER
+        the standard validations as part of `validate_authorization_request()`
+
+        Token validators added to `pre_token` will be run BEFORE
+        the standard validations as part of `validate_token_request()`
+
+        Token validators added to `post_token` will be run AFTER
+        the standard validations as part of `validate_token_request()`
+
+        For example:
+
+        >>> def my_auth_validator(request):
+        ...    return {'myval': True}
+        >>> auth_code_grant = AuthorizationCodeGrant(request_validator)
+        >>> auth_code_grant.custom_validators.pre_auth.append(my_auth_validator)
+        >>> def my_token_validator(request):
+        ...     if not request.everything_okay:
+        ...         raise errors.OAuth2Error("uh-oh")
+        >>> auth_code_grant.custom_validators.post_token.append(my_token_validator)
+    """
+
+    def __init__(self, post_auth, post_token,
+                 pre_auth, pre_token):
+        self.pre_auth = pre_auth
+        self.post_auth = post_auth
+        self.pre_token = pre_token
+        self.post_token = post_token
+
+    @property
+    def all_pre(self):
+        return chain(self.pre_auth, self.pre_token)
+
+    @property
+    def all_post(self):
+        return chain(self.post_auth, self.post_token)
+
 
 class GrantTypeBase(object):
     error_uri = None
     request_validator = None
     default_response_mode = 'fragment'
+    refresh_token = True
+    response_types = ['code']
+
+    def __init__(self, request_validator=None, **kwargs):
+        self.request_validator = request_validator or RequestValidator()
+
+        # Transforms class variables into instance variables:
+        self.response_types = self.response_types
+        self.refresh_token = self.refresh_token
+        self._setup_custom_validators(kwargs)
+        self._code_modifiers = []
+        self._token_modifiers = []
+
+        for kw, val in kwargs.items():
+            setattr(self, kw, val)
+
+    def _setup_custom_validators(self, kwargs):
+        post_auth = kwargs.get('post_auth', [])
+        post_token = kwargs.get('post_token', [])
+        pre_auth = kwargs.get('pre_auth', [])
+        pre_token = kwargs.get('pre_token', [])
+        if not hasattr(self, 'validate_authorization_request'):
+            if post_auth or pre_auth:
+                msg = ("{} does not support authorization validators. Use "
+                       "token validators instead.").format(self.__class__.__name__)
+                raise ValueError(msg)
+            # Using tuples here because they can't be appended to:
+            post_auth, pre_auth = (), ()
+        self.custom_validators = ValidatorsContainer(post_auth, post_token,
+                                                     pre_auth, pre_token)
+
+    def register_response_type(self, response_type):
+        self.response_types.append(response_type)
+
+    def register_code_modifier(self, modifier):
+        self._code_modifiers.append(modifier)
+
+    def register_token_modifier(self, modifier):
+        self._token_modifiers.append(modifier)
+
 
     def create_authorization_response(self, request, token_handler):
         raise NotImplementedError('Subclasses must implement this method.')
diff --git a/oauthlib/oauth2/rfc6749/grant_types/client_credentials.py b/oauthlib/oauth2/rfc6749/grant_types/client_credentials.py
index 91c17a6..dd0a39a 100644
--- a/oauthlib/oauth2/rfc6749/grant_types/client_credentials.py
+++ b/oauthlib/oauth2/rfc6749/grant_types/client_credentials.py
@@ -50,13 +50,6 @@ class ClientCredentialsGrant(GrantTypeBase):
     .. _`Client Credentials Grant`: http://tools.ietf.org/html/rfc6749#section-4.4
     """
 
-    def __init__(self, request_validator=None):
-        self.request_validator = request_validator or RequestValidator()
-        self._token_modifiers = []
-
-    def register_token_modifier(self, modifier):
-        self._token_modifiers.append(modifier)
-
     def create_token_response(self, request, token_handler):
         """Return token or error in JSON format.
 
@@ -92,6 +85,9 @@ class ClientCredentialsGrant(GrantTypeBase):
         return headers, json.dumps(token), 200
 
     def validate_token_request(self, request):
+        for validator in self.custom_validators.pre_token:
+            validator(request)
+
         if not getattr(request, 'grant_type', None):
             raise errors.InvalidRequestError('Request is missing grant type.',
                                              request=request)
@@ -119,3 +115,6 @@ class ClientCredentialsGrant(GrantTypeBase):
         log.debug('Authorizing access to user %r.', request.user)
         request.client_id = request.client_id or request.client.client_id
         self.validate_scopes(request)
+
+        for validator in self.custom_validators.post_token:
+            validator(request)
diff --git a/oauthlib/oauth2/rfc6749/grant_types/implicit.py b/oauthlib/oauth2/rfc6749/grant_types/implicit.py
index 7366b94..51e95af 100644
--- a/oauthlib/oauth2/rfc6749/grant_types/implicit.py
+++ b/oauthlib/oauth2/rfc6749/grant_types/implicit.py
@@ -117,20 +117,8 @@ class ImplicitGrant(GrantTypeBase):
     .. _`Section 10.16`: http://tools.ietf.org/html/rfc6749#section-10.16
     """
 
-    def __init__(self, request_validator=None):
-        self.request_validator = request_validator or RequestValidator()
-        self._authorization_validators = []
-        self._token_modifiers = []
-        self.response_types = ['token']
-
-    def register_response_type(self, response_type):
-        self.response_types.append(response_type)
-
-    def register_authorization_validator(self, validator):
-        self._authorization_validators.append(validator)
-
-    def register_token_modifier(self, modifier):
-        self._token_modifiers.append(modifier)
+    response_types = ['token']
+    grant_allows_refresh_token = False
 
     def create_authorization_response(self, request, token_handler):
         """Create an authorization response.
@@ -328,6 +316,10 @@ class ImplicitGrant(GrantTypeBase):
 
         # Then check for normal errors.
 
+        request_info = self._run_custom_validators(request,
+                                self.custom_validators.all_pre)
+
+
         # If the resource owner denies the access request or if the request
         # fails for reasons other than a missing or invalid redirection URI,
         # the authorization server informs the client by adding the following
@@ -359,15 +351,32 @@ class ImplicitGrant(GrantTypeBase):
         # http://tools.ietf.org/html/rfc6749#section-3.3
         self.validate_scopes(request)
 
-        request_info = {
+        request_info.update({
                 'client_id': request.client_id,
                 'redirect_uri': request.redirect_uri,
                 'response_type': request.response_type,
                 'state': request.state,
                 'request': request,
-        }
+        })
 
-        for validator in self._authorization_validators:
-            request_info.update(validator(request))
+        request_info = self._run_custom_validators(request,
+                            self.custom_validators.all_post,
+                            request_info)
 
         return request.scopes, request_info
+
+
+    def _run_custom_validators(self,
+                               request,
+                               validations,
+                               request_info=None):
+        # Make a copy so we don't modify the existing request_info dict
+        request_info = {} if request_info is None else request_info.copy()
+        # For implicit grant, auth_validators and token_validators are
+        # basically equivalent since the token is returned from the
+        # authorization endpoint.
+        for validator in validations:
+            result = validator(request)
+            if result is not None:
+                request_info.update(result)
+        return request_info
diff --git a/oauthlib/oauth2/rfc6749/grant_types/openid_connect.py b/oauthlib/oauth2/rfc6749/grant_types/openid_connect.py
index 6cc3772..025d368 100644
--- a/oauthlib/oauth2/rfc6749/grant_types/openid_connect.py
+++ b/oauthlib/oauth2/rfc6749/grant_types/openid_connect.py
@@ -77,10 +77,33 @@ class AuthCodeGrantDispatcher(object):
         return self._handler_for_request(request).validate_authorization_request(request)
 
 
-class OpenIDConnectBase(GrantTypeBase):
+class OpenIDConnectBase(object):
+
+    # Just proxy the majority of method calls through to the
+    # proxy_target grant type handler, which will usually be either
+    # the standard OAuth2 AuthCode or Implicit grant types.
+    def __getattr__(self, attr):
+        return getattr(self.proxy_target, attr)
+
+    def __setattr__(self, attr, value):
+        proxied_attrs = set(('refresh_token', 'response_types'))
+        if attr in proxied_attrs:
+            setattr(self.proxy_target, attr, value)
+        else:
+            super(OpenIDConnectBase, self).__setattr__(attr, value)
 
-    def __init__(self, request_validator=None):
-        self.request_validator = request_validator or RequestValidator()
+    def validate_authorization_request(self, request):
+        """Validates the OpenID Connect authorization request parameters.
+
+        :returns: (list of scopes, dict of request info)
+        """
+        # If request.prompt is 'none' then no login/authorization form should
+        # be presented to the user. Instead, a silent login/authorization
+        # should be performed.
+        if request.prompt == 'none':
+            raise OIDCNoPrompt()
+        else:
+            return self.proxy_target.validate_authorization_request(request)
 
     def _inflate_claims(self, request):
         # this may be called multiple times in a single request so make sure we only de-serialize the claims once
@@ -270,10 +293,15 @@ class OpenIDConnectBase(GrantTypeBase):
             msg = "Session user does not match client supplied user."
             raise LoginRequired(request=request, description=msg)
 
+        prompt = []
+        if request.prompt:
+            prompt = request.prompt
+            if hasattr(prompt, 'split'):
+                prompt = prompt.split()
 
         request_info = {
             'display': request.display,
-            'prompt': request.prompt.split() if request.prompt else [],
+            'prompt': prompt,
             'ui_locales': request.ui_locales.split() if request.ui_locales else [],
             'id_token_hint': request.id_token_hint,
             'login_hint': request.login_hint,
@@ -309,135 +337,40 @@ class OpenIDConnectBase(GrantTypeBase):
 
 class OpenIDConnectAuthCode(OpenIDConnectBase):
 
-    def __init__(self, request_validator=None):
-        self.request_validator = request_validator or RequestValidator()
-        super(OpenIDConnectAuthCode, self).__init__(
-            request_validator=self.request_validator)
-        self.auth_code = AuthorizationCodeGrant(
-            request_validator=self.request_validator)
-        self.auth_code.register_authorization_validator(
+    def __init__(self, request_validator=None, **kwargs):
+        self.proxy_target = AuthorizationCodeGrant(
+            request_validator=request_validator, **kwargs)
+        self.custom_validators.post_auth.append(
             self.openid_authorization_validator)
-        self.auth_code.register_token_modifier(self.add_id_token)
-
-    @property
-    def refresh_token(self):
-        return self.auth_code.refresh_token
-
-    @refresh_token.setter
-    def refresh_token(self, value):
-        self.auth_code.refresh_token = value
-
-    def create_authorization_code(self, request):
-        return self.auth_code.create_authorization_code(request)
-
-    def create_authorization_response(self, request, token_handler):
-        return self.auth_code.create_authorization_response(
-            request, token_handler)
-
-    def create_token_response(self, request, token_handler):
-        return self.auth_code.create_token_response(request, token_handler)
-
-    def validate_authorization_request(self, request):
-        """Validates the OpenID Connect authorization request parameters.
-
-        :returns: (list of scopes, dict of request info)
-        """
-        # If request.prompt is 'none' then no login/authorization form should
-        # be presented to the user. Instead, a silent login/authorization
-        # should be performed.
-        if request.prompt == 'none':
-            raise OIDCNoPrompt()
-        else:
-            return self.auth_code.validate_authorization_request(request)
-
-    def validate_token_request(self, request):
-        return self.auth_code.validate_token_request(request)
-
+        self.register_token_modifier(self.add_id_token)
 
 class OpenIDConnectImplicit(OpenIDConnectBase):
 
-    def __init__(self, request_validator=None):
-        self.request_validator = request_validator or RequestValidator()
-        super(OpenIDConnectImplicit, self).__init__(
-            request_validator=self.request_validator)
-        self.implicit = ImplicitGrant(
-            request_validator=request_validator)
-        self.implicit.register_response_type('id_token')
-        self.implicit.register_response_type('id_token token')
-        self.implicit.register_authorization_validator(
+    def __init__(self, request_validator=None, **kwargs):
+        self.proxy_target = ImplicitGrant(
+            request_validator=request_validator, **kwargs)
+        self.register_response_type('id_token')
+        self.register_response_type('id_token token')
+        self.custom_validators.post_auth.append(
             self.openid_authorization_validator)
-        self.implicit.register_authorization_validator(
+        self.custom_validators.post_auth.append(
             self.openid_implicit_authorization_validator)
-        self.implicit.register_token_modifier(self.add_id_token)
-
-    def create_authorization_response(self, request, token_handler):
-        return self.create_token_response(request, token_handler)
-
-    def create_token_response(self, request, token_handler):
-        return self.implicit.create_authorization_response(
-            request, token_handler)
-
-    def validate_authorization_request(self, request):
-        """Validates the OpenID Connect authorization request parameters.
-
-        :returns: (list of scopes, dict of request info)
-        """
-        # If request.prompt is 'none' then no login/authorization form should
-        # be presented to the user. Instead, a silent login/authorization
-        # should be performed.
-        if request.prompt == 'none':
-            raise OIDCNoPrompt()
-        else:
-            return self.implicit.validate_authorization_request(request)
-
+        self.register_token_modifier(self.add_id_token)
 
 class OpenIDConnectHybrid(OpenIDConnectBase):
 
-    def __init__(self, request_validator=None):
+    def __init__(self, request_validator=None, **kwargs):
         self.request_validator = request_validator or RequestValidator()
 
-        self.auth_code = AuthorizationCodeGrant(
-            request_validator=request_validator)
-        self.auth_code.register_response_type('code id_token')
-        self.auth_code.register_response_type('code token')
-        self.auth_code.register_response_type('code id_token token')
-        self.auth_code.register_authorization_validator(
+        self.proxy_target = AuthorizationCodeGrant(
+            request_validator=request_validator, **kwargs)
+        self.register_response_type('code id_token')
+        self.register_response_type('code token')
+        self.register_response_type('code id_token token')
+        self.custom_validators.post_auth.append(
             self.openid_authorization_validator)
-        self.auth_code.register_code_modifier(self.add_token)
-        self.auth_code.register_code_modifier(self.add_id_token)
-        self.auth_code.register_token_modifier(self.add_id_token)
-
-    @property
-    def refresh_token(self):
-        return self.auth_code.refresh_token
-
-    @refresh_token.setter
-    def refresh_token(self, value):
-        self.auth_code.refresh_token = value
-
-    def create_authorization_code(self, request):
-        return self.auth_code.create_authorization_code(request)
-
-    def create_authorization_response(self, request, token_handler):
-        return self.auth_code.create_authorization_response(
-            request, token_handler)
-
-    def create_token_response(self, request, token_handler):
-        return self.auth_code.create_token_response(request, token_handler)
-
-    def validate_authorization_request(self, request):
-        """Validates the OpenID Connect authorization request parameters.
-
-        :returns: (list of scopes, dict of request info)
-        """
-        # If request.prompt is 'none' then no login/authorization form should
-        # be presented to the user. Instead, a silent login/authorization
-        # should be performed.
-        if request.prompt == 'none':
-            raise OIDCNoPrompt()
-        else:
-            return self.auth_code.validate_authorization_request(request)
-
-    def validate_token_request(self, request):
-        return self.auth_code.validate_token_request(request)
-
+        # Hybrid flows can return the id_token from the authorization
+        # endpoint as part of the 'code' response
+        self.register_code_modifier(self.add_token)
+        self.register_code_modifier(self.add_id_token)
+        self.register_token_modifier(self.add_id_token)
diff --git a/oauthlib/oauth2/rfc6749/grant_types/refresh_token.py b/oauthlib/oauth2/rfc6749/grant_types/refresh_token.py
index cb26880..396668b 100644
--- a/oauthlib/oauth2/rfc6749/grant_types/refresh_token.py
+++ b/oauthlib/oauth2/rfc6749/grant_types/refresh_token.py
@@ -22,13 +22,13 @@ class RefreshTokenGrant(GrantTypeBase):
     .. _`Refresh token grant`: http://tools.ietf.org/html/rfc6749#section-6
     """
 
-    def __init__(self, request_validator=None, issue_new_refresh_tokens=True):
-        self.request_validator = request_validator or RequestValidator()
-        self.issue_new_refresh_tokens = issue_new_refresh_tokens
-        self._token_modifiers = []
-
-    def register_token_modifier(self, modifier):
-        self._token_modifiers.append(modifier)
+    def __init__(self, request_validator=None,
+                 issue_new_refresh_tokens=True,
+                 **kwargs):
+        super(RefreshTokenGrant, self).__init__(
+            request_validator,
+            issue_new_refresh_tokens=issue_new_refresh_tokens,
+            **kwargs)
 
     def create_token_response(self, request, token_handler):
         """Create a new access token from a refresh_token.
@@ -76,6 +76,9 @@ class RefreshTokenGrant(GrantTypeBase):
         if request.grant_type != 'refresh_token':
             raise errors.UnsupportedGrantTypeError(request=request)
 
+        for validator in self.custom_validators.pre_token:
+            validator(request)
+
         if request.refresh_token is None:
             raise errors.InvalidRequestError(
                 description='Missing refresh token parameter.',
@@ -123,3 +126,6 @@ class RefreshTokenGrant(GrantTypeBase):
                 raise errors.InvalidScopeError(request=request)
         else:
             request.scopes = original_scopes
+
+        for validator in self.custom_validators.post_token:
+            validator(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 0f4d65e..f755240 100644
--- a/oauthlib/oauth2/rfc6749/grant_types/resource_owner_password_credentials.py
+++ b/oauthlib/oauth2/rfc6749/grant_types/resource_owner_password_credentials.py
@@ -70,18 +70,6 @@ class ResourceOwnerPasswordCredentialsGrant(GrantTypeBase):
     .. _`Resource Owner Password Credentials Grant`: http://tools.ietf.org/html/rfc6749#section-4.3
     """
 
-    def __init__(self, request_validator=None, refresh_token=True):
-        """
-        If the refresh_token keyword argument is False, do not return
-        a refresh token in the response.
-        """
-        self.request_validator = request_validator or RequestValidator()
-        self.refresh_token = refresh_token
-        self._token_modifiers = []
-
-    def register_token_modifier(self, modifier):
-        self._token_modifiers.append(modifier)
-
     def create_token_response(self, request, token_handler):
         """Return token or error in json format.
 
@@ -168,6 +156,9 @@ class ResourceOwnerPasswordCredentialsGrant(GrantTypeBase):
         .. _`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
         """
+        for validator in self.custom_validators.pre_token:
+            validator(request)
+
         for param in ('grant_type', 'username', 'password'):
             if not getattr(request, param, None):
                 raise errors.InvalidRequestError(
@@ -201,3 +192,6 @@ class ResourceOwnerPasswordCredentialsGrant(GrantTypeBase):
         if request.client:
             request.client_id = request.client_id or request.client.client_id
         self.validate_scopes(request)
+
+        for validator in self.custom_validators.post_token:
+            validator(request)
diff --git a/setup.cfg b/setup.cfg
index 6bc2ff3..8bfd5a1 100644
--- a/setup.cfg
+++ b/setup.cfg
@@ -1,5 +1,4 @@
 [egg_info]
-tag_date = 0
 tag_build = 
-tag_svn_revision = 0
+tag_date = 0
 
diff --git a/setup.py b/setup.py
index e2870b2..718db43 100755
--- a/setup.py
+++ b/setup.py
@@ -50,7 +50,7 @@ setup(
     },
     install_requires=requires,
     classifiers=[
-        'Development Status :: 4 - Beta',
+        'Development Status :: 5 - Production/Stable',
         'Environment :: Web Environment',
         'Intended Audience :: Developers',
         'License :: OSI Approved',
@@ -59,11 +59,10 @@ setup(
         'Operating System :: POSIX',
         'Operating System :: POSIX :: Linux',
         'Programming Language :: Python',
-        'Programming Language :: Python :: 2.6',
         'Programming Language :: Python :: 2.7',
-        'Programming Language :: Python :: 3.2',
         'Programming Language :: Python :: 3.3',
         'Programming Language :: Python :: 3.4',
+        'Programming Language :: Python :: 3.5',
         'Programming Language :: Python :: Implementation',
         'Programming Language :: Python :: Implementation :: CPython',
         'Programming Language :: Python :: Implementation :: PyPy',
diff --git a/tests/oauth2/rfc6749/endpoints/test_prompt_handling.py b/tests/oauth2/rfc6749/endpoints/test_prompt_handling.py
new file mode 100644
index 0000000..bad424f
--- /dev/null
+++ b/tests/oauth2/rfc6749/endpoints/test_prompt_handling.py
@@ -0,0 +1,50 @@
+from __future__ import absolute_import, unicode_literals
+try:
+    from urllib.parse import urlencode
+except ImportError:
+    from urllib import urlencode
+
+import mock
+
+from ....unittest import TestCase
+from oauthlib.oauth2.rfc6749.tokens import BearerToken
+from oauthlib.oauth2.rfc6749.grant_types import OpenIDConnectAuthCode
+from oauthlib.oauth2.rfc6749.endpoints.authorization import AuthorizationEndpoint
+
+class OpenIDConnectEndpointTest(TestCase):
+
+    def setUp(self):
+        self.mock_validator = mock.MagicMock()
+        self.mock_validator.authenticate_client.side_effect = self.set_client
+        grant = OpenIDConnectAuthCode(request_validator=self.mock_validator)
+        bearer = BearerToken(self.mock_validator)
+        self.endpoint = AuthorizationEndpoint(grant, bearer,
+                                              response_types={'code': grant})
+        params = {
+            'prompt': 'consent',
+            'state': 'abc',
+            'redirect_uri': 'https://a.b/cb',
+            'response_type': 'code',
+            'client_id': 'abcdef',
+            'scope': 'hello openid'
+        }
+        self.url = 'http://a.b/path?' + urlencode(params)
+
+    def set_client(self, request):
+        request.client = mock.MagicMock()
+        request.client.client_id = 'mocked'
+        return True
+
+    @mock.patch('oauthlib.common.generate_token')
+    def test_authorization_endpoint_handles_prompt(self, generate_token):
+        generate_token.return_value = "MOCK_CODE"
+        # In the GET view:
+        scopes, creds = self.endpoint.validate_authorization_request(self.url)
+        # In the POST view:
+        creds['scopes'] = scopes
+        h, b, s = self.endpoint.create_authorization_response(self.url,
+                                                        credentials=creds)
+        expected = 'https://a.b/cb?state=abc&code=MOCK_CODE'
+        self.assertURLEqual(h['Location'], expected)
+        self.assertEqual(b, None)
+        self.assertEqual(s, 302)
diff --git a/tests/oauth2/rfc6749/grant_types/test_authorization_code.py b/tests/oauth2/rfc6749/grant_types/test_authorization_code.py
index 18cd3f2..c5e6869 100644
--- a/tests/oauth2/rfc6749/grant_types/test_authorization_code.py
+++ b/tests/oauth2/rfc6749/grant_types/test_authorization_code.py
@@ -32,6 +32,38 @@ class AuthorizationCodeGrantTest(TestCase):
         request.client.client_id = 'mocked'
         return True
 
+    def setup_validators(self):
+        self.authval1, self.authval2 = mock.Mock(), mock.Mock()
+        self.authval1.return_value = {}
+        self.authval2.return_value = {}
+        self.tknval1, self.tknval2 = mock.Mock(), mock.Mock()
+        self.tknval1.return_value = None
+        self.tknval2.return_value = None
+        self.auth.custom_validators.pre_token.append(self.tknval1)
+        self.auth.custom_validators.post_token.append(self.tknval2)
+        self.auth.custom_validators.pre_auth.append(self.authval1)
+        self.auth.custom_validators.post_auth.append(self.authval2)
+
+    def test_custom_auth_validators(self):
+        self.setup_validators()
+
+        bearer = BearerToken(self.mock_validator)
+        self.auth.create_authorization_response(self.request, bearer)
+        self.assertTrue(self.authval1.called)
+        self.assertTrue(self.authval2.called)
+        self.assertFalse(self.tknval1.called)
+        self.assertFalse(self.tknval2.called)
+
+    def test_custom_token_validators(self):
+        self.setup_validators()
+
+        bearer = BearerToken(self.mock_validator)
+        self.auth.create_token_response(self.request, bearer)
+        self.assertTrue(self.tknval1.called)
+        self.assertTrue(self.tknval2.called)
+        self.assertFalse(self.authval1.called)
+        self.assertFalse(self.authval2.called)
+
     def test_create_authorization_grant(self):
         bearer = BearerToken(self.mock_validator)
         h, b, s = self.auth.create_authorization_response(self.request, bearer)
diff --git a/tests/oauth2/rfc6749/grant_types/test_client_credentials.py b/tests/oauth2/rfc6749/grant_types/test_client_credentials.py
index 0865c7e..1698abf 100644
--- a/tests/oauth2/rfc6749/grant_types/test_client_credentials.py
+++ b/tests/oauth2/rfc6749/grant_types/test_client_credentials.py
@@ -22,6 +22,31 @@ class ClientCredentialsGrantTest(TestCase):
         self.auth = ClientCredentialsGrant(
                 request_validator=self.mock_validator)
 
+    def test_custom_auth_validators_unsupported(self):
+        authval1, authval2 = mock.Mock(), mock.Mock()
+        expected = ('ClientCredentialsGrant does not support authorization '
+                    'validators. Use token validators instead.')
+        with self.assertRaises(ValueError) as caught:
+            ClientCredentialsGrant(self.mock_validator, pre_auth=[authval1])
+        self.assertEqual(caught.exception.args[0], expected)
+        with self.assertRaises(ValueError) as caught:
+            ClientCredentialsGrant(self.mock_validator, post_auth=[authval2])
+        self.assertEqual(caught.exception.args[0], expected)
+        with self.assertRaises(AttributeError):
+            self.auth.custom_validators.pre_auth.append(authval1)
+        with self.assertRaises(AttributeError):
+            self.auth.custom_validators.pre_auth.append(authval2)
+
+    def test_custom_token_validators(self):
+        tknval1, tknval2 = mock.Mock(), mock.Mock()
+        self.auth.custom_validators.pre_token.append(tknval1)
+        self.auth.custom_validators.post_token.append(tknval2)
+
+        bearer = BearerToken(self.mock_validator)
+        self.auth.create_token_response(self.request, bearer)
+        self.assertTrue(tknval1.called)
+        self.assertTrue(tknval2.called)
+
     def test_create_token_response(self):
         bearer = BearerToken(self.mock_validator)
         headers, body, status_code = self.auth.create_token_response(
diff --git a/tests/oauth2/rfc6749/grant_types/test_implicit.py b/tests/oauth2/rfc6749/grant_types/test_implicit.py
index cdeecb7..53f4ac3 100644
--- a/tests/oauth2/rfc6749/grant_types/test_implicit.py
+++ b/tests/oauth2/rfc6749/grant_types/test_implicit.py
@@ -40,5 +40,24 @@ class ImplicitGrantTest(TestCase):
         h, b, s = self.auth.create_token_response(self.request, bearer)
         self.assertURLEqual(h['Location'], correct_uri)
 
+    def test_custom_validators(self):
+        self.authval1, self.authval2 = mock.Mock(), mock.Mock()
+        self.tknval1, self.tknval2 = mock.Mock(), mock.Mock()
+        for val in (self.authval1, self.authval2):
+            val.return_value = {}
+        for val in (self.tknval1, self.tknval2):
+            val.return_value = None
+        self.auth.custom_validators.pre_token.append(self.tknval1)
+        self.auth.custom_validators.post_token.append(self.tknval2)
+        self.auth.custom_validators.pre_auth.append(self.authval1)
+        self.auth.custom_validators.post_auth.append(self.authval2)
+
+        bearer = BearerToken(self.mock_validator)
+        self.auth.create_token_response(self.request, bearer)
+        self.assertTrue(self.tknval1.called)
+        self.assertTrue(self.tknval2.called)
+        self.assertTrue(self.authval1.called)
+        self.assertTrue(self.authval2.called)
+
     def test_error_response(self):
         pass
diff --git a/tests/oauth2/rfc6749/grant_types/test_refresh_token.py b/tests/oauth2/rfc6749/grant_types/test_refresh_token.py
index 125dc2b..5671155 100644
--- a/tests/oauth2/rfc6749/grant_types/test_refresh_token.py
+++ b/tests/oauth2/rfc6749/grant_types/test_refresh_token.py
@@ -36,6 +36,31 @@ class RefreshTokenGrantTest(TestCase):
         self.assertIn('expires_in', token)
         self.assertEqual(token['scope'], 'foo')
 
+    def test_custom_auth_validators_unsupported(self):
+        authval1, authval2 = mock.Mock(), mock.Mock()
+        expected = ('RefreshTokenGrant does not support authorization '
... 64 lines suppressed ...

-- 
Alioth's /usr/local/bin/git-commit-notice on /srv/git.debian.org/git/python-modules/packages/python-oauthlib.git



More information about the Python-modules-commits mailing list