Esempio n. 1
0
class AuthorizationView(View):

    def __init__(self):
        validator = DjangoValidator()
        # TODO: this should probably be tunable through settings
        self._authorization_endpoint = Server(validator)
        self._error_uri = reverse('oauth2_error')

    def get(self, request, *args, **kwargs):
        uri, http_method, body, headers = extract_params(request)
        redirect_uri = request.GET.get('redirect_uri', None)
        log.debug('Found redirect uri %s.', redirect_uri)
        try:
            scopes, credentials = self._authorization_endpoint.validate_authorization_request(
                    uri, http_method, body, headers)
            log.debug('Saving credentials to session, %r.', credentials)
            request.session['oauth2_credentials'] = credentials
            kwargs['scopes'] = scopes
            kwargs.update(credentials)
            actual_view = get_actual_authorization_view(request)
            log.debug('Invoking actual view method, %r.', actual_view)
            return actual_view(request, *args, **kwargs)

        except errors.FatalClientError as e:
            log.debug('Fatal client error, redirecting to error page.')
            return HttpResponseRedirect(e.in_uri(self._error_uri))

        except errors.OAuth2Error as e:
            log.debug('Client error, redirecting back to client.')
            # TODO: remove after federico PR
            e.redirect_uri = redirect_uri or 'https://localhost'
            return HttpResponseRedirect(e.in_uri(e.redirect_uri))

    @csrf_exempt
    def post(self, request, *args, **kwargs):
        uri, http_method, body, headers = extract_params(request)
        scopes, credentials = get_authorization(request)
        log.debug('Fetched credentials view, %r.', credentials)
        credentials.update(request.session.get('oauth2_credentials', {}))
        log.debug('Fetched credentials from session, %r.', credentials)
        redirect_uri = credentials.get('redirect_uri')
        log.debug('Found redirect uri %s.', redirect_uri)
        try:
            url, headers, body, status = self._authorization_endpoint.create_authorization_response(
                    uri, http_method, body, headers, scopes, credentials)
            log.debug('Authorization successful, redirecting to client.')
            return HttpResponseRedirect(url)
        except errors.FatalClientError as e:
            log.debug('Fatal client error, redirecting to error page.')
            return HttpResponseRedirect(e.in_uri(self._error_uri))
        except errors.OAuth2Error as e:
            log.debug('Client error, redirecting back to client.')
            return HttpResponseRedirect(e.in_uri(redirect_uri))
Esempio n. 2
0
class AuthorizationView(View):
    def __init__(self):
        validator = DjangoValidator()
        # TODO: this should probably be tunable through settings
        self._authorization_endpoint = Server(validator)
        self._error_uri = reverse('oauth2_error')

    def get(self, request, *args, **kwargs):
        uri, http_method, body, headers = extract_params(request)
        redirect_uri = request.GET.get('redirect_uri', None)
        log.debug('Found redirect uri %s.', redirect_uri)
        try:
            scopes, credentials = self._authorization_endpoint.validate_authorization_request(
                uri, http_method, body, headers)
            log.debug('Saving credentials to session, %r.', credentials)
            request.session['oauth2_credentials'] = credentials
            kwargs['scopes'] = scopes
            kwargs.update(credentials)
            actual_view = get_actual_authorization_view(request)
            log.debug('Invoking actual view method, %r.', actual_view)
            return actual_view(request, *args, **kwargs)

        except errors.FatalClientError as e:
            log.debug('Fatal client error, redirecting to error page.')
            return HttpResponseRedirect(e.in_uri(self._error_uri))

        except errors.OAuth2Error as e:
            log.debug('Client error, redirecting back to client.')
            # TODO: remove after federico PR
            e.redirect_uri = redirect_uri or 'https://localhost'
            return HttpResponseRedirect(e.in_uri(e.redirect_uri))

    @csrf_exempt
    def post(self, request, *args, **kwargs):
        uri, http_method, body, headers = extract_params(request)
        scopes, credentials = get_authorization(request)
        log.debug('Fetched credentials view, %r.', credentials)
        credentials.update(request.session.get('oauth2_credentials', {}))
        log.debug('Fetched credentials from session, %r.', credentials)
        redirect_uri = credentials.get('redirect_uri')
        log.debug('Found redirect uri %s.', redirect_uri)
        try:
            url, headers, body, status = self._authorization_endpoint.create_authorization_response(
                uri, http_method, body, headers, scopes, credentials)
            log.debug('Authorization successful, redirecting to client.')
            return HttpResponseRedirect(url)
        except errors.FatalClientError as e:
            log.debug('Fatal client error, redirecting to error page.')
            return HttpResponseRedirect(e.in_uri(self._error_uri))
        except errors.OAuth2Error as e:
            log.debug('Client error, redirecting back to client.')
            return HttpResponseRedirect(e.in_uri(redirect_uri))
Esempio n. 3
0
class IamRequestValidator(IRequestValidator):
    def __init__(self, validator: OauthlibRequestValidator):
        self._server = Server(validator)

    def validate_pre_auth_request(self, request: ff.Message):
        http_request = request.headers.get('http_request')
        return self._server.validate_authorization_request(
            f'{http_request["headers"]["Host"]}{http_request["url"]}',
            http_request['method'], '', http_request['headers'])

    def validate_post_auth_request(self, request: ff.Message):
        pass

    def create_response(self, request: ff.Message):
        return self._server.create_authorization_response(
            request.headers.get('uri'), request.headers.get('http_method'),
            request.to_dict(), request.headers)
Esempio n. 4
0
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 = '******'
        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.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.assertItemsEqual(scopes, correct_scopes)
            scopes, _ = self.mobile.validate_authorization_request(
                    uri % (scope, 'token'))
            self.assertItemsEqual(scopes, correct_scopes)
            scopes, _ = self.server.validate_authorization_request(
                uri % (scope, 'code'))
            self.assertItemsEqual(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='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')
Esempio n. 5
0
class AuthorizationEndpoint(object):

    def __init__(self, request):
        self.request = request
        self.validator = RequestValidator()
        self.server = Server(self.validator)

    @view_config(route_name='oauth2_authorization_endpoint',
                 renderer='templates/application_authorization.pt',
                 permission='add-authorized-app',
                 request_method='GET')
    def get(self):
        uri, http_method, body, headers = extract_params(self.request)

        try:
            scopes, credentials = self.server.validate_authorization_request(
                uri, http_method, body, headers,
            )

            app = self.validator.get_client(credentials['client_id'])

            try:
                auth_app = Session.query(AuthorizedApplication).filter(
                    AuthorizedApplication.user == self.request.user,
                    AuthorizedApplication.scope == scopes,
                    AuthorizedApplication.redirect_uri == credentials['redirect_uri'],
                    AuthorizedApplication.response_type == credentials['response_type'],
                    AuthorizedApplication.application == app,
                ).one()
            except NoResultFound:
                auth_app = None

            if auth_app is not None:
                credentials['user'] = self.request.user
                server_response = self.server.create_authorization_response(
                    uri, http_method, body, headers, scopes, credentials,
                )
                return create_response(*server_response)
            else:
                authorship_information = app.user.email

                pretty_scopes = self.validator.get_pretty_scopes(scopes)
                return {
                    'response_type': credentials['response_type'],
                    'client_id': credentials['client_id'],
                    'redirect_uri': credentials['redirect_uri'],
                    'state': credentials['state'],
                    'scope': ' '.join(scopes),
                    'app': app,
                    'scopes': pretty_scopes,
                    'authorship_information': authorship_information,
                }
        except FatalClientError as e:
            return response_from_error(e)

        except OAuth2Error as e:
            return HTTPFound(e.in_uri(e.redirect_uri))

    @view_config(route_name='oauth2_authorization_endpoint',
                 permission='add-authorized-app',
                 request_method='POST')
    def post(self):
        uri, http_method, body, headers = extract_params(self.request)

        redirect_uri = self.request.POST.get('redirect_uri')
        if 'submit' in self.request.POST:
            scope = self.request.POST.get('scope', '')
            scopes = scope.split()
            credentials = {
                'client_id': self.request.POST.get('client_id'),
                'redirect_uri': redirect_uri,
                'response_type': self.request.POST.get('response_type'),
                'state': self.request.POST.get('state'),
                'user': self.request.user,
            }
            try:
                server_response = self.server.create_authorization_response(
                    uri, http_method, body, headers, scopes, credentials,
                )

                app = Session.query(Application).filter(
                    Application.id == credentials['client_id'],
                ).one()

                try:
                    auth_app = Session.query(AuthorizedApplication).filter(
                        AuthorizedApplication.user == self.request.user,
                        AuthorizedApplication.application == app,
                    ).one()
                except NoResultFound:
                    auth_app = AuthorizedApplication(
                        user=self.request.user,
                        application=app,
                    )

                auth_app.redirect_uri = credentials['redirect_uri']
                auth_app.response_type = credentials['response_type']
                auth_app.scope = scopes

                Session.add(auth_app)

                return create_response(*server_response)
            except FatalClientError as e:
                return response_from_error(e)

        elif 'cancel' in self.request.POST:
            e = AccessDeniedError()
            return HTTPFound(e.in_uri(redirect_uri))
Esempio n. 6
0
class AuthorizationEndpoint(object):
    def __init__(self, request):
        self.request = request
        self.validator = RequestValidator()
        self.server = Server(self.validator)

    @view_config(route_name='oauth2_authorization_endpoint',
                 renderer='templates/application_authorization.pt',
                 permission='add-authorized-app',
                 request_method='GET')
    def get(self):
        uri, http_method, body, headers = extract_params(self.request)

        try:
            scopes, credentials = self.server.validate_authorization_request(
                uri,
                http_method,
                body,
                headers,
            )

            app = self.validator.get_client(credentials['client_id'])

            try:
                auth_app = Session.query(AuthorizedApplication).filter(
                    AuthorizedApplication.user == self.request.user,
                    AuthorizedApplication.scope == scopes,
                    AuthorizedApplication.redirect_uri ==
                    credentials['redirect_uri'],
                    AuthorizedApplication.response_type ==
                    credentials['response_type'],
                    AuthorizedApplication.application == app,
                ).one()
            except NoResultFound:
                auth_app = None

            if auth_app is not None:
                credentials['user'] = self.request.user
                server_response = self.server.create_authorization_response(
                    uri,
                    http_method,
                    body,
                    headers,
                    scopes,
                    credentials,
                )
                return create_response(*server_response)
            else:
                authorship_information = app.user.email

                pretty_scopes = self.validator.get_pretty_scopes(scopes)
                return {
                    'response_type': credentials['response_type'],
                    'client_id': credentials['client_id'],
                    'redirect_uri': credentials['redirect_uri'],
                    'state': credentials['state'],
                    'scope': ' '.join(scopes),
                    'app': app,
                    'scopes': pretty_scopes,
                    'authorship_information': authorship_information,
                }
        except FatalClientError as e:
            return response_from_error(e)

        except OAuth2Error as e:
            return HTTPFound(e.in_uri(e.redirect_uri))

    @view_config(route_name='oauth2_authorization_endpoint',
                 permission='add-authorized-app',
                 request_method='POST')
    def post(self):
        uri, http_method, body, headers = extract_params(self.request)

        redirect_uri = self.request.POST.get('redirect_uri')
        if 'submit' in self.request.POST:
            scope = self.request.POST.get('scope', '')
            scopes = scope.split()
            credentials = {
                'client_id': self.request.POST.get('client_id'),
                'redirect_uri': redirect_uri,
                'response_type': self.request.POST.get('response_type'),
                'state': self.request.POST.get('state'),
                'user': self.request.user,
            }
            try:
                server_response = self.server.create_authorization_response(
                    uri,
                    http_method,
                    body,
                    headers,
                    scopes,
                    credentials,
                )

                app = Session.query(Application).filter(
                    Application.id == credentials['client_id'], ).one()

                try:
                    auth_app = Session.query(AuthorizedApplication).filter(
                        AuthorizedApplication.user == self.request.user,
                        AuthorizedApplication.application == app,
                    ).one()
                except NoResultFound:
                    auth_app = AuthorizedApplication(
                        user=self.request.user,
                        application=app,
                    )

                auth_app.redirect_uri = credentials['redirect_uri']
                auth_app.response_type = credentials['response_type']
                auth_app.scope = scopes

                Session.add(auth_app)

                return create_response(*server_response)
            except FatalClientError as e:
                return response_from_error(e)

        elif 'cancel' in self.request.POST:
            e = AccessDeniedError()
            return HTTPFound(e.in_uri(redirect_uri))
Esempio n. 7
0
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 = '******'
        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.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.assertItemsEqual(scopes, correct_scopes)
            scopes, _ = self.mobile.validate_authorization_request(
                uri % (scope, 'token'))
            self.assertItemsEqual(scopes, correct_scopes)
            scopes, _ = self.server.validate_authorization_request(
                uri % (scope, 'code'))
            self.assertItemsEqual(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')