diff --git a/keystone/identity/core.py b/keystone/identity/core.py index c9c496c..085a3dd 100644 --- a/keystone/identity/core.py +++ b/keystone/identity/core.py @@ -590,6 +590,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} @@ -614,7 +616,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): @@ -657,6 +659,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} @@ -684,3 +688,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 d6e9d38..5ad70ba 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.common import manager from keystone import config @@ -26,6 +27,7 @@ from keystone.openstack.common import timeutils CONF = config.CONF config.register_int('expiration', group='token', default=86400) +LOG = logging.getLogger(__name__) class Manager(manager.Manager): @@ -39,6 +41,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.""" @@ -106,6 +117,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 944ca79..f42c3e7 100644 --- a/tests/test_keystoneclient.py +++ b/tests/test_keystoneclient.py @@ -794,15 +794,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 @@ -1001,16 +1001,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']): @@ -1018,11 +1018,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])