Unset project ids for all identity backends

Previously, the default behavior for the callback that unset
default project ids was to only call the method for the default
domain's identity driver. This meant that when a project was deleted,
only the default identity backend would have references to that
project removed. This means it would be possible for other identity
backends to still have references to a project that doesn't exist
because the callback wasn't invoked for that specific backend.

This commit ensures each backend clears project id from a user's
default_project_id attribute when a project is deleted.

Change-Id: Ibb5396f20101a3956fa91d6ff68155d4c00ab0f9
Closes-Bug: 1705072
This commit is contained in:
Lance Bragstad 2017-08-08 20:31:26 +00:00
parent 6167850d12
commit d0ad287df3
2 changed files with 28 additions and 9 deletions

View File

@ -15,6 +15,7 @@
"""Main entry point into the Identity service.""" """Main entry point into the Identity service."""
import functools import functools
import itertools
import operator import operator
import os import os
import threading import threading
@ -530,15 +531,19 @@ class Manager(manager.Manager):
""" """
project_id = payload['resource_info'] project_id = payload['resource_info']
try: drivers = itertools.chain(
self.driver.unset_default_project_id(project_id) self.domain_configs.values(), [{'driver': self.driver}]
except exception.Forbidden: )
# NOTE(lbragstad): If the driver throws a Forbidden, it's because for d in drivers:
# the driver doesn't support writes. This is the case with the try:
# in-tree LDAP implementation since it is read-only. This also d['driver'].unset_default_project_id(project_id)
# ensures consistency for out-of-tree backends that might be except exception.Forbidden:
# read-only. # NOTE(lbragstad): If the driver throws a Forbidden, it's
pass # because the driver doesn't support writes. This is the case
# with the in-tree LDAP implementation since it is read-only.
# This also ensures consistency for out-of-tree backends that
# might be read-only.
pass
# Domain ID normalization methods # Domain ID normalization methods
def _set_domain_id_and_mapping(self, ref, domain_id, driver, def _set_domain_id_and_mapping(self, ref, domain_id, driver,

View File

@ -33,6 +33,7 @@ from keystone import exception
from keystone import identity from keystone import identity
from keystone.identity.backends import ldap as ldap_identity from keystone.identity.backends import ldap as ldap_identity
from keystone.identity.backends.ldap import common as common_ldap from keystone.identity.backends.ldap import common as common_ldap
from keystone.identity.backends import sql as sql_identity
from keystone.identity.mapping_backends import mapping as map from keystone.identity.mapping_backends import mapping as map
from keystone.tests import unit from keystone.tests import unit
from keystone.tests.unit.assignment import test_backends as assignment_tests from keystone.tests.unit.assignment import test_backends as assignment_tests
@ -2500,6 +2501,19 @@ class MultiLDAPandSQLIdentity(BaseLDAPIdentity, unit.SQLDriverOverrides,
base = super(BaseLDAPIdentity, self) base = super(BaseLDAPIdentity, self)
base.test_remove_foreign_assignments_when_deleting_a_domain() base.test_remove_foreign_assignments_when_deleting_a_domain()
@mock.patch.object(ldap_identity.Identity, 'unset_default_project_id')
@mock.patch.object(sql_identity.Identity, 'unset_default_project_id')
def test_delete_project_unset_project_ids_for_all_backends(self, sql_mock,
ldap_mock):
ldap_mock.side_effect = exception.Forbidden
project = unit.new_project_ref(
domain_id=CONF.identity.default_domain_id
)
project = self.resource_api.create_project(project['id'], project)
self.resource_api.delete_project(project['id'])
ldap_mock.assert_called_with(project['id'])
sql_mock.assert_called_with(project['id'])
class MultiLDAPandSQLIdentityDomainConfigsInSQL(MultiLDAPandSQLIdentity): class MultiLDAPandSQLIdentityDomainConfigsInSQL(MultiLDAPandSQLIdentity):
"""Class to test the use of domain configs stored in the database. """Class to test the use of domain configs stored in the database.