diff options
author | Ib Lundgren <ib.lundgren@gmail.com> | 2012-08-13 23:32:35 +0200 |
---|---|---|
committer | Ib Lundgren <ib.lundgren@gmail.com> | 2012-08-13 23:32:35 +0200 |
commit | 905b30e604d874c217c4e67a952dbeec63ced78d (patch) | |
tree | 9178214a5f0acbd8defec32d596eb9707f1e6ba8 | |
parent | b3a769e8a85bb3fbd3d39d6facf4386c768730af (diff) | |
download | oauthlib-905b30e604d874c217c4e67a952dbeec63ced78d.tar.gz |
backin it up
-rw-r--r-- | oauthlib/common.py | 3 | ||||
-rw-r--r-- | oauthlib/oauth2/draft25/__init__.py | 264 | ||||
-rw-r--r-- | oauthlib/oauth2/draft25/errors.py | 50 | ||||
-rw-r--r-- | oauthlib/oauth2/draft25/grant_types.py | 75 | ||||
-rw-r--r-- | oauthlib/oauth2/draft25/response_types.py | 60 | ||||
-rw-r--r-- | oauthlib/oauth2/draft25/tokens.py | 10 | ||||
-rw-r--r-- | oauthlib/oauth2/draft25/utils.py | 10 | ||||
-rw-r--r-- | tests/oauth2/draft25/test_server.py | 60 |
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) |