Rationalize list_user_projects and get_projects_for_user
These two functions have slightly different implementations and yet neither takes into account group or inherited roles. Rationalize these into a single list_projects_for_user() that gets the correct list of project refs, allowing for group and inherited roles. The public API name, as referenced in the policy file, remains as 'list_user_projects' to avoid a policy file change at this late stage. The most common use cases of the above is via the v2 API, when we need to ensure only projects from the default domain are included. Given that this means we must inspect each project ref anyway, having a call that returns a list of IDs will not be any more efficient than returning the project refs and letting the caller extract the IDs. Fixes bug #1201487 Change-Id: I614140639c71dae4dfe501d27eda65e41a78694d
This commit is contained in:
parent
54b8ec55e6
commit
fb6b5eba63
|
@ -101,9 +101,12 @@ class Assignment(kvs.Base, assignment.Driver):
|
|||
role_ids = self.db.get('role_list', [])
|
||||
return [self.get_role(x) for x in role_ids]
|
||||
|
||||
def get_projects_for_user(self, user_id):
|
||||
def list_projects_for_user(self, user_id, group_ids):
|
||||
# NOTE(henry-nash): The kvs backend is being deprecated, so no
|
||||
# support is provided for projects that the user has a role on solely
|
||||
# by virtue of group membership.
|
||||
user_ref = self._get_user(user_id)
|
||||
return user_ref.get('tenants', [])
|
||||
return [self.get_project(x) for x in user_ref.get('tenants', [])]
|
||||
|
||||
def add_role_to_user_and_project(self, user_id, tenant_id, role_id):
|
||||
self.identity_api.get_user(user_id)
|
||||
|
|
|
@ -115,12 +115,18 @@ class Assignment(assignment.Driver):
|
|||
def list_roles(self):
|
||||
return self.role.get_all()
|
||||
|
||||
def get_projects_for_user(self, user_id):
|
||||
def list_projects_for_user(self, user_id, group_ids):
|
||||
# NOTE(henry-nash): The LDAP backend is being deprecated, so no
|
||||
# support is provided for projects that the user has a role on solely
|
||||
# by virtue of group membership.
|
||||
self.identity_api.get_user(user_id)
|
||||
user_dn = self.user._id_to_dn(user_id)
|
||||
associations = (self.role.list_project_roles_for_user
|
||||
(user_dn, self.project.tree_dn))
|
||||
return [p['id'] for p in
|
||||
# Since the LDAP backend doesn't store the domain_id in the LDAP
|
||||
# records (and only supports the default domain), we fill in the
|
||||
# domain_id before we return the list.
|
||||
return [self._set_default_domain(x) for x in
|
||||
self.project.get_user_projects(user_dn, associations)]
|
||||
|
||||
def get_project_users(self, tenant_id):
|
||||
|
|
|
@ -19,9 +19,13 @@ from keystone import clean
|
|||
from keystone.common import dependency
|
||||
from keystone.common import sql
|
||||
from keystone.common.sql import migration
|
||||
from keystone import config
|
||||
from keystone import exception
|
||||
|
||||
|
||||
CONF = config.CONF
|
||||
|
||||
|
||||
@dependency.requires('identity_api')
|
||||
class Assignment(sql.Base, assignment.Driver):
|
||||
|
||||
|
@ -219,21 +223,76 @@ class Assignment(sql.Base, assignment.Driver):
|
|||
project_refs = query.all()
|
||||
return [project_ref.to_dict() for project_ref in project_refs]
|
||||
|
||||
def get_projects_for_user(self, user_id):
|
||||
def list_projects_for_user(self, user_id, group_ids):
|
||||
# NOTE(henry-nash): This method is written as a series of code blocks,
|
||||
# rather than broken down into too many sub-functions, to prepare for
|
||||
# SQL optimization when we rationalize the grant tables in the
|
||||
# future.
|
||||
|
||||
# FIXME(henry-nash) The following should take into account
|
||||
# both group and inherited roles. In fact, I don't see why this
|
||||
# call can't be handled at the controller level like we do
|
||||
# with 'get_roles_for_user_and_project()'. Further, this
|
||||
# call seems essentially the same as 'list_user_projects()'
|
||||
# later in this driver. Both should be removed.
|
||||
def _list_domains_with_inherited_grants(query):
|
||||
domain_ids = set()
|
||||
domain_grants = query.all()
|
||||
for domain_grant in domain_grants:
|
||||
for grant in domain_grant.data.get('roles', []):
|
||||
if 'inherited_to' in grant:
|
||||
domain_ids.add(domain_grant.domain_id)
|
||||
return domain_ids
|
||||
|
||||
self.identity_api.get_user(user_id)
|
||||
# NOTE(henry-nash): The metadata management code doesn't always clean
|
||||
# up table entries when the last role is deleted - so when checking
|
||||
# grant entries, only include this project if there are actually roles
|
||||
# present.
|
||||
|
||||
# First get a list of the projects for which the user has a direct
|
||||
# role assigned
|
||||
session = self.get_session()
|
||||
query = session.query(UserProjectGrant)
|
||||
query = query.filter_by(user_id=user_id)
|
||||
membership_refs = query.all()
|
||||
return [x.project_id for x in membership_refs]
|
||||
project_grants_for_user = query.all()
|
||||
project_ids = set(x.project_id for x in project_grants_for_user
|
||||
if x.data.get('roles'))
|
||||
|
||||
# Now find any projects with group roles and add them in
|
||||
for group_id in group_ids:
|
||||
query = session.query(GroupProjectGrant)
|
||||
query = query.filter_by(group_id=group_id)
|
||||
project_grants_for_group = query.all()
|
||||
for project_grant in project_grants_for_group:
|
||||
if project_grant.data.get('roles'):
|
||||
project_ids.add(project_grant.project_id)
|
||||
|
||||
if not CONF.os_inherit.enabled:
|
||||
return [self.get_project(x) for x in project_ids]
|
||||
|
||||
# Inherited roles are enabled, so check to see if this user has any
|
||||
# such roles (direct or group) on any domain, in which case we must
|
||||
# add in all the projects in that domain.
|
||||
|
||||
domain_ids = set()
|
||||
|
||||
# First check for user roles on any domains
|
||||
query = session.query(UserDomainGrant)
|
||||
query = query.filter_by(user_id=user_id)
|
||||
domain_ids.update(_list_domains_with_inherited_grants(query))
|
||||
|
||||
# Now for group roles on any domains
|
||||
for group_id in group_ids:
|
||||
query = session.query(GroupDomainGrant)
|
||||
query = query.filter_by(group_id=group_id)
|
||||
domain_ids.update(_list_domains_with_inherited_grants(query))
|
||||
|
||||
# For each domain on which the user has an inherited role, get the
|
||||
# list of projects in that domain and add them in to the
|
||||
# project id list
|
||||
|
||||
for domain_id in domain_ids:
|
||||
query = session.query(Project)
|
||||
query = query.filter_by(domain_id=domain_id)
|
||||
project_refs = query.all()
|
||||
for project_ref in project_refs:
|
||||
project_ids.add(project_ref.id)
|
||||
|
||||
return [self.get_project(x) for x in project_ids]
|
||||
|
||||
def add_role_to_user_and_project(self, user_id, tenant_id, role_id):
|
||||
self.identity_api.get_user(user_id)
|
||||
|
@ -508,31 +567,6 @@ class Assignment(sql.Base, assignment.Driver):
|
|||
session.delete(ref)
|
||||
session.flush()
|
||||
|
||||
def list_user_projects(self, user_id):
|
||||
|
||||
# FIXME(henry-nash) The following should take into account
|
||||
# both group and inherited roles. In fact, I don't see why this
|
||||
# call can't be handled at the controller level like we do
|
||||
# with 'get_roles_for_user_and_project()'. Further, this
|
||||
# call seems essentially the same as 'get_projects_for_user()'
|
||||
# earlier in this driver. Both should be removed.
|
||||
|
||||
session = self.get_session()
|
||||
user = self.identity_api.get_user(user_id)
|
||||
metadata_refs = session\
|
||||
.query(UserProjectGrant)\
|
||||
.filter_by(user_id=user_id)
|
||||
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'])
|
||||
|
||||
# FIXME(dolph): this should be removed with proper migrations
|
||||
if user.get('tenant_id'):
|
||||
project_ids.add(user['tenant_id'])
|
||||
|
||||
return [self.get_project(x) for x in project_ids]
|
||||
|
||||
# role crud
|
||||
|
||||
@sql.handle_conflicts(type='role')
|
||||
|
|
|
@ -243,6 +243,18 @@ class Manager(manager.Manager):
|
|||
for role_id in roles:
|
||||
self.remove_role_from_user_and_project(user_id, tenant_id, role_id)
|
||||
|
||||
def list_projects_for_user(self, user_id):
|
||||
# NOTE(henry-nash): In order to get a complete list of user projects,
|
||||
# the driver will need to look at group assignments. To avoid cross
|
||||
# calling between the assignment and identity driver we get the group
|
||||
# list here and pass it in. The rest of the detailed logic of listing
|
||||
# projects for a user is pushed down into the driver to enable
|
||||
# optimization with the various backend technologies (SQL, LDAP etc.).
|
||||
|
||||
group_ids = [x['id'] for
|
||||
x in self.identity_api.list_groups_for_user(user_id)]
|
||||
return self.driver.list_projects_for_user(user_id, group_ids)
|
||||
|
||||
@cache.on_arguments(should_cache_fn=SHOULD_CACHE,
|
||||
expiration_time=CONF.assignment.cache_time)
|
||||
def get_domain(self, domain_id):
|
||||
|
@ -357,15 +369,6 @@ class Driver(object):
|
|||
"""
|
||||
raise exception.NotImplemented()
|
||||
|
||||
def get_projects_for_user(self, user_id):
|
||||
"""Get the tenants associated with a given user.
|
||||
|
||||
:returns: a list of tenant_id's.
|
||||
:raises: keystone.exception.UserNotFound
|
||||
|
||||
"""
|
||||
raise exception.NotImplemented()
|
||||
|
||||
def add_role_to_user_and_project(self, user_id, tenant_id, role_id):
|
||||
"""Add a role to a user within given tenant.
|
||||
|
||||
|
@ -524,9 +527,14 @@ class Driver(object):
|
|||
"""
|
||||
raise exception.NotImplemented()
|
||||
|
||||
def list_user_projects(self, user_id):
|
||||
def list_projects_for_user(self, user_id, group_ids):
|
||||
"""List all projects associated with a given user.
|
||||
|
||||
:param user_id: the user in question
|
||||
:param group_ids: the groups this user is a member of. This list is
|
||||
built in the Manager, so that the driver itself
|
||||
does not have to call across to identity.
|
||||
|
||||
:returns: a list of project_refs or an empty list.
|
||||
|
||||
"""
|
||||
|
|
|
@ -336,7 +336,7 @@ class OAuthControllerV3(controller.V3Controller):
|
|||
|
||||
# verify the user has the project too
|
||||
req_project_id = req_token['requested_project_id']
|
||||
user_projects = self.assignment_api.list_user_projects(user_id)
|
||||
user_projects = self.assignment_api.list_projects_for_user(user_id)
|
||||
found = False
|
||||
for user_project in user_projects:
|
||||
if user_project['id'] == req_project_id:
|
||||
|
|
|
@ -99,8 +99,8 @@ class PamIdentity(identity.Driver):
|
|||
def remove_user_from_project(self, tenant_id, user_id):
|
||||
pass
|
||||
|
||||
def get_projects_for_user(self, user_id):
|
||||
return [user_id]
|
||||
def list_projects_for_user(self, user_id):
|
||||
return [{'id': user_id, 'name': user_id}]
|
||||
|
||||
def get_roles_for_user_and_project(self, user_id, tenant_id):
|
||||
raise NotImplementedError()
|
||||
|
|
|
@ -64,11 +64,10 @@ class Tenant(controller.V2Controller):
|
|||
raise exception.Unauthorized(e)
|
||||
|
||||
user_ref = token_ref['user']
|
||||
tenant_ids = self.identity_api.get_projects_for_user(user_ref['id'])
|
||||
tenant_refs = []
|
||||
for tenant_id in tenant_ids:
|
||||
ref = self.identity_api.get_project(tenant_id)
|
||||
tenant_refs.append(self._filter_domain_id(ref))
|
||||
tenant_refs = (
|
||||
self.assignment_api.list_projects_for_user(user_ref['id']))
|
||||
tenant_refs = [self._filter_domain_id(ref) for ref in tenant_refs
|
||||
if ref['domain_id'] == DEFAULT_DOMAIN_ID]
|
||||
params = {
|
||||
'limit': context['query_string'].get('limit'),
|
||||
'marker': context['query_string'].get('marker'),
|
||||
|
@ -350,14 +349,18 @@ class Role(controller.V2Controller):
|
|||
self.assert_admin(context)
|
||||
# Ensure user exists by getting it first.
|
||||
self.identity_api.get_user(user_id)
|
||||
tenant_ids = self.identity_api.get_projects_for_user(user_id)
|
||||
tenants = self.assignment_api.list_projects_for_user(user_id)
|
||||
o = []
|
||||
for tenant_id in tenant_ids:
|
||||
for tenant in tenants:
|
||||
# As a v2 call, we should limit the response to those projects in
|
||||
# the default domain.
|
||||
if tenant['domain_id'] != DEFAULT_DOMAIN_ID:
|
||||
continue
|
||||
role_ids = self.identity_api.get_roles_for_user_and_project(
|
||||
user_id, tenant_id)
|
||||
user_id, tenant['id'])
|
||||
for role_id in role_ids:
|
||||
ref = {'roleId': role_id,
|
||||
'tenantId': tenant_id,
|
||||
'tenantId': tenant['id'],
|
||||
'userId': user_id}
|
||||
ref['id'] = urllib.urlencode(ref)
|
||||
o.append(ref)
|
||||
|
@ -575,7 +578,7 @@ class ProjectV3(controller.V3Controller):
|
|||
|
||||
@controller.filterprotected('enabled', 'name')
|
||||
def list_user_projects(self, context, filters, user_id):
|
||||
refs = self.identity_api.list_user_projects(user_id)
|
||||
refs = self.identity_api.list_projects_for_user(user_id)
|
||||
return ProjectV3.wrap_collection(context, refs, filters)
|
||||
|
||||
@controller.protected()
|
||||
|
|
|
@ -426,9 +426,6 @@ class Manager(manager.Manager):
|
|||
def list_roles(self):
|
||||
return self.assignment_api.list_roles()
|
||||
|
||||
def get_projects_for_user(self, user_id):
|
||||
return self.assignment_api.get_projects_for_user(user_id)
|
||||
|
||||
def get_project_users(self, tenant_id):
|
||||
return self.assignment_api.get_project_users(tenant_id)
|
||||
|
||||
|
@ -508,8 +505,8 @@ class Manager(manager.Manager):
|
|||
def list_domains(self):
|
||||
return self.assignment_api.list_domains()
|
||||
|
||||
def list_user_projects(self, user_id):
|
||||
return self.assignment_api.list_user_projects(user_id)
|
||||
def list_projects_for_user(self, user_id):
|
||||
return self.assignment_api.list_projects_for_user(user_id)
|
||||
|
||||
def add_user_to_project(self, tenant_id, user_id):
|
||||
return self.assignment_api.add_user_to_project(tenant_id, user_id)
|
||||
|
|
|
@ -1451,8 +1451,9 @@ class IdentityTests(object):
|
|||
def test_add_user_to_project(self):
|
||||
self.identity_api.add_user_to_project(self.tenant_baz['id'],
|
||||
self.user_foo['id'])
|
||||
tenants = self.identity_api.get_projects_for_user(self.user_foo['id'])
|
||||
self.assertIn(self.tenant_baz['id'], tenants)
|
||||
tenants = self.assignment_api.list_projects_for_user(
|
||||
self.user_foo['id'])
|
||||
self.assertIn(self.tenant_baz, tenants)
|
||||
|
||||
def test_add_user_to_project_missing_default_role(self):
|
||||
self.assignment_api.delete_role(CONF.member_role_id)
|
||||
|
@ -1461,8 +1462,9 @@ class IdentityTests(object):
|
|||
CONF.member_role_id)
|
||||
self.identity_api.add_user_to_project(self.tenant_baz['id'],
|
||||
self.user_foo['id'])
|
||||
tenants = self.identity_api.get_projects_for_user(self.user_foo['id'])
|
||||
self.assertIn(self.tenant_baz['id'], tenants)
|
||||
tenants = (
|
||||
self.assignment_api.list_projects_for_user(self.user_foo['id']))
|
||||
self.assertIn(self.tenant_baz, tenants)
|
||||
default_role = self.assignment_api.get_role(CONF.member_role_id)
|
||||
self.assertIsNotNone(default_role)
|
||||
|
||||
|
@ -1482,8 +1484,9 @@ class IdentityTests(object):
|
|||
self.user_foo['id'])
|
||||
self.identity_api.remove_user_from_project(self.tenant_baz['id'],
|
||||
self.user_foo['id'])
|
||||
tenants = self.identity_api.get_projects_for_user(self.user_foo['id'])
|
||||
self.assertNotIn(self.tenant_baz['id'], tenants)
|
||||
tenants = self.assignment_api.list_projects_for_user(
|
||||
self.user_foo['id'])
|
||||
self.assertNotIn(self.tenant_baz, tenants)
|
||||
|
||||
def test_remove_user_from_project_404(self):
|
||||
self.assertRaises(exception.ProjectNotFound,
|
||||
|
@ -1501,9 +1504,9 @@ class IdentityTests(object):
|
|||
self.tenant_baz['id'],
|
||||
self.user_foo['id'])
|
||||
|
||||
def test_get_projects_for_user_404(self):
|
||||
def test_list_user_project_ids_404(self):
|
||||
self.assertRaises(exception.UserNotFound,
|
||||
self.identity_api.get_projects_for_user,
|
||||
self.assignment_api.list_projects_for_user,
|
||||
uuid.uuid4().hex)
|
||||
|
||||
def test_update_project_404(self):
|
||||
|
@ -1535,7 +1538,7 @@ class IdentityTests(object):
|
|||
user['id'])
|
||||
self.identity_api.delete_user(user['id'])
|
||||
self.assertRaises(exception.UserNotFound,
|
||||
self.identity_api.get_projects_for_user,
|
||||
self.assignment_api.list_projects_for_user,
|
||||
user['id'])
|
||||
|
||||
def test_delete_user_with_project_roles(self):
|
||||
|
@ -1550,7 +1553,7 @@ class IdentityTests(object):
|
|||
self.role_member['id'])
|
||||
self.identity_api.delete_user(user['id'])
|
||||
self.assertRaises(exception.UserNotFound,
|
||||
self.identity_api.get_projects_for_user,
|
||||
self.assignment_api.list_projects_for_user,
|
||||
user['id'])
|
||||
|
||||
def test_delete_user_404(self):
|
||||
|
@ -2263,14 +2266,14 @@ class IdentityTests(object):
|
|||
self.identity_api.get_user,
|
||||
user['id'])
|
||||
|
||||
def test_list_user_projects(self):
|
||||
def test_list_projects_for_user(self):
|
||||
domain = {'id': uuid.uuid4().hex, 'name': uuid.uuid4().hex}
|
||||
self.identity_api.create_domain(domain['id'], domain)
|
||||
user1 = {'id': uuid.uuid4().hex, 'name': uuid.uuid4().hex,
|
||||
'password': uuid.uuid4().hex, 'domain_id': domain['id'],
|
||||
'enabled': True}
|
||||
self.identity_api.create_user(user1['id'], user1)
|
||||
user_projects = self.identity_api.list_user_projects(user1['id'])
|
||||
user_projects = self.assignment_api.list_projects_for_user(user1['id'])
|
||||
self.assertEquals(len(user_projects), 0)
|
||||
self.identity_api.create_grant(user_id=user1['id'],
|
||||
project_id=self.tenant_bar['id'],
|
||||
|
@ -2278,9 +2281,47 @@ class IdentityTests(object):
|
|||
self.identity_api.create_grant(user_id=user1['id'],
|
||||
project_id=self.tenant_baz['id'],
|
||||
role_id=self.role_member['id'])
|
||||
user_projects = self.identity_api.list_user_projects(user1['id'])
|
||||
user_projects = self.assignment_api.list_projects_for_user(user1['id'])
|
||||
self.assertEquals(len(user_projects), 2)
|
||||
|
||||
def test_list_projects_for_user_with_grants(self):
|
||||
# Create two groups each with a role on a different project, and
|
||||
# make user1 a member of both groups. Both these new projects
|
||||
# should now be included, along with any direct user grants.
|
||||
domain = {'id': uuid.uuid4().hex, 'name': uuid.uuid4().hex}
|
||||
self.identity_api.create_domain(domain['id'], domain)
|
||||
user1 = {'id': uuid.uuid4().hex, 'name': uuid.uuid4().hex,
|
||||
'password': uuid.uuid4().hex, 'domain_id': domain['id'],
|
||||
'enabled': True}
|
||||
self.identity_api.create_user(user1['id'], user1)
|
||||
group1 = {'id': uuid.uuid4().hex, 'name': uuid.uuid4().hex,
|
||||
'domain_id': domain['id']}
|
||||
self.identity_api.create_group(group1['id'], group1)
|
||||
group2 = {'id': uuid.uuid4().hex, 'name': uuid.uuid4().hex,
|
||||
'domain_id': domain['id']}
|
||||
self.identity_api.create_group(group2['id'], group2)
|
||||
project1 = {'id': uuid.uuid4().hex, 'name': uuid.uuid4().hex,
|
||||
'domain_id': domain['id']}
|
||||
self.assignment_api.create_project(project1['id'], project1)
|
||||
project2 = {'id': uuid.uuid4().hex, 'name': uuid.uuid4().hex,
|
||||
'domain_id': domain['id']}
|
||||
self.assignment_api.create_project(project2['id'], project2)
|
||||
self.identity_api.add_user_to_group(user1['id'], group1['id'])
|
||||
self.identity_api.add_user_to_group(user1['id'], group2['id'])
|
||||
|
||||
# Create 3 grants, one user grant, the other two as group grants
|
||||
self.identity_api.create_grant(user_id=user1['id'],
|
||||
project_id=self.tenant_bar['id'],
|
||||
role_id=self.role_member['id'])
|
||||
self.identity_api.create_grant(group_id=group1['id'],
|
||||
project_id=project1['id'],
|
||||
role_id=self.role_admin['id'])
|
||||
self.identity_api.create_grant(group_id=group2['id'],
|
||||
project_id=project2['id'],
|
||||
role_id=self.role_admin['id'])
|
||||
user_projects = self.assignment_api.list_projects_for_user(user1['id'])
|
||||
self.assertEquals(len(user_projects), 3)
|
||||
|
||||
def test_cache_layer_domain_crud(self):
|
||||
domain = {'id': uuid.uuid4().hex, 'name': uuid.uuid4().hex,
|
||||
'enabled': True}
|
||||
|
@ -3171,3 +3212,107 @@ class InheritanceTests(object):
|
|||
self.assertIn(role_list[0]['id'], combined_role_list)
|
||||
self.assertIn(role_list[2]['id'], combined_role_list)
|
||||
self.assertIn(role_list[3]['id'], combined_role_list)
|
||||
|
||||
def test_list_projects_for_user_with_inherited_grants(self):
|
||||
"""Test inherited group roles.
|
||||
|
||||
Test Plan:
|
||||
- Enable OS-INHERIT extension
|
||||
- Create a domain, with two projects and a user
|
||||
- Assign an inherited user role on the domain, as well as a direct
|
||||
user role to a separate project in a different domain
|
||||
- Get a list of projects for user, should return all three projects
|
||||
|
||||
"""
|
||||
self.opt_in_group('os_inherit', enabled=True)
|
||||
domain = {'id': uuid.uuid4().hex, 'name': uuid.uuid4().hex}
|
||||
self.identity_api.create_domain(domain['id'], domain)
|
||||
user1 = {'id': uuid.uuid4().hex, 'name': uuid.uuid4().hex,
|
||||
'password': uuid.uuid4().hex, 'domain_id': domain['id'],
|
||||
'enabled': True}
|
||||
self.identity_api.create_user(user1['id'], user1)
|
||||
project1 = {'id': uuid.uuid4().hex, 'name': uuid.uuid4().hex,
|
||||
'domain_id': domain['id']}
|
||||
self.assignment_api.create_project(project1['id'], project1)
|
||||
project2 = {'id': uuid.uuid4().hex, 'name': uuid.uuid4().hex,
|
||||
'domain_id': domain['id']}
|
||||
self.assignment_api.create_project(project2['id'], project2)
|
||||
|
||||
# Create 2 grants, one on a project and one inherited grant
|
||||
# on the domain
|
||||
self.identity_api.create_grant(user_id=user1['id'],
|
||||
project_id=self.tenant_bar['id'],
|
||||
role_id=self.role_member['id'])
|
||||
self.identity_api.create_grant(user_id=user1['id'],
|
||||
domain_id=domain['id'],
|
||||
role_id=self.role_admin['id'],
|
||||
inherited_to_projects=True)
|
||||
# Should get back all three projects, one by virtue of the direct
|
||||
# grant, plus both projects in the domain
|
||||
user_projects = self.assignment_api.list_projects_for_user(user1['id'])
|
||||
self.assertEquals(len(user_projects), 3)
|
||||
|
||||
def test_list_projects_for_user_with_inherited_group_grants(self):
|
||||
"""Test inherited group roles.
|
||||
|
||||
Test Plan:
|
||||
- Enable OS-INHERIT extension
|
||||
- Create two domains, each with two projects
|
||||
- Create a user and group
|
||||
- Make the user a member of the group
|
||||
- Assign a user role two projects, an inherited
|
||||
group role to one domain and an inherited regular role on
|
||||
the other domain
|
||||
- Get a list of projects for user, should return both pairs of projects
|
||||
from the domain, plus the one separate project
|
||||
|
||||
"""
|
||||
self.opt_in_group('os_inherit', enabled=True)
|
||||
domain = {'id': uuid.uuid4().hex, 'name': uuid.uuid4().hex}
|
||||
self.identity_api.create_domain(domain['id'], domain)
|
||||
domain2 = {'id': uuid.uuid4().hex, 'name': uuid.uuid4().hex}
|
||||
self.identity_api.create_domain(domain2['id'], domain2)
|
||||
project1 = {'id': uuid.uuid4().hex, 'name': uuid.uuid4().hex,
|
||||
'domain_id': domain['id']}
|
||||
self.assignment_api.create_project(project1['id'], project1)
|
||||
project2 = {'id': uuid.uuid4().hex, 'name': uuid.uuid4().hex,
|
||||
'domain_id': domain['id']}
|
||||
self.assignment_api.create_project(project2['id'], project2)
|
||||
project3 = {'id': uuid.uuid4().hex, 'name': uuid.uuid4().hex,
|
||||
'domain_id': domain2['id']}
|
||||
self.assignment_api.create_project(project3['id'], project3)
|
||||
project4 = {'id': uuid.uuid4().hex, 'name': uuid.uuid4().hex,
|
||||
'domain_id': domain2['id']}
|
||||
self.assignment_api.create_project(project4['id'], project4)
|
||||
user1 = {'id': uuid.uuid4().hex, 'name': uuid.uuid4().hex,
|
||||
'password': uuid.uuid4().hex, 'domain_id': domain['id'],
|
||||
'enabled': True}
|
||||
self.identity_api.create_user(user1['id'], user1)
|
||||
group1 = {'id': uuid.uuid4().hex, 'name': uuid.uuid4().hex,
|
||||
'domain_id': domain['id']}
|
||||
self.identity_api.create_group(group1['id'], group1)
|
||||
self.identity_api.add_user_to_group(user1['id'], group1['id'])
|
||||
|
||||
# Create 4 grants:
|
||||
# - one user grant on a project in domain2
|
||||
# - one user grant on a project in the default domain
|
||||
# - one inherited user grant on domain
|
||||
# - one inherited group grant on domain2
|
||||
self.identity_api.create_grant(user_id=user1['id'],
|
||||
project_id=project3['id'],
|
||||
role_id=self.role_member['id'])
|
||||
self.identity_api.create_grant(user_id=user1['id'],
|
||||
project_id=self.tenant_bar['id'],
|
||||
role_id=self.role_member['id'])
|
||||
self.identity_api.create_grant(user_id=user1['id'],
|
||||
domain_id=domain['id'],
|
||||
role_id=self.role_admin['id'],
|
||||
inherited_to_projects=True)
|
||||
self.identity_api.create_grant(group_id=group1['id'],
|
||||
domain_id=domain2['id'],
|
||||
role_id=self.role_admin['id'],
|
||||
inherited_to_projects=True)
|
||||
# Should get back all five projects, but without a duplicate for
|
||||
# project3 (since it has both a direct user role and an inherited role)
|
||||
user_projects = self.assignment_api.list_projects_for_user(user1['id'])
|
||||
self.assertEquals(len(user_projects), 5)
|
||||
|
|
|
@ -30,9 +30,8 @@ class KvsIdentity(tests.TestCase, test_backend.IdentityTests):
|
|||
self.load_backends()
|
||||
self.load_fixtures(default_fixtures)
|
||||
|
||||
def test_list_user_projects(self):
|
||||
# NOTE(chungg): not implemented
|
||||
self.skipTest('Blocked by bug 1119770')
|
||||
def test_list_projects_for_user_with_grants(self):
|
||||
self.skipTest('kvs backend is now deprecated')
|
||||
|
||||
def test_create_duplicate_group_name_in_different_domains(self):
|
||||
self.skipTest('Blocked by bug 1119770')
|
||||
|
|
|
@ -169,9 +169,12 @@ class BaseLDAPIdentity(test_backend.IdentityTests):
|
|||
def test_delete_group_with_user_project_domain_links(self):
|
||||
self.skipTest('N/A: LDAP does not support multiple domains')
|
||||
|
||||
def test_list_user_projects(self):
|
||||
def test_list_projects_for_user(self):
|
||||
self.skipTest('Blocked by bug 1101287')
|
||||
|
||||
def test_list_projects_for_user_with_grants(self):
|
||||
self.skipTest('Blocked by bug 1221805')
|
||||
|
||||
def test_create_duplicate_user_name_in_different_domains(self):
|
||||
self.skipTest('Blocked by bug 1101276')
|
||||
|
||||
|
|
|
@ -161,7 +161,7 @@ class SqlIdentity(SqlTests, test_backend.IdentityTests):
|
|||
user['id'])
|
||||
self.identity_api.delete_user(user['id'])
|
||||
self.assertRaises(exception.UserNotFound,
|
||||
self.identity_api.get_projects_for_user,
|
||||
self.assignment_api.list_projects_for_user,
|
||||
user['id'])
|
||||
|
||||
def test_create_null_user_name(self):
|
||||
|
@ -217,7 +217,7 @@ class SqlIdentity(SqlTests, test_backend.IdentityTests):
|
|||
self.identity_api.add_user_to_project(self.tenant_bar['id'],
|
||||
user['id'])
|
||||
self.assignment_api.delete_project(self.tenant_bar['id'])
|
||||
tenants = self.identity_api.get_projects_for_user(user['id'])
|
||||
tenants = self.assignment_api.list_projects_for_user(user['id'])
|
||||
self.assertEquals(tenants, [])
|
||||
|
||||
def test_metadata_removed_on_delete_user(self):
|
||||
|
|
|
@ -352,23 +352,6 @@ class Auth(controller.V2Controller):
|
|||
raise exception.Unauthorized(e)
|
||||
return domain_id
|
||||
|
||||
def _get_project_ref(self, user_id, tenant_id):
|
||||
"""Returns the tenant_ref for the user's tenant."""
|
||||
tenant_ref = None
|
||||
if tenant_id:
|
||||
tenants = self.identity_api.get_projects_for_user(user_id)
|
||||
if tenant_id not in tenants:
|
||||
msg = 'User %s is unauthorized for tenant %s' % (
|
||||
user_id, tenant_id)
|
||||
LOG.warning(msg)
|
||||
raise exception.Unauthorized(msg)
|
||||
|
||||
try:
|
||||
tenant_ref = self.identity_api.get_project(tenant_id)
|
||||
except exception.ProjectNotFound as e:
|
||||
exception.Unauthorized(e)
|
||||
return tenant_ref
|
||||
|
||||
def _get_project_roles_and_ref(self, user_id, tenant_id):
|
||||
"""Returns the project roles for this user, and the project ref."""
|
||||
|
||||
|
|
Loading…
Reference in New Issue