6e33ed6b5a7436f4dc7b7d66861fff5d9e7b9676
[osm/NBI.git] / authconn_keystone.py
1 # -*- coding: utf-8 -*-
2
3 """
4 AuthconnKeystone implements implements the connector for
5 Openstack Keystone and leverages the RBAC model, to bring
6 it for OSM.
7 """
8
9 __author__ = "Eduardo Sousa <esousa@whitestack.com>"
10 __date__ = "$27-jul-2018 23:59:59$"
11
12 from authconn import Authconn, AuthException, AuthconnOperationException
13
14 import logging
15 from keystoneauth1 import session
16 from keystoneauth1.identity import v3
17 from keystoneauth1.exceptions.base import ClientException
18 from keystoneclient.v3 import client
19 from http import HTTPStatus
20
21
22 class AuthconnKeystone(Authconn):
23 def __init__(self, config):
24 Authconn.__init__(self, config)
25
26 self.logger = logging.getLogger("nbi.authenticator.keystone")
27
28 self.auth_url = "http://{0}:{1}/v3".format(config.get("auth_url", "keystone"), config.get("auth_port", "5000"))
29 self.user_domain_name = config.get("user_domain_name", "default")
30 self.admin_project = config.get("service_project", "service")
31 self.admin_username = config.get("service_username", "nbi")
32 self.admin_password = config.get("service_password", "nbi")
33 self.project_domain_name = config.get("project_domain_name", "default")
34
35 self.auth = v3.Password(user_domain_name=self.user_domain_name,
36 username=self.admin_username,
37 password=self.admin_password,
38 project_domain_name=self.project_domain_name,
39 project_name=self.admin_project,
40 auth_url=self.auth_url)
41 self.sess = session.Session(auth=self.auth)
42 self.keystone = client.Client(session=self.sess)
43
44 def authenticate_with_user_password(self, user, password):
45 """
46 Authenticate a user using username and password.
47
48 :param user: username
49 :param password: password
50 :return: an unscoped token that grants access to project list
51 """
52 try:
53 user_id = list(filter(lambda x: x.name == user, self.keystone.users.list()))[0].id
54 project_names = [project.name for project in self.keystone.projects.list(user=user_id)]
55
56 token = self.keystone.get_raw_token_from_identity_service(
57 auth_url=self.auth_url,
58 username=user,
59 password=password,
60 user_domain_name=self.user_domain_name,
61 project_domain_name=self.project_domain_name)
62
63 return token["auth_token"], project_names
64 except ClientException:
65 self.logger.exception("Error during user authentication using keystone. Method: basic")
66 raise AuthException("Error during user authentication using Keystone", http_code=HTTPStatus.UNAUTHORIZED)
67
68 def authenticate_with_token(self, token, project=None):
69 """
70 Authenticate a user using a token. Can be used to revalidate the token
71 or to get a scoped token.
72
73 :param token: a valid token.
74 :param project: (optional) project for a scoped token.
75 :return: return a revalidated token, scoped if a project was passed or
76 the previous token was already scoped.
77 """
78 try:
79 token_info = self.keystone.tokens.validate(token=token)
80 projects = self.keystone.projects.list(user=token_info["user"]["id"])
81 project_names = [project.name for project in projects]
82
83 token = self.keystone.get_raw_token_from_identity_service(
84 auth_url=self.auth_url,
85 token=token,
86 project_name=project,
87 user_domain_name=self.user_domain_name,
88 project_domain_name=self.project_domain_name)
89
90 return token["auth_token"], project_names
91 except ClientException:
92 self.logger.exception("Error during user authentication using keystone. Method: bearer")
93 raise AuthException("Error during user authentication using Keystone", http_code=HTTPStatus.UNAUTHORIZED)
94
95 def validate_token(self, token):
96 """
97 Check if the token is valid.
98
99 :param token: token to validate
100 :return: dictionary with information associated with the token. If the
101 token is not valid, returns None.
102 """
103 if not token:
104 return
105
106 try:
107 token_info = self.keystone.tokens.validate(token=token)
108
109 return token_info
110 except ClientException:
111 self.logger.exception("Error during token validation using keystone")
112 raise AuthException("Error during token validation using Keystone", http_code=HTTPStatus.UNAUTHORIZED)
113
114 def revoke_token(self, token):
115 """
116 Invalidate a token.
117
118 :param token: token to be revoked
119 """
120 try:
121 self.keystone.tokens.revoke_token(token=token)
122
123 return True
124 except ClientException:
125 self.logger.exception("Error during token revocation using keystone")
126 raise AuthException("Error during token revocation using Keystone", http_code=HTTPStatus.UNAUTHORIZED)
127
128 def get_project_list(self, token):
129 """
130 Get all the projects associated with a user.
131
132 :param token: valid token
133 :return: list of projects
134 """
135 try:
136 token_info = self.keystone.tokens.validate(token=token)
137 projects = self.keystone.projects.list(user=token_info["user"]["id"])
138 project_names = [project.name for project in projects]
139
140 return project_names
141 except ClientException:
142 self.logger.exception("Error during user project listing using keystone")
143 raise AuthException("Error during user project listing using Keystone", http_code=HTTPStatus.UNAUTHORIZED)
144
145 def get_role_list(self, token):
146 """
147 Get role list for a scoped project.
148
149 :param token: scoped token.
150 :return: returns the list of roles for the user in that project. If
151 the token is unscoped it returns None.
152 """
153 try:
154 token_info = self.keystone.tokens.validate(token=token)
155 roles = self.keystone.roles.list(user=token_info["user"]["id"], project=token_info["project"]["id"])
156
157 return roles
158 except ClientException:
159 self.logger.exception("Error during user role listing using keystone")
160 raise AuthException("Error during user role listing using Keystone", http_code=HTTPStatus.UNAUTHORIZED)
161
162 def create_user(self, user, password):
163 """
164 Create a user.
165
166 :param user: username.
167 :param password: password.
168 :raises AuthconnOperationException: if user creation failed.
169 """
170 try:
171 result = self.keystone.users.create(user, password=password, domain=self.user_domain_name)
172
173 if not result:
174 raise ClientException()
175 except ClientException:
176 self.logger.exception("Error during user creation using keystone")
177 raise AuthconnOperationException("Error during user creation using Keystone")
178
179 def change_password(self, user, new_password):
180 """
181 Change the user password.
182
183 :param user: username.
184 :param new_password: new password.
185 :raises AuthconnOperationException: if user password change failed.
186 """
187 try:
188 result = self.keystone.users.update(user, password=new_password)
189
190 if not result:
191 raise ClientException()
192 except ClientException:
193 self.logger.exception("Error during user password update using keystone")
194 raise AuthconnOperationException("Error during user password update using Keystone")
195
196 def delete_user(self, user):
197 """
198 Delete user.
199
200 :param user: username.
201 :raises AuthconnOperationException: if user deletion failed.
202 """
203 try:
204 result = self.keystone.users.delete(user)
205
206 if not result:
207 raise ClientException()
208 except ClientException:
209 self.logger.exception("Error during user deletion using keystone")
210 raise AuthconnOperationException("Error during user deletion using Keystone")
211
212 def create_role(self, role):
213 """
214 Create a role.
215
216 :param role: role name.
217 :raises AuthconnOperationException: if role creation failed.
218 """
219 try:
220 result = self.keystone.roles.create(role, domain=self.user_domain_name)
221
222 if not result:
223 raise ClientException()
224 except ClientException:
225 self.logger.exception("Error during role creation using keystone")
226 raise AuthconnOperationException("Error during role creation using Keystone")
227
228 def delete_role(self, role):
229 """
230 Delete a role.
231
232 :param role: role name.
233 :raises AuthconnOperationException: if role deletion failed.
234 """
235 try:
236 result = self.keystone.roles.delete(role)
237
238 if not result:
239 raise ClientException()
240 except ClientException:
241 self.logger.exception("Error during role deletion using keystone")
242 raise AuthconnOperationException("Error during role deletion using Keystone")
243
244 def create_project(self, project):
245 """
246 Create a project.
247
248 :param project: project name.
249 :raises AuthconnOperationException: if project creation failed.
250 """
251 try:
252 result = self.keystone.project.create(project, self.project_domain_name)
253
254 if not result:
255 raise ClientException()
256 except ClientException:
257 self.logger.exception("Error during project creation using keystone")
258 raise AuthconnOperationException("Error during project creation using Keystone")
259
260 def delete_project(self, project):
261 """
262 Delete a project.
263
264 :param project: project name.
265 :raises AuthconnOperationException: if project deletion failed.
266 """
267 try:
268 result = self.keystone.project.delete(project)
269
270 if not result:
271 raise ClientException()
272 except ClientException:
273 self.logger.exception("Error during project deletion using keystone")
274 raise AuthconnOperationException("Error during project deletion using Keystone")
275
276 def assign_role_to_user(self, user, project, role):
277 """
278 Assigning a role to a user in a project.
279
280 :param user: username.
281 :param project: project name.
282 :param role: role name.
283 :raises AuthconnOperationException: if role assignment failed.
284 """
285 try:
286 result = self.keystone.roles.grant(role, user=user, project=project)
287
288 if not result:
289 raise ClientException()
290 except ClientException:
291 self.logger.exception("Error during user role assignment using keystone")
292 raise AuthconnOperationException("Error during user role assignment using Keystone")
293
294 def remove_role_from_user(self, user, project, role):
295 """
296 Remove a role from a user in a project.
297
298 :param user: username.
299 :param project: project name.
300 :param role: role name.
301 :raises AuthconnOperationException: if role assignment revocation failed.
302 """
303 try:
304 result = self.keystone.roles.revoke(role, user=user, project=project)
305
306 if not result:
307 raise ClientException()
308 except ClientException:
309 self.logger.exception("Error during user role revocation using keystone")
310 raise AuthconnOperationException("Error during user role revocation using Keystone")