Merge "Enhance manager list_role_assignments to support group listing"

This commit is contained in:
Jenkins 2016-02-02 09:16:11 +00:00 committed by Gerrit Code Review
commit f473352e1a
5 changed files with 297 additions and 248 deletions

View File

@ -13,8 +13,6 @@
# under the License.
from oslo_config import cfg
import sqlalchemy
from sqlalchemy.sql.expression import false
from keystone import assignment as keystone_assignment
from keystone.common import sql
@ -122,105 +120,6 @@ class Assignment(keystone_assignment.AssignmentDriverV9):
actor_id=actor_id,
target_id=target_id)
def _list_project_ids_for_actor(self, actors, hints, inherited,
group_only=False):
# TODO(henry-nash): Now that we have a single assignment table, we
# should be able to honor the hints list that is provided.
assignment_type = [AssignmentType.GROUP_PROJECT]
if not group_only:
assignment_type.append(AssignmentType.USER_PROJECT)
sql_constraints = sqlalchemy.and_(
RoleAssignment.type.in_(assignment_type),
RoleAssignment.inherited == inherited,
RoleAssignment.actor_id.in_(actors))
with sql.transaction() as session:
query = session.query(RoleAssignment.target_id).filter(
sql_constraints).distinct()
return [x.target_id for x in query.all()]
def list_role_ids_for_groups_on_domain(self, group_ids, domain_id):
if not group_ids:
# If there's no groups then there will be no domain roles.
return []
sql_constraints = sqlalchemy.and_(
RoleAssignment.type == AssignmentType.GROUP_DOMAIN,
RoleAssignment.target_id == domain_id,
RoleAssignment.inherited == false(),
RoleAssignment.actor_id.in_(group_ids))
with sql.transaction() as session:
query = session.query(RoleAssignment.role_id).filter(
sql_constraints).distinct()
return [role.role_id for role in query.all()]
def list_role_ids_for_groups_on_project(
self, group_ids, project_id, project_domain_id, project_parents):
if not group_ids:
# If there's no groups then there will be no project roles.
return []
# NOTE(rodrigods): First, we always include projects with
# non-inherited assignments
sql_constraints = sqlalchemy.and_(
RoleAssignment.type == AssignmentType.GROUP_PROJECT,
RoleAssignment.inherited == false(),
RoleAssignment.target_id == project_id)
if CONF.os_inherit.enabled:
# Inherited roles from domains
sql_constraints = sqlalchemy.or_(
sql_constraints,
sqlalchemy.and_(
RoleAssignment.type == AssignmentType.GROUP_DOMAIN,
RoleAssignment.inherited,
RoleAssignment.target_id == project_domain_id))
# Inherited roles from projects
if project_parents:
sql_constraints = sqlalchemy.or_(
sql_constraints,
sqlalchemy.and_(
RoleAssignment.type == AssignmentType.GROUP_PROJECT,
RoleAssignment.inherited,
RoleAssignment.target_id.in_(project_parents)))
sql_constraints = sqlalchemy.and_(
sql_constraints, RoleAssignment.actor_id.in_(group_ids))
with sql.transaction() as session:
# NOTE(morganfainberg): Only select the columns we actually care
# about here, in this case role_id.
query = session.query(RoleAssignment.role_id).filter(
sql_constraints).distinct()
return [result.role_id for result in query.all()]
def list_project_ids_for_groups(self, group_ids, hints,
inherited=False):
return self._list_project_ids_for_actor(
group_ids, hints, inherited, group_only=True)
def list_domain_ids_for_groups(self, group_ids, inherited=False):
if not group_ids:
# If there's no groups then there will be no domains.
return []
group_sql_conditions = sqlalchemy.and_(
RoleAssignment.type == AssignmentType.GROUP_DOMAIN,
RoleAssignment.inherited == inherited,
RoleAssignment.actor_id.in_(group_ids))
with sql.transaction() as session:
query = session.query(RoleAssignment.target_id).filter(
group_sql_conditions).distinct()
return [x.target_id for x in query.all()]
def add_role_to_user_and_project(self, user_id, tenant_id, role_id):
try:
with sql.transaction() as session:

View File

@ -133,16 +133,18 @@ class Manager(manager.Manager):
def get_roles_for_groups(self, group_ids, project_id=None, domain_id=None):
"""Get a list of roles for this group on domain and/or project."""
if project_id is not None:
project = self.resource_api.get_project(project_id)
role_ids = self.list_role_ids_for_groups_on_project(
group_ids, project_id, project['domain_id'],
self._list_parent_ids_of_project(project_id))
self.resource_api.get_project(project_id)
assignment_list = self.list_role_assignments(
source_from_group_ids=group_ids, project_id=project_id,
effective=True)
elif domain_id is not None:
role_ids = self.list_role_ids_for_groups_on_domain(
group_ids, domain_id)
assignment_list = self.list_role_assignments(
source_from_group_ids=group_ids, domain_id=domain_id,
effective=True)
else:
raise AttributeError(_("Must specify either domain or project"))
role_ids = list(set([x['role_id'] for x in assignment_list]))
return self.role_api.list_roles_from_ids(role_ids)
def add_user_to_project(self, tenant_id, user_id):
@ -244,37 +246,18 @@ class Manager(manager.Manager):
return self.resource_api.list_domains_from_ids(domain_ids)
def list_domains_for_groups(self, group_ids):
domain_ids = self.list_domain_ids_for_groups(group_ids)
assignment_list = self.list_role_assignments(
source_from_group_ids=group_ids, effective=True)
domain_ids = list(set([x['domain_id'] for x in assignment_list
if x.get('domain_id')]))
return self.resource_api.list_domains_from_ids(domain_ids)
def list_projects_for_groups(self, group_ids):
project_ids = (
self.list_project_ids_for_groups(group_ids, driver_hints.Hints()))
if not CONF.os_inherit.enabled:
return self.resource_api.list_projects_from_ids(project_ids)
# os_inherit extension is enabled, so check to see if these groups have
# any inherited role assignment on: i) any domain, in which case we
# must add in all the projects in that domain; ii) any project, in
# which case we must add in all the subprojects under that project in
# the hierarchy.
domain_ids = self.list_domain_ids_for_groups(group_ids, inherited=True)
project_ids_from_domains = (
self.resource_api.list_project_ids_from_domain_ids(domain_ids))
parents_ids = self.list_project_ids_for_groups(group_ids,
driver_hints.Hints(),
inherited=True)
subproject_ids = []
for parent_id in parents_ids:
subtree = self.resource_api.list_projects_in_subtree(parent_id)
subproject_ids += [subproject['id'] for subproject in subtree]
return self.resource_api.list_projects_from_ids(
list(set(project_ids + project_ids_from_domains + subproject_ids)))
assignment_list = self.list_role_assignments(
source_from_group_ids=group_ids, effective=True)
project_ids = list(set([x['project_id'] for x in assignment_list
if x.get('project_id')]))
return self.resource_api.list_projects_from_ids(project_ids)
@notifications.role_assignment('deleted')
def _remove_role_from_user_and_project_adapter(self, role_id, user_id=None,
@ -409,8 +392,8 @@ class Manager(manager.Manager):
# kept as it is in order to detect unnecessarily complex code, which is not
# this case.
def _expand_indirect_assignment(self, ref, user_id=None,
project_id=None, subtree_ids=None):
def _expand_indirect_assignment(self, ref, user_id=None, project_id=None,
subtree_ids=None, expand_groups=True):
"""Returns a list of expanded role assignments.
This methods is called for each discovered assignment that either needs
@ -428,6 +411,9 @@ class Manager(manager.Manager):
already ensured only those assignments that could affect them
were passed to this method.
If expand_groups is True then we expand groups out to a list of
assignments, one for each member of that group.
"""
def create_group_assignment(base_ref, user_id):
"""Creates a group assignment from the provided ref."""
@ -482,12 +468,15 @@ class Manager(manager.Manager):
for m in self.identity_api.list_users_in_group(
ref['group_id'])]
def expand_inherited_assignment(ref, user_id, project_id, subtree_ids):
def expand_inherited_assignment(ref, user_id, project_id, subtree_ids,
expand_groups):
"""Expands inherited role assignments.
If this is a group role assignment on a target, replace it by a
list of role assignments containing one for each user of that
group, on every project under that target.
If expand_groups is True and this is a group role assignment on a
target, replace it by a list of role assignments containing one for
each user of that group, on every project under that target. If
expand_groups is False, then return a group assignment on an
inherited target.
If this is a user role assignment on a specific target (i.e.
project_id is specified, but subtree_ids is None) then simply
@ -587,8 +576,15 @@ class Manager(manager.Manager):
new_refs = []
if 'group_id' in ref:
# Expand role assignment for all members and for all projects
for ref in expand_group_assignment(ref, user_id):
if expand_groups:
# Expand role assignment to all group members on any
# inherited target of any of the projects
for ref in expand_group_assignment(ref, user_id):
new_refs += [create_inherited_assignment(ref, proj_id)
for proj_id in project_ids]
else:
# Just place the group assignment on any inherited target
# of any of the projects
new_refs += [create_inherited_assignment(ref, proj_id)
for proj_id in project_ids]
else:
@ -599,9 +595,9 @@ class Manager(manager.Manager):
return new_refs
if ref.get('inherited_to_projects') == 'projects':
return expand_inherited_assignment(ref, user_id, project_id,
subtree_ids)
elif 'group_id' in ref:
return expand_inherited_assignment(
ref, user_id, project_id, subtree_ids, expand_groups)
elif 'group_id' in ref and expand_groups:
return expand_group_assignment(ref, user_id)
return [ref]
@ -669,7 +665,7 @@ class Manager(manager.Manager):
def _list_effective_role_assignments(self, role_id, user_id, group_id,
domain_id, project_id, subtree_ids,
inherited):
inherited, source_from_group_ids):
"""List role assignments in effective mode.
When using effective mode, besides the direct assignments, the indirect
@ -786,24 +782,31 @@ class Manager(manager.Manager):
if group_id or (domain_id and inherited):
return []
if user_id and source_from_group_ids:
# You can't do both - and since source_from_group_ids is only used
# internally, this must be a coding error by the caller.
msg = _('Cannot list assignments sourced from groups and filtered '
'by user ID.')
raise exception.UnexpectedError(msg)
# If filtering by domain, then only non-inherited assignments are
# relevant, since domains don't inherit assignments
inherited = False if domain_id else inherited
# List user assignments.
# List user or explicit group assignments.
# Due to the need to expand implied roles, this call will skip
# filtering by role_id and instead return the whole set of roles.
# Matching on the specified role is performed at the end.
direct_refs = list_role_assignments_for_actor(
role_id=None, user_id=user_id, project_id=project_id,
subtree_ids=subtree_ids, domain_id=domain_id,
inherited=inherited)
role_id=None, user_id=user_id, group_ids=source_from_group_ids,
project_id=project_id, subtree_ids=subtree_ids,
domain_id=domain_id, inherited=inherited)
# And those from the user's groups. Again, role_id is not
# used to filter here
# And those from the user's groups, so long as we are not restricting
# to a set of source groups (in which case we already got those
# assignments in the direct listing above).
group_refs = []
if user_id:
if not source_from_group_ids and user_id:
group_ids = self._get_group_ids_for_user_id(user_id)
if group_ids:
group_refs = list_role_assignments_for_actor(
@ -813,10 +816,10 @@ class Manager(manager.Manager):
# Expand grouping and inheritance on retrieved role assignments
refs = []
expand_groups = (source_from_group_ids is None)
for ref in (direct_refs + group_refs):
refs += self._expand_indirect_assignment(
ref=ref, user_id=user_id, project_id=project_id,
subtree_ids=subtree_ids)
ref, user_id, project_id, subtree_ids, expand_groups)
refs = self._add_implied_roles(refs)
if role_id:
@ -850,7 +853,8 @@ class Manager(manager.Manager):
def list_role_assignments(self, role_id=None, user_id=None, group_id=None,
domain_id=None, project_id=None,
include_subtree=False, inherited=None,
effective=None, include_names=False):
effective=None, include_names=False,
source_from_group_ids=None):
"""List role assignments, honoring effective mode and provided filters.
Returns a list of role assignments, where their attributes match the
@ -869,7 +873,18 @@ class Manager(manager.Manager):
affect a user, for example the roles that would be placed in a token.
If include_names is set to true the entities' names are returned
in addition to their id's
in addition to their id's.
source_from_group_ids is a list of group IDs and, if specified, then
only those assignments that are derived from membership of these groups
are considered, and any such assignments will not be expanded into
their user membership assignments. This is different to a group filter
of the resulting list, instead being a restriction on which assignments
should be considered before expansion of inheritance. This option is
only used internally (i.e. it is not exposed at the API level) and is
only supported in effective mode (since in regular mode there is no
difference between this and a group filter, other than it is a list of
groups).
If OS-INHERIT extension is disabled or the used driver does not support
inherited roles retrieval, inherited role assignments will be ignored.
@ -889,7 +904,7 @@ class Manager(manager.Manager):
if effective:
role_assignments = self._list_effective_role_assignments(
role_id, user_id, group_id, domain_id, project_id,
subtree_ids, inherited)
subtree_ids, inherited, source_from_group_ids)
else:
role_assignments = self._list_direct_role_assignments(
role_id, user_id, group_id, domain_id, project_id,
@ -1105,71 +1120,6 @@ class AssignmentDriverBase(object):
"""
raise exception.NotImplemented() # pragma: no cover
@abc.abstractmethod
def list_project_ids_for_groups(self, group_ids, hints,
inherited=False):
"""List project ids accessible to specified groups.
:param group_ids: List of group ids.
:param hints: filter hints which the driver should
implement if at all possible.
:param inherited: whether assignments marked as inherited should
be included.
:returns: List of project ids accessible to specified groups.
This method should not try and expand any inherited assignments,
just report the projects that have the role for this group. The manager
method is responsible for expanding out inherited assignments.
"""
raise exception.NotImplemented() # pragma: no cover
@abc.abstractmethod
def list_domain_ids_for_groups(self, group_ids, inherited=False):
"""List domain ids accessible to specified groups.
:param group_ids: List of group ids.
:param inherited: whether to return domain_ids that have inherited
assignments or not.
:returns: List of domain ids accessible to specified groups.
"""
raise exception.NotImplemented() # pragma: no cover
@abc.abstractmethod
def list_role_ids_for_groups_on_project(
self, group_ids, project_id, project_domain_id, project_parents):
"""List the group role ids for a specific project.
Supports the ``OS-INHERIT`` role inheritance from the project's domain
if supported by the assignment driver.
:param group_ids: list of group ids
:type group_ids: list
:param project_id: project identifier
:type project_id: str
:param project_domain_id: project's domain identifier
:type project_domain_id: str
:param project_parents: list of parent ids of this project
:type project_parents: list
:returns: list of role ids for the project
:rtype: list
"""
raise exception.NotImplemented()
@abc.abstractmethod
def list_role_ids_for_groups_on_domain(self, group_ids, domain_id):
"""List the group role ids for a specific domain.
:param group_ids: list of group ids
:type group_ids: list
:param domain_id: domain identifier
:type domain_id: str
:returns: list of role ids for the project
:rtype: list
"""
raise exception.NotImplemented()
@abc.abstractmethod
def delete_project_assignments(self, project_id):
"""Deletes all assignments for a project.
@ -1265,6 +1215,71 @@ class AssignmentDriverV8(AssignmentDriverBase):
"""
raise exception.NotImplemented() # pragma: no cover
@abc.abstractmethod
def list_project_ids_for_groups(self, group_ids, hints,
inherited=False):
"""List project ids accessible to specified groups.
:param group_ids: List of group ids.
:param hints: filter hints which the driver should
implement if at all possible.
:param inherited: whether assignments marked as inherited should
be included.
:returns: List of project ids accessible to specified groups.
This method should not try and expand any inherited assignments,
just report the projects that have the role for this group. The manager
method is responsible for expanding out inherited assignments.
"""
raise exception.NotImplemented() # pragma: no cover
@abc.abstractmethod
def list_domain_ids_for_groups(self, group_ids, inherited=False):
"""List domain ids accessible to specified groups.
:param group_ids: List of group ids.
:param inherited: whether to return domain_ids that have inherited
assignments or not.
:returns: List of domain ids accessible to specified groups.
"""
raise exception.NotImplemented() # pragma: no cover
@abc.abstractmethod
def list_role_ids_for_groups_on_project(
self, group_ids, project_id, project_domain_id, project_parents):
"""List the group role ids for a specific project.
Supports the ``OS-INHERIT`` role inheritance from the project's domain
if supported by the assignment driver.
:param group_ids: list of group ids
:type group_ids: list
:param project_id: project identifier
:type project_id: str
:param project_domain_id: project's domain identifier
:type project_domain_id: str
:param project_parents: list of parent ids of this project
:type project_parents: list
:returns: list of role ids for the project
:rtype: list
"""
raise exception.NotImplemented()
@abc.abstractmethod
def list_role_ids_for_groups_on_domain(self, group_ids, domain_id):
"""List the group role ids for a specific domain.
:param group_ids: list of group ids
:type group_ids: list
:param domain_id: domain identifier
:type domain_id: str
:returns: list of role ids for the project
:rtype: list
"""
raise exception.NotImplemented()
class AssignmentDriverV9(AssignmentDriverBase):
"""New or redefined methods from V8.
@ -1362,24 +1377,6 @@ class V9AssignmentWrapperForV8Driver(AssignmentDriverV9):
domain_id=domain_id, project_ids=project_ids,
inherited_to_projects=inherited_to_projects)
def list_project_ids_for_groups(self, group_ids, hints,
inherited=False):
return self.driver.list_project_ids_for_groups(
group_ids, hints, inherited=inherited)
def list_domain_ids_for_groups(self, group_ids, inherited=False):
return self.driver.list_domain_ids_for_groups(
group_ids, inherited=inherited)
def list_role_ids_for_groups_on_project(
self, group_ids, project_id, project_domain_id, project_parents):
return self.driver.list_role_ids_for_groups_on_project(
group_ids, project_id, project_domain_id, project_parents)
def list_role_ids_for_groups_on_domain(self, group_ids, domain_id):
return self.driver.list_role_ids_for_groups_on_domain(
group_ids, domain_id)
def delete_project_assignments(self, project_id):
self.driver.delete_project_assignments(project_id)

View File

@ -138,8 +138,9 @@ class AssignmentTestHelperMixin(object):
'results': [{'group': 0, 'role': 2, 'domain': 0},
{'user': 0, 'role': 2, 'project': 0}]}]
# The 'params' key also supports the 'effective' and
# 'inherited_to_projects' options to list_role_assignments.}
# The 'params' key also supports the 'effective',
# 'inherited_to_projects' and 'source_from_group_ids' options to
# list_role_assignments.}
"""
@ -394,6 +395,13 @@ class AssignmentTestHelperMixin(object):
expected_assignment[key] = value
self.assertIn(expected_assignment, actual)
def convert_group_ids_sourced_from_list(index_list, reference_data):
value_list = []
for group_index in index_list:
value_list.append(
reference_data['groups'][group_index]['id'])
return value_list
# Go through each test in the array, processing the input params, which
# we build into an args dict, and then call list_role_assignments. Then
# check the results against those specified in the test plan.
@ -403,6 +411,10 @@ class AssignmentTestHelperMixin(object):
if param in ['effective', 'inherited', 'include_subtree']:
# Just pass the value into the args
args[param] = test['params'][param]
elif param == 'source_from_group_ids':
# Convert the list of indexes into a list of IDs
args[param] = convert_group_ids_sourced_from_list(
test['params']['source_from_group_ids'], test_data)
else:
# Turn 'entity : 0' into 'entity_id = ac6736ba873d'
# where entity in user, group, project or domain
@ -1970,6 +1982,91 @@ class IdentityTests(AssignmentTestHelperMixin):
}
self.execute_assignment_plan(test_plan)
def test_list_role_assignment_using_sourced_groups(self):
"""Test listing assignments when restricted by source groups."""
test_plan = {
# The default domain with 3 users, 3 groups, 3 projects,
# plus 3 roles.
'entities': {'domains': {'id': DEFAULT_DOMAIN_ID,
'users': 3, 'groups': 3, 'projects': 3},
'roles': 3},
# Users 0 & 1 are in the group 0, User 0 also in group 1
'group_memberships': [{'group': 0, 'users': [0, 1]},
{'group': 1, 'users': [0]}],
# Spread the assignments around - we want to be able to show that
# if sourced by group, assignments from other sources are excluded
'assignments': [{'user': 0, 'role': 0, 'project': 0},
{'group': 0, 'role': 1, 'project': 1},
{'group': 1, 'role': 2, 'project': 0},
{'group': 1, 'role': 2, 'project': 1},
{'user': 2, 'role': 1, 'project': 1},
{'group': 2, 'role': 2, 'project': 2}
],
'tests': [
# List all effective assignments sourced from groups 0 and 1
{'params': {'source_from_group_ids': [0, 1],
'effective': True},
'results': [{'group': 0, 'role': 1, 'project': 1},
{'group': 1, 'role': 2, 'project': 0},
{'group': 1, 'role': 2, 'project': 1}
]},
# Adding a role a filter should further restrict the entries
{'params': {'source_from_group_ids': [0, 1], 'role': 2,
'effective': True},
'results': [{'group': 1, 'role': 2, 'project': 0},
{'group': 1, 'role': 2, 'project': 1}
]},
]
}
self.execute_assignment_plan(test_plan)
def test_list_role_assignment_using_sourced_groups_with_domains(self):
"""Test listing domain assignments when restricted by source groups."""
test_plan = {
# A domain with 3 users, 3 groups, 3 projects, a second domain,
# plus 3 roles.
'entities': {'domains': [{'users': 3, 'groups': 3, 'projects': 3},
1],
'roles': 3},
# Users 0 & 1 are in the group 0, User 0 also in group 1
'group_memberships': [{'group': 0, 'users': [0, 1]},
{'group': 1, 'users': [0]}],
# Spread the assignments around - we want to be able to show that
# if sourced by group, assignments from other sources are excluded
'assignments': [{'user': 0, 'role': 0, 'domain': 0},
{'group': 0, 'role': 1, 'domain': 1},
{'group': 1, 'role': 2, 'project': 0},
{'group': 1, 'role': 2, 'project': 1},
{'user': 2, 'role': 1, 'project': 1},
{'group': 2, 'role': 2, 'project': 2}
],
'tests': [
# List all effective assignments sourced from groups 0 and 1
{'params': {'source_from_group_ids': [0, 1],
'effective': True},
'results': [{'group': 0, 'role': 1, 'domain': 1},
{'group': 1, 'role': 2, 'project': 0},
{'group': 1, 'role': 2, 'project': 1}
]},
# Adding a role a filter should further restrict the entries
{'params': {'source_from_group_ids': [0, 1], 'role': 1,
'effective': True},
'results': [{'group': 0, 'role': 1, 'domain': 1},
]},
]
}
self.execute_assignment_plan(test_plan)
def test_list_role_assignment_fails_with_userid_and_source_groups(self):
"""Show we trap this unsupported internal combination of params."""
group = unit.new_group_ref(domain_id=DEFAULT_DOMAIN_ID)
group = self.identity_api.create_group(group)
self.assertRaises(exception.UnexpectedError,
self.assignment_api.list_role_assignments,
effective=True,
user_id=self.user_foo['id'],
source_from_group_ids=[group['id']])
def test_delete_domain_with_user_group_project_links(self):
# TODO(chungg):add test case once expected behaviour defined
pass
@ -6546,6 +6643,47 @@ class InheritanceTests(AssignmentTestHelperMixin):
for x in range(0, 4):
self.assertIn(test_data['users'][x]['id'], user_ids)
def test_list_role_assignment_using_inherited_sourced_groups(self):
"""Test listing inherited assignments when restricted by groups."""
test_plan = {
# A domain with 3 users, 3 groups, 3 projects, a second domain,
# plus 3 roles.
'entities': {'domains': [{'users': 3, 'groups': 3, 'projects': 3},
1],
'roles': 3},
# Users 0 & 1 are in the group 0, User 0 also in group 1
'group_memberships': [{'group': 0, 'users': [0, 1]},
{'group': 1, 'users': [0]}],
# Spread the assignments around - we want to be able to show that
# if sourced by group, assignments from other sources are excluded
'assignments': [{'user': 0, 'role': 0, 'domain': 0},
{'group': 0, 'role': 1, 'domain': 1},
{'group': 1, 'role': 2, 'domain': 0,
'inherited_to_projects': True},
{'group': 1, 'role': 2, 'project': 1},
{'user': 2, 'role': 1, 'project': 1,
'inherited_to_projects': True},
{'group': 2, 'role': 2, 'project': 2}
],
'tests': [
# List all effective assignments sourced from groups 0 and 1.
# We should see the inherited group assigned on the 3 projects
# from domain 0, as well as the direct assignments.
{'params': {'source_from_group_ids': [0, 1],
'effective': True},
'results': [{'group': 0, 'role': 1, 'domain': 1},
{'group': 1, 'role': 2, 'project': 0,
'indirect': {'domain': 0}},
{'group': 1, 'role': 2, 'project': 1,
'indirect': {'domain': 0}},
{'group': 1, 'role': 2, 'project': 2,
'indirect': {'domain': 0}},
{'group': 1, 'role': 2, 'project': 1}
]},
]
}
self.execute_assignment_plan(test_plan)
class ImpliedRoleTests(AssignmentTestHelperMixin):

View File

@ -981,6 +981,13 @@ class BaseLDAPIdentity(test_backend.IdentityTests):
def test_domain_crud(self):
self.skipTest('Resource LDAP has been removed')
def test_list_role_assignment_using_sourced_groups_with_domains(self):
"""Multiple domain assignments are not supported."""
self.assertRaises(
(exception.Forbidden, exception.DomainNotFound),
super(BaseLDAPIdentity, self).
test_list_role_assignment_using_sourced_groups_with_domains)
class LDAPIdentity(BaseLDAPIdentity, unit.TestCase):
@ -2553,6 +2560,12 @@ class MultiLDAPandSQLIdentity(BaseLDAPIdentity, unit.SQLDriverOverrides,
super(BaseLDAPIdentity, self).\
test_list_role_assignment_by_user_with_domain_group_roles
def test_list_role_assignment_using_sourced_groups_with_domains(self):
# With SQL Assignment this method should work, so override the override
# from BaseLDAPIdentity
base = super(BaseLDAPIdentity, self)
base.test_list_role_assignment_using_sourced_groups_with_domains()
class MultiLDAPandSQLIdentityDomainConfigsInSQL(MultiLDAPandSQLIdentity):
"""Class to test the use of domain configs stored in the database.

View File

@ -1,8 +1,10 @@
---
features:
- The list_project_ids_for_user(), list_domain_ids_for_user() and
list_user_ids_for_project() methods have been removed from the V9 version
of the Assignment driver.
- The list_project_ids_for_user(), list_domain_ids_for_user(),
list_user_ids_for_project(), list_project_ids_for_groups(),
list_domain_ids_for_groups(), list_role_ids_for_groups_on_project() and
list_role_ids_for_groups_on_domain() methods have been removed from the
V9 version of the Assignment driver.
upgrade:
- The V8 Assignment driver interface is deprecated, but still supported in
this release, so any custom drivers based on the V8 interface should still