diff options
Diffstat (limited to 'tests/test_v3_identity.py')
-rw-r--r-- | tests/test_v3_identity.py | 940 |
1 files changed, 934 insertions, 6 deletions
diff --git a/tests/test_v3_identity.py b/tests/test_v3_identity.py index 1e10070e..f1e19c42 100644 --- a/tests/test_v3_identity.py +++ b/tests/test_v3_identity.py @@ -16,11 +16,64 @@ import uuid +from keystone import config from keystone import exception import test_v3 +def _build_role_assignment_url_and_entity( + role_id, user_id=None, group_id=None, domain_id=None, + project_id=None, inherited_to_projects=False, + effective=False): + + if user_id and domain_id: + url = ('/domains/%(domain_id)s/users/%(user_id)s' + '/roles/%(role_id)s' % { + 'domain_id': domain_id, + 'user_id': user_id, + 'role_id': role_id}) + entity = {'role': {'id': role_id}, + 'user': {'id': user_id}, + 'scope': {'domain': {'id': domain_id}}} + if inherited_to_projects: + url = '/OS-INHERIT%s/inherited_to_projects' % url + if not effective: + entity['OS-INHERIT:inherited_to'] = 'projects' + elif user_id and project_id: + url = ('/projects/%(project_id)s/users/%(user_id)s' + '/roles/%(role_id)s' % { + 'project_id': project_id, + 'user_id': user_id, + 'role_id': role_id}) + entity = {'role': {'id': role_id}, + 'user': {'id': user_id}, + 'scope': {'project': {'id': project_id}}} + if group_id and domain_id: + url = ('/domains/%(domain_id)s/groups/%(group_id)s' + '/roles/%(role_id)s' % { + 'domain_id': domain_id, + 'group_id': group_id, + 'role_id': role_id}) + entity = {'role': {'id': role_id}, + 'group': {'id': group_id}, + 'scope': {'domain': {'id': domain_id}}} + if inherited_to_projects: + url = '/OS-INHERIT%s/inherited_to_projects' % url + if not effective: + entity['OS-INHERIT:inherited_to'] = 'projects' + elif group_id and project_id: + url = ('/projects/%(project_id)s/groups/%(group_id)s' + '/roles/%(role_id)s' % { + 'project_id': project_id, + 'group_id': group_id, + 'role_id': role_id}) + entity = {'role': {'id': role_id}, + 'group': {'id': group_id}, + 'scope': {'project': {'id': project_id}}} + return (url, entity) + + class IdentityTestCase(test_v3.RestfulTestCase): """Test domains, projects, users, groups, & role CRUD.""" @@ -52,6 +105,10 @@ class IdentityTestCase(test_v3.RestfulTestCase): body={'domain': ref}) return self.assertValidDomainResponse(r, ref) + def test_create_domain_400(self): + """Call ``POST /domains``.""" + self.post('/domains', body={'domain': {}}, expected_status=400) + def test_list_domains(self): """Call ``GET /domains``.""" r = self.get('/domains') @@ -213,19 +270,19 @@ class IdentityTestCase(test_v3.RestfulTestCase): # Check all the domain2 relevant entities are gone self.assertRaises(exception.DomainNotFound, self.identity_api.get_domain, - domain_id=self.domain2['id']) + self.domain2['id']) self.assertRaises(exception.ProjectNotFound, self.identity_api.get_project, - tenant_id=self.project2['id']) + self.project2['id']) self.assertRaises(exception.GroupNotFound, self.identity_api.get_group, - group_id=self.group2['id']) + self.group2['id']) self.assertRaises(exception.UserNotFound, self.identity_api.get_user, - user_id=self.user2['id']) + self.user2['id']) self.assertRaises(exception.CredentialNotFound, self.credential_api.get_credential, - credential_id=self.credential2['id']) + self.credential2['id']) # ...and that all self.domain entities are still here r = self.identity_api.get_domain(self.domain['id']) @@ -260,6 +317,10 @@ class IdentityTestCase(test_v3.RestfulTestCase): body={'project': ref}) self.assertValidProjectResponse(r, ref) + def test_create_project_400(self): + """Call ``POST /projects``.""" + self.post('/projects', body={'project': {}}, expected_status=400) + def test_get_project(self): """Call ``GET /projects/{project_id}``.""" r = self.get( @@ -323,6 +384,10 @@ class IdentityTestCase(test_v3.RestfulTestCase): body={'user': ref}) return self.assertValidUserResponse(r, ref) + def test_create_user_400(self): + """Call ``POST /users``.""" + self.post('/users', body={'user': {}}, expected_status=400) + def test_list_users(self): """Call ``GET /users``.""" r = self.get('/users') @@ -458,7 +523,7 @@ class IdentityTestCase(test_v3.RestfulTestCase): # that reference this project self.assertRaises(exception.CredentialNotFound, self.credential_api.get_credential, - credential_id=self.credential['id']) + self.credential['id']) # And the no tokens we remain valid tokens = self.token_api.list_tokens(self.user['id']) self.assertEquals(len(tokens), 0) @@ -476,6 +541,10 @@ class IdentityTestCase(test_v3.RestfulTestCase): body={'group': ref}) return self.assertValidGroupResponse(r, ref) + def test_create_group_400(self): + """Call ``POST /groups``.""" + self.post('/groups', body={'group': {}}, expected_status=400) + def test_list_groups(self): """Call ``GET /groups``.""" r = self.get('/groups') @@ -516,6 +585,10 @@ class IdentityTestCase(test_v3.RestfulTestCase): body={'role': ref}) return self.assertValidRoleResponse(r, ref) + def test_create_role_400(self): + """Call ``POST /roles``.""" + self.post('/roles', body={'role': {}}, expected_status=400) + def test_list_roles(self): """Call ``GET /roles``.""" r = self.get('/roles') @@ -627,3 +700,858 @@ class IdentityTestCase(test_v3.RestfulTestCase): r = self.get(collection_url) self.assertValidRoleListResponse(r, expected_length=0) self.assertIn(collection_url, r.result['links']['self']) + + def test_get_role_assignments(self): + """Call ``GET /role_assignments``. + + The sample data set up already has a user, group and project + that is part of self.domain. We use these plus a new user + we create as our data set, making sure we ignore any + role assignments that are already in existence. + + Since we don't yet support a first class entity for role + assignments, we are only testing the LIST API. To create + and delete the role assignments we use the old grant APIs. + + Test Plan: + - Create extra user for tests + - Get a list of all existing role assignments + - Add a new assignment for each of the four combinations, i.e. + group+domain, user+domain, group+project, user+project, using + the same role each time + - Get a new list of all role assignments, checking these four new + ones have been added + - Then delete the four we added + - Get a new list of all role assignments, checking the four have + been removed + + """ + + # Since the default fixtures already assign some roles to the + # user it creates, we also need a new user that will not have any + # existing assignments + self.user1 = self.new_user_ref( + domain_id=self.domain['id']) + self.user1['password'] = uuid.uuid4().hex + self.identity_api.create_user(self.user1['id'], self.user1) + + collection_url = '/role_assignments' + r = self.get(collection_url) + self.assertValidRoleAssignmentListResponse(r) + self.assertIn(collection_url, r.result['links']['self']) + existing_assignments = len(r.result.get('role_assignments')) + + # Now add one of each of the four types of assignment, making sure + # that we get them all back. + gd_url, gd_entity = _build_role_assignment_url_and_entity( + domain_id=self.domain_id, group_id=self.group_id, + role_id=self.role_id) + self.put(gd_url) + r = self.get(collection_url) + self.assertValidRoleAssignmentListResponse(r) + self.assertEqual(len(r.result.get('role_assignments')), + existing_assignments + 1) + self.assertRoleAssignmentInListResponse(r, gd_entity, link_url=gd_url) + + ud_url, ud_entity = _build_role_assignment_url_and_entity( + domain_id=self.domain_id, user_id=self.user1['id'], + role_id=self.role_id) + self.put(ud_url) + r = self.get(collection_url) + self.assertValidRoleAssignmentListResponse(r) + self.assertEqual(len(r.result.get('role_assignments')), + existing_assignments + 2) + self.assertRoleAssignmentInListResponse(r, ud_entity, link_url=ud_url) + + gp_url, gp_entity = _build_role_assignment_url_and_entity( + project_id=self.project_id, group_id=self.group_id, + role_id=self.role_id) + self.put(gp_url) + r = self.get(collection_url) + self.assertValidRoleAssignmentListResponse(r) + self.assertEqual(len(r.result.get('role_assignments')), + existing_assignments + 3) + self.assertRoleAssignmentInListResponse(r, gp_entity, link_url=gp_url) + + up_url, up_entity = _build_role_assignment_url_and_entity( + project_id=self.project_id, user_id=self.user1['id'], + role_id=self.role_id) + self.put(up_url) + r = self.get(collection_url) + self.assertValidRoleAssignmentListResponse(r) + self.assertEqual(len(r.result.get('role_assignments')), + existing_assignments + 4) + self.assertRoleAssignmentInListResponse(r, up_entity, link_url=up_url) + + # Now delete the four we added and make sure they are removed + # from the collection. + + self.delete(gd_url) + self.delete(ud_url) + self.delete(gp_url) + self.delete(up_url) + r = self.get(collection_url) + self.assertValidRoleAssignmentListResponse(r) + self.assertEqual(len(r.result.get('role_assignments')), + existing_assignments) + self.assertRoleAssignmentNotInListResponse(r, gd_entity) + self.assertRoleAssignmentNotInListResponse(r, ud_entity) + self.assertRoleAssignmentNotInListResponse(r, gp_entity) + self.assertRoleAssignmentNotInListResponse(r, up_entity) + + def test_get_effective_role_assignments(self): + """Call ``GET /role_assignments?effective``. + + Test Plan: + - Create two extra user for tests + - Add these users to a group + - Add a role assignment for the group on a domain + - Get a list of all role assignments, checking one has been added + - Then get a list of all effective role assignments - the group + assignment should have turned into assignments on the domain + for each of the group members. + + """ + self.user1 = self.new_user_ref( + domain_id=self.domain['id']) + self.user1['password'] = uuid.uuid4().hex + self.identity_api.create_user(self.user1['id'], self.user1) + self.user2 = self.new_user_ref( + domain_id=self.domain['id']) + self.user2['password'] = uuid.uuid4().hex + self.identity_api.create_user(self.user2['id'], self.user2) + self.identity_api.add_user_to_group(self.user1['id'], self.group['id']) + self.identity_api.add_user_to_group(self.user2['id'], self.group['id']) + + collection_url = '/role_assignments' + r = self.get(collection_url) + self.assertValidRoleAssignmentListResponse(r) + self.assertIn(collection_url, r.result['links']['self']) + existing_assignments = len(r.result.get('role_assignments')) + + gd_url, gd_entity = _build_role_assignment_url_and_entity( + domain_id=self.domain_id, group_id=self.group_id, + role_id=self.role_id) + self.put(gd_url) + r = self.get(collection_url) + self.assertValidRoleAssignmentListResponse(r) + self.assertEqual(len(r.result.get('role_assignments')), + existing_assignments + 1) + self.assertRoleAssignmentInListResponse(r, gd_entity, link_url=gd_url) + + # Now re-read the collection asking for effective roles - this + # should mean the group assignment is translated into the two + # member user assignments + collection_url = '/role_assignments?effective' + r = self.get(collection_url) + self.assertValidRoleAssignmentListResponse(r) + self.assertEqual(len(r.result.get('role_assignments')), + existing_assignments + 2) + unused, ud_entity = _build_role_assignment_url_and_entity( + domain_id=self.domain_id, user_id=self.user1['id'], + role_id=self.role_id) + gd_url, unused = _build_role_assignment_url_and_entity( + domain_id=self.domain_id, group_id=self.group['id'], + role_id=self.role_id) + self.assertRoleAssignmentInListResponse(r, ud_entity, link_url=gd_url) + ud_url, ud_entity = _build_role_assignment_url_and_entity( + domain_id=self.domain_id, user_id=self.user2['id'], + role_id=self.role_id) + self.assertRoleAssignmentInListResponse(r, ud_entity, link_url=gd_url) + + def test_check_effective_values_for_role_assignments(self): + """Call ``GET /role_assignments?effective=value``. + + Check the various ways of specifying the 'effective' + query parameter. If the 'effective' query parameter + is included then this should always be treated as + as meaning 'True' unless it is specified as: + + {url}?effective=0 + + This is by design to match the agreed way of handling + policy checking on query/filter parameters. + + Test Plan: + - Create two extra user for tests + - Add these users to a group + - Add a role assignment for the group on a domain + - Get a list of all role assignments, checking one has been added + - Then issue various request with different ways of defining + the 'effective' query parameter. As we have tested the + correctness of the data coming back when we get effective roles + in other tests, here we just use the count of entities to + know if we are getting effective roles or not + + """ + self.user1 = self.new_user_ref( + domain_id=self.domain['id']) + self.user1['password'] = uuid.uuid4().hex + self.identity_api.create_user(self.user1['id'], self.user1) + self.user2 = self.new_user_ref( + domain_id=self.domain['id']) + self.user2['password'] = uuid.uuid4().hex + self.identity_api.create_user(self.user2['id'], self.user2) + self.identity_api.add_user_to_group(self.user1['id'], self.group['id']) + self.identity_api.add_user_to_group(self.user2['id'], self.group['id']) + + collection_url = '/role_assignments' + r = self.get(collection_url) + self.assertValidRoleAssignmentListResponse(r) + existing_assignments = len(r.result.get('role_assignments')) + + gd_url, gd_entity = _build_role_assignment_url_and_entity( + domain_id=self.domain_id, group_id=self.group_id, + role_id=self.role_id) + self.put(gd_url) + r = self.get(collection_url) + self.assertValidRoleAssignmentListResponse(r) + self.assertEqual(len(r.result.get('role_assignments')), + existing_assignments + 1) + self.assertRoleAssignmentInListResponse(r, gd_entity, link_url=gd_url) + + # Now re-read the collection asking for effective roles, + # using the most common way of defining "effective'. This + # should mean the group assignment is translated into the two + # member user assignments + collection_url = '/role_assignments?effective' + r = self.get(collection_url) + self.assertValidRoleAssignmentListResponse(r) + self.assertEqual(len(r.result.get('role_assignments')), + existing_assignments + 2) + # Now set 'effective' to false explicitly - should get + # back the regular roles + collection_url = '/role_assignments?effective=0' + r = self.get(collection_url) + self.assertValidRoleAssignmentListResponse(r) + self.assertEqual(len(r.result.get('role_assignments')), + existing_assignments + 1) + # Now try setting 'effective' to 'False' explicitly- this is + # NOT supported as a way of setting a query or filter + # parameter to false by design. Hence we should get back + # effective roles. + collection_url = '/role_assignments?effective=False' + r = self.get(collection_url) + self.assertValidRoleAssignmentListResponse(r) + self.assertEqual(len(r.result.get('role_assignments')), + existing_assignments + 2) + # Now set 'effective' to True explicitly + collection_url = '/role_assignments?effective=True' + r = self.get(collection_url) + self.assertValidRoleAssignmentListResponse(r) + self.assertEqual(len(r.result.get('role_assignments')), + existing_assignments + 2) + + def test_filtered_role_assignments(self): + """Call ``GET /role_assignments?filters``. + + Test Plan: + - Create extra users, group, role and project for tests + - Make the following assignments: + Give group1, role1 on project1 and domain + Give user1, role2 on project1 and domain + Make User1 a member of Group1 + - Test a series of single filter list calls, checking that + the correct results are obtained + - Test a multi-filtered list call + - Test listing all effective roles for a given user + - Test the equivalent of the list of roles in a project scoped + token (all effective roles for a user on a project) + + """ + + # Since the default fixtures already assign some roles to the + # user it creates, we also need a new user that will not have any + # existing assignments + self.user1 = self.new_user_ref( + domain_id=self.domain['id']) + self.user1['password'] = uuid.uuid4().hex + self.identity_api.create_user(self.user1['id'], self.user1) + self.user2 = self.new_user_ref( + domain_id=self.domain['id']) + self.user2['password'] = uuid.uuid4().hex + self.identity_api.create_user(self.user2['id'], self.user2) + self.group1 = self.new_group_ref( + domain_id=self.domain['id']) + self.identity_api.create_group(self.group1['id'], self.group1) + self.identity_api.add_user_to_group(self.user1['id'], + self.group1['id']) + self.identity_api.add_user_to_group(self.user2['id'], + self.group1['id']) + self.project1 = self.new_project_ref( + domain_id=self.domain['id']) + self.identity_api.create_project(self.project1['id'], self.project1) + self.role1 = self.new_role_ref() + self.identity_api.create_role(self.role1['id'], self.role1) + self.role2 = self.new_role_ref() + self.identity_api.create_role(self.role2['id'], self.role2) + + # Now add one of each of the four types of assignment + + gd_url, gd_entity = _build_role_assignment_url_and_entity( + domain_id=self.domain_id, group_id=self.group1['id'], + role_id=self.role1['id']) + self.put(gd_url) + + ud_url, ud_entity = _build_role_assignment_url_and_entity( + domain_id=self.domain_id, user_id=self.user1['id'], + role_id=self.role2['id']) + self.put(ud_url) + + gp_url, gp_entity = _build_role_assignment_url_and_entity( + project_id=self.project1['id'], group_id=self.group1['id'], + role_id=self.role1['id']) + self.put(gp_url) + + up_url, up_entity = _build_role_assignment_url_and_entity( + project_id=self.project1['id'], user_id=self.user1['id'], + role_id=self.role2['id']) + self.put(up_url) + + # Now list by various filters to make sure we get back the right ones + + collection_url = ('/role_assignments?scope.project.id=%s' % + self.project1['id']) + r = self.get(collection_url) + self.assertValidRoleAssignmentListResponse(r) + self.assertEqual(len(r.result.get('role_assignments')), 2) + self.assertRoleAssignmentInListResponse(r, up_entity, link_url=up_url) + self.assertRoleAssignmentInListResponse(r, gp_entity, link_url=gp_url) + + collection_url = ('/role_assignments?scope.domain.id=%s' % + self.domain['id']) + r = self.get(collection_url) + self.assertValidRoleAssignmentListResponse(r) + self.assertEqual(len(r.result.get('role_assignments')), 2) + self.assertRoleAssignmentInListResponse(r, ud_entity, link_url=ud_url) + self.assertRoleAssignmentInListResponse(r, gd_entity, link_url=gd_url) + + collection_url = '/role_assignments?user.id=%s' % self.user1['id'] + r = self.get(collection_url) + self.assertValidRoleAssignmentListResponse(r) + self.assertEqual(len(r.result.get('role_assignments')), 2) + self.assertRoleAssignmentInListResponse(r, up_entity, link_url=up_url) + self.assertRoleAssignmentInListResponse(r, ud_entity, link_url=ud_url) + + collection_url = '/role_assignments?group.id=%s' % self.group1['id'] + r = self.get(collection_url) + self.assertValidRoleAssignmentListResponse(r) + self.assertEqual(len(r.result.get('role_assignments')), 2) + self.assertRoleAssignmentInListResponse(r, gd_entity, link_url=gd_url) + self.assertRoleAssignmentInListResponse(r, gp_entity, link_url=gp_url) + + collection_url = '/role_assignments?role.id=%s' % self.role1['id'] + r = self.get(collection_url) + self.assertValidRoleAssignmentListResponse(r) + self.assertEqual(len(r.result.get('role_assignments')), 2) + self.assertRoleAssignmentInListResponse(r, gd_entity, link_url=gd_url) + self.assertRoleAssignmentInListResponse(r, gp_entity, link_url=gp_url) + + # Let's try combining two filers together.... + + collection_url = ( + '/role_assignments?user.id=%(user_id)s' + '&scope.project.id=%(project_id)s' % { + 'user_id': self.user1['id'], + 'project_id': self.project1['id']}) + r = self.get(collection_url) + self.assertValidRoleAssignmentListResponse(r) + self.assertEqual(len(r.result.get('role_assignments')), 1) + self.assertRoleAssignmentInListResponse(r, up_entity, link_url=up_url) + + # Now for a harder one - filter for user with effective + # roles - this should return role assignment that were directly + # assigned as well as by virtue of group membership + + collection_url = ('/role_assignments?effective&user.id=%s' % + self.user1['id']) + r = self.get(collection_url) + self.assertValidRoleAssignmentListResponse(r) + self.assertEqual(len(r.result.get('role_assignments')), 4) + # Should have the two direct roles... + self.assertRoleAssignmentInListResponse(r, up_entity, link_url=up_url) + self.assertRoleAssignmentInListResponse(r, ud_entity, link_url=ud_url) + # ...and the two via group membership... + unused, up1_entity = _build_role_assignment_url_and_entity( + project_id=self.project1['id'], user_id=self.user1['id'], + role_id=self.role1['id']) + unused, ud1_entity = _build_role_assignment_url_and_entity( + domain_id=self.domain_id, user_id=self.user1['id'], + role_id=self.role1['id']) + gp1_url, unused = _build_role_assignment_url_and_entity( + project_id=self.project1['id'], group_id=self.group1['id'], + role_id=self.role1['id']) + gd1_url, unused = _build_role_assignment_url_and_entity( + domain_id=self.domain_id, group_id=self.group1['id'], + role_id=self.role1['id']) + self.assertRoleAssignmentInListResponse(r, up1_entity, + link_url=gp1_url) + self.assertRoleAssignmentInListResponse(r, ud1_entity, + link_url=gd1_url) + + # ...and for the grand-daddy of them all, simulate the request + # that would generate the list of effective roles in a project + # scoped token. + + collection_url = ( + '/role_assignments?effective&user.id=%(user_id)s' + '&scope.project.id=%(project_id)s' % { + 'user_id': self.user1['id'], + 'project_id': self.project1['id']}) + r = self.get(collection_url) + self.assertValidRoleAssignmentListResponse(r) + self.assertEqual(len(r.result.get('role_assignments')), 2) + # Should have one direct role and one from group membership... + self.assertRoleAssignmentInListResponse(r, up_entity, link_url=up_url) + self.assertRoleAssignmentInListResponse(r, up1_entity, + link_url=gp1_url) + + +class IdentityIneritanceTestCase(test_v3.RestfulTestCase): + """Test inheritance crud and its effects.""" + + def setUp(self): + self.orig_extension_enablement = config.CONF.os_inherit.enabled + self.opt_in_group('os_inherit', enabled=True) + super(IdentityIneritanceTestCase, self).setUp() + + def tearDown(self): + super(IdentityIneritanceTestCase, self).tearDown() + self.opt_in_group('os_inherit', enabled=self.orig_extension_enablement) + + def test_crud_user_inherited_domain_role_grants(self): + role_list = [] + for _ in range(2): + role = {'id': uuid.uuid4().hex, 'name': uuid.uuid4().hex} + self.assignment_api.create_role(role['id'], role) + role_list.append(role) + + # Create a non-inherited role as a spoiler + self.assignment_api.create_grant( + role_list[1]['id'], user_id=self.user['id'], + domain_id=self.domain_id) + + base_collection_url = ( + '/OS-INHERIT/domains/%(domain_id)s/users/%(user_id)s/roles' % { + 'domain_id': self.domain_id, + 'user_id': self.user['id']}) + member_url = '%(collection_url)s/%(role_id)s/inherited_to_projects' % { + 'collection_url': base_collection_url, + 'role_id': role_list[0]['id']} + collection_url = base_collection_url + '/inherited_to_projects' + + self.put(member_url) + + # Check we can read it back + self.head(member_url) + r = self.get(collection_url) + self.assertValidRoleListResponse(r, ref=role_list[0]) + self.assertIn(collection_url, r.result['links']['self']) + + # Now delete and check its gone + self.delete(member_url) + r = self.get(collection_url) + self.assertValidRoleListResponse(r, expected_length=0) + self.assertIn(collection_url, r.result['links']['self']) + + def test_crud_inherited_role_grants_failed_if_disabled(self): + # Disable the extension and check no API calls can be issued + self.opt_in_group('os_inherit', enabled=False) + super(IdentityIneritanceTestCase, self).setUp() + + role = {'id': uuid.uuid4().hex, 'name': uuid.uuid4().hex} + self.assignment_api.create_role(role['id'], role) + + base_collection_url = ( + '/OS-INHERIT/domains/%(domain_id)s/users/%(user_id)s/roles' % { + 'domain_id': self.domain_id, + 'user_id': self.user['id']}) + member_url = '%(collection_url)s/%(role_id)s/inherited_to_projects' % { + 'collection_url': base_collection_url, + 'role_id': role['id']} + collection_url = base_collection_url + '/inherited_to_projects' + + self.put(member_url, expected_status=404) + self.head(member_url, expected_status=404) + self.get(collection_url, expected_status=404) + self.delete(member_url, expected_status=404) + + def test_list_role_assignments_for_inherited_domain_grants(self): + """Call ``GET /role_assignments with inherited domain grants``. + + Test Plan: + - Create 4 roles + - Create a domain with a user and two projects + - Assign two direct roles to project1 + - Assign a spoiler role to project2 + - Issue the URL to add inherited role to the domain + - Issue the URL to check it is indeed on the domain + - Issue the URL to check effective roles on project1 - this + should return 3 roles. + + """ + role_list = [] + for _ in range(4): + role = {'id': uuid.uuid4().hex, 'name': uuid.uuid4().hex} + self.assignment_api.create_role(role['id'], role) + role_list.append(role) + + domain = self.new_domain_ref() + self.identity_api.create_domain(domain['id'], domain) + user1 = self.new_user_ref( + domain_id=domain['id']) + user1['password'] = uuid.uuid4().hex + self.identity_api.create_user(user1['id'], user1) + project1 = self.new_project_ref( + domain_id=domain['id']) + self.assignment_api.create_project(project1['id'], project1) + project2 = self.new_project_ref( + domain_id=domain['id']) + self.assignment_api.create_project(project2['id'], project2) + # Add some roles to the project + self.assignment_api.add_role_to_user_and_project( + user1['id'], project1['id'], role_list[0]['id']) + self.assignment_api.add_role_to_user_and_project( + user1['id'], project1['id'], role_list[1]['id']) + # ..and one on a different project as a spoiler + self.assignment_api.add_role_to_user_and_project( + user1['id'], project2['id'], role_list[2]['id']) + + # Now create our inherited role on the domain + base_collection_url = ( + '/OS-INHERIT/domains/%(domain_id)s/users/%(user_id)s/roles' % { + 'domain_id': domain['id'], + 'user_id': user1['id']}) + member_url = '%(collection_url)s/%(role_id)s/inherited_to_projects' % { + 'collection_url': base_collection_url, + 'role_id': role_list[3]['id']} + collection_url = base_collection_url + '/inherited_to_projects' + + self.put(member_url) + self.head(member_url) + r = self.get(collection_url) + self.assertValidRoleListResponse(r, ref=role_list[3]) + self.assertIn(collection_url, r.result['links']['self']) + + # Now use the list domain role assignments api to check if this + # is included + collection_url = ( + '/role_assignments?user.id=%(user_id)s' + '&scope.domain.id=%(domain_id)s' % { + 'user_id': user1['id'], + 'domain_id': domain['id']}) + r = self.get(collection_url) + self.assertValidRoleAssignmentListResponse(r) + self.assertEqual(len(r.result.get('role_assignments')), 1) + ud_url, ud_entity = _build_role_assignment_url_and_entity( + domain_id=domain['id'], user_id=user1['id'], + role_id=role_list[3]['id'], inherited_to_projects=True) + self.assertRoleAssignmentInListResponse(r, ud_entity, link_url=ud_url) + + # Now ask for effective list role assignments - the role should + # turn into a project role, along with the two direct roles that are + # on the project + collection_url = ( + '/role_assignments?effective&user.id=%(user_id)s' + '&scope.project.id=%(project_id)s' % { + 'user_id': user1['id'], + 'project_id': project1['id']}) + r = self.get(collection_url) + self.assertValidRoleAssignmentListResponse(r) + self.assertEqual(len(r.result.get('role_assignments')), 3) + # An effective role for an inherited role will be a project + # entity, with a domain link to the inherited assignment + unused, up_entity = _build_role_assignment_url_and_entity( + project_id=project1['id'], user_id=user1['id'], + role_id=role_list[3]['id']) + ud_url, unused = _build_role_assignment_url_and_entity( + domain_id=domain['id'], user_id=user1['id'], + role_id=role_list[3]['id'], inherited_to_projects=True) + self.assertRoleAssignmentInListResponse(r, up_entity, link_url=ud_url) + + def test_list_role_assignments_for_disabled_inheritance_extension(self): + """Call ``GET /role_assignments with inherited domain grants``. + + Test Plan: + - Issue the URL to add inherited role to the domain + - Issue the URL to check effective roles on project include the + inherited role + - Disable the extension + - Re-check the effective roles, proving the inherited role no longer + shows up. + + """ + + role_list = [] + for _ in range(4): + role = {'id': uuid.uuid4().hex, 'name': uuid.uuid4().hex} + self.assignment_api.create_role(role['id'], role) + role_list.append(role) + + domain = self.new_domain_ref() + self.identity_api.create_domain(domain['id'], domain) + user1 = self.new_user_ref( + domain_id=domain['id']) + user1['password'] = uuid.uuid4().hex + self.identity_api.create_user(user1['id'], user1) + project1 = self.new_project_ref( + domain_id=domain['id']) + self.assignment_api.create_project(project1['id'], project1) + project2 = self.new_project_ref( + domain_id=domain['id']) + self.assignment_api.create_project(project2['id'], project2) + # Add some roles to the project + self.assignment_api.add_role_to_user_and_project( + user1['id'], project1['id'], role_list[0]['id']) + self.assignment_api.add_role_to_user_and_project( + user1['id'], project1['id'], role_list[1]['id']) + # ..and one on a different project as a spoiler + self.assignment_api.add_role_to_user_and_project( + user1['id'], project2['id'], role_list[2]['id']) + + # Now create our inherited role on the domain + base_collection_url = ( + '/OS-INHERIT/domains/%(domain_id)s/users/%(user_id)s/roles' % { + 'domain_id': domain['id'], + 'user_id': user1['id']}) + member_url = '%(collection_url)s/%(role_id)s/inherited_to_projects' % { + 'collection_url': base_collection_url, + 'role_id': role_list[3]['id']} + collection_url = base_collection_url + '/inherited_to_projects' + + self.put(member_url) + self.head(member_url) + r = self.get(collection_url) + self.assertValidRoleListResponse(r, ref=role_list[3]) + self.assertIn(collection_url, r.result['links']['self']) + + # Get effective list role assignments - the role should + # turn into a project role, along with the two direct roles that are + # on the project + collection_url = ( + '/role_assignments?effective&user.id=%(user_id)s' + '&scope.project.id=%(project_id)s' % { + 'user_id': user1['id'], + 'project_id': project1['id']}) + r = self.get(collection_url) + self.assertValidRoleAssignmentListResponse(r) + self.assertEqual(len(r.result.get('role_assignments')), 3) + + unused, up_entity = _build_role_assignment_url_and_entity( + project_id=project1['id'], user_id=user1['id'], + role_id=role_list[3]['id']) + ud_url, unused = _build_role_assignment_url_and_entity( + domain_id=domain['id'], user_id=user1['id'], + role_id=role_list[3]['id'], inherited_to_projects=True) + self.assertRoleAssignmentInListResponse(r, up_entity, link_url=ud_url) + + # Disable the extension and re-check the list, the role inherited + # from the project should no longer show up + self.opt_in_group('os_inherit', enabled=False) + r = self.get(collection_url) + self.assertValidRoleAssignmentListResponse(r) + self.assertEqual(len(r.result.get('role_assignments')), 2) + + unused, up_entity = _build_role_assignment_url_and_entity( + project_id=project1['id'], user_id=user1['id'], + role_id=role_list[3]['id']) + ud_url, unused = _build_role_assignment_url_and_entity( + domain_id=domain['id'], user_id=user1['id'], + role_id=role_list[3]['id'], inherited_to_projects=True) + self.assertRoleAssignmentNotInListResponse(r, up_entity, + link_url=ud_url) + + def test_list_role_assignments_for_inherited_group_domain_grants(self): + """Call ``GET /role_assignments with inherited group domain grants``. + + Test Plan: + - Create 4 roles + - Create a domain with a user and two projects + - Assign two direct roles to project1 + - Assign a spoiler role to project2 + - Issue the URL to add inherited role to the domain + - Issue the URL to check it is indeed on the domain + - Issue the URL to check effective roles on project1 - this + should return 3 roles. + + """ + role_list = [] + for _ in range(4): + role = {'id': uuid.uuid4().hex, 'name': uuid.uuid4().hex} + self.assignment_api.create_role(role['id'], role) + role_list.append(role) + + domain = self.new_domain_ref() + self.identity_api.create_domain(domain['id'], domain) + user1 = self.new_user_ref( + domain_id=domain['id']) + user1['password'] = uuid.uuid4().hex + self.identity_api.create_user(user1['id'], user1) + user2 = self.new_user_ref( + domain_id=domain['id']) + user2['password'] = uuid.uuid4().hex + self.identity_api.create_user(user2['id'], user2) + group1 = self.new_group_ref( + domain_id=domain['id']) + self.identity_api.create_group(group1['id'], group1) + self.identity_api.add_user_to_group(user1['id'], + group1['id']) + self.identity_api.add_user_to_group(user2['id'], + group1['id']) + project1 = self.new_project_ref( + domain_id=domain['id']) + self.assignment_api.create_project(project1['id'], project1) + project2 = self.new_project_ref( + domain_id=domain['id']) + self.assignment_api.create_project(project2['id'], project2) + # Add some roles to the project + self.assignment_api.add_role_to_user_and_project( + user1['id'], project1['id'], role_list[0]['id']) + self.assignment_api.add_role_to_user_and_project( + user1['id'], project1['id'], role_list[1]['id']) + # ..and one on a different project as a spoiler + self.assignment_api.add_role_to_user_and_project( + user1['id'], project2['id'], role_list[2]['id']) + + # Now create our inherited role on the domain + base_collection_url = ( + '/OS-INHERIT/domains/%(domain_id)s/groups/%(group_id)s/roles' % { + 'domain_id': domain['id'], + 'group_id': group1['id']}) + member_url = '%(collection_url)s/%(role_id)s/inherited_to_projects' % { + 'collection_url': base_collection_url, + 'role_id': role_list[3]['id']} + collection_url = base_collection_url + '/inherited_to_projects' + + self.put(member_url) + self.head(member_url) + r = self.get(collection_url) + self.assertValidRoleListResponse(r, ref=role_list[3]) + self.assertIn(collection_url, r.result['links']['self']) + + # Now use the list domain role assignments api to check if this + # is included + collection_url = ( + '/role_assignments?group.id=%(group_id)s' + '&scope.domain.id=%(domain_id)s' % { + 'group_id': group1['id'], + 'domain_id': domain['id']}) + r = self.get(collection_url) + self.assertValidRoleAssignmentListResponse(r) + self.assertEqual(len(r.result.get('role_assignments')), 1) + gd_url, gd_entity = _build_role_assignment_url_and_entity( + domain_id=domain['id'], group_id=group1['id'], + role_id=role_list[3]['id'], inherited_to_projects=True) + self.assertRoleAssignmentInListResponse(r, gd_entity, link_url=gd_url) + + # Now ask for effective list role assignments - the role should + # turn into a user project role, along with the two direct roles + # that are on the project + collection_url = ( + '/role_assignments?effective&user.id=%(user_id)s' + '&scope.project.id=%(project_id)s' % { + 'user_id': user1['id'], + 'project_id': project1['id']}) + r = self.get(collection_url) + self.assertValidRoleAssignmentListResponse(r) + self.assertEqual(len(r.result.get('role_assignments')), 3) + # An effective role for an inherited role will be a project + # entity, with a domain link to the inherited assignment + unused, up_entity = _build_role_assignment_url_and_entity( + project_id=project1['id'], user_id=user1['id'], + role_id=role_list[3]['id']) + gd_url, unused = _build_role_assignment_url_and_entity( + domain_id=domain['id'], group_id=group1['id'], + role_id=role_list[3]['id'], inherited_to_projects=True) + self.assertRoleAssignmentInListResponse(r, up_entity, link_url=gd_url) + + def test_filtered_role_assignments_for_inherited_grants(self): + """Call ``GET /role_assignments?scope.OS-INHERIT:inherited_to``. + + Test Plan: + - Create 5 roles + - Create a domain with a user, group and two projects + - Assign three direct spoiler roles to projects + - Issue the URL to add an inherited user role to the domain + - Issue the URL to add an inherited group role to the domain + - Issue the URL to filter by inherited roles - this should + return just the 2 inherited roles. + + """ + role_list = [] + for _ in range(5): + role = {'id': uuid.uuid4().hex, 'name': uuid.uuid4().hex} + self.assignment_api.create_role(role['id'], role) + role_list.append(role) + + domain = self.new_domain_ref() + self.identity_api.create_domain(domain['id'], domain) + user1 = self.new_user_ref( + domain_id=domain['id']) + user1['password'] = uuid.uuid4().hex + self.identity_api.create_user(user1['id'], user1) + group1 = self.new_group_ref( + domain_id=domain['id']) + self.identity_api.create_group(group1['id'], group1) + project1 = self.new_project_ref( + domain_id=domain['id']) + self.assignment_api.create_project(project1['id'], project1) + project2 = self.new_project_ref( + domain_id=domain['id']) + self.assignment_api.create_project(project2['id'], project2) + # Add some spoiler roles to the projects + self.assignment_api.add_role_to_user_and_project( + user1['id'], project1['id'], role_list[0]['id']) + self.assignment_api.add_role_to_user_and_project( + user1['id'], project2['id'], role_list[1]['id']) + # Create a non-inherited role as a spoiler + self.assignment_api.create_grant( + role_list[2]['id'], user_id=user1['id'], domain_id=domain['id']) + + # Now create two inherited roles on the domain, one for a user + # and one for a domain + base_collection_url = ( + '/OS-INHERIT/domains/%(domain_id)s/users/%(user_id)s/roles' % { + 'domain_id': domain['id'], + 'user_id': user1['id']}) + member_url = '%(collection_url)s/%(role_id)s/inherited_to_projects' % { + 'collection_url': base_collection_url, + 'role_id': role_list[3]['id']} + collection_url = base_collection_url + '/inherited_to_projects' + + self.put(member_url) + self.head(member_url) + r = self.get(collection_url) + self.assertValidRoleListResponse(r, ref=role_list[3]) + self.assertIn(collection_url, r.result['links']['self']) + + base_collection_url = ( + '/OS-INHERIT/domains/%(domain_id)s/groups/%(group_id)s/roles' % { + 'domain_id': domain['id'], + 'group_id': group1['id']}) + member_url = '%(collection_url)s/%(role_id)s/inherited_to_projects' % { + 'collection_url': base_collection_url, + 'role_id': role_list[4]['id']} + collection_url = base_collection_url + '/inherited_to_projects' + + self.put(member_url) + self.head(member_url) + r = self.get(collection_url) + self.assertValidRoleListResponse(r, ref=role_list[4]) + self.assertIn(collection_url, r.result['links']['self']) + + # Now use the list role assignments api to get a list of inherited + # roles on the domain - should get back the two roles + collection_url = ( + '/role_assignments?scope.OS-INHERIT:inherited_to=projects') + r = self.get(collection_url) + self.assertValidRoleAssignmentListResponse(r) + self.assertEqual(len(r.result.get('role_assignments')), 2) + ud_url, ud_entity = _build_role_assignment_url_and_entity( + domain_id=domain['id'], user_id=user1['id'], + role_id=role_list[3]['id'], inherited_to_projects=True) + gd_url, gd_entity = _build_role_assignment_url_and_entity( + domain_id=domain['id'], group_id=group1['id'], + role_id=role_list[4]['id'], inherited_to_projects=True) + self.assertRoleAssignmentInListResponse(r, ud_entity, link_url=ud_url) + self.assertRoleAssignmentInListResponse(r, gd_entity, link_url=gd_url) |