aboutsummaryrefslogtreecommitdiffstats
path: root/keystone-moon/keystone/assignment/backends
diff options
context:
space:
mode:
Diffstat (limited to 'keystone-moon/keystone/assignment/backends')
-rw-r--r--keystone-moon/keystone/assignment/backends/__init__.py0
-rw-r--r--keystone-moon/keystone/assignment/backends/ldap.py545
-rw-r--r--keystone-moon/keystone/assignment/backends/sql.py319
3 files changed, 0 insertions, 864 deletions
diff --git a/keystone-moon/keystone/assignment/backends/__init__.py b/keystone-moon/keystone/assignment/backends/__init__.py
deleted file mode 100644
index e69de29b..00000000
--- a/keystone-moon/keystone/assignment/backends/__init__.py
+++ /dev/null
diff --git a/keystone-moon/keystone/assignment/backends/ldap.py b/keystone-moon/keystone/assignment/backends/ldap.py
deleted file mode 100644
index b52dc46e..00000000
--- a/keystone-moon/keystone/assignment/backends/ldap.py
+++ /dev/null
@@ -1,545 +0,0 @@
-# Copyright 2012-2013 OpenStack Foundation
-#
-# Licensed under the Apache License, Version 2.0 (the "License"); you may
-# not use this file except in compliance with the License. You may obtain
-# a copy of the License at
-#
-# http://www.apache.org/licenses/LICENSE-2.0
-#
-# Unless required by applicable law or agreed to in writing, software
-# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
-# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
-# License for the specific language governing permissions and limitations
-# under the License.
-from __future__ import absolute_import
-
-import ldap.filter
-from oslo_config import cfg
-from oslo_log import log
-from oslo_log import versionutils
-
-from keystone import assignment
-from keystone.assignment.role_backends import ldap as ldap_role
-from keystone.common import ldap as common_ldap
-from keystone.common import models
-from keystone import exception
-from keystone.i18n import _
-from keystone.identity.backends import ldap as ldap_identity
-
-
-CONF = cfg.CONF
-LOG = log.getLogger(__name__)
-
-
-class Assignment(assignment.AssignmentDriverV8):
- @versionutils.deprecated(
- versionutils.deprecated.KILO,
- remove_in=+2,
- what='ldap assignment')
- def __init__(self):
- super(Assignment, self).__init__()
- self.LDAP_URL = CONF.ldap.url
- self.LDAP_USER = CONF.ldap.user
- self.LDAP_PASSWORD = CONF.ldap.password
- self.suffix = CONF.ldap.suffix
-
- # This is the only deep dependency from assignment back to identity.
- # This is safe to do since if you are using LDAP for assignment, it is
- # required that you are using it for identity as well.
- self.user = ldap_identity.UserApi(CONF)
- self.group = ldap_identity.GroupApi(CONF)
-
- self.project = ProjectApi(CONF)
- self.role = RoleApi(CONF, self.user)
-
- def default_role_driver(self):
- return 'ldap'
-
- def default_resource_driver(self):
- return 'ldap'
-
- def list_role_ids_for_groups_on_project(
- self, groups, project_id, project_domain_id, project_parents):
- group_dns = [self.group._id_to_dn(group_id) for group_id in groups]
- role_list = [self.role._dn_to_id(role_assignment.role_dn)
- for role_assignment in self.role.get_role_assignments
- (self.project._id_to_dn(project_id))
- if role_assignment.user_dn.upper() in group_dns]
- # NOTE(morganfainberg): Does not support OS-INHERIT as domain
- # metadata/roles are not supported by LDAP backend. Skip OS-INHERIT
- # logic.
- return role_list
-
- def _get_metadata(self, user_id=None, tenant_id=None,
- domain_id=None, group_id=None):
-
- def _get_roles_for_just_user_and_project(user_id, tenant_id):
- user_dn = self.user._id_to_dn(user_id)
- return [self.role._dn_to_id(a.role_dn)
- for a in self.role.get_role_assignments
- (self.project._id_to_dn(tenant_id))
- if common_ldap.is_dn_equal(a.user_dn, user_dn)]
-
- def _get_roles_for_group_and_project(group_id, project_id):
- group_dn = self.group._id_to_dn(group_id)
- return [self.role._dn_to_id(a.role_dn)
- for a in self.role.get_role_assignments
- (self.project._id_to_dn(project_id))
- if common_ldap.is_dn_equal(a.user_dn, group_dn)]
-
- if domain_id is not None:
- msg = _('Domain metadata not supported by LDAP')
- raise exception.NotImplemented(message=msg)
- if group_id is None and user_id is None:
- return {}
-
- if tenant_id is None:
- return {}
- if user_id is None:
- metadata_ref = _get_roles_for_group_and_project(group_id,
- tenant_id)
- else:
- metadata_ref = _get_roles_for_just_user_and_project(user_id,
- tenant_id)
- if not metadata_ref:
- return {}
- return {'roles': [self._role_to_dict(r, False) for r in metadata_ref]}
-
- def list_project_ids_for_user(self, user_id, group_ids, hints,
- inherited=False):
- # TODO(henry-nash): The ldap driver does not support inherited
- # assignments, so the inherited parameter is unused.
- # See bug #1404273.
- user_dn = self.user._id_to_dn(user_id)
- associations = (self.role.list_project_roles_for_user
- (user_dn, self.project.tree_dn))
-
- for group_id in group_ids:
- group_dn = self.group._id_to_dn(group_id)
- for group_role in self.role.list_project_roles_for_group(
- group_dn, self.project.tree_dn):
- associations.append(group_role)
-
- return list(set(
- [self.project._dn_to_id(x.project_dn) for x in associations]))
-
- def list_role_ids_for_groups_on_domain(self, group_ids, domain_id):
- raise exception.NotImplemented()
-
- def list_project_ids_for_groups(self, group_ids, hints,
- inherited=False):
- raise exception.NotImplemented()
-
- def list_domain_ids_for_user(self, user_id, group_ids, hints):
- raise exception.NotImplemented()
-
- def list_domain_ids_for_groups(self, group_ids, inherited=False):
- raise exception.NotImplemented()
-
- def list_user_ids_for_project(self, tenant_id):
- tenant_dn = self.project._id_to_dn(tenant_id)
- rolegrants = self.role.get_role_assignments(tenant_dn)
- return [self.user._dn_to_id(user_dn) for user_dn in
- self.project.get_user_dns(tenant_id, rolegrants)]
-
- def _subrole_id_to_dn(self, role_id, tenant_id):
- if tenant_id is None:
- return self.role._id_to_dn(role_id)
- else:
- return '%s=%s,%s' % (self.role.id_attr,
- ldap.dn.escape_dn_chars(role_id),
- self.project._id_to_dn(tenant_id))
-
- def add_role_to_user_and_project(self, user_id, tenant_id, role_id):
- user_dn = self.user._id_to_dn(user_id)
- role_dn = self._subrole_id_to_dn(role_id, tenant_id)
- self.role.add_user(role_id, role_dn, user_dn, user_id, tenant_id)
- tenant_dn = self.project._id_to_dn(tenant_id)
- return UserRoleAssociation(role_dn=role_dn,
- user_dn=user_dn,
- tenant_dn=tenant_dn)
-
- def _add_role_to_group_and_project(self, group_id, tenant_id, role_id):
- group_dn = self.group._id_to_dn(group_id)
- role_dn = self._subrole_id_to_dn(role_id, tenant_id)
- self.role.add_user(role_id, role_dn, group_dn, group_id, tenant_id)
- tenant_dn = self.project._id_to_dn(tenant_id)
- return GroupRoleAssociation(group_dn=group_dn,
- role_dn=role_dn,
- tenant_dn=tenant_dn)
-
- def remove_role_from_user_and_project(self, user_id, tenant_id, role_id):
- role_dn = self._subrole_id_to_dn(role_id, tenant_id)
- return self.role.delete_user(role_dn,
- self.user._id_to_dn(user_id), role_id)
-
- def _remove_role_from_group_and_project(self, group_id, tenant_id,
- role_id):
- role_dn = self._subrole_id_to_dn(role_id, tenant_id)
- return self.role.delete_user(role_dn,
- self.group._id_to_dn(group_id), role_id)
-
-# Bulk actions on User From identity
- def delete_user_assignments(self, user_id):
- user_dn = self.user._id_to_dn(user_id)
- for ref in self.role.list_global_roles_for_user(user_dn):
- self.role.delete_user(ref.role_dn, ref.user_dn,
- self.role._dn_to_id(ref.role_dn))
- for ref in self.role.list_project_roles_for_user(user_dn,
- self.project.tree_dn):
- self.role.delete_user(ref.role_dn, ref.user_dn,
- self.role._dn_to_id(ref.role_dn))
-
- def delete_group_assignments(self, group_id):
- """Called when the group was deleted.
-
- Any role assignments for the group should be cleaned up.
-
- """
- group_dn = self.group._id_to_dn(group_id)
- group_role_assignments = self.role.list_project_roles_for_group(
- group_dn, self.project.tree_dn)
- for ref in group_role_assignments:
- self.role.delete_user(ref.role_dn, ref.group_dn,
- self.role._dn_to_id(ref.role_dn))
-
- def create_grant(self, role_id, user_id=None, group_id=None,
- domain_id=None, project_id=None,
- inherited_to_projects=False):
-
- try:
- metadata_ref = self._get_metadata(user_id, project_id,
- domain_id, group_id)
- except exception.MetadataNotFound:
- metadata_ref = {}
-
- if user_id is None:
- metadata_ref['roles'] = self._add_role_to_group_and_project(
- group_id, project_id, role_id)
- else:
- metadata_ref['roles'] = self.add_role_to_user_and_project(
- user_id, project_id, role_id)
-
- def check_grant_role_id(self, role_id, user_id=None, group_id=None,
- domain_id=None, project_id=None,
- inherited_to_projects=False):
-
- try:
- metadata_ref = self._get_metadata(user_id, project_id,
- domain_id, group_id)
- except exception.MetadataNotFound:
- metadata_ref = {}
- role_ids = set(self._roles_from_role_dicts(
- metadata_ref.get('roles', []), inherited_to_projects))
- if role_id not in role_ids:
- actor_id = user_id or group_id
- target_id = domain_id or project_id
- raise exception.RoleAssignmentNotFound(role_id=role_id,
- actor_id=actor_id,
- target_id=target_id)
-
- def delete_grant(self, role_id, user_id=None, group_id=None,
- domain_id=None, project_id=None,
- inherited_to_projects=False):
-
- try:
- metadata_ref = self._get_metadata(user_id, project_id,
- domain_id, group_id)
- except exception.MetadataNotFound:
- metadata_ref = {}
-
- try:
- if user_id is None:
- metadata_ref['roles'] = (
- self._remove_role_from_group_and_project(
- group_id, project_id, role_id))
- else:
- metadata_ref['roles'] = self.remove_role_from_user_and_project(
- user_id, project_id, role_id)
- except (exception.RoleNotFound, KeyError):
- actor_id = user_id or group_id
- target_id = domain_id or project_id
- raise exception.RoleAssignmentNotFound(role_id=role_id,
- actor_id=actor_id,
- target_id=target_id)
-
- def list_grant_role_ids(self, user_id=None, group_id=None,
- domain_id=None, project_id=None,
- inherited_to_projects=False):
-
- try:
- metadata_ref = self._get_metadata(user_id, project_id,
- domain_id, group_id)
- except exception.MetadataNotFound:
- metadata_ref = {}
-
- return self._roles_from_role_dicts(metadata_ref.get('roles', []),
- inherited_to_projects)
-
- def list_role_assignments(self, role_id=None,
- user_id=None, group_ids=None,
- domain_id=None, project_ids=None,
- inherited_to_projects=None):
- role_assignments = []
-
- # Since the LDAP backend does not support assignments to domains, if
- # the request is to filter by domain, then the answer is guaranteed
- # to be an empty list.
- if not domain_id:
- for a in self.role.list_role_assignments(self.project.tree_dn):
- if isinstance(a, UserRoleAssociation):
- assignment = {
- 'role_id': self.role._dn_to_id(a.role_dn),
- 'user_id': self.user._dn_to_id(a.user_dn),
- 'project_id': self.project._dn_to_id(a.project_dn)}
- else:
- assignment = {
- 'role_id': self.role._dn_to_id(a.role_dn),
- 'group_id': self.group._dn_to_id(a.group_dn),
- 'project_id': self.project._dn_to_id(a.project_dn)}
-
- if role_id and assignment['role_id'] != role_id:
- continue
- if user_id and assignment.get('user_id') != user_id:
- continue
- if group_ids and assignment.get('group_id') not in group_ids:
- continue
- if project_ids and assignment['project_id'] not in project_ids:
- continue
-
- role_assignments.append(assignment)
-
- return role_assignments
-
- def delete_project_assignments(self, project_id):
- tenant_dn = self.project._id_to_dn(project_id)
- self.role.roles_delete_subtree_by_project(tenant_dn)
-
- def delete_role_assignments(self, role_id):
- self.role.roles_delete_subtree_by_role(role_id, self.project.tree_dn)
-
-
-# TODO(termie): turn this into a data object and move logic to driver
-class ProjectApi(common_ldap.ProjectLdapStructureMixin,
- common_ldap.EnabledEmuMixIn, common_ldap.BaseLdap):
-
- model = models.Project
-
- def __init__(self, conf):
- super(ProjectApi, self).__init__(conf)
- self.member_attribute = (conf.ldap.project_member_attribute
- or self.DEFAULT_MEMBER_ATTRIBUTE)
-
- def get_user_projects(self, user_dn, associations):
- """Returns the list of tenants to which a user has access."""
- project_ids = set()
- for assoc in associations:
- project_ids.add(self._dn_to_id(assoc.project_dn))
- projects = []
- for project_id in project_ids:
- # slower to get them one at a time, but a huge list could blow out
- # the connection. This is the safer way
- projects.append(self.get(project_id))
- return projects
-
- def get_user_dns(self, tenant_id, rolegrants, role_dn=None):
- tenant = self._ldap_get(tenant_id)
- res = set()
- if not role_dn:
- # Get users who have default tenant mapping
- for user_dn in tenant[1].get(self.member_attribute, []):
- if self._is_dumb_member(user_dn):
- continue
- res.add(user_dn)
-
- # Get users who are explicitly mapped via a tenant
- for rolegrant in rolegrants:
- if role_dn is None or rolegrant.role_dn == role_dn:
- res.add(rolegrant.user_dn)
- return list(res)
-
-
-class UserRoleAssociation(object):
- """Role Grant model."""
-
- def __init__(self, user_dn=None, role_dn=None, tenant_dn=None,
- *args, **kw):
- self.user_dn = user_dn
- self.role_dn = role_dn
- self.project_dn = tenant_dn
-
-
-class GroupRoleAssociation(object):
- """Role Grant model."""
-
- def __init__(self, group_dn=None, role_dn=None, tenant_dn=None,
- *args, **kw):
- self.group_dn = group_dn
- self.role_dn = role_dn
- self.project_dn = tenant_dn
-
-
-# TODO(termie): turn this into a data object and move logic to driver
-# NOTE(heny-nash): The RoleLdapStructureMixin class enables the sharing of the
-# LDAP structure between here and the role backend LDAP, no methods are shared.
-class RoleApi(ldap_role.RoleLdapStructureMixin, common_ldap.BaseLdap):
-
- def __init__(self, conf, user_api):
- super(RoleApi, self).__init__(conf)
- self.member_attribute = (conf.ldap.role_member_attribute
- or self.DEFAULT_MEMBER_ATTRIBUTE)
- self._user_api = user_api
-
- def add_user(self, role_id, role_dn, user_dn, user_id, tenant_id=None):
- try:
- super(RoleApi, self).add_member(user_dn, role_dn)
- except exception.Conflict:
- msg = (_('User %(user_id)s already has role %(role_id)s in '
- 'tenant %(tenant_id)s') %
- dict(user_id=user_id, role_id=role_id, tenant_id=tenant_id))
- raise exception.Conflict(type='role grant', details=msg)
- except self.NotFound:
- if tenant_id is None or self.get(role_id) is None:
- raise Exception(_("Role %s not found") % (role_id,))
-
- attrs = [('objectClass', [self.object_class]),
- (self.member_attribute, [user_dn]),
- (self.id_attr, [role_id])]
-
- if self.use_dumb_member:
- attrs[1][1].append(self.dumb_member)
- with self.get_connection() as conn:
- conn.add_s(role_dn, attrs)
-
- def delete_user(self, role_dn, user_dn, role_id):
- try:
- super(RoleApi, self).remove_member(user_dn, role_dn)
- except (self.NotFound, ldap.NO_SUCH_ATTRIBUTE):
- raise exception.RoleNotFound(message=_(
- 'Cannot remove role that has not been granted, %s') %
- role_id)
-
- def get_role_assignments(self, tenant_dn):
- try:
- roles = self._ldap_get_list(tenant_dn, ldap.SCOPE_ONELEVEL,
- attrlist=[self.member_attribute])
- except ldap.NO_SUCH_OBJECT:
- roles = []
- res = []
- for role_dn, attrs in roles:
- try:
- user_dns = attrs[self.member_attribute]
- except KeyError:
- continue
- for user_dn in user_dns:
- if self._is_dumb_member(user_dn):
- continue
- res.append(UserRoleAssociation(
- user_dn=user_dn,
- role_dn=role_dn,
- tenant_dn=tenant_dn))
-
- return res
-
- def list_global_roles_for_user(self, user_dn):
- user_dn_esc = ldap.filter.escape_filter_chars(user_dn)
- roles = self.get_all('(%s=%s)' % (self.member_attribute, user_dn_esc))
- return [UserRoleAssociation(
- role_dn=role.dn,
- user_dn=user_dn) for role in roles]
-
- def list_project_roles_for_user(self, user_dn, project_subtree):
- try:
- roles = self._ldap_get_list(project_subtree, ldap.SCOPE_SUBTREE,
- query_params={
- self.member_attribute: user_dn},
- attrlist=common_ldap.DN_ONLY)
- except ldap.NO_SUCH_OBJECT:
- roles = []
- res = []
- for role_dn, _role_attrs in roles:
- # ldap.dn.dn2str returns an array, where the first
- # element is the first segment.
- # For a role assignment, this contains the role ID,
- # The remainder is the DN of the tenant.
- # role_dn is already utf8 encoded since it came from LDAP.
- tenant = ldap.dn.str2dn(role_dn)
- tenant.pop(0)
- tenant_dn = ldap.dn.dn2str(tenant)
- res.append(UserRoleAssociation(
- user_dn=user_dn,
- role_dn=role_dn,
- tenant_dn=tenant_dn))
- return res
-
- def list_project_roles_for_group(self, group_dn, project_subtree):
- group_dn_esc = ldap.filter.escape_filter_chars(group_dn)
- query = '(&(objectClass=%s)(%s=%s))' % (self.object_class,
- self.member_attribute,
- group_dn_esc)
- with self.get_connection() as conn:
- try:
- roles = conn.search_s(project_subtree,
- ldap.SCOPE_SUBTREE,
- query,
- attrlist=common_ldap.DN_ONLY)
- except ldap.NO_SUCH_OBJECT:
- # Return no roles rather than raise an exception if the project
- # subtree entry doesn't exist because an empty subtree is not
- # an error.
- return []
-
- res = []
- for role_dn, _role_attrs in roles:
- # ldap.dn.str2dn returns a list, where the first
- # element is the first RDN.
- # For a role assignment, this contains the role ID,
- # the remainder is the DN of the project.
- # role_dn is already utf8 encoded since it came from LDAP.
- project = ldap.dn.str2dn(role_dn)
- project.pop(0)
- project_dn = ldap.dn.dn2str(project)
- res.append(GroupRoleAssociation(
- group_dn=group_dn,
- role_dn=role_dn,
- tenant_dn=project_dn))
- return res
-
- def roles_delete_subtree_by_project(self, tenant_dn):
- self._delete_tree_nodes(tenant_dn, ldap.SCOPE_ONELEVEL)
-
- def roles_delete_subtree_by_role(self, role_id, tree_dn):
- self._delete_tree_nodes(tree_dn, ldap.SCOPE_SUBTREE, query_params={
- self.id_attr: role_id})
-
- def list_role_assignments(self, project_tree_dn):
- """List the role assignments linked to project_tree_dn attribute."""
- try:
- roles = self._ldap_get_list(project_tree_dn, ldap.SCOPE_SUBTREE,
- attrlist=[self.member_attribute])
- except ldap.NO_SUCH_OBJECT:
- roles = []
- res = []
- for role_dn, role in roles:
- # role_dn is already utf8 encoded since it came from LDAP.
- tenant = ldap.dn.str2dn(role_dn)
- tenant.pop(0)
- # It obtains the tenant DN to construct the UserRoleAssociation
- # object.
- tenant_dn = ldap.dn.dn2str(tenant)
- for occupant_dn in role[self.member_attribute]:
- if self._is_dumb_member(occupant_dn):
- continue
- if self._user_api.is_user(occupant_dn):
- association = UserRoleAssociation(
- user_dn=occupant_dn,
- role_dn=role_dn,
- tenant_dn=tenant_dn)
- else:
- # occupant_dn is a group.
- association = GroupRoleAssociation(
- group_dn=occupant_dn,
- role_dn=role_dn,
- tenant_dn=tenant_dn)
- res.append(association)
- return res
diff --git a/keystone-moon/keystone/assignment/backends/sql.py b/keystone-moon/keystone/assignment/backends/sql.py
deleted file mode 100644
index e089726a..00000000
--- a/keystone-moon/keystone/assignment/backends/sql.py
+++ /dev/null
@@ -1,319 +0,0 @@
-# Copyright 2012-13 OpenStack Foundation
-#
-# Licensed under the Apache License, Version 2.0 (the "License"); you may
-# not use this file except in compliance with the License. You may obtain
-# a copy of the License at
-#
-# http://www.apache.org/licenses/LICENSE-2.0
-#
-# Unless required by applicable law or agreed to in writing, software
-# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
-# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
-# License for the specific language governing permissions and limitations
-# under the License.
-
-from keystone import assignment as keystone_assignment
-from keystone.common import sql
-from keystone import exception
-from keystone.i18n import _
-
-
-class AssignmentType(object):
- USER_PROJECT = 'UserProject'
- GROUP_PROJECT = 'GroupProject'
- USER_DOMAIN = 'UserDomain'
- GROUP_DOMAIN = 'GroupDomain'
-
- @classmethod
- def calculate_type(cls, user_id, group_id, project_id, domain_id):
- if user_id:
- if project_id:
- return cls.USER_PROJECT
- if domain_id:
- return cls.USER_DOMAIN
- if group_id:
- if project_id:
- return cls.GROUP_PROJECT
- if domain_id:
- return cls.GROUP_DOMAIN
- # Invalid parameters combination
- raise exception.AssignmentTypeCalculationError(**locals())
-
-
-class Assignment(keystone_assignment.AssignmentDriverV9):
-
- def default_role_driver(self):
- return 'sql'
-
- def default_resource_driver(self):
- return 'sql'
-
- def create_grant(self, role_id, user_id=None, group_id=None,
- domain_id=None, project_id=None,
- inherited_to_projects=False):
-
- assignment_type = AssignmentType.calculate_type(
- user_id, group_id, project_id, domain_id)
- try:
- with sql.session_for_write() as session:
- session.add(RoleAssignment(
- type=assignment_type,
- actor_id=user_id or group_id,
- target_id=project_id or domain_id,
- role_id=role_id,
- inherited=inherited_to_projects))
- except sql.DBDuplicateEntry: # nosec : The v3 grant APIs are silent if
- # the assignment already exists
- pass
-
- def list_grant_role_ids(self, user_id=None, group_id=None,
- domain_id=None, project_id=None,
- inherited_to_projects=False):
- with sql.session_for_read() as session:
- q = session.query(RoleAssignment.role_id)
- q = q.filter(RoleAssignment.actor_id == (user_id or group_id))
- q = q.filter(RoleAssignment.target_id == (project_id or domain_id))
- q = q.filter(RoleAssignment.inherited == inherited_to_projects)
- return [x.role_id for x in q.all()]
-
- def _build_grant_filter(self, session, role_id, user_id, group_id,
- domain_id, project_id, inherited_to_projects):
- q = session.query(RoleAssignment)
- q = q.filter_by(actor_id=user_id or group_id)
- q = q.filter_by(target_id=project_id or domain_id)
- q = q.filter_by(role_id=role_id)
- q = q.filter_by(inherited=inherited_to_projects)
- return q
-
- def check_grant_role_id(self, role_id, user_id=None, group_id=None,
- domain_id=None, project_id=None,
- inherited_to_projects=False):
- with sql.session_for_read() as session:
- try:
- q = self._build_grant_filter(
- session, role_id, user_id, group_id, domain_id, project_id,
- inherited_to_projects)
- q.one()
- except sql.NotFound:
- actor_id = user_id or group_id
- target_id = domain_id or project_id
- raise exception.RoleAssignmentNotFound(role_id=role_id,
- actor_id=actor_id,
- target_id=target_id)
-
- def delete_grant(self, role_id, user_id=None, group_id=None,
- domain_id=None, project_id=None,
- inherited_to_projects=False):
- with sql.session_for_write() as session:
- q = self._build_grant_filter(
- session, role_id, user_id, group_id, domain_id, project_id,
- inherited_to_projects)
- if not q.delete(False):
- actor_id = user_id or group_id
- target_id = domain_id or project_id
- raise exception.RoleAssignmentNotFound(role_id=role_id,
- actor_id=actor_id,
- target_id=target_id)
-
- def add_role_to_user_and_project(self, user_id, tenant_id, role_id):
- try:
- with sql.session_for_write() as session:
- session.add(RoleAssignment(
- type=AssignmentType.USER_PROJECT,
- actor_id=user_id, target_id=tenant_id,
- role_id=role_id, inherited=False))
- except sql.DBDuplicateEntry:
- msg = ('User %s already has role %s in tenant %s'
- % (user_id, role_id, tenant_id))
- raise exception.Conflict(type='role grant', details=msg)
-
- def remove_role_from_user_and_project(self, user_id, tenant_id, role_id):
- with sql.session_for_write() as session:
- q = session.query(RoleAssignment)
- q = q.filter_by(actor_id=user_id)
- q = q.filter_by(target_id=tenant_id)
- q = q.filter_by(role_id=role_id)
- if q.delete() == 0:
- raise exception.RoleNotFound(message=_(
- 'Cannot remove role that has not been granted, %s') %
- role_id)
-
- def _get_user_assignment_types(self):
- return [AssignmentType.USER_PROJECT, AssignmentType.USER_DOMAIN]
-
- def _get_group_assignment_types(self):
- return [AssignmentType.GROUP_PROJECT, AssignmentType.GROUP_DOMAIN]
-
- def _get_project_assignment_types(self):
- return [AssignmentType.USER_PROJECT, AssignmentType.GROUP_PROJECT]
-
- def _get_domain_assignment_types(self):
- return [AssignmentType.USER_DOMAIN, AssignmentType.GROUP_DOMAIN]
-
- def _get_assignment_types(self, user, group, project, domain):
- """Returns a list of role assignment types based on provided entities
-
- If one of user or group (the "actor") as well as one of project or
- domain (the "target") are provided, the list will contain the role
- assignment type for that specific pair of actor and target.
-
- If only an actor or target is provided, the list will contain the
- role assignment types that satisfy the specified entity.
-
- For example, if user and project are provided, the return will be:
-
- [AssignmentType.USER_PROJECT]
-
- However, if only user was provided, the return would be:
-
- [AssignmentType.USER_PROJECT, AssignmentType.USER_DOMAIN]
-
- It is not expected that user and group (or project and domain) are
- specified - but if they are, the most fine-grained value will be
- chosen (i.e. user over group, project over domain).
-
- """
- actor_types = []
- if user:
- actor_types = self._get_user_assignment_types()
- elif group:
- actor_types = self._get_group_assignment_types()
-
- target_types = []
- if project:
- target_types = self._get_project_assignment_types()
- elif domain:
- target_types = self._get_domain_assignment_types()
-
- if actor_types and target_types:
- return list(set(actor_types).intersection(target_types))
-
- return actor_types or target_types
-
- def list_role_assignments(self, role_id=None,
- user_id=None, group_ids=None,
- domain_id=None, project_ids=None,
- inherited_to_projects=None):
-
- def denormalize_role(ref):
- assignment = {}
- if ref.type == AssignmentType.USER_PROJECT:
- assignment['user_id'] = ref.actor_id
- assignment['project_id'] = ref.target_id
- elif ref.type == AssignmentType.USER_DOMAIN:
- assignment['user_id'] = ref.actor_id
- assignment['domain_id'] = ref.target_id
- elif ref.type == AssignmentType.GROUP_PROJECT:
- assignment['group_id'] = ref.actor_id
- assignment['project_id'] = ref.target_id
- elif ref.type == AssignmentType.GROUP_DOMAIN:
- assignment['group_id'] = ref.actor_id
- assignment['domain_id'] = ref.target_id
- else:
- raise exception.Error(message=_(
- 'Unexpected assignment type encountered, %s') %
- ref.type)
- assignment['role_id'] = ref.role_id
- if ref.inherited:
- assignment['inherited_to_projects'] = 'projects'
- return assignment
-
- with sql.session_for_read() as session:
- assignment_types = self._get_assignment_types(
- user_id, group_ids, project_ids, domain_id)
-
- targets = None
- if project_ids:
- targets = project_ids
- elif domain_id:
- targets = [domain_id]
-
- actors = None
- if group_ids:
- actors = group_ids
- elif user_id:
- actors = [user_id]
-
- query = session.query(RoleAssignment)
-
- if role_id:
- query = query.filter_by(role_id=role_id)
- if actors:
- query = query.filter(RoleAssignment.actor_id.in_(actors))
- if targets:
- query = query.filter(RoleAssignment.target_id.in_(targets))
- if assignment_types:
- query = query.filter(RoleAssignment.type.in_(assignment_types))
- if inherited_to_projects is not None:
- query = query.filter_by(inherited=inherited_to_projects)
-
- return [denormalize_role(ref) for ref in query.all()]
-
- def delete_project_assignments(self, project_id):
- with sql.session_for_write() as session:
- q = session.query(RoleAssignment)
- q = q.filter_by(target_id=project_id).filter(
- RoleAssignment.type.in_((AssignmentType.USER_PROJECT,
- AssignmentType.GROUP_PROJECT))
- )
- q.delete(False)
-
- def delete_role_assignments(self, role_id):
- with sql.session_for_write() as session:
- q = session.query(RoleAssignment)
- q = q.filter_by(role_id=role_id)
- q.delete(False)
-
- def delete_domain_assignments(self, domain_id):
- with sql.session_for_write() as session:
- q = session.query(RoleAssignment)
- q = q.filter(RoleAssignment.target_id == domain_id).filter(
- (RoleAssignment.type == AssignmentType.USER_DOMAIN) |
- (RoleAssignment.type == AssignmentType.GROUP_DOMAIN))
- q.delete(False)
-
- def delete_user_assignments(self, user_id):
- with sql.session_for_write() as session:
- q = session.query(RoleAssignment)
- q = q.filter_by(actor_id=user_id).filter(
- RoleAssignment.type.in_((AssignmentType.USER_PROJECT,
- AssignmentType.USER_DOMAIN))
- )
- q.delete(False)
-
- def delete_group_assignments(self, group_id):
- with sql.session_for_write() as session:
- q = session.query(RoleAssignment)
- q = q.filter_by(actor_id=group_id).filter(
- RoleAssignment.type.in_((AssignmentType.GROUP_PROJECT,
- AssignmentType.GROUP_DOMAIN))
- )
- q.delete(False)
-
-
-class RoleAssignment(sql.ModelBase, sql.DictBase):
- __tablename__ = 'assignment'
- attributes = ['type', 'actor_id', 'target_id', 'role_id', 'inherited']
- # NOTE(henry-nash): Postgres requires a name to be defined for an Enum
- type = sql.Column(
- sql.Enum(AssignmentType.USER_PROJECT, AssignmentType.GROUP_PROJECT,
- AssignmentType.USER_DOMAIN, AssignmentType.GROUP_DOMAIN,
- name='type'),
- nullable=False)
- actor_id = sql.Column(sql.String(64), nullable=False)
- target_id = sql.Column(sql.String(64), nullable=False)
- role_id = sql.Column(sql.String(64), nullable=False)
- inherited = sql.Column(sql.Boolean, default=False, nullable=False)
- __table_args__ = (
- sql.PrimaryKeyConstraint('type', 'actor_id', 'target_id', 'role_id',
- 'inherited'),
- sql.Index('ix_actor_id', 'actor_id'),
- )
-
- def to_dict(self):
- """Override parent method with a simpler implementation.
-
- RoleAssignment doesn't have non-indexed 'extra' attributes, so the
- parent implementation is not applicable.
- """
- return dict(self.items())