summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorIb Lundgren <ib.lundgren@gmail.com>2012-08-13 23:32:35 +0200
committerIb Lundgren <ib.lundgren@gmail.com>2012-08-13 23:32:35 +0200
commit905b30e604d874c217c4e67a952dbeec63ced78d (patch)
tree9178214a5f0acbd8defec32d596eb9707f1e6ba8
parentb3a769e8a85bb3fbd3d39d6facf4386c768730af (diff)
downloadoauthlib-905b30e604d874c217c4e67a952dbeec63ced78d.tar.gz
backin it up
-rw-r--r--oauthlib/common.py3
-rw-r--r--oauthlib/oauth2/draft25/__init__.py264
-rw-r--r--oauthlib/oauth2/draft25/errors.py50
-rw-r--r--oauthlib/oauth2/draft25/grant_types.py75
-rw-r--r--oauthlib/oauth2/draft25/response_types.py60
-rw-r--r--oauthlib/oauth2/draft25/tokens.py10
-rw-r--r--oauthlib/oauth2/draft25/utils.py10
-rw-r--r--tests/oauth2/draft25/test_server.py60
8 files changed, 363 insertions, 169 deletions
diff --git a/oauthlib/common.py b/oauthlib/common.py
index c2ef553..143c77a 100644
--- a/oauthlib/common.py
+++ b/oauthlib/common.py
@@ -233,5 +233,4 @@ class Request(object):
@property
def uri_query_params(self):
- return urlparse.parse_qsl(self.uri_query, keep_blank_values=True,
- strict_parsing=True)
+ return urldecode(self.uri_query)
diff --git a/oauthlib/oauth2/draft25/__init__.py b/oauthlib/oauth2/draft25/__init__.py
index 779efec..2ca5c1f 100644
--- a/oauthlib/oauth2/draft25/__init__.py
+++ b/oauthlib/oauth2/draft25/__init__.py
@@ -5,14 +5,18 @@ oauthlib.oauth2.draft_25
This module is an implementation of various logic needed
for signing and checking OAuth 2.0 draft 25 requests.
"""
-from oauthlib.common import add_params_to_uri, generate_token
+from oauthlib.common import Request
from oauthlib.uri_validate import is_absolute_uri
-from tokens import prepare_bearer_uri, prepare_bearer_headers
-from tokens import prepare_bearer_body, prepare_mac_header
+from errors import OAuth2Error
+from grant_types import AuthorizationCodeGrantTokenHandler
from parameters import prepare_grant_uri, prepare_token_request
from parameters import parse_authorization_code_response
from parameters import parse_implicit_response, parse_token_response
-
+from response_types import AuthorizationCodeGrantCodeHandler, ImplicitGrantTokenHandler
+from tokens import BearerTokenHandler
+from tokens import prepare_bearer_uri, prepare_bearer_headers
+from tokens import prepare_bearer_body, prepare_mac_header
+from utils import params_from_uri
AUTH_HEADER = u'auth_header'
URI_QUERY = u'query'
@@ -520,51 +524,6 @@ class PasswordCredentialsClient(Client):
return response
-class OAuth2Error(Exception):
-# TODO: move into error.py
-
- def __init__(self, description=None, uri=None, state=None):
- """
- description: A human-readable ASCII [USASCII] text providing
- additional information, used to assist the client
- developer in understanding the error that occurred.
- Values for the "error_description" parameter MUST NOT
- include characters outside the set
- %x20-21 / %x23-5B / %x5D-7E.
-
- uri: A URI identifying a human-readable web page with information
- about the error, used to provide the client developer with
- additional information about the error. Values for the
- "error_uri" parameter MUST conform to the URI- Reference
- syntax, and thus MUST NOT include characters outside the set
- %x21 / %x23-5B / %x5D-7E.
-
- state: A CSRF protection value received from the client.
- """
- self.description = description
- self.uri = uri
- self.state = state
-
- @property
- def twotuples(self):
- error = [(u'error', self.error)]
- if self.description:
- error.append((u'error_description', self.description))
- if self.uri:
- error.append((u'error_uri', self.uri))
- if self.state:
- error.append((u'state', self.state))
- return error
-
- @property
- def urlencoded(self):
- pass
-
- @property
- def json(self):
- pass
-
-
class AuthorizationEndpoint(object):
"""Authorization endpoint - used by the client to obtain authorization
from the resource owner via user-agent redirection.
@@ -642,68 +601,71 @@ class AuthorizationEndpoint(object):
def __init__(self, valid_scopes=None):
self.valid_scopes = valid_scopes
- self.state = None
@property
def response_type_handlers(self):
return {
- u'code': AuthorizationGrantCodeHandler(),
- u'token': ImplicitGrantHandler(),
+ u'code': AuthorizationCodeGrantCodeHandler(),
+ u'token': ImplicitGrantTokenHandler(),
}
- def parse_authorization_parameters(self, uri):
- self.params = params_from_uri(uri)
- self.client_id = self.params.get(u'client_id', None)
- self.scopes = self.params.get(u'scope', None)
- self.redirect_uri = self.params.get(u'redirect_uri', None)
- self.response_type = self.params.get(u'response_type')
- self.state = self.params.get(u'state')
- self.validate_authorization_parameters()
-
- def validate_authorization_parameters(self):
-
- if not self.client_id:
- raise AuthorizationEndpoint.InvalidRequestError(state=self.state,
+ @property
+ def token_handler(self):
+ return BearerTokenHandler()
+
+ def parse_authorization_parameters(self, uri, http_method=u'GET', body=None, headers=None):
+ self.request = Request(uri, http_method=http_method, body=body, headers=headers)
+ self.request.params = params_from_uri(self.request.uri)
+ self.request.client_id = self.request.params.get(u'client_id', None)
+ self.request.scopes = self.request.params.get(u'scope', None)
+ self.request.redirect_uri = self.request.params.get(u'redirect_uri', None)
+ self.request.response_type = self.request.params.get(u'response_type')
+ self.request.state = self.request.params.get(u'state')
+ self.validate_request(self.request)
+
+ def validate_request(self, request):
+
+ if not request.client_id:
+ raise AuthorizationEndpoint.InvalidRequestError(state=request.state,
description=u'Missing client_id parameter.')
- if not self.response_type:
- raise AuthorizationEndpoint.InvalidRequestError(state=self.state,
+ if not request.response_type:
+ raise AuthorizationEndpoint.InvalidRequestError(state=request.state,
description=u'Missing response_type parameter.')
- if not self.validate_client(self.client_id):
- raise AuthorizationEndpoint.UnauthorizedClientError(state=self.state)
+ if not self.validate_client(request.client_id):
+ raise AuthorizationEndpoint.UnauthorizedClientError(state=request.state)
- if not self.response_type in self.response_type_handlers:
- raise AuthorizationEndpoint.UnsupportedResponseTypeError(state=self.state)
+ if not request.response_type in self.response_type_handlers:
+ raise AuthorizationEndpoint.UnsupportedResponseTypeError(state=request.state)
- if self.scopes:
- if not self.validate_scopes(self.client_id, self.scopes):
- raise AuthorizationEndpoint.InvalidScopeError(state=self.state)
+ if request.scopes:
+ if not self.validate_scopes(request.client_id, request.scopes):
+ raise AuthorizationEndpoint.InvalidScopeError(state=request.state)
else:
- self.scopes = self.get_default_scopes(self.client_id)
+ request.scopes = self.get_default_scopes(request.client_id)
- if self.redirect_uri:
- if not is_absolute_uri(self.redirect_uri):
- raise AuthorizationEndpoint.InvalidRequestError(state=self.state,
+ if request.redirect_uri:
+ if not is_absolute_uri(request.redirect_uri):
+ raise AuthorizationEndpoint.InvalidRequestError(state=request.state,
description=u'Non absolute redirect URI. See RFC3986')
- if not self.validate_redirect_uri(self.client_id, self.redirect_uri):
- raise AuthorizationEndpoint.AccessDeniedError(state=self.state)
+ if not self.validate_redirect_uri(request.client_id, request.redirect_uri):
+ raise AuthorizationEndpoint.AccessDeniedError(state=request.state)
else:
- self.redirect_uri = self.get_default_redirect_uri(self.client_id)
- if not self.redirect_uri:
- raise AuthorizationEndpoint.AccessDeniedError(state=self.state)
+ request.redirect_uri = self.get_default_redirect_uri(request.client_id)
+ if not request.redirect_uri:
+ raise AuthorizationEndpoint.AccessDeniedError(state=request.state)
return True
def create_authorization_response(self, authorized_scopes):
- self.scopes = authorized_scopes
-
- if not self.response_type in self.response_type_handlers:
+ self.request.scopes = authorized_scopes
+ if not self.request.response_type in self.response_type_handlers:
raise AuthorizationEndpoint.UnsupportedResponseTypeError(
- state=self.state, description=u'Invalid response type')
+ state=self.request.state, description=u'Invalid response type')
- return self.response_type_handlers.get(self.response_type)(self)
+ return self.response_type_handlers.get(self.request.response_type)(self)
def validate_client(self, client_id):
raise NotImplementedError('Subclasses must implement this method.')
@@ -736,93 +698,83 @@ class AuthorizationEndpoint(object):
raise NotImplementedError('Subclasses must implement this method.')
-def params_from_uri(uri):
- import urlparse
- query = urlparse.urlparse(uri).query
- params = dict(urlparse.parse_qsl(query))
- if u'scope' in params:
- params[u'scope'] = params[u'scope'].split(u' ')
- return params
-
-
-class AuthorizationGrantCodeHandler(object):
+class TokenEndpoint(object):
- def __call__(self, endpoint):
- self.endpoint = endpoint
- try:
- self.endpoint.validate_authorization_parameters()
+ class InvalidRequestError(OAuth2Error):
+ """The request is missing a required parameter, includes an unsupported
+ parameter value (other than grant type), repeats a parameter, includes
+ multiple credentials, utilizes more than one mechanism for
+ authenticating the client, or is otherwise malformed.
+ """
+ error = u'invalid_request'
- except OAuth2Error as e:
- return add_params_to_uri(self.endpoint.redirect_uri, e.twotuples)
+ class InvalidClientError(OAuth2Error):
+ """Client authentication failed (e.g. unknown client, no client
+ authentication included, or unsupported authentication method).
+ The authorization server MAY return an HTTP 401 (Unauthorized) status
+ code to indicate which HTTP authentication schemes are supported.
+ If the client attempted to authenticate via the "Authorization" request
+ header field, the authorization server MUST respond with an
+ HTTP 401 (Unauthorized) status code, and include the "WWW-Authenticate"
+ response header field matching the authentication scheme used by the
+ client.
+ """
+ error = u'invalid_client'
- self.grant = self.create_authorization_grant()
- self.endpoint.save_authorization_grant(
- self.endpoint.client_id, self.grant, state=self.endpoint.state)
- return add_params_to_uri(self.endpoint.redirect_uri, self.grant.items())
+ class InvalidGrantError(OAuth2Error):
+ """The provided authorization grant (e.g. authorization code, resource
+ owner credentials) or refresh token is invalid, expired, revoked, does
+ not match the redirection URI used in the authorization request, or was
+ issued to another client.
+ """
+ error = u'invalid_grant'
- def create_authorization_grant(self):
- """Generates an authorization grant represented as a dictionary."""
- grant = {u'code': generate_token()}
- if self.endpoint.state:
- grant[u'state'] = self.endpoint.state
- return grant
+ class Unauthorized_clientError(OAuth2Error):
+ """The authenticated client is not authorized to use this authorization
+ grant type.
+ """
+ error = u'unauthorized_client'
+ class UnsupportedGrantTypeError(OAuth2Error):
+ """The authorization grant type is not supported by the authorization
+ server.
+ """
+ error = u'unsupported_grant_type'
-class ImplicitGrantHandler(object):
+ class InvalidScopeError(OAuth2Error):
+ """The requested scope is invalid, unknown, malformed, or exceeds the
+ scope granted by the resource owner.
+ """
+ error = u'invalid_scope'
@property
- def expires_in(self):
- return 3600
+ def token_handler(self):
+ return BearerTokenHandler()
@property
- def token_type(self):
- return u'Bearer'
-
- def create_implicit_grant(self):
+ def grant_type_handlers(self):
return {
- u'access_token': generate_token(),
- u'token_type': self.token_type,
- u'expires_in': self.expires_in,
- u'scope': ' '.join(self.endpoint.scopes),
- u'state': self.endpoint.state
+ u'authorization_code': AuthorizationCodeGrantTokenHandler(),
}
- def __call__(self, endpoint):
- self.endpoint = endpoint
- try:
- self.endpoint.validate_authorization_parameters()
-
- except OAuth2Error as e:
- return add_params_to_uri(
- self.endpoint.redirect_uri, e.twotuples, fragment=True)
-
- self.grant = self.create_implicit_grant()
- self.endpoint.save_implicit_grant(
- self.endpoint.client_id, self.grant, state=self.endpoint.state)
- return add_params_to_uri(
- self.endpoint.redirect_uri, self.grant.items(), fragment=True)
-
-
-class TokenEndpoint(object):
-
- def access_token(self, uri, body, http_method=u'GET', headers=None):
+ def create_token_response(self, body, http_method=u'GET', uri=None, headers=None):
"""Validate client, code etc, return body + headers"""
- pass
+ self.request = Request(uri, http_method, body, headers)
+ self.request.params = dict(self.request.decoded_body)
+ if not u'grant_type' in self.request.params:
+ raise TokenEndpoint.InvalidRequestError(description=u'Missing grant_type parameter.')
- def validate_authorization_code(self, client_id):
- """Validate the authorization code.
+ self.request.grant_type = self.request.params.get(u'grant_type')
+ if not self.request.grant_type in self.grant_type_handlers:
+ raise TokenEndpoint.UnsupportedGrantTypeError()
- The client MUST NOT use the authorization code more than once. If an
- authorization code is used more than once, the authorization server
- MUST deny the request and SHOULD revoke (when possible) all tokens
- previously issued based on that authorization code. The authorization
- code is bound to the client identifier and redirection URI.
- """
- pass
+ return self.grant_type_handlers.get(self.request.grant_type)(self)
class ResourceEndpoint(object):
- pass
+ @property
+ def grant_type_handlers(self):
+ return None
class Server(AuthorizationEndpoint, TokenEndpoint, ResourceEndpoint):
diff --git a/oauthlib/oauth2/draft25/errors.py b/oauthlib/oauth2/draft25/errors.py
new file mode 100644
index 0000000..0dcd646
--- /dev/null
+++ b/oauthlib/oauth2/draft25/errors.py
@@ -0,0 +1,50 @@
+"""
+oauthlib.oauth2.draft_25.errors
+~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+"""
+from oauthlib.common import urlencode
+import json
+
+
+class OAuth2Error(Exception):
+
+ def __init__(self, description=None, uri=None, state=None):
+ """
+ description: A human-readable ASCII [USASCII] text providing
+ additional information, used to assist the client
+ developer in understanding the error that occurred.
+ Values for the "error_description" parameter MUST NOT
+ include characters outside the set
+ %x20-21 / %x23-5B / %x5D-7E.
+
+ uri: A URI identifying a human-readable web page with information
+ about the error, used to provide the client developer with
+ additional information about the error. Values for the
+ "error_uri" parameter MUST conform to the URI- Reference
+ syntax, and thus MUST NOT include characters outside the set
+ %x21 / %x23-5B / %x5D-7E.
+
+ state: A CSRF protection value received from the client.
+ """
+ self.description = description
+ self.uri = uri
+ self.state = state
+
+ @property
+ def twotuples(self):
+ error = [(u'error', self.error)]
+ if self.description:
+ error.append((u'error_description', self.description))
+ if self.uri:
+ error.append((u'error_uri', self.uri))
+ if self.state:
+ error.append((u'state', self.state))
+ return error
+
+ @property
+ def urlencoded(self):
+ return urlencode(self.twotuples)
+
+ @property
+ def json(self):
+ return json.dumps(self.twotuples)
diff --git a/oauthlib/oauth2/draft25/grant_types.py b/oauthlib/oauth2/draft25/grant_types.py
new file mode 100644
index 0000000..8dabc71
--- /dev/null
+++ b/oauthlib/oauth2/draft25/grant_types.py
@@ -0,0 +1,75 @@
+"""
+oauthlib.oauth2.draft_25.errors
+~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+"""
+from oauthlib.common import generate_token
+from errors import OAuth2Error
+import json
+
+
+class AuthorizationCodeGrantTokenHandler(object):
+
+ @property
+ def expires_in(self):
+ return 3600
+
+ def create_token(self):
+ return {
+ u'access_token': generate_token(),
+ u'refresh_token': generate_token(),
+ u'expires_in': self.expires_in,
+ u'scope': ' '.join(self.scopes),
+ }
+
+ def validate_request(self, request):
+
+ # This will likely already be checked but including anyway
+ if not request.grant_type == u'authorization_code':
+ raise self.endpoint.UnsupportedGrantTypeError()
+
+ if not request.code:
+ raise self.endpoint.InvalidRequestError(
+ description=u'Missing code parameter.')
+
+ if not self.endpoint.client:
+ raise self.endpoint.InvalidClientError(u'unrecognized client')
+
+ if not self.validate_client(self.endpoint.client, request.grant_type):
+ raise self.endpoint.UnauthorizedClientError()
+
+ if not self.validate_code(self.endpoint.client, request.code):
+ raise self.endpoint.InvalidGrantError()
+
+ def validate_client(self, client, grant_type):
+ raise NotImplementedError('Subclasses must implement this method.')
+
+ def validate_code(self, client, code):
+ raise NotImplementedError('Subclasses must implement this method.')
+
+ def get_scopes(self, client, code):
+ raise NotImplementedError('Subclasses must implement this method.')
+
+ def __call__(self, endpoint):
+ """Validate the authorization code.
+
+ The client MUST NOT use the authorization code more than once. If an
+ authorization code is used more than once, the authorization server
+ MUST deny the request and SHOULD revoke (when possible) all tokens
+ previously issued based on that authorization code. The authorization
+ code is bound to the client identifier and redirection URI.
+ """
+ self.endpoint = endpoint
+ self.endpoint.request.grant_type = self.endpoint.request.params.get(u'grant_type')
+ self.endpoint.request.code = self.endpoint.request.params.get(u'code')
+ self.endpoint.request.redirect_uri = self.endpoint.request.params.get(u'redirect_uri')
+
+ try:
+ self.validate_request(self.endpoint.request)
+
+ except OAuth2Error as e:
+ return e.json
+
+ self.scopes = self.get_scopes(self.endpoint.client, self.endpoint.request.code)
+ self.token = self.create_token()
+ self.token = self.endpoint.token_handler(self, self.token)
+ return json.dumps(self.token)
diff --git a/oauthlib/oauth2/draft25/response_types.py b/oauthlib/oauth2/draft25/response_types.py
new file mode 100644
index 0000000..f5ee43b
--- /dev/null
+++ b/oauthlib/oauth2/draft25/response_types.py
@@ -0,0 +1,60 @@
+"""
+oauthlib.oauth2.draft_25.response_types
+~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+"""
+from oauthlib.common import add_params_to_uri, generate_token
+from errors import OAuth2Error
+
+
+class AuthorizationCodeGrantCodeHandler(object):
+
+ def __call__(self, endpoint):
+ self.endpoint = endpoint
+ try:
+ self.endpoint.validate_request(self.endpoint.request)
+
+ except OAuth2Error as e:
+ return add_params_to_uri(self.endpoint.request.redirect_uri, e.twotuples)
+
+ self.grant = self.create_authorization_grant()
+ self.endpoint.save_authorization_grant(
+ self.endpoint.request.client_id, self.grant, state=self.endpoint.request.state)
+ return add_params_to_uri(self.endpoint.request.redirect_uri, self.grant.items())
+
+ def create_authorization_grant(self):
+ """Generates an authorization grant represented as a dictionary."""
+ grant = {u'code': generate_token()}
+ if self.endpoint.request.state:
+ grant[u'state'] = self.endpoint.request.state
+ return grant
+
+
+class ImplicitGrantTokenHandler(object):
+
+ @property
+ def expires_in(self):
+ return 3600
+
+ def create_token(self):
+ return {
+ u'access_token': generate_token(),
+ u'expires_in': self.expires_in,
+ u'scope': ' '.join(self.endpoint.request.scopes),
+ u'state': self.endpoint.request.state
+ }
+
+ def __call__(self, endpoint):
+ self.endpoint = endpoint
+ try:
+ self.endpoint.validate_request(self.endpoint.request)
+
+ except OAuth2Error as e:
+ return add_params_to_uri(
+ self.endpoint.request.redirect_uri, e.twotuples, fragment=True)
+
+ self.token = self.create_token()
+ self.token = self.endpoint.token_handler(self, self.token)
+ self.endpoint.save_implicit_grant(
+ self.endpoint.request.client_id, self.token, state=self.endpoint.request.state)
+ return add_params_to_uri(
+ self.endpoint.request.redirect_uri, self.token.items(), fragment=True)
diff --git a/oauthlib/oauth2/draft25/tokens.py b/oauthlib/oauth2/draft25/tokens.py
index 74491fb..79fe7a2 100644
--- a/oauthlib/oauth2/draft25/tokens.py
+++ b/oauthlib/oauth2/draft25/tokens.py
@@ -130,3 +130,13 @@ def prepare_bearer_body(token, body=u''):
.. _`Bearer Token`: http://tools.ietf.org/html/draft-ietf-oauth-v2-bearer-18
"""
return add_params_to_qs(body, [((u'access_token', token))])
+
+
+class BearerTokenHandler(object):
+
+ def __call__(self, endpoint, grant):
+ grant[u'token_type'] = u'Bearer'
+ return grant
+
+ def validate(self, parameters):
+ pass
diff --git a/oauthlib/oauth2/draft25/utils.py b/oauthlib/oauth2/draft25/utils.py
index 1a2c5e5..fe28c31 100644
--- a/oauthlib/oauth2/draft25/utils.py
+++ b/oauthlib/oauth2/draft25/utils.py
@@ -8,6 +8,8 @@ This module contains utility methods used by various parts of the OAuth 2 spec.
import urllib
import urlparse
+from oauthlib.common import urldecode
+
def scope_to_string(scope):
"""Convert a list of scopes to a space separated string."""
@@ -46,6 +48,14 @@ def host_from_uri(uri):
return netloc, port
+def params_from_uri(uri):
+ query = urlparse.urlparse(uri).query
+ params = dict(urldecode(query))
+ if u'scope' in params:
+ params[u'scope'] = scope_to_list(params[u'scope'])
+ return params
+
+
def escape(u):
"""Escape a string in an OAuth-compatible fashion.
diff --git a/tests/oauth2/draft25/test_server.py b/tests/oauth2/draft25/test_server.py
index 9c797df..f747553 100644
--- a/tests/oauth2/draft25/test_server.py
+++ b/tests/oauth2/draft25/test_server.py
@@ -2,7 +2,9 @@
from __future__ import absolute_import
from ...unittest import TestCase
-from oauthlib.oauth2.draft25 import AuthorizationEndpoint
+from oauthlib.oauth2.draft25 import AuthorizationEndpoint, TokenEndpoint
+from oauthlib.oauth2.draft25.grant_types import AuthorizationCodeGrantTokenHandler
+import json
class AuthorizationEndpointTest(TestCase):
@@ -19,8 +21,8 @@ class AuthorizationEndpointTest(TestCase):
base_uri = u'http://a.b/authorize?client_id=%s&state=%s&response_type=%s'
uri = base_uri % (state, client_id, u'code')
- uri_scope = uri + u'&scope=%s' % u' '.join(default_scope)
- uri_scopes = uri + u'&scope=%s' % u' '.join(scopes)
+ uri_scope = uri + u'&scope=%s' % u'+'.join(default_scope)
+ uri_scopes = uri + u'&scope=%s' % u'+'.join(scopes)
uri_redirect = uri + u'&redirect_uri=%s' % default_redirect_uri
uri_redirect_extra = uri_redirect + u'%26extra%3Dparameter'
uri_extra = uri_redirect + u'&extra=parameter'
@@ -29,9 +31,9 @@ class AuthorizationEndpointTest(TestCase):
implicit_uri_redirect = implicit_uri + u'&redirect_uri=%s' % default_redirect_uri
implicit_uri_redirect_extra = implicit_uri_redirect + u'%26extra%3Dparameter'
- uri_missing = u'http%3A%2f%2fno.client.id'
+ uri_missing = u'http://no.client.id'
uri_unsupported = u'http://a.b/?client_id=a&response_type=invalid'
- uri_scope_invalid = uri + u'&scope=%s' % u'invalid scope'
+ uri_scope_invalid = uri + u'&scope=%s' % u'invalid%20scope'
uri_redirect_invalid = uri_redirect + u'%23notabsolute'
class SimpleAuthorizationEndpoint(AuthorizationEndpoint):
@@ -68,13 +70,13 @@ class AuthorizationEndpointTest(TestCase):
for uri, scope, extras in tests:
ae = self.SimpleAuthorizationEndpoint(valid_scopes=self.scopes_decoded)
ae.parse_authorization_parameters(uri)
- self.assertEqual(ae.response_type, u'code')
- self.assertEqual(ae.client_id, self.client_id)
- self.assertEqual(ae.scopes, scope or self.default_scope)
- self.assertEqual(ae.redirect_uri, self.default_redirect_uri_decoded)
- self.assertEqual(ae.state, self.state)
+ self.assertEqual(ae.request.response_type, u'code')
+ self.assertEqual(ae.request.client_id, self.client_id)
+ self.assertEqual(ae.request.scopes, scope or self.default_scope)
+ self.assertEqual(ae.request.redirect_uri, self.default_redirect_uri_decoded)
+ self.assertEqual(ae.request.state, self.state)
for attr, value in extras:
- self.assertEqual(ae.params.get(attr), value)
+ self.assertEqual(ae.request.params.get(attr), value)
def test_invalid_authorization_parameters(self):
@@ -128,6 +130,7 @@ class AuthorizationEndpointTest(TestCase):
ae = self.SimpleAuthorizationEndpoint(valid_scopes=self.scopes_decoded)
ae.parse_authorization_parameters(uri)
setattr(ae, name, attr)
+ setattr(ae.request, name, attr)
response_uri = ae.create_authorization_response(self.scopes_decoded)
self.assertIn(u'error', response_uri)
self.assertIn(result, response_uri)
@@ -141,3 +144,38 @@ class AuthorizationEndpointTest(TestCase):
self.assertRaises(NotImplementedError, ae.get_default_redirect_uri, None)
self.assertRaises(NotImplementedError, ae.save_authorization_grant, None, None)
self.assertRaises(NotImplementedError, ae.save_implicit_grant, None, None)
+
+
+class TokenEndpointTest(TestCase):
+
+ default_redirect_uri = u'http%3A%2f%2fdefault.redirect%2Furi'
+ default_redirect_uri_decoded = u'http://default.redirect/uri'
+
+ body = u'grant_type=authorization_code&code=abc'
+ body_response = json.loads('{"hello":"yes"}')
+ body_redirect = body + u'&redirect_uri=%s' % default_redirect_uri
+
+ class SimpleAuthorizationCodeTokenHandler(AuthorizationCodeGrantTokenHandler):
+
+ def validate_client(self, client, grant_type):
+ return True
+
+ def validate_code(self, client, code):
+ return True
+
+ def get_scopes(self, client, code):
+ return ['hello', 'world']
+
+ class SimpleTokenEndpoint(TokenEndpoint):
+
+ @property
+ def grant_type_handlers(self):
+ return {
+ u'authorization_code': TokenEndpointTest.SimpleAuthorizationCodeTokenHandler()
+ }
+
+ def test_authorization_token_request(self):
+ te = TokenEndpointTest.SimpleTokenEndpoint()
+ te.client = u'dummyvalue'
+ print te.create_token_response(self.body)
+ self.assertEqual(json.loads(te.create_token_response(self.body)), self.body_response)