summaryrefslogtreecommitdiffstats
path: root/keystone-moon/keystone/assignment/core.py
diff options
context:
space:
mode:
Diffstat (limited to 'keystone-moon/keystone/assignment/core.py')
-rw-r--r--keystone-moon/keystone/assignment/core.py660
1 files changed, 465 insertions, 195 deletions
diff --git a/keystone-moon/keystone/assignment/core.py b/keystone-moon/keystone/assignment/core.py
index 0f9c03e9..a001e6b1 100644
--- a/keystone-moon/keystone/assignment/core.py
+++ b/keystone-moon/keystone/assignment/core.py
@@ -12,9 +12,10 @@
# License for the specific language governing permissions and limitations
# under the License.
-"""Main entry point into the assignment service."""
+"""Main entry point into the Assignment service."""
import abc
+import copy
from oslo_config import cfg
from oslo_log import log
@@ -28,7 +29,6 @@ from keystone import exception
from keystone.i18n import _
from keystone.i18n import _LI
from keystone import notifications
-from keystone.openstack.common import versionutils
CONF = cfg.CONF
@@ -36,40 +36,6 @@ LOG = log.getLogger(__name__)
MEMOIZE = cache.get_memoization_decorator(section='role')
-def deprecated_to_role_api(f):
- """Specialized deprecation wrapper for assignment to role api.
-
- This wraps the standard deprecation wrapper and fills in the method
- names automatically.
-
- """
- @six.wraps(f)
- def wrapper(*args, **kwargs):
- x = versionutils.deprecated(
- what='assignment.' + f.__name__ + '()',
- as_of=versionutils.deprecated.KILO,
- in_favor_of='role.' + f.__name__ + '()')
- return x(f)
- return wrapper()
-
-
-def deprecated_to_resource_api(f):
- """Specialized deprecation wrapper for assignment to resource api.
-
- This wraps the standard deprecation wrapper and fills in the method
- names automatically.
-
- """
- @six.wraps(f)
- def wrapper(*args, **kwargs):
- x = versionutils.deprecated(
- what='assignment.' + f.__name__ + '()',
- as_of=versionutils.deprecated.KILO,
- in_favor_of='resource.' + f.__name__ + '()')
- return x(f)
- return wrapper()
-
-
@dependency.provider('assignment_api')
@dependency.requires('credential_api', 'identity_api', 'resource_api',
'revoke_api', 'role_api')
@@ -80,6 +46,9 @@ class Manager(manager.Manager):
dynamically calls the backend.
"""
+
+ driver_namespace = 'keystone.assignment'
+
_PROJECT = 'project'
_ROLE_REMOVED_FROM_USER = 'role_removed_from_user'
_INVALIDATION_USER_PROJECT_TOKENS = 'invalidate_user_project_tokens'
@@ -129,7 +98,7 @@ class Manager(manager.Manager):
"""
def _get_group_project_roles(user_id, project_ref):
group_ids = self._get_group_ids_for_user_id(user_id)
- return self.driver.list_role_ids_for_groups_on_project(
+ return self.list_role_ids_for_groups_on_project(
group_ids,
project_ref['id'],
project_ref['domain_id'],
@@ -155,7 +124,8 @@ class Manager(manager.Manager):
except (exception.MetadataNotFound, exception.NotImplemented):
pass
# As well inherited roles from parent projects
- for p in self.list_project_parents(project_ref['id']):
+ for p in self.resource_api.list_project_parents(
+ project_ref['id']):
p_roles = self.list_grants(
user_id=user_id, project_id=p['id'],
inherited_to_projects=True)
@@ -207,7 +177,7 @@ class Manager(manager.Manager):
return self._roles_from_role_dicts(
metadata_ref.get('roles', {}), False)
- self.get_domain(domain_id)
+ self.resource_api.get_domain(domain_id)
user_role_list = _get_user_domain_roles(user_id, domain_id)
group_role_list = _get_group_domain_roles(user_id, domain_id)
# Use set() to process the list to remove any duplicates
@@ -218,11 +188,11 @@ class Manager(manager.Manager):
if project_id is not None:
project = self.resource_api.get_project(project_id)
- role_ids = self.driver.list_role_ids_for_groups_on_project(
+ 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))
elif domain_id is not None:
- role_ids = self.driver.list_role_ids_for_groups_on_domain(
+ role_ids = self.list_role_ids_for_groups_on_domain(
group_ids, domain_id)
else:
raise AttributeError(_("Must specify either domain or project"))
@@ -261,10 +231,24 @@ class Manager(manager.Manager):
tenant_id,
CONF.member_role_id)
- def add_role_to_user_and_project(self, user_id, tenant_id, role_id):
- self.resource_api.get_project(tenant_id)
+ @notifications.role_assignment('created')
+ def _add_role_to_user_and_project_adapter(self, role_id, user_id=None,
+ group_id=None, domain_id=None,
+ project_id=None,
+ inherited_to_projects=False,
+ context=None):
+
+ # The parameters for this method must match the parameters for
+ # create_grant so that the notifications.role_assignment decorator
+ # will work.
+
+ self.resource_api.get_project(project_id)
self.role_api.get_role(role_id)
- self.driver.add_role_to_user_and_project(user_id, tenant_id, role_id)
+ self.driver.add_role_to_user_and_project(user_id, project_id, role_id)
+
+ def add_role_to_user_and_project(self, user_id, tenant_id, role_id):
+ self._add_role_to_user_and_project_adapter(
+ role_id, user_id=user_id, project_id=tenant_id)
def remove_user_from_project(self, tenant_id, user_id):
"""Remove user from a tenant
@@ -299,7 +283,7 @@ class Manager(manager.Manager):
# optimization with the various backend technologies (SQL, LDAP etc.).
group_ids = self._get_group_ids_for_user_id(user_id)
- project_ids = self.driver.list_project_ids_for_user(
+ project_ids = self.list_project_ids_for_user(
user_id, group_ids, hints or driver_hints.Hints())
if not CONF.os_inherit.enabled:
@@ -309,7 +293,7 @@ class Manager(manager.Manager):
# inherited role (direct or group) on any parent project, in which
# case we must add in all the projects in that parent's subtree.
project_ids = set(project_ids)
- project_ids_inherited = self.driver.list_project_ids_for_user(
+ project_ids_inherited = self.list_project_ids_for_user(
user_id, group_ids, hints or driver_hints.Hints(), inherited=True)
for proj_id in project_ids_inherited:
project_ids.update(
@@ -317,7 +301,7 @@ class Manager(manager.Manager):
self.resource_api.list_projects_in_subtree(proj_id)))
# Now do the same for any domain inherited roles
- domain_ids = self.driver.list_domain_ids_for_user(
+ domain_ids = self.list_domain_ids_for_user(
user_id, group_ids, hints or driver_hints.Hints(),
inherited=True)
project_ids.update(
@@ -335,33 +319,42 @@ class Manager(manager.Manager):
# projects for a user is pushed down into the driver to enable
# optimization with the various backend technologies (SQL, LDAP etc.).
group_ids = self._get_group_ids_for_user_id(user_id)
- domain_ids = self.driver.list_domain_ids_for_user(
+ domain_ids = self.list_domain_ids_for_user(
user_id, group_ids, hints or driver_hints.Hints())
return self.resource_api.list_domains_from_ids(domain_ids)
def list_domains_for_groups(self, group_ids):
- domain_ids = self.driver.list_domain_ids_for_groups(group_ids)
+ domain_ids = self.list_domain_ids_for_groups(group_ids)
return self.resource_api.list_domains_from_ids(domain_ids)
def list_projects_for_groups(self, group_ids):
project_ids = (
- self.driver.list_project_ids_for_groups(group_ids,
- driver_hints.Hints()))
+ 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)
- # Inherited roles are enabled, so check to see if these groups have any
- # roles on any domain, in which case we must add in all the projects
- # in that domain.
+ # 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.driver.list_domain_ids_for_groups(
- group_ids, inherited=True)
+ 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)))
+ list(set(project_ids + project_ids_from_domains + subproject_ids)))
def list_role_assignments_for_role(self, role_id=None):
# NOTE(henry-nash): Currently the efficiency of the key driver
@@ -374,17 +367,37 @@ class Manager(manager.Manager):
return [r for r in self.driver.list_role_assignments()
if r['role_id'] == role_id]
- def remove_role_from_user_and_project(self, user_id, tenant_id, role_id):
- self.driver.remove_role_from_user_and_project(user_id, tenant_id,
+ @notifications.role_assignment('deleted')
+ def _remove_role_from_user_and_project_adapter(self, role_id, user_id=None,
+ group_id=None,
+ domain_id=None,
+ project_id=None,
+ inherited_to_projects=False,
+ context=None):
+
+ # The parameters for this method must match the parameters for
+ # delete_grant so that the notifications.role_assignment decorator
+ # will work.
+
+ self.driver.remove_role_from_user_and_project(user_id, project_id,
role_id)
self.identity_api.emit_invalidate_user_token_persistence(user_id)
self.revoke_api.revoke_by_grant(role_id, user_id=user_id,
- project_id=tenant_id)
+ project_id=project_id)
+
+ def remove_role_from_user_and_project(self, user_id, tenant_id, role_id):
+ self._remove_role_from_user_and_project_adapter(
+ role_id, user_id=user_id, project_id=tenant_id)
@notifications.internal(notifications.INVALIDATE_USER_TOKEN_PERSISTENCE)
def _emit_invalidate_user_token_persistence(self, user_id):
self.identity_api.emit_invalidate_user_token_persistence(user_id)
+ def _emit_invalidate_grant_token_persistence(self, user_id, project_id):
+ self.identity_api.emit_invalidate_grant_token_persistence(
+ {'user_id': user_id, 'project_id': project_id}
+ )
+
@notifications.role_assignment('created')
def create_grant(self, role_id, user_id=None, group_id=None,
domain_id=None, project_id=None,
@@ -405,7 +418,7 @@ class Manager(manager.Manager):
self.resource_api.get_domain(domain_id)
if project_id:
self.resource_api.get_project(project_id)
- self.driver.check_grant_role_id(
+ self.check_grant_role_id(
role_id, user_id, group_id, domain_id, project_id,
inherited_to_projects)
return role_ref
@@ -417,11 +430,15 @@ class Manager(manager.Manager):
self.resource_api.get_domain(domain_id)
if project_id:
self.resource_api.get_project(project_id)
- grant_ids = self.driver.list_grant_role_ids(
+ grant_ids = self.list_grant_role_ids(
user_id, group_id, domain_id, project_id, inherited_to_projects)
return self.role_api.list_roles_from_ids(grant_ids)
@notifications.role_assignment('deleted')
+ def _emit_revoke_user_grant(self, role_id, user_id, domain_id, project_id,
+ inherited_to_projects, context):
+ self._emit_invalidate_grant_token_persistence(user_id, project_id)
+
def delete_grant(self, role_id, user_id=None, group_id=None,
domain_id=None, project_id=None,
inherited_to_projects=False, context=None):
@@ -430,17 +447,29 @@ class Manager(manager.Manager):
role_id=role_id,
domain_id=domain_id,
project_id=project_id)
+ self._emit_revoke_user_grant(
+ role_id, user_id, domain_id, project_id,
+ inherited_to_projects, context)
else:
try:
- # NOTE(morganfainberg): The user ids are the important part
- # for invalidating tokens below, so extract them here.
- for user in self.identity_api.list_users_in_group(group_id):
- if user['id'] != user_id:
- self._emit_invalidate_user_token_persistence(
- user['id'])
- self.revoke_api.revoke_by_grant(
- user_id=user['id'], role_id=role_id,
- domain_id=domain_id, project_id=project_id)
+ # Group may contain a lot of users so revocation will be
+ # by role & domain/project
+ if domain_id is None:
+ self.revoke_api.revoke_by_project_role_assignment(
+ project_id, role_id
+ )
+ else:
+ self.revoke_api.revoke_by_domain_role_assignment(
+ domain_id, role_id
+ )
+ if CONF.token.revoke_by_id:
+ # NOTE(morganfainberg): The user ids are the important part
+ # for invalidating tokens below, so extract them here.
+ for user in self.identity_api.list_users_in_group(
+ group_id):
+ self._emit_revoke_user_grant(
+ role_id, user['id'], domain_id, project_id,
+ inherited_to_projects, context)
except exception.GroupNotFound:
LOG.debug('Group %s not found, no tokens to invalidate.',
group_id)
@@ -457,8 +486,356 @@ class Manager(manager.Manager):
self.resource_api.get_project(project_id)
self.driver.delete_grant(role_id, user_id, group_id, domain_id,
project_id, inherited_to_projects)
- if user_id is not None:
- self._emit_invalidate_user_token_persistence(user_id)
+
+ # The methods _expand_indirect_assignment, _list_direct_role_assignments
+ # and _list_effective_role_assignments below are only used on
+ # list_role_assignments, but they are not in its scope as nested functions
+ # since it would significantly increase McCabe complexity, that should be
+ # 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):
+ """Returns a list of expanded role assignments.
+
+ This methods is called for each discovered assignment that either needs
+ a group assignment expanded into individual user assignments, or needs
+ an inherited assignment to be applied to its children.
+
+ In all cases, if either user_id and/or project_id is specified, then we
+ filter the result on those values.
+
+ """
+
+ def create_group_assignment(base_ref, user_id):
+ """Creates a group assignment from the provided ref."""
+
+ ref = copy.deepcopy(base_ref)
+
+ ref['user_id'] = user_id
+
+ indirect = ref.setdefault('indirect', {})
+ indirect['group_id'] = ref.pop('group_id')
+
+ return ref
+
+ def expand_group_assignment(ref, user_id):
+ """Expands group role assignment.
+
+ For any group role assignment on a target, it is replaced by a list
+ of role assignments containing one for each user of that group on
+ that target.
+
+ An example of accepted ref is:
+
+ {
+ 'group_id': group_id,
+ 'project_id': project_id,
+ 'role_id': role_id
+ }
+
+ Once expanded, it should be returned as a list of entities like the
+ one below, one for each each user_id in the provided group_id.
+
+ {
+ 'user_id': user_id,
+ 'project_id': project_id,
+ 'role_id': role_id,
+ 'indirect' : {
+ 'group_id': group_id
+ }
+ }
+
+ Returned list will be formatted by the Controller, which will
+ deduce a role assignment came from group membership if it has both
+ 'user_id' in the main body of the dict and 'group_id' in indirect
+ subdict.
+
+ """
+ if user_id:
+ return [create_group_assignment(ref, user_id=user_id)]
+
+ return [create_group_assignment(ref, user_id=m['id'])
+ for m in self.identity_api.list_users_in_group(
+ ref['group_id'])]
+
+ def expand_inherited_assignment(ref, user_id, project_id=None):
+ """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 this is a user role assignment on a target, replace it by a
+ list of role assignments for that user on every project under
+ that target.
+
+ An example of accepted ref is:
+
+ {
+ 'group_id': group_id,
+ 'project_id': parent_id,
+ 'role_id': role_id,
+ 'inherited_to_projects': 'projects'
+ }
+
+ Once expanded, it should be returned as a list of entities like the
+ one below, one for each each user_id in the provided group_id and
+ for each subproject_id in the project_id subtree.
+
+ {
+ 'user_id': user_id,
+ 'project_id': subproject_id,
+ 'role_id': role_id,
+ 'indirect' : {
+ 'group_id': group_id,
+ 'project_id': parent_id
+ }
+ }
+
+ Returned list will be formatted by the Controller, which will
+ deduce a role assignment came from group membership if it has both
+ 'user_id' in the main body of the dict and 'group_id' in the
+ 'indirect' subdict, as well as it is possible to deduce if it has
+ come from inheritance if it contains both a 'project_id' in the
+ main body of the dict and 'parent_id' in the 'indirect' subdict.
+
+ """
+ def create_inherited_assignment(base_ref, project_id):
+ """Creates a project assignment from the provided ref.
+
+ base_ref can either be a project or domain inherited
+ assignment ref.
+
+ """
+ ref = copy.deepcopy(base_ref)
+
+ indirect = ref.setdefault('indirect', {})
+ if ref.get('project_id'):
+ indirect['project_id'] = ref.pop('project_id')
+ else:
+ indirect['domain_id'] = ref.pop('domain_id')
+
+ ref['project_id'] = project_id
+ ref.pop('inherited_to_projects')
+
+ return ref
+
+ # Define expanded project list to which to apply this assignment
+ if project_id:
+ # Since ref is an inherited assignment, it must have come from
+ # the domain or a parent. We only need apply it to the project
+ # requested.
+ project_ids = [project_id]
+ elif ref.get('domain_id'):
+ # A domain inherited assignment, so apply it to all projects
+ # in this domain
+ project_ids = (
+ [x['id'] for x in
+ self.resource_api.list_projects_in_domain(
+ ref['domain_id'])])
+ else:
+ # It must be a project assignment, so apply it to the subtree
+ project_ids = (
+ [x['id'] for x in
+ self.resource_api.list_projects_in_subtree(
+ ref['project_id'])])
+
+ 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):
+ new_refs += [create_inherited_assignment(ref, proj_id)
+ for proj_id in project_ids]
+ else:
+ # Expand role assignment for all projects
+ new_refs += [create_inherited_assignment(ref, proj_id)
+ for proj_id in project_ids]
+
+ return new_refs
+
+ if ref.get('inherited_to_projects') == 'projects':
+ return expand_inherited_assignment(ref, user_id, project_id)
+ elif 'group_id' in ref:
+ return expand_group_assignment(ref, user_id)
+ return [ref]
+
+ def _list_effective_role_assignments(self, role_id, user_id, group_id,
+ domain_id, project_id, inherited):
+ """List role assignments in effective mode.
+
+ When using effective mode, besides the direct assignments, the indirect
+ ones that come from grouping or inheritance are retrieved and will then
+ be expanded.
+
+ The resulting list of assignments will be filtered by the provided
+ parameters, although since we are in effective mode, group can never
+ act as a filter (since group assignments are expanded into user roles)
+ and domain can only be filter if we want non-inherited assignments,
+ since domains can't inherit assignments.
+
+ The goal of this method is to only ask the driver for those
+ assignments as could effect the result based on the parameter filters
+ specified, hence avoiding retrieving a huge list.
+
+ """
+
+ def list_role_assignments_for_actor(
+ role_id, inherited, user_id=None,
+ group_ids=None, project_id=None, domain_id=None):
+ """List role assignments for actor on target.
+
+ List direct and indirect assignments for an actor, optionally
+ for a given target (i.e. project or domain).
+
+ :param role_id: List for a specific role, can be None meaning all
+ roles
+ :param inherited: Indicates whether inherited assignments or only
+ direct assignments are required. If None, then
+ both are required.
+ :param user_id: If not None, list only assignments that affect this
+ user.
+ :param group_ids: A list of groups required. Only one of user_id
+ and group_ids can be specified
+ :param project_id: If specified, only include those assignments
+ that affect this project
+ :param domain_id: If specified, only include those assignments
+ that affect this domain - by definition this will
+ not include any inherited assignments
+
+ :returns: List of assignments matching the criteria. Any inherited
+ or group assignments that could affect the resulting
+ response are included.
+
+ """
+
+ # List direct project role assignments
+ project_ids = [project_id] if project_id else None
+
+ non_inherited_refs = []
+ if inherited is False or inherited is None:
+ # Get non inherited assignments
+ non_inherited_refs = self.driver.list_role_assignments(
+ role_id=role_id, domain_id=domain_id,
+ project_ids=project_ids, user_id=user_id,
+ group_ids=group_ids, inherited_to_projects=False)
+
+ inherited_refs = []
+ if inherited is True or inherited is None:
+ # Get inherited assignments
+ if project_id:
+ # If we are filtering by a specific project, then we can
+ # only get inherited assignments from its domain or from
+ # any of its parents.
+
+ # List inherited assignments from the project's domain
+ proj_domain_id = self.resource_api.get_project(
+ project_id)['domain_id']
+ inherited_refs += self.driver.list_role_assignments(
+ role_id=role_id, domain_id=proj_domain_id,
+ user_id=user_id, group_ids=group_ids,
+ inherited_to_projects=True)
+
+ # And those assignments that could be inherited from the
+ # project's parents.
+ parent_ids = [project['id'] for project in
+ self.resource_api.list_project_parents(
+ project_id)]
+ if parent_ids:
+ inherited_refs += self.driver.list_role_assignments(
+ role_id=role_id, project_ids=parent_ids,
+ user_id=user_id, group_ids=group_ids,
+ inherited_to_projects=True)
+ else:
+ # List inherited assignments without filtering by target
+ inherited_refs = self.driver.list_role_assignments(
+ role_id=role_id, user_id=user_id, group_ids=group_ids,
+ inherited_to_projects=True)
+
+ return non_inherited_refs + inherited_refs
+
+ # If filtering by group or inherited domain assignment the list is
+ # guranteed to be empty
+ if group_id or (domain_id and inherited):
+ return []
+
+ # 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
+ direct_refs = list_role_assignments_for_actor(
+ role_id=role_id, user_id=user_id, project_id=project_id,
+ domain_id=domain_id, inherited=inherited)
+
+ # And those from the user's groups
+ group_refs = []
+ if user_id:
+ group_ids = self._get_group_ids_for_user_id(user_id)
+ if group_ids:
+ group_refs = list_role_assignments_for_actor(
+ role_id=role_id, project_id=project_id,
+ group_ids=group_ids, domain_id=domain_id,
+ inherited=inherited)
+
+ # Expand grouping and inheritance on retrieved role assignments
+ refs = []
+ for ref in (direct_refs + group_refs):
+ refs += self._expand_indirect_assignment(ref=ref, user_id=user_id,
+ project_id=project_id)
+
+ return refs
+
+ def _list_direct_role_assignments(self, role_id, user_id, group_id,
+ domain_id, project_id, inherited):
+ """List role assignments without applying expansion.
+
+ Returns a list of direct role assignments, where their attributes match
+ the provided filters.
+
+ """
+ group_ids = [group_id] if group_id else None
+ project_ids = [project_id] if project_id else None
+
+ return self.driver.list_role_assignments(
+ role_id=role_id, user_id=user_id, group_ids=group_ids,
+ domain_id=domain_id, project_ids=project_ids,
+ inherited_to_projects=inherited)
+
+ def list_role_assignments(self, role_id=None, user_id=None, group_id=None,
+ domain_id=None, project_id=None, inherited=None,
+ effective=None):
+ """List role assignments, honoring effective mode and provided filters.
+
+ Returns a list of role assignments, where their attributes match the
+ provided filters (role_id, user_id, group_id, domain_id, project_id and
+ inherited). The inherited filter defaults to None, meaning to get both
+ non-inherited and inherited role assignments.
+
+ If effective mode is specified, this means that rather than simply
+ return the assignments that match the filters, any group or
+ inheritance assignments will be expanded. Group assignments will
+ become assignments for all the users in that group, and inherited
+ assignments will be shown on the projects below the assignment point.
+ Think of effective mode as being the list of assignments that actually
+ affect a user, for example the roles that would be placed in a token.
+
+ If OS-INHERIT extension is disabled or the used driver does not support
+ inherited roles retrieval, inherited role assignments will be ignored.
+
+ """
+
+ if not CONF.os_inherit.enabled:
+ if inherited:
+ return []
+ inherited = False
+
+ if effective:
+ return self._list_effective_role_assignments(
+ role_id, user_id, group_id, domain_id, project_id, inherited)
+ else:
+ return self._list_direct_role_assignments(
+ role_id, user_id, group_id, domain_id, project_id, inherited)
def delete_tokens_for_role_assignments(self, role_id):
assignments = self.list_role_assignments_for_role(role_id=role_id)
@@ -532,98 +909,6 @@ class Manager(manager.Manager):
# from persistence if persistence is enabled.
pass
- @deprecated_to_role_api
- def create_role(self, role_id, role):
- return self.role_api.create_role(role_id, role)
-
- @deprecated_to_role_api
- def get_role(self, role_id):
- return self.role_api.get_role(role_id)
-
- @deprecated_to_role_api
- def update_role(self, role_id, role):
- return self.role_api.update_role(role_id, role)
-
- @deprecated_to_role_api
- def delete_role(self, role_id):
- return self.role_api.delete_role(role_id)
-
- @deprecated_to_role_api
- def list_roles(self, hints=None):
- return self.role_api.list_roles(hints=hints)
-
- @deprecated_to_resource_api
- def create_project(self, project_id, project):
- return self.resource_api.create_project(project_id, project)
-
- @deprecated_to_resource_api
- def get_project_by_name(self, tenant_name, domain_id):
- return self.resource_api.get_project_by_name(tenant_name, domain_id)
-
- @deprecated_to_resource_api
- def get_project(self, project_id):
- return self.resource_api.get_project(project_id)
-
- @deprecated_to_resource_api
- def update_project(self, project_id, project):
- return self.resource_api.update_project(project_id, project)
-
- @deprecated_to_resource_api
- def delete_project(self, project_id):
- return self.resource_api.delete_project(project_id)
-
- @deprecated_to_resource_api
- def list_projects(self, hints=None):
- return self.resource_api.list_projects(hints=hints)
-
- @deprecated_to_resource_api
- def list_projects_in_domain(self, domain_id):
- return self.resource_api.list_projects_in_domain(domain_id)
-
- @deprecated_to_resource_api
- def create_domain(self, domain_id, domain):
- return self.resource_api.create_domain(domain_id, domain)
-
- @deprecated_to_resource_api
- def get_domain_by_name(self, domain_name):
- return self.resource_api.get_domain_by_name(domain_name)
-
- @deprecated_to_resource_api
- def get_domain(self, domain_id):
- return self.resource_api.get_domain(domain_id)
-
- @deprecated_to_resource_api
- def update_domain(self, domain_id, domain):
- return self.resource_api.update_domain(domain_id, domain)
-
- @deprecated_to_resource_api
- def delete_domain(self, domain_id):
- return self.resource_api.delete_domain(domain_id)
-
- @deprecated_to_resource_api
- def list_domains(self, hints=None):
- return self.resource_api.list_domains(hints=hints)
-
- @deprecated_to_resource_api
- def assert_domain_enabled(self, domain_id, domain=None):
- return self.resource_api.assert_domain_enabled(domain_id, domain)
-
- @deprecated_to_resource_api
- def assert_project_enabled(self, project_id, project=None):
- return self.resource_api.assert_project_enabled(project_id, project)
-
- @deprecated_to_resource_api
- def is_leaf_project(self, project_id):
- return self.resource_api.is_leaf_project(project_id)
-
- @deprecated_to_resource_api
- def list_project_parents(self, project_id, user_id=None):
- return self.resource_api.list_project_parents(project_id, user_id)
-
- @deprecated_to_resource_api
- def list_projects_in_subtree(self, project_id, user_id=None):
- return self.resource_api.list_projects_in_subtree(project_id, user_id)
-
@six.add_metaclass(abc.ABCMeta)
class Driver(object):
@@ -642,26 +927,6 @@ class Driver(object):
role_list.append(d['id'])
return role_list
- def _add_role_to_role_dicts(self, role_id, inherited, dict_list,
- allow_existing=True):
- # There is a difference in error semantics when trying to
- # assign a role that already exists between the coded v2 and v3
- # API calls. v2 will error if the assignment already exists,
- # while v3 is silent. Setting the 'allow_existing' parameter
- # appropriately lets this call be used for both.
- role_set = set([frozenset(r.items()) for r in dict_list])
- key = frozenset(self._role_to_dict(role_id, inherited).items())
- if not allow_existing and key in role_set:
- raise KeyError
- role_set.add(key)
- return [dict(r) for r in role_set]
-
- def _remove_role_from_role_dicts(self, role_id, inherited, dict_list):
- role_set = set([frozenset(r.items()) for r in dict_list])
- role_set.remove(frozenset(self._role_to_dict(role_id,
- inherited).items()))
- return [dict(r) for r in role_set]
-
def _get_list_limit(self):
return CONF.assignment.list_limit or CONF.list_limit
@@ -740,8 +1005,16 @@ class Driver(object):
raise exception.NotImplemented() # pragma: no cover
@abc.abstractmethod
- def list_role_assignments(self):
+ def list_role_assignments(self, role_id=None,
+ user_id=None, group_ids=None,
+ domain_id=None, project_ids=None,
+ inherited_to_projects=None):
+ """Returns a list of role assignments for actors on targets.
+
+ Available parameters represent values in which the returned role
+ assignments attributes need to be filtered on.
+ """
raise exception.NotImplemented() # pragma: no cover
@abc.abstractmethod
@@ -866,12 +1139,8 @@ class Driver(object):
raise exception.NotImplemented() # pragma: no cover
- # TODO(henry-nash): Rename the following two methods to match the more
- # meaningfully named ones above.
-
-# TODO(ayoung): determine what else these two functions raise
@abc.abstractmethod
- def delete_user(self, user_id):
+ def delete_user_assignments(self, user_id):
"""Deletes all assignments for a user.
:raises: keystone.exception.RoleNotFound
@@ -880,7 +1149,7 @@ class Driver(object):
raise exception.NotImplemented() # pragma: no cover
@abc.abstractmethod
- def delete_group(self, group_id):
+ def delete_group_assignments(self, group_id):
"""Deletes all assignments for a group.
:raises: keystone.exception.RoleNotFound
@@ -894,6 +1163,8 @@ class Driver(object):
class RoleManager(manager.Manager):
"""Default pivot point for the Role backend."""
+ driver_namespace = 'keystone.role'
+
_ROLE = 'role'
def __init__(self):
@@ -902,9 +1173,8 @@ class RoleManager(manager.Manager):
role_driver = CONF.role.driver
if role_driver is None:
- assignment_driver = (
- dependency.get_provider('assignment_api').driver)
- role_driver = assignment_driver.default_role_driver()
+ assignment_manager = dependency.get_provider('assignment_api')
+ role_driver = assignment_manager.default_role_driver()
super(RoleManager, self).__init__(role_driver)