123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193 |
- """Ensure scope is preserved across authorization.
- Fairly trivial in all grants except the Authorization Code Grant where scope
- need to be persisted temporarily in an authorization code.
- """
- import json
- from unittest import mock
- from oauthlib.oauth2 import (
- BackendApplicationServer, LegacyApplicationServer, MobileApplicationServer,
- RequestValidator, Server, WebApplicationServer,
- )
- from tests.unittest import TestCase
- from .test_utils import get_fragment_credentials, get_query_credentials
- class TestScopeHandling(TestCase):
- DEFAULT_REDIRECT_URI = 'http://i.b./path'
- def set_scopes(self, scopes):
- def set_request_scopes(client_id, code, client, request):
- request.scopes = scopes
- return True
- return set_request_scopes
- def set_user(self, request):
- request.user = 'foo'
- request.client_id = 'bar'
- request.client = mock.MagicMock()
- request.client.client_id = 'mocked'
- return True
- def set_client(self, request):
- request.client = mock.MagicMock()
- request.client.client_id = 'mocked'
- return True
- def setUp(self):
- self.validator = mock.MagicMock(spec=RequestValidator)
- self.validator.get_default_redirect_uri.return_value = TestScopeHandling.DEFAULT_REDIRECT_URI
- self.validator.get_code_challenge.return_value = None
- self.validator.authenticate_client.side_effect = self.set_client
- self.server = Server(self.validator)
- self.web = WebApplicationServer(self.validator)
- self.mobile = MobileApplicationServer(self.validator)
- self.legacy = LegacyApplicationServer(self.validator)
- self.backend = BackendApplicationServer(self.validator)
- def test_scope_extraction(self):
- scopes = (
- ('images', ['images']),
- ('images+videos', ['images', 'videos']),
- ('images+videos+openid', ['images', 'videos', 'openid']),
- ('http%3A%2f%2fa.b%2fvideos', ['http://a.b/videos']),
- ('http%3A%2f%2fa.b%2fvideos+pics', ['http://a.b/videos', 'pics']),
- ('pics+http%3A%2f%2fa.b%2fvideos', ['pics', 'http://a.b/videos']),
- ('http%3A%2f%2fa.b%2fvideos+https%3A%2f%2fc.d%2Fsecret', ['http://a.b/videos', 'https://c.d/secret']),
- )
- uri = 'http://example.com/path?client_id=abc&scope=%s&response_type=%s'
- for scope, correct_scopes in scopes:
- scopes, _ = self.web.validate_authorization_request(
- uri % (scope, 'code'))
- self.assertCountEqual(scopes, correct_scopes)
- scopes, _ = self.mobile.validate_authorization_request(
- uri % (scope, 'token'))
- self.assertCountEqual(scopes, correct_scopes)
- scopes, _ = self.server.validate_authorization_request(
- uri % (scope, 'code'))
- self.assertCountEqual(scopes, correct_scopes)
- def test_scope_preservation(self):
- scope = 'pics+http%3A%2f%2fa.b%2fvideos'
- decoded_scope = 'pics http://a.b/videos'
- auth_uri = 'http://example.com/path?client_id=abc&response_type='
- token_uri = 'http://example.com/path'
- # authorization grant
- for backend_server_type in ['web', 'server']:
- h, _, s = getattr(self, backend_server_type).create_authorization_response(
- auth_uri + 'code', scopes=decoded_scope.split(' '))
- self.validator.validate_code.side_effect = self.set_scopes(decoded_scope.split(' '))
- self.assertEqual(s, 302)
- self.assertIn('Location', h)
- code = get_query_credentials(h['Location'])['code'][0]
- _, body, _ = getattr(self, backend_server_type).create_token_response(token_uri,
- body='client_id=me&redirect_uri=http://back.to/me&grant_type=authorization_code&code=%s' % code)
- self.assertEqual(json.loads(body)['scope'], decoded_scope)
- # implicit grant
- for backend_server_type in ['mobile', 'server']:
- h, _, s = getattr(self, backend_server_type).create_authorization_response(
- auth_uri + 'token', scopes=decoded_scope.split(' '))
- self.assertEqual(s, 302)
- self.assertIn('Location', h)
- self.assertEqual(get_fragment_credentials(h['Location'])['scope'][0], decoded_scope)
- # resource owner password credentials grant
- for backend_server_type in ['legacy', 'server']:
- body = 'grant_type=password&username=abc&password=secret&scope=%s'
- _, body, _ = getattr(self, backend_server_type).create_token_response(token_uri,
- body=body % scope)
- self.assertEqual(json.loads(body)['scope'], decoded_scope)
- # client credentials grant
- for backend_server_type in ['backend', 'server']:
- body = 'grant_type=client_credentials&scope=%s'
- self.validator.authenticate_client.side_effect = self.set_user
- _, body, _ = getattr(self, backend_server_type).create_token_response(token_uri,
- body=body % scope)
- self.assertEqual(json.loads(body)['scope'], decoded_scope)
- def test_scope_changed(self):
- scope = 'pics+http%3A%2f%2fa.b%2fvideos'
- scopes = ['images', 'http://a.b/videos']
- decoded_scope = 'images http://a.b/videos'
- auth_uri = 'http://example.com/path?client_id=abc&response_type='
- token_uri = 'http://example.com/path'
- # authorization grant
- h, _, s = self.web.create_authorization_response(
- auth_uri + 'code', scopes=scopes)
- 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='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)
- h, _, s = self.mobile.create_authorization_response(
- auth_uri + 'token', scopes=scopes)
- 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=body % scope)
- self.assertEqual(json.loads(body)['scope'], decoded_scope)
- # client credentials grant
- 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=body % scope)
- self.assertEqual(json.loads(body)['scope'], decoded_scope)
- def test_invalid_scope(self):
- scope = 'pics+http%3A%2f%2fa.b%2fvideos'
- auth_uri = 'http://example.com/path?client_id=abc&response_type='
- token_uri = 'http://example.com/path'
- self.validator.validate_scopes.return_value = False
- # authorization grant
- h, _, s = self.web.create_authorization_response(
- auth_uri + 'code', scopes=['invalid'])
- self.assertEqual(s, 302)
- self.assertIn('Location', h)
- error = get_query_credentials(h['Location'])['error'][0]
- self.assertEqual(error, 'invalid_scope')
- # implicit grant
- h, _, s = self.mobile.create_authorization_response(
- auth_uri + 'token', scopes=['invalid'])
- 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=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=body % scope)
- self.assertEqual(json.loads(body)['error'], 'invalid_scope')
|