[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