diff options
-rw-r--r-- | keystone/common/controller.py | 4 | ||||
-rw-r--r-- | keystone/identity/controllers.py | 16 | ||||
-rw-r--r-- | keystone/tests/_ldap_livetest.py | 11 | ||||
-rw-r--r-- | keystone/tests/test_backend_ldap.py | 4 | ||||
-rw-r--r-- | keystone/tests/test_keystoneclient.py | 46 | ||||
-rw-r--r-- | keystone/tests/test_v3_auth.py | 61 |
6 files changed, 138 insertions, 4 deletions
diff --git a/keystone/common/controller.py b/keystone/common/controller.py index 15857c45..1bf65cda 100644 --- a/keystone/common/controller.py +++ b/keystone/common/controller.py @@ -168,6 +168,10 @@ class V2Controller(wsgi.Application): self._delete_tokens_for_trust(trust['trustee_user_id'], trust['id']) + def _delete_tokens_for_project(self, project_id): + for user_ref in self.identity_api.get_project_users(project_id): + self._delete_tokens_for_user(user_ref['id'], project_id=project_id) + def _require_attribute(self, ref, attr): """Ensures the reference contains the specified attribute.""" if ref.get(attr) is None or ref.get(attr) == '': diff --git a/keystone/identity/controllers.py b/keystone/identity/controllers.py index cf8c83c7..67f3beac 100644 --- a/keystone/identity/controllers.py +++ b/keystone/identity/controllers.py @@ -108,12 +108,20 @@ class Tenant(controller.V2Controller): # be specifying that clean_tenant = tenant.copy() clean_tenant.pop('domain_id', None) + + # If the project has been disabled (or enabled=False) we are + # deleting the tokens for that project. + if not tenant.get('enabled', True): + self._delete_tokens_for_project(tenant_id) + tenant_ref = self.identity_api.update_project( tenant_id, clean_tenant) return {'tenant': tenant_ref} def delete_project(self, context, tenant_id): self.assert_admin(context) + # Delete all tokens belonging to the users for that project + self._delete_tokens_for_project(tenant_id) self.identity_api.delete_project(tenant_id) def get_project_users(self, context, tenant_id, **kw): @@ -571,6 +579,10 @@ class ProjectV3(controller.V3Controller): def update_project(self, context, project_id, project): self._require_matching_id(project_id, project) + # The project was disabled so we delete the tokens + if not project.get('enabled', True): + self._delete_tokens_for_project(project_id) + ref = self.identity_api.update_project(project_id, project) return ProjectV3.wrap_member(context, ref) @@ -579,6 +591,10 @@ class ProjectV3(controller.V3Controller): for cred in self.credential_api.list_credentials(): if cred['project_id'] == project_id: self.credential_api.delete_credential(cred['id']) + + # Delete all tokens belonging to the users for that project + self._delete_tokens_for_project(project_id) + # Finally delete the project itself - the backend is # responsible for deleting any role assignments related # to this project diff --git a/keystone/tests/_ldap_livetest.py b/keystone/tests/_ldap_livetest.py index 59da4e66..4562ccb6 100644 --- a/keystone/tests/_ldap_livetest.py +++ b/keystone/tests/_ldap_livetest.py @@ -87,9 +87,6 @@ class LiveLDAPIdentity(test_backend_ldap.LDAPIdentity): def tearDown(self): test.TestCase.tearDown(self) - def test_user_enable_attribute_mask(self): - self.skipTest('Test is for Active Directory Only') - def test_ldap_dereferencing(self): alt_users_ldif = {'objectclass': ['top', 'organizationalUnit'], 'ou': 'alt_users'} @@ -158,3 +155,11 @@ class LiveLDAPIdentity(test_backend_ldap.LDAPIdentity): alias_dereferencing=deref) self.assertEqual(ldap.DEREF_SEARCHING, ldap_wrapper.conn.get_option(ldap.OPT_DEREF)) + + def test_user_enable_attribute_mask(self): + CONF.ldap.user_enabled_emulation = False + CONF.ldap.user_enabled_attribute = 'employeeType' + super(LiveLDAPIdentity, self).test_user_enable_attribute_mask() + + def test_create_unicode_user_name(self): + self.skipTest('Addressed by bug #1172106') diff --git a/keystone/tests/test_backend_ldap.py b/keystone/tests/test_backend_ldap.py index 9c1c98d5..6f9cfef9 100644 --- a/keystone/tests/test_backend_ldap.py +++ b/keystone/tests/test_backend_ldap.py @@ -454,10 +454,12 @@ class LDAPIdentity(test.TestCase, BaseLDAPIdentity): self.assertNotIn('name', role_ref) def test_user_enable_attribute_mask(self): - CONF.ldap.user_enabled_attribute = 'enabled' CONF.ldap.user_enabled_mask = 2 CONF.ldap.user_enabled_default = 512 self.clear_database() + self.load_backends() + self.load_fixtures(default_fixtures) + user = {'id': 'fake1', 'name': 'fake1', 'enabled': True} self.identity_api.create_user('fake1', user) user_ref = self.identity_api.get_user('fake1') diff --git a/keystone/tests/test_keystoneclient.py b/keystone/tests/test_keystoneclient.py index 7e59885d..0c323ddd 100644 --- a/keystone/tests/test_keystoneclient.py +++ b/keystone/tests/test_keystoneclient.py @@ -378,6 +378,46 @@ class KeystoneClientTests(object): client.tokens.authenticate, token=token_id) + def test_disable_tenant_invalidates_token(self): + from keystoneclient import exceptions as client_exceptions + + admin_client = self.get_client(admin=True) + foo_client = self.get_client(self.user_foo) + tenant_bar = admin_client.tenants.get(self.tenant_bar['id']) + + # Disable the tenant. + tenant_bar.update(enabled=False) + + # Test that the token has been removed. + self.assertRaises(client_exceptions.Unauthorized, + foo_client.tokens.authenticate, + token=foo_client.auth_token) + + # Test that the user access has been disabled. + self.assertRaises(client_exceptions.Unauthorized, + self.get_client, + self.user_foo) + + def test_delete_tenant_invalidates_token(self): + from keystoneclient import exceptions as client_exceptions + + admin_client = self.get_client(admin=True) + foo_client = self.get_client(self.user_foo) + tenant_bar = admin_client.tenants.get(self.tenant_bar['id']) + + # Delete the tenant. + tenant_bar.delete() + + # Test that the token has been removed. + self.assertRaises(client_exceptions.Unauthorized, + foo_client.tokens.authenticate, + token=foo_client.auth_token) + + # Test that the user access has been disabled. + self.assertRaises(client_exceptions.Unauthorized, + self.get_client, + self.user_foo) + def test_disable_user_invalidates_token(self): from keystoneclient import exceptions as client_exceptions @@ -1165,6 +1205,12 @@ class KcEssex3TestCase(CompatTestCase, KeystoneClientTests): def test_policy_crud(self): self.skipTest('N/A due to lack of endpoint CRUD') + def test_disable_tenant_invalidates_token(self): + self.skipTest('N/A') + + def test_delete_tenant_invalidates_token(self): + self.skipTest('N/A') + class Kc11TestCase(CompatTestCase, KeystoneClientTests): def get_checkout(self): diff --git a/keystone/tests/test_v3_auth.py b/keystone/tests/test_v3_auth.py index 43f87d98..1f4425ce 100644 --- a/keystone/tests/test_v3_auth.py +++ b/keystone/tests/test_v3_auth.py @@ -545,6 +545,67 @@ class TestTokenRevoking(test_v3.RestfulTestCase): headers={'X-Subject-Token': token}, expected_status=204) + def test_disabling_project_revokes_token(self): + resp = self.post( + '/auth/tokens', + body=self.build_authentication_request( + user_id=self.user3['id'], + password=self.user3['password'], + project_id=self.projectA['id'])) + token = resp.headers.get('X-Subject-Token') + + # confirm token is valid + self.head('/auth/tokens', + headers={'X-Subject-Token': token}, + expected_status=204) + + # disable the project, which should invalidate the token + self.patch( + '/projects/%(project_id)s' % {'project_id': self.projectA['id']}, + body={'project': {'enabled': False}}) + + # user should no longer have access to the project + self.head('/auth/tokens', + headers={'X-Subject-Token': token}, + expected_status=401) + resp = self.post( + '/auth/tokens', + body=self.build_authentication_request( + user_id=self.user3['id'], + password=self.user3['password'], + project_id=self.projectA['id']), + expected_status=401) + + def test_deleting_project_revokes_token(self): + resp = self.post( + '/auth/tokens', + body=self.build_authentication_request( + user_id=self.user3['id'], + password=self.user3['password'], + project_id=self.projectA['id'])) + token = resp.headers.get('X-Subject-Token') + + # confirm token is valid + self.head('/auth/tokens', + headers={'X-Subject-Token': token}, + expected_status=204) + + # delete the project, which should invalidate the token + self.delete( + '/projects/%(project_id)s' % {'project_id': self.projectA['id']}) + + # user should no longer have access to the project + self.head('/auth/tokens', + headers={'X-Subject-Token': token}, + expected_status=401) + resp = self.post( + '/auth/tokens', + body=self.build_authentication_request( + user_id=self.user3['id'], + password=self.user3['password'], + project_id=self.projectA['id']), + expected_status=401) + def test_deleting_group_grant_revokes_tokens(self): """Test deleting a group grant revokes tokens. |