Add inherited role assignments tests
Inherited role assignments are really useful when dealing with
hierarchies - we must test that granting an inherited role in a higher
level of the hierarchy has effect in the project's tree.
The verification is done via the "role_assignments" API and its query
parameters, such as "effective" (which lists the role assignments that
take effect in each project layer).
Change-Id: I0f5a54d85a28c8c011fd3489cf55629b9caa1dcf
diff --git a/tempest/api/identity/admin/v3/test_inherits.py b/tempest/api/identity/admin/v3/test_inherits.py
index 373d44b..955b6fb 100644
--- a/tempest/api/identity/admin/v3/test_inherits.py
+++ b/tempest/api/identity/admin/v3/test_inherits.py
@@ -147,3 +147,88 @@
(self.inherited_roles_client.
delete_inherited_role_from_group_on_project(
self.project['id'], self.group['id'], src_role['id']))
+
+ @test.idempotent_id('3acf666e-5354-42ac-8e17-8b68893bcd36')
+ def test_inherit_assign_list_revoke_user_roles_on_domain(self):
+ # Create role
+ src_role = self.roles_client.create_role(
+ name=data_utils.rand_name('Role'))['role']
+ self.addCleanup(self.roles_client.delete_role, src_role['id'])
+
+ # Create a project hierarchy
+ leaf_project_name = data_utils.rand_name('project')
+ leaf_project = self.projects_client.create_project(
+ leaf_project_name, domain_id=self.domain['id'],
+ parent_id=self.project['id'])['project']
+ self.addCleanup(
+ self.projects_client.delete_project, leaf_project['id'])
+
+ # Assign role on domain
+ self.inherited_roles_client.create_inherited_role_on_domains_user(
+ self.domain['id'], self.user['id'], src_role['id'])
+
+ # List "effective" role assignments from user on the parent project
+ assignments = (
+ self.role_assignments.list_user_project_effective_assignments(
+ self.project['id'], self.user['id']))['role_assignments']
+ self.assertNotEmpty(assignments)
+
+ # List "effective" role assignments from user on the leaf project
+ assignments = (
+ self.role_assignments.list_user_project_effective_assignments(
+ leaf_project['id'], self.user['id']))['role_assignments']
+ self.assertNotEmpty(assignments)
+
+ # Revoke role from domain
+ self.inherited_roles_client.delete_inherited_role_from_user_on_domain(
+ self.domain['id'], self.user['id'], src_role['id'])
+
+ # List "effective" role assignments from user on the parent project
+ # should return an empty list
+ assignments = (
+ self.role_assignments.list_user_project_effective_assignments(
+ self.project['id'], self.user['id']))['role_assignments']
+ self.assertEmpty(assignments)
+
+ # List "effective" role assignments from user on the leaf project
+ # should return an empty list
+ assignments = (
+ self.role_assignments.list_user_project_effective_assignments(
+ leaf_project['id'], self.user['id']))['role_assignments']
+ self.assertEmpty(assignments)
+
+ @test.idempotent_id('9f02ccd9-9b57-46b4-8f77-dd5a736f3a06')
+ def test_inherit_assign_list_revoke_user_roles_on_project_tree(self):
+ # Create role
+ src_role = self.roles_client.create_role(
+ name=data_utils.rand_name('Role'))['role']
+ self.addCleanup(self.roles_client.delete_role, src_role['id'])
+
+ # Create a project hierarchy
+ leaf_project_name = data_utils.rand_name('project')
+ leaf_project = self.projects_client.create_project(
+ leaf_project_name, domain_id=self.domain['id'],
+ parent_id=self.project['id'])['project']
+ self.addCleanup(
+ self.projects_client.delete_project, leaf_project['id'])
+
+ # Assign role on parent project
+ self.inherited_roles_client.create_inherited_role_on_projects_user(
+ self.project['id'], self.user['id'], src_role['id'])
+
+ # List "effective" role assignments from user on the leaf project
+ assignments = (
+ self.role_assignments.list_user_project_effective_assignments(
+ leaf_project['id'], self.user['id']))['role_assignments']
+ self.assertNotEmpty(assignments)
+
+ # Revoke role from parent project
+ self.inherited_roles_client.delete_inherited_role_from_user_on_project(
+ self.project['id'], self.user['id'], src_role['id'])
+
+ # List "effective" role assignments from user on the leaf project
+ # should return an empty list
+ assignments = (
+ self.role_assignments.list_user_project_effective_assignments(
+ leaf_project['id'], self.user['id']))['role_assignments']
+ self.assertEmpty(assignments)
diff --git a/tempest/api/identity/base.py b/tempest/api/identity/base.py
index f5e4943..14bf4f8 100644
--- a/tempest/api/identity/base.py
+++ b/tempest/api/identity/base.py
@@ -182,6 +182,7 @@
cls.creds_client = cls.os_adm.credentials_client
cls.groups_client = cls.os_adm.groups_client
cls.projects_client = cls.os_adm.projects_client
+ cls.role_assignments = cls.os_admin.role_assignments_client
if CONF.identity.admin_domain_scope:
# NOTE(andreaf) When keystone policy requires it, the identity
# admin clients for these tests shall use 'domain' scoped tokens.
diff --git a/tempest/clients.py b/tempest/clients.py
index edc34bd..765a526 100644
--- a/tempest/clients.py
+++ b/tempest/clients.py
@@ -250,6 +250,8 @@
**params_v3)
self.inherited_roles_client = identity.v3.InheritedRolesClient(
self.auth_provider, **params_v3)
+ self.role_assignments_client = identity.v3.RoleAssignmentsClient(
+ self.auth_provider, **params_v3)
self.identity_services_v3_client = identity.v3.ServicesClient(
self.auth_provider, **params_v3)
self.policies_client = identity.v3.PoliciesClient(self.auth_provider,
diff --git a/tempest/services/identity/v3/__init__.py b/tempest/services/identity/v3/__init__.py
index 3f5c3d5..9b40b77 100644
--- a/tempest/services/identity/v3/__init__.py
+++ b/tempest/services/identity/v3/__init__.py
@@ -28,8 +28,11 @@
from tempest.lib.services.identity.v3.trusts_client import TrustsClient
from tempest.lib.services.identity.v3.users_client import UsersClient
from tempest.services.identity.v3.json.domains_client import DomainsClient
+from tempest.services.identity.v3.json.role_assignments_client import \
+ RoleAssignmentsClient
__all__ = ['CredentialsClient', 'EndPointsClient', 'GroupsClient',
'IdentityClient', 'InheritedRolesClient', 'PoliciesClient',
- 'ProjectsClient', 'RegionsClient', 'RolesClient', 'ServicesClient',
- 'V3TokenClient', 'TrustsClient', 'UsersClient', 'DomainsClient', ]
+ 'ProjectsClient', 'RegionsClient', 'RoleAssignmentsClient',
+ 'RolesClient', 'ServicesClient', 'V3TokenClient', 'TrustsClient',
+ 'UsersClient', 'DomainsClient', ]
diff --git a/tempest/services/identity/v3/json/role_assignments_client.py b/tempest/services/identity/v3/json/role_assignments_client.py
new file mode 100644
index 0000000..9fd7736
--- /dev/null
+++ b/tempest/services/identity/v3/json/role_assignments_client.py
@@ -0,0 +1,31 @@
+# Copyright 2016 Red Hat, Inc.
+#
+# 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.
+
+from oslo_serialization import jsonutils as json
+
+from tempest.lib.common import rest_client
+
+
+class RoleAssignmentsClient(rest_client.RestClient):
+ api_version = "v3"
+
+ def list_user_project_effective_assignments(
+ self, project_id, user_id):
+ """List the effective role assignments for a user in a project."""
+ resp, body = self.get(
+ "role_assignments?scope.project.id=%s&user.id=%s&effective" %
+ (project_id, user_id))
+ self.expected_success(200, resp.status)
+ body = json.loads(body)
+ return rest_client.ResponseBody(resp, body)