diff --git a/keystoneclient/tests/unit/v3/test_role_assignments.py b/keystoneclient/tests/unit/v3/test_role_assignments.py index b24799cbc..45dd13d6c 100644 --- a/keystoneclient/tests/unit/v3/test_role_assignments.py +++ b/keystoneclient/tests/unit/v3/test_role_assignments.py @@ -23,6 +23,32 @@ class RoleAssignmentsTests(utils.ClientTestCase, utils.CrudTests): self.collection_key = 'role_assignments' self.model = role_assignments.RoleAssignment self.manager = self.client.role_assignments + self.TEST_USER_SYSTEM_LIST = [{ + 'role': { + 'id': self.TEST_ROLE_ID + }, + 'scope': { + 'system': { + 'all': True + } + }, + 'user': { + 'id': self.TEST_USER_ID + } + }] + self.TEST_GROUP_SYSTEM_LIST = [{ + 'role': { + 'id': self.TEST_ROLE_ID + }, + 'scope': { + 'system': { + 'all': True + } + }, + 'group': { + 'id': self.TEST_GROUP_ID + } + }] self.TEST_USER_DOMAIN_LIST = [{ 'role': { 'id': self.TEST_ROLE_ID @@ -65,7 +91,9 @@ class RoleAssignmentsTests(utils.ClientTestCase, utils.CrudTests): self.TEST_ALL_RESPONSE_LIST = (self.TEST_USER_PROJECT_LIST + self.TEST_GROUP_PROJECT_LIST + - self.TEST_USER_DOMAIN_LIST) + self.TEST_USER_DOMAIN_LIST + + self.TEST_USER_SYSTEM_LIST + + self.TEST_GROUP_SYSTEM_LIST) def _assert_returned_list(self, ref_list, returned_list): self.assertEqual(len(ref_list), len(returned_list)) @@ -150,6 +178,50 @@ class RoleAssignmentsTests(utils.ClientTestCase, utils.CrudTests): kwargs = {'scope.domain.id': self.TEST_DOMAIN_ID} self.assertQueryStringContains(**kwargs) + def test_system_assignment_list(self): + ref_list = self.TEST_USER_SYSTEM_LIST + self.TEST_GROUP_SYSTEM_LIST + + self.stub_entity('GET', + [self.collection_key, '?scope.system=all'], + entity=ref_list) + + returned_list = self.manager.list(system='all') + self._assert_returned_list(ref_list, returned_list) + + kwargs = {'scope.system': 'all'} + self.assertQueryStringContains(**kwargs) + + def test_system_assignment_list_for_user(self): + ref_list = self.TEST_USER_SYSTEM_LIST + + self.stub_entity('GET', + [self.collection_key, + '?user.id=%s&scope.system=all' % self.TEST_USER_ID], + entity=ref_list) + + returned_list = self.manager.list(system='all', user=self.TEST_USER_ID) + self._assert_returned_list(ref_list, returned_list) + + kwargs = {'scope.system': 'all', 'user.id': self.TEST_USER_ID} + self.assertQueryStringContains(**kwargs) + + def test_system_assignment_list_for_group(self): + ref_list = self.TEST_GROUP_SYSTEM_LIST + + self.stub_entity( + 'GET', + [self.collection_key, + '?group.id=%s&scope.system=all' % self.TEST_GROUP_ID], + entity=ref_list) + + returned_list = self.manager.list( + system='all', group=self.TEST_GROUP_ID + ) + self._assert_returned_list(ref_list, returned_list) + + kwargs = {'scope.system': 'all', 'group.id': self.TEST_GROUP_ID} + self.assertQueryStringContains(**kwargs) + def test_group_assignments_list(self): ref_list = self.TEST_GROUP_PROJECT_LIST self.stub_entity('GET', diff --git a/keystoneclient/v3/role_assignments.py b/keystoneclient/v3/role_assignments.py index 5360a9488..ce1e550a0 100644 --- a/keystoneclient/v3/role_assignments.py +++ b/keystoneclient/v3/role_assignments.py @@ -46,9 +46,25 @@ class RoleAssignmentManager(base.CrudManager): msg = _('Specify either a domain or project, not both') raise exceptions.ValidationError(msg) - def list(self, user=None, group=None, project=None, domain=None, role=None, - effective=False, os_inherit_extension_inherited_to=None, - include_subtree=False, include_names=False): + def _check_not_system_and_domain(self, system, domain): + if system and domain: + msg = _('Specify either system or domain, not both') + raise exceptions.ValidationError(msg) + + def _check_not_system_and_project(self, system, project): + if system and project: + msg = _('Specify either system or project, not both') + raise exceptions.ValidationError(msg) + + def _check_system_value(self, system): + if system and system != 'all': + msg = _("Only a system scope of 'all' is currently supported") + raise exceptions.ValidationError(msg) + + def list(self, user=None, group=None, project=None, domain=None, + system=False, role=None, effective=False, + os_inherit_extension_inherited_to=None, include_subtree=False, + include_names=False): """List role assignments. If no arguments are provided, all role assignments in the @@ -64,6 +80,8 @@ class RoleAssignmentManager(base.CrudManager): (optional) :param domain: Domain to be used as query filter. (optional) + :param system: Boolean to be used to filter system assignments. + (optional) :param role: Role to be used as query filter. (optional) :param boolean effective: return effective role assignments. (optional) @@ -76,6 +94,9 @@ class RoleAssignmentManager(base.CrudManager): """ self._check_not_user_and_group(user, group) self._check_not_domain_and_project(domain, project) + self._check_not_system_and_domain(system, domain) + self._check_not_system_and_project(system, project) + self._check_system_value(system) query_params = {} if user: @@ -86,6 +107,8 @@ class RoleAssignmentManager(base.CrudManager): query_params['scope.project.id'] = base.getid(project) if domain: query_params['scope.domain.id'] = base.getid(domain) + if system: + query_params['scope.system'] = system if role: query_params['role.id'] = base.getid(role) if effective: diff --git a/keystoneclient/v3/roles.py b/keystoneclient/v3/roles.py index ce0cfe889..a84ab39a3 100644 --- a/keystoneclient/v3/roles.py +++ b/keystoneclient/v3/roles.py @@ -54,7 +54,7 @@ class RoleManager(base.CrudManager): key = 'role' deprecation_msg = 'keystoneclient.v3.roles.InferenceRuleManager' - def _role_grants_base_url(self, user, group, domain, project, + def _role_grants_base_url(self, user, group, system, domain, project, use_inherit_extension): # When called, we have already checked that only one of user & group # and one of domain & project have been specified @@ -66,6 +66,18 @@ class RoleManager(base.CrudManager): elif domain: params['domain_id'] = base.getid(domain) base_url = '/domains/%(domain_id)s' + elif system: + if system == 'all': + base_url = '/system' + else: + # NOTE(lbragstad): If we've made it this far, a user is + # attempting to do something with system scope that isn't + # supported yet (e.g. 'all' is currently the only supported + # system scope). In the future that may change but until then + # we should fail like we would if a user provided a bogus + # project name or domain ID. + msg = _("Only a system scope of 'all' is currently supported") + raise exceptions.ValidationError(msg) if use_inherit_extension: base_url = '/OS-INHERIT' + base_url @@ -79,13 +91,26 @@ class RoleManager(base.CrudManager): return base_url % params - def _require_domain_xor_project(self, domain, project): - if domain and project: - msg = _('Specify either a domain or project, not both') - raise exceptions.ValidationError(msg) - elif not (domain or project): - msg = _('Must specify either a domain or project') - raise exceptions.ValidationError(msg) + def _enforce_mutually_exclusive_group(self, system, domain, project): + if not system: + if domain and project: + msg = _('Specify either a domain or project, not both') + raise exceptions.ValidationError(msg) + elif not (domain or project): + msg = _('Must specify either system, domain, or project') + raise exceptions.ValidationError(msg) + elif system: + if domain and project: + msg = _( + 'Specify either system, domain, or project, not all three.' + ) + raise exceptions.ValidationError(msg) + if domain: + msg = _('Specify either system or a domain, not both') + raise exceptions.ValidationError(msg) + if project: + msg = _('Specify either a system or project, not both') + raise exceptions.ValidationError(msg) def _require_user_xor_group(self, user, group): if user and group: @@ -130,7 +155,7 @@ class RoleManager(base.CrudManager): """ return super(RoleManager, self).get(role_id=base.getid(role)) - def list(self, user=None, group=None, domain=None, + def list(self, user=None, group=None, system=None, domain=None, project=None, os_inherit_extension_inherited=False, **kwargs): """List roles and role grants. @@ -143,12 +168,12 @@ class RoleManager(base.CrudManager): User and group are mutually exclusive. :type group: str or :class:`keystoneclient.v3.groups.Group` :param domain: filter in role grants on the specified domain. Either - user or group must be specified. Project and domain - are mutually exclusive. + user or group must be specified. Project, domain, and + system are mutually exclusive. :type domain: str or :class:`keystoneclient.v3.domains.Domain` :param project: filter in role grants on the specified project. Either - user or group must be specified. Project and domain - are mutually exclusive. + user or group must be specified. Project, domain and + system are mutually exclusive. :type project: str or :class:`keystoneclient.v3.projects.Project` :param bool os_inherit_extension_inherited: OS-INHERIT will be used. It provides the ability for @@ -166,10 +191,12 @@ class RoleManager(base.CrudManager): kwargs['tail'] = '/inherited_to_projects' if user or group: self._require_user_xor_group(user, group) - self._require_domain_xor_project(domain, project) + self._enforce_mutually_exclusive_group(system, domain, project) base_url = self._role_grants_base_url( - user, group, domain, project, os_inherit_extension_inherited) + user, group, system, domain, project, + os_inherit_extension_inherited + ) return super(RoleManager, self).list(base_url=base_url, **kwargs) @@ -208,8 +235,8 @@ class RoleManager(base.CrudManager): return super(RoleManager, self).delete( role_id=base.getid(role)) - def grant(self, role, user=None, group=None, domain=None, project=None, - os_inherit_extension_inherited=False, **kwargs): + def grant(self, role, user=None, group=None, system=None, domain=None, + project=None, os_inherit_extension_inherited=False, **kwargs): """Grant a role to a user or group on a domain or project. :param role: the role to be granted on the server. @@ -222,13 +249,16 @@ class RoleManager(base.CrudManager): resource. Domain or project must be specified. User and group are mutually exclusive. :type group: str or :class:`keystoneclient.v3.groups.Group` + :param system: system information to grant the role on. Project, + domain, and system are mutually exclusive. + :type system: str :param domain: the domain in which the role will be granted. Either - user or group must be specified. Project and domain - are mutually exclusive. + user or group must be specified. Project, domain, and + system are mutually exclusive. :type domain: str or :class:`keystoneclient.v3.domains.Domain` :param project: the project in which the role will be granted. Either - user or group must be specified. Project and domain - are mutually exclusive. + user or group must be specified. Project, domain, and + system are mutually exclusive. :type project: str or :class:`keystoneclient.v3.projects.Project` :param bool os_inherit_extension_inherited: OS-INHERIT will be used. It provides the ability for @@ -242,20 +272,21 @@ class RoleManager(base.CrudManager): :rtype: :class:`keystoneclient.v3.roles.Role` """ - self._require_domain_xor_project(domain, project) + self._enforce_mutually_exclusive_group(system, domain, project) self._require_user_xor_group(user, group) if os_inherit_extension_inherited: kwargs['tail'] = '/inherited_to_projects' base_url = self._role_grants_base_url( - user, group, domain, project, os_inherit_extension_inherited) + user, group, system, domain, project, + os_inherit_extension_inherited) return super(RoleManager, self).put(base_url=base_url, role_id=base.getid(role), **kwargs) - def check(self, role, user=None, group=None, domain=None, project=None, - os_inherit_extension_inherited=False, **kwargs): + def check(self, role, user=None, group=None, system=None, domain=None, + project=None, os_inherit_extension_inherited=False, **kwargs): """Check if a user or group has a role on a domain or project. :param user: check for role grants for the specified user on a @@ -266,13 +297,16 @@ class RoleManager(base.CrudManager): resource. Domain or project must be specified. User and group are mutually exclusive. :type group: str or :class:`keystoneclient.v3.groups.Group` + :param system: check for role grants on the system. Project, domain, + and system are mutually exclusive. + :type system: str :param domain: check for role grants on the specified domain. Either - user or group must be specified. Project and domain - are mutually exclusive. + user or group must be specified. Project, domain, and + system are mutually exclusive. :type domain: str or :class:`keystoneclient.v3.domains.Domain` :param project: check for role grants on the specified project. Either - user or group must be specified. Project and domain - are mutually exclusive. + user or group must be specified. Project, domain, and + system are mutually exclusive. :type project: str or :class:`keystoneclient.v3.projects.Project` :param bool os_inherit_extension_inherited: OS-INHERIT will be used. It provides the ability for @@ -290,22 +324,23 @@ class RoleManager(base.CrudManager): :rtype: :class:`requests.models.Response` """ - self._require_domain_xor_project(domain, project) + self._enforce_mutually_exclusive_group(system, domain, project) self._require_user_xor_group(user, group) if os_inherit_extension_inherited: kwargs['tail'] = '/inherited_to_projects' base_url = self._role_grants_base_url( - user, group, domain, project, os_inherit_extension_inherited) + user, group, system, domain, project, + os_inherit_extension_inherited) return super(RoleManager, self).head( base_url=base_url, role_id=base.getid(role), os_inherit_extension_inherited=os_inherit_extension_inherited, **kwargs) - def revoke(self, role, user=None, group=None, domain=None, project=None, - os_inherit_extension_inherited=False, **kwargs): + def revoke(self, role, user=None, group=None, system=None, domain=None, + project=None, os_inherit_extension_inherited=False, **kwargs): """Revoke a role from a user or group on a domain or project. :param user: revoke role grants for the specified user on a @@ -316,13 +351,16 @@ class RoleManager(base.CrudManager): resource. Domain or project must be specified. User and group are mutually exclusive. :type group: str or :class:`keystoneclient.v3.groups.Group` + :param system: revoke role grants on the system. Project, domain, and + system are mutually exclusive. + :type system: str :param domain: revoke role grants on the specified domain. Either - user or group must be specified. Project and domain - are mutually exclusive. + user or group must be specified. Project, domain, and + system are mutually exclusive. :type domain: str or :class:`keystoneclient.v3.domains.Domain` :param project: revoke role grants on the specified project. Either - user or group must be specified. Project and domain - are mutually exclusive. + user or group must be specified. Project, domain, and + system are mutually exclusive. :type project: str or :class:`keystoneclient.v3.projects.Project` :param bool os_inherit_extension_inherited: OS-INHERIT will be used. It provides the ability for @@ -336,14 +374,15 @@ class RoleManager(base.CrudManager): :rtype: list of :class:`keystoneclient.v3.roles.Role` """ - self._require_domain_xor_project(domain, project) + self._enforce_mutually_exclusive_group(system, domain, project) self._require_user_xor_group(user, group) if os_inherit_extension_inherited: kwargs['tail'] = '/inherited_to_projects' base_url = self._role_grants_base_url( - user, group, domain, project, os_inherit_extension_inherited) + user, group, system, domain, project, + os_inherit_extension_inherited) return super(RoleManager, self).delete( base_url=base_url, role_id=base.getid(role),