diff --git a/keystone/tests/unit/assignment/__init__.py b/keystone/tests/unit/assignment/__init__.py new file mode 100644 index 0000000000..e69de29bb2 diff --git a/keystone/tests/unit/assignment/test_backends.py b/keystone/tests/unit/assignment/test_backends.py new file mode 100644 index 0000000000..d8b46ef7c5 --- /dev/null +++ b/keystone/tests/unit/assignment/test_backends.py @@ -0,0 +1,3712 @@ +# Licensed under the Apache License, Version 2.0 (the "License"); you may +# not use this file except in compliance with the License. You may obtain +# a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT +# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the +# License for the specific language governing permissions and limitations +# under the License. + +import uuid + +import mock +from oslo_config import cfg +from six.moves import range +from testtools import matchers + +from keystone import exception +from keystone.tests import unit + + +CONF = cfg.CONF + + +class AssignmentTestHelperMixin(object): + """Mixin class to aid testing of assignments. + + This class supports data driven test plans that enable: + + - Creation of initial entities, such as domains, users, groups, projects + and roles + - Creation of assignments referencing the above entities + - A set of input parameters and expected outputs to list_role_assignments + based on the above test data + + A test plan is a dict of the form: + + test_plan = { + entities: details and number of entities, + group_memberships: group-user entity memberships, + assignments: list of assignments to create, + tests: list of pairs of input params and expected outputs} + + An example test plan: + + test_plan = { + # First, create the entities required. Entities are specified by + # a dict with the key being the entity type and the value an + # entity specification which can be one of: + # + # - a simple number, e.g. {'users': 3} creates 3 users + # - a dict where more information regarding the contents of the entity + # is required, e.g. {'domains' : {'users : 3}} creates a domain + # with three users + # - a list of entity specifications if multiple are required + # + # The following creates a domain that contains a single user, group and + # project, as well as creating three roles. + + 'entities': {'domains': {'users': 1, 'groups': 1, 'projects': 1}, + 'roles': 3}, + + # If it is required that an existing domain be used for the new + # entities, then the id of that domain can be included in the + # domain dict. For example, if alternatively we wanted to add 3 users + # to the default domain, add a second domain containing 3 projects as + # well as 5 additional empty domains, the entities would be defined as: + # + # 'entities': {'domains': [{'id': DEFAULT_DOMAIN, 'users': 3}, + # {'projects': 3}, 5]}, + # + # A project hierarchy can be specified within the 'projects' section by + # nesting the 'project' key, for example to create a project with three + # sub-projects you would use: + + 'projects': {'project': 3} + + # A more complex hierarchy can also be defined, for example the + # following would define three projects each containing a + # sub-project, each of which contain a further three sub-projects. + + 'projects': [{'project': {'project': 3}}, + {'project': {'project': 3}}, + {'project': {'project': 3}}] + + # If the 'roles' entity count is defined as top level key in 'entities' + # dict then these are global roles. If it is placed within the + # 'domain' dict, then they will be domain specific roles. A mix of + # domain specific and global roles are allowed, with the role index + # being calculated in the order they are defined in the 'entities' + # dict. + + # A set of implied role specifications. In this case, prior role + # index 0 implies role index 1, and role 1 implies roles 2 and 3. + + 'roles': [{'role': 0, 'implied_roles': [1]}, + {'role': 1, 'implied_roles': [2, 3]}] + + # A list of groups and their members. In this case make users with + # index 0 and 1 members of group with index 0. Users and Groups are + # indexed in the order they appear in the 'entities' key above. + + 'group_memberships': [{'group': 0, 'users': [0, 1]}] + + # Next, create assignments between the entities, referencing the + # entities by index, i.e. 'user': 0 refers to user[0]. Entities are + # indexed in the order they appear in the 'entities' key above within + # their entity type. + + 'assignments': [{'user': 0, 'role': 0, 'domain': 0}, + {'user': 0, 'role': 1, 'project': 0}, + {'group': 0, 'role': 2, 'domain': 0}, + {'user': 0, 'role': 2, 'project': 0}], + + # Finally, define an array of tests where list_role_assignment() is + # called with the given input parameters and the results are then + # confirmed to be as given in 'results'. Again, all entities are + # referenced by index. + + 'tests': [ + {'params': {}, + 'results': [{'user': 0, 'role': 0, 'domain': 0}, + {'user': 0, 'role': 1, 'project': 0}, + {'group': 0, 'role': 2, 'domain': 0}, + {'user': 0, 'role': 2, 'project': 0}]}, + {'params': {'role': 2}, + 'results': [{'group': 0, 'role': 2, 'domain': 0}, + {'user': 0, 'role': 2, 'project': 0}]}] + + # The 'params' key also supports the 'effective', + # 'inherited_to_projects' and 'source_from_group_ids' options to + # list_role_assignments.} + + """ + + def _handle_project_spec(self, test_data, domain_id, project_spec, + parent_id=None): + """Handle the creation of a project or hierarchy of projects. + + project_spec may either be a count of the number of projects to + create, or it may be a list of the form: + + [{'project': project_spec}, {'project': project_spec}, ...] + + This method is called recursively to handle the creation of a + hierarchy of projects. + + """ + def _create_project(domain_id, parent_id): + new_project = unit.new_project_ref(domain_id=domain_id, + parent_id=parent_id) + new_project = self.resource_api.create_project(new_project['id'], + new_project) + return new_project + + if isinstance(project_spec, list): + for this_spec in project_spec: + self._handle_project_spec( + test_data, domain_id, this_spec, parent_id=parent_id) + elif isinstance(project_spec, dict): + new_proj = _create_project(domain_id, parent_id) + test_data['projects'].append(new_proj) + self._handle_project_spec( + test_data, domain_id, project_spec['project'], + parent_id=new_proj['id']) + else: + for _ in range(project_spec): + test_data['projects'].append( + _create_project(domain_id, parent_id)) + + def _create_role(self, domain_id=None): + new_role = unit.new_role_ref(domain_id=domain_id) + return self.role_api.create_role(new_role['id'], new_role) + + def _handle_domain_spec(self, test_data, domain_spec): + """Handle the creation of domains and their contents. + + domain_spec may either be a count of the number of empty domains to + create, a dict describing the domain contents, or a list of + domain_specs. + + In the case when a list is provided, this method calls itself + recursively to handle the list elements. + + This method will insert any entities created into test_data + + """ + def _create_domain(domain_id=None): + if domain_id is None: + new_domain = unit.new_domain_ref() + self.resource_api.create_domain(new_domain['id'], + new_domain) + return new_domain + else: + # The test plan specified an existing domain to use + return self.resource_api.get_domain(domain_id) + + def _create_entity_in_domain(entity_type, domain_id): + """Create a user or group entity in the domain.""" + if entity_type == 'users': + new_entity = unit.new_user_ref(domain_id=domain_id) + new_entity = self.identity_api.create_user(new_entity) + elif entity_type == 'groups': + new_entity = unit.new_group_ref(domain_id=domain_id) + new_entity = self.identity_api.create_group(new_entity) + elif entity_type == 'roles': + new_entity = self._create_role(domain_id=domain_id) + else: + # Must be a bad test plan + raise exception.NotImplemented() + return new_entity + + if isinstance(domain_spec, list): + for x in domain_spec: + self._handle_domain_spec(test_data, x) + elif isinstance(domain_spec, dict): + # If there is a domain ID specified, then use it + the_domain = _create_domain(domain_spec.get('id')) + test_data['domains'].append(the_domain) + for entity_type, value in domain_spec.items(): + if entity_type == 'id': + # We already used this above to determine whether to + # use and existing domain + continue + if entity_type == 'projects': + # If it's projects, we need to handle the potential + # specification of a project hierarchy + self._handle_project_spec( + test_data, the_domain['id'], value) + else: + # It's a count of number of entities + for _ in range(value): + test_data[entity_type].append( + _create_entity_in_domain( + entity_type, the_domain['id'])) + else: + for _ in range(domain_spec): + test_data['domains'].append(_create_domain()) + + def create_entities(self, entity_pattern): + """Create the entities specified in the test plan. + + Process the 'entities' key in the test plan, creating the requested + entities. Each created entity will be added to the array of entities + stored in the returned test_data object, e.g.: + + test_data['users'] = [user[0], user[1]....] + + """ + test_data = {} + for entity in ['users', 'groups', 'domains', 'projects', 'roles']: + test_data[entity] = [] + + # Create any domains requested and, if specified, any entities within + # those domains + if 'domains' in entity_pattern: + self._handle_domain_spec(test_data, entity_pattern['domains']) + + # Create any roles requested + if 'roles' in entity_pattern: + for _ in range(entity_pattern['roles']): + test_data['roles'].append(self._create_role()) + + return test_data + + def _convert_entity_shorthand(self, key, shorthand_data, reference_data): + """Convert a shorthand entity description into a full ID reference. + + In test plan definitions, we allow a shorthand for referencing to an + entity of the form: + + 'user': 0 + + which is actually shorthand for: + + 'user_id': reference_data['users'][0]['id'] + + This method converts the shorthand version into the full reference. + + """ + expanded_key = '%s_id' % key + reference_index = '%ss' % key + index_value = ( + reference_data[reference_index][shorthand_data[key]]['id']) + return expanded_key, index_value + + def create_implied_roles(self, implied_pattern, test_data): + """Create the implied roles specified in the test plan.""" + for implied_spec in implied_pattern: + # Each implied role specification is a dict of the form: + # + # {'role': 0, 'implied_roles': list of roles} + + prior_role = test_data['roles'][implied_spec['role']]['id'] + if isinstance(implied_spec['implied_roles'], list): + for this_role in implied_spec['implied_roles']: + implied_role = test_data['roles'][this_role]['id'] + self.role_api.create_implied_role(prior_role, implied_role) + else: + implied_role = ( + test_data['roles'][implied_spec['implied_roles']]['id']) + self.role_api.create_implied_role(prior_role, implied_role) + + def create_group_memberships(self, group_pattern, test_data): + """Create the group memberships specified in the test plan.""" + for group_spec in group_pattern: + # Each membership specification is a dict of the form: + # + # {'group': 0, 'users': [list of user indexes]} + # + # Add all users in the list to the specified group, first + # converting from index to full entity ID. + group_value = test_data['groups'][group_spec['group']]['id'] + for user_index in group_spec['users']: + user_value = test_data['users'][user_index]['id'] + self.identity_api.add_user_to_group(user_value, group_value) + return test_data + + def create_assignments(self, assignment_pattern, test_data): + """Create the assignments specified in the test plan.""" + # First store how many assignments are already in the system, + # so during the tests we can check the number of new assignments + # created. + test_data['initial_assignment_count'] = ( + len(self.assignment_api.list_role_assignments())) + + # Now create the new assignments in the test plan + for assignment in assignment_pattern: + # Each assignment is a dict of the form: + # + # { 'user': 0, 'project':1, 'role': 6} + # + # where the value of each item is the index into the array of + # entities created earlier. + # + # We process the assignment dict to create the args required to + # make the create_grant() call. + args = {} + for param in assignment: + if param == 'inherited_to_projects': + args[param] = assignment[param] + else: + # Turn 'entity : 0' into 'entity_id = ac6736ba873d' + # where entity in user, group, project or domain + key, value = self._convert_entity_shorthand( + param, assignment, test_data) + args[key] = value + self.assignment_api.create_grant(**args) + return test_data + + def execute_assignment_cases(self, test_plan, test_data): + """Execute the test plan, based on the created test_data.""" + def check_results(expected, actual, param_arg_count): + if param_arg_count == 0: + # It was an unfiltered call, so default fixture assignments + # might be polluting our answer - so we take into account + # how many assignments there were before the test. + self.assertEqual( + len(expected) + test_data['initial_assignment_count'], + len(actual)) + else: + self.assertThat(actual, matchers.HasLength(len(expected))) + + for each_expected in expected: + expected_assignment = {} + for param in each_expected: + if param == 'inherited_to_projects': + expected_assignment[param] = each_expected[param] + elif param == 'indirect': + # We're expecting the result to contain an indirect + # dict with the details how the role came to be placed + # on this entity - so convert the key/value pairs of + # that dict into real entity references. + indirect_term = {} + for indirect_param in each_expected[param]: + key, value = self._convert_entity_shorthand( + indirect_param, each_expected[param], + test_data) + indirect_term[key] = value + expected_assignment[param] = indirect_term + else: + # Convert a simple shorthand entry into a full + # entity reference + key, value = self._convert_entity_shorthand( + param, each_expected, test_data) + expected_assignment[key] = value + self.assertIn(expected_assignment, actual) + + def convert_group_ids_sourced_from_list(index_list, reference_data): + value_list = [] + for group_index in index_list: + value_list.append( + reference_data['groups'][group_index]['id']) + return value_list + + # Go through each test in the array, processing the input params, which + # we build into an args dict, and then call list_role_assignments. Then + # check the results against those specified in the test plan. + for test in test_plan.get('tests', []): + args = {} + for param in test['params']: + if param in ['effective', 'inherited', 'include_subtree']: + # Just pass the value into the args + args[param] = test['params'][param] + elif param == 'source_from_group_ids': + # Convert the list of indexes into a list of IDs + args[param] = convert_group_ids_sourced_from_list( + test['params']['source_from_group_ids'], test_data) + else: + # Turn 'entity : 0' into 'entity_id = ac6736ba873d' + # where entity in user, group, project or domain + key, value = self._convert_entity_shorthand( + param, test['params'], test_data) + args[key] = value + results = self.assignment_api.list_role_assignments(**args) + check_results(test['results'], results, len(args)) + + def execute_assignment_plan(self, test_plan): + """Create entities, assignments and execute the test plan. + + The standard method to call to create entities and assignments and + execute the tests as specified in the test_plan. The test_data + dict is returned so that, if required, the caller can execute + additional manual tests with the entities and assignments created. + + """ + test_data = self.create_entities(test_plan['entities']) + if 'implied_roles' in test_plan: + self.create_implied_roles(test_plan['implied_roles'], test_data) + if 'group_memberships' in test_plan: + self.create_group_memberships(test_plan['group_memberships'], + test_data) + if 'assignments' in test_plan: + test_data = self.create_assignments(test_plan['assignments'], + test_data) + self.execute_assignment_cases(test_plan, test_data) + return test_data + + +class AssignmentTests(AssignmentTestHelperMixin): + + def _get_domain_fixture(self): + domain = unit.new_domain_ref() + self.resource_api.create_domain(domain['id'], domain) + return domain + + def test_project_add_and_remove_user_role(self): + user_ids = self.assignment_api.list_user_ids_for_project( + self.tenant_bar['id']) + self.assertNotIn(self.user_two['id'], user_ids) + + self.assignment_api.add_role_to_user_and_project( + tenant_id=self.tenant_bar['id'], + user_id=self.user_two['id'], + role_id=self.role_other['id']) + user_ids = self.assignment_api.list_user_ids_for_project( + self.tenant_bar['id']) + self.assertIn(self.user_two['id'], user_ids) + + self.assignment_api.remove_role_from_user_and_project( + tenant_id=self.tenant_bar['id'], + user_id=self.user_two['id'], + role_id=self.role_other['id']) + + user_ids = self.assignment_api.list_user_ids_for_project( + self.tenant_bar['id']) + self.assertNotIn(self.user_two['id'], user_ids) + + def test_remove_user_role_not_assigned(self): + # Expect failure if attempt to remove a role that was never assigned to + # the user. + self.assertRaises(exception.RoleNotFound, + self.assignment_api. + remove_role_from_user_and_project, + tenant_id=self.tenant_bar['id'], + user_id=self.user_two['id'], + role_id=self.role_other['id']) + + def test_list_user_ids_for_project(self): + user_ids = self.assignment_api.list_user_ids_for_project( + self.tenant_baz['id']) + self.assertEqual(2, len(user_ids)) + self.assertIn(self.user_two['id'], user_ids) + self.assertIn(self.user_badguy['id'], user_ids) + + def test_list_user_ids_for_project_no_duplicates(self): + # Create user + user_ref = unit.new_user_ref(domain_id=CONF.identity.default_domain_id) + user_ref = self.identity_api.create_user(user_ref) + # Create project + project_ref = unit.new_project_ref( + domain_id=CONF.identity.default_domain_id) + self.resource_api.create_project( + project_ref['id'], project_ref) + # Create 2 roles and give user each role in project + for i in range(2): + role_ref = unit.new_role_ref() + self.role_api.create_role(role_ref['id'], role_ref) + self.assignment_api.add_role_to_user_and_project( + user_id=user_ref['id'], + tenant_id=project_ref['id'], + role_id=role_ref['id']) + # Get the list of user_ids in project + user_ids = self.assignment_api.list_user_ids_for_project( + project_ref['id']) + # Ensure the user is only returned once + self.assertEqual(1, len(user_ids)) + + def test_get_project_user_ids_returns_not_found(self): + self.assertRaises(exception.ProjectNotFound, + self.assignment_api.list_user_ids_for_project, + uuid.uuid4().hex) + + def test_list_role_assignments_unfiltered(self): + """Test unfiltered listing of role assignments.""" + test_plan = { + # Create a domain, with a user, group & project + 'entities': {'domains': {'users': 1, 'groups': 1, 'projects': 1}, + 'roles': 3}, + # Create a grant of each type (user/group on project/domain) + 'assignments': [{'user': 0, 'role': 0, 'domain': 0}, + {'user': 0, 'role': 1, 'project': 0}, + {'group': 0, 'role': 2, 'domain': 0}, + {'group': 0, 'role': 2, 'project': 0}], + 'tests': [ + # Check that we get back the 4 assignments + {'params': {}, + 'results': [{'user': 0, 'role': 0, 'domain': 0}, + {'user': 0, 'role': 1, 'project': 0}, + {'group': 0, 'role': 2, 'domain': 0}, + {'group': 0, 'role': 2, 'project': 0}]} + ] + } + self.execute_assignment_plan(test_plan) + + def test_list_role_assignments_filtered_by_role(self): + """Test listing of role assignments filtered by role ID.""" + test_plan = { + # Create a user, group & project in the default domain + 'entities': {'domains': {'id': CONF.identity.default_domain_id, + 'users': 1, 'groups': 1, 'projects': 1}, + 'roles': 3}, + # Create a grant of each type (user/group on project/domain) + 'assignments': [{'user': 0, 'role': 0, 'domain': 0}, + {'user': 0, 'role': 1, 'project': 0}, + {'group': 0, 'role': 2, 'domain': 0}, + {'group': 0, 'role': 2, 'project': 0}], + 'tests': [ + # Check that when filtering by role, we only get back those + # that match + {'params': {'role': 2}, + 'results': [{'group': 0, 'role': 2, 'domain': 0}, + {'group': 0, 'role': 2, 'project': 0}]} + ] + } + self.execute_assignment_plan(test_plan) + + def test_list_group_role_assignment(self): + # When a group role assignment is created and the role assignments are + # listed then the group role assignment is included in the list. + + test_plan = { + 'entities': {'domains': {'id': CONF.identity.default_domain_id, + 'groups': 1, 'projects': 1}, + 'roles': 1}, + 'assignments': [{'group': 0, 'role': 0, 'project': 0}], + 'tests': [ + {'params': {}, + 'results': [{'group': 0, 'role': 0, 'project': 0}]} + ] + } + self.execute_assignment_plan(test_plan) + + def test_list_role_assignments_bad_role(self): + assignment_list = self.assignment_api.list_role_assignments( + role_id=uuid.uuid4().hex) + self.assertEqual([], assignment_list) + + def test_add_duplicate_role_grant(self): + roles_ref = self.assignment_api.get_roles_for_user_and_project( + self.user_foo['id'], self.tenant_bar['id']) + self.assertNotIn(self.role_admin['id'], roles_ref) + self.assignment_api.add_role_to_user_and_project( + self.user_foo['id'], self.tenant_bar['id'], self.role_admin['id']) + self.assertRaises(exception.Conflict, + self.assignment_api.add_role_to_user_and_project, + self.user_foo['id'], + self.tenant_bar['id'], + self.role_admin['id']) + + def test_get_role_by_user_and_project_with_user_in_group(self): + """Test for get role by user and project, user was added into a group. + + Test Plan: + + - Create a user, a project & a group, add this user to group + - Create roles and grant them to user and project + - Check the role list get by the user and project was as expected + + """ + user_ref = unit.new_user_ref(domain_id=CONF.identity.default_domain_id) + user_ref = self.identity_api.create_user(user_ref) + + project_ref = unit.new_project_ref( + domain_id=CONF.identity.default_domain_id) + self.resource_api.create_project(project_ref['id'], project_ref) + + group = unit.new_group_ref(domain_id=CONF.identity.default_domain_id) + group_id = self.identity_api.create_group(group)['id'] + self.identity_api.add_user_to_group(user_ref['id'], group_id) + + role_ref_list = [] + for i in range(2): + role_ref = unit.new_role_ref() + self.role_api.create_role(role_ref['id'], role_ref) + role_ref_list.append(role_ref) + + self.assignment_api.add_role_to_user_and_project( + user_id=user_ref['id'], + tenant_id=project_ref['id'], + role_id=role_ref['id']) + + role_list = self.assignment_api.get_roles_for_user_and_project( + user_ref['id'], + project_ref['id']) + + self.assertEqual(set([r['id'] for r in role_ref_list]), + set(role_list)) + + def test_get_role_by_user_and_project(self): + roles_ref = self.assignment_api.get_roles_for_user_and_project( + self.user_foo['id'], self.tenant_bar['id']) + self.assertNotIn(self.role_admin['id'], roles_ref) + self.assignment_api.add_role_to_user_and_project( + self.user_foo['id'], self.tenant_bar['id'], self.role_admin['id']) + roles_ref = self.assignment_api.get_roles_for_user_and_project( + self.user_foo['id'], self.tenant_bar['id']) + self.assertIn(self.role_admin['id'], roles_ref) + self.assertNotIn('member', roles_ref) + + self.assignment_api.add_role_to_user_and_project( + self.user_foo['id'], self.tenant_bar['id'], 'member') + roles_ref = self.assignment_api.get_roles_for_user_and_project( + self.user_foo['id'], self.tenant_bar['id']) + self.assertIn(self.role_admin['id'], roles_ref) + self.assertIn('member', roles_ref) + + def test_get_roles_for_user_and_domain(self): + """Test for getting roles for user on a domain. + + Test Plan: + + - Create a domain, with 2 users + - Check no roles yet exit + - Give user1 two roles on the domain, user2 one role + - Get roles on user1 and the domain - maybe sure we only + get back the 2 roles on user1 + - Delete both roles from user1 + - Check we get no roles back for user1 on domain + + """ + new_domain = unit.new_domain_ref() + self.resource_api.create_domain(new_domain['id'], new_domain) + new_user1 = unit.new_user_ref(domain_id=new_domain['id']) + new_user1 = self.identity_api.create_user(new_user1) + new_user2 = unit.new_user_ref(domain_id=new_domain['id']) + new_user2 = self.identity_api.create_user(new_user2) + roles_ref = self.assignment_api.list_grants( + user_id=new_user1['id'], + domain_id=new_domain['id']) + self.assertEqual(0, len(roles_ref)) + # Now create the grants (roles are defined in default_fixtures) + self.assignment_api.create_grant(user_id=new_user1['id'], + domain_id=new_domain['id'], + role_id='member') + self.assignment_api.create_grant(user_id=new_user1['id'], + domain_id=new_domain['id'], + role_id='other') + self.assignment_api.create_grant(user_id=new_user2['id'], + domain_id=new_domain['id'], + role_id='admin') + # Read back the roles for user1 on domain + roles_ids = self.assignment_api.get_roles_for_user_and_domain( + new_user1['id'], new_domain['id']) + self.assertEqual(2, len(roles_ids)) + self.assertIn(self.role_member['id'], roles_ids) + self.assertIn(self.role_other['id'], roles_ids) + + # Now delete both grants for user1 + self.assignment_api.delete_grant(user_id=new_user1['id'], + domain_id=new_domain['id'], + role_id='member') + self.assignment_api.delete_grant(user_id=new_user1['id'], + domain_id=new_domain['id'], + role_id='other') + roles_ref = self.assignment_api.list_grants( + user_id=new_user1['id'], + domain_id=new_domain['id']) + self.assertEqual(0, len(roles_ref)) + + def test_get_roles_for_user_and_domain_returns_not_found(self): + """Test errors raised when getting roles for user on a domain. + + Test Plan: + + - Check non-existing user gives UserNotFound + - Check non-existing domain gives DomainNotFound + + """ + new_domain = self._get_domain_fixture() + new_user1 = unit.new_user_ref(domain_id=new_domain['id']) + new_user1 = self.identity_api.create_user(new_user1) + + self.assertRaises(exception.UserNotFound, + self.assignment_api.get_roles_for_user_and_domain, + uuid.uuid4().hex, + new_domain['id']) + + self.assertRaises(exception.DomainNotFound, + self.assignment_api.get_roles_for_user_and_domain, + new_user1['id'], + uuid.uuid4().hex) + + def test_get_roles_for_user_and_project_returns_not_found(self): + self.assertRaises(exception.UserNotFound, + self.assignment_api.get_roles_for_user_and_project, + uuid.uuid4().hex, + self.tenant_bar['id']) + + self.assertRaises(exception.ProjectNotFound, + self.assignment_api.get_roles_for_user_and_project, + self.user_foo['id'], + uuid.uuid4().hex) + + def test_add_role_to_user_and_project_returns_not_found(self): + self.assertRaises(exception.ProjectNotFound, + self.assignment_api.add_role_to_user_and_project, + self.user_foo['id'], + uuid.uuid4().hex, + self.role_admin['id']) + + self.assertRaises(exception.RoleNotFound, + self.assignment_api.add_role_to_user_and_project, + self.user_foo['id'], + self.tenant_bar['id'], + uuid.uuid4().hex) + + def test_add_role_to_user_and_project_no_user(self): + # If add_role_to_user_and_project and the user doesn't exist, then + # no error. + user_id_not_exist = uuid.uuid4().hex + self.assignment_api.add_role_to_user_and_project( + user_id_not_exist, self.tenant_bar['id'], self.role_admin['id']) + + def test_remove_role_from_user_and_project(self): + self.assignment_api.add_role_to_user_and_project( + self.user_foo['id'], self.tenant_bar['id'], 'member') + self.assignment_api.remove_role_from_user_and_project( + self.user_foo['id'], self.tenant_bar['id'], 'member') + roles_ref = self.assignment_api.get_roles_for_user_and_project( + self.user_foo['id'], self.tenant_bar['id']) + self.assertNotIn('member', roles_ref) + self.assertRaises(exception.NotFound, + self.assignment_api. + remove_role_from_user_and_project, + self.user_foo['id'], + self.tenant_bar['id'], + 'member') + + def test_get_role_grant_by_user_and_project(self): + roles_ref = self.assignment_api.list_grants( + user_id=self.user_foo['id'], + project_id=self.tenant_bar['id']) + self.assertEqual(1, len(roles_ref)) + self.assignment_api.create_grant(user_id=self.user_foo['id'], + project_id=self.tenant_bar['id'], + role_id=self.role_admin['id']) + roles_ref = self.assignment_api.list_grants( + user_id=self.user_foo['id'], + project_id=self.tenant_bar['id']) + self.assertIn(self.role_admin['id'], + [role_ref['id'] for role_ref in roles_ref]) + + self.assignment_api.create_grant(user_id=self.user_foo['id'], + project_id=self.tenant_bar['id'], + role_id='member') + roles_ref = self.assignment_api.list_grants( + user_id=self.user_foo['id'], + project_id=self.tenant_bar['id']) + + roles_ref_ids = [] + for ref in roles_ref: + roles_ref_ids.append(ref['id']) + self.assertIn(self.role_admin['id'], roles_ref_ids) + self.assertIn('member', roles_ref_ids) + + def test_remove_role_grant_from_user_and_project(self): + self.assignment_api.create_grant(user_id=self.user_foo['id'], + project_id=self.tenant_baz['id'], + role_id='member') + roles_ref = self.assignment_api.list_grants( + user_id=self.user_foo['id'], + project_id=self.tenant_baz['id']) + self.assertDictEqual(self.role_member, roles_ref[0]) + + self.assignment_api.delete_grant(user_id=self.user_foo['id'], + project_id=self.tenant_baz['id'], + role_id='member') + roles_ref = self.assignment_api.list_grants( + user_id=self.user_foo['id'], + project_id=self.tenant_baz['id']) + self.assertEqual(0, len(roles_ref)) + self.assertRaises(exception.RoleAssignmentNotFound, + self.assignment_api.delete_grant, + user_id=self.user_foo['id'], + project_id=self.tenant_baz['id'], + role_id='member') + + def test_get_role_assignment_by_project_not_found(self): + self.assertRaises(exception.RoleAssignmentNotFound, + self.assignment_api.check_grant_role_id, + user_id=self.user_foo['id'], + project_id=self.tenant_baz['id'], + role_id='member') + + self.assertRaises(exception.RoleAssignmentNotFound, + self.assignment_api.check_grant_role_id, + group_id=uuid.uuid4().hex, + project_id=self.tenant_baz['id'], + role_id='member') + + def test_get_role_assignment_by_domain_not_found(self): + self.assertRaises(exception.RoleAssignmentNotFound, + self.assignment_api.check_grant_role_id, + user_id=self.user_foo['id'], + domain_id=self.domain_default['id'], + role_id='member') + + self.assertRaises(exception.RoleAssignmentNotFound, + self.assignment_api.check_grant_role_id, + group_id=uuid.uuid4().hex, + domain_id=self.domain_default['id'], + role_id='member') + + def test_del_role_assignment_by_project_not_found(self): + self.assertRaises(exception.RoleAssignmentNotFound, + self.assignment_api.delete_grant, + user_id=self.user_foo['id'], + project_id=self.tenant_baz['id'], + role_id='member') + + self.assertRaises(exception.RoleAssignmentNotFound, + self.assignment_api.delete_grant, + group_id=uuid.uuid4().hex, + project_id=self.tenant_baz['id'], + role_id='member') + + def test_del_role_assignment_by_domain_not_found(self): + self.assertRaises(exception.RoleAssignmentNotFound, + self.assignment_api.delete_grant, + user_id=self.user_foo['id'], + domain_id=self.domain_default['id'], + role_id='member') + + self.assertRaises(exception.RoleAssignmentNotFound, + self.assignment_api.delete_grant, + group_id=uuid.uuid4().hex, + domain_id=self.domain_default['id'], + role_id='member') + + def test_get_and_remove_role_grant_by_group_and_project(self): + new_domain = unit.new_domain_ref() + self.resource_api.create_domain(new_domain['id'], new_domain) + new_group = unit.new_group_ref(domain_id=new_domain['id']) + new_group = self.identity_api.create_group(new_group) + new_user = unit.new_user_ref(domain_id=new_domain['id']) + new_user = self.identity_api.create_user(new_user) + self.identity_api.add_user_to_group(new_user['id'], + new_group['id']) + roles_ref = self.assignment_api.list_grants( + group_id=new_group['id'], + project_id=self.tenant_bar['id']) + self.assertEqual(0, len(roles_ref)) + self.assignment_api.create_grant(group_id=new_group['id'], + project_id=self.tenant_bar['id'], + role_id='member') + roles_ref = self.assignment_api.list_grants( + group_id=new_group['id'], + project_id=self.tenant_bar['id']) + self.assertDictEqual(self.role_member, roles_ref[0]) + + self.assignment_api.delete_grant(group_id=new_group['id'], + project_id=self.tenant_bar['id'], + role_id='member') + roles_ref = self.assignment_api.list_grants( + group_id=new_group['id'], + project_id=self.tenant_bar['id']) + self.assertEqual(0, len(roles_ref)) + self.assertRaises(exception.RoleAssignmentNotFound, + self.assignment_api.delete_grant, + group_id=new_group['id'], + project_id=self.tenant_bar['id'], + role_id='member') + + def test_get_and_remove_role_grant_by_group_and_domain(self): + new_domain = unit.new_domain_ref() + self.resource_api.create_domain(new_domain['id'], new_domain) + new_group = unit.new_group_ref(domain_id=new_domain['id']) + new_group = self.identity_api.create_group(new_group) + new_user = unit.new_user_ref(domain_id=new_domain['id']) + new_user = self.identity_api.create_user(new_user) + self.identity_api.add_user_to_group(new_user['id'], + new_group['id']) + + roles_ref = self.assignment_api.list_grants( + group_id=new_group['id'], + domain_id=new_domain['id']) + self.assertEqual(0, len(roles_ref)) + + self.assignment_api.create_grant(group_id=new_group['id'], + domain_id=new_domain['id'], + role_id='member') + + roles_ref = self.assignment_api.list_grants( + group_id=new_group['id'], + domain_id=new_domain['id']) + self.assertDictEqual(self.role_member, roles_ref[0]) + + self.assignment_api.delete_grant(group_id=new_group['id'], + domain_id=new_domain['id'], + role_id='member') + roles_ref = self.assignment_api.list_grants( + group_id=new_group['id'], + domain_id=new_domain['id']) + self.assertEqual(0, len(roles_ref)) + self.assertRaises(exception.RoleAssignmentNotFound, + self.assignment_api.delete_grant, + group_id=new_group['id'], + domain_id=new_domain['id'], + role_id='member') + + def test_get_and_remove_correct_role_grant_from_a_mix(self): + new_domain = unit.new_domain_ref() + self.resource_api.create_domain(new_domain['id'], new_domain) + new_project = unit.new_project_ref(domain_id=new_domain['id']) + self.resource_api.create_project(new_project['id'], new_project) + new_group = unit.new_group_ref(domain_id=new_domain['id']) + new_group = self.identity_api.create_group(new_group) + new_group2 = unit.new_group_ref(domain_id=new_domain['id']) + new_group2 = self.identity_api.create_group(new_group2) + new_user = unit.new_user_ref(domain_id=new_domain['id']) + new_user = self.identity_api.create_user(new_user) + new_user2 = unit.new_user_ref(domain_id=new_domain['id']) + new_user2 = self.identity_api.create_user(new_user2) + self.identity_api.add_user_to_group(new_user['id'], + new_group['id']) + # First check we have no grants + roles_ref = self.assignment_api.list_grants( + group_id=new_group['id'], + domain_id=new_domain['id']) + self.assertEqual(0, len(roles_ref)) + # Now add the grant we are going to test for, and some others as + # well just to make sure we get back the right one + self.assignment_api.create_grant(group_id=new_group['id'], + domain_id=new_domain['id'], + role_id='member') + + self.assignment_api.create_grant(group_id=new_group2['id'], + domain_id=new_domain['id'], + role_id=self.role_admin['id']) + self.assignment_api.create_grant(user_id=new_user2['id'], + domain_id=new_domain['id'], + role_id=self.role_admin['id']) + self.assignment_api.create_grant(group_id=new_group['id'], + project_id=new_project['id'], + role_id=self.role_admin['id']) + + roles_ref = self.assignment_api.list_grants( + group_id=new_group['id'], + domain_id=new_domain['id']) + self.assertDictEqual(self.role_member, roles_ref[0]) + + self.assignment_api.delete_grant(group_id=new_group['id'], + domain_id=new_domain['id'], + role_id='member') + roles_ref = self.assignment_api.list_grants( + group_id=new_group['id'], + domain_id=new_domain['id']) + self.assertEqual(0, len(roles_ref)) + self.assertRaises(exception.RoleAssignmentNotFound, + self.assignment_api.delete_grant, + group_id=new_group['id'], + domain_id=new_domain['id'], + role_id='member') + + def test_get_and_remove_role_grant_by_user_and_domain(self): + new_domain = unit.new_domain_ref() + self.resource_api.create_domain(new_domain['id'], new_domain) + new_user = unit.new_user_ref(domain_id=new_domain['id']) + new_user = self.identity_api.create_user(new_user) + roles_ref = self.assignment_api.list_grants( + user_id=new_user['id'], + domain_id=new_domain['id']) + self.assertEqual(0, len(roles_ref)) + self.assignment_api.create_grant(user_id=new_user['id'], + domain_id=new_domain['id'], + role_id='member') + roles_ref = self.assignment_api.list_grants( + user_id=new_user['id'], + domain_id=new_domain['id']) + self.assertDictEqual(self.role_member, roles_ref[0]) + + self.assignment_api.delete_grant(user_id=new_user['id'], + domain_id=new_domain['id'], + role_id='member') + roles_ref = self.assignment_api.list_grants( + user_id=new_user['id'], + domain_id=new_domain['id']) + self.assertEqual(0, len(roles_ref)) + self.assertRaises(exception.RoleAssignmentNotFound, + self.assignment_api.delete_grant, + user_id=new_user['id'], + domain_id=new_domain['id'], + role_id='member') + + def test_get_and_remove_role_grant_by_group_and_cross_domain(self): + group1_domain1_role = unit.new_role_ref() + self.role_api.create_role(group1_domain1_role['id'], + group1_domain1_role) + group1_domain2_role = unit.new_role_ref() + self.role_api.create_role(group1_domain2_role['id'], + group1_domain2_role) + domain1 = unit.new_domain_ref() + self.resource_api.create_domain(domain1['id'], domain1) + domain2 = unit.new_domain_ref() + self.resource_api.create_domain(domain2['id'], domain2) + group1 = unit.new_group_ref(domain_id=domain1['id']) + group1 = self.identity_api.create_group(group1) + roles_ref = self.assignment_api.list_grants( + group_id=group1['id'], + domain_id=domain1['id']) + self.assertEqual(0, len(roles_ref)) + roles_ref = self.assignment_api.list_grants( + group_id=group1['id'], + domain_id=domain2['id']) + self.assertEqual(0, len(roles_ref)) + self.assignment_api.create_grant(group_id=group1['id'], + domain_id=domain1['id'], + role_id=group1_domain1_role['id']) + self.assignment_api.create_grant(group_id=group1['id'], + domain_id=domain2['id'], + role_id=group1_domain2_role['id']) + roles_ref = self.assignment_api.list_grants( + group_id=group1['id'], + domain_id=domain1['id']) + self.assertDictEqual(group1_domain1_role, roles_ref[0]) + roles_ref = self.assignment_api.list_grants( + group_id=group1['id'], + domain_id=domain2['id']) + self.assertDictEqual(group1_domain2_role, roles_ref[0]) + + self.assignment_api.delete_grant(group_id=group1['id'], + domain_id=domain2['id'], + role_id=group1_domain2_role['id']) + roles_ref = self.assignment_api.list_grants( + group_id=group1['id'], + domain_id=domain2['id']) + self.assertEqual(0, len(roles_ref)) + self.assertRaises(exception.RoleAssignmentNotFound, + self.assignment_api.delete_grant, + group_id=group1['id'], + domain_id=domain2['id'], + role_id=group1_domain2_role['id']) + + def test_get_and_remove_role_grant_by_user_and_cross_domain(self): + user1_domain1_role = unit.new_role_ref() + self.role_api.create_role(user1_domain1_role['id'], user1_domain1_role) + user1_domain2_role = unit.new_role_ref() + self.role_api.create_role(user1_domain2_role['id'], user1_domain2_role) + domain1 = unit.new_domain_ref() + self.resource_api.create_domain(domain1['id'], domain1) + domain2 = unit.new_domain_ref() + self.resource_api.create_domain(domain2['id'], domain2) + user1 = unit.new_user_ref(domain_id=domain1['id']) + user1 = self.identity_api.create_user(user1) + roles_ref = self.assignment_api.list_grants( + user_id=user1['id'], + domain_id=domain1['id']) + self.assertEqual(0, len(roles_ref)) + roles_ref = self.assignment_api.list_grants( + user_id=user1['id'], + domain_id=domain2['id']) + self.assertEqual(0, len(roles_ref)) + self.assignment_api.create_grant(user_id=user1['id'], + domain_id=domain1['id'], + role_id=user1_domain1_role['id']) + self.assignment_api.create_grant(user_id=user1['id'], + domain_id=domain2['id'], + role_id=user1_domain2_role['id']) + roles_ref = self.assignment_api.list_grants( + user_id=user1['id'], + domain_id=domain1['id']) + self.assertDictEqual(user1_domain1_role, roles_ref[0]) + roles_ref = self.assignment_api.list_grants( + user_id=user1['id'], + domain_id=domain2['id']) + self.assertDictEqual(user1_domain2_role, roles_ref[0]) + + self.assignment_api.delete_grant(user_id=user1['id'], + domain_id=domain2['id'], + role_id=user1_domain2_role['id']) + roles_ref = self.assignment_api.list_grants( + user_id=user1['id'], + domain_id=domain2['id']) + self.assertEqual(0, len(roles_ref)) + self.assertRaises(exception.RoleAssignmentNotFound, + self.assignment_api.delete_grant, + user_id=user1['id'], + domain_id=domain2['id'], + role_id=user1_domain2_role['id']) + + def test_role_grant_by_group_and_cross_domain_project(self): + role1 = unit.new_role_ref() + self.role_api.create_role(role1['id'], role1) + role2 = unit.new_role_ref() + self.role_api.create_role(role2['id'], role2) + domain1 = unit.new_domain_ref() + self.resource_api.create_domain(domain1['id'], domain1) + domain2 = unit.new_domain_ref() + self.resource_api.create_domain(domain2['id'], domain2) + group1 = unit.new_group_ref(domain_id=domain1['id']) + group1 = self.identity_api.create_group(group1) + project1 = unit.new_project_ref(domain_id=domain2['id']) + self.resource_api.create_project(project1['id'], project1) + roles_ref = self.assignment_api.list_grants( + group_id=group1['id'], + project_id=project1['id']) + self.assertEqual(0, len(roles_ref)) + self.assignment_api.create_grant(group_id=group1['id'], + project_id=project1['id'], + role_id=role1['id']) + self.assignment_api.create_grant(group_id=group1['id'], + project_id=project1['id'], + role_id=role2['id']) + roles_ref = self.assignment_api.list_grants( + group_id=group1['id'], + project_id=project1['id']) + + roles_ref_ids = [] + for ref in roles_ref: + roles_ref_ids.append(ref['id']) + self.assertIn(role1['id'], roles_ref_ids) + self.assertIn(role2['id'], roles_ref_ids) + + self.assignment_api.delete_grant(group_id=group1['id'], + project_id=project1['id'], + role_id=role1['id']) + roles_ref = self.assignment_api.list_grants( + group_id=group1['id'], + project_id=project1['id']) + self.assertEqual(1, len(roles_ref)) + self.assertDictEqual(role2, roles_ref[0]) + + def test_role_grant_by_user_and_cross_domain_project(self): + role1 = unit.new_role_ref() + self.role_api.create_role(role1['id'], role1) + role2 = unit.new_role_ref() + self.role_api.create_role(role2['id'], role2) + domain1 = unit.new_domain_ref() + self.resource_api.create_domain(domain1['id'], domain1) + domain2 = unit.new_domain_ref() + self.resource_api.create_domain(domain2['id'], domain2) + user1 = unit.new_user_ref(domain_id=domain1['id']) + user1 = self.identity_api.create_user(user1) + project1 = unit.new_project_ref(domain_id=domain2['id']) + self.resource_api.create_project(project1['id'], project1) + roles_ref = self.assignment_api.list_grants( + user_id=user1['id'], + project_id=project1['id']) + self.assertEqual(0, len(roles_ref)) + self.assignment_api.create_grant(user_id=user1['id'], + project_id=project1['id'], + role_id=role1['id']) + self.assignment_api.create_grant(user_id=user1['id'], + project_id=project1['id'], + role_id=role2['id']) + roles_ref = self.assignment_api.list_grants( + user_id=user1['id'], + project_id=project1['id']) + + roles_ref_ids = [] + for ref in roles_ref: + roles_ref_ids.append(ref['id']) + self.assertIn(role1['id'], roles_ref_ids) + self.assertIn(role2['id'], roles_ref_ids) + + self.assignment_api.delete_grant(user_id=user1['id'], + project_id=project1['id'], + role_id=role1['id']) + roles_ref = self.assignment_api.list_grants( + user_id=user1['id'], + project_id=project1['id']) + self.assertEqual(1, len(roles_ref)) + self.assertDictEqual(role2, roles_ref[0]) + + def test_delete_user_grant_no_user(self): + # Can delete a grant where the user doesn't exist. + role = unit.new_role_ref() + role_id = role['id'] + self.role_api.create_role(role_id, role) + + user_id = uuid.uuid4().hex + + self.assignment_api.create_grant(role_id, user_id=user_id, + project_id=self.tenant_bar['id']) + + self.assignment_api.delete_grant(role_id, user_id=user_id, + project_id=self.tenant_bar['id']) + + def test_delete_group_grant_no_group(self): + # Can delete a grant where the group doesn't exist. + role = unit.new_role_ref() + role_id = role['id'] + self.role_api.create_role(role_id, role) + + group_id = uuid.uuid4().hex + + self.assignment_api.create_grant(role_id, group_id=group_id, + project_id=self.tenant_bar['id']) + + self.assignment_api.delete_grant(role_id, group_id=group_id, + project_id=self.tenant_bar['id']) + + def test_grant_crud_throws_exception_if_invalid_role(self): + """Ensure RoleNotFound thrown if role does not exist.""" + def assert_role_not_found_exception(f, **kwargs): + self.assertRaises(exception.RoleNotFound, f, + role_id=uuid.uuid4().hex, **kwargs) + + user = unit.new_user_ref(domain_id=CONF.identity.default_domain_id) + user_resp = self.identity_api.create_user(user) + group = unit.new_group_ref(domain_id=CONF.identity.default_domain_id) + group_resp = self.identity_api.create_group(group) + project = unit.new_project_ref( + domain_id=CONF.identity.default_domain_id) + project_resp = self.resource_api.create_project(project['id'], project) + + for manager_call in [self.assignment_api.create_grant, + self.assignment_api.get_grant, + self.assignment_api.delete_grant]: + assert_role_not_found_exception( + manager_call, + user_id=user_resp['id'], project_id=project_resp['id']) + assert_role_not_found_exception( + manager_call, + group_id=group_resp['id'], project_id=project_resp['id']) + assert_role_not_found_exception( + manager_call, + user_id=user_resp['id'], + domain_id=CONF.identity.default_domain_id) + assert_role_not_found_exception( + manager_call, + group_id=group_resp['id'], + domain_id=CONF.identity.default_domain_id) + + def test_multi_role_grant_by_user_group_on_project_domain(self): + role_list = [] + for _ in range(10): + role = unit.new_role_ref() + self.role_api.create_role(role['id'], role) + role_list.append(role) + domain1 = unit.new_domain_ref() + self.resource_api.create_domain(domain1['id'], domain1) + user1 = unit.new_user_ref(domain_id=domain1['id']) + user1 = self.identity_api.create_user(user1) + group1 = unit.new_group_ref(domain_id=domain1['id']) + group1 = self.identity_api.create_group(group1) + group2 = unit.new_group_ref(domain_id=domain1['id']) + group2 = self.identity_api.create_group(group2) + project1 = unit.new_project_ref(domain_id=domain1['id']) + self.resource_api.create_project(project1['id'], project1) + + self.identity_api.add_user_to_group(user1['id'], + group1['id']) + self.identity_api.add_user_to_group(user1['id'], + group2['id']) + + roles_ref = self.assignment_api.list_grants( + user_id=user1['id'], + project_id=project1['id']) + self.assertEqual(0, len(roles_ref)) + self.assignment_api.create_grant(user_id=user1['id'], + domain_id=domain1['id'], + role_id=role_list[0]['id']) + self.assignment_api.create_grant(user_id=user1['id'], + domain_id=domain1['id'], + role_id=role_list[1]['id']) + self.assignment_api.create_grant(group_id=group1['id'], + domain_id=domain1['id'], + role_id=role_list[2]['id']) + self.assignment_api.create_grant(group_id=group1['id'], + domain_id=domain1['id'], + role_id=role_list[3]['id']) + self.assignment_api.create_grant(user_id=user1['id'], + project_id=project1['id'], + role_id=role_list[4]['id']) + self.assignment_api.create_grant(user_id=user1['id'], + project_id=project1['id'], + role_id=role_list[5]['id']) + self.assignment_api.create_grant(group_id=group1['id'], + project_id=project1['id'], + role_id=role_list[6]['id']) + self.assignment_api.create_grant(group_id=group1['id'], + project_id=project1['id'], + role_id=role_list[7]['id']) + roles_ref = self.assignment_api.list_grants(user_id=user1['id'], + domain_id=domain1['id']) + self.assertEqual(2, len(roles_ref)) + self.assertIn(role_list[0], roles_ref) + self.assertIn(role_list[1], roles_ref) + roles_ref = self.assignment_api.list_grants(group_id=group1['id'], + domain_id=domain1['id']) + self.assertEqual(2, len(roles_ref)) + self.assertIn(role_list[2], roles_ref) + self.assertIn(role_list[3], roles_ref) + roles_ref = self.assignment_api.list_grants(user_id=user1['id'], + project_id=project1['id']) + self.assertEqual(2, len(roles_ref)) + self.assertIn(role_list[4], roles_ref) + self.assertIn(role_list[5], roles_ref) + roles_ref = self.assignment_api.list_grants(group_id=group1['id'], + project_id=project1['id']) + self.assertEqual(2, len(roles_ref)) + self.assertIn(role_list[6], roles_ref) + self.assertIn(role_list[7], roles_ref) + + # Now test the alternate way of getting back lists of grants, + # where user and group roles are combined. These should match + # the above results. + combined_list = self.assignment_api.get_roles_for_user_and_project( + user1['id'], project1['id']) + self.assertEqual(4, len(combined_list)) + self.assertIn(role_list[4]['id'], combined_list) + self.assertIn(role_list[5]['id'], combined_list) + self.assertIn(role_list[6]['id'], combined_list) + self.assertIn(role_list[7]['id'], combined_list) + + combined_role_list = self.assignment_api.get_roles_for_user_and_domain( + user1['id'], domain1['id']) + self.assertEqual(4, len(combined_role_list)) + self.assertIn(role_list[0]['id'], combined_role_list) + self.assertIn(role_list[1]['id'], combined_role_list) + self.assertIn(role_list[2]['id'], combined_role_list) + self.assertIn(role_list[3]['id'], combined_role_list) + + def test_multi_group_grants_on_project_domain(self): + """Test multiple group roles for user on project and domain. + + Test Plan: + + - Create 6 roles + - Create a domain, with a project, user and two groups + - Make the user a member of both groups + - Check no roles yet exit + - Assign a role to each user and both groups on both the + project and domain + - Get a list of effective roles for the user on both the + project and domain, checking we get back the correct three + roles + + """ + role_list = [] + for _ in range(6): + role = unit.new_role_ref() + self.role_api.create_role(role['id'], role) + role_list.append(role) + domain1 = unit.new_domain_ref() + self.resource_api.create_domain(domain1['id'], domain1) + user1 = unit.new_user_ref(domain_id=domain1['id']) + user1 = self.identity_api.create_user(user1) + group1 = unit.new_group_ref(domain_id=domain1['id']) + group1 = self.identity_api.create_group(group1) + group2 = unit.new_group_ref(domain_id=domain1['id']) + group2 = self.identity_api.create_group(group2) + project1 = unit.new_project_ref(domain_id=domain1['id']) + self.resource_api.create_project(project1['id'], project1) + + self.identity_api.add_user_to_group(user1['id'], + group1['id']) + self.identity_api.add_user_to_group(user1['id'], + group2['id']) + + roles_ref = self.assignment_api.list_grants( + user_id=user1['id'], + project_id=project1['id']) + self.assertEqual(0, len(roles_ref)) + self.assignment_api.create_grant(user_id=user1['id'], + domain_id=domain1['id'], + role_id=role_list[0]['id']) + self.assignment_api.create_grant(group_id=group1['id'], + domain_id=domain1['id'], + role_id=role_list[1]['id']) + self.assignment_api.create_grant(group_id=group2['id'], + domain_id=domain1['id'], + role_id=role_list[2]['id']) + self.assignment_api.create_grant(user_id=user1['id'], + project_id=project1['id'], + role_id=role_list[3]['id']) + self.assignment_api.create_grant(group_id=group1['id'], + project_id=project1['id'], + role_id=role_list[4]['id']) + self.assignment_api.create_grant(group_id=group2['id'], + project_id=project1['id'], + role_id=role_list[5]['id']) + + # Read by the roles, ensuring we get the correct 3 roles for + # both project and domain + combined_list = self.assignment_api.get_roles_for_user_and_project( + user1['id'], project1['id']) + self.assertEqual(3, len(combined_list)) + self.assertIn(role_list[3]['id'], combined_list) + self.assertIn(role_list[4]['id'], combined_list) + self.assertIn(role_list[5]['id'], combined_list) + + combined_role_list = self.assignment_api.get_roles_for_user_and_domain( + user1['id'], domain1['id']) + self.assertEqual(3, len(combined_role_list)) + self.assertIn(role_list[0]['id'], combined_role_list) + self.assertIn(role_list[1]['id'], combined_role_list) + self.assertIn(role_list[2]['id'], combined_role_list) + + def test_delete_role_with_user_and_group_grants(self): + role1 = unit.new_role_ref() + self.role_api.create_role(role1['id'], role1) + domain1 = unit.new_domain_ref() + self.resource_api.create_domain(domain1['id'], domain1) + project1 = unit.new_project_ref(domain_id=domain1['id']) + self.resource_api.create_project(project1['id'], project1) + user1 = unit.new_user_ref(domain_id=domain1['id']) + user1 = self.identity_api.create_user(user1) + group1 = unit.new_group_ref(domain_id=domain1['id']) + group1 = self.identity_api.create_group(group1) + self.assignment_api.create_grant(user_id=user1['id'], + project_id=project1['id'], + role_id=role1['id']) + self.assignment_api.create_grant(user_id=user1['id'], + domain_id=domain1['id'], + role_id=role1['id']) + self.assignment_api.create_grant(group_id=group1['id'], + project_id=project1['id'], + role_id=role1['id']) + self.assignment_api.create_grant(group_id=group1['id'], + domain_id=domain1['id'], + role_id=role1['id']) + roles_ref = self.assignment_api.list_grants( + user_id=user1['id'], + project_id=project1['id']) + self.assertEqual(1, len(roles_ref)) + roles_ref = self.assignment_api.list_grants( + group_id=group1['id'], + project_id=project1['id']) + self.assertEqual(1, len(roles_ref)) + roles_ref = self.assignment_api.list_grants( + user_id=user1['id'], + domain_id=domain1['id']) + self.assertEqual(1, len(roles_ref)) + roles_ref = self.assignment_api.list_grants( + group_id=group1['id'], + domain_id=domain1['id']) + self.assertEqual(1, len(roles_ref)) + self.role_api.delete_role(role1['id']) + roles_ref = self.assignment_api.list_grants( + user_id=user1['id'], + project_id=project1['id']) + self.assertEqual(0, len(roles_ref)) + roles_ref = self.assignment_api.list_grants( + group_id=group1['id'], + project_id=project1['id']) + self.assertEqual(0, len(roles_ref)) + roles_ref = self.assignment_api.list_grants( + user_id=user1['id'], + domain_id=domain1['id']) + self.assertEqual(0, len(roles_ref)) + roles_ref = self.assignment_api.list_grants( + group_id=group1['id'], + domain_id=domain1['id']) + self.assertEqual(0, len(roles_ref)) + + def test_list_role_assignment_by_domain(self): + """Test listing of role assignment filtered by domain.""" + test_plan = { + # A domain with 3 users, 1 group, a spoiler domain and 2 roles. + 'entities': {'domains': [{'users': 3, 'groups': 1}, 1], + 'roles': 2}, + # Users 1 & 2 are in the group + 'group_memberships': [{'group': 0, 'users': [1, 2]}], + # Assign a role for user 0 and the group + 'assignments': [{'user': 0, 'role': 0, 'domain': 0}, + {'group': 0, 'role': 1, 'domain': 0}], + 'tests': [ + # List all effective assignments for domain[0]. + # Should get one direct user role and user roles for each of + # the users in the group. + {'params': {'domain': 0, 'effective': True}, + 'results': [{'user': 0, 'role': 0, 'domain': 0}, + {'user': 1, 'role': 1, 'domain': 0, + 'indirect': {'group': 0}}, + {'user': 2, 'role': 1, 'domain': 0, + 'indirect': {'group': 0}} + ]}, + # Using domain[1] should return nothing + {'params': {'domain': 1, 'effective': True}, + 'results': []}, + ] + } + self.execute_assignment_plan(test_plan) + + def test_list_role_assignment_by_user_with_domain_group_roles(self): + """Test listing assignments by user, with group roles on a domain.""" + test_plan = { + # A domain with 3 users, 3 groups, a spoiler domain + # plus 3 roles. + 'entities': {'domains': [{'users': 3, 'groups': 3}, 1], + 'roles': 3}, + # Users 1 & 2 are in the group 0, User 1 also in group 1 + 'group_memberships': [{'group': 0, 'users': [0, 1]}, + {'group': 1, 'users': [0]}], + 'assignments': [{'user': 0, 'role': 0, 'domain': 0}, + {'group': 0, 'role': 1, 'domain': 0}, + {'group': 1, 'role': 2, 'domain': 0}, + # ...and two spoiler assignments + {'user': 1, 'role': 1, 'domain': 0}, + {'group': 2, 'role': 2, 'domain': 0}], + 'tests': [ + # List all effective assignments for user[0]. + # Should get one direct user role and a user roles for each of + # groups 0 and 1 + {'params': {'user': 0, 'effective': True}, + 'results': [{'user': 0, 'role': 0, 'domain': 0}, + {'user': 0, 'role': 1, 'domain': 0, + 'indirect': {'group': 0}}, + {'user': 0, 'role': 2, 'domain': 0, + 'indirect': {'group': 1}} + ]}, + # Adding domain[0] as a filter should return the same data + {'params': {'user': 0, 'domain': 0, 'effective': True}, + 'results': [{'user': 0, 'role': 0, 'domain': 0}, + {'user': 0, 'role': 1, 'domain': 0, + 'indirect': {'group': 0}}, + {'user': 0, 'role': 2, 'domain': 0, + 'indirect': {'group': 1}} + ]}, + # Using domain[1] should return nothing + {'params': {'user': 0, 'domain': 1, 'effective': True}, + 'results': []}, + # Using user[2] should return nothing + {'params': {'user': 2, 'domain': 0, 'effective': True}, + 'results': []}, + ] + } + self.execute_assignment_plan(test_plan) + + def test_list_role_assignment_using_sourced_groups(self): + """Test listing assignments when restricted by source groups.""" + test_plan = { + # The default domain with 3 users, 3 groups, 3 projects, + # plus 3 roles. + 'entities': {'domains': {'id': CONF.identity.default_domain_id, + 'users': 3, 'groups': 3, 'projects': 3}, + 'roles': 3}, + # Users 0 & 1 are in the group 0, User 0 also in group 1 + 'group_memberships': [{'group': 0, 'users': [0, 1]}, + {'group': 1, 'users': [0]}], + # Spread the assignments around - we want to be able to show that + # if sourced by group, assignments from other sources are excluded + 'assignments': [{'user': 0, 'role': 0, 'project': 0}, + {'group': 0, 'role': 1, 'project': 1}, + {'group': 1, 'role': 2, 'project': 0}, + {'group': 1, 'role': 2, 'project': 1}, + {'user': 2, 'role': 1, 'project': 1}, + {'group': 2, 'role': 2, 'project': 2} + ], + 'tests': [ + # List all effective assignments sourced from groups 0 and 1 + {'params': {'source_from_group_ids': [0, 1], + 'effective': True}, + 'results': [{'group': 0, 'role': 1, 'project': 1}, + {'group': 1, 'role': 2, 'project': 0}, + {'group': 1, 'role': 2, 'project': 1} + ]}, + # Adding a role a filter should further restrict the entries + {'params': {'source_from_group_ids': [0, 1], 'role': 2, + 'effective': True}, + 'results': [{'group': 1, 'role': 2, 'project': 0}, + {'group': 1, 'role': 2, 'project': 1} + ]}, + ] + } + self.execute_assignment_plan(test_plan) + + def test_list_role_assignment_using_sourced_groups_with_domains(self): + """Test listing domain assignments when restricted by source groups.""" + test_plan = { + # A domain with 3 users, 3 groups, 3 projects, a second domain, + # plus 3 roles. + 'entities': {'domains': [{'users': 3, 'groups': 3, 'projects': 3}, + 1], + 'roles': 3}, + # Users 0 & 1 are in the group 0, User 0 also in group 1 + 'group_memberships': [{'group': 0, 'users': [0, 1]}, + {'group': 1, 'users': [0]}], + # Spread the assignments around - we want to be able to show that + # if sourced by group, assignments from other sources are excluded + 'assignments': [{'user': 0, 'role': 0, 'domain': 0}, + {'group': 0, 'role': 1, 'domain': 1}, + {'group': 1, 'role': 2, 'project': 0}, + {'group': 1, 'role': 2, 'project': 1}, + {'user': 2, 'role': 1, 'project': 1}, + {'group': 2, 'role': 2, 'project': 2} + ], + 'tests': [ + # List all effective assignments sourced from groups 0 and 1 + {'params': {'source_from_group_ids': [0, 1], + 'effective': True}, + 'results': [{'group': 0, 'role': 1, 'domain': 1}, + {'group': 1, 'role': 2, 'project': 0}, + {'group': 1, 'role': 2, 'project': 1} + ]}, + # Adding a role a filter should further restrict the entries + {'params': {'source_from_group_ids': [0, 1], 'role': 1, + 'effective': True}, + 'results': [{'group': 0, 'role': 1, 'domain': 1}, + ]}, + ] + } + self.execute_assignment_plan(test_plan) + + def test_list_role_assignment_fails_with_userid_and_source_groups(self): + """Show we trap this unsupported internal combination of params.""" + group = unit.new_group_ref(domain_id=CONF.identity.default_domain_id) + group = self.identity_api.create_group(group) + self.assertRaises(exception.UnexpectedError, + self.assignment_api.list_role_assignments, + effective=True, + user_id=self.user_foo['id'], + source_from_group_ids=[group['id']]) + + def test_add_user_to_project(self): + self.assignment_api.add_user_to_project(self.tenant_baz['id'], + self.user_foo['id']) + 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.role_api.delete_role(CONF.member_role_id) + self.assertRaises(exception.RoleNotFound, + self.role_api.get_role, + CONF.member_role_id) + self.assignment_api.add_user_to_project(self.tenant_baz['id'], + self.user_foo['id']) + tenants = ( + self.assignment_api.list_projects_for_user(self.user_foo['id'])) + self.assertIn(self.tenant_baz, tenants) + default_role = self.role_api.get_role(CONF.member_role_id) + self.assertIsNotNone(default_role) + + def test_add_user_to_project_returns_not_found(self): + self.assertRaises(exception.ProjectNotFound, + self.assignment_api.add_user_to_project, + uuid.uuid4().hex, + self.user_foo['id']) + + def test_add_user_to_project_no_user(self): + # If add_user_to_project and the user doesn't exist, then + # no error. + user_id_not_exist = uuid.uuid4().hex + self.assignment_api.add_user_to_project(self.tenant_bar['id'], + user_id_not_exist) + + def test_remove_user_from_project(self): + self.assignment_api.add_user_to_project(self.tenant_baz['id'], + self.user_foo['id']) + self.assignment_api.remove_user_from_project(self.tenant_baz['id'], + self.user_foo['id']) + tenants = self.assignment_api.list_projects_for_user( + self.user_foo['id']) + self.assertNotIn(self.tenant_baz, tenants) + + def test_remove_user_from_project_race_delete_role(self): + self.assignment_api.add_user_to_project(self.tenant_baz['id'], + self.user_foo['id']) + self.assignment_api.add_role_to_user_and_project( + tenant_id=self.tenant_baz['id'], + user_id=self.user_foo['id'], + role_id=self.role_other['id']) + + # Mock a race condition, delete a role after + # get_roles_for_user_and_project() is called in + # remove_user_from_project(). + roles = self.assignment_api.get_roles_for_user_and_project( + self.user_foo['id'], self.tenant_baz['id']) + self.role_api.delete_role(self.role_other['id']) + self.assignment_api.get_roles_for_user_and_project = mock.Mock( + return_value=roles) + self.assignment_api.remove_user_from_project(self.tenant_baz['id'], + self.user_foo['id']) + tenants = self.assignment_api.list_projects_for_user( + self.user_foo['id']) + self.assertNotIn(self.tenant_baz, tenants) + + def test_remove_user_from_project_returns_not_found(self): + self.assertRaises(exception.ProjectNotFound, + self.assignment_api.remove_user_from_project, + uuid.uuid4().hex, + self.user_foo['id']) + + self.assertRaises(exception.UserNotFound, + self.assignment_api.remove_user_from_project, + self.tenant_bar['id'], + uuid.uuid4().hex) + + self.assertRaises(exception.NotFound, + self.assignment_api.remove_user_from_project, + self.tenant_baz['id'], + self.user_foo['id']) + + def test_list_user_project_ids_returns_not_found(self): + self.assertRaises(exception.UserNotFound, + self.assignment_api.list_projects_for_user, + uuid.uuid4().hex) + + def test_delete_user_with_project_association(self): + user = unit.new_user_ref(domain_id=CONF.identity.default_domain_id) + user = self.identity_api.create_user(user) + self.assignment_api.add_user_to_project(self.tenant_bar['id'], + user['id']) + self.identity_api.delete_user(user['id']) + self.assertRaises(exception.UserNotFound, + self.assignment_api.list_projects_for_user, + user['id']) + + def test_delete_user_with_project_roles(self): + user = unit.new_user_ref(domain_id=CONF.identity.default_domain_id) + user = self.identity_api.create_user(user) + self.assignment_api.add_role_to_user_and_project( + user['id'], + self.tenant_bar['id'], + self.role_member['id']) + self.identity_api.delete_user(user['id']) + self.assertRaises(exception.UserNotFound, + self.assignment_api.list_projects_for_user, + user['id']) + + def test_delete_role_returns_not_found(self): + self.assertRaises(exception.RoleNotFound, + self.role_api.delete_role, + uuid.uuid4().hex) + + def test_delete_project_with_role_assignments(self): + project = unit.new_project_ref( + domain_id=CONF.identity.default_domain_id) + self.resource_api.create_project(project['id'], project) + self.assignment_api.add_role_to_user_and_project( + self.user_foo['id'], project['id'], 'member') + self.resource_api.delete_project(project['id']) + # TODO(samueldmq): Check NotFound by calling list_user_ids_for_project, + # making this method consistent with the approach in the 2 tests above. + self.assertRaises(exception.NotFound, + self.resource_api.get_project, + project['id']) + + def test_delete_role_check_role_grant(self): + role = unit.new_role_ref() + alt_role = unit.new_role_ref() + self.role_api.create_role(role['id'], role) + self.role_api.create_role(alt_role['id'], alt_role) + self.assignment_api.add_role_to_user_and_project( + self.user_foo['id'], self.tenant_bar['id'], role['id']) + self.assignment_api.add_role_to_user_and_project( + self.user_foo['id'], self.tenant_bar['id'], alt_role['id']) + self.role_api.delete_role(role['id']) + roles_ref = self.assignment_api.get_roles_for_user_and_project( + self.user_foo['id'], self.tenant_bar['id']) + self.assertNotIn(role['id'], roles_ref) + self.assertIn(alt_role['id'], roles_ref) + + def test_list_projects_for_user(self): + domain = unit.new_domain_ref() + self.resource_api.create_domain(domain['id'], domain) + user1 = unit.new_user_ref(domain_id=domain['id']) + user1 = self.identity_api.create_user(user1) + user_projects = self.assignment_api.list_projects_for_user(user1['id']) + self.assertEqual(0, len(user_projects)) + self.assignment_api.create_grant(user_id=user1['id'], + project_id=self.tenant_bar['id'], + role_id=self.role_member['id']) + self.assignment_api.create_grant(user_id=user1['id'], + project_id=self.tenant_baz['id'], + role_id=self.role_member['id']) + user_projects = self.assignment_api.list_projects_for_user(user1['id']) + self.assertEqual(2, len(user_projects)) + + 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 = unit.new_domain_ref() + self.resource_api.create_domain(domain['id'], domain) + user1 = unit.new_user_ref(domain_id=domain['id']) + user1 = self.identity_api.create_user(user1) + group1 = unit.new_group_ref(domain_id=domain['id']) + group1 = self.identity_api.create_group(group1) + group2 = unit.new_group_ref(domain_id=domain['id']) + group2 = self.identity_api.create_group(group2) + project1 = unit.new_project_ref(domain_id=domain['id']) + self.resource_api.create_project(project1['id'], project1) + project2 = unit.new_project_ref(domain_id=domain['id']) + self.resource_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.assignment_api.create_grant(user_id=user1['id'], + project_id=self.tenant_bar['id'], + role_id=self.role_member['id']) + self.assignment_api.create_grant(group_id=group1['id'], + project_id=project1['id'], + role_id=self.role_admin['id']) + self.assignment_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.assertEqual(3, len(user_projects)) + + def test_create_grant_no_user(self): + # If call create_grant with a user that doesn't exist, doesn't fail. + self.assignment_api.create_grant( + self.role_other['id'], + user_id=uuid.uuid4().hex, + project_id=self.tenant_bar['id']) + + def test_create_grant_no_group(self): + # If call create_grant with a group that doesn't exist, doesn't fail. + self.assignment_api.create_grant( + self.role_other['id'], + group_id=uuid.uuid4().hex, + project_id=self.tenant_bar['id']) + + def test_delete_group_removes_role_assignments(self): + # When a group is deleted any role assignments for the group are + # removed. + + MEMBER_ROLE_ID = 'member' + + def get_member_assignments(): + assignments = self.assignment_api.list_role_assignments() + return [x for x in assignments if x['role_id'] == MEMBER_ROLE_ID] + + orig_member_assignments = get_member_assignments() + + # Create a group. + new_group = unit.new_group_ref( + domain_id=CONF.identity.default_domain_id) + new_group = self.identity_api.create_group(new_group) + + # Create a project. + new_project = unit.new_project_ref( + domain_id=CONF.identity.default_domain_id) + self.resource_api.create_project(new_project['id'], new_project) + + # Assign a role to the group. + self.assignment_api.create_grant( + group_id=new_group['id'], project_id=new_project['id'], + role_id=MEMBER_ROLE_ID) + + # Delete the group. + self.identity_api.delete_group(new_group['id']) + + # Check that the role assignment for the group is gone + member_assignments = get_member_assignments() + + self.assertThat(member_assignments, + matchers.Equals(orig_member_assignments)) + + def test_get_roles_for_groups_on_domain(self): + """Test retrieving group domain roles. + + Test Plan: + + - Create a domain, three groups and three roles + - Assign one an inherited and the others a non-inherited group role + to the domain + - Ensure that only the non-inherited roles are returned on the domain + + """ + domain1 = unit.new_domain_ref() + self.resource_api.create_domain(domain1['id'], domain1) + group_list = [] + group_id_list = [] + role_list = [] + for _ in range(3): + group = unit.new_group_ref(domain_id=domain1['id']) + group = self.identity_api.create_group(group) + group_list.append(group) + group_id_list.append(group['id']) + + role = unit.new_role_ref() + self.role_api.create_role(role['id'], role) + role_list.append(role) + + # Assign the roles - one is inherited + self.assignment_api.create_grant(group_id=group_list[0]['id'], + domain_id=domain1['id'], + role_id=role_list[0]['id']) + self.assignment_api.create_grant(group_id=group_list[1]['id'], + domain_id=domain1['id'], + role_id=role_list[1]['id']) + self.assignment_api.create_grant(group_id=group_list[2]['id'], + domain_id=domain1['id'], + role_id=role_list[2]['id'], + inherited_to_projects=True) + + # Now get the effective roles for the groups on the domain project. We + # shouldn't get back the inherited role. + + role_refs = self.assignment_api.get_roles_for_groups( + group_id_list, domain_id=domain1['id']) + + self.assertThat(role_refs, matchers.HasLength(2)) + self.assertIn(role_list[0], role_refs) + self.assertIn(role_list[1], role_refs) + + def test_get_roles_for_groups_on_project(self): + """Test retrieving group project roles. + + Test Plan: + + - Create two domains, two projects, six groups and six roles + - Project1 is in Domain1, Project2 is in Domain2 + - Domain2/Project2 are spoilers + - Assign a different direct group role to each project as well + as both an inherited and non-inherited role to each domain + - Get the group roles for Project 1 - depending on whether we have + enabled inheritance, we should either get back just the direct role + or both the direct one plus the inherited domain role from Domain 1 + + """ + domain1 = unit.new_domain_ref() + self.resource_api.create_domain(domain1['id'], domain1) + domain2 = unit.new_domain_ref() + self.resource_api.create_domain(domain2['id'], domain2) + project1 = unit.new_project_ref(domain_id=domain1['id']) + self.resource_api.create_project(project1['id'], project1) + project2 = unit.new_project_ref(domain_id=domain2['id']) + self.resource_api.create_project(project2['id'], project2) + group_list = [] + group_id_list = [] + role_list = [] + for _ in range(6): + group = unit.new_group_ref(domain_id=domain1['id']) + group = self.identity_api.create_group(group) + group_list.append(group) + group_id_list.append(group['id']) + + role = unit.new_role_ref() + self.role_api.create_role(role['id'], role) + role_list.append(role) + + # Assign the roles - one inherited and one non-inherited on Domain1, + # plus one on Project1 + self.assignment_api.create_grant(group_id=group_list[0]['id'], + domain_id=domain1['id'], + role_id=role_list[0]['id']) + self.assignment_api.create_grant(group_id=group_list[1]['id'], + domain_id=domain1['id'], + role_id=role_list[1]['id'], + inherited_to_projects=True) + self.assignment_api.create_grant(group_id=group_list[2]['id'], + project_id=project1['id'], + role_id=role_list[2]['id']) + + # ...and a duplicate set of spoiler assignments to Domain2/Project2 + self.assignment_api.create_grant(group_id=group_list[3]['id'], + domain_id=domain2['id'], + role_id=role_list[3]['id']) + self.assignment_api.create_grant(group_id=group_list[4]['id'], + domain_id=domain2['id'], + role_id=role_list[4]['id'], + inherited_to_projects=True) + self.assignment_api.create_grant(group_id=group_list[5]['id'], + project_id=project2['id'], + role_id=role_list[5]['id']) + + # Now get the effective roles for all groups on the Project1. With + # inheritance off, we should only get back the direct role. + + self.config_fixture.config(group='os_inherit', enabled=False) + role_refs = self.assignment_api.get_roles_for_groups( + group_id_list, project_id=project1['id']) + + self.assertThat(role_refs, matchers.HasLength(1)) + self.assertIn(role_list[2], role_refs) + + # With inheritance on, we should also get back the inherited role from + # its owning domain. + + self.config_fixture.config(group='os_inherit', enabled=True) + role_refs = self.assignment_api.get_roles_for_groups( + group_id_list, project_id=project1['id']) + + self.assertThat(role_refs, matchers.HasLength(2)) + self.assertIn(role_list[1], role_refs) + self.assertIn(role_list[2], role_refs) + + def test_list_domains_for_groups(self): + """Test retrieving domains for a list of groups. + + Test Plan: + + - Create three domains, three groups and one role + - Assign a non-inherited group role to two domains, and an inherited + group role to the third + - Ensure only the domains with non-inherited roles are returned + + """ + domain_list = [] + group_list = [] + group_id_list = [] + for _ in range(3): + domain = unit.new_domain_ref() + self.resource_api.create_domain(domain['id'], domain) + domain_list.append(domain) + + group = unit.new_group_ref(domain_id=domain['id']) + group = self.identity_api.create_group(group) + group_list.append(group) + group_id_list.append(group['id']) + + role1 = unit.new_role_ref() + self.role_api.create_role(role1['id'], role1) + + # Assign the roles - one is inherited + self.assignment_api.create_grant(group_id=group_list[0]['id'], + domain_id=domain_list[0]['id'], + role_id=role1['id']) + self.assignment_api.create_grant(group_id=group_list[1]['id'], + domain_id=domain_list[1]['id'], + role_id=role1['id']) + self.assignment_api.create_grant(group_id=group_list[2]['id'], + domain_id=domain_list[2]['id'], + role_id=role1['id'], + inherited_to_projects=True) + + # Now list the domains that have roles for any of the 3 groups + # We shouldn't get back domain[2] since that had an inherited role. + + domain_refs = ( + self.assignment_api.list_domains_for_groups(group_id_list)) + + self.assertThat(domain_refs, matchers.HasLength(2)) + self.assertIn(domain_list[0], domain_refs) + self.assertIn(domain_list[1], domain_refs) + + def test_list_projects_for_groups(self): + """Test retrieving projects for a list of groups. + + Test Plan: + + - Create two domains, four projects, seven groups and seven roles + - Project1-3 are in Domain1, Project4 is in Domain2 + - Domain2/Project4 are spoilers + - Project1 and 2 have direct group roles, Project3 has no direct + roles but should inherit a group role from Domain1 + - Get the projects for the group roles that are assigned to Project1 + Project2 and the inherited one on Domain1. Depending on whether we + have enabled inheritance, we should either get back just the projects + with direct roles (Project 1 and 2) or also Project3 due to its + inherited role from Domain1. + + """ + domain1 = unit.new_domain_ref() + self.resource_api.create_domain(domain1['id'], domain1) + domain2 = unit.new_domain_ref() + self.resource_api.create_domain(domain2['id'], domain2) + project1 = unit.new_project_ref(domain_id=domain1['id']) + project1 = self.resource_api.create_project(project1['id'], project1) + project2 = unit.new_project_ref(domain_id=domain1['id']) + project2 = self.resource_api.create_project(project2['id'], project2) + project3 = unit.new_project_ref(domain_id=domain1['id']) + project3 = self.resource_api.create_project(project3['id'], project3) + project4 = unit.new_project_ref(domain_id=domain2['id']) + project4 = self.resource_api.create_project(project4['id'], project4) + group_list = [] + role_list = [] + for _ in range(7): + group = unit.new_group_ref(domain_id=domain1['id']) + group = self.identity_api.create_group(group) + group_list.append(group) + + role = unit.new_role_ref() + self.role_api.create_role(role['id'], role) + role_list.append(role) + + # Assign the roles - one inherited and one non-inherited on Domain1, + # plus one on Project1 and Project2 + self.assignment_api.create_grant(group_id=group_list[0]['id'], + domain_id=domain1['id'], + role_id=role_list[0]['id']) + self.assignment_api.create_grant(group_id=group_list[1]['id'], + domain_id=domain1['id'], + role_id=role_list[1]['id'], + inherited_to_projects=True) + self.assignment_api.create_grant(group_id=group_list[2]['id'], + project_id=project1['id'], + role_id=role_list[2]['id']) + self.assignment_api.create_grant(group_id=group_list[3]['id'], + project_id=project2['id'], + role_id=role_list[3]['id']) + + # ...and a few of spoiler assignments to Domain2/Project4 + self.assignment_api.create_grant(group_id=group_list[4]['id'], + domain_id=domain2['id'], + role_id=role_list[4]['id']) + self.assignment_api.create_grant(group_id=group_list[5]['id'], + domain_id=domain2['id'], + role_id=role_list[5]['id'], + inherited_to_projects=True) + self.assignment_api.create_grant(group_id=group_list[6]['id'], + project_id=project4['id'], + role_id=role_list[6]['id']) + + # Now get the projects for the groups that have roles on Project1, + # Project2 and the inherited role on Domain!. With inheritance off, + # we should only get back the projects with direct role. + + self.config_fixture.config(group='os_inherit', enabled=False) + group_id_list = [group_list[1]['id'], group_list[2]['id'], + group_list[3]['id']] + project_refs = ( + self.assignment_api.list_projects_for_groups(group_id_list)) + + self.assertThat(project_refs, matchers.HasLength(2)) + self.assertIn(project1, project_refs) + self.assertIn(project2, project_refs) + + # With inheritance on, we should also get back the Project3 due to the + # inherited role from its owning domain. + + self.config_fixture.config(group='os_inherit', enabled=True) + project_refs = ( + self.assignment_api.list_projects_for_groups(group_id_list)) + + self.assertThat(project_refs, matchers.HasLength(3)) + self.assertIn(project1, project_refs) + self.assertIn(project2, project_refs) + self.assertIn(project3, project_refs) + + def test_update_role_no_name(self): + # A user can update a role and not include the name. + + # description is picked just because it's not name. + self.role_api.update_role(self.role_member['id'], + {'description': uuid.uuid4().hex}) + # If the previous line didn't raise an exception then the test passes. + + def test_update_role_same_name(self): + # A user can update a role and set the name to be the same as it was. + + self.role_api.update_role(self.role_member['id'], + {'name': self.role_member['name']}) + # If the previous line didn't raise an exception then the test passes. + + def test_list_role_assignment_containing_names(self): + # Create Refs + new_role = unit.new_role_ref() + new_domain = self._get_domain_fixture() + new_user = unit.new_user_ref(domain_id=new_domain['id']) + new_project = unit.new_project_ref(domain_id=new_domain['id']) + new_group = unit.new_group_ref(domain_id=new_domain['id']) + # Create entities + new_role = self.role_api.create_role(new_role['id'], new_role) + new_user = self.identity_api.create_user(new_user) + new_group = self.identity_api.create_group(new_group) + self.resource_api.create_project(new_project['id'], new_project) + self.assignment_api.create_grant(user_id=new_user['id'], + project_id=new_project['id'], + role_id=new_role['id']) + self.assignment_api.create_grant(group_id=new_group['id'], + project_id=new_project['id'], + role_id=new_role['id']) + self.assignment_api.create_grant(domain_id=new_domain['id'], + user_id=new_user['id'], + role_id=new_role['id']) + # Get the created assignments with the include_names flag + _asgmt_prj = self.assignment_api.list_role_assignments( + user_id=new_user['id'], + project_id=new_project['id'], + include_names=True) + _asgmt_grp = self.assignment_api.list_role_assignments( + group_id=new_group['id'], + project_id=new_project['id'], + include_names=True) + _asgmt_dmn = self.assignment_api.list_role_assignments( + domain_id=new_domain['id'], + user_id=new_user['id'], + include_names=True) + # Make sure we can get back the correct number of assignments + self.assertThat(_asgmt_prj, matchers.HasLength(1)) + self.assertThat(_asgmt_grp, matchers.HasLength(1)) + self.assertThat(_asgmt_dmn, matchers.HasLength(1)) + # get the first assignment + first_asgmt_prj = _asgmt_prj[0] + first_asgmt_grp = _asgmt_grp[0] + first_asgmt_dmn = _asgmt_dmn[0] + # Assert the names are correct in the project response + self.assertEqual(new_project['name'], + first_asgmt_prj['project_name']) + self.assertEqual(new_project['domain_id'], + first_asgmt_prj['project_domain_id']) + self.assertEqual(new_user['name'], + first_asgmt_prj['user_name']) + self.assertEqual(new_user['domain_id'], + first_asgmt_prj['user_domain_id']) + self.assertEqual(new_role['name'], + first_asgmt_prj['role_name']) + # Assert the names are correct in the group response + self.assertEqual(new_group['name'], + first_asgmt_grp['group_name']) + self.assertEqual(new_group['domain_id'], + first_asgmt_grp['group_domain_id']) + self.assertEqual(new_project['name'], + first_asgmt_grp['project_name']) + self.assertEqual(new_project['domain_id'], + first_asgmt_grp['project_domain_id']) + self.assertEqual(new_role['name'], + first_asgmt_grp['role_name']) + # Assert the names are correct in the domain response + self.assertEqual(new_domain['name'], + first_asgmt_dmn['domain_name']) + self.assertEqual(new_user['name'], + first_asgmt_dmn['user_name']) + self.assertEqual(new_user['domain_id'], + first_asgmt_dmn['user_domain_id']) + self.assertEqual(new_role['name'], + first_asgmt_dmn['role_name']) + + def test_list_role_assignment_does_not_contain_names(self): + """Test names are not included with list role assignments. + + Scenario: + - names are NOT included by default + - names are NOT included when include_names=False + + """ + def assert_does_not_contain_names(assignment): + first_asgmt_prj = assignment[0] + self.assertNotIn('project_name', first_asgmt_prj) + self.assertNotIn('project_domain_id', first_asgmt_prj) + self.assertNotIn('user_name', first_asgmt_prj) + self.assertNotIn('user_domain_id', first_asgmt_prj) + self.assertNotIn('role_name', first_asgmt_prj) + + # Create Refs + new_role = unit.new_role_ref() + new_domain = self._get_domain_fixture() + new_user = unit.new_user_ref(domain_id=new_domain['id']) + new_project = unit.new_project_ref(domain_id=new_domain['id']) + # Create entities + new_role = self.role_api.create_role(new_role['id'], new_role) + new_user = self.identity_api.create_user(new_user) + self.resource_api.create_project(new_project['id'], new_project) + self.assignment_api.create_grant(user_id=new_user['id'], + project_id=new_project['id'], + role_id=new_role['id']) + # Get the created assignments with NO include_names flag + role_assign_without_names = self.assignment_api.list_role_assignments( + user_id=new_user['id'], + project_id=new_project['id']) + assert_does_not_contain_names(role_assign_without_names) + # Get the created assignments with include_names=False + role_assign_without_names = self.assignment_api.list_role_assignments( + user_id=new_user['id'], + project_id=new_project['id'], + include_names=False) + assert_does_not_contain_names(role_assign_without_names) + + def test_delete_user_assignments_user_same_id_as_group(self): + """Test deleting user assignments when user_id == group_id. + + In this scenario, only user assignments must be deleted (i.e. + USER_DOMAIN or USER_PROJECT). + + Test plan: + * Create a user and a group with the same ID; + * Create four roles and assign them to both user and group; + * Delete all user assignments; + * Group assignments must stay intact. + """ + # Create a common ID + common_id = uuid.uuid4().hex + # Create a project + project = unit.new_project_ref( + domain_id=CONF.identity.default_domain_id) + project = self.resource_api.create_project(project['id'], project) + # Create a user + user = unit.new_user_ref(id=common_id, + domain_id=CONF.identity.default_domain_id) + user = self.identity_api.driver.create_user(common_id, user) + self.assertEqual(common_id, user['id']) + # Create a group + group = unit.new_group_ref(id=common_id, + domain_id=CONF.identity.default_domain_id) + group = self.identity_api.driver.create_group(common_id, group) + self.assertEqual(common_id, group['id']) + # Create four roles + roles = [] + for _ in range(4): + role = unit.new_role_ref() + roles.append(self.role_api.create_role(role['id'], role)) + # Assign roles for user + self.assignment_api.driver.create_grant( + user_id=user['id'], domain_id=CONF.identity.default_domain_id, + role_id=roles[0]['id']) + self.assignment_api.driver.create_grant(user_id=user['id'], + project_id=project['id'], + role_id=roles[1]['id']) + # Assign roles for group + self.assignment_api.driver.create_grant( + group_id=group['id'], domain_id=CONF.identity.default_domain_id, + role_id=roles[2]['id']) + self.assignment_api.driver.create_grant(group_id=group['id'], + project_id=project['id'], + role_id=roles[3]['id']) + # Make sure they were assigned + user_assignments = self.assignment_api.list_role_assignments( + user_id=user['id']) + self.assertThat(user_assignments, matchers.HasLength(2)) + group_assignments = self.assignment_api.list_role_assignments( + group_id=group['id']) + self.assertThat(group_assignments, matchers.HasLength(2)) + # Delete user assignments + self.assignment_api.delete_user_assignments(user_id=user['id']) + # Assert only user assignments were deleted + user_assignments = self.assignment_api.list_role_assignments( + user_id=user['id']) + self.assertThat(user_assignments, matchers.HasLength(0)) + group_assignments = self.assignment_api.list_role_assignments( + group_id=group['id']) + self.assertThat(group_assignments, matchers.HasLength(2)) + # Make sure these remaining assignments are group-related + for assignment in group_assignments: + self.assertThat(assignment.keys(), matchers.Contains('group_id')) + + def test_delete_group_assignments_group_same_id_as_user(self): + """Test deleting group assignments when group_id == user_id. + + In this scenario, only group assignments must be deleted (i.e. + GROUP_DOMAIN or GROUP_PROJECT). + + Test plan: + * Create a group and a user with the same ID; + * Create four roles and assign them to both group and user; + * Delete all group assignments; + * User assignments must stay intact. + """ + # Create a common ID + common_id = uuid.uuid4().hex + # Create a project + project = unit.new_project_ref( + domain_id=CONF.identity.default_domain_id) + project = self.resource_api.create_project(project['id'], project) + # Create a user + user = unit.new_user_ref(id=common_id, + domain_id=CONF.identity.default_domain_id) + user = self.identity_api.driver.create_user(common_id, user) + self.assertEqual(common_id, user['id']) + # Create a group + group = unit.new_group_ref(id=common_id, + domain_id=CONF.identity.default_domain_id) + group = self.identity_api.driver.create_group(common_id, group) + self.assertEqual(common_id, group['id']) + # Create four roles + roles = [] + for _ in range(4): + role = unit.new_role_ref() + roles.append(self.role_api.create_role(role['id'], role)) + # Assign roles for user + self.assignment_api.driver.create_grant( + user_id=user['id'], domain_id=CONF.identity.default_domain_id, + role_id=roles[0]['id']) + self.assignment_api.driver.create_grant(user_id=user['id'], + project_id=project['id'], + role_id=roles[1]['id']) + # Assign roles for group + self.assignment_api.driver.create_grant( + group_id=group['id'], domain_id=CONF.identity.default_domain_id, + role_id=roles[2]['id']) + self.assignment_api.driver.create_grant(group_id=group['id'], + project_id=project['id'], + role_id=roles[3]['id']) + # Make sure they were assigned + user_assignments = self.assignment_api.list_role_assignments( + user_id=user['id']) + self.assertThat(user_assignments, matchers.HasLength(2)) + group_assignments = self.assignment_api.list_role_assignments( + group_id=group['id']) + self.assertThat(group_assignments, matchers.HasLength(2)) + # Delete group assignments + self.assignment_api.delete_group_assignments(group_id=group['id']) + # Assert only group assignments were deleted + group_assignments = self.assignment_api.list_role_assignments( + group_id=group['id']) + self.assertThat(group_assignments, matchers.HasLength(0)) + user_assignments = self.assignment_api.list_role_assignments( + user_id=user['id']) + self.assertThat(user_assignments, matchers.HasLength(2)) + # Make sure these remaining assignments are user-related + for assignment in group_assignments: + self.assertThat(assignment.keys(), matchers.Contains('user_id')) + + +class InheritanceTests(AssignmentTestHelperMixin): + + def test_role_assignments_user_domain_to_project_inheritance(self): + test_plan = { + 'entities': {'domains': {'users': 2, 'projects': 1}, + 'roles': 3}, + 'assignments': [{'user': 0, 'role': 0, 'domain': 0}, + {'user': 0, 'role': 1, 'project': 0}, + {'user': 0, 'role': 2, 'domain': 0, + 'inherited_to_projects': True}, + {'user': 1, 'role': 1, 'project': 0}], + 'tests': [ + # List all direct assignments for user[0] + {'params': {'user': 0}, + 'results': [{'user': 0, 'role': 0, 'domain': 0}, + {'user': 0, 'role': 1, 'project': 0}, + {'user': 0, 'role': 2, 'domain': 0, + 'inherited_to_projects': 'projects'}]}, + # Now the effective ones - so the domain role should turn into + # a project role + {'params': {'user': 0, 'effective': True}, + 'results': [{'user': 0, 'role': 0, 'domain': 0}, + {'user': 0, 'role': 1, 'project': 0}, + {'user': 0, 'role': 2, 'project': 0, + 'indirect': {'domain': 0}}]}, + # Narrow down to effective roles for user[0] and project[0] + {'params': {'user': 0, 'project': 0, 'effective': True}, + 'results': [{'user': 0, 'role': 1, 'project': 0}, + {'user': 0, 'role': 2, 'project': 0, + 'indirect': {'domain': 0}}]} + ] + } + self.config_fixture.config(group='os_inherit', enabled=True) + self.execute_assignment_plan(test_plan) + + def test_inherited_role_assignments_excluded_if_os_inherit_false(self): + test_plan = { + 'entities': {'domains': {'users': 2, 'groups': 1, 'projects': 1}, + 'roles': 4}, + 'group_memberships': [{'group': 0, 'users': [0]}], + 'assignments': [{'user': 0, 'role': 0, 'domain': 0}, + {'user': 0, 'role': 1, 'project': 0}, + {'user': 0, 'role': 2, 'domain': 0, + 'inherited_to_projects': True}, + {'user': 1, 'role': 1, 'project': 0}, + {'group': 0, 'role': 3, 'project': 0}], + 'tests': [ + # List all direct assignments for user[0], since os-inherit is + # disabled, we should not see the inherited role + {'params': {'user': 0}, + 'results': [{'user': 0, 'role': 0, 'domain': 0}, + {'user': 0, 'role': 1, 'project': 0}]}, + # Same in effective mode - inherited roles should not be + # included or expanded...but the group role should now + # turn up as a user role, since group expansion is not + # part of os-inherit. + {'params': {'user': 0, 'effective': True}, + 'results': [{'user': 0, 'role': 0, 'domain': 0}, + {'user': 0, 'role': 1, 'project': 0}, + {'user': 0, 'role': 3, 'project': 0, + 'indirect': {'group': 0}}]}, + ] + } + self.config_fixture.config(group='os_inherit', enabled=False) + self.execute_assignment_plan(test_plan) + + def _test_crud_inherited_and_direct_assignment(self, **kwargs): + """Tests inherited and direct assignments for the actor and target + + Ensure it is possible to create both inherited and direct role + assignments for the same actor on the same target. The actor and the + target are specified in the kwargs as ('user_id' or 'group_id') and + ('project_id' or 'domain_id'), respectively. + + """ + self.config_fixture.config(group='os_inherit', enabled=True) + # Create a new role to avoid assignments loaded from default fixtures + role = unit.new_role_ref() + role = self.role_api.create_role(role['id'], role) + + # Define the common assignment entity + assignment_entity = {'role_id': role['id']} + assignment_entity.update(kwargs) + + # Define assignments under test + direct_assignment_entity = assignment_entity.copy() + inherited_assignment_entity = assignment_entity.copy() + inherited_assignment_entity['inherited_to_projects'] = 'projects' + + # Create direct assignment and check grants + self.assignment_api.create_grant(inherited_to_projects=False, + **assignment_entity) + + grants = self.assignment_api.list_role_assignments(role_id=role['id']) + self.assertThat(grants, matchers.HasLength(1)) + self.assertIn(direct_assignment_entity, grants) + + # Now add inherited assignment and check grants + self.assignment_api.create_grant(inherited_to_projects=True, + **assignment_entity) + + grants = self.assignment_api.list_role_assignments(role_id=role['id']) + self.assertThat(grants, matchers.HasLength(2)) + self.assertIn(direct_assignment_entity, grants) + self.assertIn(inherited_assignment_entity, grants) + + # Delete both and check grants + self.assignment_api.delete_grant(inherited_to_projects=False, + **assignment_entity) + self.assignment_api.delete_grant(inherited_to_projects=True, + **assignment_entity) + + grants = self.assignment_api.list_role_assignments(role_id=role['id']) + self.assertEqual([], grants) + + def test_crud_inherited_and_direct_assignment_for_user_on_domain(self): + self._test_crud_inherited_and_direct_assignment( + user_id=self.user_foo['id'], + domain_id=CONF.identity.default_domain_id) + + def test_crud_inherited_and_direct_assignment_for_group_on_domain(self): + group = unit.new_group_ref(domain_id=CONF.identity.default_domain_id) + group = self.identity_api.create_group(group) + + self._test_crud_inherited_and_direct_assignment( + group_id=group['id'], domain_id=CONF.identity.default_domain_id) + + def test_crud_inherited_and_direct_assignment_for_user_on_project(self): + self._test_crud_inherited_and_direct_assignment( + user_id=self.user_foo['id'], project_id=self.tenant_baz['id']) + + def test_crud_inherited_and_direct_assignment_for_group_on_project(self): + group = unit.new_group_ref(domain_id=CONF.identity.default_domain_id) + group = self.identity_api.create_group(group) + + self._test_crud_inherited_and_direct_assignment( + group_id=group['id'], project_id=self.tenant_baz['id']) + + def test_inherited_role_grants_for_user(self): + """Test inherited user roles. + + Test Plan: + + - Enable OS-INHERIT extension + - Create 3 roles + - Create a domain, with a project and a user + - Check no roles yet exit + - Assign a direct user role to the project and a (non-inherited) + user role to the domain + - Get a list of effective roles - should only get the one direct role + - Now add an inherited user role to the domain + - Get a list of effective roles - should have two roles, one + direct and one by virtue of the inherited user role + - Also get effective roles for the domain - the role marked as + inherited should not show up + + """ + self.config_fixture.config(group='os_inherit', enabled=True) + role_list = [] + for _ in range(3): + role = unit.new_role_ref() + self.role_api.create_role(role['id'], role) + role_list.append(role) + domain1 = unit.new_domain_ref() + self.resource_api.create_domain(domain1['id'], domain1) + user1 = unit.new_user_ref(domain_id=domain1['id']) + user1 = self.identity_api.create_user(user1) + project1 = unit.new_project_ref(domain_id=domain1['id']) + self.resource_api.create_project(project1['id'], project1) + + roles_ref = self.assignment_api.list_grants( + user_id=user1['id'], + project_id=project1['id']) + self.assertEqual(0, len(roles_ref)) + + # Create the first two roles - the domain one is not inherited + self.assignment_api.create_grant(user_id=user1['id'], + project_id=project1['id'], + role_id=role_list[0]['id']) + self.assignment_api.create_grant(user_id=user1['id'], + domain_id=domain1['id'], + role_id=role_list[1]['id']) + + # Now get the effective roles for the user and project, this + # should only include the direct role assignment on the project + combined_list = self.assignment_api.get_roles_for_user_and_project( + user1['id'], project1['id']) + self.assertEqual(1, len(combined_list)) + self.assertIn(role_list[0]['id'], combined_list) + + # Now add an inherited role on the domain + self.assignment_api.create_grant(user_id=user1['id'], + domain_id=domain1['id'], + role_id=role_list[2]['id'], + inherited_to_projects=True) + + # Now get the effective roles for the user and project again, this + # should now include the inherited role on the domain + combined_list = self.assignment_api.get_roles_for_user_and_project( + user1['id'], project1['id']) + self.assertEqual(2, len(combined_list)) + self.assertIn(role_list[0]['id'], combined_list) + self.assertIn(role_list[2]['id'], combined_list) + + # Finally, check that the inherited role does not appear as a valid + # directly assigned role on the domain itself + combined_role_list = self.assignment_api.get_roles_for_user_and_domain( + user1['id'], domain1['id']) + self.assertEqual(1, len(combined_role_list)) + self.assertIn(role_list[1]['id'], combined_role_list) + + # TODO(henry-nash): The test above uses get_roles_for_user_and_project + # and get_roles_for_user_and_domain, which will, in a subsequent patch, + # be re-implemented to simply call list_role_assignments (see blueprint + # remove-role-metadata). + # + # The test plan below therefore mirrors this test, to ensure that + # list_role_assignments works the same. Once get_roles_for_user_and + # project/domain have been re-implemented then the manual tests above + # can be refactored to simply ensure it gives the same answers. + test_plan = { + # A domain with a user & project, plus 3 roles. + 'entities': {'domains': {'users': 1, 'projects': 1}, + 'roles': 3}, + 'assignments': [{'user': 0, 'role': 0, 'project': 0}, + {'user': 0, 'role': 1, 'domain': 0}, + {'user': 0, 'role': 2, 'domain': 0, + 'inherited_to_projects': True}], + 'tests': [ + # List all effective assignments for user[0] on project[0]. + # Should get one direct role and one inherited role. + {'params': {'user': 0, 'project': 0, 'effective': True}, + 'results': [{'user': 0, 'role': 0, 'project': 0}, + {'user': 0, 'role': 2, 'project': 0, + 'indirect': {'domain': 0}}]}, + # Ensure effective mode on the domain does not list the + # inherited role on that domain + {'params': {'user': 0, 'domain': 0, 'effective': True}, + 'results': [{'user': 0, 'role': 1, 'domain': 0}]}, + # Ensure non-inherited mode also only returns the non-inherited + # role on the domain + {'params': {'user': 0, 'domain': 0, 'inherited': False}, + 'results': [{'user': 0, 'role': 1, 'domain': 0}]}, + ] + } + self.execute_assignment_plan(test_plan) + + def test_inherited_role_grants_for_group(self): + """Test inherited group roles. + + Test Plan: + + - Enable OS-INHERIT extension + - Create 4 roles + - Create a domain, with a project, user and two groups + - Make the user a member of both groups + - Check no roles yet exit + - Assign a direct user role to the project and a (non-inherited) + group role on the domain + - Get a list of effective roles - should only get the one direct role + - Now add two inherited group roles to the domain + - Get a list of effective roles - should have three roles, one + direct and two by virtue of inherited group roles + + """ + self.config_fixture.config(group='os_inherit', enabled=True) + role_list = [] + for _ in range(4): + role = unit.new_role_ref() + self.role_api.create_role(role['id'], role) + role_list.append(role) + domain1 = unit.new_domain_ref() + self.resource_api.create_domain(domain1['id'], domain1) + user1 = unit.new_user_ref(domain_id=domain1['id']) + user1 = self.identity_api.create_user(user1) + group1 = unit.new_group_ref(domain_id=domain1['id']) + group1 = self.identity_api.create_group(group1) + group2 = unit.new_group_ref(domain_id=domain1['id']) + group2 = self.identity_api.create_group(group2) + project1 = unit.new_project_ref(domain_id=domain1['id']) + self.resource_api.create_project(project1['id'], project1) + + self.identity_api.add_user_to_group(user1['id'], + group1['id']) + self.identity_api.add_user_to_group(user1['id'], + group2['id']) + + roles_ref = self.assignment_api.list_grants( + user_id=user1['id'], + project_id=project1['id']) + self.assertEqual(0, len(roles_ref)) + + # Create two roles - the domain one is not inherited + self.assignment_api.create_grant(user_id=user1['id'], + project_id=project1['id'], + role_id=role_list[0]['id']) + self.assignment_api.create_grant(group_id=group1['id'], + domain_id=domain1['id'], + role_id=role_list[1]['id']) + + # Now get the effective roles for the user and project, this + # should only include the direct role assignment on the project + combined_list = self.assignment_api.get_roles_for_user_and_project( + user1['id'], project1['id']) + self.assertEqual(1, len(combined_list)) + self.assertIn(role_list[0]['id'], combined_list) + + # Now add to more group roles, both inherited, to the domain + self.assignment_api.create_grant(group_id=group2['id'], + domain_id=domain1['id'], + role_id=role_list[2]['id'], + inherited_to_projects=True) + self.assignment_api.create_grant(group_id=group2['id'], + domain_id=domain1['id'], + role_id=role_list[3]['id'], + inherited_to_projects=True) + + # Now get the effective roles for the user and project again, this + # should now include the inherited roles on the domain + combined_list = self.assignment_api.get_roles_for_user_and_project( + user1['id'], project1['id']) + self.assertEqual(3, len(combined_list)) + self.assertIn(role_list[0]['id'], combined_list) + self.assertIn(role_list[2]['id'], combined_list) + self.assertIn(role_list[3]['id'], combined_list) + + # TODO(henry-nash): The test above uses get_roles_for_user_and_project + # which will, in a subsequent patch, be re-implemented to simply call + # list_role_assignments (see blueprint remove-role-metadata). + # + # The test plan below therefore mirrors this test, to ensure that + # list_role_assignments works the same. Once + # get_roles_for_user_and_project has been re-implemented then the + # manual tests above can be refactored to simply ensure it gives + # the same answers. + test_plan = { + # A domain with a user and project, 2 groups, plus 4 roles. + 'entities': {'domains': {'users': 1, 'projects': 1, 'groups': 2}, + 'roles': 4}, + 'group_memberships': [{'group': 0, 'users': [0]}, + {'group': 1, 'users': [0]}], + 'assignments': [{'user': 0, 'role': 0, 'project': 0}, + {'group': 0, 'role': 1, 'domain': 0}, + {'group': 1, 'role': 2, 'domain': 0, + 'inherited_to_projects': True}, + {'group': 1, 'role': 3, 'domain': 0, + 'inherited_to_projects': True}], + 'tests': [ + # List all effective assignments for user[0] on project[0]. + # Should get one direct role and both inherited roles, but + # not the direct one on domain[0], even though user[0] is + # in group[0]. + {'params': {'user': 0, 'project': 0, 'effective': True}, + 'results': [{'user': 0, 'role': 0, 'project': 0}, + {'user': 0, 'role': 2, 'project': 0, + 'indirect': {'domain': 0, 'group': 1}}, + {'user': 0, 'role': 3, 'project': 0, + 'indirect': {'domain': 0, 'group': 1}}]} + ] + } + self.execute_assignment_plan(test_plan) + + def test_list_projects_for_user_with_inherited_grants(self): + """Test inherited user 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.config_fixture.config(group='os_inherit', enabled=True) + domain = unit.new_domain_ref() + self.resource_api.create_domain(domain['id'], domain) + user1 = unit.new_user_ref(domain_id=domain['id']) + user1 = self.identity_api.create_user(user1) + project1 = unit.new_project_ref(domain_id=domain['id']) + self.resource_api.create_project(project1['id'], project1) + project2 = unit.new_project_ref(domain_id=domain['id']) + self.resource_api.create_project(project2['id'], project2) + + # Create 2 grants, one on a project and one inherited grant + # on the domain + self.assignment_api.create_grant(user_id=user1['id'], + project_id=self.tenant_bar['id'], + role_id=self.role_member['id']) + self.assignment_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.assertEqual(3, len(user_projects)) + + # TODO(henry-nash): The test above uses list_projects_for_user + # which may, in a subsequent patch, be re-implemented to call + # list_role_assignments and then report only the distinct projects. + # + # The test plan below therefore mirrors this test, to ensure that + # list_role_assignments works the same. Once list_projects_for_user + # has been re-implemented then the manual tests above can be + # refactored. + test_plan = { + # A domain with 1 project, plus a second domain with 2 projects, + # as well as a user. Also, create 2 roles. + 'entities': {'domains': [{'projects': 1}, + {'users': 1, 'projects': 2}], + 'roles': 2}, + 'assignments': [{'user': 0, 'role': 0, 'project': 0}, + {'user': 0, 'role': 1, 'domain': 1, + 'inherited_to_projects': True}], + 'tests': [ + # List all effective assignments for user[0] + # Should get one direct role plus one inherited role for each + # project in domain + {'params': {'user': 0, 'effective': True}, + 'results': [{'user': 0, 'role': 0, 'project': 0}, + {'user': 0, 'role': 1, 'project': 1, + 'indirect': {'domain': 1}}, + {'user': 0, 'role': 1, 'project': 2, + 'indirect': {'domain': 1}}]} + ] + } + self.execute_assignment_plan(test_plan) + + def test_list_projects_for_user_with_inherited_user_project_grants(self): + """Test inherited role assignments for users on nested projects. + + Test Plan: + + - Enable OS-INHERIT extension + - Create a hierarchy of projects with one root and one leaf project + - Assign an inherited user role on root project + - Assign a non-inherited user role on root project + - Get a list of projects for user, should return both projects + - Disable OS-INHERIT extension + - Get a list of projects for user, should return only root project + + """ + # Enable OS-INHERIT extension + self.config_fixture.config(group='os_inherit', enabled=True) + root_project = unit.new_project_ref( + domain_id=CONF.identity.default_domain_id) + root_project = self.resource_api.create_project(root_project['id'], + root_project) + leaf_project = unit.new_project_ref( + domain_id=CONF.identity.default_domain_id, + parent_id=root_project['id']) + leaf_project = self.resource_api.create_project(leaf_project['id'], + leaf_project) + + user = unit.new_user_ref(domain_id=CONF.identity.default_domain_id) + user = self.identity_api.create_user(user) + + # Grant inherited user role + self.assignment_api.create_grant(user_id=user['id'], + project_id=root_project['id'], + role_id=self.role_admin['id'], + inherited_to_projects=True) + # Grant non-inherited user role + self.assignment_api.create_grant(user_id=user['id'], + project_id=root_project['id'], + role_id=self.role_member['id']) + # Should get back both projects: because the direct role assignment for + # the root project and inherited role assignment for leaf project + user_projects = self.assignment_api.list_projects_for_user(user['id']) + self.assertEqual(2, len(user_projects)) + self.assertIn(root_project, user_projects) + self.assertIn(leaf_project, user_projects) + + # Disable OS-INHERIT extension + self.config_fixture.config(group='os_inherit', enabled=False) + # Should get back just root project - due the direct role assignment + user_projects = self.assignment_api.list_projects_for_user(user['id']) + self.assertEqual(1, len(user_projects)) + self.assertIn(root_project, user_projects) + + # TODO(henry-nash): The test above uses list_projects_for_user + # which may, in a subsequent patch, be re-implemented to call + # list_role_assignments and then report only the distinct projects. + # + # The test plan below therefore mirrors this test, to ensure that + # list_role_assignments works the same. Once list_projects_for_user + # has been re-implemented then the manual tests above can be + # refactored. + test_plan = { + # A domain with a project and sub-project, plus a user. + # Also, create 2 roles. + 'entities': { + 'domains': {'id': CONF.identity.default_domain_id, 'users': 1, + 'projects': {'project': 1}}, + 'roles': 2}, + # A direct role and an inherited role on the parent + 'assignments': [{'user': 0, 'role': 0, 'project': 0}, + {'user': 0, 'role': 1, 'project': 0, + 'inherited_to_projects': True}], + 'tests': [ + # List all effective assignments for user[0] - should get back + # one direct role plus one inherited role. + {'params': {'user': 0, 'effective': True}, + 'results': [{'user': 0, 'role': 0, 'project': 0}, + {'user': 0, 'role': 1, 'project': 1, + 'indirect': {'project': 0}}]} + ] + } + + test_plan_with_os_inherit_disabled = { + 'tests': [ + # List all effective assignments for user[0] - should only get + # back the one direct role. + {'params': {'user': 0, 'effective': True}, + 'results': [{'user': 0, 'role': 0, 'project': 0}]} + ] + } + self.config_fixture.config(group='os_inherit', enabled=True) + test_data = self.execute_assignment_plan(test_plan) + self.config_fixture.config(group='os_inherit', enabled=False) + # Pass the existing test data in to allow execution of 2nd test plan + self.execute_assignment_cases( + test_plan_with_os_inherit_disabled, test_data) + + 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.config_fixture.config(group='os_inherit', enabled=True) + domain = unit.new_domain_ref() + self.resource_api.create_domain(domain['id'], domain) + domain2 = unit.new_domain_ref() + self.resource_api.create_domain(domain2['id'], domain2) + project1 = unit.new_project_ref(domain_id=domain['id']) + self.resource_api.create_project(project1['id'], project1) + project2 = unit.new_project_ref(domain_id=domain['id']) + self.resource_api.create_project(project2['id'], project2) + project3 = unit.new_project_ref(domain_id=domain2['id']) + self.resource_api.create_project(project3['id'], project3) + project4 = unit.new_project_ref(domain_id=domain2['id']) + self.resource_api.create_project(project4['id'], project4) + user1 = unit.new_user_ref(domain_id=domain['id']) + user1 = self.identity_api.create_user(user1) + group1 = unit.new_group_ref(domain_id=domain['id']) + group1 = self.identity_api.create_group(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.assignment_api.create_grant(user_id=user1['id'], + project_id=project3['id'], + role_id=self.role_member['id']) + self.assignment_api.create_grant(user_id=user1['id'], + project_id=self.tenant_bar['id'], + role_id=self.role_member['id']) + self.assignment_api.create_grant(user_id=user1['id'], + domain_id=domain['id'], + role_id=self.role_admin['id'], + inherited_to_projects=True) + self.assignment_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.assertEqual(5, len(user_projects)) + + # TODO(henry-nash): The test above uses list_projects_for_user + # which may, in a subsequent patch, be re-implemented to call + # list_role_assignments and then report only the distinct projects. + # + # The test plan below therefore mirrors this test, to ensure that + # list_role_assignments works the same. Once list_projects_for_user + # has been re-implemented then the manual tests above can be + # refactored. + test_plan = { + # A domain with a 1 project, plus a second domain with 2 projects, + # as well as a user & group and a 3rd domain with 2 projects. + # Also, created 2 roles. + 'entities': {'domains': [{'projects': 1}, + {'users': 1, 'groups': 1, 'projects': 2}, + {'projects': 2}], + 'roles': 2}, + 'group_memberships': [{'group': 0, 'users': [0]}], + 'assignments': [{'user': 0, 'role': 0, 'project': 0}, + {'user': 0, 'role': 0, 'project': 3}, + {'user': 0, 'role': 1, 'domain': 1, + 'inherited_to_projects': True}, + {'user': 0, 'role': 1, 'domain': 2, + 'inherited_to_projects': True}], + 'tests': [ + # List all effective assignments for user[0] + # Should get back both direct roles plus roles on both projects + # from each domain. Duplicates should not be filtered out. + {'params': {'user': 0, 'effective': True}, + 'results': [{'user': 0, 'role': 0, 'project': 3}, + {'user': 0, 'role': 0, 'project': 0}, + {'user': 0, 'role': 1, 'project': 1, + 'indirect': {'domain': 1}}, + {'user': 0, 'role': 1, 'project': 2, + 'indirect': {'domain': 1}}, + {'user': 0, 'role': 1, 'project': 3, + 'indirect': {'domain': 2}}, + {'user': 0, 'role': 1, 'project': 4, + 'indirect': {'domain': 2}}]} + ] + } + self.execute_assignment_plan(test_plan) + + def test_list_projects_for_user_with_inherited_group_project_grants(self): + """Test inherited role assignments for groups on nested projects. + + Test Plan: + + - Enable OS-INHERIT extension + - Create a hierarchy of projects with one root and one leaf project + - Assign an inherited group role on root project + - Assign a non-inherited group role on root project + - Get a list of projects for user, should return both projects + - Disable OS-INHERIT extension + - Get a list of projects for user, should return only root project + + """ + self.config_fixture.config(group='os_inherit', enabled=True) + root_project = unit.new_project_ref( + domain_id=CONF.identity.default_domain_id) + root_project = self.resource_api.create_project(root_project['id'], + root_project) + leaf_project = unit.new_project_ref( + domain_id=CONF.identity.default_domain_id, + parent_id=root_project['id']) + leaf_project = self.resource_api.create_project(leaf_project['id'], + leaf_project) + + user = unit.new_user_ref(domain_id=CONF.identity.default_domain_id) + user = self.identity_api.create_user(user) + + group = unit.new_group_ref(domain_id=CONF.identity.default_domain_id) + group = self.identity_api.create_group(group) + self.identity_api.add_user_to_group(user['id'], group['id']) + + # Grant inherited group role + self.assignment_api.create_grant(group_id=group['id'], + project_id=root_project['id'], + role_id=self.role_admin['id'], + inherited_to_projects=True) + # Grant non-inherited group role + self.assignment_api.create_grant(group_id=group['id'], + project_id=root_project['id'], + role_id=self.role_member['id']) + # Should get back both projects: because the direct role assignment for + # the root project and inherited role assignment for leaf project + user_projects = self.assignment_api.list_projects_for_user(user['id']) + self.assertEqual(2, len(user_projects)) + self.assertIn(root_project, user_projects) + self.assertIn(leaf_project, user_projects) + + # Disable OS-INHERIT extension + self.config_fixture.config(group='os_inherit', enabled=False) + # Should get back just root project - due the direct role assignment + user_projects = self.assignment_api.list_projects_for_user(user['id']) + self.assertEqual(1, len(user_projects)) + self.assertIn(root_project, user_projects) + + # TODO(henry-nash): The test above uses list_projects_for_user + # which may, in a subsequent patch, be re-implemented to call + # list_role_assignments and then report only the distinct projects. + # + # The test plan below therefore mirrors this test, to ensure that + # list_role_assignments works the same. Once list_projects_for_user + # has been re-implemented then the manual tests above can be + # refactored. + test_plan = { + # A domain with a project ans sub-project, plus a user. + # Also, create 2 roles. + 'entities': { + 'domains': {'id': CONF.identity.default_domain_id, 'users': 1, + 'groups': 1, + 'projects': {'project': 1}}, + 'roles': 2}, + 'group_memberships': [{'group': 0, 'users': [0]}], + # A direct role and an inherited role on the parent + 'assignments': [{'group': 0, 'role': 0, 'project': 0}, + {'group': 0, 'role': 1, 'project': 0, + 'inherited_to_projects': True}], + 'tests': [ + # List all effective assignments for user[0] - should get back + # one direct role plus one inherited role. + {'params': {'user': 0, 'effective': True}, + 'results': [{'user': 0, 'role': 0, 'project': 0, + 'indirect': {'group': 0}}, + {'user': 0, 'role': 1, 'project': 1, + 'indirect': {'group': 0, 'project': 0}}]} + ] + } + + test_plan_with_os_inherit_disabled = { + 'tests': [ + # List all effective assignments for user[0] - should only get + # back the one direct role. + {'params': {'user': 0, 'effective': True}, + 'results': [{'user': 0, 'role': 0, 'project': 0, + 'indirect': {'group': 0}}]} + ] + } + self.config_fixture.config(group='os_inherit', enabled=True) + test_data = self.execute_assignment_plan(test_plan) + self.config_fixture.config(group='os_inherit', enabled=False) + # Pass the existing test data in to allow execution of 2nd test plan + self.execute_assignment_cases( + test_plan_with_os_inherit_disabled, test_data) + + def test_list_assignments_for_tree(self): + """Test we correctly list direct assignments for a tree""" + # Enable OS-INHERIT extension + self.config_fixture.config(group='os_inherit', enabled=True) + + test_plan = { + # Create a domain with a project hierarchy 3 levels deep: + # + # project 0 + # ____________|____________ + # | | + # project 1 project 4 + # ______|_____ ______|_____ + # | | | | + # project 2 project 3 project 5 project 6 + # + # Also, create 1 user and 4 roles. + 'entities': { + 'domains': { + 'projects': {'project': [{'project': 2}, + {'project': 2}]}, + 'users': 1}, + 'roles': 4}, + 'assignments': [ + # Direct assignment to projects 1 and 2 + {'user': 0, 'role': 0, 'project': 1}, + {'user': 0, 'role': 1, 'project': 2}, + # Also an inherited assignment on project 1 + {'user': 0, 'role': 2, 'project': 1, + 'inherited_to_projects': True}, + # ...and two spoiler assignments, one to the root and one + # to project 4 + {'user': 0, 'role': 0, 'project': 0}, + {'user': 0, 'role': 3, 'project': 4}], + 'tests': [ + # List all assignments for project 1 and its subtree. + {'params': {'project': 1, 'include_subtree': True}, + 'results': [ + # Only the actual assignments should be returned, no + # expansion of inherited assignments + {'user': 0, 'role': 0, 'project': 1}, + {'user': 0, 'role': 1, 'project': 2}, + {'user': 0, 'role': 2, 'project': 1, + 'inherited_to_projects': 'projects'}]} + ] + } + + self.execute_assignment_plan(test_plan) + + def test_list_effective_assignments_for_tree(self): + """Test we correctly list effective assignments for a tree""" + # Enable OS-INHERIT extension + self.config_fixture.config(group='os_inherit', enabled=True) + + test_plan = { + # Create a domain with a project hierarchy 3 levels deep: + # + # project 0 + # ____________|____________ + # | | + # project 1 project 4 + # ______|_____ ______|_____ + # | | | | + # project 2 project 3 project 5 project 6 + # + # Also, create 1 user and 4 roles. + 'entities': { + 'domains': { + 'projects': {'project': [{'project': 2}, + {'project': 2}]}, + 'users': 1}, + 'roles': 4}, + 'assignments': [ + # An inherited assignment on project 1 + {'user': 0, 'role': 1, 'project': 1, + 'inherited_to_projects': True}, + # A direct assignment to project 2 + {'user': 0, 'role': 2, 'project': 2}, + # ...and two spoiler assignments, one to the root and one + # to project 4 + {'user': 0, 'role': 0, 'project': 0}, + {'user': 0, 'role': 3, 'project': 4}], + 'tests': [ + # List all effective assignments for project 1 and its subtree. + {'params': {'project': 1, 'effective': True, + 'include_subtree': True}, + 'results': [ + # The inherited assignment on project 1 should appear only + # on its children + {'user': 0, 'role': 1, 'project': 2, + 'indirect': {'project': 1}}, + {'user': 0, 'role': 1, 'project': 3, + 'indirect': {'project': 1}}, + # And finally the direct assignment on project 2 + {'user': 0, 'role': 2, 'project': 2}]} + ] + } + + self.execute_assignment_plan(test_plan) + + def test_list_effective_assignments_for_tree_with_mixed_assignments(self): + """Test that we correctly combine assignments for a tree. + + In this test we want to ensure that when asking for a list of + assignments in a subtree, any assignments inherited from above the + subtree are correctly combined with any assignments within the subtree + itself. + + """ + # Enable OS-INHERIT extension + self.config_fixture.config(group='os_inherit', enabled=True) + + test_plan = { + # Create a domain with a project hierarchy 3 levels deep: + # + # project 0 + # ____________|____________ + # | | + # project 1 project 4 + # ______|_____ ______|_____ + # | | | | + # project 2 project 3 project 5 project 6 + # + # Also, create 2 users, 1 group and 4 roles. + 'entities': { + 'domains': { + 'projects': {'project': [{'project': 2}, + {'project': 2}]}, + 'users': 2, 'groups': 1}, + 'roles': 4}, + # Both users are part of the same group + 'group_memberships': [{'group': 0, 'users': [0, 1]}], + # We are going to ask for listing of assignment on project 1 and + # it's subtree. So first we'll add two inherited assignments above + # this (one user and one for a group that contains this user). + 'assignments': [{'user': 0, 'role': 0, 'project': 0, + 'inherited_to_projects': True}, + {'group': 0, 'role': 1, 'project': 0, + 'inherited_to_projects': True}, + # Now an inherited assignment on project 1 itself, + # which should ONLY show up on its children + {'user': 0, 'role': 2, 'project': 1, + 'inherited_to_projects': True}, + # ...and a direct assignment on one of those + # children + {'user': 0, 'role': 3, 'project': 2}, + # The rest are spoiler assignments + {'user': 0, 'role': 2, 'project': 5}, + {'user': 0, 'role': 3, 'project': 4}], + 'tests': [ + # List all effective assignments for project 1 and its subtree. + {'params': {'project': 1, 'user': 0, 'effective': True, + 'include_subtree': True}, + 'results': [ + # First, we should see the inherited user assignment from + # project 0 on all projects in the subtree + {'user': 0, 'role': 0, 'project': 1, + 'indirect': {'project': 0}}, + {'user': 0, 'role': 0, 'project': 2, + 'indirect': {'project': 0}}, + {'user': 0, 'role': 0, 'project': 3, + 'indirect': {'project': 0}}, + # Also the inherited group assignment from project 0 on + # the subtree + {'user': 0, 'role': 1, 'project': 1, + 'indirect': {'project': 0, 'group': 0}}, + {'user': 0, 'role': 1, 'project': 2, + 'indirect': {'project': 0, 'group': 0}}, + {'user': 0, 'role': 1, 'project': 3, + 'indirect': {'project': 0, 'group': 0}}, + # The inherited assignment on project 1 should appear only + # on its children + {'user': 0, 'role': 2, 'project': 2, + 'indirect': {'project': 1}}, + {'user': 0, 'role': 2, 'project': 3, + 'indirect': {'project': 1}}, + # And finally the direct assignment on project 2 + {'user': 0, 'role': 3, 'project': 2}]} + ] + } + + self.execute_assignment_plan(test_plan) + + def test_list_effective_assignments_for_tree_with_domain_assignments(self): + """Test we correctly honor domain inherited assignments on the tree""" + # Enable OS-INHERIT extension + self.config_fixture.config(group='os_inherit', enabled=True) + + test_plan = { + # Create a domain with a project hierarchy 3 levels deep: + # + # project 0 + # ____________|____________ + # | | + # project 1 project 4 + # ______|_____ ______|_____ + # | | | | + # project 2 project 3 project 5 project 6 + # + # Also, create 1 user and 4 roles. + 'entities': { + 'domains': { + 'projects': {'project': [{'project': 2}, + {'project': 2}]}, + 'users': 1}, + 'roles': 4}, + 'assignments': [ + # An inherited assignment on the domain (which should be + # applied to all the projects) + {'user': 0, 'role': 1, 'domain': 0, + 'inherited_to_projects': True}, + # A direct assignment to project 2 + {'user': 0, 'role': 2, 'project': 2}, + # ...and two spoiler assignments, one to the root and one + # to project 4 + {'user': 0, 'role': 0, 'project': 0}, + {'user': 0, 'role': 3, 'project': 4}], + 'tests': [ + # List all effective assignments for project 1 and its subtree. + {'params': {'project': 1, 'effective': True, + 'include_subtree': True}, + 'results': [ + # The inherited assignment from the domain should appear + # only on the part of the subtree we are interested in + {'user': 0, 'role': 1, 'project': 1, + 'indirect': {'domain': 0}}, + {'user': 0, 'role': 1, 'project': 2, + 'indirect': {'domain': 0}}, + {'user': 0, 'role': 1, 'project': 3, + 'indirect': {'domain': 0}}, + # And finally the direct assignment on project 2 + {'user': 0, 'role': 2, 'project': 2}]} + ] + } + + self.execute_assignment_plan(test_plan) + + def test_list_user_ids_for_project_with_inheritance(self): + test_plan = { + # A domain with a project and sub-project, plus four users, + # two groups, as well as 4 roles. + 'entities': { + 'domains': {'id': CONF.identity.default_domain_id, 'users': 4, + 'groups': 2, + 'projects': {'project': 1}}, + 'roles': 4}, + # Each group has a unique user member + 'group_memberships': [{'group': 0, 'users': [1]}, + {'group': 1, 'users': [3]}], + # Set up assignments so that there should end up with four + # effective assignments on project 1 - one direct, one due to + # group membership and one user assignment inherited from the + # parent and one group assignment inhertied from the parent. + 'assignments': [{'user': 0, 'role': 0, 'project': 1}, + {'group': 0, 'role': 1, 'project': 1}, + {'user': 2, 'role': 2, 'project': 0, + 'inherited_to_projects': True}, + {'group': 1, 'role': 3, 'project': 0, + 'inherited_to_projects': True}], + } + # Use assignment plan helper to create all the entities and + # assignments - then we'll run our own tests using the data + test_data = self.execute_assignment_plan(test_plan) + self.config_fixture.config(group='os_inherit', enabled=True) + user_ids = self.assignment_api.list_user_ids_for_project( + test_data['projects'][1]['id']) + self.assertThat(user_ids, matchers.HasLength(4)) + for x in range(0, 4): + self.assertIn(test_data['users'][x]['id'], user_ids) + + def test_list_role_assignment_using_inherited_sourced_groups(self): + """Test listing inherited assignments when restricted by groups.""" + test_plan = { + # A domain with 3 users, 3 groups, 3 projects, a second domain, + # plus 3 roles. + 'entities': {'domains': [{'users': 3, 'groups': 3, 'projects': 3}, + 1], + 'roles': 3}, + # Users 0 & 1 are in the group 0, User 0 also in group 1 + 'group_memberships': [{'group': 0, 'users': [0, 1]}, + {'group': 1, 'users': [0]}], + # Spread the assignments around - we want to be able to show that + # if sourced by group, assignments from other sources are excluded + 'assignments': [{'user': 0, 'role': 0, 'domain': 0}, + {'group': 0, 'role': 1, 'domain': 1}, + {'group': 1, 'role': 2, 'domain': 0, + 'inherited_to_projects': True}, + {'group': 1, 'role': 2, 'project': 1}, + {'user': 2, 'role': 1, 'project': 1, + 'inherited_to_projects': True}, + {'group': 2, 'role': 2, 'project': 2} + ], + 'tests': [ + # List all effective assignments sourced from groups 0 and 1. + # We should see the inherited group assigned on the 3 projects + # from domain 0, as well as the direct assignments. + {'params': {'source_from_group_ids': [0, 1], + 'effective': True}, + 'results': [{'group': 0, 'role': 1, 'domain': 1}, + {'group': 1, 'role': 2, 'project': 0, + 'indirect': {'domain': 0}}, + {'group': 1, 'role': 2, 'project': 1, + 'indirect': {'domain': 0}}, + {'group': 1, 'role': 2, 'project': 2, + 'indirect': {'domain': 0}}, + {'group': 1, 'role': 2, 'project': 1} + ]}, + ] + } + self.execute_assignment_plan(test_plan) + + +class ImpliedRoleTests(AssignmentTestHelperMixin): + + def test_implied_role_crd(self): + prior_role_ref = unit.new_role_ref() + self.role_api.create_role(prior_role_ref['id'], prior_role_ref) + implied_role_ref = unit.new_role_ref() + self.role_api.create_role(implied_role_ref['id'], implied_role_ref) + + self.role_api.create_implied_role( + prior_role_ref['id'], + implied_role_ref['id']) + implied_role = self.role_api.get_implied_role( + prior_role_ref['id'], + implied_role_ref['id']) + expected_implied_role_ref = { + 'prior_role_id': prior_role_ref['id'], + 'implied_role_id': implied_role_ref['id']} + self.assertDictContainsSubset( + expected_implied_role_ref, + implied_role) + + self.role_api.delete_implied_role( + prior_role_ref['id'], + implied_role_ref['id']) + self.assertRaises(exception.ImpliedRoleNotFound, + self.role_api.get_implied_role, + uuid.uuid4().hex, + uuid.uuid4().hex) + + def test_delete_implied_role_returns_not_found(self): + self.assertRaises(exception.ImpliedRoleNotFound, + self.role_api.delete_implied_role, + uuid.uuid4().hex, + uuid.uuid4().hex) + + def test_role_assignments_simple_tree_of_implied_roles(self): + """Test that implied roles are expanded out.""" + test_plan = { + 'entities': {'domains': {'users': 1, 'projects': 1}, + 'roles': 4}, + # Three level tree of implied roles + 'implied_roles': [{'role': 0, 'implied_roles': 1}, + {'role': 1, 'implied_roles': [2, 3]}], + 'assignments': [{'user': 0, 'role': 0, 'project': 0}], + 'tests': [ + # List all direct assignments for user[0], this should just + # show the one top level role assignment + {'params': {'user': 0}, + 'results': [{'user': 0, 'role': 0, 'project': 0}]}, + # Listing in effective mode should show the implied roles + # expanded out + {'params': {'user': 0, 'effective': True}, + 'results': [{'user': 0, 'role': 0, 'project': 0}, + {'user': 0, 'role': 1, 'project': 0, + 'indirect': {'role': 0}}, + {'user': 0, 'role': 2, 'project': 0, + 'indirect': {'role': 1}}, + {'user': 0, 'role': 3, 'project': 0, + 'indirect': {'role': 1}}]}, + ] + } + self.execute_assignment_plan(test_plan) + + def test_circular_inferences(self): + """Test that implied roles are expanded out.""" + test_plan = { + 'entities': {'domains': {'users': 1, 'projects': 1}, + 'roles': 4}, + # Three level tree of implied roles + 'implied_roles': [{'role': 0, 'implied_roles': [1]}, + {'role': 1, 'implied_roles': [2, 3]}, + {'role': 3, 'implied_roles': [0]}], + 'assignments': [{'user': 0, 'role': 0, 'project': 0}], + 'tests': [ + # List all direct assignments for user[0], this should just + # show the one top level role assignment + {'params': {'user': 0}, + 'results': [{'user': 0, 'role': 0, 'project': 0}]}, + # Listing in effective mode should show the implied roles + # expanded out + {'params': {'user': 0, 'effective': True}, + 'results': [{'user': 0, 'role': 0, 'project': 0}, + {'user': 0, 'role': 0, 'project': 0, + 'indirect': {'role': 3}}, + {'user': 0, 'role': 1, 'project': 0, + 'indirect': {'role': 0}}, + {'user': 0, 'role': 2, 'project': 0, + 'indirect': {'role': 1}}, + {'user': 0, 'role': 3, 'project': 0, + 'indirect': {'role': 1}}]}, + ] + } + self.execute_assignment_plan(test_plan) + + def test_role_assignments_directed_graph_of_implied_roles(self): + """Test that a role can have multiple, different prior roles.""" + test_plan = { + 'entities': {'domains': {'users': 1, 'projects': 1}, + 'roles': 6}, + # Three level tree of implied roles, where one of the roles at the + # bottom is implied by more than one top level role + 'implied_roles': [{'role': 0, 'implied_roles': [1, 2]}, + {'role': 1, 'implied_roles': [3, 4]}, + {'role': 5, 'implied_roles': 4}], + # The user gets both top level roles + 'assignments': [{'user': 0, 'role': 0, 'project': 0}, + {'user': 0, 'role': 5, 'project': 0}], + 'tests': [ + # The implied roles should be expanded out and there should be + # two entries for the role that had two different prior roles. + {'params': {'user': 0, 'effective': True}, + 'results': [{'user': 0, 'role': 0, 'project': 0}, + {'user': 0, 'role': 5, 'project': 0}, + {'user': 0, 'role': 1, 'project': 0, + 'indirect': {'role': 0}}, + {'user': 0, 'role': 2, 'project': 0, + 'indirect': {'role': 0}}, + {'user': 0, 'role': 3, 'project': 0, + 'indirect': {'role': 1}}, + {'user': 0, 'role': 4, 'project': 0, + 'indirect': {'role': 1}}, + {'user': 0, 'role': 4, 'project': 0, + 'indirect': {'role': 5}}]}, + ] + } + test_data = self.execute_assignment_plan(test_plan) + + # We should also be able to get a similar (yet summarized) answer to + # the above by calling get_roles_for_user_and_project(), which should + # list the role_ids, yet remove any duplicates + role_ids = self.assignment_api.get_roles_for_user_and_project( + test_data['users'][0]['id'], test_data['projects'][0]['id']) + # We should see 6 entries, not 7, since role index 5 appeared twice in + # the answer from list_role_assignments + self.assertThat(role_ids, matchers.HasLength(6)) + for x in range(0, 5): + self.assertIn(test_data['roles'][x]['id'], role_ids) + + def test_role_assignments_implied_roles_filtered_by_role(self): + """Test that you can filter by role even if roles are implied.""" + test_plan = { + 'entities': {'domains': {'users': 1, 'projects': 2}, + 'roles': 4}, + # Three level tree of implied roles + 'implied_roles': [{'role': 0, 'implied_roles': 1}, + {'role': 1, 'implied_roles': [2, 3]}], + 'assignments': [{'user': 0, 'role': 0, 'project': 0}, + {'user': 0, 'role': 3, 'project': 1}], + 'tests': [ + # List effective roles filtering by one of the implied roles, + # showing that the filter was implied post expansion of + # implied roles (and that non impled roles are included in + # the filter + {'params': {'role': 3, 'effective': True}, + 'results': [{'user': 0, 'role': 3, 'project': 0, + 'indirect': {'role': 1}}, + {'user': 0, 'role': 3, 'project': 1}]}, + ] + } + self.execute_assignment_plan(test_plan) + + def test_role_assignments_simple_tree_of_implied_roles_on_domain(self): + """Test that implied roles are expanded out when placed on a domain.""" + test_plan = { + 'entities': {'domains': {'users': 1}, + 'roles': 4}, + # Three level tree of implied roles + 'implied_roles': [{'role': 0, 'implied_roles': 1}, + {'role': 1, 'implied_roles': [2, 3]}], + 'assignments': [{'user': 0, 'role': 0, 'domain': 0}], + 'tests': [ + # List all direct assignments for user[0], this should just + # show the one top level role assignment + {'params': {'user': 0}, + 'results': [{'user': 0, 'role': 0, 'domain': 0}]}, + # Listing in effective mode should how the implied roles + # expanded out + {'params': {'user': 0, 'effective': True}, + 'results': [{'user': 0, 'role': 0, 'domain': 0}, + {'user': 0, 'role': 1, 'domain': 0, + 'indirect': {'role': 0}}, + {'user': 0, 'role': 2, 'domain': 0, + 'indirect': {'role': 1}}, + {'user': 0, 'role': 3, 'domain': 0, + 'indirect': {'role': 1}}]}, + ] + } + self.execute_assignment_plan(test_plan) + + def test_role_assignments_inherited_implied_roles(self): + """Test that you can intermix inherited and implied roles.""" + test_plan = { + 'entities': {'domains': {'users': 1, 'projects': 1}, + 'roles': 4}, + # Simply one level of implied roles + 'implied_roles': [{'role': 0, 'implied_roles': 1}], + # Assign to top level role as an inherited assignment to the + # domain + 'assignments': [{'user': 0, 'role': 0, 'domain': 0, + 'inherited_to_projects': True}], + 'tests': [ + # List all direct assignments for user[0], this should just + # show the one top level role assignment + {'params': {'user': 0}, + 'results': [{'user': 0, 'role': 0, 'domain': 0, + 'inherited_to_projects': 'projects'}]}, + # List in effective mode - we should only see the initial and + # implied role on the project (since inherited roles are not + # active on their anchor point). + {'params': {'user': 0, 'effective': True}, + 'results': [{'user': 0, 'role': 0, 'project': 0, + 'indirect': {'domain': 0}}, + {'user': 0, 'role': 1, 'project': 0, + 'indirect': {'domain': 0, 'role': 0}}]}, + ] + } + self.config_fixture.config(group='os_inherit', enabled=True) + self.execute_assignment_plan(test_plan) + + def test_role_assignments_domain_specific_with_implied_roles(self): + test_plan = { + 'entities': {'domains': {'users': 1, 'projects': 1, 'roles': 2}, + 'roles': 2}, + # Two level tree of implied roles, with the top and 1st level being + # domain specific roles, and the bottom level being infered global + # roles. + 'implied_roles': [{'role': 0, 'implied_roles': [1]}, + {'role': 1, 'implied_roles': [2, 3]}], + 'assignments': [{'user': 0, 'role': 0, 'project': 0}], + 'tests': [ + # List all direct assignments for user[0], this should just + # show the one top level role assignment, even though this is a + # domain specific role (since we are in non-effective mode and + # we show any direct role assignment in that mode). + {'params': {'user': 0}, + 'results': [{'user': 0, 'role': 0, 'project': 0}]}, + # Now the effective ones - so the implied roles should be + # expanded out, as well as any domain specific roles should be + # removed. + {'params': {'user': 0, 'effective': True}, + 'results': [{'user': 0, 'role': 2, 'project': 0, + 'indirect': {'role': 1}}, + {'user': 0, 'role': 3, 'project': 0, + 'indirect': {'role': 1}}]}, + ] + } + self.execute_assignment_plan(test_plan) diff --git a/keystone/tests/unit/test_backend.py b/keystone/tests/unit/test_backend.py index 8fb6cd9b13..6a45a27eb1 100644 --- a/keystone/tests/unit/test_backend.py +++ b/keystone/tests/unit/test_backend.py @@ -39,422 +39,7 @@ CONF = cfg.CONF NULL_OBJECT = object() -class AssignmentTestHelperMixin(object): - """Mixin class to aid testing of assignments. - - This class supports data driven test plans that enable: - - - Creation of initial entities, such as domains, users, groups, projects - and roles - - Creation of assignments referencing the above entities - - A set of input parameters and expected outputs to list_role_assignments - based on the above test data - - A test plan is a dict of the form: - - test_plan = { - entities: details and number of entities, - group_memberships: group-user entity memberships, - assignments: list of assignments to create, - tests: list of pairs of input params and expected outputs} - - An example test plan: - - test_plan = { - # First, create the entities required. Entities are specified by - # a dict with the key being the entity type and the value an - # entity specification which can be one of: - # - # - a simple number, e.g. {'users': 3} creates 3 users - # - a dict where more information regarding the contents of the entity - # is required, e.g. {'domains' : {'users : 3}} creates a domain - # with three users - # - a list of entity specifications if multiple are required - # - # The following creates a domain that contains a single user, group and - # project, as well as creating three roles. - - 'entities': {'domains': {'users': 1, 'groups': 1, 'projects': 1}, - 'roles': 3}, - - # If it is required that an existing domain be used for the new - # entities, then the id of that domain can be included in the - # domain dict. For example, if alternatively we wanted to add 3 users - # to the default domain, add a second domain containing 3 projects as - # well as 5 additional empty domains, the entities would be defined as: - # - # 'entities': {'domains': [{'id': DEFAULT_DOMAIN, 'users': 3}, - # {'projects': 3}, 5]}, - # - # A project hierarchy can be specified within the 'projects' section by - # nesting the 'project' key, for example to create a project with three - # sub-projects you would use: - - 'projects': {'project': 3} - - # A more complex hierarchy can also be defined, for example the - # following would define three projects each containing a - # sub-project, each of which contain a further three sub-projects. - - 'projects': [{'project': {'project': 3}}, - {'project': {'project': 3}}, - {'project': {'project': 3}}] - - # If the 'roles' entity count is defined as top level key in 'entities' - # dict then these are global roles. If it is placed within the - # 'domain' dict, then they will be domain specific roles. A mix of - # domain specific and global roles are allowed, with the role index - # being calculated in the order they are defined in the 'entities' - # dict. - - # A set of implied role specifications. In this case, prior role - # index 0 implies role index 1, and role 1 implies roles 2 and 3. - - 'roles': [{'role': 0, 'implied_roles': [1]}, - {'role': 1, 'implied_roles': [2, 3]}] - - # A list of groups and their members. In this case make users with - # index 0 and 1 members of group with index 0. Users and Groups are - # indexed in the order they appear in the 'entities' key above. - - 'group_memberships': [{'group': 0, 'users': [0, 1]}] - - # Next, create assignments between the entities, referencing the - # entities by index, i.e. 'user': 0 refers to user[0]. Entities are - # indexed in the order they appear in the 'entities' key above within - # their entity type. - - 'assignments': [{'user': 0, 'role': 0, 'domain': 0}, - {'user': 0, 'role': 1, 'project': 0}, - {'group': 0, 'role': 2, 'domain': 0}, - {'user': 0, 'role': 2, 'project': 0}], - - # Finally, define an array of tests where list_role_assignment() is - # called with the given input parameters and the results are then - # confirmed to be as given in 'results'. Again, all entities are - # referenced by index. - - 'tests': [ - {'params': {}, - 'results': [{'user': 0, 'role': 0, 'domain': 0}, - {'user': 0, 'role': 1, 'project': 0}, - {'group': 0, 'role': 2, 'domain': 0}, - {'user': 0, 'role': 2, 'project': 0}]}, - {'params': {'role': 2}, - 'results': [{'group': 0, 'role': 2, 'domain': 0}, - {'user': 0, 'role': 2, 'project': 0}]}] - - # The 'params' key also supports the 'effective', - # 'inherited_to_projects' and 'source_from_group_ids' options to - # list_role_assignments.} - - """ - - def _handle_project_spec(self, test_data, domain_id, project_spec, - parent_id=None): - """Handle the creation of a project or hierarchy of projects. - - project_spec may either be a count of the number of projects to - create, or it may be a list of the form: - - [{'project': project_spec}, {'project': project_spec}, ...] - - This method is called recursively to handle the creation of a - hierarchy of projects. - - """ - def _create_project(domain_id, parent_id): - new_project = unit.new_project_ref(domain_id=domain_id, - parent_id=parent_id) - new_project = self.resource_api.create_project(new_project['id'], - new_project) - return new_project - - if isinstance(project_spec, list): - for this_spec in project_spec: - self._handle_project_spec( - test_data, domain_id, this_spec, parent_id=parent_id) - elif isinstance(project_spec, dict): - new_proj = _create_project(domain_id, parent_id) - test_data['projects'].append(new_proj) - self._handle_project_spec( - test_data, domain_id, project_spec['project'], - parent_id=new_proj['id']) - else: - for _ in range(project_spec): - test_data['projects'].append( - _create_project(domain_id, parent_id)) - - def _create_role(self, domain_id=None): - new_role = unit.new_role_ref(domain_id=domain_id) - return self.role_api.create_role(new_role['id'], new_role) - - def _handle_domain_spec(self, test_data, domain_spec): - """Handle the creation of domains and their contents. - - domain_spec may either be a count of the number of empty domains to - create, a dict describing the domain contents, or a list of - domain_specs. - - In the case when a list is provided, this method calls itself - recursively to handle the list elements. - - This method will insert any entities created into test_data - - """ - def _create_domain(domain_id=None): - if domain_id is None: - new_domain = unit.new_domain_ref() - self.resource_api.create_domain(new_domain['id'], - new_domain) - return new_domain - else: - # The test plan specified an existing domain to use - return self.resource_api.get_domain(domain_id) - - def _create_entity_in_domain(entity_type, domain_id): - """Create a user or group entity in the domain.""" - if entity_type == 'users': - new_entity = unit.new_user_ref(domain_id=domain_id) - new_entity = self.identity_api.create_user(new_entity) - elif entity_type == 'groups': - new_entity = unit.new_group_ref(domain_id=domain_id) - new_entity = self.identity_api.create_group(new_entity) - elif entity_type == 'roles': - new_entity = self._create_role(domain_id=domain_id) - else: - # Must be a bad test plan - raise exception.NotImplemented() - return new_entity - - if isinstance(domain_spec, list): - for x in domain_spec: - self._handle_domain_spec(test_data, x) - elif isinstance(domain_spec, dict): - # If there is a domain ID specified, then use it - the_domain = _create_domain(domain_spec.get('id')) - test_data['domains'].append(the_domain) - for entity_type, value in domain_spec.items(): - if entity_type == 'id': - # We already used this above to determine whether to - # use and existing domain - continue - if entity_type == 'projects': - # If it's projects, we need to handle the potential - # specification of a project hierarchy - self._handle_project_spec( - test_data, the_domain['id'], value) - else: - # It's a count of number of entities - for _ in range(value): - test_data[entity_type].append( - _create_entity_in_domain( - entity_type, the_domain['id'])) - else: - for _ in range(domain_spec): - test_data['domains'].append(_create_domain()) - - def create_entities(self, entity_pattern): - """Create the entities specified in the test plan. - - Process the 'entities' key in the test plan, creating the requested - entities. Each created entity will be added to the array of entities - stored in the returned test_data object, e.g.: - - test_data['users'] = [user[0], user[1]....] - - """ - test_data = {} - for entity in ['users', 'groups', 'domains', 'projects', 'roles']: - test_data[entity] = [] - - # Create any domains requested and, if specified, any entities within - # those domains - if 'domains' in entity_pattern: - self._handle_domain_spec(test_data, entity_pattern['domains']) - - # Create any roles requested - if 'roles' in entity_pattern: - for _ in range(entity_pattern['roles']): - test_data['roles'].append(self._create_role()) - - return test_data - - def _convert_entity_shorthand(self, key, shorthand_data, reference_data): - """Convert a shorthand entity description into a full ID reference. - - In test plan definitions, we allow a shorthand for referencing to an - entity of the form: - - 'user': 0 - - which is actually shorthand for: - - 'user_id': reference_data['users'][0]['id'] - - This method converts the shorthand version into the full reference. - - """ - expanded_key = '%s_id' % key - reference_index = '%ss' % key - index_value = ( - reference_data[reference_index][shorthand_data[key]]['id']) - return expanded_key, index_value - - def create_implied_roles(self, implied_pattern, test_data): - """Create the implied roles specified in the test plan.""" - for implied_spec in implied_pattern: - # Each implied role specification is a dict of the form: - # - # {'role': 0, 'implied_roles': list of roles} - - prior_role = test_data['roles'][implied_spec['role']]['id'] - if isinstance(implied_spec['implied_roles'], list): - for this_role in implied_spec['implied_roles']: - implied_role = test_data['roles'][this_role]['id'] - self.role_api.create_implied_role(prior_role, implied_role) - else: - implied_role = ( - test_data['roles'][implied_spec['implied_roles']]['id']) - self.role_api.create_implied_role(prior_role, implied_role) - - def create_group_memberships(self, group_pattern, test_data): - """Create the group memberships specified in the test plan.""" - for group_spec in group_pattern: - # Each membership specification is a dict of the form: - # - # {'group': 0, 'users': [list of user indexes]} - # - # Add all users in the list to the specified group, first - # converting from index to full entity ID. - group_value = test_data['groups'][group_spec['group']]['id'] - for user_index in group_spec['users']: - user_value = test_data['users'][user_index]['id'] - self.identity_api.add_user_to_group(user_value, group_value) - return test_data - - def create_assignments(self, assignment_pattern, test_data): - """Create the assignments specified in the test plan.""" - # First store how many assignments are already in the system, - # so during the tests we can check the number of new assignments - # created. - test_data['initial_assignment_count'] = ( - len(self.assignment_api.list_role_assignments())) - - # Now create the new assignments in the test plan - for assignment in assignment_pattern: - # Each assignment is a dict of the form: - # - # { 'user': 0, 'project':1, 'role': 6} - # - # where the value of each item is the index into the array of - # entities created earlier. - # - # We process the assignment dict to create the args required to - # make the create_grant() call. - args = {} - for param in assignment: - if param == 'inherited_to_projects': - args[param] = assignment[param] - else: - # Turn 'entity : 0' into 'entity_id = ac6736ba873d' - # where entity in user, group, project or domain - key, value = self._convert_entity_shorthand( - param, assignment, test_data) - args[key] = value - self.assignment_api.create_grant(**args) - return test_data - - def execute_assignment_cases(self, test_plan, test_data): - """Execute the test plan, based on the created test_data.""" - def check_results(expected, actual, param_arg_count): - if param_arg_count == 0: - # It was an unfiltered call, so default fixture assignments - # might be polluting our answer - so we take into account - # how many assignments there were before the test. - self.assertEqual( - len(expected) + test_data['initial_assignment_count'], - len(actual)) - else: - self.assertThat(actual, matchers.HasLength(len(expected))) - - for each_expected in expected: - expected_assignment = {} - for param in each_expected: - if param == 'inherited_to_projects': - expected_assignment[param] = each_expected[param] - elif param == 'indirect': - # We're expecting the result to contain an indirect - # dict with the details how the role came to be placed - # on this entity - so convert the key/value pairs of - # that dict into real entity references. - indirect_term = {} - for indirect_param in each_expected[param]: - key, value = self._convert_entity_shorthand( - indirect_param, each_expected[param], - test_data) - indirect_term[key] = value - expected_assignment[param] = indirect_term - else: - # Convert a simple shorthand entry into a full - # entity reference - key, value = self._convert_entity_shorthand( - param, each_expected, test_data) - expected_assignment[key] = value - self.assertIn(expected_assignment, actual) - - def convert_group_ids_sourced_from_list(index_list, reference_data): - value_list = [] - for group_index in index_list: - value_list.append( - reference_data['groups'][group_index]['id']) - return value_list - - # Go through each test in the array, processing the input params, which - # we build into an args dict, and then call list_role_assignments. Then - # check the results against those specified in the test plan. - for test in test_plan.get('tests', []): - args = {} - for param in test['params']: - if param in ['effective', 'inherited', 'include_subtree']: - # Just pass the value into the args - args[param] = test['params'][param] - elif param == 'source_from_group_ids': - # Convert the list of indexes into a list of IDs - args[param] = convert_group_ids_sourced_from_list( - test['params']['source_from_group_ids'], test_data) - else: - # Turn 'entity : 0' into 'entity_id = ac6736ba873d' - # where entity in user, group, project or domain - key, value = self._convert_entity_shorthand( - param, test['params'], test_data) - args[key] = value - results = self.assignment_api.list_role_assignments(**args) - check_results(test['results'], results, len(args)) - - def execute_assignment_plan(self, test_plan): - """Create entities, assignments and execute the test plan. - - The standard method to call to create entities and assignments and - execute the tests as specified in the test_plan. The test_data - dict is returned so that, if required, the caller can execute - additional manual tests with the entities and assignments created. - - """ - test_data = self.create_entities(test_plan['entities']) - if 'implied_roles' in test_plan: - self.create_implied_roles(test_plan['implied_roles'], test_data) - if 'group_memberships' in test_plan: - self.create_group_memberships(test_plan['group_memberships'], - test_data) - if 'assignments' in test_plan: - test_data = self.create_assignments(test_plan['assignments'], - test_data) - self.execute_assignment_cases(test_plan, test_data) - return test_data - - -class IdentityTests(AssignmentTestHelperMixin): +class IdentityTests(object): domain_count = len(default_fixtures.DOMAINS) @@ -468,38 +53,6 @@ class IdentityTests(AssignmentTestHelperMixin): if CONF.identity.domain_specific_drivers_enabled: return domain_id - def test_project_add_and_remove_user_role(self): - user_ids = self.assignment_api.list_user_ids_for_project( - self.tenant_bar['id']) - self.assertNotIn(self.user_two['id'], user_ids) - - self.assignment_api.add_role_to_user_and_project( - tenant_id=self.tenant_bar['id'], - user_id=self.user_two['id'], - role_id=self.role_other['id']) - user_ids = self.assignment_api.list_user_ids_for_project( - self.tenant_bar['id']) - self.assertIn(self.user_two['id'], user_ids) - - self.assignment_api.remove_role_from_user_and_project( - tenant_id=self.tenant_bar['id'], - user_id=self.user_two['id'], - role_id=self.role_other['id']) - - user_ids = self.assignment_api.list_user_ids_for_project( - self.tenant_bar['id']) - self.assertNotIn(self.user_two['id'], user_ids) - - def test_remove_user_role_not_assigned(self): - # Expect failure if attempt to remove a role that was never assigned to - # the user. - self.assertRaises(exception.RoleNotFound, - self.assignment_api. - remove_role_from_user_and_project, - tenant_id=self.tenant_bar['id'], - user_id=self.user_two['id'], - role_id=self.role_other['id']) - def test_authenticate_bad_user(self): self.assertRaises(AssertionError, self.identity_api.authenticate, @@ -614,41 +167,6 @@ class IdentityTests(AssignmentTestHelperMixin): uuid.uuid4().hex, CONF.identity.default_domain_id) - def test_list_user_ids_for_project(self): - user_ids = self.assignment_api.list_user_ids_for_project( - self.tenant_baz['id']) - self.assertEqual(2, len(user_ids)) - self.assertIn(self.user_two['id'], user_ids) - self.assertIn(self.user_badguy['id'], user_ids) - - def test_list_user_ids_for_project_no_duplicates(self): - # Create user - user_ref = unit.new_user_ref(domain_id=CONF.identity.default_domain_id) - user_ref = self.identity_api.create_user(user_ref) - # Create project - project_ref = unit.new_project_ref( - domain_id=CONF.identity.default_domain_id) - self.resource_api.create_project( - project_ref['id'], project_ref) - # Create 2 roles and give user each role in project - for i in range(2): - role_ref = unit.new_role_ref() - self.role_api.create_role(role_ref['id'], role_ref) - self.assignment_api.add_role_to_user_and_project( - user_id=user_ref['id'], - tenant_id=project_ref['id'], - role_id=role_ref['id']) - # Get the list of user_ids in project - user_ids = self.assignment_api.list_user_ids_for_project( - project_ref['id']) - # Ensure the user is only returned once - self.assertEqual(1, len(user_ids)) - - def test_get_project_user_ids_returns_not_found(self): - self.assertRaises(exception.ProjectNotFound, - self.assignment_api.list_user_ids_for_project, - uuid.uuid4().hex) - def test_get_user(self): user_ref = self.identity_api.get_user(self.user_foo['id']) # NOTE(termie): the password field is left in user_foo to make @@ -985,981 +503,6 @@ class IdentityTests(AssignmentTestHelperMixin): self.resource_api.get_project, 'fake2') - def test_list_role_assignments_unfiltered(self): - """Test unfiltered listing of role assignments.""" - test_plan = { - # Create a domain, with a user, group & project - 'entities': {'domains': {'users': 1, 'groups': 1, 'projects': 1}, - 'roles': 3}, - # Create a grant of each type (user/group on project/domain) - 'assignments': [{'user': 0, 'role': 0, 'domain': 0}, - {'user': 0, 'role': 1, 'project': 0}, - {'group': 0, 'role': 2, 'domain': 0}, - {'group': 0, 'role': 2, 'project': 0}], - 'tests': [ - # Check that we get back the 4 assignments - {'params': {}, - 'results': [{'user': 0, 'role': 0, 'domain': 0}, - {'user': 0, 'role': 1, 'project': 0}, - {'group': 0, 'role': 2, 'domain': 0}, - {'group': 0, 'role': 2, 'project': 0}]} - ] - } - self.execute_assignment_plan(test_plan) - - def test_list_role_assignments_filtered_by_role(self): - """Test listing of role assignments filtered by role ID.""" - test_plan = { - # Create a user, group & project in the default domain - 'entities': {'domains': {'id': CONF.identity.default_domain_id, - 'users': 1, 'groups': 1, 'projects': 1}, - 'roles': 3}, - # Create a grant of each type (user/group on project/domain) - 'assignments': [{'user': 0, 'role': 0, 'domain': 0}, - {'user': 0, 'role': 1, 'project': 0}, - {'group': 0, 'role': 2, 'domain': 0}, - {'group': 0, 'role': 2, 'project': 0}], - 'tests': [ - # Check that when filtering by role, we only get back those - # that match - {'params': {'role': 2}, - 'results': [{'group': 0, 'role': 2, 'domain': 0}, - {'group': 0, 'role': 2, 'project': 0}]} - ] - } - self.execute_assignment_plan(test_plan) - - def test_list_group_role_assignment(self): - # When a group role assignment is created and the role assignments are - # listed then the group role assignment is included in the list. - - test_plan = { - 'entities': {'domains': {'id': CONF.identity.default_domain_id, - 'groups': 1, 'projects': 1}, - 'roles': 1}, - 'assignments': [{'group': 0, 'role': 0, 'project': 0}], - 'tests': [ - {'params': {}, - 'results': [{'group': 0, 'role': 0, 'project': 0}]} - ] - } - self.execute_assignment_plan(test_plan) - - def test_list_role_assignments_bad_role(self): - assignment_list = self.assignment_api.list_role_assignments( - role_id=uuid.uuid4().hex) - self.assertEqual([], assignment_list) - - def test_add_duplicate_role_grant(self): - roles_ref = self.assignment_api.get_roles_for_user_and_project( - self.user_foo['id'], self.tenant_bar['id']) - self.assertNotIn(self.role_admin['id'], roles_ref) - self.assignment_api.add_role_to_user_and_project( - self.user_foo['id'], self.tenant_bar['id'], self.role_admin['id']) - self.assertRaises(exception.Conflict, - self.assignment_api.add_role_to_user_and_project, - self.user_foo['id'], - self.tenant_bar['id'], - self.role_admin['id']) - - def test_get_role_by_user_and_project_with_user_in_group(self): - """Test for get role by user and project, user was added into a group. - - Test Plan: - - - Create a user, a project & a group, add this user to group - - Create roles and grant them to user and project - - Check the role list get by the user and project was as expected - - """ - user_ref = unit.new_user_ref(domain_id=CONF.identity.default_domain_id) - user_ref = self.identity_api.create_user(user_ref) - - project_ref = unit.new_project_ref( - domain_id=CONF.identity.default_domain_id) - self.resource_api.create_project(project_ref['id'], project_ref) - - group = unit.new_group_ref(domain_id=CONF.identity.default_domain_id) - group_id = self.identity_api.create_group(group)['id'] - self.identity_api.add_user_to_group(user_ref['id'], group_id) - - role_ref_list = [] - for i in range(2): - role_ref = unit.new_role_ref() - self.role_api.create_role(role_ref['id'], role_ref) - role_ref_list.append(role_ref) - - self.assignment_api.add_role_to_user_and_project( - user_id=user_ref['id'], - tenant_id=project_ref['id'], - role_id=role_ref['id']) - - role_list = self.assignment_api.get_roles_for_user_and_project( - user_ref['id'], - project_ref['id']) - - self.assertEqual(set([r['id'] for r in role_ref_list]), - set(role_list)) - - def test_get_role_by_user_and_project(self): - roles_ref = self.assignment_api.get_roles_for_user_and_project( - self.user_foo['id'], self.tenant_bar['id']) - self.assertNotIn(self.role_admin['id'], roles_ref) - self.assignment_api.add_role_to_user_and_project( - self.user_foo['id'], self.tenant_bar['id'], self.role_admin['id']) - roles_ref = self.assignment_api.get_roles_for_user_and_project( - self.user_foo['id'], self.tenant_bar['id']) - self.assertIn(self.role_admin['id'], roles_ref) - self.assertNotIn('member', roles_ref) - - self.assignment_api.add_role_to_user_and_project( - self.user_foo['id'], self.tenant_bar['id'], 'member') - roles_ref = self.assignment_api.get_roles_for_user_and_project( - self.user_foo['id'], self.tenant_bar['id']) - self.assertIn(self.role_admin['id'], roles_ref) - self.assertIn('member', roles_ref) - - def test_get_roles_for_user_and_domain(self): - """Test for getting roles for user on a domain. - - Test Plan: - - - Create a domain, with 2 users - - Check no roles yet exit - - Give user1 two roles on the domain, user2 one role - - Get roles on user1 and the domain - maybe sure we only - get back the 2 roles on user1 - - Delete both roles from user1 - - Check we get no roles back for user1 on domain - - """ - new_domain = unit.new_domain_ref() - self.resource_api.create_domain(new_domain['id'], new_domain) - new_user1 = unit.new_user_ref(domain_id=new_domain['id']) - new_user1 = self.identity_api.create_user(new_user1) - new_user2 = unit.new_user_ref(domain_id=new_domain['id']) - new_user2 = self.identity_api.create_user(new_user2) - roles_ref = self.assignment_api.list_grants( - user_id=new_user1['id'], - domain_id=new_domain['id']) - self.assertEqual(0, len(roles_ref)) - # Now create the grants (roles are defined in default_fixtures) - self.assignment_api.create_grant(user_id=new_user1['id'], - domain_id=new_domain['id'], - role_id='member') - self.assignment_api.create_grant(user_id=new_user1['id'], - domain_id=new_domain['id'], - role_id='other') - self.assignment_api.create_grant(user_id=new_user2['id'], - domain_id=new_domain['id'], - role_id='admin') - # Read back the roles for user1 on domain - roles_ids = self.assignment_api.get_roles_for_user_and_domain( - new_user1['id'], new_domain['id']) - self.assertEqual(2, len(roles_ids)) - self.assertIn(self.role_member['id'], roles_ids) - self.assertIn(self.role_other['id'], roles_ids) - - # Now delete both grants for user1 - self.assignment_api.delete_grant(user_id=new_user1['id'], - domain_id=new_domain['id'], - role_id='member') - self.assignment_api.delete_grant(user_id=new_user1['id'], - domain_id=new_domain['id'], - role_id='other') - roles_ref = self.assignment_api.list_grants( - user_id=new_user1['id'], - domain_id=new_domain['id']) - self.assertEqual(0, len(roles_ref)) - - def test_get_roles_for_user_and_domain_returns_not_found(self): - """Test errors raised when getting roles for user on a domain. - - Test Plan: - - - Check non-existing user gives UserNotFound - - Check non-existing domain gives DomainNotFound - - """ - new_domain = self._get_domain_fixture() - new_user1 = unit.new_user_ref(domain_id=new_domain['id']) - new_user1 = self.identity_api.create_user(new_user1) - - self.assertRaises(exception.UserNotFound, - self.assignment_api.get_roles_for_user_and_domain, - uuid.uuid4().hex, - new_domain['id']) - - self.assertRaises(exception.DomainNotFound, - self.assignment_api.get_roles_for_user_and_domain, - new_user1['id'], - uuid.uuid4().hex) - - def test_get_roles_for_user_and_project_returns_not_found(self): - self.assertRaises(exception.UserNotFound, - self.assignment_api.get_roles_for_user_and_project, - uuid.uuid4().hex, - self.tenant_bar['id']) - - self.assertRaises(exception.ProjectNotFound, - self.assignment_api.get_roles_for_user_and_project, - self.user_foo['id'], - uuid.uuid4().hex) - - def test_add_role_to_user_and_project_returns_not_found(self): - self.assertRaises(exception.ProjectNotFound, - self.assignment_api.add_role_to_user_and_project, - self.user_foo['id'], - uuid.uuid4().hex, - self.role_admin['id']) - - self.assertRaises(exception.RoleNotFound, - self.assignment_api.add_role_to_user_and_project, - self.user_foo['id'], - self.tenant_bar['id'], - uuid.uuid4().hex) - - def test_add_role_to_user_and_project_no_user(self): - # If add_role_to_user_and_project and the user doesn't exist, then - # no error. - user_id_not_exist = uuid.uuid4().hex - self.assignment_api.add_role_to_user_and_project( - user_id_not_exist, self.tenant_bar['id'], self.role_admin['id']) - - def test_remove_role_from_user_and_project(self): - self.assignment_api.add_role_to_user_and_project( - self.user_foo['id'], self.tenant_bar['id'], 'member') - self.assignment_api.remove_role_from_user_and_project( - self.user_foo['id'], self.tenant_bar['id'], 'member') - roles_ref = self.assignment_api.get_roles_for_user_and_project( - self.user_foo['id'], self.tenant_bar['id']) - self.assertNotIn('member', roles_ref) - self.assertRaises(exception.NotFound, - self.assignment_api. - remove_role_from_user_and_project, - self.user_foo['id'], - self.tenant_bar['id'], - 'member') - - def test_get_role_grant_by_user_and_project(self): - roles_ref = self.assignment_api.list_grants( - user_id=self.user_foo['id'], - project_id=self.tenant_bar['id']) - self.assertEqual(1, len(roles_ref)) - self.assignment_api.create_grant(user_id=self.user_foo['id'], - project_id=self.tenant_bar['id'], - role_id=self.role_admin['id']) - roles_ref = self.assignment_api.list_grants( - user_id=self.user_foo['id'], - project_id=self.tenant_bar['id']) - self.assertIn(self.role_admin['id'], - [role_ref['id'] for role_ref in roles_ref]) - - self.assignment_api.create_grant(user_id=self.user_foo['id'], - project_id=self.tenant_bar['id'], - role_id='member') - roles_ref = self.assignment_api.list_grants( - user_id=self.user_foo['id'], - project_id=self.tenant_bar['id']) - - roles_ref_ids = [] - for ref in roles_ref: - roles_ref_ids.append(ref['id']) - self.assertIn(self.role_admin['id'], roles_ref_ids) - self.assertIn('member', roles_ref_ids) - - def test_remove_role_grant_from_user_and_project(self): - self.assignment_api.create_grant(user_id=self.user_foo['id'], - project_id=self.tenant_baz['id'], - role_id='member') - roles_ref = self.assignment_api.list_grants( - user_id=self.user_foo['id'], - project_id=self.tenant_baz['id']) - self.assertDictEqual(self.role_member, roles_ref[0]) - - self.assignment_api.delete_grant(user_id=self.user_foo['id'], - project_id=self.tenant_baz['id'], - role_id='member') - roles_ref = self.assignment_api.list_grants( - user_id=self.user_foo['id'], - project_id=self.tenant_baz['id']) - self.assertEqual(0, len(roles_ref)) - self.assertRaises(exception.RoleAssignmentNotFound, - self.assignment_api.delete_grant, - user_id=self.user_foo['id'], - project_id=self.tenant_baz['id'], - role_id='member') - - def test_get_role_assignment_by_project_not_found(self): - self.assertRaises(exception.RoleAssignmentNotFound, - self.assignment_api.check_grant_role_id, - user_id=self.user_foo['id'], - project_id=self.tenant_baz['id'], - role_id='member') - - self.assertRaises(exception.RoleAssignmentNotFound, - self.assignment_api.check_grant_role_id, - group_id=uuid.uuid4().hex, - project_id=self.tenant_baz['id'], - role_id='member') - - def test_get_role_assignment_by_domain_not_found(self): - self.assertRaises(exception.RoleAssignmentNotFound, - self.assignment_api.check_grant_role_id, - user_id=self.user_foo['id'], - domain_id=self.domain_default['id'], - role_id='member') - - self.assertRaises(exception.RoleAssignmentNotFound, - self.assignment_api.check_grant_role_id, - group_id=uuid.uuid4().hex, - domain_id=self.domain_default['id'], - role_id='member') - - def test_del_role_assignment_by_project_not_found(self): - self.assertRaises(exception.RoleAssignmentNotFound, - self.assignment_api.delete_grant, - user_id=self.user_foo['id'], - project_id=self.tenant_baz['id'], - role_id='member') - - self.assertRaises(exception.RoleAssignmentNotFound, - self.assignment_api.delete_grant, - group_id=uuid.uuid4().hex, - project_id=self.tenant_baz['id'], - role_id='member') - - def test_del_role_assignment_by_domain_not_found(self): - self.assertRaises(exception.RoleAssignmentNotFound, - self.assignment_api.delete_grant, - user_id=self.user_foo['id'], - domain_id=self.domain_default['id'], - role_id='member') - - self.assertRaises(exception.RoleAssignmentNotFound, - self.assignment_api.delete_grant, - group_id=uuid.uuid4().hex, - domain_id=self.domain_default['id'], - role_id='member') - - def test_get_and_remove_role_grant_by_group_and_project(self): - new_domain = unit.new_domain_ref() - self.resource_api.create_domain(new_domain['id'], new_domain) - new_group = unit.new_group_ref(domain_id=new_domain['id']) - new_group = self.identity_api.create_group(new_group) - new_user = unit.new_user_ref(domain_id=new_domain['id']) - new_user = self.identity_api.create_user(new_user) - self.identity_api.add_user_to_group(new_user['id'], - new_group['id']) - roles_ref = self.assignment_api.list_grants( - group_id=new_group['id'], - project_id=self.tenant_bar['id']) - self.assertEqual(0, len(roles_ref)) - self.assignment_api.create_grant(group_id=new_group['id'], - project_id=self.tenant_bar['id'], - role_id='member') - roles_ref = self.assignment_api.list_grants( - group_id=new_group['id'], - project_id=self.tenant_bar['id']) - self.assertDictEqual(self.role_member, roles_ref[0]) - - self.assignment_api.delete_grant(group_id=new_group['id'], - project_id=self.tenant_bar['id'], - role_id='member') - roles_ref = self.assignment_api.list_grants( - group_id=new_group['id'], - project_id=self.tenant_bar['id']) - self.assertEqual(0, len(roles_ref)) - self.assertRaises(exception.RoleAssignmentNotFound, - self.assignment_api.delete_grant, - group_id=new_group['id'], - project_id=self.tenant_bar['id'], - role_id='member') - - def test_get_and_remove_role_grant_by_group_and_domain(self): - new_domain = unit.new_domain_ref() - self.resource_api.create_domain(new_domain['id'], new_domain) - new_group = unit.new_group_ref(domain_id=new_domain['id']) - new_group = self.identity_api.create_group(new_group) - new_user = unit.new_user_ref(domain_id=new_domain['id']) - new_user = self.identity_api.create_user(new_user) - self.identity_api.add_user_to_group(new_user['id'], - new_group['id']) - - roles_ref = self.assignment_api.list_grants( - group_id=new_group['id'], - domain_id=new_domain['id']) - self.assertEqual(0, len(roles_ref)) - - self.assignment_api.create_grant(group_id=new_group['id'], - domain_id=new_domain['id'], - role_id='member') - - roles_ref = self.assignment_api.list_grants( - group_id=new_group['id'], - domain_id=new_domain['id']) - self.assertDictEqual(self.role_member, roles_ref[0]) - - self.assignment_api.delete_grant(group_id=new_group['id'], - domain_id=new_domain['id'], - role_id='member') - roles_ref = self.assignment_api.list_grants( - group_id=new_group['id'], - domain_id=new_domain['id']) - self.assertEqual(0, len(roles_ref)) - self.assertRaises(exception.RoleAssignmentNotFound, - self.assignment_api.delete_grant, - group_id=new_group['id'], - domain_id=new_domain['id'], - role_id='member') - - def test_get_and_remove_correct_role_grant_from_a_mix(self): - new_domain = unit.new_domain_ref() - self.resource_api.create_domain(new_domain['id'], new_domain) - new_project = unit.new_project_ref(domain_id=new_domain['id']) - self.resource_api.create_project(new_project['id'], new_project) - new_group = unit.new_group_ref(domain_id=new_domain['id']) - new_group = self.identity_api.create_group(new_group) - new_group2 = unit.new_group_ref(domain_id=new_domain['id']) - new_group2 = self.identity_api.create_group(new_group2) - new_user = unit.new_user_ref(domain_id=new_domain['id']) - new_user = self.identity_api.create_user(new_user) - new_user2 = unit.new_user_ref(domain_id=new_domain['id']) - new_user2 = self.identity_api.create_user(new_user2) - self.identity_api.add_user_to_group(new_user['id'], - new_group['id']) - # First check we have no grants - roles_ref = self.assignment_api.list_grants( - group_id=new_group['id'], - domain_id=new_domain['id']) - self.assertEqual(0, len(roles_ref)) - # Now add the grant we are going to test for, and some others as - # well just to make sure we get back the right one - self.assignment_api.create_grant(group_id=new_group['id'], - domain_id=new_domain['id'], - role_id='member') - - self.assignment_api.create_grant(group_id=new_group2['id'], - domain_id=new_domain['id'], - role_id=self.role_admin['id']) - self.assignment_api.create_grant(user_id=new_user2['id'], - domain_id=new_domain['id'], - role_id=self.role_admin['id']) - self.assignment_api.create_grant(group_id=new_group['id'], - project_id=new_project['id'], - role_id=self.role_admin['id']) - - roles_ref = self.assignment_api.list_grants( - group_id=new_group['id'], - domain_id=new_domain['id']) - self.assertDictEqual(self.role_member, roles_ref[0]) - - self.assignment_api.delete_grant(group_id=new_group['id'], - domain_id=new_domain['id'], - role_id='member') - roles_ref = self.assignment_api.list_grants( - group_id=new_group['id'], - domain_id=new_domain['id']) - self.assertEqual(0, len(roles_ref)) - self.assertRaises(exception.RoleAssignmentNotFound, - self.assignment_api.delete_grant, - group_id=new_group['id'], - domain_id=new_domain['id'], - role_id='member') - - def test_get_and_remove_role_grant_by_user_and_domain(self): - new_domain = unit.new_domain_ref() - self.resource_api.create_domain(new_domain['id'], new_domain) - new_user = unit.new_user_ref(domain_id=new_domain['id']) - new_user = self.identity_api.create_user(new_user) - roles_ref = self.assignment_api.list_grants( - user_id=new_user['id'], - domain_id=new_domain['id']) - self.assertEqual(0, len(roles_ref)) - self.assignment_api.create_grant(user_id=new_user['id'], - domain_id=new_domain['id'], - role_id='member') - roles_ref = self.assignment_api.list_grants( - user_id=new_user['id'], - domain_id=new_domain['id']) - self.assertDictEqual(self.role_member, roles_ref[0]) - - self.assignment_api.delete_grant(user_id=new_user['id'], - domain_id=new_domain['id'], - role_id='member') - roles_ref = self.assignment_api.list_grants( - user_id=new_user['id'], - domain_id=new_domain['id']) - self.assertEqual(0, len(roles_ref)) - self.assertRaises(exception.RoleAssignmentNotFound, - self.assignment_api.delete_grant, - user_id=new_user['id'], - domain_id=new_domain['id'], - role_id='member') - - def test_get_and_remove_role_grant_by_group_and_cross_domain(self): - group1_domain1_role = unit.new_role_ref() - self.role_api.create_role(group1_domain1_role['id'], - group1_domain1_role) - group1_domain2_role = unit.new_role_ref() - self.role_api.create_role(group1_domain2_role['id'], - group1_domain2_role) - domain1 = unit.new_domain_ref() - self.resource_api.create_domain(domain1['id'], domain1) - domain2 = unit.new_domain_ref() - self.resource_api.create_domain(domain2['id'], domain2) - group1 = unit.new_group_ref(domain_id=domain1['id']) - group1 = self.identity_api.create_group(group1) - roles_ref = self.assignment_api.list_grants( - group_id=group1['id'], - domain_id=domain1['id']) - self.assertEqual(0, len(roles_ref)) - roles_ref = self.assignment_api.list_grants( - group_id=group1['id'], - domain_id=domain2['id']) - self.assertEqual(0, len(roles_ref)) - self.assignment_api.create_grant(group_id=group1['id'], - domain_id=domain1['id'], - role_id=group1_domain1_role['id']) - self.assignment_api.create_grant(group_id=group1['id'], - domain_id=domain2['id'], - role_id=group1_domain2_role['id']) - roles_ref = self.assignment_api.list_grants( - group_id=group1['id'], - domain_id=domain1['id']) - self.assertDictEqual(group1_domain1_role, roles_ref[0]) - roles_ref = self.assignment_api.list_grants( - group_id=group1['id'], - domain_id=domain2['id']) - self.assertDictEqual(group1_domain2_role, roles_ref[0]) - - self.assignment_api.delete_grant(group_id=group1['id'], - domain_id=domain2['id'], - role_id=group1_domain2_role['id']) - roles_ref = self.assignment_api.list_grants( - group_id=group1['id'], - domain_id=domain2['id']) - self.assertEqual(0, len(roles_ref)) - self.assertRaises(exception.RoleAssignmentNotFound, - self.assignment_api.delete_grant, - group_id=group1['id'], - domain_id=domain2['id'], - role_id=group1_domain2_role['id']) - - def test_get_and_remove_role_grant_by_user_and_cross_domain(self): - user1_domain1_role = unit.new_role_ref() - self.role_api.create_role(user1_domain1_role['id'], user1_domain1_role) - user1_domain2_role = unit.new_role_ref() - self.role_api.create_role(user1_domain2_role['id'], user1_domain2_role) - domain1 = unit.new_domain_ref() - self.resource_api.create_domain(domain1['id'], domain1) - domain2 = unit.new_domain_ref() - self.resource_api.create_domain(domain2['id'], domain2) - user1 = unit.new_user_ref(domain_id=domain1['id']) - user1 = self.identity_api.create_user(user1) - roles_ref = self.assignment_api.list_grants( - user_id=user1['id'], - domain_id=domain1['id']) - self.assertEqual(0, len(roles_ref)) - roles_ref = self.assignment_api.list_grants( - user_id=user1['id'], - domain_id=domain2['id']) - self.assertEqual(0, len(roles_ref)) - self.assignment_api.create_grant(user_id=user1['id'], - domain_id=domain1['id'], - role_id=user1_domain1_role['id']) - self.assignment_api.create_grant(user_id=user1['id'], - domain_id=domain2['id'], - role_id=user1_domain2_role['id']) - roles_ref = self.assignment_api.list_grants( - user_id=user1['id'], - domain_id=domain1['id']) - self.assertDictEqual(user1_domain1_role, roles_ref[0]) - roles_ref = self.assignment_api.list_grants( - user_id=user1['id'], - domain_id=domain2['id']) - self.assertDictEqual(user1_domain2_role, roles_ref[0]) - - self.assignment_api.delete_grant(user_id=user1['id'], - domain_id=domain2['id'], - role_id=user1_domain2_role['id']) - roles_ref = self.assignment_api.list_grants( - user_id=user1['id'], - domain_id=domain2['id']) - self.assertEqual(0, len(roles_ref)) - self.assertRaises(exception.RoleAssignmentNotFound, - self.assignment_api.delete_grant, - user_id=user1['id'], - domain_id=domain2['id'], - role_id=user1_domain2_role['id']) - - def test_role_grant_by_group_and_cross_domain_project(self): - role1 = unit.new_role_ref() - self.role_api.create_role(role1['id'], role1) - role2 = unit.new_role_ref() - self.role_api.create_role(role2['id'], role2) - domain1 = unit.new_domain_ref() - self.resource_api.create_domain(domain1['id'], domain1) - domain2 = unit.new_domain_ref() - self.resource_api.create_domain(domain2['id'], domain2) - group1 = unit.new_group_ref(domain_id=domain1['id']) - group1 = self.identity_api.create_group(group1) - project1 = unit.new_project_ref(domain_id=domain2['id']) - self.resource_api.create_project(project1['id'], project1) - roles_ref = self.assignment_api.list_grants( - group_id=group1['id'], - project_id=project1['id']) - self.assertEqual(0, len(roles_ref)) - self.assignment_api.create_grant(group_id=group1['id'], - project_id=project1['id'], - role_id=role1['id']) - self.assignment_api.create_grant(group_id=group1['id'], - project_id=project1['id'], - role_id=role2['id']) - roles_ref = self.assignment_api.list_grants( - group_id=group1['id'], - project_id=project1['id']) - - roles_ref_ids = [] - for ref in roles_ref: - roles_ref_ids.append(ref['id']) - self.assertIn(role1['id'], roles_ref_ids) - self.assertIn(role2['id'], roles_ref_ids) - - self.assignment_api.delete_grant(group_id=group1['id'], - project_id=project1['id'], - role_id=role1['id']) - roles_ref = self.assignment_api.list_grants( - group_id=group1['id'], - project_id=project1['id']) - self.assertEqual(1, len(roles_ref)) - self.assertDictEqual(role2, roles_ref[0]) - - def test_role_grant_by_user_and_cross_domain_project(self): - role1 = unit.new_role_ref() - self.role_api.create_role(role1['id'], role1) - role2 = unit.new_role_ref() - self.role_api.create_role(role2['id'], role2) - domain1 = unit.new_domain_ref() - self.resource_api.create_domain(domain1['id'], domain1) - domain2 = unit.new_domain_ref() - self.resource_api.create_domain(domain2['id'], domain2) - user1 = unit.new_user_ref(domain_id=domain1['id']) - user1 = self.identity_api.create_user(user1) - project1 = unit.new_project_ref(domain_id=domain2['id']) - self.resource_api.create_project(project1['id'], project1) - roles_ref = self.assignment_api.list_grants( - user_id=user1['id'], - project_id=project1['id']) - self.assertEqual(0, len(roles_ref)) - self.assignment_api.create_grant(user_id=user1['id'], - project_id=project1['id'], - role_id=role1['id']) - self.assignment_api.create_grant(user_id=user1['id'], - project_id=project1['id'], - role_id=role2['id']) - roles_ref = self.assignment_api.list_grants( - user_id=user1['id'], - project_id=project1['id']) - - roles_ref_ids = [] - for ref in roles_ref: - roles_ref_ids.append(ref['id']) - self.assertIn(role1['id'], roles_ref_ids) - self.assertIn(role2['id'], roles_ref_ids) - - self.assignment_api.delete_grant(user_id=user1['id'], - project_id=project1['id'], - role_id=role1['id']) - roles_ref = self.assignment_api.list_grants( - user_id=user1['id'], - project_id=project1['id']) - self.assertEqual(1, len(roles_ref)) - self.assertDictEqual(role2, roles_ref[0]) - - def test_delete_user_grant_no_user(self): - # Can delete a grant where the user doesn't exist. - role = unit.new_role_ref() - role_id = role['id'] - self.role_api.create_role(role_id, role) - - user_id = uuid.uuid4().hex - - self.assignment_api.create_grant(role_id, user_id=user_id, - project_id=self.tenant_bar['id']) - - self.assignment_api.delete_grant(role_id, user_id=user_id, - project_id=self.tenant_bar['id']) - - def test_delete_group_grant_no_group(self): - # Can delete a grant where the group doesn't exist. - role = unit.new_role_ref() - role_id = role['id'] - self.role_api.create_role(role_id, role) - - group_id = uuid.uuid4().hex - - self.assignment_api.create_grant(role_id, group_id=group_id, - project_id=self.tenant_bar['id']) - - self.assignment_api.delete_grant(role_id, group_id=group_id, - project_id=self.tenant_bar['id']) - - def test_grant_crud_throws_exception_if_invalid_role(self): - """Ensure RoleNotFound thrown if role does not exist.""" - def assert_role_not_found_exception(f, **kwargs): - self.assertRaises(exception.RoleNotFound, f, - role_id=uuid.uuid4().hex, **kwargs) - - user = unit.new_user_ref(domain_id=CONF.identity.default_domain_id) - user_resp = self.identity_api.create_user(user) - group = unit.new_group_ref(domain_id=CONF.identity.default_domain_id) - group_resp = self.identity_api.create_group(group) - project = unit.new_project_ref( - domain_id=CONF.identity.default_domain_id) - project_resp = self.resource_api.create_project(project['id'], project) - - for manager_call in [self.assignment_api.create_grant, - self.assignment_api.get_grant, - self.assignment_api.delete_grant]: - assert_role_not_found_exception( - manager_call, - user_id=user_resp['id'], project_id=project_resp['id']) - assert_role_not_found_exception( - manager_call, - group_id=group_resp['id'], project_id=project_resp['id']) - assert_role_not_found_exception( - manager_call, - user_id=user_resp['id'], - domain_id=CONF.identity.default_domain_id) - assert_role_not_found_exception( - manager_call, - group_id=group_resp['id'], - domain_id=CONF.identity.default_domain_id) - - def test_multi_role_grant_by_user_group_on_project_domain(self): - role_list = [] - for _ in range(10): - role = unit.new_role_ref() - self.role_api.create_role(role['id'], role) - role_list.append(role) - domain1 = unit.new_domain_ref() - self.resource_api.create_domain(domain1['id'], domain1) - user1 = unit.new_user_ref(domain_id=domain1['id']) - user1 = self.identity_api.create_user(user1) - group1 = unit.new_group_ref(domain_id=domain1['id']) - group1 = self.identity_api.create_group(group1) - group2 = unit.new_group_ref(domain_id=domain1['id']) - group2 = self.identity_api.create_group(group2) - project1 = unit.new_project_ref(domain_id=domain1['id']) - self.resource_api.create_project(project1['id'], project1) - - self.identity_api.add_user_to_group(user1['id'], - group1['id']) - self.identity_api.add_user_to_group(user1['id'], - group2['id']) - - roles_ref = self.assignment_api.list_grants( - user_id=user1['id'], - project_id=project1['id']) - self.assertEqual(0, len(roles_ref)) - self.assignment_api.create_grant(user_id=user1['id'], - domain_id=domain1['id'], - role_id=role_list[0]['id']) - self.assignment_api.create_grant(user_id=user1['id'], - domain_id=domain1['id'], - role_id=role_list[1]['id']) - self.assignment_api.create_grant(group_id=group1['id'], - domain_id=domain1['id'], - role_id=role_list[2]['id']) - self.assignment_api.create_grant(group_id=group1['id'], - domain_id=domain1['id'], - role_id=role_list[3]['id']) - self.assignment_api.create_grant(user_id=user1['id'], - project_id=project1['id'], - role_id=role_list[4]['id']) - self.assignment_api.create_grant(user_id=user1['id'], - project_id=project1['id'], - role_id=role_list[5]['id']) - self.assignment_api.create_grant(group_id=group1['id'], - project_id=project1['id'], - role_id=role_list[6]['id']) - self.assignment_api.create_grant(group_id=group1['id'], - project_id=project1['id'], - role_id=role_list[7]['id']) - roles_ref = self.assignment_api.list_grants(user_id=user1['id'], - domain_id=domain1['id']) - self.assertEqual(2, len(roles_ref)) - self.assertIn(role_list[0], roles_ref) - self.assertIn(role_list[1], roles_ref) - roles_ref = self.assignment_api.list_grants(group_id=group1['id'], - domain_id=domain1['id']) - self.assertEqual(2, len(roles_ref)) - self.assertIn(role_list[2], roles_ref) - self.assertIn(role_list[3], roles_ref) - roles_ref = self.assignment_api.list_grants(user_id=user1['id'], - project_id=project1['id']) - self.assertEqual(2, len(roles_ref)) - self.assertIn(role_list[4], roles_ref) - self.assertIn(role_list[5], roles_ref) - roles_ref = self.assignment_api.list_grants(group_id=group1['id'], - project_id=project1['id']) - self.assertEqual(2, len(roles_ref)) - self.assertIn(role_list[6], roles_ref) - self.assertIn(role_list[7], roles_ref) - - # Now test the alternate way of getting back lists of grants, - # where user and group roles are combined. These should match - # the above results. - combined_list = self.assignment_api.get_roles_for_user_and_project( - user1['id'], project1['id']) - self.assertEqual(4, len(combined_list)) - self.assertIn(role_list[4]['id'], combined_list) - self.assertIn(role_list[5]['id'], combined_list) - self.assertIn(role_list[6]['id'], combined_list) - self.assertIn(role_list[7]['id'], combined_list) - - combined_role_list = self.assignment_api.get_roles_for_user_and_domain( - user1['id'], domain1['id']) - self.assertEqual(4, len(combined_role_list)) - self.assertIn(role_list[0]['id'], combined_role_list) - self.assertIn(role_list[1]['id'], combined_role_list) - self.assertIn(role_list[2]['id'], combined_role_list) - self.assertIn(role_list[3]['id'], combined_role_list) - - def test_multi_group_grants_on_project_domain(self): - """Test multiple group roles for user on project and domain. - - Test Plan: - - - Create 6 roles - - Create a domain, with a project, user and two groups - - Make the user a member of both groups - - Check no roles yet exit - - Assign a role to each user and both groups on both the - project and domain - - Get a list of effective roles for the user on both the - project and domain, checking we get back the correct three - roles - - """ - role_list = [] - for _ in range(6): - role = unit.new_role_ref() - self.role_api.create_role(role['id'], role) - role_list.append(role) - domain1 = unit.new_domain_ref() - self.resource_api.create_domain(domain1['id'], domain1) - user1 = unit.new_user_ref(domain_id=domain1['id']) - user1 = self.identity_api.create_user(user1) - group1 = unit.new_group_ref(domain_id=domain1['id']) - group1 = self.identity_api.create_group(group1) - group2 = unit.new_group_ref(domain_id=domain1['id']) - group2 = self.identity_api.create_group(group2) - project1 = unit.new_project_ref(domain_id=domain1['id']) - self.resource_api.create_project(project1['id'], project1) - - self.identity_api.add_user_to_group(user1['id'], - group1['id']) - self.identity_api.add_user_to_group(user1['id'], - group2['id']) - - roles_ref = self.assignment_api.list_grants( - user_id=user1['id'], - project_id=project1['id']) - self.assertEqual(0, len(roles_ref)) - self.assignment_api.create_grant(user_id=user1['id'], - domain_id=domain1['id'], - role_id=role_list[0]['id']) - self.assignment_api.create_grant(group_id=group1['id'], - domain_id=domain1['id'], - role_id=role_list[1]['id']) - self.assignment_api.create_grant(group_id=group2['id'], - domain_id=domain1['id'], - role_id=role_list[2]['id']) - self.assignment_api.create_grant(user_id=user1['id'], - project_id=project1['id'], - role_id=role_list[3]['id']) - self.assignment_api.create_grant(group_id=group1['id'], - project_id=project1['id'], - role_id=role_list[4]['id']) - self.assignment_api.create_grant(group_id=group2['id'], - project_id=project1['id'], - role_id=role_list[5]['id']) - - # Read by the roles, ensuring we get the correct 3 roles for - # both project and domain - combined_list = self.assignment_api.get_roles_for_user_and_project( - user1['id'], project1['id']) - self.assertEqual(3, len(combined_list)) - self.assertIn(role_list[3]['id'], combined_list) - self.assertIn(role_list[4]['id'], combined_list) - self.assertIn(role_list[5]['id'], combined_list) - - combined_role_list = self.assignment_api.get_roles_for_user_and_domain( - user1['id'], domain1['id']) - self.assertEqual(3, len(combined_role_list)) - self.assertIn(role_list[0]['id'], combined_role_list) - self.assertIn(role_list[1]['id'], combined_role_list) - self.assertIn(role_list[2]['id'], combined_role_list) - - def test_delete_role_with_user_and_group_grants(self): - role1 = unit.new_role_ref() - self.role_api.create_role(role1['id'], role1) - domain1 = unit.new_domain_ref() - self.resource_api.create_domain(domain1['id'], domain1) - project1 = unit.new_project_ref(domain_id=domain1['id']) - self.resource_api.create_project(project1['id'], project1) - user1 = unit.new_user_ref(domain_id=domain1['id']) - user1 = self.identity_api.create_user(user1) - group1 = unit.new_group_ref(domain_id=domain1['id']) - group1 = self.identity_api.create_group(group1) - self.assignment_api.create_grant(user_id=user1['id'], - project_id=project1['id'], - role_id=role1['id']) - self.assignment_api.create_grant(user_id=user1['id'], - domain_id=domain1['id'], - role_id=role1['id']) - self.assignment_api.create_grant(group_id=group1['id'], - project_id=project1['id'], - role_id=role1['id']) - self.assignment_api.create_grant(group_id=group1['id'], - domain_id=domain1['id'], - role_id=role1['id']) - roles_ref = self.assignment_api.list_grants( - user_id=user1['id'], - project_id=project1['id']) - self.assertEqual(1, len(roles_ref)) - roles_ref = self.assignment_api.list_grants( - group_id=group1['id'], - project_id=project1['id']) - self.assertEqual(1, len(roles_ref)) - roles_ref = self.assignment_api.list_grants( - user_id=user1['id'], - domain_id=domain1['id']) - self.assertEqual(1, len(roles_ref)) - roles_ref = self.assignment_api.list_grants( - group_id=group1['id'], - domain_id=domain1['id']) - self.assertEqual(1, len(roles_ref)) - self.role_api.delete_role(role1['id']) - roles_ref = self.assignment_api.list_grants( - user_id=user1['id'], - project_id=project1['id']) - self.assertEqual(0, len(roles_ref)) - roles_ref = self.assignment_api.list_grants( - group_id=group1['id'], - project_id=project1['id']) - self.assertEqual(0, len(roles_ref)) - roles_ref = self.assignment_api.list_grants( - user_id=user1['id'], - domain_id=domain1['id']) - self.assertEqual(0, len(roles_ref)) - roles_ref = self.assignment_api.list_grants( - group_id=group1['id'], - domain_id=domain1['id']) - self.assertEqual(0, len(roles_ref)) - def test_delete_user_with_group_project_domain_links(self): role1 = unit.new_role_ref() self.role_api.create_role(role1['id'], role1) @@ -2030,254 +573,10 @@ class IdentityTests(AssignmentTestHelperMixin): self.identity_api.delete_group(group1['id']) self.identity_api.get_user(user1['id']) - def test_list_role_assignment_by_domain(self): - """Test listing of role assignment filtered by domain.""" - test_plan = { - # A domain with 3 users, 1 group, a spoiler domain and 2 roles. - 'entities': {'domains': [{'users': 3, 'groups': 1}, 1], - 'roles': 2}, - # Users 1 & 2 are in the group - 'group_memberships': [{'group': 0, 'users': [1, 2]}], - # Assign a role for user 0 and the group - 'assignments': [{'user': 0, 'role': 0, 'domain': 0}, - {'group': 0, 'role': 1, 'domain': 0}], - 'tests': [ - # List all effective assignments for domain[0]. - # Should get one direct user role and user roles for each of - # the users in the group. - {'params': {'domain': 0, 'effective': True}, - 'results': [{'user': 0, 'role': 0, 'domain': 0}, - {'user': 1, 'role': 1, 'domain': 0, - 'indirect': {'group': 0}}, - {'user': 2, 'role': 1, 'domain': 0, - 'indirect': {'group': 0}} - ]}, - # Using domain[1] should return nothing - {'params': {'domain': 1, 'effective': True}, - 'results': []}, - ] - } - self.execute_assignment_plan(test_plan) - - def test_list_role_assignment_by_user_with_domain_group_roles(self): - """Test listing assignments by user, with group roles on a domain.""" - test_plan = { - # A domain with 3 users, 3 groups, a spoiler domain - # plus 3 roles. - 'entities': {'domains': [{'users': 3, 'groups': 3}, 1], - 'roles': 3}, - # Users 1 & 2 are in the group 0, User 1 also in group 1 - 'group_memberships': [{'group': 0, 'users': [0, 1]}, - {'group': 1, 'users': [0]}], - 'assignments': [{'user': 0, 'role': 0, 'domain': 0}, - {'group': 0, 'role': 1, 'domain': 0}, - {'group': 1, 'role': 2, 'domain': 0}, - # ...and two spoiler assignments - {'user': 1, 'role': 1, 'domain': 0}, - {'group': 2, 'role': 2, 'domain': 0}], - 'tests': [ - # List all effective assignments for user[0]. - # Should get one direct user role and a user roles for each of - # groups 0 and 1 - {'params': {'user': 0, 'effective': True}, - 'results': [{'user': 0, 'role': 0, 'domain': 0}, - {'user': 0, 'role': 1, 'domain': 0, - 'indirect': {'group': 0}}, - {'user': 0, 'role': 2, 'domain': 0, - 'indirect': {'group': 1}} - ]}, - # Adding domain[0] as a filter should return the same data - {'params': {'user': 0, 'domain': 0, 'effective': True}, - 'results': [{'user': 0, 'role': 0, 'domain': 0}, - {'user': 0, 'role': 1, 'domain': 0, - 'indirect': {'group': 0}}, - {'user': 0, 'role': 2, 'domain': 0, - 'indirect': {'group': 1}} - ]}, - # Using domain[1] should return nothing - {'params': {'user': 0, 'domain': 1, 'effective': True}, - 'results': []}, - # Using user[2] should return nothing - {'params': {'user': 2, 'domain': 0, 'effective': True}, - 'results': []}, - ] - } - self.execute_assignment_plan(test_plan) - - def test_list_role_assignment_using_sourced_groups(self): - """Test listing assignments when restricted by source groups.""" - test_plan = { - # The default domain with 3 users, 3 groups, 3 projects, - # plus 3 roles. - 'entities': {'domains': {'id': CONF.identity.default_domain_id, - 'users': 3, 'groups': 3, 'projects': 3}, - 'roles': 3}, - # Users 0 & 1 are in the group 0, User 0 also in group 1 - 'group_memberships': [{'group': 0, 'users': [0, 1]}, - {'group': 1, 'users': [0]}], - # Spread the assignments around - we want to be able to show that - # if sourced by group, assignments from other sources are excluded - 'assignments': [{'user': 0, 'role': 0, 'project': 0}, - {'group': 0, 'role': 1, 'project': 1}, - {'group': 1, 'role': 2, 'project': 0}, - {'group': 1, 'role': 2, 'project': 1}, - {'user': 2, 'role': 1, 'project': 1}, - {'group': 2, 'role': 2, 'project': 2} - ], - 'tests': [ - # List all effective assignments sourced from groups 0 and 1 - {'params': {'source_from_group_ids': [0, 1], - 'effective': True}, - 'results': [{'group': 0, 'role': 1, 'project': 1}, - {'group': 1, 'role': 2, 'project': 0}, - {'group': 1, 'role': 2, 'project': 1} - ]}, - # Adding a role a filter should further restrict the entries - {'params': {'source_from_group_ids': [0, 1], 'role': 2, - 'effective': True}, - 'results': [{'group': 1, 'role': 2, 'project': 0}, - {'group': 1, 'role': 2, 'project': 1} - ]}, - ] - } - self.execute_assignment_plan(test_plan) - - def test_list_role_assignment_using_sourced_groups_with_domains(self): - """Test listing domain assignments when restricted by source groups.""" - test_plan = { - # A domain with 3 users, 3 groups, 3 projects, a second domain, - # plus 3 roles. - 'entities': {'domains': [{'users': 3, 'groups': 3, 'projects': 3}, - 1], - 'roles': 3}, - # Users 0 & 1 are in the group 0, User 0 also in group 1 - 'group_memberships': [{'group': 0, 'users': [0, 1]}, - {'group': 1, 'users': [0]}], - # Spread the assignments around - we want to be able to show that - # if sourced by group, assignments from other sources are excluded - 'assignments': [{'user': 0, 'role': 0, 'domain': 0}, - {'group': 0, 'role': 1, 'domain': 1}, - {'group': 1, 'role': 2, 'project': 0}, - {'group': 1, 'role': 2, 'project': 1}, - {'user': 2, 'role': 1, 'project': 1}, - {'group': 2, 'role': 2, 'project': 2} - ], - 'tests': [ - # List all effective assignments sourced from groups 0 and 1 - {'params': {'source_from_group_ids': [0, 1], - 'effective': True}, - 'results': [{'group': 0, 'role': 1, 'domain': 1}, - {'group': 1, 'role': 2, 'project': 0}, - {'group': 1, 'role': 2, 'project': 1} - ]}, - # Adding a role a filter should further restrict the entries - {'params': {'source_from_group_ids': [0, 1], 'role': 1, - 'effective': True}, - 'results': [{'group': 0, 'role': 1, 'domain': 1}, - ]}, - ] - } - self.execute_assignment_plan(test_plan) - - def test_list_role_assignment_fails_with_userid_and_source_groups(self): - """Show we trap this unsupported internal combination of params.""" - group = unit.new_group_ref(domain_id=CONF.identity.default_domain_id) - group = self.identity_api.create_group(group) - self.assertRaises(exception.UnexpectedError, - self.assignment_api.list_role_assignments, - effective=True, - user_id=self.user_foo['id'], - source_from_group_ids=[group['id']]) - def test_delete_domain_with_user_group_project_links(self): # TODO(chungg):add test case once expected behaviour defined pass - def test_add_user_to_project(self): - self.assignment_api.add_user_to_project(self.tenant_baz['id'], - self.user_foo['id']) - 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.role_api.delete_role(CONF.member_role_id) - self.assertRaises(exception.RoleNotFound, - self.role_api.get_role, - CONF.member_role_id) - self.assignment_api.add_user_to_project(self.tenant_baz['id'], - self.user_foo['id']) - tenants = ( - self.assignment_api.list_projects_for_user(self.user_foo['id'])) - self.assertIn(self.tenant_baz, tenants) - default_role = self.role_api.get_role(CONF.member_role_id) - self.assertIsNotNone(default_role) - - def test_add_user_to_project_returns_not_found(self): - self.assertRaises(exception.ProjectNotFound, - self.assignment_api.add_user_to_project, - uuid.uuid4().hex, - self.user_foo['id']) - - def test_add_user_to_project_no_user(self): - # If add_user_to_project and the user doesn't exist, then - # no error. - user_id_not_exist = uuid.uuid4().hex - self.assignment_api.add_user_to_project(self.tenant_bar['id'], - user_id_not_exist) - - def test_remove_user_from_project(self): - self.assignment_api.add_user_to_project(self.tenant_baz['id'], - self.user_foo['id']) - self.assignment_api.remove_user_from_project(self.tenant_baz['id'], - self.user_foo['id']) - tenants = self.assignment_api.list_projects_for_user( - self.user_foo['id']) - self.assertNotIn(self.tenant_baz, tenants) - - def test_remove_user_from_project_race_delete_role(self): - self.assignment_api.add_user_to_project(self.tenant_baz['id'], - self.user_foo['id']) - self.assignment_api.add_role_to_user_and_project( - tenant_id=self.tenant_baz['id'], - user_id=self.user_foo['id'], - role_id=self.role_other['id']) - - # Mock a race condition, delete a role after - # get_roles_for_user_and_project() is called in - # remove_user_from_project(). - roles = self.assignment_api.get_roles_for_user_and_project( - self.user_foo['id'], self.tenant_baz['id']) - self.role_api.delete_role(self.role_other['id']) - self.assignment_api.get_roles_for_user_and_project = mock.Mock( - return_value=roles) - self.assignment_api.remove_user_from_project(self.tenant_baz['id'], - self.user_foo['id']) - tenants = self.assignment_api.list_projects_for_user( - self.user_foo['id']) - self.assertNotIn(self.tenant_baz, tenants) - - def test_remove_user_from_project_returns_not_found(self): - self.assertRaises(exception.ProjectNotFound, - self.assignment_api.remove_user_from_project, - uuid.uuid4().hex, - self.user_foo['id']) - - self.assertRaises(exception.UserNotFound, - self.assignment_api.remove_user_from_project, - self.tenant_bar['id'], - uuid.uuid4().hex) - - self.assertRaises(exception.NotFound, - self.assignment_api.remove_user_from_project, - self.tenant_baz['id'], - self.user_foo['id']) - - def test_list_user_project_ids_returns_not_found(self): - self.assertRaises(exception.UserNotFound, - self.assignment_api.list_projects_for_user, - uuid.uuid4().hex) - def test_update_project_returns_not_found(self): self.assertRaises(exception.ProjectNotFound, self.resource_api.update_project, @@ -2297,38 +596,11 @@ class IdentityTests(AssignmentTestHelperMixin): {'id': user_id, 'domain_id': CONF.identity.default_domain_id}) - def test_delete_user_with_project_association(self): - user = unit.new_user_ref(domain_id=CONF.identity.default_domain_id) - user = self.identity_api.create_user(user) - self.assignment_api.add_user_to_project(self.tenant_bar['id'], - user['id']) - self.identity_api.delete_user(user['id']) - self.assertRaises(exception.UserNotFound, - self.assignment_api.list_projects_for_user, - user['id']) - - def test_delete_user_with_project_roles(self): - user = unit.new_user_ref(domain_id=CONF.identity.default_domain_id) - user = self.identity_api.create_user(user) - self.assignment_api.add_role_to_user_and_project( - user['id'], - self.tenant_bar['id'], - self.role_member['id']) - self.identity_api.delete_user(user['id']) - self.assertRaises(exception.UserNotFound, - self.assignment_api.list_projects_for_user, - user['id']) - def test_delete_user_returns_not_found(self): self.assertRaises(exception.UserNotFound, self.identity_api.delete_user, uuid.uuid4().hex) - def test_delete_role_returns_not_found(self): - self.assertRaises(exception.RoleNotFound, - self.role_api.delete_role, - uuid.uuid4().hex) - def test_create_update_delete_unicode_project(self): unicode_project_name = u'name \u540d\u5b57' project = unit.new_project_ref( @@ -3087,32 +1359,6 @@ class IdentityTests(AssignmentTestHelperMixin): self.resource_api.list_project_parents, uuid.uuid4().hex) - def test_delete_project_with_role_assignments(self): - project = unit.new_project_ref( - domain_id=CONF.identity.default_domain_id) - self.resource_api.create_project(project['id'], project) - self.assignment_api.add_role_to_user_and_project( - self.user_foo['id'], project['id'], 'member') - self.resource_api.delete_project(project['id']) - self.assertRaises(exception.NotFound, - self.resource_api.get_project, - project['id']) - - def test_delete_role_check_role_grant(self): - role = unit.new_role_ref() - alt_role = unit.new_role_ref() - self.role_api.create_role(role['id'], role) - self.role_api.create_role(alt_role['id'], alt_role) - self.assignment_api.add_role_to_user_and_project( - self.user_foo['id'], self.tenant_bar['id'], role['id']) - self.assignment_api.add_role_to_user_and_project( - self.user_foo['id'], self.tenant_bar['id'], alt_role['id']) - self.role_api.delete_role(role['id']) - roles_ref = self.assignment_api.get_roles_for_user_and_project( - self.user_foo['id'], self.tenant_bar['id']) - self.assertNotIn(role['id'], roles_ref) - self.assertIn(alt_role['id'], roles_ref) - def test_create_project_doesnt_modify_passed_in_dict(self): new_project = unit.new_project_ref( domain_id=CONF.identity.default_domain_id) @@ -4071,54 +2317,6 @@ class IdentityTests(AssignmentTestHelperMixin): self.identity_api.get_user, user['id']) - def test_list_projects_for_user(self): - domain = unit.new_domain_ref() - self.resource_api.create_domain(domain['id'], domain) - user1 = unit.new_user_ref(domain_id=domain['id']) - user1 = self.identity_api.create_user(user1) - user_projects = self.assignment_api.list_projects_for_user(user1['id']) - self.assertEqual(0, len(user_projects)) - self.assignment_api.create_grant(user_id=user1['id'], - project_id=self.tenant_bar['id'], - role_id=self.role_member['id']) - self.assignment_api.create_grant(user_id=user1['id'], - project_id=self.tenant_baz['id'], - role_id=self.role_member['id']) - user_projects = self.assignment_api.list_projects_for_user(user1['id']) - self.assertEqual(2, len(user_projects)) - - 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 = unit.new_domain_ref() - self.resource_api.create_domain(domain['id'], domain) - user1 = unit.new_user_ref(domain_id=domain['id']) - user1 = self.identity_api.create_user(user1) - group1 = unit.new_group_ref(domain_id=domain['id']) - group1 = self.identity_api.create_group(group1) - group2 = unit.new_group_ref(domain_id=domain['id']) - group2 = self.identity_api.create_group(group2) - project1 = unit.new_project_ref(domain_id=domain['id']) - self.resource_api.create_project(project1['id'], project1) - project2 = unit.new_project_ref(domain_id=domain['id']) - self.resource_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.assignment_api.create_grant(user_id=user1['id'], - project_id=self.tenant_bar['id'], - role_id=self.role_member['id']) - self.assignment_api.create_grant(group_id=group1['id'], - project_id=project1['id'], - role_id=self.role_admin['id']) - self.assignment_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.assertEqual(3, len(user_projects)) - @unit.skip_if_cache_disabled('resource') @unit.skip_if_no_multiple_domains_support def test_domain_rename_invalidates_get_domain_by_name_cache(self): @@ -4308,20 +2506,6 @@ class IdentityTests(AssignmentTestHelperMixin): self.assertEqual(new_attr_value, updated_user['arbitrary_attr']) - def test_create_grant_no_user(self): - # If call create_grant with a user that doesn't exist, doesn't fail. - self.assignment_api.create_grant( - self.role_other['id'], - user_id=uuid.uuid4().hex, - project_id=self.tenant_bar['id']) - - def test_create_grant_no_group(self): - # If call create_grant with a group that doesn't exist, doesn't fail. - self.assignment_api.create_grant( - self.role_other['id'], - group_id=uuid.uuid4().hex, - project_id=self.tenant_bar['id']) - @unit.skip_if_no_multiple_domains_support def test_get_default_domain_by_name(self): domain_name = 'default' @@ -4373,578 +2557,6 @@ class IdentityTests(AssignmentTestHelperMixin): user_ref = self.identity_api.get_user(user['id']) self.assertDictEqual(updated_user_ref, user_ref) - def test_delete_group_removes_role_assignments(self): - # When a group is deleted any role assignments for the group are - # removed. - - MEMBER_ROLE_ID = 'member' - - def get_member_assignments(): - assignments = self.assignment_api.list_role_assignments() - return [x for x in assignments if x['role_id'] == MEMBER_ROLE_ID] - - orig_member_assignments = get_member_assignments() - - # Create a group. - new_group = unit.new_group_ref( - domain_id=CONF.identity.default_domain_id) - new_group = self.identity_api.create_group(new_group) - - # Create a project. - new_project = unit.new_project_ref( - domain_id=CONF.identity.default_domain_id) - self.resource_api.create_project(new_project['id'], new_project) - - # Assign a role to the group. - self.assignment_api.create_grant( - group_id=new_group['id'], project_id=new_project['id'], - role_id=MEMBER_ROLE_ID) - - # Delete the group. - self.identity_api.delete_group(new_group['id']) - - # Check that the role assignment for the group is gone - member_assignments = get_member_assignments() - - self.assertThat(member_assignments, - matchers.Equals(orig_member_assignments)) - - def test_get_roles_for_groups_on_domain(self): - """Test retrieving group domain roles. - - Test Plan: - - - Create a domain, three groups and three roles - - Assign one an inherited and the others a non-inherited group role - to the domain - - Ensure that only the non-inherited roles are returned on the domain - - """ - domain1 = unit.new_domain_ref() - self.resource_api.create_domain(domain1['id'], domain1) - group_list = [] - group_id_list = [] - role_list = [] - for _ in range(3): - group = unit.new_group_ref(domain_id=domain1['id']) - group = self.identity_api.create_group(group) - group_list.append(group) - group_id_list.append(group['id']) - - role = unit.new_role_ref() - self.role_api.create_role(role['id'], role) - role_list.append(role) - - # Assign the roles - one is inherited - self.assignment_api.create_grant(group_id=group_list[0]['id'], - domain_id=domain1['id'], - role_id=role_list[0]['id']) - self.assignment_api.create_grant(group_id=group_list[1]['id'], - domain_id=domain1['id'], - role_id=role_list[1]['id']) - self.assignment_api.create_grant(group_id=group_list[2]['id'], - domain_id=domain1['id'], - role_id=role_list[2]['id'], - inherited_to_projects=True) - - # Now get the effective roles for the groups on the domain project. We - # shouldn't get back the inherited role. - - role_refs = self.assignment_api.get_roles_for_groups( - group_id_list, domain_id=domain1['id']) - - self.assertThat(role_refs, matchers.HasLength(2)) - self.assertIn(role_list[0], role_refs) - self.assertIn(role_list[1], role_refs) - - def test_get_roles_for_groups_on_project(self): - """Test retrieving group project roles. - - Test Plan: - - - Create two domains, two projects, six groups and six roles - - Project1 is in Domain1, Project2 is in Domain2 - - Domain2/Project2 are spoilers - - Assign a different direct group role to each project as well - as both an inherited and non-inherited role to each domain - - Get the group roles for Project 1 - depending on whether we have - enabled inheritance, we should either get back just the direct role - or both the direct one plus the inherited domain role from Domain 1 - - """ - domain1 = unit.new_domain_ref() - self.resource_api.create_domain(domain1['id'], domain1) - domain2 = unit.new_domain_ref() - self.resource_api.create_domain(domain2['id'], domain2) - project1 = unit.new_project_ref(domain_id=domain1['id']) - self.resource_api.create_project(project1['id'], project1) - project2 = unit.new_project_ref(domain_id=domain2['id']) - self.resource_api.create_project(project2['id'], project2) - group_list = [] - group_id_list = [] - role_list = [] - for _ in range(6): - group = unit.new_group_ref(domain_id=domain1['id']) - group = self.identity_api.create_group(group) - group_list.append(group) - group_id_list.append(group['id']) - - role = unit.new_role_ref() - self.role_api.create_role(role['id'], role) - role_list.append(role) - - # Assign the roles - one inherited and one non-inherited on Domain1, - # plus one on Project1 - self.assignment_api.create_grant(group_id=group_list[0]['id'], - domain_id=domain1['id'], - role_id=role_list[0]['id']) - self.assignment_api.create_grant(group_id=group_list[1]['id'], - domain_id=domain1['id'], - role_id=role_list[1]['id'], - inherited_to_projects=True) - self.assignment_api.create_grant(group_id=group_list[2]['id'], - project_id=project1['id'], - role_id=role_list[2]['id']) - - # ...and a duplicate set of spoiler assignments to Domain2/Project2 - self.assignment_api.create_grant(group_id=group_list[3]['id'], - domain_id=domain2['id'], - role_id=role_list[3]['id']) - self.assignment_api.create_grant(group_id=group_list[4]['id'], - domain_id=domain2['id'], - role_id=role_list[4]['id'], - inherited_to_projects=True) - self.assignment_api.create_grant(group_id=group_list[5]['id'], - project_id=project2['id'], - role_id=role_list[5]['id']) - - # Now get the effective roles for all groups on the Project1. With - # inheritance off, we should only get back the direct role. - - self.config_fixture.config(group='os_inherit', enabled=False) - role_refs = self.assignment_api.get_roles_for_groups( - group_id_list, project_id=project1['id']) - - self.assertThat(role_refs, matchers.HasLength(1)) - self.assertIn(role_list[2], role_refs) - - # With inheritance on, we should also get back the inherited role from - # its owning domain. - - self.config_fixture.config(group='os_inherit', enabled=True) - role_refs = self.assignment_api.get_roles_for_groups( - group_id_list, project_id=project1['id']) - - self.assertThat(role_refs, matchers.HasLength(2)) - self.assertIn(role_list[1], role_refs) - self.assertIn(role_list[2], role_refs) - - def test_list_domains_for_groups(self): - """Test retrieving domains for a list of groups. - - Test Plan: - - - Create three domains, three groups and one role - - Assign a non-inherited group role to two domains, and an inherited - group role to the third - - Ensure only the domains with non-inherited roles are returned - - """ - domain_list = [] - group_list = [] - group_id_list = [] - for _ in range(3): - domain = unit.new_domain_ref() - self.resource_api.create_domain(domain['id'], domain) - domain_list.append(domain) - - group = unit.new_group_ref(domain_id=domain['id']) - group = self.identity_api.create_group(group) - group_list.append(group) - group_id_list.append(group['id']) - - role1 = unit.new_role_ref() - self.role_api.create_role(role1['id'], role1) - - # Assign the roles - one is inherited - self.assignment_api.create_grant(group_id=group_list[0]['id'], - domain_id=domain_list[0]['id'], - role_id=role1['id']) - self.assignment_api.create_grant(group_id=group_list[1]['id'], - domain_id=domain_list[1]['id'], - role_id=role1['id']) - self.assignment_api.create_grant(group_id=group_list[2]['id'], - domain_id=domain_list[2]['id'], - role_id=role1['id'], - inherited_to_projects=True) - - # Now list the domains that have roles for any of the 3 groups - # We shouldn't get back domain[2] since that had an inherited role. - - domain_refs = ( - self.assignment_api.list_domains_for_groups(group_id_list)) - - self.assertThat(domain_refs, matchers.HasLength(2)) - self.assertIn(domain_list[0], domain_refs) - self.assertIn(domain_list[1], domain_refs) - - def test_list_projects_for_groups(self): - """Test retrieving projects for a list of groups. - - Test Plan: - - - Create two domains, four projects, seven groups and seven roles - - Project1-3 are in Domain1, Project4 is in Domain2 - - Domain2/Project4 are spoilers - - Project1 and 2 have direct group roles, Project3 has no direct - roles but should inherit a group role from Domain1 - - Get the projects for the group roles that are assigned to Project1 - Project2 and the inherited one on Domain1. Depending on whether we - have enabled inheritance, we should either get back just the projects - with direct roles (Project 1 and 2) or also Project3 due to its - inherited role from Domain1. - - """ - domain1 = unit.new_domain_ref() - self.resource_api.create_domain(domain1['id'], domain1) - domain2 = unit.new_domain_ref() - self.resource_api.create_domain(domain2['id'], domain2) - project1 = unit.new_project_ref(domain_id=domain1['id']) - project1 = self.resource_api.create_project(project1['id'], project1) - project2 = unit.new_project_ref(domain_id=domain1['id']) - project2 = self.resource_api.create_project(project2['id'], project2) - project3 = unit.new_project_ref(domain_id=domain1['id']) - project3 = self.resource_api.create_project(project3['id'], project3) - project4 = unit.new_project_ref(domain_id=domain2['id']) - project4 = self.resource_api.create_project(project4['id'], project4) - group_list = [] - role_list = [] - for _ in range(7): - group = unit.new_group_ref(domain_id=domain1['id']) - group = self.identity_api.create_group(group) - group_list.append(group) - - role = unit.new_role_ref() - self.role_api.create_role(role['id'], role) - role_list.append(role) - - # Assign the roles - one inherited and one non-inherited on Domain1, - # plus one on Project1 and Project2 - self.assignment_api.create_grant(group_id=group_list[0]['id'], - domain_id=domain1['id'], - role_id=role_list[0]['id']) - self.assignment_api.create_grant(group_id=group_list[1]['id'], - domain_id=domain1['id'], - role_id=role_list[1]['id'], - inherited_to_projects=True) - self.assignment_api.create_grant(group_id=group_list[2]['id'], - project_id=project1['id'], - role_id=role_list[2]['id']) - self.assignment_api.create_grant(group_id=group_list[3]['id'], - project_id=project2['id'], - role_id=role_list[3]['id']) - - # ...and a few of spoiler assignments to Domain2/Project4 - self.assignment_api.create_grant(group_id=group_list[4]['id'], - domain_id=domain2['id'], - role_id=role_list[4]['id']) - self.assignment_api.create_grant(group_id=group_list[5]['id'], - domain_id=domain2['id'], - role_id=role_list[5]['id'], - inherited_to_projects=True) - self.assignment_api.create_grant(group_id=group_list[6]['id'], - project_id=project4['id'], - role_id=role_list[6]['id']) - - # Now get the projects for the groups that have roles on Project1, - # Project2 and the inherited role on Domain!. With inheritance off, - # we should only get back the projects with direct role. - - self.config_fixture.config(group='os_inherit', enabled=False) - group_id_list = [group_list[1]['id'], group_list[2]['id'], - group_list[3]['id']] - project_refs = ( - self.assignment_api.list_projects_for_groups(group_id_list)) - - self.assertThat(project_refs, matchers.HasLength(2)) - self.assertIn(project1, project_refs) - self.assertIn(project2, project_refs) - - # With inheritance on, we should also get back the Project3 due to the - # inherited role from its owning domain. - - self.config_fixture.config(group='os_inherit', enabled=True) - project_refs = ( - self.assignment_api.list_projects_for_groups(group_id_list)) - - self.assertThat(project_refs, matchers.HasLength(3)) - self.assertIn(project1, project_refs) - self.assertIn(project2, project_refs) - self.assertIn(project3, project_refs) - - def test_update_role_no_name(self): - # A user can update a role and not include the name. - - # description is picked just because it's not name. - self.role_api.update_role(self.role_member['id'], - {'description': uuid.uuid4().hex}) - # If the previous line didn't raise an exception then the test passes. - - def test_update_role_same_name(self): - # A user can update a role and set the name to be the same as it was. - - self.role_api.update_role(self.role_member['id'], - {'name': self.role_member['name']}) - # If the previous line didn't raise an exception then the test passes. - - def test_list_role_assignment_containing_names(self): - # Create Refs - new_role = unit.new_role_ref() - new_domain = self._get_domain_fixture() - new_user = unit.new_user_ref(domain_id=new_domain['id']) - new_project = unit.new_project_ref(domain_id=new_domain['id']) - new_group = unit.new_group_ref(domain_id=new_domain['id']) - # Create entities - new_role = self.role_api.create_role(new_role['id'], new_role) - new_user = self.identity_api.create_user(new_user) - new_group = self.identity_api.create_group(new_group) - self.resource_api.create_project(new_project['id'], new_project) - self.assignment_api.create_grant(user_id=new_user['id'], - project_id=new_project['id'], - role_id=new_role['id']) - self.assignment_api.create_grant(group_id=new_group['id'], - project_id=new_project['id'], - role_id=new_role['id']) - self.assignment_api.create_grant(domain_id=new_domain['id'], - user_id=new_user['id'], - role_id=new_role['id']) - # Get the created assignments with the include_names flag - _asgmt_prj = self.assignment_api.list_role_assignments( - user_id=new_user['id'], - project_id=new_project['id'], - include_names=True) - _asgmt_grp = self.assignment_api.list_role_assignments( - group_id=new_group['id'], - project_id=new_project['id'], - include_names=True) - _asgmt_dmn = self.assignment_api.list_role_assignments( - domain_id=new_domain['id'], - user_id=new_user['id'], - include_names=True) - # Make sure we can get back the correct number of assignments - self.assertThat(_asgmt_prj, matchers.HasLength(1)) - self.assertThat(_asgmt_grp, matchers.HasLength(1)) - self.assertThat(_asgmt_dmn, matchers.HasLength(1)) - # get the first assignment - first_asgmt_prj = _asgmt_prj[0] - first_asgmt_grp = _asgmt_grp[0] - first_asgmt_dmn = _asgmt_dmn[0] - # Assert the names are correct in the project response - self.assertEqual(new_project['name'], - first_asgmt_prj['project_name']) - self.assertEqual(new_project['domain_id'], - first_asgmt_prj['project_domain_id']) - self.assertEqual(new_user['name'], - first_asgmt_prj['user_name']) - self.assertEqual(new_user['domain_id'], - first_asgmt_prj['user_domain_id']) - self.assertEqual(new_role['name'], - first_asgmt_prj['role_name']) - # Assert the names are correct in the group response - self.assertEqual(new_group['name'], - first_asgmt_grp['group_name']) - self.assertEqual(new_group['domain_id'], - first_asgmt_grp['group_domain_id']) - self.assertEqual(new_project['name'], - first_asgmt_grp['project_name']) - self.assertEqual(new_project['domain_id'], - first_asgmt_grp['project_domain_id']) - self.assertEqual(new_role['name'], - first_asgmt_grp['role_name']) - # Assert the names are correct in the domain response - self.assertEqual(new_domain['name'], - first_asgmt_dmn['domain_name']) - self.assertEqual(new_user['name'], - first_asgmt_dmn['user_name']) - self.assertEqual(new_user['domain_id'], - first_asgmt_dmn['user_domain_id']) - self.assertEqual(new_role['name'], - first_asgmt_dmn['role_name']) - - def test_list_role_assignment_does_not_contain_names(self): - """Test names are not included with list role assignments. - - Scenario: - - names are NOT included by default - - names are NOT included when include_names=False - - """ - def assert_does_not_contain_names(assignment): - first_asgmt_prj = assignment[0] - self.assertNotIn('project_name', first_asgmt_prj) - self.assertNotIn('project_domain_id', first_asgmt_prj) - self.assertNotIn('user_name', first_asgmt_prj) - self.assertNotIn('user_domain_id', first_asgmt_prj) - self.assertNotIn('role_name', first_asgmt_prj) - - # Create Refs - new_role = unit.new_role_ref() - new_domain = self._get_domain_fixture() - new_user = unit.new_user_ref(domain_id=new_domain['id']) - new_project = unit.new_project_ref(domain_id=new_domain['id']) - # Create entities - new_role = self.role_api.create_role(new_role['id'], new_role) - new_user = self.identity_api.create_user(new_user) - self.resource_api.create_project(new_project['id'], new_project) - self.assignment_api.create_grant(user_id=new_user['id'], - project_id=new_project['id'], - role_id=new_role['id']) - # Get the created assignments with NO include_names flag - role_assign_without_names = self.assignment_api.list_role_assignments( - user_id=new_user['id'], - project_id=new_project['id']) - assert_does_not_contain_names(role_assign_without_names) - # Get the created assignments with include_names=False - role_assign_without_names = self.assignment_api.list_role_assignments( - user_id=new_user['id'], - project_id=new_project['id'], - include_names=False) - assert_does_not_contain_names(role_assign_without_names) - - def test_delete_user_assignments_user_same_id_as_group(self): - """Test deleting user assignments when user_id == group_id. - - In this scenario, only user assignments must be deleted (i.e. - USER_DOMAIN or USER_PROJECT). - - Test plan: - * Create a user and a group with the same ID; - * Create four roles and assign them to both user and group; - * Delete all user assignments; - * Group assignments must stay intact. - """ - # Create a common ID - common_id = uuid.uuid4().hex - # Create a project - project = unit.new_project_ref( - domain_id=CONF.identity.default_domain_id) - project = self.resource_api.create_project(project['id'], project) - # Create a user - user = unit.new_user_ref(id=common_id, - domain_id=CONF.identity.default_domain_id) - user = self.identity_api.driver.create_user(common_id, user) - self.assertEqual(common_id, user['id']) - # Create a group - group = unit.new_group_ref(id=common_id, - domain_id=CONF.identity.default_domain_id) - group = self.identity_api.driver.create_group(common_id, group) - self.assertEqual(common_id, group['id']) - # Create four roles - roles = [] - for _ in range(4): - role = unit.new_role_ref() - roles.append(self.role_api.create_role(role['id'], role)) - # Assign roles for user - self.assignment_api.driver.create_grant( - user_id=user['id'], domain_id=CONF.identity.default_domain_id, - role_id=roles[0]['id']) - self.assignment_api.driver.create_grant(user_id=user['id'], - project_id=project['id'], - role_id=roles[1]['id']) - # Assign roles for group - self.assignment_api.driver.create_grant( - group_id=group['id'], domain_id=CONF.identity.default_domain_id, - role_id=roles[2]['id']) - self.assignment_api.driver.create_grant(group_id=group['id'], - project_id=project['id'], - role_id=roles[3]['id']) - # Make sure they were assigned - user_assignments = self.assignment_api.list_role_assignments( - user_id=user['id']) - self.assertThat(user_assignments, matchers.HasLength(2)) - group_assignments = self.assignment_api.list_role_assignments( - group_id=group['id']) - self.assertThat(group_assignments, matchers.HasLength(2)) - # Delete user assignments - self.assignment_api.delete_user_assignments(user_id=user['id']) - # Assert only user assignments were deleted - user_assignments = self.assignment_api.list_role_assignments( - user_id=user['id']) - self.assertThat(user_assignments, matchers.HasLength(0)) - group_assignments = self.assignment_api.list_role_assignments( - group_id=group['id']) - self.assertThat(group_assignments, matchers.HasLength(2)) - # Make sure these remaining assignments are group-related - for assignment in group_assignments: - self.assertThat(assignment.keys(), matchers.Contains('group_id')) - - def test_delete_group_assignments_group_same_id_as_user(self): - """Test deleting group assignments when group_id == user_id. - - In this scenario, only group assignments must be deleted (i.e. - GROUP_DOMAIN or GROUP_PROJECT). - - Test plan: - * Create a group and a user with the same ID; - * Create four roles and assign them to both group and user; - * Delete all group assignments; - * User assignments must stay intact. - """ - # Create a common ID - common_id = uuid.uuid4().hex - # Create a project - project = unit.new_project_ref( - domain_id=CONF.identity.default_domain_id) - project = self.resource_api.create_project(project['id'], project) - # Create a user - user = unit.new_user_ref(id=common_id, - domain_id=CONF.identity.default_domain_id) - user = self.identity_api.driver.create_user(common_id, user) - self.assertEqual(common_id, user['id']) - # Create a group - group = unit.new_group_ref(id=common_id, - domain_id=CONF.identity.default_domain_id) - group = self.identity_api.driver.create_group(common_id, group) - self.assertEqual(common_id, group['id']) - # Create four roles - roles = [] - for _ in range(4): - role = unit.new_role_ref() - roles.append(self.role_api.create_role(role['id'], role)) - # Assign roles for user - self.assignment_api.driver.create_grant( - user_id=user['id'], domain_id=CONF.identity.default_domain_id, - role_id=roles[0]['id']) - self.assignment_api.driver.create_grant(user_id=user['id'], - project_id=project['id'], - role_id=roles[1]['id']) - # Assign roles for group - self.assignment_api.driver.create_grant( - group_id=group['id'], domain_id=CONF.identity.default_domain_id, - role_id=roles[2]['id']) - self.assignment_api.driver.create_grant(group_id=group['id'], - project_id=project['id'], - role_id=roles[3]['id']) - # Make sure they were assigned - user_assignments = self.assignment_api.list_role_assignments( - user_id=user['id']) - self.assertThat(user_assignments, matchers.HasLength(2)) - group_assignments = self.assignment_api.list_role_assignments( - group_id=group['id']) - self.assertThat(group_assignments, matchers.HasLength(2)) - # Delete group assignments - self.assignment_api.delete_group_assignments(group_id=group['id']) - # Assert only group assignments were deleted - group_assignments = self.assignment_api.list_role_assignments( - group_id=group['id']) - self.assertThat(group_assignments, matchers.HasLength(0)) - user_assignments = self.assignment_api.list_role_assignments( - user_id=user['id']) - self.assertThat(user_assignments, matchers.HasLength(2)) - # Make sure these remaining assignments are user-related - for assignment in group_assignments: - self.assertThat(assignment.keys(), matchers.Contains('user_id')) - class TokenTests(object): def _create_token_id(self): @@ -6254,1296 +3866,6 @@ class PolicyTests(object): uuid.uuid4().hex) -class InheritanceTests(AssignmentTestHelperMixin): - - def test_role_assignments_user_domain_to_project_inheritance(self): - test_plan = { - 'entities': {'domains': {'users': 2, 'projects': 1}, - 'roles': 3}, - 'assignments': [{'user': 0, 'role': 0, 'domain': 0}, - {'user': 0, 'role': 1, 'project': 0}, - {'user': 0, 'role': 2, 'domain': 0, - 'inherited_to_projects': True}, - {'user': 1, 'role': 1, 'project': 0}], - 'tests': [ - # List all direct assignments for user[0] - {'params': {'user': 0}, - 'results': [{'user': 0, 'role': 0, 'domain': 0}, - {'user': 0, 'role': 1, 'project': 0}, - {'user': 0, 'role': 2, 'domain': 0, - 'inherited_to_projects': 'projects'}]}, - # Now the effective ones - so the domain role should turn into - # a project role - {'params': {'user': 0, 'effective': True}, - 'results': [{'user': 0, 'role': 0, 'domain': 0}, - {'user': 0, 'role': 1, 'project': 0}, - {'user': 0, 'role': 2, 'project': 0, - 'indirect': {'domain': 0}}]}, - # Narrow down to effective roles for user[0] and project[0] - {'params': {'user': 0, 'project': 0, 'effective': True}, - 'results': [{'user': 0, 'role': 1, 'project': 0}, - {'user': 0, 'role': 2, 'project': 0, - 'indirect': {'domain': 0}}]} - ] - } - self.config_fixture.config(group='os_inherit', enabled=True) - self.execute_assignment_plan(test_plan) - - def test_inherited_role_assignments_excluded_if_os_inherit_false(self): - test_plan = { - 'entities': {'domains': {'users': 2, 'groups': 1, 'projects': 1}, - 'roles': 4}, - 'group_memberships': [{'group': 0, 'users': [0]}], - 'assignments': [{'user': 0, 'role': 0, 'domain': 0}, - {'user': 0, 'role': 1, 'project': 0}, - {'user': 0, 'role': 2, 'domain': 0, - 'inherited_to_projects': True}, - {'user': 1, 'role': 1, 'project': 0}, - {'group': 0, 'role': 3, 'project': 0}], - 'tests': [ - # List all direct assignments for user[0], since os-inherit is - # disabled, we should not see the inherited role - {'params': {'user': 0}, - 'results': [{'user': 0, 'role': 0, 'domain': 0}, - {'user': 0, 'role': 1, 'project': 0}]}, - # Same in effective mode - inherited roles should not be - # included or expanded...but the group role should now - # turn up as a user role, since group expansion is not - # part of os-inherit. - {'params': {'user': 0, 'effective': True}, - 'results': [{'user': 0, 'role': 0, 'domain': 0}, - {'user': 0, 'role': 1, 'project': 0}, - {'user': 0, 'role': 3, 'project': 0, - 'indirect': {'group': 0}}]}, - ] - } - self.config_fixture.config(group='os_inherit', enabled=False) - self.execute_assignment_plan(test_plan) - - def _test_crud_inherited_and_direct_assignment(self, **kwargs): - """Tests inherited and direct assignments for the actor and target - - Ensure it is possible to create both inherited and direct role - assignments for the same actor on the same target. The actor and the - target are specified in the kwargs as ('user_id' or 'group_id') and - ('project_id' or 'domain_id'), respectively. - - """ - self.config_fixture.config(group='os_inherit', enabled=True) - # Create a new role to avoid assignments loaded from default fixtures - role = unit.new_role_ref() - role = self.role_api.create_role(role['id'], role) - - # Define the common assignment entity - assignment_entity = {'role_id': role['id']} - assignment_entity.update(kwargs) - - # Define assignments under test - direct_assignment_entity = assignment_entity.copy() - inherited_assignment_entity = assignment_entity.copy() - inherited_assignment_entity['inherited_to_projects'] = 'projects' - - # Create direct assignment and check grants - self.assignment_api.create_grant(inherited_to_projects=False, - **assignment_entity) - - grants = self.assignment_api.list_role_assignments(role_id=role['id']) - self.assertThat(grants, matchers.HasLength(1)) - self.assertIn(direct_assignment_entity, grants) - - # Now add inherited assignment and check grants - self.assignment_api.create_grant(inherited_to_projects=True, - **assignment_entity) - - grants = self.assignment_api.list_role_assignments(role_id=role['id']) - self.assertThat(grants, matchers.HasLength(2)) - self.assertIn(direct_assignment_entity, grants) - self.assertIn(inherited_assignment_entity, grants) - - # Delete both and check grants - self.assignment_api.delete_grant(inherited_to_projects=False, - **assignment_entity) - self.assignment_api.delete_grant(inherited_to_projects=True, - **assignment_entity) - - grants = self.assignment_api.list_role_assignments(role_id=role['id']) - self.assertEqual([], grants) - - def test_crud_inherited_and_direct_assignment_for_user_on_domain(self): - self._test_crud_inherited_and_direct_assignment( - user_id=self.user_foo['id'], - domain_id=CONF.identity.default_domain_id) - - def test_crud_inherited_and_direct_assignment_for_group_on_domain(self): - group = unit.new_group_ref(domain_id=CONF.identity.default_domain_id) - group = self.identity_api.create_group(group) - - self._test_crud_inherited_and_direct_assignment( - group_id=group['id'], domain_id=CONF.identity.default_domain_id) - - def test_crud_inherited_and_direct_assignment_for_user_on_project(self): - self._test_crud_inherited_and_direct_assignment( - user_id=self.user_foo['id'], project_id=self.tenant_baz['id']) - - def test_crud_inherited_and_direct_assignment_for_group_on_project(self): - group = unit.new_group_ref(domain_id=CONF.identity.default_domain_id) - group = self.identity_api.create_group(group) - - self._test_crud_inherited_and_direct_assignment( - group_id=group['id'], project_id=self.tenant_baz['id']) - - def test_inherited_role_grants_for_user(self): - """Test inherited user roles. - - Test Plan: - - - Enable OS-INHERIT extension - - Create 3 roles - - Create a domain, with a project and a user - - Check no roles yet exit - - Assign a direct user role to the project and a (non-inherited) - user role to the domain - - Get a list of effective roles - should only get the one direct role - - Now add an inherited user role to the domain - - Get a list of effective roles - should have two roles, one - direct and one by virtue of the inherited user role - - Also get effective roles for the domain - the role marked as - inherited should not show up - - """ - self.config_fixture.config(group='os_inherit', enabled=True) - role_list = [] - for _ in range(3): - role = unit.new_role_ref() - self.role_api.create_role(role['id'], role) - role_list.append(role) - domain1 = unit.new_domain_ref() - self.resource_api.create_domain(domain1['id'], domain1) - user1 = unit.new_user_ref(domain_id=domain1['id']) - user1 = self.identity_api.create_user(user1) - project1 = unit.new_project_ref(domain_id=domain1['id']) - self.resource_api.create_project(project1['id'], project1) - - roles_ref = self.assignment_api.list_grants( - user_id=user1['id'], - project_id=project1['id']) - self.assertEqual(0, len(roles_ref)) - - # Create the first two roles - the domain one is not inherited - self.assignment_api.create_grant(user_id=user1['id'], - project_id=project1['id'], - role_id=role_list[0]['id']) - self.assignment_api.create_grant(user_id=user1['id'], - domain_id=domain1['id'], - role_id=role_list[1]['id']) - - # Now get the effective roles for the user and project, this - # should only include the direct role assignment on the project - combined_list = self.assignment_api.get_roles_for_user_and_project( - user1['id'], project1['id']) - self.assertEqual(1, len(combined_list)) - self.assertIn(role_list[0]['id'], combined_list) - - # Now add an inherited role on the domain - self.assignment_api.create_grant(user_id=user1['id'], - domain_id=domain1['id'], - role_id=role_list[2]['id'], - inherited_to_projects=True) - - # Now get the effective roles for the user and project again, this - # should now include the inherited role on the domain - combined_list = self.assignment_api.get_roles_for_user_and_project( - user1['id'], project1['id']) - self.assertEqual(2, len(combined_list)) - self.assertIn(role_list[0]['id'], combined_list) - self.assertIn(role_list[2]['id'], combined_list) - - # Finally, check that the inherited role does not appear as a valid - # directly assigned role on the domain itself - combined_role_list = self.assignment_api.get_roles_for_user_and_domain( - user1['id'], domain1['id']) - self.assertEqual(1, len(combined_role_list)) - self.assertIn(role_list[1]['id'], combined_role_list) - - # TODO(henry-nash): The test above uses get_roles_for_user_and_project - # and get_roles_for_user_and_domain, which will, in a subsequent patch, - # be re-implemented to simply call list_role_assignments (see blueprint - # remove-role-metadata). - # - # The test plan below therefore mirrors this test, to ensure that - # list_role_assignments works the same. Once get_roles_for_user_and - # project/domain have been re-implemented then the manual tests above - # can be refactored to simply ensure it gives the same answers. - test_plan = { - # A domain with a user & project, plus 3 roles. - 'entities': {'domains': {'users': 1, 'projects': 1}, - 'roles': 3}, - 'assignments': [{'user': 0, 'role': 0, 'project': 0}, - {'user': 0, 'role': 1, 'domain': 0}, - {'user': 0, 'role': 2, 'domain': 0, - 'inherited_to_projects': True}], - 'tests': [ - # List all effective assignments for user[0] on project[0]. - # Should get one direct role and one inherited role. - {'params': {'user': 0, 'project': 0, 'effective': True}, - 'results': [{'user': 0, 'role': 0, 'project': 0}, - {'user': 0, 'role': 2, 'project': 0, - 'indirect': {'domain': 0}}]}, - # Ensure effective mode on the domain does not list the - # inherited role on that domain - {'params': {'user': 0, 'domain': 0, 'effective': True}, - 'results': [{'user': 0, 'role': 1, 'domain': 0}]}, - # Ensure non-inherited mode also only returns the non-inherited - # role on the domain - {'params': {'user': 0, 'domain': 0, 'inherited': False}, - 'results': [{'user': 0, 'role': 1, 'domain': 0}]}, - ] - } - self.execute_assignment_plan(test_plan) - - def test_inherited_role_grants_for_group(self): - """Test inherited group roles. - - Test Plan: - - - Enable OS-INHERIT extension - - Create 4 roles - - Create a domain, with a project, user and two groups - - Make the user a member of both groups - - Check no roles yet exit - - Assign a direct user role to the project and a (non-inherited) - group role on the domain - - Get a list of effective roles - should only get the one direct role - - Now add two inherited group roles to the domain - - Get a list of effective roles - should have three roles, one - direct and two by virtue of inherited group roles - - """ - self.config_fixture.config(group='os_inherit', enabled=True) - role_list = [] - for _ in range(4): - role = unit.new_role_ref() - self.role_api.create_role(role['id'], role) - role_list.append(role) - domain1 = unit.new_domain_ref() - self.resource_api.create_domain(domain1['id'], domain1) - user1 = unit.new_user_ref(domain_id=domain1['id']) - user1 = self.identity_api.create_user(user1) - group1 = unit.new_group_ref(domain_id=domain1['id']) - group1 = self.identity_api.create_group(group1) - group2 = unit.new_group_ref(domain_id=domain1['id']) - group2 = self.identity_api.create_group(group2) - project1 = unit.new_project_ref(domain_id=domain1['id']) - self.resource_api.create_project(project1['id'], project1) - - self.identity_api.add_user_to_group(user1['id'], - group1['id']) - self.identity_api.add_user_to_group(user1['id'], - group2['id']) - - roles_ref = self.assignment_api.list_grants( - user_id=user1['id'], - project_id=project1['id']) - self.assertEqual(0, len(roles_ref)) - - # Create two roles - the domain one is not inherited - self.assignment_api.create_grant(user_id=user1['id'], - project_id=project1['id'], - role_id=role_list[0]['id']) - self.assignment_api.create_grant(group_id=group1['id'], - domain_id=domain1['id'], - role_id=role_list[1]['id']) - - # Now get the effective roles for the user and project, this - # should only include the direct role assignment on the project - combined_list = self.assignment_api.get_roles_for_user_and_project( - user1['id'], project1['id']) - self.assertEqual(1, len(combined_list)) - self.assertIn(role_list[0]['id'], combined_list) - - # Now add to more group roles, both inherited, to the domain - self.assignment_api.create_grant(group_id=group2['id'], - domain_id=domain1['id'], - role_id=role_list[2]['id'], - inherited_to_projects=True) - self.assignment_api.create_grant(group_id=group2['id'], - domain_id=domain1['id'], - role_id=role_list[3]['id'], - inherited_to_projects=True) - - # Now get the effective roles for the user and project again, this - # should now include the inherited roles on the domain - combined_list = self.assignment_api.get_roles_for_user_and_project( - user1['id'], project1['id']) - self.assertEqual(3, len(combined_list)) - self.assertIn(role_list[0]['id'], combined_list) - self.assertIn(role_list[2]['id'], combined_list) - self.assertIn(role_list[3]['id'], combined_list) - - # TODO(henry-nash): The test above uses get_roles_for_user_and_project - # which will, in a subsequent patch, be re-implemented to simply call - # list_role_assignments (see blueprint remove-role-metadata). - # - # The test plan below therefore mirrors this test, to ensure that - # list_role_assignments works the same. Once - # get_roles_for_user_and_project has been re-implemented then the - # manual tests above can be refactored to simply ensure it gives - # the same answers. - test_plan = { - # A domain with a user and project, 2 groups, plus 4 roles. - 'entities': {'domains': {'users': 1, 'projects': 1, 'groups': 2}, - 'roles': 4}, - 'group_memberships': [{'group': 0, 'users': [0]}, - {'group': 1, 'users': [0]}], - 'assignments': [{'user': 0, 'role': 0, 'project': 0}, - {'group': 0, 'role': 1, 'domain': 0}, - {'group': 1, 'role': 2, 'domain': 0, - 'inherited_to_projects': True}, - {'group': 1, 'role': 3, 'domain': 0, - 'inherited_to_projects': True}], - 'tests': [ - # List all effective assignments for user[0] on project[0]. - # Should get one direct role and both inherited roles, but - # not the direct one on domain[0], even though user[0] is - # in group[0]. - {'params': {'user': 0, 'project': 0, 'effective': True}, - 'results': [{'user': 0, 'role': 0, 'project': 0}, - {'user': 0, 'role': 2, 'project': 0, - 'indirect': {'domain': 0, 'group': 1}}, - {'user': 0, 'role': 3, 'project': 0, - 'indirect': {'domain': 0, 'group': 1}}]} - ] - } - self.execute_assignment_plan(test_plan) - - def test_list_projects_for_user_with_inherited_grants(self): - """Test inherited user 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.config_fixture.config(group='os_inherit', enabled=True) - domain = unit.new_domain_ref() - self.resource_api.create_domain(domain['id'], domain) - user1 = unit.new_user_ref(domain_id=domain['id']) - user1 = self.identity_api.create_user(user1) - project1 = unit.new_project_ref(domain_id=domain['id']) - self.resource_api.create_project(project1['id'], project1) - project2 = unit.new_project_ref(domain_id=domain['id']) - self.resource_api.create_project(project2['id'], project2) - - # Create 2 grants, one on a project and one inherited grant - # on the domain - self.assignment_api.create_grant(user_id=user1['id'], - project_id=self.tenant_bar['id'], - role_id=self.role_member['id']) - self.assignment_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.assertEqual(3, len(user_projects)) - - # TODO(henry-nash): The test above uses list_projects_for_user - # which may, in a subsequent patch, be re-implemented to call - # list_role_assignments and then report only the distinct projects. - # - # The test plan below therefore mirrors this test, to ensure that - # list_role_assignments works the same. Once list_projects_for_user - # has been re-implemented then the manual tests above can be - # refactored. - test_plan = { - # A domain with 1 project, plus a second domain with 2 projects, - # as well as a user. Also, create 2 roles. - 'entities': {'domains': [{'projects': 1}, - {'users': 1, 'projects': 2}], - 'roles': 2}, - 'assignments': [{'user': 0, 'role': 0, 'project': 0}, - {'user': 0, 'role': 1, 'domain': 1, - 'inherited_to_projects': True}], - 'tests': [ - # List all effective assignments for user[0] - # Should get one direct role plus one inherited role for each - # project in domain - {'params': {'user': 0, 'effective': True}, - 'results': [{'user': 0, 'role': 0, 'project': 0}, - {'user': 0, 'role': 1, 'project': 1, - 'indirect': {'domain': 1}}, - {'user': 0, 'role': 1, 'project': 2, - 'indirect': {'domain': 1}}]} - ] - } - self.execute_assignment_plan(test_plan) - - def test_list_projects_for_user_with_inherited_user_project_grants(self): - """Test inherited role assignments for users on nested projects. - - Test Plan: - - - Enable OS-INHERIT extension - - Create a hierarchy of projects with one root and one leaf project - - Assign an inherited user role on root project - - Assign a non-inherited user role on root project - - Get a list of projects for user, should return both projects - - Disable OS-INHERIT extension - - Get a list of projects for user, should return only root project - - """ - # Enable OS-INHERIT extension - self.config_fixture.config(group='os_inherit', enabled=True) - root_project = unit.new_project_ref( - domain_id=CONF.identity.default_domain_id) - root_project = self.resource_api.create_project(root_project['id'], - root_project) - leaf_project = unit.new_project_ref( - domain_id=CONF.identity.default_domain_id, - parent_id=root_project['id']) - leaf_project = self.resource_api.create_project(leaf_project['id'], - leaf_project) - - user = unit.new_user_ref(domain_id=CONF.identity.default_domain_id) - user = self.identity_api.create_user(user) - - # Grant inherited user role - self.assignment_api.create_grant(user_id=user['id'], - project_id=root_project['id'], - role_id=self.role_admin['id'], - inherited_to_projects=True) - # Grant non-inherited user role - self.assignment_api.create_grant(user_id=user['id'], - project_id=root_project['id'], - role_id=self.role_member['id']) - # Should get back both projects: because the direct role assignment for - # the root project and inherited role assignment for leaf project - user_projects = self.assignment_api.list_projects_for_user(user['id']) - self.assertEqual(2, len(user_projects)) - self.assertIn(root_project, user_projects) - self.assertIn(leaf_project, user_projects) - - # Disable OS-INHERIT extension - self.config_fixture.config(group='os_inherit', enabled=False) - # Should get back just root project - due the direct role assignment - user_projects = self.assignment_api.list_projects_for_user(user['id']) - self.assertEqual(1, len(user_projects)) - self.assertIn(root_project, user_projects) - - # TODO(henry-nash): The test above uses list_projects_for_user - # which may, in a subsequent patch, be re-implemented to call - # list_role_assignments and then report only the distinct projects. - # - # The test plan below therefore mirrors this test, to ensure that - # list_role_assignments works the same. Once list_projects_for_user - # has been re-implemented then the manual tests above can be - # refactored. - test_plan = { - # A domain with a project and sub-project, plus a user. - # Also, create 2 roles. - 'entities': { - 'domains': {'id': CONF.identity.default_domain_id, 'users': 1, - 'projects': {'project': 1}}, - 'roles': 2}, - # A direct role and an inherited role on the parent - 'assignments': [{'user': 0, 'role': 0, 'project': 0}, - {'user': 0, 'role': 1, 'project': 0, - 'inherited_to_projects': True}], - 'tests': [ - # List all effective assignments for user[0] - should get back - # one direct role plus one inherited role. - {'params': {'user': 0, 'effective': True}, - 'results': [{'user': 0, 'role': 0, 'project': 0}, - {'user': 0, 'role': 1, 'project': 1, - 'indirect': {'project': 0}}]} - ] - } - - test_plan_with_os_inherit_disabled = { - 'tests': [ - # List all effective assignments for user[0] - should only get - # back the one direct role. - {'params': {'user': 0, 'effective': True}, - 'results': [{'user': 0, 'role': 0, 'project': 0}]} - ] - } - self.config_fixture.config(group='os_inherit', enabled=True) - test_data = self.execute_assignment_plan(test_plan) - self.config_fixture.config(group='os_inherit', enabled=False) - # Pass the existing test data in to allow execution of 2nd test plan - self.execute_assignment_cases( - test_plan_with_os_inherit_disabled, test_data) - - 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.config_fixture.config(group='os_inherit', enabled=True) - domain = unit.new_domain_ref() - self.resource_api.create_domain(domain['id'], domain) - domain2 = unit.new_domain_ref() - self.resource_api.create_domain(domain2['id'], domain2) - project1 = unit.new_project_ref(domain_id=domain['id']) - self.resource_api.create_project(project1['id'], project1) - project2 = unit.new_project_ref(domain_id=domain['id']) - self.resource_api.create_project(project2['id'], project2) - project3 = unit.new_project_ref(domain_id=domain2['id']) - self.resource_api.create_project(project3['id'], project3) - project4 = unit.new_project_ref(domain_id=domain2['id']) - self.resource_api.create_project(project4['id'], project4) - user1 = unit.new_user_ref(domain_id=domain['id']) - user1 = self.identity_api.create_user(user1) - group1 = unit.new_group_ref(domain_id=domain['id']) - group1 = self.identity_api.create_group(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.assignment_api.create_grant(user_id=user1['id'], - project_id=project3['id'], - role_id=self.role_member['id']) - self.assignment_api.create_grant(user_id=user1['id'], - project_id=self.tenant_bar['id'], - role_id=self.role_member['id']) - self.assignment_api.create_grant(user_id=user1['id'], - domain_id=domain['id'], - role_id=self.role_admin['id'], - inherited_to_projects=True) - self.assignment_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.assertEqual(5, len(user_projects)) - - # TODO(henry-nash): The test above uses list_projects_for_user - # which may, in a subsequent patch, be re-implemented to call - # list_role_assignments and then report only the distinct projects. - # - # The test plan below therefore mirrors this test, to ensure that - # list_role_assignments works the same. Once list_projects_for_user - # has been re-implemented then the manual tests above can be - # refactored. - test_plan = { - # A domain with a 1 project, plus a second domain with 2 projects, - # as well as a user & group and a 3rd domain with 2 projects. - # Also, created 2 roles. - 'entities': {'domains': [{'projects': 1}, - {'users': 1, 'groups': 1, 'projects': 2}, - {'projects': 2}], - 'roles': 2}, - 'group_memberships': [{'group': 0, 'users': [0]}], - 'assignments': [{'user': 0, 'role': 0, 'project': 0}, - {'user': 0, 'role': 0, 'project': 3}, - {'user': 0, 'role': 1, 'domain': 1, - 'inherited_to_projects': True}, - {'user': 0, 'role': 1, 'domain': 2, - 'inherited_to_projects': True}], - 'tests': [ - # List all effective assignments for user[0] - # Should get back both direct roles plus roles on both projects - # from each domain. Duplicates should not be filtered out. - {'params': {'user': 0, 'effective': True}, - 'results': [{'user': 0, 'role': 0, 'project': 3}, - {'user': 0, 'role': 0, 'project': 0}, - {'user': 0, 'role': 1, 'project': 1, - 'indirect': {'domain': 1}}, - {'user': 0, 'role': 1, 'project': 2, - 'indirect': {'domain': 1}}, - {'user': 0, 'role': 1, 'project': 3, - 'indirect': {'domain': 2}}, - {'user': 0, 'role': 1, 'project': 4, - 'indirect': {'domain': 2}}]} - ] - } - self.execute_assignment_plan(test_plan) - - def test_list_projects_for_user_with_inherited_group_project_grants(self): - """Test inherited role assignments for groups on nested projects. - - Test Plan: - - - Enable OS-INHERIT extension - - Create a hierarchy of projects with one root and one leaf project - - Assign an inherited group role on root project - - Assign a non-inherited group role on root project - - Get a list of projects for user, should return both projects - - Disable OS-INHERIT extension - - Get a list of projects for user, should return only root project - - """ - self.config_fixture.config(group='os_inherit', enabled=True) - root_project = unit.new_project_ref( - domain_id=CONF.identity.default_domain_id) - root_project = self.resource_api.create_project(root_project['id'], - root_project) - leaf_project = unit.new_project_ref( - domain_id=CONF.identity.default_domain_id, - parent_id=root_project['id']) - leaf_project = self.resource_api.create_project(leaf_project['id'], - leaf_project) - - user = unit.new_user_ref(domain_id=CONF.identity.default_domain_id) - user = self.identity_api.create_user(user) - - group = unit.new_group_ref(domain_id=CONF.identity.default_domain_id) - group = self.identity_api.create_group(group) - self.identity_api.add_user_to_group(user['id'], group['id']) - - # Grant inherited group role - self.assignment_api.create_grant(group_id=group['id'], - project_id=root_project['id'], - role_id=self.role_admin['id'], - inherited_to_projects=True) - # Grant non-inherited group role - self.assignment_api.create_grant(group_id=group['id'], - project_id=root_project['id'], - role_id=self.role_member['id']) - # Should get back both projects: because the direct role assignment for - # the root project and inherited role assignment for leaf project - user_projects = self.assignment_api.list_projects_for_user(user['id']) - self.assertEqual(2, len(user_projects)) - self.assertIn(root_project, user_projects) - self.assertIn(leaf_project, user_projects) - - # Disable OS-INHERIT extension - self.config_fixture.config(group='os_inherit', enabled=False) - # Should get back just root project - due the direct role assignment - user_projects = self.assignment_api.list_projects_for_user(user['id']) - self.assertEqual(1, len(user_projects)) - self.assertIn(root_project, user_projects) - - # TODO(henry-nash): The test above uses list_projects_for_user - # which may, in a subsequent patch, be re-implemented to call - # list_role_assignments and then report only the distinct projects. - # - # The test plan below therefore mirrors this test, to ensure that - # list_role_assignments works the same. Once list_projects_for_user - # has been re-implemented then the manual tests above can be - # refactored. - test_plan = { - # A domain with a project ans sub-project, plus a user. - # Also, create 2 roles. - 'entities': { - 'domains': {'id': CONF.identity.default_domain_id, 'users': 1, - 'groups': 1, - 'projects': {'project': 1}}, - 'roles': 2}, - 'group_memberships': [{'group': 0, 'users': [0]}], - # A direct role and an inherited role on the parent - 'assignments': [{'group': 0, 'role': 0, 'project': 0}, - {'group': 0, 'role': 1, 'project': 0, - 'inherited_to_projects': True}], - 'tests': [ - # List all effective assignments for user[0] - should get back - # one direct role plus one inherited role. - {'params': {'user': 0, 'effective': True}, - 'results': [{'user': 0, 'role': 0, 'project': 0, - 'indirect': {'group': 0}}, - {'user': 0, 'role': 1, 'project': 1, - 'indirect': {'group': 0, 'project': 0}}]} - ] - } - - test_plan_with_os_inherit_disabled = { - 'tests': [ - # List all effective assignments for user[0] - should only get - # back the one direct role. - {'params': {'user': 0, 'effective': True}, - 'results': [{'user': 0, 'role': 0, 'project': 0, - 'indirect': {'group': 0}}]} - ] - } - self.config_fixture.config(group='os_inherit', enabled=True) - test_data = self.execute_assignment_plan(test_plan) - self.config_fixture.config(group='os_inherit', enabled=False) - # Pass the existing test data in to allow execution of 2nd test plan - self.execute_assignment_cases( - test_plan_with_os_inherit_disabled, test_data) - - def test_list_assignments_for_tree(self): - """Test we correctly list direct assignments for a tree""" - # Enable OS-INHERIT extension - self.config_fixture.config(group='os_inherit', enabled=True) - - test_plan = { - # Create a domain with a project hierarchy 3 levels deep: - # - # project 0 - # ____________|____________ - # | | - # project 1 project 4 - # ______|_____ ______|_____ - # | | | | - # project 2 project 3 project 5 project 6 - # - # Also, create 1 user and 4 roles. - 'entities': { - 'domains': { - 'projects': {'project': [{'project': 2}, - {'project': 2}]}, - 'users': 1}, - 'roles': 4}, - 'assignments': [ - # Direct assignment to projects 1 and 2 - {'user': 0, 'role': 0, 'project': 1}, - {'user': 0, 'role': 1, 'project': 2}, - # Also an inherited assignment on project 1 - {'user': 0, 'role': 2, 'project': 1, - 'inherited_to_projects': True}, - # ...and two spoiler assignments, one to the root and one - # to project 4 - {'user': 0, 'role': 0, 'project': 0}, - {'user': 0, 'role': 3, 'project': 4}], - 'tests': [ - # List all assignments for project 1 and its subtree. - {'params': {'project': 1, 'include_subtree': True}, - 'results': [ - # Only the actual assignments should be returned, no - # expansion of inherited assignments - {'user': 0, 'role': 0, 'project': 1}, - {'user': 0, 'role': 1, 'project': 2}, - {'user': 0, 'role': 2, 'project': 1, - 'inherited_to_projects': 'projects'}]} - ] - } - - self.execute_assignment_plan(test_plan) - - def test_list_effective_assignments_for_tree(self): - """Test we correctly list effective assignments for a tree""" - # Enable OS-INHERIT extension - self.config_fixture.config(group='os_inherit', enabled=True) - - test_plan = { - # Create a domain with a project hierarchy 3 levels deep: - # - # project 0 - # ____________|____________ - # | | - # project 1 project 4 - # ______|_____ ______|_____ - # | | | | - # project 2 project 3 project 5 project 6 - # - # Also, create 1 user and 4 roles. - 'entities': { - 'domains': { - 'projects': {'project': [{'project': 2}, - {'project': 2}]}, - 'users': 1}, - 'roles': 4}, - 'assignments': [ - # An inherited assignment on project 1 - {'user': 0, 'role': 1, 'project': 1, - 'inherited_to_projects': True}, - # A direct assignment to project 2 - {'user': 0, 'role': 2, 'project': 2}, - # ...and two spoiler assignments, one to the root and one - # to project 4 - {'user': 0, 'role': 0, 'project': 0}, - {'user': 0, 'role': 3, 'project': 4}], - 'tests': [ - # List all effective assignments for project 1 and its subtree. - {'params': {'project': 1, 'effective': True, - 'include_subtree': True}, - 'results': [ - # The inherited assignment on project 1 should appear only - # on its children - {'user': 0, 'role': 1, 'project': 2, - 'indirect': {'project': 1}}, - {'user': 0, 'role': 1, 'project': 3, - 'indirect': {'project': 1}}, - # And finally the direct assignment on project 2 - {'user': 0, 'role': 2, 'project': 2}]} - ] - } - - self.execute_assignment_plan(test_plan) - - def test_list_effective_assignments_for_tree_with_mixed_assignments(self): - """Test that we correctly combine assignments for a tree. - - In this test we want to ensure that when asking for a list of - assignments in a subtree, any assignments inherited from above the - subtree are correctly combined with any assignments within the subtree - itself. - - """ - # Enable OS-INHERIT extension - self.config_fixture.config(group='os_inherit', enabled=True) - - test_plan = { - # Create a domain with a project hierarchy 3 levels deep: - # - # project 0 - # ____________|____________ - # | | - # project 1 project 4 - # ______|_____ ______|_____ - # | | | | - # project 2 project 3 project 5 project 6 - # - # Also, create 2 users, 1 group and 4 roles. - 'entities': { - 'domains': { - 'projects': {'project': [{'project': 2}, - {'project': 2}]}, - 'users': 2, 'groups': 1}, - 'roles': 4}, - # Both users are part of the same group - 'group_memberships': [{'group': 0, 'users': [0, 1]}], - # We are going to ask for listing of assignment on project 1 and - # it's subtree. So first we'll add two inherited assignments above - # this (one user and one for a group that contains this user). - 'assignments': [{'user': 0, 'role': 0, 'project': 0, - 'inherited_to_projects': True}, - {'group': 0, 'role': 1, 'project': 0, - 'inherited_to_projects': True}, - # Now an inherited assignment on project 1 itself, - # which should ONLY show up on its children - {'user': 0, 'role': 2, 'project': 1, - 'inherited_to_projects': True}, - # ...and a direct assignment on one of those - # children - {'user': 0, 'role': 3, 'project': 2}, - # The rest are spoiler assignments - {'user': 0, 'role': 2, 'project': 5}, - {'user': 0, 'role': 3, 'project': 4}], - 'tests': [ - # List all effective assignments for project 1 and its subtree. - {'params': {'project': 1, 'user': 0, 'effective': True, - 'include_subtree': True}, - 'results': [ - # First, we should see the inherited user assignment from - # project 0 on all projects in the subtree - {'user': 0, 'role': 0, 'project': 1, - 'indirect': {'project': 0}}, - {'user': 0, 'role': 0, 'project': 2, - 'indirect': {'project': 0}}, - {'user': 0, 'role': 0, 'project': 3, - 'indirect': {'project': 0}}, - # Also the inherited group assignment from project 0 on - # the subtree - {'user': 0, 'role': 1, 'project': 1, - 'indirect': {'project': 0, 'group': 0}}, - {'user': 0, 'role': 1, 'project': 2, - 'indirect': {'project': 0, 'group': 0}}, - {'user': 0, 'role': 1, 'project': 3, - 'indirect': {'project': 0, 'group': 0}}, - # The inherited assignment on project 1 should appear only - # on its children - {'user': 0, 'role': 2, 'project': 2, - 'indirect': {'project': 1}}, - {'user': 0, 'role': 2, 'project': 3, - 'indirect': {'project': 1}}, - # And finally the direct assignment on project 2 - {'user': 0, 'role': 3, 'project': 2}]} - ] - } - - self.execute_assignment_plan(test_plan) - - def test_list_effective_assignments_for_tree_with_domain_assignments(self): - """Test we correctly honor domain inherited assignments on the tree""" - # Enable OS-INHERIT extension - self.config_fixture.config(group='os_inherit', enabled=True) - - test_plan = { - # Create a domain with a project hierarchy 3 levels deep: - # - # project 0 - # ____________|____________ - # | | - # project 1 project 4 - # ______|_____ ______|_____ - # | | | | - # project 2 project 3 project 5 project 6 - # - # Also, create 1 user and 4 roles. - 'entities': { - 'domains': { - 'projects': {'project': [{'project': 2}, - {'project': 2}]}, - 'users': 1}, - 'roles': 4}, - 'assignments': [ - # An inherited assignment on the domain (which should be - # applied to all the projects) - {'user': 0, 'role': 1, 'domain': 0, - 'inherited_to_projects': True}, - # A direct assignment to project 2 - {'user': 0, 'role': 2, 'project': 2}, - # ...and two spoiler assignments, one to the root and one - # to project 4 - {'user': 0, 'role': 0, 'project': 0}, - {'user': 0, 'role': 3, 'project': 4}], - 'tests': [ - # List all effective assignments for project 1 and its subtree. - {'params': {'project': 1, 'effective': True, - 'include_subtree': True}, - 'results': [ - # The inherited assignment from the domain should appear - # only on the part of the subtree we are interested in - {'user': 0, 'role': 1, 'project': 1, - 'indirect': {'domain': 0}}, - {'user': 0, 'role': 1, 'project': 2, - 'indirect': {'domain': 0}}, - {'user': 0, 'role': 1, 'project': 3, - 'indirect': {'domain': 0}}, - # And finally the direct assignment on project 2 - {'user': 0, 'role': 2, 'project': 2}]} - ] - } - - self.execute_assignment_plan(test_plan) - - def test_list_user_ids_for_project_with_inheritance(self): - test_plan = { - # A domain with a project and sub-project, plus four users, - # two groups, as well as 4 roles. - 'entities': { - 'domains': {'id': CONF.identity.default_domain_id, 'users': 4, - 'groups': 2, - 'projects': {'project': 1}}, - 'roles': 4}, - # Each group has a unique user member - 'group_memberships': [{'group': 0, 'users': [1]}, - {'group': 1, 'users': [3]}], - # Set up assignments so that there should end up with four - # effective assignments on project 1 - one direct, one due to - # group membership and one user assignment inherited from the - # parent and one group assignment inhertied from the parent. - 'assignments': [{'user': 0, 'role': 0, 'project': 1}, - {'group': 0, 'role': 1, 'project': 1}, - {'user': 2, 'role': 2, 'project': 0, - 'inherited_to_projects': True}, - {'group': 1, 'role': 3, 'project': 0, - 'inherited_to_projects': True}], - } - # Use assignment plan helper to create all the entities and - # assignments - then we'll run our own tests using the data - test_data = self.execute_assignment_plan(test_plan) - self.config_fixture.config(group='os_inherit', enabled=True) - user_ids = self.assignment_api.list_user_ids_for_project( - test_data['projects'][1]['id']) - self.assertThat(user_ids, matchers.HasLength(4)) - for x in range(0, 4): - self.assertIn(test_data['users'][x]['id'], user_ids) - - def test_list_role_assignment_using_inherited_sourced_groups(self): - """Test listing inherited assignments when restricted by groups.""" - test_plan = { - # A domain with 3 users, 3 groups, 3 projects, a second domain, - # plus 3 roles. - 'entities': {'domains': [{'users': 3, 'groups': 3, 'projects': 3}, - 1], - 'roles': 3}, - # Users 0 & 1 are in the group 0, User 0 also in group 1 - 'group_memberships': [{'group': 0, 'users': [0, 1]}, - {'group': 1, 'users': [0]}], - # Spread the assignments around - we want to be able to show that - # if sourced by group, assignments from other sources are excluded - 'assignments': [{'user': 0, 'role': 0, 'domain': 0}, - {'group': 0, 'role': 1, 'domain': 1}, - {'group': 1, 'role': 2, 'domain': 0, - 'inherited_to_projects': True}, - {'group': 1, 'role': 2, 'project': 1}, - {'user': 2, 'role': 1, 'project': 1, - 'inherited_to_projects': True}, - {'group': 2, 'role': 2, 'project': 2} - ], - 'tests': [ - # List all effective assignments sourced from groups 0 and 1. - # We should see the inherited group assigned on the 3 projects - # from domain 0, as well as the direct assignments. - {'params': {'source_from_group_ids': [0, 1], - 'effective': True}, - 'results': [{'group': 0, 'role': 1, 'domain': 1}, - {'group': 1, 'role': 2, 'project': 0, - 'indirect': {'domain': 0}}, - {'group': 1, 'role': 2, 'project': 1, - 'indirect': {'domain': 0}}, - {'group': 1, 'role': 2, 'project': 2, - 'indirect': {'domain': 0}}, - {'group': 1, 'role': 2, 'project': 1} - ]}, - ] - } - self.execute_assignment_plan(test_plan) - - -class ImpliedRoleTests(AssignmentTestHelperMixin): - - def test_implied_role_crd(self): - prior_role_ref = unit.new_role_ref() - self.role_api.create_role(prior_role_ref['id'], prior_role_ref) - implied_role_ref = unit.new_role_ref() - self.role_api.create_role(implied_role_ref['id'], implied_role_ref) - - self.role_api.create_implied_role( - prior_role_ref['id'], - implied_role_ref['id']) - implied_role = self.role_api.get_implied_role( - prior_role_ref['id'], - implied_role_ref['id']) - expected_implied_role_ref = { - 'prior_role_id': prior_role_ref['id'], - 'implied_role_id': implied_role_ref['id']} - self.assertDictContainsSubset( - expected_implied_role_ref, - implied_role) - - self.role_api.delete_implied_role( - prior_role_ref['id'], - implied_role_ref['id']) - self.assertRaises(exception.ImpliedRoleNotFound, - self.role_api.get_implied_role, - uuid.uuid4().hex, - uuid.uuid4().hex) - - def test_delete_implied_role_returns_not_found(self): - self.assertRaises(exception.ImpliedRoleNotFound, - self.role_api.delete_implied_role, - uuid.uuid4().hex, - uuid.uuid4().hex) - - def test_role_assignments_simple_tree_of_implied_roles(self): - """Test that implied roles are expanded out.""" - test_plan = { - 'entities': {'domains': {'users': 1, 'projects': 1}, - 'roles': 4}, - # Three level tree of implied roles - 'implied_roles': [{'role': 0, 'implied_roles': 1}, - {'role': 1, 'implied_roles': [2, 3]}], - 'assignments': [{'user': 0, 'role': 0, 'project': 0}], - 'tests': [ - # List all direct assignments for user[0], this should just - # show the one top level role assignment - {'params': {'user': 0}, - 'results': [{'user': 0, 'role': 0, 'project': 0}]}, - # Listing in effective mode should show the implied roles - # expanded out - {'params': {'user': 0, 'effective': True}, - 'results': [{'user': 0, 'role': 0, 'project': 0}, - {'user': 0, 'role': 1, 'project': 0, - 'indirect': {'role': 0}}, - {'user': 0, 'role': 2, 'project': 0, - 'indirect': {'role': 1}}, - {'user': 0, 'role': 3, 'project': 0, - 'indirect': {'role': 1}}]}, - ] - } - self.execute_assignment_plan(test_plan) - - def test_circular_inferences(self): - """Test that implied roles are expanded out.""" - test_plan = { - 'entities': {'domains': {'users': 1, 'projects': 1}, - 'roles': 4}, - # Three level tree of implied roles - 'implied_roles': [{'role': 0, 'implied_roles': [1]}, - {'role': 1, 'implied_roles': [2, 3]}, - {'role': 3, 'implied_roles': [0]}], - 'assignments': [{'user': 0, 'role': 0, 'project': 0}], - 'tests': [ - # List all direct assignments for user[0], this should just - # show the one top level role assignment - {'params': {'user': 0}, - 'results': [{'user': 0, 'role': 0, 'project': 0}]}, - # Listing in effective mode should show the implied roles - # expanded out - {'params': {'user': 0, 'effective': True}, - 'results': [{'user': 0, 'role': 0, 'project': 0}, - {'user': 0, 'role': 0, 'project': 0, - 'indirect': {'role': 3}}, - {'user': 0, 'role': 1, 'project': 0, - 'indirect': {'role': 0}}, - {'user': 0, 'role': 2, 'project': 0, - 'indirect': {'role': 1}}, - {'user': 0, 'role': 3, 'project': 0, - 'indirect': {'role': 1}}]}, - ] - } - self.execute_assignment_plan(test_plan) - - def test_role_assignments_directed_graph_of_implied_roles(self): - """Test that a role can have multiple, different prior roles.""" - test_plan = { - 'entities': {'domains': {'users': 1, 'projects': 1}, - 'roles': 6}, - # Three level tree of implied roles, where one of the roles at the - # bottom is implied by more than one top level role - 'implied_roles': [{'role': 0, 'implied_roles': [1, 2]}, - {'role': 1, 'implied_roles': [3, 4]}, - {'role': 5, 'implied_roles': 4}], - # The user gets both top level roles - 'assignments': [{'user': 0, 'role': 0, 'project': 0}, - {'user': 0, 'role': 5, 'project': 0}], - 'tests': [ - # The implied roles should be expanded out and there should be - # two entries for the role that had two different prior roles. - {'params': {'user': 0, 'effective': True}, - 'results': [{'user': 0, 'role': 0, 'project': 0}, - {'user': 0, 'role': 5, 'project': 0}, - {'user': 0, 'role': 1, 'project': 0, - 'indirect': {'role': 0}}, - {'user': 0, 'role': 2, 'project': 0, - 'indirect': {'role': 0}}, - {'user': 0, 'role': 3, 'project': 0, - 'indirect': {'role': 1}}, - {'user': 0, 'role': 4, 'project': 0, - 'indirect': {'role': 1}}, - {'user': 0, 'role': 4, 'project': 0, - 'indirect': {'role': 5}}]}, - ] - } - test_data = self.execute_assignment_plan(test_plan) - - # We should also be able to get a similar (yet summarized) answer to - # the above by calling get_roles_for_user_and_project(), which should - # list the role_ids, yet remove any duplicates - role_ids = self.assignment_api.get_roles_for_user_and_project( - test_data['users'][0]['id'], test_data['projects'][0]['id']) - # We should see 6 entries, not 7, since role index 5 appeared twice in - # the answer from list_role_assignments - self.assertThat(role_ids, matchers.HasLength(6)) - for x in range(0, 5): - self.assertIn(test_data['roles'][x]['id'], role_ids) - - def test_role_assignments_implied_roles_filtered_by_role(self): - """Test that you can filter by role even if roles are implied.""" - test_plan = { - 'entities': {'domains': {'users': 1, 'projects': 2}, - 'roles': 4}, - # Three level tree of implied roles - 'implied_roles': [{'role': 0, 'implied_roles': 1}, - {'role': 1, 'implied_roles': [2, 3]}], - 'assignments': [{'user': 0, 'role': 0, 'project': 0}, - {'user': 0, 'role': 3, 'project': 1}], - 'tests': [ - # List effective roles filtering by one of the implied roles, - # showing that the filter was implied post expansion of - # implied roles (and that non impled roles are included in - # the filter - {'params': {'role': 3, 'effective': True}, - 'results': [{'user': 0, 'role': 3, 'project': 0, - 'indirect': {'role': 1}}, - {'user': 0, 'role': 3, 'project': 1}]}, - ] - } - self.execute_assignment_plan(test_plan) - - def test_role_assignments_simple_tree_of_implied_roles_on_domain(self): - """Test that implied roles are expanded out when placed on a domain.""" - test_plan = { - 'entities': {'domains': {'users': 1}, - 'roles': 4}, - # Three level tree of implied roles - 'implied_roles': [{'role': 0, 'implied_roles': 1}, - {'role': 1, 'implied_roles': [2, 3]}], - 'assignments': [{'user': 0, 'role': 0, 'domain': 0}], - 'tests': [ - # List all direct assignments for user[0], this should just - # show the one top level role assignment - {'params': {'user': 0}, - 'results': [{'user': 0, 'role': 0, 'domain': 0}]}, - # Listing in effective mode should how the implied roles - # expanded out - {'params': {'user': 0, 'effective': True}, - 'results': [{'user': 0, 'role': 0, 'domain': 0}, - {'user': 0, 'role': 1, 'domain': 0, - 'indirect': {'role': 0}}, - {'user': 0, 'role': 2, 'domain': 0, - 'indirect': {'role': 1}}, - {'user': 0, 'role': 3, 'domain': 0, - 'indirect': {'role': 1}}]}, - ] - } - self.execute_assignment_plan(test_plan) - - def test_role_assignments_inherited_implied_roles(self): - """Test that you can intermix inherited and implied roles.""" - test_plan = { - 'entities': {'domains': {'users': 1, 'projects': 1}, - 'roles': 4}, - # Simply one level of implied roles - 'implied_roles': [{'role': 0, 'implied_roles': 1}], - # Assign to top level role as an inherited assignment to the - # domain - 'assignments': [{'user': 0, 'role': 0, 'domain': 0, - 'inherited_to_projects': True}], - 'tests': [ - # List all direct assignments for user[0], this should just - # show the one top level role assignment - {'params': {'user': 0}, - 'results': [{'user': 0, 'role': 0, 'domain': 0, - 'inherited_to_projects': 'projects'}]}, - # List in effective mode - we should only see the initial and - # implied role on the project (since inherited roles are not - # active on their anchor point). - {'params': {'user': 0, 'effective': True}, - 'results': [{'user': 0, 'role': 0, 'project': 0, - 'indirect': {'domain': 0}}, - {'user': 0, 'role': 1, 'project': 0, - 'indirect': {'domain': 0, 'role': 0}}]}, - ] - } - self.config_fixture.config(group='os_inherit', enabled=True) - self.execute_assignment_plan(test_plan) - - def test_role_assignments_domain_specific_with_implied_roles(self): - test_plan = { - 'entities': {'domains': {'users': 1, 'projects': 1, 'roles': 2}, - 'roles': 2}, - # Two level tree of implied roles, with the top and 1st level being - # domain specific roles, and the bottom level being infered global - # roles. - 'implied_roles': [{'role': 0, 'implied_roles': [1]}, - {'role': 1, 'implied_roles': [2, 3]}], - 'assignments': [{'user': 0, 'role': 0, 'project': 0}], - 'tests': [ - # List all direct assignments for user[0], this should just - # show the one top level role assignment, even though this is a - # domain specific role (since we are in non-effective mode and - # we show any direct role assignment in that mode). - {'params': {'user': 0}, - 'results': [{'user': 0, 'role': 0, 'project': 0}]}, - # Now the effective ones - so the implied roles should be - # expanded out, as well as any domain specific roles should be - # removed. - {'params': {'user': 0, 'effective': True}, - 'results': [{'user': 0, 'role': 2, 'project': 0, - 'indirect': {'role': 1}}, - {'user': 0, 'role': 3, 'project': 0, - 'indirect': {'role': 1}}]}, - ] - } - self.execute_assignment_plan(test_plan) - - class FilterTests(filtering.FilterTests): def test_list_entities_filtered(self): for entity in ['user', 'group', 'project']: diff --git a/keystone/tests/unit/test_backend_ldap.py b/keystone/tests/unit/test_backend_ldap.py index 85c8e89c95..ba73e93b65 100644 --- a/keystone/tests/unit/test_backend_ldap.py +++ b/keystone/tests/unit/test_backend_ldap.py @@ -36,6 +36,7 @@ from keystone import identity from keystone.identity.mapping_backends import mapping as map from keystone import resource from keystone.tests import unit +from keystone.tests.unit.assignment import test_backends as assignment_tests from keystone.tests.unit import default_fixtures from keystone.tests.unit import identity_mapping as mapping_sql from keystone.tests.unit.ksfixtures import database @@ -120,7 +121,8 @@ def create_group_container(identity_api): ('ou', ['Groups'])]) -class BaseLDAPIdentity(test_backend.IdentityTests): +class BaseLDAPIdentity(test_backend.IdentityTests, + assignment_tests.AssignmentTests): def setUp(self): super(BaseLDAPIdentity, self).setUp() @@ -1660,9 +1662,9 @@ class LDAPIdentity(BaseLDAPIdentity, unit.TestCase): def test_multi_role_grant_by_user_group_on_project_domain(self): # This is a partial implementation of the standard test that - # is defined in test_backend.py. It omits both domain and - # group grants. since neither of these are yet supported by - # the ldap backend. + # is defined in unit.assignment.test_backends.py. It omits + # both domain and group grants. since neither of these are + # yet supported by the ldap backend. role_list = [] for _ in range(2): diff --git a/keystone/tests/unit/test_backend_sql.py b/keystone/tests/unit/test_backend_sql.py index 25befc6e87..a0145335cd 100644 --- a/keystone/tests/unit/test_backend_sql.py +++ b/keystone/tests/unit/test_backend_sql.py @@ -31,6 +31,7 @@ from keystone import exception from keystone.identity.backends import sql as identity_sql from keystone import resource from keystone.tests import unit +from keystone.tests.unit.assignment import test_backends as assignment_tests from keystone.tests.unit import default_fixtures from keystone.tests.unit.ksfixtures import database from keystone.tests.unit import test_backend @@ -191,7 +192,8 @@ class SqlModels(SqlTests): self.assertExpectedSchema('user_group_membership', cols) -class SqlIdentity(SqlTests, test_backend.IdentityTests): +class SqlIdentity(SqlTests, test_backend.IdentityTests, + assignment_tests.AssignmentTests): def test_password_hashed(self): with sql.session_for_read() as session: user_ref = self.identity_api._get_user(session, @@ -814,11 +816,11 @@ class SqlPolicy(SqlTests, test_backend.PolicyTests): pass -class SqlInheritance(SqlTests, test_backend.InheritanceTests): +class SqlInheritance(SqlTests, assignment_tests.InheritanceTests): pass -class SqlImpliedRoles(SqlTests, test_backend.ImpliedRoleTests): +class SqlImpliedRoles(SqlTests, assignment_tests.ImpliedRoleTests): pass