diff --git a/keystone/common/wsgi.py b/keystone/common/wsgi.py index ee5aac6bd6..0c78e1d87a 100644 --- a/keystone/common/wsgi.py +++ b/keystone/common/wsgi.py @@ -202,8 +202,11 @@ class Application(BaseApplication): def assert_admin(self, context): if not context['is_admin']: - user_token_ref = self.token_api.get_token( - context=context, token_id=context['token_id']) + try: + user_token_ref = self.token_api.get_token( + context=context, token_id=context['token_id']) + except exception.TokenNotFound: + raise exception.Unauthorized() creds = user_token_ref['metadata'].copy() creds['user_id'] = user_token_ref['user'].get('id') creds['tenant_id'] = user_token_ref['tenant'].get('id') diff --git a/keystone/contrib/ec2/core.py b/keystone/contrib/ec2/core.py index 888b8ddd3f..c8ad4425b6 100644 --- a/keystone/contrib/ec2/core.py +++ b/keystone/contrib/ec2/core.py @@ -26,6 +26,7 @@ import webob.exc from keystone import catalog from keystone import config +from keystone import exception from keystone import identity from keystone import policy from keystone import service @@ -252,8 +253,11 @@ class Ec2Controller(wsgi.Application): :raises webob.exc.HTTPForbidden: when token is invalid """ - token_ref = self.token_api.get_token(context=context, - token_id=context['token_id']) + try: + token_ref = self.token_api.get_token(context=context, + token_id=context['token_id']) + except exception.TokenNotFound: + raise exception.Unauthorized() token_user_id = token_ref['user'].get('id') if not token_user_id == user_id: raise webob.exc.HTTPForbidden() diff --git a/keystone/exception.py b/keystone/exception.py index cefc260431..c2f32afa30 100644 --- a/keystone/exception.py +++ b/keystone/exception.py @@ -52,3 +52,7 @@ class NotFound(Error): """Could not find: %(target)s""" code = 404 title = 'Not Found' + + +class TokenNotFound(NotFound): + """Could not find token: %(token_id)s""" diff --git a/keystone/identity/core.py b/keystone/identity/core.py index 5982a7ab00..1928c6954b 100644 --- a/keystone/identity/core.py +++ b/keystone/identity/core.py @@ -232,10 +232,10 @@ class TenantController(wsgi.Application): Doesn't care about token scopedness. """ - token_ref = self.token_api.get_token(context=context, - token_id=context['token_id']) - - if token_ref is None: + try: + token_ref = self.token_api.get_token(context=context, + token_id=context['token_id']) + except exception.NotFound: raise exception.Unauthorized() user_ref = token_ref['user'] @@ -250,17 +250,7 @@ class TenantController(wsgi.Application): def get_tenant(self, context, tenant_id): # TODO(termie): this stuff should probably be moved to middleware - if not context['is_admin']: - user_token_ref = self.token_api.get_token( - context=context, token_id=context['token_id']) - creds = user_token_ref['metadata'].copy() - creds['user_id'] = user_token_ref['user'].get('id') - creds['tenant_id'] = user_token_ref['tenant'].get('id') - # Accept either is_admin or the admin role - assert self.policy_api.can_haz(context, - ('is_admin:1', 'roles:admin'), - creds) - + self.assert_admin(context) tenant = self.identity_api.get_tenant(context, tenant_id) if not tenant: return webob.exc.HTTPNotFound() diff --git a/keystone/service.py b/keystone/service.py index e2698cf7c1..0d94a5b906 100644 --- a/keystone/service.py +++ b/keystone/service.py @@ -1,8 +1,5 @@ # vim: tabstop=4 shiftwidth=4 softtabstop=4 -import json -import urllib -import urlparse import uuid import routes @@ -15,7 +12,6 @@ from keystone import identity from keystone import policy from keystone import token from keystone.common import logging -from keystone.common import utils from keystone.common import wsgi @@ -195,10 +191,10 @@ class TokenController(wsgi.Application): else: tenant_id = auth.get('tenantId', None) - old_token_ref = self.token_api.get_token(context=context, - token_id=token) - - if old_token_ref is None: + try: + old_token_ref = self.token_api.get_token(context=context, + token_id=token) + except exception.NotFound: raise exception.Unauthorized() user_ref = old_token_ref['user'] @@ -253,9 +249,6 @@ class TokenController(wsgi.Application): token_ref = self.token_api.get_token(context=context, token_id=token_id) - if token_ref is None: - raise exception.NotFound(target='token') - if belongs_to: assert token_ref['tenant']['id'] == belongs_to @@ -277,8 +270,12 @@ class TokenController(wsgi.Application): def endpoints(self, context, token_id): """Return service catalog endpoints.""" - token_ref = self.token_api.get_token(context=context, - token_id=token_id) + try: + token_ref = self.token_api.get_token(context=context, + token_id=token_id) + except exception.NotFound: + raise exception.Unauthorized() + catalog_ref = self.catalog_api.get_catalog(context, token_ref['user']['id'], token_ref['tenant']['id']) diff --git a/keystone/token/backends/kvs.py b/keystone/token/backends/kvs.py index c19bcc796e..84604ac5e3 100644 --- a/keystone/token/backends/kvs.py +++ b/keystone/token/backends/kvs.py @@ -1,17 +1,24 @@ # vim: tabstop=4 shiftwidth=4 softtabstop=4 -from keystone import token from keystone.common import kvs +from keystone import exception +from keystone import token class Token(kvs.Base, token.Driver): # Public interface def get_token(self, token_id): - return self.db.get('token-%s' % token_id) + try: + return self.db['token-%s' % token_id] + except KeyError: + raise exception.TokenNotFound(token_id=token_id) def create_token(self, token_id, data): self.db.set('token-%s' % token_id, data) return data def delete_token(self, token_id): - return self.db.delete('token-%s' % token_id) + try: + return self.db.delete('token-%s' % token_id) + except KeyError: + raise exception.TokenNotFound(token_id=token_id) diff --git a/keystone/token/backends/memcache.py b/keystone/token/backends/memcache.py index 686da5a71b..d4674ce9e5 100644 --- a/keystone/token/backends/memcache.py +++ b/keystone/token/backends/memcache.py @@ -5,6 +5,7 @@ from __future__ import absolute_import import memcache from keystone import config +from keystone import exception from keystone import token @@ -30,7 +31,11 @@ class Token(token.Driver): def get_token(self, token_id): ptk = self._prefix_token_id(token_id) - return self.client.get(ptk) + token = self.client.get(ptk) + if token is None: + raise exception.TokenNotFound(token_id=token_id) + + return token def create_token(self, token_id, data): ptk = self._prefix_token_id(token_id) @@ -38,5 +43,7 @@ class Token(token.Driver): return data def delete_token(self, token_id): + # Test for existence + self.get_token(token_id) ptk = self._prefix_token_id(token_id) return self.client.delete(ptk) diff --git a/keystone/token/backends/sql.py b/keystone/token/backends/sql.py index 3bb5aea542..090a3600dd 100644 --- a/keystone/token/backends/sql.py +++ b/keystone/token/backends/sql.py @@ -1,7 +1,8 @@ # vim: tabstop=4 shiftwidth=4 softtabstop=4 -from keystone import token from keystone.common import sql +from keystone import exception +from keystone import token class TokenModel(sql.ModelBase, sql.DictBase): @@ -30,7 +31,7 @@ class Token(sql.Base, token.Driver): session = self.get_session() token_ref = session.query(TokenModel).filter_by(id=token_id).first() if not token_ref: - return + raise exception.TokenNotFound(token_id=token_id) return token_ref.to_dict() def create_token(self, token_id, data): @@ -47,6 +48,9 @@ class Token(sql.Base, token.Driver): token_ref = session.query(TokenModel)\ .filter_by(id=token_id)\ .first() + if not token_ref: + raise exception.TokenNotFound(token_id=token_id) + with session.begin(): session.delete(token_ref) session.flush() diff --git a/keystone/token/core.py b/keystone/token/core.py index 47dadcea48..7183c1793e 100644 --- a/keystone/token/core.py +++ b/keystone/token/core.py @@ -29,7 +29,8 @@ class Driver(object): :param token_id: identity of the token :type token_id: string - :returns: token_ref or None. + :returns: token_ref + :raises: keystone.exception.TokenNotFound """ raise NotImplementedError() @@ -63,6 +64,7 @@ class Driver(object): :param token_id: identity of the token :type token_id: string :returns: None. + :raises: keystone.exception.TokenNotFound """ raise NotImplementedError() diff --git a/tests/test_backend.py b/tests/test_backend.py index 59cebd6f31..9dc949da57 100644 --- a/tests/test_backend.py +++ b/tests/test_backend.py @@ -2,6 +2,9 @@ import uuid +from keystone import exception + + class IdentityTests(object): def test_authenticate_bad_user(self): self.assertRaises(AssertionError, @@ -214,5 +217,7 @@ class TokenTests(object): self.assertEquals(new_data_ref, data) self.token_api.delete_token(token_id) - deleted_data_ref = self.token_api.get_token(token_id) - self.assertTrue(deleted_data_ref is None) + self.assertRaises(exception.TokenNotFound, + self.token_api.delete_token, token_id) + self.assertRaises(exception.TokenNotFound, + self.token_api.get_token, token_id) diff --git a/tests/test_backend_memcache.py b/tests/test_backend_memcache.py index 61a967cc2c..f665fb4bb5 100644 --- a/tests/test_backend_memcache.py +++ b/tests/test_backend_memcache.py @@ -1,6 +1,11 @@ +# vim: tabstop=4 shiftwidth=4 softtabstop=4 + +from keystone import exception from keystone import test from keystone.token.backends import memcache as token_memcache +import test_backend + class MemcacheClient(object): """Replicates a tiny subset of memcached client interface.""" @@ -11,7 +16,10 @@ class MemcacheClient(object): def get(self, key): """Retrieves the value for a key or None.""" - return self.cache.get(key) + try: + return self.cache[key] + except KeyError: + raise exception.TokenNotFound(token_id=key) def set(self, key, value): """Sets the value for a key.""" @@ -26,7 +34,7 @@ class MemcacheClient(object): pass -class MemcacheToken(test.TestCase): +class MemcacheToken(test.TestCase, test_backend.TokenTests): def setUp(self): super(MemcacheToken, self).setUp() fake_client = MemcacheClient()