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/ldap.py66
-rw-r--r--keystone-moon/keystone/assignment/backends/sql.py108
2 files changed, 136 insertions, 38 deletions
diff --git a/keystone-moon/keystone/assignment/backends/ldap.py b/keystone-moon/keystone/assignment/backends/ldap.py
index f93e989f..4ca66c4d 100644
--- a/keystone-moon/keystone/assignment/backends/ldap.py
+++ b/keystone-moon/keystone/assignment/backends/ldap.py
@@ -13,10 +13,10 @@
# under the License.
from __future__ import absolute_import
-import ldap as ldap
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
@@ -25,7 +25,6 @@ from keystone.common import models
from keystone import exception
from keystone.i18n import _
from keystone.identity.backends import ldap as ldap_identity
-from keystone.openstack.common import versionutils
CONF = cfg.CONF
@@ -36,7 +35,7 @@ class Assignment(assignment.Driver):
@versionutils.deprecated(
versionutils.deprecated.KILO,
remove_in=+2,
- what='keystone.assignment.backends.ldap.Assignment')
+ what='ldap')
def __init__(self):
super(Assignment, self).__init__()
self.LDAP_URL = CONF.ldap.url
@@ -54,10 +53,10 @@ class Assignment(assignment.Driver):
self.role = RoleApi(CONF, self.user)
def default_role_driver(self):
- return 'keystone.assignment.role_backends.ldap.Role'
+ return 'ldap'
def default_resource_driver(self):
- return 'keystone.resource.backends.ldap.Resource'
+ return 'ldap'
def list_role_ids_for_groups_on_project(
self, groups, project_id, project_domain_id, project_parents):
@@ -181,7 +180,7 @@ class Assignment(assignment.Driver):
self.group._id_to_dn(group_id), role_id)
# Bulk actions on User From identity
- def delete_user(self, user_id):
+ 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,
@@ -191,7 +190,7 @@ class Assignment(assignment.Driver):
self.role.delete_user(ref.role_dn, ref.user_dn,
self.role._dn_to_id(ref.role_dn))
- def delete_group(self, group_id):
+ def delete_group_assignments(self, group_id):
"""Called when the group was deleted.
Any role assignments for the group should be cleaned up.
@@ -277,20 +276,39 @@ class Assignment(assignment.Driver):
return self._roles_from_role_dicts(metadata_ref.get('roles', []),
inherited_to_projects)
- 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):
role_assignments = []
- 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)}
- role_assignments.append(assignment)
+
+ # 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):
@@ -313,9 +331,7 @@ class ProjectApi(common_ldap.ProjectLdapStructureMixin,
or self.DEFAULT_MEMBER_ATTRIBUTE)
def get_user_projects(self, user_dn, associations):
- """Returns list of tenants a user has access to
- """
-
+ """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))
@@ -497,9 +513,7 @@ class RoleApi(ldap_role.RoleLdapStructureMixin, common_ldap.BaseLdap):
self.id_attr: role_id})
def list_role_assignments(self, project_tree_dn):
- """Returns a list of all the role assignments linked to project_tree_dn
- attribute.
- """
+ """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])
diff --git a/keystone-moon/keystone/assignment/backends/sql.py b/keystone-moon/keystone/assignment/backends/sql.py
index 2de6ca60..89ff64b5 100644
--- a/keystone-moon/keystone/assignment/backends/sql.py
+++ b/keystone-moon/keystone/assignment/backends/sql.py
@@ -14,7 +14,6 @@
from oslo_config import cfg
from oslo_log import log
-import six
import sqlalchemy
from sqlalchemy.sql.expression import false
@@ -53,10 +52,10 @@ class AssignmentType(object):
class Assignment(keystone_assignment.Driver):
def default_role_driver(self):
- return "keystone.assignment.role_backends.sql.Role"
+ return 'sql'
def default_resource_driver(self):
- return 'keystone.resource.backends.sql.Resource'
+ return 'sql'
def list_user_ids_for_project(self, tenant_id):
with sql.transaction() as session:
@@ -336,7 +335,62 @@ class Assignment(keystone_assignment.Driver):
'Cannot remove role that has not been granted, %s') %
role_id)
- def list_role_assignments(self):
+ 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 = {}
@@ -362,8 +416,35 @@ class Assignment(keystone_assignment.Driver):
return assignment
with sql.transaction() as session:
- refs = session.query(RoleAssignment).all()
- return [denormalize_role(ref) for ref in refs]
+ 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.transaction() as session:
@@ -377,13 +458,13 @@ class Assignment(keystone_assignment.Driver):
q = q.filter_by(role_id=role_id)
q.delete(False)
- def delete_user(self, user_id):
+ def delete_user_assignments(self, user_id):
with sql.transaction() as session:
q = session.query(RoleAssignment)
q = q.filter_by(actor_id=user_id)
q.delete(False)
- def delete_group(self, group_id):
+ def delete_group_assignments(self, group_id):
with sql.transaction() as session:
q = session.query(RoleAssignment)
q = q.filter_by(actor_id=group_id)
@@ -399,12 +480,15 @@ class RoleAssignment(sql.ModelBase, sql.DictBase):
AssignmentType.USER_DOMAIN, AssignmentType.GROUP_DOMAIN,
name='type'),
nullable=False)
- actor_id = sql.Column(sql.String(64), nullable=False, index=True)
+ 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'), {})
+ __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 to_dict() method with a simpler implementation.
@@ -412,4 +496,4 @@ class RoleAssignment(sql.ModelBase, sql.DictBase):
RoleAssignment doesn't have non-indexed 'extra' attributes, so the
parent implementation is not applicable.
"""
- return dict(six.iteritems(self))
+ return dict(self.items())