From 8e2a183992311fe005abbfaa40d68dd7ce1fffd3 Mon Sep 17 00:00:00 2001 From: Dolph Mathews Date: Mon, 10 Dec 2012 10:10:22 -0600 Subject: Test drivers return HTTP 501 Not Implemented Change-Id: I4cd21022593e6b4c3965edd00ecea01a00584516 --- keystone/policy/core.py | 2 +- keystone/token/backends/kvs.py | 14 +++++----- keystone/token/backends/memcache.py | 8 +++--- keystone/token/backends/sql.py | 8 +++--- keystone/token/controllers.py | 5 ++-- keystone/token/core.py | 44 +++++++++++++++++-------------- tests/test_drivers.py | 52 +++++++++++++++++++++++++++++++++++++ 7 files changed, 96 insertions(+), 37 deletions(-) create mode 100644 tests/test_drivers.py diff --git a/keystone/policy/core.py b/keystone/policy/core.py index 447e11e3..a8d01f2f 100644 --- a/keystone/policy/core.py +++ b/keystone/policy/core.py @@ -58,7 +58,7 @@ class Manager(manager.Manager): class Driver(object): - def enforce(context, credentials, action, target): + def enforce(self, context, credentials, action, target): """Verify that a user is authorized to perform action. For more information on a full implementation of this see: diff --git a/keystone/token/backends/kvs.py b/keystone/token/backends/kvs.py index 123e12f9..f12fe80d 100644 --- a/keystone/token/backends/kvs.py +++ b/keystone/token/backends/kvs.py @@ -26,26 +26,26 @@ class Token(kvs.Base, token.Driver): # Public interface def get_token(self, token_id): - token_id = self.token_to_key(token_id) + token_id = token.unique_id(token_id) try: - token = self.db.get('token-%s' % token_id) + ref = self.db.get('token-%s' % token_id) except exception.NotFound: raise exception.TokenNotFound(token_id=token_id) - if token['expires'] is None or token['expires'] > timeutils.utcnow(): - return copy.deepcopy(token) + if ref['expires'] is None or ref['expires'] > timeutils.utcnow(): + return copy.deepcopy(ref) else: raise exception.TokenNotFound(token_id=token_id) def create_token(self, token_id, data): - token_id = self.token_to_key(token_id) + token_id = token.unique_id(token_id) data_copy = copy.deepcopy(data) if 'expires' not in data: - data_copy['expires'] = self._get_default_expire_time() + data_copy['expires'] = token.default_expire_time() self.db.set('token-%s' % token_id, data_copy) return copy.deepcopy(data_copy) def delete_token(self, token_id): - token_id = self.token_to_key(token_id) + token_id = token.unique_id(token_id) try: token_ref = self.get_token(token_id) self.db.delete('token-%s' % token_id) diff --git a/keystone/token/backends/memcache.py b/keystone/token/backends/memcache.py index e4fa69ad..efac16fd 100644 --- a/keystone/token/backends/memcache.py +++ b/keystone/token/backends/memcache.py @@ -63,9 +63,9 @@ class Token(token.Driver): def create_token(self, token_id, data): data_copy = copy.deepcopy(data) - ptk = self._prefix_token_id(self.token_to_key(token_id)) + ptk = self._prefix_token_id(token.unique_id(token_id)) if 'expires' not in data_copy: - data_copy['expires'] = self._get_default_expire_time() + data_copy['expires'] = token.default_expire_time() kwargs = {} if data_copy['expires'] is not None: expires_ts = utils.unixtime(data_copy['expires']) @@ -93,8 +93,8 @@ class Token(token.Driver): def delete_token(self, token_id): # Test for existence - data = self.get_token(self.token_to_key(token_id)) - ptk = self._prefix_token_id(self.token_to_key(token_id)) + data = self.get_token(token.unique_id(token_id)) + ptk = self._prefix_token_id(token.unique_id(token_id)) result = self.client.delete(ptk) self._add_to_revocation_list(data) return result diff --git a/keystone/token/backends/sql.py b/keystone/token/backends/sql.py index 6e40e91b..822b869e 100644 --- a/keystone/token/backends/sql.py +++ b/keystone/token/backends/sql.py @@ -40,7 +40,7 @@ class Token(sql.Base, token.Driver): raise exception.TokenNotFound(token_id=token_id) session = self.get_session() query = session.query(TokenModel) - query = query.filter_by(id=self.token_to_key(token_id), valid=True) + query = query.filter_by(id=token.unique_id(token_id), valid=True) token_ref = query.first() now = datetime.datetime.utcnow() if token_ref and (not token_ref.expires or now < token_ref.expires): @@ -51,10 +51,10 @@ class Token(sql.Base, token.Driver): def create_token(self, token_id, data): data_copy = copy.deepcopy(data) if 'expires' not in data_copy: - data_copy['expires'] = self._get_default_expire_time() + data_copy['expires'] = token.default_expire_time() token_ref = TokenModel.from_dict(data_copy) - token_ref.id = self.token_to_key(token_id) + token_ref.id = token.unique_id(token_id) token_ref.valid = True session = self.get_session() with session.begin(): @@ -64,7 +64,7 @@ class Token(sql.Base, token.Driver): def delete_token(self, token_id): session = self.get_session() - key = self.token_to_key(token_id) + key = token.unique_id(token_id) with session.begin(): token_ref = session.query(TokenModel).filter_by(id=key, valid=True).first() diff --git a/keystone/token/controllers.py b/keystone/token/controllers.py index 329235ad..3a2d710d 100644 --- a/keystone/token/controllers.py +++ b/keystone/token/controllers.py @@ -7,6 +7,7 @@ from keystone.common import controller from keystone.common import logging from keystone import exception from keystone.openstack.common import timeutils +from keystone.token import core LOG = logging.getLogger(__name__) @@ -223,7 +224,7 @@ class Auth(controller.V2Controller): raise exception.Unauthorized(e) (user_ref, tenant_ref, metadata_ref) = auth_info - expiry = self.token_api._get_default_expire_time(context=context) + expiry = core.default_expire_time() auth_token_data = self._get_auth_token_data(user_ref, tenant_ref, metadata_ref, @@ -252,7 +253,7 @@ class Auth(controller.V2Controller): tenant_ref = self._get_tenant_ref(context, user_id, tenant_id) metadata_ref = self._get_metadata_ref(context, user_id, tenant_id) - expiry = self.token_api._get_default_expire_time(context=context) + expiry = core.default_expire_time() auth_token_data = self._get_auth_token_data(user_ref, tenant_ref, metadata_ref, diff --git a/keystone/token/core.py b/keystone/token/core.py index 05994538..bb7a705b 100644 --- a/keystone/token/core.py +++ b/keystone/token/core.py @@ -29,6 +29,31 @@ CONF = config.CONF config.register_int('expiration', group='token', default=86400) +def unique_id(token_id): + """Return a unique ID for a token. + + The returned value is useful as the primary key of a database table, + memcache store, or other lookup table. + + :returns: Given a PKI token, returns it's hashed value. Otherwise, returns + the passed-in value (such as a UUID token ID or an existing + hash). + """ + return cms.cms_hash_token(token_id) + + +def default_expire_time(): + """Determine when a fresh token should expire. + + Expiration time varies based on configuration (see ``[token] expiration``). + + :returns: a naive UTC datetime.datetime object + + """ + expire_delta = datetime.timedelta(seconds=CONF.token.expiration) + return timeutils.utcnow() + expire_delta + + class Manager(manager.Manager): """Default pivot point for the Token backend. @@ -53,16 +78,6 @@ class Manager(manager.Manager): class Driver(object): """Interface description for a Token driver.""" - def token_to_key(self, token_id): - """ Converts PKI tokens to their short form used for keys in - Database tables, memcached, and other lookup tables. - - :returns: if given a PKI token, returns its hashed value - Otherwise, returns the passed-in value if given a UUID or - hash of a token. - """ - return cms.cms_hash_token(token_id) - def get_token(self, token_id): """Get a token by id. @@ -133,12 +148,3 @@ class Driver(object): keystone.exception.TenantNotFound """ raise exception.NotImplemented() - - def _get_default_expire_time(self): - """Determine when a token should expire based on the config. - - :returns: a naive utc datetime.datetime object - - """ - expire_delta = datetime.timedelta(seconds=CONF.token.expiration) - return timeutils.utcnow() + expire_delta diff --git a/tests/test_drivers.py b/tests/test_drivers.py new file mode 100644 index 00000000..5eb6eca4 --- /dev/null +++ b/tests/test_drivers.py @@ -0,0 +1,52 @@ +import inspect +import unittest2 as unittest + +from keystone import catalog +from keystone import identity +from keystone import policy +from keystone import token +from keystone import exception + + +class TestDrivers(unittest.TestCase): + """Asserts that drivers are written as expected. + + Public methods on drivers should raise keystone.exception.NotImplemented, + which renders to the API as a HTTP 501 Not Implemented. + + """ + + def assertMethodNotImplemented(self, f): + """Asserts that a given method raises 501 Not Implemented. + + Provides each argument with a value of None, ignoring optional + arguments. + """ + args = inspect.getargspec(f).args + args.remove('self') + kwargs = dict(zip(args, [None] * len(args))) + with self.assertRaises(exception.NotImplemented): + f(**kwargs) + + def assertInterfaceNotImplemented(self, interface): + """Public methods on an interface class should not be implemented.""" + for name in dir(interface): + method = getattr(interface, name) + if name[0] != '_' and callable(method): + self.assertMethodNotImplemented(method) + + def test_catalog_driver_unimplemented(self): + interface = catalog.Driver() + self.assertInterfaceNotImplemented(interface) + + def test_identity_driver_unimplemented(self): + interface = identity.Driver() + self.assertInterfaceNotImplemented(interface) + + def test_policy_driver_unimplemented(self): + interface = policy.Driver() + self.assertInterfaceNotImplemented(interface) + + def test_token_driver_unimplemented(self): + interface = token.Driver() + self.assertInterfaceNotImplemented(interface) -- cgit