Merge "Revoke user tokens when disabling/delete a project"

This commit is contained in:
Jenkins
2013-08-15 20:45:50 +00:00
committed by Gerrit Code Review
4 changed files with 127 additions and 0 deletions

View File

@@ -169,6 +169,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) == '':

View File

@@ -109,12 +109,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):
@@ -572,6 +580,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)
@@ -580,6 +592,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

View File

@@ -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):

View File

@@ -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.