blob: ff5413066f8ef0b5ce07bcdc30aa3cb4732071c2 [file] [log] [blame]
Eduardo Sousa819d34c2018-07-31 01:20:02 +01001# -*- coding: utf-8 -*-
2
Eduardo Sousad795f872019-02-05 16:05:53 +00003# Copyright 2018 Whitestack, LLC
4#
5# Licensed under the Apache License, Version 2.0 (the "License"); you may
6# not use this file except in compliance with the License. You may obtain
7# a copy of the License at
8#
9# http://www.apache.org/licenses/LICENSE-2.0
10#
11# Unless required by applicable law or agreed to in writing, software
12# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
13# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
14# License for the specific language governing permissions and limitations
15# under the License.
16#
17# For those usages not covered by the Apache License, Version 2.0 please
18# contact: esousa@whitestack.com or glavado@whitestack.com
19##
20
Eduardo Sousa819d34c2018-07-31 01:20:02 +010021"""
22AuthconnKeystone implements implements the connector for
23Openstack Keystone and leverages the RBAC model, to bring
24it for OSM.
25"""
Eduardo Sousa44603902019-06-04 08:10:32 +010026
Eduardo Sousa819d34c2018-07-31 01:20:02 +010027
28__author__ = "Eduardo Sousa <esousa@whitestack.com>"
29__date__ = "$27-jul-2018 23:59:59$"
30
31from authconn import Authconn, AuthException, AuthconnOperationException
32
33import logging
Eduardo Sousa29933fc2018-11-14 06:36:35 +000034import requests
Eduardo Sousa44603902019-06-04 08:10:32 +010035import time
Eduardo Sousa819d34c2018-07-31 01:20:02 +010036from keystoneauth1 import session
37from keystoneauth1.identity import v3
38from keystoneauth1.exceptions.base import ClientException
Eduardo Sousa29933fc2018-11-14 06:36:35 +000039from keystoneauth1.exceptions.http import Conflict
Eduardo Sousa819d34c2018-07-31 01:20:02 +010040from keystoneclient.v3 import client
41from http import HTTPStatus
Eduardo Sousa44603902019-06-04 08:10:32 +010042from validation import is_valid_uuid
Eduardo Sousa819d34c2018-07-31 01:20:02 +010043
44
45class AuthconnKeystone(Authconn):
46 def __init__(self, config):
47 Authconn.__init__(self, config)
48
49 self.logger = logging.getLogger("nbi.authenticator.keystone")
50
51 self.auth_url = "http://{0}:{1}/v3".format(config.get("auth_url", "keystone"), config.get("auth_port", "5000"))
52 self.user_domain_name = config.get("user_domain_name", "default")
53 self.admin_project = config.get("service_project", "service")
54 self.admin_username = config.get("service_username", "nbi")
55 self.admin_password = config.get("service_password", "nbi")
56 self.project_domain_name = config.get("project_domain_name", "default")
57
Eduardo Sousa29933fc2018-11-14 06:36:35 +000058 # Waiting for Keystone to be up
59 available = None
60 counter = 300
61 while available is None:
62 time.sleep(1)
63 try:
64 result = requests.get(self.auth_url)
65 available = True if result.status_code == 200 else None
66 except Exception:
67 counter -= 1
68 if counter == 0:
69 raise AuthException("Keystone not available after 300s timeout")
70
Eduardo Sousa819d34c2018-07-31 01:20:02 +010071 self.auth = v3.Password(user_domain_name=self.user_domain_name,
72 username=self.admin_username,
73 password=self.admin_password,
74 project_domain_name=self.project_domain_name,
75 project_name=self.admin_project,
76 auth_url=self.auth_url)
77 self.sess = session.Session(auth=self.auth)
78 self.keystone = client.Client(session=self.sess)
79
tierno38dcfeb2019-06-10 16:44:00 +000080 def authenticate(self, user, password, project=None, token=None):
Eduardo Sousa819d34c2018-07-31 01:20:02 +010081 """
tierno38dcfeb2019-06-10 16:44:00 +000082 Authenticate a user using username/password or token, plus project
83 :param user: user: name, id or None
84 :param password: password or None
85 :param project: name, id, or None. If None first found project will be used to get an scope token
86 :param token: previous token to obtain authorization
87 :return: the scoped token info or raises an exception. The token is a dictionary with:
88 _id: token string id,
89 username: username,
90 project_id: scoped_token project_id,
91 project_name: scoped_token project_name,
92 expires: epoch time when it expires,
Eduardo Sousa819d34c2018-07-31 01:20:02 +010093
Eduardo Sousa819d34c2018-07-31 01:20:02 +010094 """
95 try:
tierno38dcfeb2019-06-10 16:44:00 +000096 username = None
97 user_id = None
98 project_id = None
99 project_name = None
Eduardo Sousa819d34c2018-07-31 01:20:02 +0100100
tierno38dcfeb2019-06-10 16:44:00 +0000101 if user:
102 if is_valid_uuid(user):
103 user_id = user
104 else:
105 username = user
106
107 # get an unscoped token firstly
108 unscoped_token = self.keystone.get_raw_token_from_identity_service(
109 auth_url=self.auth_url,
110 user_id=user_id,
111 username=username,
112 password=password,
113 user_domain_name=self.user_domain_name,
114 project_domain_name=self.project_domain_name)
115 elif token:
116 unscoped_token = self.keystone.tokens.validate(token=token)
117 else:
118 raise AuthException("Provide credentials: username/password or Authorization Bearer token",
119 http_code=HTTPStatus.UNAUTHORIZED)
120
121 if not project:
122 # get first project for the user
123 project_list = self.keystone.projects.list(user=unscoped_token["user"]["id"])
124 if not project_list:
125 raise AuthException("The user {} has not any project and cannot be used for authentication".
126 format(user), http_code=HTTPStatus.UNAUTHORIZED)
127 project_id = project_list[0].id
128 else:
129 if is_valid_uuid(project):
130 project_id = project
131 else:
132 project_name = project
133
134 scoped_token = self.keystone.get_raw_token_from_identity_service(
Eduardo Sousa819d34c2018-07-31 01:20:02 +0100135 auth_url=self.auth_url,
tierno38dcfeb2019-06-10 16:44:00 +0000136 project_name=project_name,
137 project_id=project_id,
Eduardo Sousa819d34c2018-07-31 01:20:02 +0100138 user_domain_name=self.user_domain_name,
tierno38dcfeb2019-06-10 16:44:00 +0000139 project_domain_name=self.project_domain_name,
140 token=unscoped_token["auth_token"])
Eduardo Sousa819d34c2018-07-31 01:20:02 +0100141
tierno38dcfeb2019-06-10 16:44:00 +0000142 auth_token = {
143 "_id": scoped_token.auth_token,
144 "username": scoped_token.username,
145 "project_id": scoped_token.project_id,
146 "project_name": scoped_token.project_name,
147 "expires": scoped_token.expires.timestamp(),
148 }
149
150 return auth_token
tierno4015b472019-06-10 13:57:29 +0000151 except ClientException as e:
152 self.logger.exception("Error during user authentication using keystone. Method: basic: {}".format(e))
153 raise AuthException("Error during user authentication using Keystone: {}".format(e),
154 http_code=HTTPStatus.UNAUTHORIZED)
Eduardo Sousa819d34c2018-07-31 01:20:02 +0100155
tierno38dcfeb2019-06-10 16:44:00 +0000156 # def authenticate_with_token(self, token, project=None):
157 # """
158 # Authenticate a user using a token. Can be used to revalidate the token
159 # or to get a scoped token.
160 #
161 # :param token: a valid token.
162 # :param project: (optional) project for a scoped token.
163 # :return: return a revalidated token, scoped if a project was passed or
164 # the previous token was already scoped.
165 # """
166 # try:
167 # token_info = self.keystone.tokens.validate(token=token)
168 # projects = self.keystone.projects.list(user=token_info["user"]["id"])
169 # project_names = [project.name for project in projects]
170 #
171 # new_token = self.keystone.get_raw_token_from_identity_service(
172 # auth_url=self.auth_url,
173 # token=token,
174 # project_name=project,
175 # project_id=None,
176 # user_domain_name=self.user_domain_name,
177 # project_domain_name=self.project_domain_name)
178 #
179 # return new_token["auth_token"], project_names
180 # except ClientException as e:
181 # self.logger.exception("Error during user authentication using keystone. Method: bearer: {}".format(e))
182 # raise AuthException("Error during user authentication using Keystone: {}".format(e),
183 # http_code=HTTPStatus.UNAUTHORIZED)
Eduardo Sousa819d34c2018-07-31 01:20:02 +0100184
185 def validate_token(self, token):
186 """
187 Check if the token is valid.
188
189 :param token: token to validate
190 :return: dictionary with information associated with the token. If the
191 token is not valid, returns None.
192 """
193 if not token:
194 return
195
196 try:
197 token_info = self.keystone.tokens.validate(token=token)
198
199 return token_info
tierno4015b472019-06-10 13:57:29 +0000200 except ClientException as e:
201 self.logger.exception("Error during token validation using keystone: {}".format(e))
202 raise AuthException("Error during token validation using Keystone: {}".format(e),
203 http_code=HTTPStatus.UNAUTHORIZED)
Eduardo Sousa819d34c2018-07-31 01:20:02 +0100204
205 def revoke_token(self, token):
206 """
207 Invalidate a token.
208
209 :param token: token to be revoked
210 """
211 try:
Eduardo Sousa29933fc2018-11-14 06:36:35 +0000212 self.logger.info("Revoking token: " + token)
Eduardo Sousa819d34c2018-07-31 01:20:02 +0100213 self.keystone.tokens.revoke_token(token=token)
214
215 return True
tierno4015b472019-06-10 13:57:29 +0000216 except ClientException as e:
217 self.logger.exception("Error during token revocation using keystone: {}".format(e))
218 raise AuthException("Error during token revocation using Keystone: {}".format(e),
219 http_code=HTTPStatus.UNAUTHORIZED)
Eduardo Sousa819d34c2018-07-31 01:20:02 +0100220
Eduardo Sousa5c01e192019-05-08 02:35:47 +0100221 def get_user_project_list(self, token):
Eduardo Sousa819d34c2018-07-31 01:20:02 +0100222 """
223 Get all the projects associated with a user.
224
225 :param token: valid token
226 :return: list of projects
227 """
228 try:
229 token_info = self.keystone.tokens.validate(token=token)
230 projects = self.keystone.projects.list(user=token_info["user"]["id"])
231 project_names = [project.name for project in projects]
232
233 return project_names
tierno4015b472019-06-10 13:57:29 +0000234 except ClientException as e:
235 self.logger.exception("Error during user project listing using keystone: {}".format(e))
236 raise AuthException("Error during user project listing using Keystone: {}".format(e),
237 http_code=HTTPStatus.UNAUTHORIZED)
Eduardo Sousa819d34c2018-07-31 01:20:02 +0100238
Eduardo Sousa5c01e192019-05-08 02:35:47 +0100239 def get_user_role_list(self, token):
Eduardo Sousa819d34c2018-07-31 01:20:02 +0100240 """
241 Get role list for a scoped project.
242
243 :param token: scoped token.
244 :return: returns the list of roles for the user in that project. If
245 the token is unscoped it returns None.
246 """
247 try:
248 token_info = self.keystone.tokens.validate(token=token)
Eduardo Sousa29933fc2018-11-14 06:36:35 +0000249 roles_info = self.keystone.roles.list(user=token_info["user"]["id"], project=token_info["project"]["id"])
250
251 roles = [role.name for role in roles_info]
Eduardo Sousa819d34c2018-07-31 01:20:02 +0100252
253 return roles
tierno4015b472019-06-10 13:57:29 +0000254 except ClientException as e:
255 self.logger.exception("Error during user role listing using keystone: {}".format(e))
256 raise AuthException("Error during user role listing using Keystone: {}".format(e),
257 http_code=HTTPStatus.UNAUTHORIZED)
Eduardo Sousa819d34c2018-07-31 01:20:02 +0100258
259 def create_user(self, user, password):
260 """
261 Create a user.
262
263 :param user: username.
264 :param password: password.
265 :raises AuthconnOperationException: if user creation failed.
Eduardo Sousa5c01e192019-05-08 02:35:47 +0100266 :return: returns the id of the user in keystone.
Eduardo Sousa819d34c2018-07-31 01:20:02 +0100267 """
268 try:
Eduardo Sousa5c01e192019-05-08 02:35:47 +0100269 new_user = self.keystone.users.create(user, password=password, domain=self.user_domain_name)
270 return {"username": new_user.name, "_id": new_user.id}
tierno4015b472019-06-10 13:57:29 +0000271 except ClientException as e:
272 self.logger.exception("Error during user creation using keystone: {}".format(e))
273 raise AuthconnOperationException("Error during user creation using Keystone: {}".format(e))
Eduardo Sousa819d34c2018-07-31 01:20:02 +0100274
275 def change_password(self, user, new_password):
276 """
277 Change the user password.
278
279 :param user: username.
280 :param new_password: new password.
281 :raises AuthconnOperationException: if user password change failed.
282 """
283 try:
Eduardo Sousa29933fc2018-11-14 06:36:35 +0000284 user_obj = list(filter(lambda x: x.name == user, self.keystone.users.list()))[0]
285 self.keystone.users.update(user_obj, password=new_password)
tierno4015b472019-06-10 13:57:29 +0000286 except ClientException as e:
287 self.logger.exception("Error during user password update using keystone: {}".format(e))
288 raise AuthconnOperationException("Error during user password update using Keystone: {}".format(e))
Eduardo Sousa819d34c2018-07-31 01:20:02 +0100289
Eduardo Sousa5c01e192019-05-08 02:35:47 +0100290 def delete_user(self, user_id):
Eduardo Sousa819d34c2018-07-31 01:20:02 +0100291 """
292 Delete user.
293
Eduardo Sousa5c01e192019-05-08 02:35:47 +0100294 :param user_id: user identifier.
Eduardo Sousa819d34c2018-07-31 01:20:02 +0100295 :raises AuthconnOperationException: if user deletion failed.
296 """
297 try:
tierno38dcfeb2019-06-10 16:44:00 +0000298 # users = self.keystone.users.list()
299 # user_obj = [user for user in users if user.id == user_id][0]
300 # result, _ = self.keystone.users.delete(user_obj)
Eduardo Sousa5c01e192019-05-08 02:35:47 +0100301
tierno38dcfeb2019-06-10 16:44:00 +0000302 result, detail = self.keystone.users.delete(user_id)
Eduardo Sousa5c01e192019-05-08 02:35:47 +0100303 if result.status_code != 204:
tierno38dcfeb2019-06-10 16:44:00 +0000304 raise ClientException("error {} {}".format(result.status_code, detail))
Eduardo Sousa5c01e192019-05-08 02:35:47 +0100305
306 return True
tierno4015b472019-06-10 13:57:29 +0000307 except ClientException as e:
308 self.logger.exception("Error during user deletion using keystone: {}".format(e))
309 raise AuthconnOperationException("Error during user deletion using Keystone: {}".format(e))
Eduardo Sousa819d34c2018-07-31 01:20:02 +0100310
Eduardo Sousa2d5a5152019-05-20 15:41:54 +0100311 def get_user_list(self, filter_q={}):
Eduardo Sousa5c01e192019-05-08 02:35:47 +0100312 """
313 Get user list.
314
Eduardo Sousa2d5a5152019-05-20 15:41:54 +0100315 :param filter_q: dictionary to filter user list.
Eduardo Sousa5c01e192019-05-08 02:35:47 +0100316 :return: returns a list of users.
317 """
318 try:
319 users = self.keystone.users.list()
320 users = [{
321 "username": user.name,
Eduardo Sousa203bad82019-05-23 01:41:18 +0100322 "_id": user.id,
323 "id": user.id
Eduardo Sousa5c01e192019-05-08 02:35:47 +0100324 } for user in users if user.name != self.admin_username]
325
Eduardo Sousa203bad82019-05-23 01:41:18 +0100326 allowed_fields = ["_id", "id", "username"]
Eduardo Sousa2d5a5152019-05-20 15:41:54 +0100327 for key in filter_q.keys():
328 if key not in allowed_fields:
329 continue
330
331 users = [user for user in users
332 if filter_q[key] == user[key]]
333
Eduardo Sousa5c01e192019-05-08 02:35:47 +0100334 for user in users:
335 projects = self.keystone.projects.list(user=user["_id"])
336 projects = [{
337 "name": project.name,
Eduardo Sousa203bad82019-05-23 01:41:18 +0100338 "_id": project.id,
339 "id": project.id
Eduardo Sousa5c01e192019-05-08 02:35:47 +0100340 } for project in projects]
341
342 for project in projects:
343 roles = self.keystone.roles.list(user=user["_id"], project=project["_id"])
344 roles = [{
345 "name": role.name,
Eduardo Sousa203bad82019-05-23 01:41:18 +0100346 "_id": role.id,
347 "id": role.id
Eduardo Sousa5c01e192019-05-08 02:35:47 +0100348 } for role in roles]
349 project["roles"] = roles
350
351 user["projects"] = projects
352
353 return users
tierno4015b472019-06-10 13:57:29 +0000354 except ClientException as e:
355 self.logger.exception("Error during user listing using keystone: {}".format(e))
356 raise AuthconnOperationException("Error during user listing using Keystone: {}".format(e))
Eduardo Sousa5c01e192019-05-08 02:35:47 +0100357
358 def get_role_list(self):
359 """
360 Get role list.
361
Eduardo Sousa37de0912019-05-23 02:17:22 +0100362 :return: returns the list of roles.
Eduardo Sousa5c01e192019-05-08 02:35:47 +0100363 """
364 try:
365 roles_list = self.keystone.roles.list()
366
367 roles = [{
368 "name": role.name,
369 "_id": role.id
370 } for role in roles_list if role.name != "service"]
371
372 return roles
tierno4015b472019-06-10 13:57:29 +0000373 except ClientException as e:
374 self.logger.exception("Error during user role listing using keystone: {}".format(e))
375 raise AuthException("Error during user role listing using Keystone: {}".format(e),
376 http_code=HTTPStatus.UNAUTHORIZED)
Eduardo Sousa5c01e192019-05-08 02:35:47 +0100377
Eduardo Sousa819d34c2018-07-31 01:20:02 +0100378 def create_role(self, role):
379 """
380 Create a role.
381
382 :param role: role name.
383 :raises AuthconnOperationException: if role creation failed.
384 """
385 try:
Eduardo Sousa5c01e192019-05-08 02:35:47 +0100386 result = self.keystone.roles.create(role)
387 return {"name": result.name, "_id": result.id}
Eduardo Sousa29933fc2018-11-14 06:36:35 +0000388 except Conflict as ex:
389 self.logger.info("Duplicate entry: %s", str(ex))
tierno4015b472019-06-10 13:57:29 +0000390 except ClientException as e:
391 self.logger.exception("Error during role creation using keystone: {}".format(e))
392 raise AuthconnOperationException("Error during role creation using Keystone: {}".format(e))
Eduardo Sousa819d34c2018-07-31 01:20:02 +0100393
Eduardo Sousa5c01e192019-05-08 02:35:47 +0100394 def delete_role(self, role_id):
Eduardo Sousa819d34c2018-07-31 01:20:02 +0100395 """
396 Delete a role.
397
Eduardo Sousa5c01e192019-05-08 02:35:47 +0100398 :param role_id: role identifier.
Eduardo Sousa819d34c2018-07-31 01:20:02 +0100399 :raises AuthconnOperationException: if role deletion failed.
400 """
401 try:
Eduardo Sousa5c01e192019-05-08 02:35:47 +0100402 roles = self.keystone.roles.list()
403 role_obj = [role for role in roles if role.id == role_id][0]
tierno38dcfeb2019-06-10 16:44:00 +0000404 result, detail = self.keystone.roles.delete(role_obj)
Eduardo Sousa5c01e192019-05-08 02:35:47 +0100405
406 if result.status_code != 204:
tierno38dcfeb2019-06-10 16:44:00 +0000407 raise ClientException("error {} {}".format(result.status_code, detail))
Eduardo Sousa5c01e192019-05-08 02:35:47 +0100408
409 return True
tierno4015b472019-06-10 13:57:29 +0000410 except ClientException as e:
411 self.logger.exception("Error during role deletion using keystone: {}".format(e))
412 raise AuthconnOperationException("Error during role deletion using Keystone: {}".format(e))
Eduardo Sousa819d34c2018-07-31 01:20:02 +0100413
tierno38dcfeb2019-06-10 16:44:00 +0000414 def get_project_list(self, filter_q=None):
Eduardo Sousa5c01e192019-05-08 02:35:47 +0100415 """
416 Get all the projects.
417
Eduardo Sousafa54cd92019-05-20 15:58:41 +0100418 :param filter_q: dictionary to filter project list.
Eduardo Sousa5c01e192019-05-08 02:35:47 +0100419 :return: list of projects
420 """
421 try:
tierno38dcfeb2019-06-10 16:44:00 +0000422 filter_name = None
423 if filter_q:
424 filter_name = filter_q.get("name")
425 projects = self.keystone.projects.list(name=filter_name)
426
Eduardo Sousa5c01e192019-05-08 02:35:47 +0100427 projects = [{
428 "name": project.name,
429 "_id": project.id
tierno38dcfeb2019-06-10 16:44:00 +0000430 } for project in projects]
Eduardo Sousa5c01e192019-05-08 02:35:47 +0100431
tierno38dcfeb2019-06-10 16:44:00 +0000432 if filter_q and filter_q.get("_id"):
Eduardo Sousafa54cd92019-05-20 15:58:41 +0100433 projects = [project for project in projects
tierno38dcfeb2019-06-10 16:44:00 +0000434 if filter_q["_id"] == project["_id"]]
Eduardo Sousafa54cd92019-05-20 15:58:41 +0100435
Eduardo Sousa5c01e192019-05-08 02:35:47 +0100436 return projects
tierno4015b472019-06-10 13:57:29 +0000437 except ClientException as e:
438 self.logger.exception("Error during user project listing using keystone: {}".format(e))
439 raise AuthException("Error during user project listing using Keystone: {}".format(e),
440 http_code=HTTPStatus.UNAUTHORIZED)
Eduardo Sousa5c01e192019-05-08 02:35:47 +0100441
Eduardo Sousa819d34c2018-07-31 01:20:02 +0100442 def create_project(self, project):
443 """
444 Create a project.
445
446 :param project: project name.
tierno4015b472019-06-10 13:57:29 +0000447 :return: the internal id of the created project
Eduardo Sousa819d34c2018-07-31 01:20:02 +0100448 :raises AuthconnOperationException: if project creation failed.
449 """
450 try:
Eduardo Sousa5c01e192019-05-08 02:35:47 +0100451 result = self.keystone.projects.create(project, self.project_domain_name)
tierno4015b472019-06-10 13:57:29 +0000452 return result.id
453 except ClientException as e:
454 self.logger.exception("Error during project creation using keystone: {}".format(e))
455 raise AuthconnOperationException("Error during project creation using Keystone: {}".format(e))
Eduardo Sousa819d34c2018-07-31 01:20:02 +0100456
Eduardo Sousa5c01e192019-05-08 02:35:47 +0100457 def delete_project(self, project_id):
Eduardo Sousa819d34c2018-07-31 01:20:02 +0100458 """
459 Delete a project.
460
Eduardo Sousa5c01e192019-05-08 02:35:47 +0100461 :param project_id: project identifier.
Eduardo Sousa819d34c2018-07-31 01:20:02 +0100462 :raises AuthconnOperationException: if project deletion failed.
463 """
464 try:
tierno38dcfeb2019-06-10 16:44:00 +0000465 # projects = self.keystone.projects.list()
466 # project_obj = [project for project in projects if project.id == project_id][0]
467 # result, _ = self.keystone.projects.delete(project_obj)
Eduardo Sousa5c01e192019-05-08 02:35:47 +0100468
tierno38dcfeb2019-06-10 16:44:00 +0000469 result, detail = self.keystone.projects.delete(project_id)
Eduardo Sousa5c01e192019-05-08 02:35:47 +0100470 if result.status_code != 204:
tierno38dcfeb2019-06-10 16:44:00 +0000471 raise ClientException("error {} {}".format(result.status_code, detail))
Eduardo Sousa5c01e192019-05-08 02:35:47 +0100472
473 return True
tierno4015b472019-06-10 13:57:29 +0000474 except ClientException as e:
475 self.logger.exception("Error during project deletion using keystone: {}".format(e))
476 raise AuthconnOperationException("Error during project deletion using Keystone: {}".format(e))
477
478 def update_project(self, project_id, new_name):
479 """
480 Change the name of a project
481 :param project_id: project to be changed
482 :param new_name: new name
483 :return: None
484 """
485 try:
486 self.keystone.projects.update(project_id, name=new_name)
487 except ClientException as e:
488 self.logger.exception("Error during project update using keystone: {}".format(e))
489 raise AuthconnOperationException("Error during project deletion using Keystone: {}".format(e))
Eduardo Sousa819d34c2018-07-31 01:20:02 +0100490
491 def assign_role_to_user(self, user, project, role):
492 """
493 Assigning a role to a user in a project.
494
495 :param user: username.
496 :param project: project name.
497 :param role: role name.
498 :raises AuthconnOperationException: if role assignment failed.
499 """
500 try:
Eduardo Sousa44603902019-06-04 08:10:32 +0100501 if is_valid_uuid(user):
502 user_obj = self.keystone.users.get(user)
503 else:
504 user_obj = self.keystone.users.list(name=user)[0]
505
506 if is_valid_uuid(project):
507 project_obj = self.keystone.projects.get(project)
508 else:
509 project_obj = self.keystone.projects.list(name=project)[0]
510
511 if is_valid_uuid(role):
512 role_obj = self.keystone.roles.get(role)
513 else:
514 role_obj = self.keystone.roles.list(name=role)[0]
Eduardo Sousa819d34c2018-07-31 01:20:02 +0100515
Eduardo Sousa29933fc2018-11-14 06:36:35 +0000516 self.keystone.roles.grant(role_obj, user=user_obj, project=project_obj)
tierno4015b472019-06-10 13:57:29 +0000517 except ClientException as e:
518 self.logger.exception("Error during user role assignment using keystone: {}".format(e))
519 raise AuthconnOperationException("Error during user role assignment using Keystone: {}".format(e))
Eduardo Sousa819d34c2018-07-31 01:20:02 +0100520
521 def remove_role_from_user(self, user, project, role):
522 """
523 Remove a role from a user in a project.
524
525 :param user: username.
526 :param project: project name.
527 :param role: role name.
528 :raises AuthconnOperationException: if role assignment revocation failed.
529 """
530 try:
Eduardo Sousa29933fc2018-11-14 06:36:35 +0000531 user_obj = list(filter(lambda x: x.name == user, self.keystone.users.list()))[0]
532 project_obj = list(filter(lambda x: x.name == project, self.keystone.projects.list()))[0]
533 role_obj = list(filter(lambda x: x.name == role, self.keystone.roles.list()))[0]
Eduardo Sousa819d34c2018-07-31 01:20:02 +0100534
Eduardo Sousa29933fc2018-11-14 06:36:35 +0000535 self.keystone.roles.revoke(role_obj, user=user_obj, project=project_obj)
tierno4015b472019-06-10 13:57:29 +0000536 except ClientException as e:
537 self.logger.exception("Error during user role revocation using keystone: {}".format(e))
538 raise AuthconnOperationException("Error during user role revocation using Keystone: {}".format(e))