Remove Identity and Assignment controller interdependancies
The DomainV3 controller explicitly instantiated the UserV3, GroupV3 and ProjectV3 controllers to call some delete methods. This makes it very difficult to isolate the controllers from each other and incorrectly implemented some logic that should exist in the credential_api. The code for deleting credentials by project and by user is now implemented on the credential_api. This allows the controllers to directly ask the credential_api to perform the deletes (and in the case of the SQL backend, perform a more efficient delete process). The DomainV3 controller properly uses the identity_api to cleanup users and groups when deletion occurs. Likewise, DomainV3 controller now properly calls the assignment_api to perform project deletions. These changes have been done to aid in clarifying explicit uses of the per-domain-identity backend logic. bp: assignment-controller-first-class related-bug: #1218094 Change-Id: Ie8ed8bce556fe2f41cc7db61f04eefaf14f836f1
This commit is contained in:
parent
a7d398c5de
commit
dcefec5e0f
|
@ -89,3 +89,19 @@ class Credential(sql.Base, credential.Driver):
|
|||
ref = self._get_credential(session, credential_id)
|
||||
session.delete(ref)
|
||||
session.flush()
|
||||
|
||||
def delete_credentials_for_project(self, project_id):
|
||||
session = self.get_session()
|
||||
|
||||
with session.begin():
|
||||
query = session.query(CredentialModel)
|
||||
query = query.filter_by(project_id=project_id)
|
||||
query.delete()
|
||||
|
||||
def delete_credentials_for_user(self, user_id):
|
||||
session = self.get_session()
|
||||
|
||||
with session.begin():
|
||||
query = session.query(CredentialModel)
|
||||
query = query.filter_by(user_id=user_id)
|
||||
query.delete()
|
||||
|
|
|
@ -95,3 +95,28 @@ class Driver(object):
|
|||
|
||||
"""
|
||||
raise exception.NotImplemented()
|
||||
|
||||
@abc.abstractmethod
|
||||
def delete_credentials_for_project(self, project_id):
|
||||
"""Deletes all existing credentials for an existing project."""
|
||||
for cred in self.list_credentials():
|
||||
if cred['project_id'] == project_id:
|
||||
try:
|
||||
self.credential_api.delete_credential(cred['id'])
|
||||
except exception.CredentialNotFound:
|
||||
# NOTE(morganfainberg): If the credential doesn't exist
|
||||
# it doesn't matter, it is meant to be deleted. Continue
|
||||
# on and delete the rest.
|
||||
pass
|
||||
|
||||
@abc.abstractmethod
|
||||
def delete_credentials_for_user(self, user_id):
|
||||
for cred in self.list_credentials():
|
||||
if cred['user_id'] == user_id:
|
||||
try:
|
||||
self.credential_api.delete_credential(cred['id'])
|
||||
except exception.CredentialNotFound:
|
||||
# NOTE(morganfainberg): If the credential doesn't exist
|
||||
# it doesn't matter, it is meant to be deleted. Continue
|
||||
# on and delete the rest.
|
||||
pass
|
||||
|
|
|
@ -508,7 +508,7 @@ class Role(controller.V2Controller):
|
|||
self._delete_tokens_for_user(user_id)
|
||||
|
||||
|
||||
@dependency.requires('assignment_api', 'identity_api')
|
||||
@dependency.requires('assignment_api', 'credential_api', 'identity_api')
|
||||
class DomainV3(controller.V3Controller):
|
||||
collection_name = 'domains'
|
||||
member_name = 'domain'
|
||||
|
@ -606,23 +606,49 @@ class DomainV3(controller.V3Controller):
|
|||
proj_refs = self.assignment_api.list_projects()
|
||||
proj_ids = [r['id'] for r in proj_refs if r['domain_id'] == domain_id]
|
||||
|
||||
# First delete the projects themselves
|
||||
project_cntl = ProjectV3()
|
||||
for project in proj_ids:
|
||||
project_cntl._delete_project(context, project)
|
||||
|
||||
# Get the list of groups owned by this domain and delete them
|
||||
group_refs = self.identity_api.list_groups()
|
||||
group_ids = ([r['id'] for r in group_refs
|
||||
if r['domain_id'] == domain_id])
|
||||
group_cntl = GroupV3()
|
||||
for group in group_ids:
|
||||
group_cntl._delete_group(context, group)
|
||||
|
||||
# First delete the projects themselves
|
||||
for project_id in proj_ids:
|
||||
# NOTE(morganfainberg): Ensure we cleanup the credentials for the
|
||||
# project and any outstanding tokens.
|
||||
self.credential_api.delete_credentials_for_project(project_id)
|
||||
try:
|
||||
self._delete_tokens_for_project(project_id)
|
||||
self.assignment_api.delete_project(project_id)
|
||||
except exception.ProjectNotFound:
|
||||
# NOTE(morganfainberg): We should still perform the cleanups
|
||||
# if the project can't be found for sanity-sake.
|
||||
pass
|
||||
|
||||
for group_id in group_ids:
|
||||
# NOTE(morganfainberg): Cleanup any existing groups.
|
||||
try:
|
||||
self.identity_api.delete_group(group_id,
|
||||
domain_scope=r['domain_id'])
|
||||
except exception.GroupNotFound:
|
||||
# NOTE(morganfainberg): In the case that a race has occurred
|
||||
# and the group no longer exists, continue on and delete the
|
||||
# rest of the groups.
|
||||
pass
|
||||
|
||||
# And finally, delete the users themselves
|
||||
user_cntl = UserV3()
|
||||
for user in user_ids:
|
||||
user_cntl._delete_user(context, user)
|
||||
for user_id in user_ids:
|
||||
# Delete any credentials that reference this user
|
||||
self.credential_api.delete_credentials_for_user(user_id)
|
||||
# Make sure any tokens are marked as deleted
|
||||
try:
|
||||
self._delete_tokens_for_user(user_id)
|
||||
self.identity_api.delete_user(user_id,
|
||||
domain_scope=r['domain_id'])
|
||||
except exception.UserNotFound:
|
||||
# NOTE(morganfainberg): In the case that a race has occurred
|
||||
# and the user no longer exists, continue on and delete the
|
||||
# rest of the users.
|
||||
pass
|
||||
|
||||
@controller.protected()
|
||||
def delete_domain(self, context, domain_id):
|
||||
|
@ -690,23 +716,11 @@ class ProjectV3(controller.V3Controller):
|
|||
ref = self.assignment_api.update_project(project_id, project)
|
||||
return ProjectV3.wrap_member(context, ref)
|
||||
|
||||
def _delete_project(self, context, project_id):
|
||||
# Delete any credentials that reference this project
|
||||
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
|
||||
return self.assignment_api.delete_project(project_id)
|
||||
|
||||
@controller.protected()
|
||||
def delete_project(self, context, project_id):
|
||||
return self._delete_project(context, project_id)
|
||||
self.credential_api.delete_credentials_for_project(project_id)
|
||||
self._delete_tokens_for_project(project_id)
|
||||
return self.assignment_api.delete_project(project_id)
|
||||
|
||||
|
||||
@dependency.requires('identity_api', 'credential_api')
|
||||
|
@ -792,24 +806,17 @@ class UserV3(controller.V3Controller):
|
|||
domain_scope=self._get_domain_id_for_request(context))
|
||||
self._delete_tokens_for_user(user_id)
|
||||
|
||||
def _delete_user(self, context, user_id):
|
||||
@controller.protected()
|
||||
def delete_user(self, context, user_id):
|
||||
# Delete any credentials that reference this user
|
||||
for cred in self.credential_api.list_credentials():
|
||||
if cred['user_id'] == user_id:
|
||||
self.credential_api.delete_credential(cred['id'])
|
||||
|
||||
self.credential_api.delete_credentials_for_user(user_id)
|
||||
# Make sure any tokens are marked as deleted
|
||||
domain_id = self._get_domain_id_for_request(context)
|
||||
self._delete_tokens_for_user(user_id)
|
||||
# Finally delete the user itself - the backend is
|
||||
# responsible for deleting any role assignments related
|
||||
# to this user
|
||||
return self.identity_api.delete_user(
|
||||
user_id, domain_scope=domain_id)
|
||||
|
||||
@controller.protected()
|
||||
def delete_user(self, context, user_id):
|
||||
return self._delete_user(context, user_id)
|
||||
return self.identity_api.delete_user(user_id, domain_scope=domain_id)
|
||||
|
||||
@controller.protected()
|
||||
def change_password(self, context, user_id, user):
|
||||
|
@ -882,13 +889,13 @@ class GroupV3(controller.V3Controller):
|
|||
domain_scope=self._get_domain_id_for_request(context))
|
||||
return GroupV3.wrap_member(context, ref)
|
||||
|
||||
def _delete_group(self, context, group_id):
|
||||
@controller.protected()
|
||||
def delete_group(self, context, group_id):
|
||||
# As well as deleting the group, we need to invalidate
|
||||
# any tokens for the users who are members of the group.
|
||||
# We get the list of users before we attempt the group
|
||||
# deletion, so that we can remove these tokens after we know
|
||||
# the group deletion succeeded.
|
||||
|
||||
domain_id = self._get_domain_id_for_request(context)
|
||||
user_refs = self.identity_api.list_users_in_group(
|
||||
group_id, domain_scope=domain_id)
|
||||
|
@ -896,10 +903,6 @@ class GroupV3(controller.V3Controller):
|
|||
for user in user_refs:
|
||||
self._delete_tokens_for_user(user['id'])
|
||||
|
||||
@controller.protected()
|
||||
def delete_group(self, context, group_id):
|
||||
return self._delete_group(context, group_id)
|
||||
|
||||
|
||||
@dependency.requires('assignment_api', 'identity_api')
|
||||
class RoleV3(controller.V3Controller):
|
||||
|
|
|
@ -18,6 +18,7 @@ import hashlib
|
|||
import json
|
||||
import uuid
|
||||
|
||||
from keystone import exception
|
||||
from keystone.tests import test_v3
|
||||
|
||||
|
||||
|
@ -36,6 +37,18 @@ class CredentialTestCase(test_v3.RestfulTestCase):
|
|||
self.credential_id,
|
||||
self.credential)
|
||||
|
||||
def test_credential_api_delete_credentials_for_project(self):
|
||||
self.credential_api.delete_credentials_for_project(self.project_id)
|
||||
self.assertRaises(exception.CredentialNotFound,
|
||||
self.credential_api.get_credential,
|
||||
credential_id=self.credential_id)
|
||||
|
||||
def test_credential_api_delete_credentials_for_user(self):
|
||||
self.credential_api.delete_credentials_for_user(self.user_id)
|
||||
self.assertRaises(exception.CredentialNotFound,
|
||||
self.credential_api.get_credential,
|
||||
credential_id=self.credential_id)
|
||||
|
||||
def test_list_credentials(self):
|
||||
"""Call ``GET /credentials``."""
|
||||
r = self.get('/credentials')
|
||||
|
|
Loading…
Reference in New Issue