blob: bbcf3422705d4419341a6dfd17e0fdffa2d1ca0f [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"""
22Authconn implements an Abstract class for the Auth backend connector
23plugins with the definition of the methods to be implemented.
24"""
25
tierno23acf402019-08-28 13:36:34 +000026__author__ = "Eduardo Sousa <esousa@whitestack.com>, " \
27 "Pedro de la Cruz Ramos <pdelacruzramos@altran.com>"
Eduardo Sousa819d34c2018-07-31 01:20:02 +010028__date__ = "$27-jul-2018 23:59:59$"
29
30from http import HTTPStatus
tierno23acf402019-08-28 13:36:34 +000031from osm_nbi.base_topic import BaseTopic
Eduardo Sousa819d34c2018-07-31 01:20:02 +010032
33
34class AuthException(Exception):
35 """
tiernoc8445362019-06-14 12:07:15 +000036 Authentication error, because token, user password not recognized
Eduardo Sousa819d34c2018-07-31 01:20:02 +010037 """
38 def __init__(self, message, http_code=HTTPStatus.UNAUTHORIZED):
Eduardo Sousa5c01e192019-05-08 02:35:47 +010039 super(AuthException, self).__init__(message)
Eduardo Sousa819d34c2018-07-31 01:20:02 +010040 self.http_code = http_code
Eduardo Sousa819d34c2018-07-31 01:20:02 +010041
42
tiernoc8445362019-06-14 12:07:15 +000043class AuthExceptionUnauthorized(AuthException):
44 """
45 Authentication error, because not having rights to make this operation
46 """
47 pass
48
49
Eduardo Sousa819d34c2018-07-31 01:20:02 +010050class AuthconnException(Exception):
51 """
52 Common and base class Exception for all authconn exceptions.
53 """
54 def __init__(self, message, http_code=HTTPStatus.UNAUTHORIZED):
Eduardo Sousa5c01e192019-05-08 02:35:47 +010055 super(AuthconnException, self).__init__(message)
Eduardo Sousa819d34c2018-07-31 01:20:02 +010056 self.http_code = http_code
57
58
59class AuthconnConnectionException(AuthconnException):
60 """
61 Connectivity error with Auth backend.
62 """
63 def __init__(self, message, http_code=HTTPStatus.BAD_GATEWAY):
Eduardo Sousa5c01e192019-05-08 02:35:47 +010064 super(AuthconnConnectionException, self).__init__(message, http_code)
Eduardo Sousa819d34c2018-07-31 01:20:02 +010065
66
67class AuthconnNotSupportedException(AuthconnException):
68 """
69 The request is not supported by the Auth backend.
70 """
71 def __init__(self, message, http_code=HTTPStatus.NOT_IMPLEMENTED):
Eduardo Sousa5c01e192019-05-08 02:35:47 +010072 super(AuthconnNotSupportedException, self).__init__(message, http_code)
Eduardo Sousa819d34c2018-07-31 01:20:02 +010073
74
75class AuthconnNotImplementedException(AuthconnException):
76 """
77 The method is not implemented by the Auth backend.
78 """
79 def __init__(self, message, http_code=HTTPStatus.NOT_IMPLEMENTED):
Eduardo Sousa5c01e192019-05-08 02:35:47 +010080 super(AuthconnNotImplementedException, self).__init__(message, http_code)
Eduardo Sousa819d34c2018-07-31 01:20:02 +010081
82
83class AuthconnOperationException(AuthconnException):
84 """
85 The operation executed failed.
86 """
87 def __init__(self, message, http_code=HTTPStatus.INTERNAL_SERVER_ERROR):
Eduardo Sousa5c01e192019-05-08 02:35:47 +010088 super(AuthconnOperationException, self).__init__(message, http_code)
Eduardo Sousa819d34c2018-07-31 01:20:02 +010089
90
tiernocf042d32019-06-13 09:06:40 +000091class AuthconnNotFoundException(AuthconnException):
92 """
93 The operation executed failed because element not found.
94 """
95 def __init__(self, message, http_code=HTTPStatus.NOT_FOUND):
96 super().__init__(message, http_code)
97
98
tierno1f029d82019-06-13 22:37:04 +000099class AuthconnConflictException(AuthconnException):
100 """
101 The operation has conflicts.
102 """
103 def __init__(self, message, http_code=HTTPStatus.CONFLICT):
104 super().__init__(message, http_code)
105
106
Eduardo Sousa819d34c2018-07-31 01:20:02 +0100107class Authconn:
108 """
109 Abstract base class for all the Auth backend connector plugins.
110 Each Auth backend connector plugin must be a subclass of
111 Authconn class.
112 """
tierno9e87a7f2020-03-23 09:24:10 +0000113 def __init__(self, config, db, role_permissions):
Eduardo Sousa819d34c2018-07-31 01:20:02 +0100114 """
115 Constructor of the Authconn class.
Eduardo Sousa819d34c2018-07-31 01:20:02 +0100116 :param config: configuration dictionary containing all the
117 necessary configuration parameters.
tierno9e87a7f2020-03-23 09:24:10 +0000118 :param db: internal database classs
119 :param role_permissions: read only role permission list
Eduardo Sousa819d34c2018-07-31 01:20:02 +0100120 """
121 self.config = config
tierno9e87a7f2020-03-23 09:24:10 +0000122 self.role_permissions = role_permissions
Eduardo Sousa819d34c2018-07-31 01:20:02 +0100123
tierno6486f742020-02-13 16:30:14 +0000124 def authenticate(self, credentials, token_info=None):
Eduardo Sousa819d34c2018-07-31 01:20:02 +0100125 """
tierno701018c2019-06-25 11:13:14 +0000126 Authenticate a user using username/password or token_info, plus project
tierno6486f742020-02-13 16:30:14 +0000127 :param credentials: dictionary that contains:
128 username: name, id or None
129 password: password or None
130 project_id: name, id, or None. If None first found project will be used to get an scope token
131 other items are allowed for specific auth backends
tierno701018c2019-06-25 11:13:14 +0000132 :param token_info: previous token_info to obtain authorization
tierno38dcfeb2019-06-10 16:44:00 +0000133 :return: the scoped token info or raises an exception. The token is a dictionary with:
134 _id: token string id,
135 username: username,
136 project_id: scoped_token project_id,
137 project_name: scoped_token project_name,
138 expires: epoch time when it expires,
Eduardo Sousa819d34c2018-07-31 01:20:02 +0100139
Eduardo Sousa819d34c2018-07-31 01:20:02 +0100140 """
141 raise AuthconnNotImplementedException("Should have implemented this")
142
Eduardo Sousa819d34c2018-07-31 01:20:02 +0100143 def validate_token(self, token):
144 """
145 Check if the token is valid.
146
147 :param token: token to validate
148 :return: dictionary with information associated with the token. If the
149 token is not valid, returns None.
150 """
151 raise AuthconnNotImplementedException("Should have implemented this")
152
153 def revoke_token(self, token):
154 """
155 Invalidate a token.
156
157 :param token: token to be revoked
158 """
159 raise AuthconnNotImplementedException("Should have implemented this")
160
delacruzramo01b15d32019-07-02 14:37:47 +0200161 def create_user(self, user_info):
Eduardo Sousa819d34c2018-07-31 01:20:02 +0100162 """
163 Create a user.
164
delacruzramo01b15d32019-07-02 14:37:47 +0200165 :param user_info: full user info.
Eduardo Sousa819d34c2018-07-31 01:20:02 +0100166 :raises AuthconnOperationException: if user creation failed.
167 """
168 raise AuthconnNotImplementedException("Should have implemented this")
169
delacruzramo01b15d32019-07-02 14:37:47 +0200170 def update_user(self, user_info):
Eduardo Sousa819d34c2018-07-31 01:20:02 +0100171 """
tiernocf042d32019-06-13 09:06:40 +0000172 Change the user name and/or password.
Eduardo Sousa819d34c2018-07-31 01:20:02 +0100173
delacruzramo01b15d32019-07-02 14:37:47 +0200174 :param user_info: user info modifications
175 :raises AuthconnNotImplementedException: if function not implemented
Eduardo Sousa819d34c2018-07-31 01:20:02 +0100176 """
177 raise AuthconnNotImplementedException("Should have implemented this")
178
Eduardo Sousa5c01e192019-05-08 02:35:47 +0100179 def delete_user(self, user_id):
Eduardo Sousa819d34c2018-07-31 01:20:02 +0100180 """
181 Delete user.
182
Eduardo Sousa5c01e192019-05-08 02:35:47 +0100183 :param user_id: user identifier.
Eduardo Sousa819d34c2018-07-31 01:20:02 +0100184 :raises AuthconnOperationException: if user deletion failed.
185 """
186 raise AuthconnNotImplementedException("Should have implemented this")
187
tiernocf042d32019-06-13 09:06:40 +0000188 def get_user_list(self, filter_q=None):
Eduardo Sousa5c01e192019-05-08 02:35:47 +0100189 """
190 Get user list.
191
tiernocf042d32019-06-13 09:06:40 +0000192 :param filter_q: dictionary to filter user list by name (username is also admited) and/or _id
Eduardo Sousa5c01e192019-05-08 02:35:47 +0100193 :return: returns a list of users.
194 """
195
tierno23acf402019-08-28 13:36:34 +0000196 def get_user(self, _id, fail=True):
197 """
198 Get one user
199 :param _id: id or name
200 :param fail: True to raise exception on not found. False to return None on not found
201 :return: dictionary with the user information
202 """
203 filt = {BaseTopic.id_field("users", _id): _id}
delacruzramo01b15d32019-07-02 14:37:47 +0200204 users = self.get_user_list(filt)
205 if not users:
206 if fail:
207 raise AuthconnNotFoundException("User with {} not found".format(filt), http_code=HTTPStatus.NOT_FOUND)
208 else:
209 return None
210 return users[0]
211
212 def create_role(self, role_info):
Eduardo Sousa819d34c2018-07-31 01:20:02 +0100213 """
214 Create a role.
215
delacruzramo01b15d32019-07-02 14:37:47 +0200216 :param role_info: full role info.
Eduardo Sousa819d34c2018-07-31 01:20:02 +0100217 :raises AuthconnOperationException: if role creation failed.
218 """
219 raise AuthconnNotImplementedException("Should have implemented this")
220
Eduardo Sousa5c01e192019-05-08 02:35:47 +0100221 def delete_role(self, role_id):
Eduardo Sousa819d34c2018-07-31 01:20:02 +0100222 """
223 Delete a role.
224
Eduardo Sousa5c01e192019-05-08 02:35:47 +0100225 :param role_id: role identifier.
Eduardo Sousa819d34c2018-07-31 01:20:02 +0100226 :raises AuthconnOperationException: if user deletion failed.
227 """
228 raise AuthconnNotImplementedException("Should have implemented this")
229
tierno1f029d82019-06-13 22:37:04 +0000230 def get_role_list(self, filter_q=None):
Eduardo Sousa5c01e192019-05-08 02:35:47 +0100231 """
232 Get all the roles.
233
tierno1f029d82019-06-13 22:37:04 +0000234 :param filter_q: dictionary to filter role list by _id and/or name.
Eduardo Sousa5c01e192019-05-08 02:35:47 +0100235 :return: list of roles
236 """
237 raise AuthconnNotImplementedException("Should have implemented this")
238
tierno23acf402019-08-28 13:36:34 +0000239 def get_role(self, _id, fail=True):
240 """
241 Get one role
242 :param _id: id or name
243 :param fail: True to raise exception on not found. False to return None on not found
244 :return: dictionary with the role information
245 """
246 filt = {BaseTopic.id_field("roles", _id): _id}
delacruzramo01b15d32019-07-02 14:37:47 +0200247 roles = self.get_role_list(filt)
248 if not roles:
249 if fail:
250 raise AuthconnNotFoundException("Role with {} not found".format(filt))
251 else:
252 return None
253 return roles[0]
254
255 def update_role(self, role_info):
tierno1f029d82019-06-13 22:37:04 +0000256 """
delacruzramo01b15d32019-07-02 14:37:47 +0200257 Change the information of a role
258 :param role_info: full role info
tierno1f029d82019-06-13 22:37:04 +0000259 :return: None
260 """
261 raise AuthconnNotImplementedException("Should have implemented this")
262
delacruzramo01b15d32019-07-02 14:37:47 +0200263 def create_project(self, project_info):
Eduardo Sousa819d34c2018-07-31 01:20:02 +0100264 """
265 Create a project.
266
delacruzramo01b15d32019-07-02 14:37:47 +0200267 :param project_info: full project info.
tierno4015b472019-06-10 13:57:29 +0000268 :return: the internal id of the created project
Eduardo Sousa819d34c2018-07-31 01:20:02 +0100269 :raises AuthconnOperationException: if project creation failed.
270 """
271 raise AuthconnNotImplementedException("Should have implemented this")
272
Eduardo Sousa5c01e192019-05-08 02:35:47 +0100273 def delete_project(self, project_id):
Eduardo Sousa819d34c2018-07-31 01:20:02 +0100274 """
275 Delete a project.
276
Eduardo Sousa5c01e192019-05-08 02:35:47 +0100277 :param project_id: project identifier.
Eduardo Sousa819d34c2018-07-31 01:20:02 +0100278 :raises AuthconnOperationException: if project deletion failed.
279 """
280 raise AuthconnNotImplementedException("Should have implemented this")
281
tierno38dcfeb2019-06-10 16:44:00 +0000282 def get_project_list(self, filter_q=None):
Eduardo Sousa5c01e192019-05-08 02:35:47 +0100283 """
284 Get all the projects.
285
tierno38dcfeb2019-06-10 16:44:00 +0000286 :param filter_q: dictionary to filter project list, by "name" and/or "_id"
Eduardo Sousa5c01e192019-05-08 02:35:47 +0100287 :return: list of projects
288 """
289 raise AuthconnNotImplementedException("Should have implemented this")
290
tierno23acf402019-08-28 13:36:34 +0000291 def get_project(self, _id, fail=True):
292 """
293 Get one project
294 :param _id: id or name
295 :param fail: True to raise exception on not found. False to return None on not found
296 :return: dictionary with the project information
297 """
298 filt = {BaseTopic.id_field("projects", _id): _id}
delacruzramo01b15d32019-07-02 14:37:47 +0200299 projs = self.get_project_list(filt)
300 if not projs:
301 if fail:
302 raise AuthconnNotFoundException("project with {} not found".format(filt))
303 else:
304 return None
305 return projs[0]
306
307 def update_project(self, project_id, project_info):
tierno4015b472019-06-10 13:57:29 +0000308 """
delacruzramo01b15d32019-07-02 14:37:47 +0200309 Change the information of a project
tierno4015b472019-06-10 13:57:29 +0000310 :param project_id: project to be changed
delacruzramo01b15d32019-07-02 14:37:47 +0200311 :param project_info: full project info
tierno4015b472019-06-10 13:57:29 +0000312 :return: None
313 """
314 raise AuthconnNotImplementedException("Should have implemented this")