From cf5c92b5c472db09ad6b832b0aed80fa5135f20b Mon Sep 17 00:00:00 2001 From: Dolph Mathews Date: Fri, 7 Sep 2012 15:18:50 -0400 Subject: [PATCH] Invalidate tokens on role change invalidates all tokens held by a user upon role grant or revoke Bug 1041396 Change-Id: Ifb25ab8b52c56587cd93778817e454362e76e0b7 --- keystone/identity/core.py | 7 ++++++- keystone/token/core.py | 18 ++++++++++++++++++ tests/test_keystoneclient.py | 18 +++++++++--------- 3 files changed, 33 insertions(+), 10 deletions(-) diff --git a/keystone/identity/core.py b/keystone/identity/core.py index db3ce31eae8f3384a7d155f0bd0f876458f5f22e..22df815d32ac6680a8c094f397b08ecb1f321482 100644 --- a/keystone/identity/core.py +++ b/keystone/identity/core.py @@ -525,6 +525,8 @@ class RoleController(wsgi.Application): self.identity_api.add_user_to_tenant(context, tenant_id, user_id) self.identity_api.add_role_to_user_and_tenant( context, user_id, tenant_id, role_id) + self.token_api.revoke_tokens(context, user_id) + role_ref = self.identity_api.get_role(context, role_id) return {'role': role_ref} @@ -555,7 +557,7 @@ class RoleController(wsgi.Application): if not roles: self.identity_api.remove_user_from_tenant( context, tenant_id, user_id) - return + self.token_api.revoke_tokens(context, user_id) # COMPAT(diablo): CRUD extension def get_role_refs(self, context, user_id): @@ -597,6 +599,8 @@ class RoleController(wsgi.Application): self.identity_api.add_user_to_tenant(context, tenant_id, user_id) self.identity_api.add_role_to_user_and_tenant( context, user_id, tenant_id, role_id) + self.token_api.revoke_tokens(context, user_id) + role_ref = self.identity_api.get_role(context, role_id) return {'role': role_ref} @@ -624,3 +628,4 @@ class RoleController(wsgi.Application): if not roles: self.identity_api.remove_user_from_tenant( context, tenant_id, user_id) + self.token_api.revoke_tokens(context, user_id) diff --git a/keystone/token/core.py b/keystone/token/core.py index 0d1101dbfda9c78de2fc5841a3338030c897ec68..4787cae51522b342caf7cfae864d5725cea33cfc 100644 --- a/keystone/token/core.py +++ b/keystone/token/core.py @@ -17,6 +17,7 @@ """Main entry point into the Token service.""" import datetime +import logging from keystone import config from keystone import exception @@ -25,6 +26,7 @@ from keystone.common import manager CONF = config.CONF config.register_int('expiration', group='token', default=86400) +LOG = logging.getLogger(__name__) class Manager(manager.Manager): @@ -38,6 +40,15 @@ class Manager(manager.Manager): def __init__(self): super(Manager, self).__init__(CONF.token.driver) + def revoke_tokens(self, context, user_id): + try: + for token_id in self.list_tokens(context, user_id): + self.delete_token(context, token_id) + except exception.NotImplemented: + # tokens remain valid for drivers that can't list tokens for users + LOG.warning('User %s roles have changed, but existing tokens ' + 'remain valid' % user_id) + class Driver(object): """Interface description for a Token driver.""" @@ -97,6 +108,13 @@ class Driver(object): """ raise exception.NotImplemented() + def revoke_tokens(self, user_id): + """Invalidates all tokens held by a user. + + :raises: keystone.exception.UserNotFound + """ + raise exception.NotImplemented() + def _get_default_expire_time(self): """Determine when a token should expire based on the config. diff --git a/tests/test_keystoneclient.py b/tests/test_keystoneclient.py index 0f6f628d7d2ea4e144f6357ddbf2daedfff85dd0..6e457900b2fc90e8f308f48a66196b3871084613 100644 --- a/tests/test_keystoneclient.py +++ b/tests/test_keystoneclient.py @@ -769,15 +769,15 @@ class KcMasterTestCase(CompatTestCase, KeystoneClientTests): def test_tenant_add_and_remove_user(self): client = self.get_client(admin=True) client.roles.add_user_role(tenant=self.tenant_baz['id'], - user=self.user_foo['id'], + user=self.user_two['id'], role=self.role_useless['id']) user_refs = client.tenants.list_users(tenant=self.tenant_baz['id']) - self.assert_(self.user_foo['id'] in [x.id for x in user_refs]) + self.assert_(self.user_two['id'] in [x.id for x in user_refs]) client.roles.remove_user_role(tenant=self.tenant_baz['id'], - user=self.user_foo['id'], + user=self.user_two['id'], role=self.role_useless['id']) user_refs = client.tenants.list_users(tenant=self.tenant_baz['id']) - self.assert_(self.user_foo['id'] not in [x.id for x in user_refs]) + self.assert_(self.user_two['id'] not in [x.id for x in user_refs]) def test_user_role_add_404(self): from keystoneclient import exceptions as client_exceptions @@ -890,16 +890,16 @@ class KcEssex3TestCase(CompatTestCase, KeystoneClientTests): def test_tenant_add_and_remove_user(self): client = self.get_client(admin=True) client.roles.add_user_to_tenant(tenant_id=self.tenant_baz['id'], - user_id=self.user_foo['id'], + user_id=self.user_two['id'], role_id=self.role_useless['id']) role_refs = client.roles.get_user_role_refs( - user_id=self.user_foo['id']) + user_id=self.user_two['id']) self.assert_(self.tenant_baz['id'] in [x.tenantId for x in role_refs]) # get the "role_refs" so we get the proper id, this is how the clients # do it roleref_refs = client.roles.get_user_role_refs( - user_id=self.user_foo['id']) + user_id=self.user_two['id']) for roleref_ref in roleref_refs: if (roleref_ref.roleId == self.role_useless['id'] and roleref_ref.tenantId == self.tenant_baz['id']): @@ -907,11 +907,11 @@ class KcEssex3TestCase(CompatTestCase, KeystoneClientTests): break client.roles.remove_user_from_tenant(tenant_id=self.tenant_baz['id'], - user_id=self.user_foo['id'], + user_id=self.user_two['id'], role_id=roleref_ref.id) role_refs = client.roles.get_user_role_refs( - user_id=self.user_foo['id']) + user_id=self.user_two['id']) self.assert_(self.tenant_baz['id'] not in [x.tenantId for x in role_refs]) -- 1.7.11.4