1 # -*- coding: utf-8 -*-
4 AuthconnKeystone implements implements the connector for
5 Openstack Keystone and leverages the RBAC model, to bring
9 __author__
= "Eduardo Sousa <esousa@whitestack.com>"
10 __date__
= "$27-jul-2018 23:59:59$"
12 from authconn
import Authconn
, AuthException
, AuthconnOperationException
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
22 class AuthconnKeystone(Authconn
):
23 def __init__(self
, config
):
24 Authconn
.__init
__(self
, config
)
26 self
.logger
= logging
.getLogger("nbi.authenticator.keystone")
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")
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
)
44 def authenticate_with_user_password(self
, user
, password
):
46 Authenticate a user using username and password.
49 :param password: password
50 :return: an unscoped token that grants access to project list
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
)]
56 token
= self
.keystone
.get_raw_token_from_identity_service(
57 auth_url
=self
.auth_url
,
60 user_domain_name
=self
.user_domain_name
,
61 project_domain_name
=self
.project_domain_name
)
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
)
68 def authenticate_with_token(self
, token
, project
=None):
70 Authenticate a user using a token. Can be used to revalidate the token
71 or to get a scoped token.
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.
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
]
83 token
= self
.keystone
.get_raw_token_from_identity_service(
84 auth_url
=self
.auth_url
,
87 user_domain_name
=self
.user_domain_name
,
88 project_domain_name
=self
.project_domain_name
)
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
)
95 def validate_token(self
, token
):
97 Check if the token is valid.
99 :param token: token to validate
100 :return: dictionary with information associated with the token. If the
101 token is not valid, returns None.
107 token_info
= self
.keystone
.tokens
.validate(token
=token
)
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
)
114 def revoke_token(self
, token
):
118 :param token: token to be revoked
121 self
.keystone
.tokens
.revoke_token(token
=token
)
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
)
128 def get_project_list(self
, token
):
130 Get all the projects associated with a user.
132 :param token: valid token
133 :return: list of projects
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
]
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
)
145 def get_role_list(self
, token
):
147 Get role list for a scoped project.
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.
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"])
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
)
162 def create_user(self
, user
, password
):
166 :param user: username.
167 :param password: password.
168 :raises AuthconnOperationException: if user creation failed.
171 result
= self
.keystone
.users
.create(user
, password
=password
, domain
=self
.user_domain_name
)
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")
179 def change_password(self
, user
, new_password
):
181 Change the user password.
183 :param user: username.
184 :param new_password: new password.
185 :raises AuthconnOperationException: if user password change failed.
188 result
= self
.keystone
.users
.update(user
, password
=new_password
)
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")
196 def delete_user(self
, user
):
200 :param user: username.
201 :raises AuthconnOperationException: if user deletion failed.
204 result
= self
.keystone
.users
.delete(user
)
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")
212 def create_role(self
, role
):
216 :param role: role name.
217 :raises AuthconnOperationException: if role creation failed.
220 result
= self
.keystone
.roles
.create(role
, domain
=self
.user_domain_name
)
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")
228 def delete_role(self
, role
):
232 :param role: role name.
233 :raises AuthconnOperationException: if role deletion failed.
236 result
= self
.keystone
.roles
.delete(role
)
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")
244 def create_project(self
, project
):
248 :param project: project name.
249 :raises AuthconnOperationException: if project creation failed.
252 result
= self
.keystone
.project
.create(project
, self
.project_domain_name
)
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")
260 def delete_project(self
, project
):
264 :param project: project name.
265 :raises AuthconnOperationException: if project deletion failed.
268 result
= self
.keystone
.project
.delete(project
)
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")
276 def assign_role_to_user(self
, user
, project
, role
):
278 Assigning a role to a user in a project.
280 :param user: username.
281 :param project: project name.
282 :param role: role name.
283 :raises AuthconnOperationException: if role assignment failed.
286 result
= self
.keystone
.roles
.grant(role
, user
=user
, project
=project
)
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")
294 def remove_role_from_user(self
, user
, project
, role
):
296 Remove a role from a user in a project.
298 :param user: username.
299 :param project: project name.
300 :param role: role name.
301 :raises AuthconnOperationException: if role assignment revocation failed.
304 result
= self
.keystone
.roles
.revoke(role
, user
=user
, project
=project
)
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")