update from RIFT as of 696b75d2fe9fb046261b08c616f1bcf6c0b54a9b second try
[osm/SO.git] / rwlaunchpad / ra / pytest / ns / rbac / test_rbac.py
1 #!/usr/bin/env python3
2 """
3 #
4 # Copyright 2017 RIFT.IO Inc
5 #
6 # Licensed under the Apache License, Version 2.0 (the "License");
7 # you may not use this file except in compliance with the License.
8 # You may obtain a copy of the License at
9 #
10 # http://www.apache.org/licenses/LICENSE-2.0
11 #
12 # Unless required by applicable law or agreed to in writing, software
13 # distributed under the License is distributed on an "AS IS" BASIS,
14 # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
15 # See the License for the specific language governing permissions and
16 # limitations under the License.
17 #
18 """
19
20 import gi
21 import pytest
22
23 from rift.auto.session import NetconfSession, RestconfSession
24 import rift.auto.mano
25
26 gi.require_version('RwUserYang', '1.0')
27 gi.require_version('RwProjectYang', '1.0')
28 gi.require_version('RwRbacPlatformYang', '1.0')
29 gi.require_version('RwRbacInternalYang', '1.0')
30 from gi.repository import (
31 RwUserYang,
32 RwProjectYang,
33 RwRbacPlatformYang,
34 RwRbacInternalYang,
35 )
36 gi.require_version('RwKeyspec', '1.0')
37 from gi.repository.RwKeyspec import quoted_key
38
39 @pytest.fixture(scope='session')
40 def rbac_test_data():
41 """Fixture which returns rbac test data: users, roles, projects being used in the test.
42 users: tuple of user names
43 projects: tuple of project names
44 map_platform_roles: mapping of a user to multiple platform roles
45 map_project_roles: mapping of a user to multiple projects (project, list of roles in that project)"""
46 users = ('admin3', 'user1', 'user2', )
47
48 projects = ('project1', 'project2', )
49
50 map_platform_roles = {
51 'admin3': ['rw-rbac-platform:platform-admin'],
52 }
53
54 map_project_roles = {
55 'user1': [
56 ('project1', ['rw-project:project-admin']),
57 ('project2', ['rw-project:project-oper']),
58 ],
59
60 'user2': [
61 ('project1', ['rw-project:project-admin']),
62 ],
63
64 'admin3': [],
65 }
66
67 return {'users': users, 'projects': projects, 'roles': (map_platform_roles, map_project_roles)}
68
69
70 @pytest.mark.setup('rbac_setup')
71 @pytest.mark.incremental
72 class TestRbacSetup(object):
73 def test_create_users(self, rbac_test_data, rw_user_proxy, user_domain, rbac_user_passwd, logger):
74 """Creates all users as per rbac test-data and verify if they are successfully created."""
75 users_test_data = rbac_test_data['users']
76
77 # Create all users mentioned in users_test_data
78 for user in users_test_data:
79 rift.auto.mano.create_user(rw_user_proxy, user, rbac_user_passwd, user_domain)
80
81 # Verify users are created
82 user_config = rw_user_proxy.get_config('/user-config')
83 assert user_config
84
85 user_config_test_data = [user.user_name for user in user_config.user if user.user_name in users_test_data]
86 logger.debug('Users: {} have been successfully created'.format(user_config_test_data))
87
88 assert len(user_config_test_data) == len(users_test_data)
89
90 def test_create_projects(self, logger, rw_conman_proxy, rbac_test_data):
91 """Creates all projects as per rbac test-data and verify them."""
92 projects_test_data = rbac_test_data['projects']
93
94 # Create all projects mentioned in projects_test_data and verify if they are created
95 for project in projects_test_data:
96 logger.debug('Creating project {}'.format(project))
97 rift.auto.mano.create_project(rw_conman_proxy, project)
98
99 def test_assign_platform_roles_to_users(self, rbac_platform_proxy, logger, rbac_test_data, user_domain, rw_rbac_int_proxy):
100 """Assign platform roles to an user as per test data mapping and verify them."""
101 platform_roles_test_data, _ = rbac_test_data['roles']
102
103 # Loop through the user & platform-roles mapping and assign roles to the user
104 for user, roles in platform_roles_test_data.items():
105 for role in roles:
106 rift.auto.mano.assign_platform_role_to_user(rbac_platform_proxy, role, user, user_domain, rw_rbac_int_proxy)
107
108 # Verify if the roles are assigned as per test data mapping
109 platform_config = rbac_platform_proxy.get_config('/rbac-platform-config')
110
111 platform_config_test_data_match = 0
112 logger.debug('Matching platform_roles_test_data with rbac-platform-config')
113 for user in platform_config.user:
114 if user.user_name in platform_roles_test_data:
115 logger.debug('Matched user: {}'.format(user.as_dict()))
116 platform_config_test_data_match += 1
117
118 test_data_user_platform_roles = platform_roles_test_data[user.user_name]
119 assert len(test_data_user_platform_roles) == len(user.role)
120 assert len(test_data_user_platform_roles) == len([role for role in user.role if role.role in test_data_user_platform_roles])
121
122 assert platform_config_test_data_match == len(platform_roles_test_data)
123
124 def test_assign_users_to_projects_roles(self, rbac_test_data, rw_project_proxy, user_domain, rw_rbac_int_proxy):
125 """Assign projects and roles to an user as per test data mapping."""
126 _, project_roles_test_data = rbac_test_data['roles']
127
128 # Loop through the user & (project, role) mapping and asign the project, role to the user
129 for user, project_role_tuple in project_roles_test_data.items():
130 for project, role_list in project_role_tuple:
131 for role in role_list:
132 rift.auto.mano.assign_project_role_to_user(rw_project_proxy, role, user, project, user_domain, rw_rbac_int_proxy)
133
134
135 @pytest.mark.depends('rbac_setup')
136 @pytest.mark.incremental
137 class TestRbacVerification(object):
138 def test_match_rbac_internal(self, mgmt_session, logger, rbac_test_data):
139 """Verifies the test data with rw-rbac-internal"""
140 rbac_intl_proxy = mgmt_session.proxy(RwRbacInternalYang)
141 rbac_intl = rbac_intl_proxy.get('/rw-rbac-internal')
142
143 # Verify users in show rw-rbac-internal
144 users_test_data = rbac_test_data['users']
145 assert len(rbac_intl.user) == len(users_test_data) + 2 # 'admin', 'oper' are two default users
146 users_match = 0
147 for user in rbac_intl.user:
148 if user.user_name in users_test_data:
149 logger.info('User matched: {}'.format(user.as_dict()))
150 users_match += 1
151 assert users_match == len(users_test_data)
152
153 # Verify roles (only project roles mapping, not the platform roles mapping)
154 # Each role in rw-rbac-internal is associated with a project through the field 'keys'. All mapping from users to project
155 # is part of project roles mapping.
156 _, project_roles_test_data = rbac_test_data['roles']
157 for user, project_role_tuple in project_roles_test_data.items():
158 for project, role_list in project_role_tuple:
159 for role in role_list:
160 logger.debug("Matching user: '{}' and its role '{}' in project '{}'".format(user, role, project))
161
162 # Verify there exists a role entry in rw-rbac-internal which matches 'role', 'project'
163 rbac_intl_role = [role_ for role_ in rbac_intl.role if (role_.role==role and role_.keys==project)]
164
165 # Each role is identified through its key 'project'. So there can be only one such role which matches
166 # the above 'role.role==role and role.keys=project'
167 assert len(rbac_intl_role) == 1
168 logger.info('Matched role in rw-rbac-internal: {}'.format(rbac_intl_role[0].as_dict()))
169
170 # Verify the user list in this rw-rbac-internal role carries 'user'
171 assert len([user_ for user_ in rbac_intl_role[0].user if user_.user_name==user]) == 1
172
173 def test_role_access(self, logger, session_class, confd_host, rbac_test_data, rbac_user_passwd, project_keyed_xpath):
174 """Verifies the roles assigned to users for a project. Login as each user and verify the user can only access
175 the projects linked to it."""
176 _, project_roles_test_data = rbac_test_data['roles']
177 projects_test_data = rbac_test_data['projects']
178
179 for user, project_role_tuple in project_roles_test_data.items():
180 logger.debug('Verifying user: {}'.format(user))
181 projects_not_accessible = list(projects_test_data)
182
183 # Establish a session with this current user
184 user_session = rift.auto.mano.get_session(session_class, confd_host, user, rbac_user_passwd)
185 print ("Connected using username {} password {}".format(user, rbac_user_passwd))
186
187 rw_project_proxy_ = user_session.proxy(RwProjectYang)
188
189 if project_role_tuple: # Skip the for loop for users who are not associated with any project e.g admin3
190 for project, role_list in project_role_tuple:
191 projects_not_accessible.remove(project)
192 project_config = rw_project_proxy_.get_config(project_keyed_xpath.format(project_name=quoted_key(project))+'/project-config')
193 user_ = [user_ for user_ in project_config.user if user_.user_name==user]
194 logger.debug('User: {}'.format(user_[0].as_dict()))
195 assert len(user_) == 1
196
197 # Match the roles for this user
198 assert set(role_list) == set([role_.role for role_ in user_[0].role])
199
200 # It can't access any other project.
201 for project in projects_not_accessible:
202 assert rw_project_proxy_.get_config(project_keyed_xpath.format(project_name=quoted_key(project))+'/project-config') is None # It should
203 # return None as the project is not mapped to this user.
204
205 def test_admin_user(self, logger, rw_project_proxy, project_keyed_xpath, rbac_test_data):
206 """Verify admin can see all projects as part of test-data as well as the default project"""
207 projects_test_data = rbac_test_data['projects']
208 projects_test_data = projects_test_data + ('default', )
209
210 # Verify admin user can see all projects including default
211 # If it is post-reboot verification, then check default project should not be listed
212 for project in projects_test_data:
213 project_ = rw_project_proxy.get_config(project_keyed_xpath.format(project_name=quoted_key(project))+'/project-state', list_obj=True)
214 if project=='default' and pytest.config.getoption('--default-project-deleted'):
215 assert project_ is None
216 continue
217 assert project_ # If the project doesn't exist, it returns None
218
219
220 @pytest.mark.depends('rbac_setup')
221 @pytest.mark.teardown('rbac_setup')
222 @pytest.mark.incremental
223 class TestRbacTeardown(object):
224 def test_delete_default_project(self, logger, rw_conman_proxy):
225 """Only deletes the default project"""
226 logger.debug('Deleting the default project')
227 rift.auto.mano.delete_project(rw_conman_proxy, 'default')
228
229 def test_delete_projects(self, logger, rbac_test_data, rw_conman_proxy):
230 """Deletes the projects which are part of rbac test-data and verify their deletion"""
231 projects_test_data = rbac_test_data['projects']
232
233 # Delete the projects
234 for project in projects_test_data:
235 logger.debug('Deleting project {}'.format(project))
236 rift.auto.mano.delete_project(rw_conman_proxy, project)
237
238 def test_delete_users(self, logger, rw_user_proxy, rbac_platform_proxy, platform_config_keyed_xpath,
239 user_keyed_xpath, rbac_test_data, user_domain):
240 """Deletes the users which are part of rbac test-data and verify their deletion"""
241 users_test_data = rbac_test_data['users']
242 map_platform_roles, _ = rbac_test_data['roles']
243
244 # Deletes the users
245 # If an user is associated with a platform role, at first it needs be removed from rbac-platform-config
246 # before deleting it from user-config
247 for user in users_test_data:
248 if user in map_platform_roles:
249 rbac_platform_proxy.delete_config(platform_config_keyed_xpath.format(user=quoted_key(user), domain=quoted_key(user_domain)))
250 rw_user_proxy.delete_config(user_keyed_xpath.format(user=quoted_key(user), domain=quoted_key(user_domain)))
251
252 # Verify if the users are deleted
253 user_config = rw_user_proxy.get_config('/user-config')
254 default_users = [user.user_name for user in user_config.user]
255
256 logger.debug('Default users list: {}'.format(default_users))
257 expected_empty_user_list = [user for user in users_test_data if user in default_users]
258 assert not expected_empty_user_list