summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorTyler Jones <tyler@squirly.ca>2013-08-01 15:29:58 -0700
committerTyler Jones <tyler@squirly.ca>2013-08-01 15:29:58 -0700
commitf538ea8f87947d7c1543a8c0fcea5b0242a12ab6 (patch)
tree76c496c92ab2a23fa8cd5c47500b8547cb5ddf21
parentf794cf31971274766378faf140d60e5ec3807286 (diff)
downloadoauthlib-f538ea8f87947d7c1543a8c0fcea5b0242a12ab6.tar.gz
#200 First attempt at API cleanup to match OAuth1.
-rw-r--r--docs/oauth2/endpoints.rst23
-rw-r--r--docs/oauth2/server.rst34
-rw-r--r--oauthlib/oauth2/rfc6749/__init__.py4
-rw-r--r--oauthlib/oauth2/rfc6749/endpoints/base.py4
-rw-r--r--oauthlib/oauth2/rfc6749/grant_types/authorization_code.py10
-rw-r--r--oauthlib/oauth2/rfc6749/grant_types/client_credentials.py4
-rw-r--r--oauthlib/oauth2/rfc6749/grant_types/implicit.py8
-rw-r--r--oauthlib/oauth2/rfc6749/grant_types/refresh_token.py4
-rw-r--r--oauthlib/oauth2/rfc6749/grant_types/resource_owner_password_credentials.py4
-rw-r--r--tests/oauth2/rfc6749/test_grant_types.py22
-rw-r--r--tests/oauth2/rfc6749/test_server.py30
-rw-r--r--tests/oauth2/rfc6749/test_servers.py178
12 files changed, 179 insertions, 146 deletions
diff --git a/docs/oauth2/endpoints.rst b/docs/oauth2/endpoints.rst
index aa73d46..1441938 100644
--- a/docs/oauth2/endpoints.rst
+++ b/docs/oauth2/endpoints.rst
@@ -79,9 +79,8 @@ Grant and the Client Credentials Grant.
except FatalClientError as e:
# this is your custom error page
- from your_views import authorization_error_page_uri
- # Use in_uri to embed error code and description in the redirect uri
- redirect(e.in_uri(authorization_error_page_uri))
+ from your_view_helpers import error_to_response
+ return error_to_response(e)
**Post Authorization Request**
@@ -107,23 +106,22 @@ Grant and the Client Credentials Grant.
scopes = request.POST.get('scopes')
from oauthlib.oauth2 import FatalClientError, OAuth2Error
- from your_framework import redirect
+ from your_framework import http_response
+ http_response(body, status=status, headers=headers)
try:
- uri, headers, body, status = server.create_authorization_response(
+ headers, body, status = server.create_authorization_response(
uri, http_method, body, headers, scopes, credentials)
- # uri = https://foo.com/welcome_back?code=somerandomstring&state=xyz
- # headers = {}, this might change to include suggested headers related
+ # headers = {'Location': 'https://foo.com/welcome_back?code=somerandomstring&state=xyz'}, this might change to include suggested headers related
# to cache best practices etc.
# body = '', this might be set in future custom grant types
# status = 302, suggested HTTP status code
- redirect(uri, headers=headers, status=status, body=body)
+ return http_response(body, status=status, headers=headers)
except FatalClientError as e:
# this is your custom error page
- from your_views import authorization_error_page_uri
- # Use in_uri to embed error code and description in the redirect uri
- redirect(e.in_uri(authorization_error_page_uri))
+ from your_view_helpers import error_to_response
+ return error_to_response(e)
except OAuth2Error as e:
# Less grave errors will be reported back to client
@@ -181,10 +179,9 @@ tokens which unless you are certain you need them, are a bad idea.
# Extra credentials you wish to include
credentials = {'client_ip': '1.2.3.4'}
- uri, headers, body, status = server.create_token_response(
+ headers, body, status = server.create_token_response(
uri, http_method, body, headers, credentials)
- # uri is not used by most grant types
# headers will contain some suggested headers to add to your response
{
'Content-Type': 'application/json;charset=UTF-8',
diff --git a/docs/oauth2/server.rst b/docs/oauth2/server.rst
index 22e5d43..cba56d1 100644
--- a/docs/oauth2/server.rst
+++ b/docs/oauth2/server.rst
@@ -260,7 +260,6 @@ as well as provide an interface for a backend to store tokens, clients, etc.
def __init__(self):
# Using the server from previous section
self._authorization_endpoint = server
- self._error_uri = '/error'
def get(self, request):
# You need to define extract_params and make sure it does not
@@ -288,7 +287,7 @@ as well as provide an interface for a backend to store tokens, clients, etc.
# Errors that should be shown to the user on the provider website
except errors.FatalClientError as e:
- return HttpResponseRedirect(e.in_uri(self._error_uri))
+ return response_from_error(e)
# Errors embedded in the redirect URI back to the client
except errors.OAuth2Error as e:
@@ -297,7 +296,7 @@ as well as provide an interface for a backend to store tokens, clients, etc.
@csrf_exempt
def post(self, request):
uri, http_method, body, headers = extract_params(request)
-
+
# The scopes the user actually authorized, i.e. checkboxes
# that were selected.
scopes = request.POST.getlist(['scopes'])
@@ -309,15 +308,12 @@ as well as provide an interface for a backend to store tokens, clients, etc.
credentials.update(request.session.get('oauth2_credentials', {}))
try:
- url, headers, body, status = self._authorization_endpoint.create_authorization_response(
+ headers, body, status = self._authorization_endpoint.create_authorization_response(
uri, http_method, body, headers, scopes, credentials)
- return HttpResponseRedirect(url)
+ return response_from_return(headers, body, status)
except errors.FatalClientError as e:
- return HttpResponseRedirect(e.in_uri(self._error_uri))
-
- except errors.OAuth2Error as e:
- return HttpResponseRedirect(e.in_uri(redirect_uri))
+ return response_from_error(e)
# Handles requests to /token
class TokenView(View):
@@ -333,21 +329,23 @@ as well as provide an interface for a backend to store tokens, clients, etc.
# use in the validator, do so here.
credentials = {'foo': 'bar'}
- url, headers, body, status = self._token_endpoint.create_token_response(
+ headers, body, status = self._token_endpoint.create_token_response(
uri, http_method, body, headers, credentials)
# All requests to /token will return a json response, no redirection.
- response = HttpResponse(content=body, status=status)
- for k, v in headers.items():
- response[k] = v
- return response
-
+ return response_from_return(headers, body, status)
- class ErrorView(View):
- response = HttpResponse()
- response.write('Evil client is unable to send a proper request.')
+ def response_from_return(headers, body, status):
+ response = HttpResponse(content=body, status=status)
+ for k, v in headers.items():
+ response[k] = v
return response
+ def response_from_error(e)
+ return HttpResponseBadRequest('Evil client is unable to send a proper request. Error is: ' + e.description)
+
+
+
**5. Protect your APIs using scopes**
Let's define a decorator we can use to protect the views.
diff --git a/oauthlib/oauth2/rfc6749/__init__.py b/oauthlib/oauth2/rfc6749/__init__.py
index c82c06a..6903955 100644
--- a/oauthlib/oauth2/rfc6749/__init__.py
+++ b/oauthlib/oauth2/rfc6749/__init__.py
@@ -43,7 +43,7 @@ def catch_errors_and_unavailability(f):
if not endpoint.available:
e = TemporarilyUnavailableError()
log.info('Endpoint unavailable, ignoring request %s.' % uri)
- return None, {}, e.json, 503
+ return {}, e.json, 503
if endpoint.catch_errors:
try:
@@ -55,7 +55,7 @@ def catch_errors_and_unavailability(f):
except Exception as e:
error = ServerError()
log.warning('Exception caught while processing request, %s.' % e)
- return None, {}, error.json, 500
+ return {}, error.json, 500
else:
return f(endpoint, uri, *args, **kwargs)
return wrapper
diff --git a/oauthlib/oauth2/rfc6749/endpoints/base.py b/oauthlib/oauth2/rfc6749/endpoints/base.py
index 41b3aef..984de2f 100644
--- a/oauthlib/oauth2/rfc6749/endpoints/base.py
+++ b/oauthlib/oauth2/rfc6749/endpoints/base.py
@@ -44,7 +44,7 @@ def catch_errors_and_unavailability(f):
if not endpoint.available:
e = TemporarilyUnavailableError()
log.info('Endpoint unavailable, ignoring request %s.' % uri)
- return None, {}, e.json, 503
+ return {}, e.json, 503
if endpoint.catch_errors:
try:
@@ -56,7 +56,7 @@ def catch_errors_and_unavailability(f):
except Exception as e:
error = ServerError()
log.warning('Exception caught while processing request, %s.' % e)
- return None, {}, error.json, 500
+ return {}, error.json, 500
else:
return f(endpoint, uri, *args, **kwargs)
return wrapper
diff --git a/oauthlib/oauth2/rfc6749/grant_types/authorization_code.py b/oauthlib/oauth2/rfc6749/grant_types/authorization_code.py
index 55f70f3..71d018b 100644
--- a/oauthlib/oauth2/rfc6749/grant_types/authorization_code.py
+++ b/oauthlib/oauth2/rfc6749/grant_types/authorization_code.py
@@ -131,7 +131,7 @@ class AuthorizationCodeGrant(GrantTypeBase):
:param request: oauthlib.commong.Request
:param token_handler: A token handler instace, for example of type
oauthlib.oauth2.BearerToken.
- :returns: uri, headers, body, status
+ :returns: headers, body, status
:raises: FatalClientError on invalid redirect URI or client id.
ValueError if scopes are not set on the request object.
@@ -203,12 +203,12 @@ class AuthorizationCodeGrant(GrantTypeBase):
except errors.OAuth2Error as e:
log.debug('Client error during validation of %r. %r.', request, e)
request.redirect_uri = request.redirect_uri or self.error_uri
- return common.add_params_to_uri(request.redirect_uri, e.twotuples), None, None, e.status_code
+ return {'Location': common.add_params_to_uri(request.redirect_uri, e.twotuples)}, None, 302
grant = self.create_authorization_code(request)
log.debug('Saving grant %r for %r.', grant, request)
self.request_validator.save_authorization_code(request.client_id, grant, request)
- return common.add_params_to_uri(request.redirect_uri, grant.items()), None, None, 302
+ return {'Location': common.add_params_to_uri(request.redirect_uri, grant.items())}, None, 302
def create_token_response(self, request, token_handler):
"""Validate the authorization code.
@@ -229,12 +229,12 @@ class AuthorizationCodeGrant(GrantTypeBase):
log.debug('Token request validation ok for %r.', request)
except errors.OAuth2Error as e:
log.debug('Client error during validation of %r. %r.', request, e)
- return None, headers, e.json, e.status_code
+ return headers, e.json, e.status_code
token = token_handler.create_token(request, refresh_token=True)
self.request_validator.invalidate_authorization_code(
request.client_id, request.code, request)
- return None, headers, json.dumps(token), 200
+ return headers, json.dumps(token), 200
def validate_authorization_request(self, request):
"""Check the authorization request for normal and fatal errors.
diff --git a/oauthlib/oauth2/rfc6749/grant_types/client_credentials.py b/oauthlib/oauth2/rfc6749/grant_types/client_credentials.py
index b2bfff3..6641f1f 100644
--- a/oauthlib/oauth2/rfc6749/grant_types/client_credentials.py
+++ b/oauthlib/oauth2/rfc6749/grant_types/client_credentials.py
@@ -66,12 +66,12 @@ class ClientCredentialsGrant(GrantTypeBase):
self.validate_token_request(request)
except errors.OAuth2Error as e:
log.debug('Client error in token request. %s.', e)
- return None, {}, e.json, e.status_code
+ return {}, e.json, e.status_code
token = token_handler.create_token(request, refresh_token=False)
log.debug('Issuing token to client id %r (%r), %r.',
request.client_id, request.client, token)
- return None, {}, json.dumps(token), 200
+ return {}, json.dumps(token), 200
def validate_token_request(self, request):
if not getattr(request, 'grant_type'):
diff --git a/oauthlib/oauth2/rfc6749/grant_types/implicit.py b/oauthlib/oauth2/rfc6749/grant_types/implicit.py
index 7e2cc54..0761287 100644
--- a/oauthlib/oauth2/rfc6749/grant_types/implicit.py
+++ b/oauthlib/oauth2/rfc6749/grant_types/implicit.py
@@ -220,12 +220,12 @@ class ImplicitGrant(GrantTypeBase):
# http://tools.ietf.org/html/rfc6749#appendix-B
except errors.OAuth2Error as e:
log.debug('Client error during validation of %r. %r.', request, e)
- return common.add_params_to_uri(request.redirect_uri, e.twotuples,
- fragment=True), {}, None, e.status_code
+ return {'Location': common.add_params_to_uri(request.redirect_uri, e.twotuples,
+ fragment=True)}, None, 302
token = token_handler.create_token(request, refresh_token=False)
- return common.add_params_to_uri(request.redirect_uri, token.items(),
- fragment=True), {}, None, 302
+ return {'Location': common.add_params_to_uri(request.redirect_uri, token.items(),
+ fragment=True)}, None, 302
def validate_authorization_request(self, request):
return self.validate_token_request(request)
diff --git a/oauthlib/oauth2/rfc6749/grant_types/refresh_token.py b/oauthlib/oauth2/rfc6749/grant_types/refresh_token.py
index 8ea176e..644f7eb 100644
--- a/oauthlib/oauth2/rfc6749/grant_types/refresh_token.py
+++ b/oauthlib/oauth2/rfc6749/grant_types/refresh_token.py
@@ -54,13 +54,13 @@ class RefreshTokenGrant(GrantTypeBase):
log.debug('Validating refresh token request, %r.', request)
self.validate_token_request(request)
except errors.OAuth2Error as e:
- return None, headers, e.json, e.status_code
+ return headers, e.json, e.status_code
token = token_handler.create_token(request,
refresh_token=self.issue_new_refresh_tokens)
log.debug('Issuing new token to client id %r (%r), %r.',
request.client_id, request.client, token)
- return None, headers, json.dumps(token), 200
+ return headers, json.dumps(token), 200
def validate_token_request(self, request):
# REQUIRED. Value MUST be set to "refresh_token".
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 5b991c6..8629518 100644
--- a/oauthlib/oauth2/rfc6749/grant_types/resource_owner_password_credentials.py
+++ b/oauthlib/oauth2/rfc6749/grant_types/resource_owner_password_credentials.py
@@ -105,12 +105,12 @@ class ResourceOwnerPasswordCredentialsGrant(GrantTypeBase):
self.validate_token_request(request)
except errors.OAuth2Error as e:
log.debug('Client error in token request, %s.', e)
- return None, headers, e.json, e.status_code
+ return headers, e.json, e.status_code
token = token_handler.create_token(request, refresh_token=True)
log.debug('Issuing token %r to client id %r (%r) and username %s.',
token, request.client_id, request.client, request.username)
- return None, headers, json.dumps(token), 200
+ return headers, json.dumps(token), 200
def validate_token_request(self, request):
"""
diff --git a/tests/oauth2/rfc6749/test_grant_types.py b/tests/oauth2/rfc6749/test_grant_types.py
index 3830d3b..6aee0e8 100644
--- a/tests/oauth2/rfc6749/test_grant_types.py
+++ b/tests/oauth2/rfc6749/test_grant_types.py
@@ -70,7 +70,7 @@ class AuthorizationCodeGrantTest(TestCase):
def test_create_token_response(self):
bearer = BearerToken(self.mock_validator)
- u, h, token, s = self.auth.create_token_response(self.request, bearer)
+ h, token, s = self.auth.create_token_response(self.request, bearer)
token = json.loads(token)
self.assertIn('access_token', token)
self.assertIn('refresh_token', token)
@@ -122,10 +122,12 @@ class ImplicitGrantTest(TestCase):
orig_generate_token = common.generate_token
self.addCleanup(setattr, common, 'generate_token', orig_generate_token)
common.generate_token = lambda *args, **kwargs: '1234'
- uri, headers, body, status_code = self.auth.create_token_response(
+ headers, body, status_code = self.auth.create_token_response(
self.request, bearer)
correct_uri = 'https://b.c/p#access_token=1234&token_type=Bearer&expires_in=1800&state=xyz&scope=hello+world'
- self.assertURLEqual(uri, correct_uri, parse_fragment=True)
+ self.assertEqual(status_code, 302)
+ self.assertIn('Location', headers)
+ self.assertURLEqual(headers['Location'], correct_uri, parse_fragment=True)
def test_error_response(self):
pass
@@ -148,7 +150,7 @@ class ResourceOwnerPasswordCredentialsGrantTest(TestCase):
def test_create_token_response(self):
bearer = BearerToken(self.mock_validator)
- uri, headers, body, status_code = self.auth.create_token_response(
+ headers, body, status_code = self.auth.create_token_response(
self.request, bearer)
token = json.loads(body)
self.assertIn('access_token', token)
@@ -178,7 +180,7 @@ class ClientCredentialsGrantTest(TestCase):
def test_create_token_response(self):
bearer = BearerToken(self.mock_validator)
- uri, headers, body, status_code = self.auth.create_token_response(
+ headers, body, status_code = self.auth.create_token_response(
self.request, bearer)
token = json.loads(body)
self.assertIn('access_token', token)
@@ -210,7 +212,7 @@ class RefreshTokenGrantTest(TestCase):
def test_create_token_response(self):
self.mock_validator.get_original_scopes.return_value = ['foo', 'bar']
bearer = BearerToken(self.mock_validator)
- uri, headers, body, status_code = self.auth.create_token_response(
+ headers, body, status_code = self.auth.create_token_response(
self.request, bearer)
token = json.loads(body)
self.assertIn('access_token', token)
@@ -222,7 +224,7 @@ class RefreshTokenGrantTest(TestCase):
self.request.scope = None
self.mock_validator.get_original_scopes.return_value = ['foo', 'bar']
bearer = BearerToken(self.mock_validator)
- uri, headers, body, status_code = self.auth.create_token_response(
+ headers, body, status_code = self.auth.create_token_response(
self.request, bearer)
token = json.loads(body)
self.assertIn('access_token', token)
@@ -233,7 +235,7 @@ class RefreshTokenGrantTest(TestCase):
def test_invalid_scope(self):
self.mock_validator.get_original_scopes.return_value = ['baz']
bearer = BearerToken(self.mock_validator)
- uri, headers, body, status_code = self.auth.create_token_response(
+ headers, body, status_code = self.auth.create_token_response(
self.request, bearer)
token = json.loads(body)
self.assertEqual(token['error'], 'invalid_scope')
@@ -242,7 +244,7 @@ class RefreshTokenGrantTest(TestCase):
def test_invalid_token(self):
self.mock_validator.validate_refresh_token.return_value = False
bearer = BearerToken(self.mock_validator)
- uri, headers, body, status_code = self.auth.create_token_response(
+ headers, body, status_code = self.auth.create_token_response(
self.request, bearer)
token = json.loads(body)
self.assertEqual(token['error'], 'invalid_grant')
@@ -251,7 +253,7 @@ class RefreshTokenGrantTest(TestCase):
def test_invalid_client(self):
self.mock_validator.authenticate_client.return_value = False
bearer = BearerToken(self.mock_validator)
- uri, headers, body, status_code = self.auth.create_token_response(
+ headers, body, status_code = self.auth.create_token_response(
self.request, bearer)
token = json.loads(body)
self.assertEqual(token['error'], 'invalid_client')
diff --git a/tests/oauth2/rfc6749/test_server.py b/tests/oauth2/rfc6749/test_server.py
index 24503b6..b6ad6c9 100644
--- a/tests/oauth2/rfc6749/test_server.py
+++ b/tests/oauth2/rfc6749/test_server.py
@@ -41,35 +41,39 @@ class AuthorizationEndpointTest(TestCase):
def test_authorization_grant(self):
uri = 'http://i.b/l?response_type=code&client_id=me&scope=all+of+them&state=xyz'
uri += '&redirect_uri=http%3A%2F%2Fback.to%2Fme'
- uri, headers, body, status_code = self.endpoint.create_authorization_response(
+ headers, body, status_code = self.endpoint.create_authorization_response(
uri, scopes=['all', 'of', 'them'])
- self.assertURLEqual(uri, 'http://back.to/me?code=abc&state=xyz')
+ self.assertIn('Location', headers)
+ self.assertURLEqual(headers['Location'], 'http://back.to/me?code=abc&state=xyz')
@mock.patch('oauthlib.common.generate_token', new=lambda: 'abc')
def test_implicit_grant(self):
uri = 'http://i.b/l?response_type=token&client_id=me&scope=all+of+them&state=xyz'
uri += '&redirect_uri=http%3A%2F%2Fback.to%2Fme'
- uri, headers, body, status_code = self.endpoint.create_authorization_response(
+ headers, body, status_code = self.endpoint.create_authorization_response(
uri, scopes=['all', 'of', 'them'])
- self.assertURLEqual(uri, 'http://back.to/me#access_token=abc&expires_in=' + str(self.expires_in) + '&token_type=Bearer&state=xyz&scope=all+of+them', parse_fragment=True)
+ self.assertIn('Location', headers)
+ self.assertURLEqual(headers['Location'], 'http://back.to/me#access_token=abc&expires_in=' + str(self.expires_in) + '&token_type=Bearer&state=xyz&scope=all+of+them', parse_fragment=True)
def test_missing_type(self):
uri = 'http://i.b/l?client_id=me&scope=all+of+them'
uri += '&redirect_uri=http%3A%2F%2Fback.to%2Fme'
self.mock_validator.validate_request = mock.MagicMock(
side_effect=errors.InvalidRequestError())
- uri, headers, body, status_code = self.endpoint.create_authorization_response(
+ headers, body, status_code = self.endpoint.create_authorization_response(
uri, scopes=['all', 'of', 'them'])
- self.assertURLEqual(uri, 'http://back.to/me?error=invalid_request&error_description=Missing+response_type+parameter.')
+ self.assertIn('Location', headers)
+ self.assertURLEqual(headers['Location'], 'http://back.to/me?error=invalid_request&error_description=Missing+response_type+parameter.')
def test_invalid_type(self):
uri = 'http://i.b/l?response_type=invalid&client_id=me&scope=all+of+them'
uri += '&redirect_uri=http%3A%2F%2Fback.to%2Fme'
self.mock_validator.validate_request = mock.MagicMock(
side_effect=errors.UnsupportedResponseTypeError())
- uri, headers, body, status_code = self.endpoint.create_authorization_response(
+ headers, body, status_code = self.endpoint.create_authorization_response(
uri, scopes=['all', 'of', 'them'])
- self.assertURLEqual(uri, 'http://back.to/me?error=unsupported_response_type')
+ self.assertIn('Location', headers)
+ self.assertURLEqual(headers['Location'], 'http://back.to/me?error=unsupported_response_type')
class TokenEndpointTest(TestCase):
@@ -104,7 +108,7 @@ class TokenEndpointTest(TestCase):
@mock.patch('oauthlib.common.generate_token', new=lambda: 'abc')
def test_authorization_grant(self):
body = 'grant_type=authorization_code&code=abc&scope=all+of+them&state=xyz'
- uri, headers, body, status_code = self.endpoint.create_token_response(
+ headers, body, status_code = self.endpoint.create_token_response(
'', body=body)
token = {
'token_type': 'Bearer',
@@ -118,7 +122,7 @@ class TokenEndpointTest(TestCase):
@mock.patch('oauthlib.common.generate_token', new=lambda: 'abc')
def test_password_grant(self):
body = 'grant_type=password&username=a&password=hello&scope=all+of+them'
- uri, headers, body, status_code = self.endpoint.create_token_response(
+ headers, body, status_code = self.endpoint.create_token_response(
'', body=body)
token = {
'token_type': 'Bearer',
@@ -132,7 +136,7 @@ class TokenEndpointTest(TestCase):
@mock.patch('oauthlib.common.generate_token', new=lambda: 'abc')
def test_client_grant(self):
body = 'grant_type=client_credentials&scope=all+of+them'
- uri, headers, body, status_code = self.endpoint.create_token_response(
+ headers, body, status_code = self.endpoint.create_token_response(
'', body=body)
token = {
'token_type': 'Bearer',
@@ -143,13 +147,13 @@ class TokenEndpointTest(TestCase):
self.assertEqual(json.loads(body), token)
def test_missing_type(self):
- _, _, body, _ = self.endpoint.create_token_response('', body='')
+ _, body, _ = self.endpoint.create_token_response('', body='')
token = {'error': 'unsupported_grant_type'}
self.assertEqual(json.loads(body), token)
def test_invalid_type(self):
body = 'grant_type=invalid'
- _, _, body, _ = self.endpoint.create_token_response('', body=body)
+ _, body, _ = self.endpoint.create_token_response('', body=body)
token = {'error': 'unsupported_grant_type'}
self.assertEqual(json.loads(body), token)
diff --git a/tests/oauth2/rfc6749/test_servers.py b/tests/oauth2/rfc6749/test_servers.py
index 4f85a95..1a26d7c 100644
--- a/tests/oauth2/rfc6749/test_servers.py
+++ b/tests/oauth2/rfc6749/test_servers.py
@@ -86,29 +86,34 @@ class TestScopeHandling(TestCase):
token_uri = 'http://example.com/path'
# authorization grant
- uri, _, _, _ = self.web.create_authorization_response(
+ h, _, s = self.web.create_authorization_response(
auth_uri + 'code', scopes=decoded_scope.split(' '))
self.validator.validate_code.side_effect = self.set_scopes(decoded_scope.split(' '))
- code = get_query_credentials(uri)['code'][0]
- _, _, body, _ = self.web.create_token_response(token_uri,
+ self.assertEqual(s, 302)
+ self.assertIn('Location', h)
+ code = get_query_credentials(h['Location'])['code'][0]
+ _, body, _ = self.web.create_token_response(token_uri,
body='grant_type=authorization_code&code=%s' % code)
self.assertEqual(json.loads(body)['scope'], decoded_scope)
# implicit grant
- uri, _, _, _ = self.mobile.create_authorization_response(
+ h, _, s = self.mobile.create_authorization_response(
auth_uri + 'token', scopes=decoded_scope.split(' '))
- self.assertEqual(get_fragment_credentials(uri)['scope'][0], decoded_scope)
+ self.assertEqual(s, 302)
+ self.assertIn('Location', h)
+ self.assertEqual(get_fragment_credentials(h['Location'])['scope'][0], decoded_scope)
# resource owner password credentials grant
body = 'grant_type=password&username=abc&password=secret&scope=%s'
- _, _, body, _ = self.legacy.create_token_response(token_uri,
+
+ _, body, _ = self.legacy.create_token_response(token_uri,
body=body % scope)
self.assertEqual(json.loads(body)['scope'], decoded_scope)
# client credentials grant
body = 'grant_type=client_credentials&scope=%s'
self.validator.authenticate_client.side_effect = self.set_user
- _, _, body, _ = self.backend.create_token_response(token_uri,
+ _, body, _ = self.backend.create_token_response(token_uri,
body=body % scope)
self.assertEqual(json.loads(body)['scope'], decoded_scope)
@@ -120,24 +125,28 @@ class TestScopeHandling(TestCase):
token_uri = 'http://example.com/path'
# authorization grant
- uri, _, _, _ = self.web.create_authorization_response(
+ h, _, s = self.web.create_authorization_response(
auth_uri + 'code', scopes=scopes)
- code = get_query_credentials(uri)['code'][0]
+ self.assertEqual(s, 302)
+ self.assertIn('Location', h)
+ code = get_query_credentials(h['Location'])['code'][0]
self.validator.validate_code.side_effect = self.set_scopes(scopes)
- _, _, body, _ = self.web.create_token_response(token_uri,
+ _, body, _ = self.web.create_token_response(token_uri,
body='grant_type=authorization_code&code=%s' % code)
self.assertEqual(json.loads(body)['scope'], decoded_scope)
# implicit grant
self.validator.validate_scopes.side_effect = self.set_scopes(scopes)
- uri, _, _, _ = self.mobile.create_authorization_response(
+ h, _, s = self.mobile.create_authorization_response(
auth_uri + 'token', scopes=scopes)
- self.assertEqual(get_fragment_credentials(uri)['scope'][0], decoded_scope)
+ self.assertEqual(s, 302)
+ self.assertIn('Location', h)
+ self.assertEqual(get_fragment_credentials(h['Location'])['scope'][0], decoded_scope)
# resource owner password credentials grant
self.validator.validate_scopes.side_effect = self.set_scopes(scopes)
body = 'grant_type=password&username=abc&password=secret&scope=%s'
- _, _, body, _ = self.legacy.create_token_response(token_uri,
+ _, body, _ = self.legacy.create_token_response(token_uri,
body=body % scope)
self.assertEqual(json.loads(body)['scope'], decoded_scope)
@@ -145,8 +154,9 @@ class TestScopeHandling(TestCase):
self.validator.validate_scopes.side_effect = self.set_scopes(scopes)
self.validator.authenticate_client.side_effect = self.set_user
body = 'grant_type=client_credentials&scope=%s'
- _, _, body, _ = self.backend.create_token_response(token_uri,
+ _, body, _ = self.backend.create_token_response(token_uri,
body=body % scope)
+
self.assertEqual(json.loads(body)['scope'], decoded_scope)
def test_invalid_scope(self):
@@ -157,27 +167,31 @@ class TestScopeHandling(TestCase):
self.validator.validate_scopes.return_value = False
# authorization grant
- uri, _, _, _ = self.web.create_authorization_response(
+ h, _, s = self.web.create_authorization_response(
auth_uri + 'code', scopes=['invalid'])
- error = get_query_credentials(uri)['error'][0]
+ self.assertEqual(s, 302)
+ self.assertIn('Location', h)
+ error = get_query_credentials(h['Location'])['error'][0]
self.assertEqual(error, 'invalid_scope')
# implicit grant
- uri, _, _, _ = self.mobile.create_authorization_response(
+ h, _, s = self.mobile.create_authorization_response(
auth_uri + 'token', scopes=['invalid'])
- error = get_fragment_credentials(uri)['error'][0]
+ self.assertEqual(s, 302)
+ self.assertIn('Location', h)
+ error = get_fragment_credentials(h['Location'])['error'][0]
self.assertEqual(error, 'invalid_scope')
# resource owner password credentials grant
body = 'grant_type=password&username=abc&password=secret&scope=%s'
- _, _, body, _ = self.legacy.create_token_response(token_uri,
+ _, body, _ = self.legacy.create_token_response(token_uri,
body=body % scope)
self.assertEqual(json.loads(body)['error'], 'invalid_scope')
# client credentials grant
self.validator.authenticate_client.side_effect = self.set_user
body = 'grant_type=client_credentials&scope=%s'
- _, _, body, _ = self.backend.create_token_response(token_uri,
+ _, body, _ = self.backend.create_token_response(token_uri,
body=body % scope)
self.assertEqual(json.loads(body)['error'], 'invalid_scope')
@@ -207,18 +221,22 @@ class PreservationTest(TestCase):
token_uri = 'http://example.com/path'
# authorization grant
- uri, _, _, _ = self.web.create_authorization_response(
+ h, _, s = self.web.create_authorization_response(
auth_uri + 'code', scopes=['random'])
- code = get_query_credentials(uri)['code'][0]
+ self.assertEqual(s, 302)
+ self.assertIn('Location', h)
+ code = get_query_credentials(h['Location'])['code'][0]
self.validator.validate_code.side_effect = self.set_state('xyz')
- _, _, body, _ = self.web.create_token_response(token_uri,
+ _, body, _ = self.web.create_token_response(token_uri,
body='grant_type=authorization_code&code=%s' % code)
self.assertEqual(json.loads(body)['state'], 'xyz')
# implicit grant
- uri, _, _, _ = self.mobile.create_authorization_response(
+ h, _, s = self.mobile.create_authorization_response(
auth_uri + 'token', scopes=['random'])
- self.assertEqual(get_fragment_credentials(uri)['state'][0], 'xyz')
+ self.assertEqual(s, 302)
+ self.assertIn('Location', h)
+ self.assertEqual(get_fragment_credentials(h['Location'])['state'][0], 'xyz')
def test_redirect_uri_preservation(self):
auth_uri = 'http://example.com/path?redirect_uri=http%3A%2F%2Fi.b%2Fpath&client_id=abc'
@@ -226,22 +244,26 @@ class PreservationTest(TestCase):
token_uri = 'http://example.com/path'
# authorization grant
- uri, _, _, _ = self.web.create_authorization_response(
+ h, _, s = self.web.create_authorization_response(
auth_uri + '&response_type=code', scopes=['random'])
- self.assertTrue(uri.startswith(redirect_uri))
+ self.assertEqual(s, 302)
+ self.assertIn('Location', h)
+ self.assertTrue(h['Location'].startswith(redirect_uri))
# confirm_redirect_uri should return false if the redirect uri
# was given in the authorization but not in the token request.
self.validator.confirm_redirect_uri.return_value = False
- code = get_query_credentials(uri)['code'][0]
- _, _, body, _ = self.web.create_token_response(token_uri,
+ code = get_query_credentials(h['Location'])['code'][0]
+ _, body, _ = self.web.create_token_response(token_uri,
body='grant_type=authorization_code&code=%s' % code)
self.assertEqual(json.loads(body)['error'], 'access_denied')
# implicit grant
- uri, _, _, _ = self.mobile.create_authorization_response(
+ h, _, s = self.mobile.create_authorization_response(
auth_uri + '&response_type=token', scopes=['random'])
- self.assertTrue(uri.startswith(redirect_uri))
+ self.assertEqual(s, 302)
+ self.assertIn('Location', h)
+ self.assertTrue(h['Location'].startswith(redirect_uri))
def test_invalid_redirect_uri(self):
auth_uri = 'http://example.com/path?redirect_uri=http%3A%2F%2Fi.b%2Fpath&client_id=abc'
@@ -313,13 +335,13 @@ class ClientAuthenticationTest(TestCase):
# authorization code grant
self.validator.authenticate_client.return_value = False
self.validator.authenticate_client_id.return_value = False
- _, _, body, _ = self.web.create_token_response(token_uri,
+ _, body, _ = self.web.create_token_response(token_uri,
body='grant_type=authorization_code&code=mock')
self.assertEqual(json.loads(body)['error'], 'invalid_client')
self.validator.authenticate_client_id.return_value = True
self.validator.authenticate_client.side_effect = self.set_client
- _, _, body, _ = self.web.create_token_response(token_uri,
+ _, body, _ = self.web.create_token_response(token_uri,
body='grant_type=authorization_code&code=mock')
self.assertIn('access_token', json.loads(body))
@@ -329,8 +351,10 @@ class ClientAuthenticationTest(TestCase):
auth_uri, scopes=['random'])
self.validator.validate_client_id.side_effect = self.set_client_id
- uri, _, _, _ = self.mobile.create_authorization_response(auth_uri, scopes=['random'])
- self.assertIn('access_token', get_fragment_credentials(uri))
+ h, _, s = self.mobile.create_authorization_response(auth_uri, scopes=['random'])
+ self.assertEqual(302, s)
+ self.assertIn('Location', h)
+ self.assertIn('access_token', get_fragment_credentials(h['Location']))
def test_custom_authentication(self):
token_uri = 'http://example.com/path'
@@ -397,16 +421,18 @@ class ResourceOwnerAssociationTest(TestCase):
def test_web_application(self):
# TODO: code generator + intercept test
- uri, _, _, _ = self.web.create_authorization_response(
+ h, _, s = self.web.create_authorization_response(
self.auth_uri + '&response_type=code',
credentials={'user': 'test'}, scopes=['random'])
- code = get_query_credentials(uri)['code'][0]
+ self.assertEqual(s, 302)
+ self.assertIn('Location', h)
+ code = get_query_credentials(h['Location'])['code'][0]
self.assertRaises(ValueError,
self.web.create_token_response, self.token_uri,
body='grant_type=authorization_code&code=%s' % code)
self.validator.validate_code.side_effect = self.set_user
- _, _, body, _ = self.web.create_token_response(self.token_uri,
+ _, body, _ = self.web.create_token_response(self.token_uri,
body='grant_type=authorization_code&code=%s' % code)
self.assertEqual(json.loads(body)['access_token'], 'abc')
@@ -415,10 +441,12 @@ class ResourceOwnerAssociationTest(TestCase):
self.mobile.create_authorization_response,
self.auth_uri + '&response_type=token')
- uri, _, _, _ = self.mobile.create_authorization_response(
+ h, _, s = self.mobile.create_authorization_response(
self.auth_uri + '&response_type=token',
credentials={'user': 'test'}, scopes=['random'])
- self.assertEqual(get_fragment_credentials(uri)['access_token'][0], 'abc')
+ self.assertEqual(s, 302)
+ self.assertIn('Location', h)
+ self.assertEqual(get_fragment_credentials(h['Location'])['access_token'][0], 'abc')
def test_legacy_application(self):
body = 'grant_type=password&username=abc&password=secret'
@@ -427,7 +455,7 @@ class ResourceOwnerAssociationTest(TestCase):
self.token_uri, body=body)
self.validator.validate_user.side_effect = self.set_user_from_username
- _, _, body, _ = self.legacy.create_token_response(
+ _, body, _ = self.legacy.create_token_response(
self.token_uri, body=body)
self.assertEqual(json.loads(body)['access_token'], 'abc')
@@ -438,7 +466,7 @@ class ResourceOwnerAssociationTest(TestCase):
self.token_uri, body=body)
self.validator.authenticate_client.side_effect = self.set_user_from_credentials
- _, _, body, _ = self.backend.create_token_response(
+ _, body, _ = self.backend.create_token_response(
self.token_uri, body=body)
self.assertEqual(json.loads(body)['access_token'], 'abc')
@@ -546,15 +574,17 @@ class ErrorResponseTest(TestCase):
self.assertRaises(errors.InvalidRequestError,
self.web.validate_authorization_request,
uri.format('code'))
- url, _, _, _ = self.web.create_authorization_response(
+ h, _, s = self.web.create_authorization_response(
uri.format('code'), scopes=['foo'])
- self.assertIn('error=invalid_request', url)
+ self.assertEqual(s, 302)
+ self.assertIn('Location', h)
+ self.assertIn('error=invalid_request', h['Location'])
invalid_bodies = [
# duplicate params
'grant_type=authorization_code&client_id=nope&client_id=nope&code=foo'
]
for body in invalid_bodies:
- _, _, body, _ = self.web.create_token_response(token_uri,
+ _, body, _ = self.web.create_token_response(token_uri,
body=body)
self.assertEqual('invalid_request', json.loads(body)['error'])
@@ -563,9 +593,11 @@ class ErrorResponseTest(TestCase):
self.assertRaises(errors.InvalidRequestError,
self.mobile.validate_authorization_request,
uri.format('token'))
- url, _, _, _ = self.mobile.create_authorization_response(
+ h, _, s = self.mobile.create_authorization_response(
uri.format('token'), scopes=['foo'])
- self.assertIn('error=invalid_request', url)
+ self.assertEqual(s, 302)
+ self.assertIn('Location', h)
+ self.assertIn('error=invalid_request', h['Location'])
# Password credentials grant
invalid_bodies = [
@@ -578,7 +610,7 @@ class ErrorResponseTest(TestCase):
]
self.validator.authenticate_client.side_effect = self.set_client
for body in invalid_bodies:
- _, _, body, _ = self.legacy.create_token_response(token_uri,
+ _, body, _ = self.legacy.create_token_response(token_uri,
body=body)
self.assertEqual('invalid_request', json.loads(body)['error'])
@@ -588,7 +620,7 @@ class ErrorResponseTest(TestCase):
'grant_type=client_credentials&scope=foo&scope=bar'
]
for body in invalid_bodies:
- _, _, body, _ = self.backend.create_token_response(token_uri,
+ _, body, _ = self.backend.create_token_response(token_uri,
body=body)
self.assertEqual('invalid_request', json.loads(body)['error'])
@@ -603,7 +635,7 @@ class ErrorResponseTest(TestCase):
self.assertRaises(errors.UnauthorizedClientError,
self.web.validate_authorization_request,
'https://i.b/auth?response_type=code&client_id=foo')
- _, _, body, _ = self.web.create_token_response(token_uri,
+ _, body, _ = self.web.create_token_response(token_uri,
body='grant_type=authorization_code&code=foo')
self.assertEqual('unauthorized_client', json.loads(body)['error'])
@@ -613,12 +645,12 @@ class ErrorResponseTest(TestCase):
'https://i.b/auth?response_type=token&client_id=foo')
# Password credentials grant
- _, _, body, _ = self.legacy.create_token_response(token_uri,
+ _, body, _ = self.legacy.create_token_response(token_uri,
body='grant_type=password&username=foo&password=bar')
self.assertEqual('unauthorized_client', json.loads(body)['error'])
# Client credentials grant
- _, _, body, _ = self.backend.create_token_response(token_uri,
+ _, body, _ = self.backend.create_token_response(token_uri,
body='grant_type=client_credentials')
self.assertEqual('unauthorized_client', json.loads(body)['error'])
@@ -627,7 +659,7 @@ class ErrorResponseTest(TestCase):
self.validator.confirm_redirect_uri.return_value = False
token_uri = 'https://i.b/token'
# Authorization code grant
- _, _, body, _ = self.web.create_token_response(token_uri,
+ _, body, _ = self.web.create_token_response(token_uri,
body='grant_type=authorization_code&code=foo')
self.assertEqual('access_denied', json.loads(body)['error'])
@@ -660,13 +692,13 @@ class ErrorResponseTest(TestCase):
'https://i.b/auth?response_type=token&client_id=foo')
# Password credentials grant
- _, _, body, _ = self.legacy.create_token_response(
+ _, body, _ = self.legacy.create_token_response(
'https://i.b/token',
body='grant_type=password&username=foo&password=bar')
self.assertEqual('invalid_scope', json.loads(body)['error'])
# Client credentials grant
- _, _, body, _ = self.backend.create_token_response(
+ _, body, _ = self.backend.create_token_response(
'https://i.b/token',
body='grant_type=client_credentials')
self.assertEqual('invalid_scope', json.loads(body)['error'])
@@ -681,11 +713,11 @@ class ErrorResponseTest(TestCase):
# Authorization code grant
self.web.catch_errors = True
- _, _, _, s = self.web.create_authorization_response(
+ _, _, s = self.web.create_authorization_response(
'https://i.b/auth?client_id=foo&response_type=code',
scopes=['foo'])
self.assertEqual(s, 500)
- _, _, _, s = self.web.create_token_response(
+ _, _, s = self.web.create_token_response(
'https://i.b/token',
body='grant_type=authorization_code&code=foo',
scopes=['foo'])
@@ -693,21 +725,21 @@ class ErrorResponseTest(TestCase):
# Implicit grant
self.mobile.catch_errors = True
- _, _, _, s = self.mobile.create_authorization_response(
+ _, _, s = self.mobile.create_authorization_response(
'https://i.b/auth?client_id=foo&response_type=token',
scopes=['foo'])
self.assertEqual(s, 500)
# Password credentials grant
self.legacy.catch_errors = True
- _, _, _, s = self.legacy.create_token_response(
+ _, _, s = self.legacy.create_token_response(
'https://i.b/token',
body='grant_type=password&username=foo&password=foo')
self.assertEqual(s, 500)
# Client credentials grant
self.backend.catch_errors = True
- _, _, _, s = self.backend.create_token_response(
+ _, _, s = self.backend.create_token_response(
'https://i.b/token',
body='grant_type=client_credentials')
self.assertEqual(s, 500)
@@ -715,11 +747,11 @@ class ErrorResponseTest(TestCase):
def test_temporarily_unavailable(self):
# Authorization code grant
self.web.available = False
- _, _, _, s = self.web.create_authorization_response(
+ _, _, s = self.web.create_authorization_response(
'https://i.b/auth?client_id=foo&response_type=code',
scopes=['foo'])
self.assertEqual(s, 503)
- _, _, _, s = self.web.create_token_response(
+ _, _, s = self.web.create_token_response(
'https://i.b/token',
body='grant_type=authorization_code&code=foo',
scopes=['foo'])
@@ -727,21 +759,21 @@ class ErrorResponseTest(TestCase):
# Implicit grant
self.mobile.available = False
- _, _, _, s = self.mobile.create_authorization_response(
+ _, _, s = self.mobile.create_authorization_response(
'https://i.b/auth?client_id=foo&response_type=token',
scopes=['foo'])
self.assertEqual(s, 503)
# Password credentials grant
self.legacy.available = False
- _, _, _, s = self.legacy.create_token_response(
+ _, _, s = self.legacy.create_token_response(
'https://i.b/token',
body='grant_type=password&username=foo&password=foo')
self.assertEqual(s, 503)
# Client credentials grant
self.backend.available = False
- _, _, _, s = self.backend.create_token_response(
+ _, _, s = self.backend.create_token_response(
'https://i.b/token',
body='grant_type=client_credentials')
self.assertEqual(s, 503)
@@ -751,17 +783,17 @@ class ErrorResponseTest(TestCase):
self.validator.authenticate_client_id.return_value = False
# Authorization code grant
- _, _, body, _ = self.web.create_token_response('https://i.b/token',
+ _, body, _ = self.web.create_token_response('https://i.b/token',
body='grant_type=authorization_code&code=foo')
self.assertEqual('invalid_client', json.loads(body)['error'])
# Password credentials grant
- _, _, body, _ = self.legacy.create_token_response('https://i.b/token',
+ _, body, _ = self.legacy.create_token_response('https://i.b/token',
body='grant_type=password&username=foo&password=bar')
self.assertEqual('invalid_client', json.loads(body)['error'])
# Client credentials grant
- _, _, body, _ = self.legacy.create_token_response('https://i.b/token',
+ _, body, _ = self.legacy.create_token_response('https://i.b/token',
body='grant_type=client_credentials')
self.assertEqual('invalid_client', json.loads(body)['error'])
@@ -770,13 +802,13 @@ class ErrorResponseTest(TestCase):
# Authorization code grant
self.validator.validate_code.return_value = False
- _, _, body, _ = self.web.create_token_response('https://i.b/token',
+ _, body, _ = self.web.create_token_response('https://i.b/token',
body='grant_type=authorization_code&code=foo')
self.assertEqual('invalid_grant', json.loads(body)['error'])
# Password credentials grant
self.validator.validate_user.return_value = False
- _, _, body, _ = self.legacy.create_token_response('https://i.b/token',
+ _, body, _ = self.legacy.create_token_response('https://i.b/token',
body='grant_type=password&username=foo&password=bar')
self.assertEqual('invalid_grant', json.loads(body)['error'])
@@ -784,17 +816,17 @@ class ErrorResponseTest(TestCase):
self.validator.authenticate_client.side_effect = self.set_client
# Authorization code grant
- _, _, body, _ = self.web.create_token_response('https://i.b/token',
+ _, body, _ = self.web.create_token_response('https://i.b/token',
body='grant_type=bar&code=foo')
self.assertEqual('unsupported_grant_type', json.loads(body)['error'])
# Password credentials grant
- _, _, body, _ = self.legacy.create_token_response('https://i.b/token',
+ _, body, _ = self.legacy.create_token_response('https://i.b/token',
body='grant_type=bar&username=foo&password=bar')
self.assertEqual('unsupported_grant_type', json.loads(body)['error'])
# Client credentials grant
- _, _, body, _ = self.backend.create_token_response('https://i.b/token',
+ _, body, _ = self.backend.create_token_response('https://i.b/token',
body='grant_type=bar')
self.assertEqual('unsupported_grant_type', json.loads(body)['error'])