diff options
Diffstat (limited to 'keystone/identity')
-rw-r--r-- | keystone/identity/backends/kvs.py | 35 | ||||
-rw-r--r-- | keystone/identity/backends/ldap/core.py | 27 | ||||
-rw-r--r-- | keystone/identity/backends/sql.py | 110 | ||||
-rw-r--r-- | keystone/identity/controllers.py | 10 | ||||
-rw-r--r-- | keystone/identity/core.py | 20 |
5 files changed, 73 insertions, 129 deletions
diff --git a/keystone/identity/backends/kvs.py b/keystone/identity/backends/kvs.py index 1d8ce608..6c59fa03 100644 --- a/keystone/identity/backends/kvs.py +++ b/keystone/identity/backends/kvs.py @@ -134,24 +134,6 @@ class Identity(kvs.Base, identity.Driver): role_ids = self.db.get('role_list', []) return [self.get_role(x) for x in role_ids] - # These should probably be part of the high-level API - def add_user_to_project(self, tenant_id, user_id): - self.get_project(tenant_id) - user_ref = self._get_user(user_id) - tenants = set(user_ref.get('tenants', [])) - tenants.add(tenant_id) - self.update_user(user_id, {'tenants': list(tenants)}) - - def remove_user_from_project(self, tenant_id, user_id): - self.get_project(tenant_id) - user_ref = self._get_user(user_id) - tenants = set(user_ref.get('tenants', [])) - try: - tenants.remove(tenant_id) - except KeyError: - raise exception.NotFound('User not found in tenant') - self.update_user(user_id, {'tenants': list(tenants)}) - def get_projects_for_user(self, user_id): user_ref = self._get_user(user_id) return user_ref.get('tenants', []) @@ -194,7 +176,16 @@ class Identity(kvs.Base, identity.Driver): roles.remove(role_id) metadata_ref['roles'] = list(roles) - self.update_metadata(user_id, tenant_id, metadata_ref) + + if not len(roles): + self.db.delete('metadata-%s-%s' % (tenant_id, user_id)) + user_ref = self._get_user(user_id) + tenants = set(user_ref.get('tenants', [])) + tenants.remove(tenant_id) + user_ref['tenants'] = list(tenants) + self.update_user(user_id, user_ref) + else: + self.update_metadata(user_id, tenant_id, metadata_ref) # CRUD def create_user(self, user_id, user): @@ -360,6 +351,12 @@ class Identity(kvs.Base, identity.Driver): if user_id: if tenant_id: self.db.set('metadata-%s-%s' % (tenant_id, user_id), metadata) + user_ref = self._get_user(user_id) + tenants = set(user_ref.get('tenants', [])) + if tenant_id not in tenants: + tenants.add(tenant_id) + user_ref['tenants'] = list(tenants) + self.update_user(user_id, user_ref) else: self.db.set('metadata-%s-%s' % (domain_id, user_id), metadata) else: diff --git a/keystone/identity/backends/ldap/core.py b/keystone/identity/backends/ldap/core.py index db95e246..22a7fd0c 100644 --- a/keystone/identity/backends/ldap/core.py +++ b/keystone/identity/backends/ldap/core.py @@ -152,12 +152,6 @@ class Identity(identity.Driver): def list_roles(self): return self.role.get_all() - # These should probably be part of the high-level API - def add_user_to_project(self, tenant_id, user_id): - self.get_project(tenant_id) - self.get_user(user_id) - return self.project.add_user(tenant_id, user_id) - def get_projects_for_user(self, user_id): self.get_user(user_id) return [p['id'] for p in self.project.get_user_projects(user_id)] @@ -243,11 +237,6 @@ class Identity(identity.Driver): def remove_role_from_user_and_project(self, user_id, tenant_id, role_id): return self.role.delete_user(role_id, user_id, tenant_id) - def remove_user_from_project(self, tenant_id, user_id): - self.get_user(user_id) - self.get_project(tenant_id) - return self.project.remove_user(tenant_id, user_id) - def update_role(self, role_id, role): self.get_role(role_id) self.role.update(role_id, role) @@ -551,13 +540,17 @@ class ProjectApi(common_ldap.BaseLdap, ApiShimMixin): def get_user_projects(self, user_id): """Returns list of tenants a user has access to - - Always includes default tenants. """ - user_dn = self.user_api._id_to_dn(user_id) - query = '(%s=%s)' % (self.member_attribute, user_dn) - memberships = self.get_all(query) - return memberships + associations = self.role_api.list_project_roles_for_user(user_id) + project_ids = set() + for assoc in associations: + project_ids.add(assoc.project_id) + 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 list_for_user_get_page(self, user, marker, limit): return self._get_page(marker, diff --git a/keystone/identity/backends/sql.py b/keystone/identity/backends/sql.py index 1d821287..bda2bf93 100644 --- a/keystone/identity/backends/sql.py +++ b/keystone/identity/backends/sql.py @@ -17,6 +17,7 @@ import functools from keystone import clean +from keystone import config from keystone.common import sql from keystone.common.sql import migration from keystone.common import utils @@ -82,7 +83,6 @@ class Domain(sql.ModelBase, sql.DictBase): extra = sql.Column(sql.JsonBlob()) -# TODO(dolph): rename to Project class Project(sql.ModelBase, sql.DictBase): __tablename__ = 'project' attributes = ['id', 'name', 'domain_id'] @@ -114,11 +114,13 @@ class BaseGrant(sql.DictBase): class UserProjectGrant(sql.ModelBase, BaseGrant): - # TODO(dolph): rename to user_project_metadata (needs a migration) - __tablename__ = 'metadata' - user_id = sql.Column(sql.String(64), primary_key=True) - # TODO(dolph): rename to project_id (needs a migration) - tenant_id = sql.Column(sql.String(64), primary_key=True) + __tablename__ = 'user_project_metadata' + user_id = sql.Column(sql.String(64), + sql.ForeignKey('user.id'), + primary_key=True) + project_id = sql.Column(sql.String(64), + sql.ForeignKey('project.id'), + primary_key=True) data = sql.Column(sql.JsonBlob()) @@ -143,18 +145,6 @@ class GroupDomainGrant(sql.ModelBase, BaseGrant): data = sql.Column(sql.JsonBlob()) -# TODO(dolph): ... do we need this table? -class UserProjectMembership(sql.ModelBase, sql.DictBase): - """Project membership join table.""" - __tablename__ = 'user_project_membership' - user_id = sql.Column(sql.String(64), - sql.ForeignKey('user.id'), - primary_key=True) - tenant_id = sql.Column(sql.String(64), - sql.ForeignKey('project.id'), - primary_key=True) - - class UserGroupMembership(sql.ModelBase, sql.DictBase): """Group membership join table.""" __tablename__ = 'user_group_membership' @@ -242,8 +232,8 @@ class Identity(sql.Base, identity.Driver): session = self.get_session() self.get_project(tenant_id) query = session.query(User) - query = query.join(UserProjectMembership) - query = query.filter(UserProjectMembership.tenant_id == tenant_id) + query = query.join(UserProjectGrant) + query = query.filter(UserProjectGrant.project_id == tenant_id) user_refs = query.all() return [identity.filter_user(user_ref.to_dict()) for user_ref in user_refs] @@ -255,7 +245,7 @@ class Identity(sql.Base, identity.Driver): if user_id: if tenant_id: q = session.query(UserProjectGrant) - q = q.filter_by(tenant_id=tenant_id) + q = q.filter_by(project_id=tenant_id) elif domain_id: q = session.query(UserDomainGrant) q = q.filter_by(domain_id=domain_id) @@ -375,37 +365,6 @@ class Identity(sql.Base, identity.Driver): self.update_metadata(user_id, project_id, metadata_ref, domain_id, group_id) - # These should probably be part of the high-level API - def add_user_to_project(self, tenant_id, user_id): - session = self.get_session() - self.get_project(tenant_id) - self.get_user(user_id) - query = session.query(UserProjectMembership) - query = query.filter_by(user_id=user_id) - query = query.filter_by(tenant_id=tenant_id) - rv = query.first() - if rv: - return - - with session.begin(): - session.add(UserProjectMembership(user_id=user_id, - tenant_id=tenant_id)) - session.flush() - - def remove_user_from_project(self, tenant_id, user_id): - session = self.get_session() - self.get_project(tenant_id) - self.get_user(user_id) - query = session.query(UserProjectMembership) - query = query.filter_by(user_id=user_id) - query = query.filter_by(tenant_id=tenant_id) - membership_ref = query.first() - if membership_ref is None: - raise exception.NotFound('User not found in tenant') - with session.begin(): - session.delete(membership_ref) - session.flush() - def list_projects(self): session = self.get_session() tenant_refs = session.query(Project).all() @@ -414,10 +373,10 @@ class Identity(sql.Base, identity.Driver): def get_projects_for_user(self, user_id): session = self.get_session() self.get_user(user_id) - query = session.query(UserProjectMembership) + query = session.query(UserProjectGrant) query = query.filter_by(user_id=user_id) membership_refs = query.all() - return [x.tenant_id for x in membership_refs] + return [x.project_id for x in membership_refs] def get_roles_for_user_and_project(self, user_id, tenant_id): self.get_user(user_id) @@ -453,22 +412,24 @@ class Identity(sql.Base, identity.Driver): def remove_role_from_user_and_project(self, user_id, tenant_id, role_id): try: metadata_ref = self.get_metadata(user_id, tenant_id) - is_new = False + roles = set(metadata_ref.get('roles', [])) + if role_id not in roles: + msg = _('Cannot remove role that has not been granted, %s' % + role_id) + raise exception.RoleNotFound(message=msg) + roles.remove(role_id) + metadata_ref['roles'] = list(roles) + if len(roles): + self.update_metadata(user_id, tenant_id, metadata_ref) + else: + session = self.get_session() + q = session.query(UserProjectGrant) + q = q.filter_by(project_id=tenant_id) + q.delete() except exception.MetadataNotFound: - metadata_ref = {} - is_new = True - roles = set(metadata_ref.get('roles', [])) - if role_id not in roles: msg = 'Cannot remove role that has not been granted, %s' % role_id raise exception.RoleNotFound(message=msg) - roles.remove(role_id) - metadata_ref['roles'] = list(roles) - if is_new: - self.create_metadata(user_id, tenant_id, metadata_ref) - else: - self.update_metadata(user_id, tenant_id, metadata_ref) - # CRUD @handle_conflicts(type='project') def create_project(self, tenant_id, tenant): @@ -512,12 +473,12 @@ class Identity(sql.Base, identity.Driver): raise exception.ProjectNotFound(project_id=tenant_id) with session.begin(): - q = session.query(UserProjectMembership) - q = q.filter_by(tenant_id=tenant_id) + q = session.query(UserProjectGrant) + q = q.filter_by(project_id=tenant_id) q.delete(False) q = session.query(UserProjectGrant) - q = q.filter_by(tenant_id=tenant_id) + q = q.filter_by(project_id=tenant_id) q.delete(False) q = session.query(GroupProjectGrant) @@ -539,7 +500,7 @@ class Identity(sql.Base, identity.Driver): if user_id: if tenant_id: session.add(UserProjectGrant(user_id=user_id, - tenant_id=tenant_id, + project_id=tenant_id, data=metadata)) elif domain_id: session.add(UserDomainGrant(user_id=user_id, @@ -566,7 +527,7 @@ class Identity(sql.Base, identity.Driver): if tenant_id: q = session.query(UserProjectGrant) q = q.filter_by(user_id=user_id) - q = q.filter_by(tenant_id=tenant_id) + q = q.filter_by(project_id=tenant_id) elif domain_id: q = session.query(UserDomainGrant) q = q.filter_by(user_id=user_id) @@ -651,7 +612,7 @@ class Identity(sql.Base, identity.Driver): metadata_refs = session\ .query(UserProjectGrant)\ .filter_by(user_id=user_id) - project_ids = set([x.tenant_id for x in metadata_refs + project_ids = set([x.project_id for x in metadata_refs if x.data.get('roles')]) if user.get('project_id'): project_ids.add(user['project_id']) @@ -797,9 +758,6 @@ class Identity(sql.Base, identity.Driver): raise exception.UserNotFound(user_id=user_id) with session.begin(): - q = session.query(UserProjectMembership) - q = q.filter_by(user_id=user_id) - q.delete(False) q = session.query(UserProjectGrant) q = q.filter_by(user_id=user_id) @@ -999,7 +957,7 @@ class Identity(sql.Base, identity.Driver): metadata = metadata_ref.to_dict() try: self.remove_role_from_user_and_project( - metadata['user_id'], metadata['tenant_id'], role_id) + metadata['user_id'], metadata['project_id'], role_id) except exception.RoleNotFound: pass diff --git a/keystone/identity/controllers.py b/keystone/identity/controllers.py index 8060e28f..31125267 100644 --- a/keystone/identity/controllers.py +++ b/keystone/identity/controllers.py @@ -304,9 +304,6 @@ class Role(controller.V2Controller): raise exception.NotImplemented(message='User roles not supported: ' 'tenant_id required') - # This still has the weird legacy semantics that adding a role to - # a user also adds them to a tenant - self.identity_api.add_user_to_project(context, tenant_id, user_id) self.identity_api.add_role_to_user_and_project( context, user_id, tenant_id, role_id) self.token_api.revoke_tokens(context, user_id, tenant_id) @@ -332,9 +329,6 @@ class Role(controller.V2Controller): context, user_id, tenant_id, role_id) roles = self.identity_api.get_roles_for_user_and_project( context, user_id, tenant_id) - if not roles: - self.identity_api.remove_user_from_project( - context, tenant_id, user_id) self.token_api.revoke_tokens(context, user_id, tenant_id) # COMPAT(diablo): CRUD extension @@ -375,7 +369,6 @@ class Role(controller.V2Controller): # TODO(termie): for now we're ignoring the actual role tenant_id = role.get('tenantId') role_id = role.get('roleId') - self.identity_api.add_user_to_project(context, tenant_id, user_id) self.identity_api.add_role_to_user_and_project( context, user_id, tenant_id, role_id) self.token_api.revoke_tokens(context, user_id, tenant_id) @@ -404,9 +397,6 @@ class Role(controller.V2Controller): context, user_id, tenant_id, role_id) roles = self.identity_api.get_roles_for_user_and_project( context, user_id, tenant_id) - if not roles: - self.identity_api.remove_user_from_project( - context, tenant_id, user_id) self.token_api.revoke_tokens(context, user_id, tenant_id) diff --git a/keystone/identity/core.py b/keystone/identity/core.py index 7810d3f4..7d8c991f 100644 --- a/keystone/identity/core.py +++ b/keystone/identity/core.py @@ -102,22 +102,28 @@ class Driver(object): raise exception.NotImplemented() def add_user_to_project(self, tenant_id, user_id): - """Add user to a tenant without an explicit role relationship. + """Add user to a tenant by creating a default role relationship. - :raises: keystone.exception.ProjectNotFound, - keystone.exception.UserNotFound + :raises: keystone.exception.ProjectNotFound, + keystone.exception.UserNotFound - """ - raise exception.NotImplemented() + """ + self.add_role_to_user_and_project(user_id, + tenant_id, + config.CONF.member_role_id) def remove_user_from_project(self, tenant_id, user_id): - """Remove user from a tenant without an explicit role relationship. + """Remove user from a tenant :raises: keystone.exception.ProjectNotFound, keystone.exception.UserNotFound """ - raise exception.NotImplemented() + roles = self.get_roles_for_user_and_project(user_id, tenant_id) + if not roles: + raise exception.NotFound(tenant_id) + for role_id in roles: + self.remove_role_from_user_and_project(user_id, tenant_id, role_id) def get_project_users(self, tenant_id): """Lists all users with a relationship to the specified project. |