blob: 17275900b1fc0e4b8a0797ff34c98adc742889ed [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
26__author__ = "Eduardo Sousa <esousa@whitestack.com>"
27__date__ = "$27-jul-2018 23:59:59$"
28
29from http import HTTPStatus
delacruzramo01b15d32019-07-02 14:37:47 +020030from base_topic import BaseTopic
Eduardo Sousa819d34c2018-07-31 01:20:02 +010031
32
33class AuthException(Exception):
34 """
tiernoc8445362019-06-14 12:07:15 +000035 Authentication error, because token, user password not recognized
Eduardo Sousa819d34c2018-07-31 01:20:02 +010036 """
37 def __init__(self, message, http_code=HTTPStatus.UNAUTHORIZED):
Eduardo Sousa5c01e192019-05-08 02:35:47 +010038 super(AuthException, self).__init__(message)
Eduardo Sousa819d34c2018-07-31 01:20:02 +010039 self.http_code = http_code
Eduardo Sousa819d34c2018-07-31 01:20:02 +010040
41
tiernoc8445362019-06-14 12:07:15 +000042class AuthExceptionUnauthorized(AuthException):
43 """
44 Authentication error, because not having rights to make this operation
45 """
46 pass
47
48
Eduardo Sousa819d34c2018-07-31 01:20:02 +010049class AuthconnException(Exception):
50 """
51 Common and base class Exception for all authconn exceptions.
52 """
53 def __init__(self, message, http_code=HTTPStatus.UNAUTHORIZED):
Eduardo Sousa5c01e192019-05-08 02:35:47 +010054 super(AuthconnException, self).__init__(message)
Eduardo Sousa819d34c2018-07-31 01:20:02 +010055 self.http_code = http_code
56
57
58class AuthconnConnectionException(AuthconnException):
59 """
60 Connectivity error with Auth backend.
61 """
62 def __init__(self, message, http_code=HTTPStatus.BAD_GATEWAY):
Eduardo Sousa5c01e192019-05-08 02:35:47 +010063 super(AuthconnConnectionException, self).__init__(message, http_code)
Eduardo Sousa819d34c2018-07-31 01:20:02 +010064
65
66class AuthconnNotSupportedException(AuthconnException):
67 """
68 The request is not supported by the Auth backend.
69 """
70 def __init__(self, message, http_code=HTTPStatus.NOT_IMPLEMENTED):
Eduardo Sousa5c01e192019-05-08 02:35:47 +010071 super(AuthconnNotSupportedException, self).__init__(message, http_code)
Eduardo Sousa819d34c2018-07-31 01:20:02 +010072
73
74class AuthconnNotImplementedException(AuthconnException):
75 """
76 The method is not implemented by the Auth backend.
77 """
78 def __init__(self, message, http_code=HTTPStatus.NOT_IMPLEMENTED):
Eduardo Sousa5c01e192019-05-08 02:35:47 +010079 super(AuthconnNotImplementedException, self).__init__(message, http_code)
Eduardo Sousa819d34c2018-07-31 01:20:02 +010080
81
82class AuthconnOperationException(AuthconnException):
83 """
84 The operation executed failed.
85 """
86 def __init__(self, message, http_code=HTTPStatus.INTERNAL_SERVER_ERROR):
Eduardo Sousa5c01e192019-05-08 02:35:47 +010087 super(AuthconnOperationException, self).__init__(message, http_code)
Eduardo Sousa819d34c2018-07-31 01:20:02 +010088
89
tiernocf042d32019-06-13 09:06:40 +000090class AuthconnNotFoundException(AuthconnException):
91 """
92 The operation executed failed because element not found.
93 """
94 def __init__(self, message, http_code=HTTPStatus.NOT_FOUND):
95 super().__init__(message, http_code)
96
97
tierno1f029d82019-06-13 22:37:04 +000098class AuthconnConflictException(AuthconnException):
99 """
100 The operation has conflicts.
101 """
102 def __init__(self, message, http_code=HTTPStatus.CONFLICT):
103 super().__init__(message, http_code)
104
105
Eduardo Sousa819d34c2018-07-31 01:20:02 +0100106class Authconn:
107 """
108 Abstract base class for all the Auth backend connector plugins.
109 Each Auth backend connector plugin must be a subclass of
110 Authconn class.
111 """
delacruzramo01b15d32019-07-02 14:37:47 +0200112 def __init__(self, config, db, token_cache):
Eduardo Sousa819d34c2018-07-31 01:20:02 +0100113 """
114 Constructor of the Authconn class.
115
116 Note: each subclass
117
118 :param config: configuration dictionary containing all the
119 necessary configuration parameters.
120 """
121 self.config = config
122
tierno701018c2019-06-25 11:13:14 +0000123 def authenticate(self, user, password, project=None, token_info=None):
Eduardo Sousa819d34c2018-07-31 01:20:02 +0100124 """
tierno701018c2019-06-25 11:13:14 +0000125 Authenticate a user using username/password or token_info, plus project
tierno38dcfeb2019-06-10 16:44:00 +0000126 :param user: user: name, id or None
127 :param password: password or None
128 :param project: name, id, or None. If None first found project will be used to get an scope token
tierno701018c2019-06-25 11:13:14 +0000129 :param token_info: previous token_info to obtain authorization
tierno38dcfeb2019-06-10 16:44:00 +0000130 :return: the scoped token info or raises an exception. The token is a dictionary with:
131 _id: token string id,
132 username: username,
133 project_id: scoped_token project_id,
134 project_name: scoped_token project_name,
135 expires: epoch time when it expires,
Eduardo Sousa819d34c2018-07-31 01:20:02 +0100136
Eduardo Sousa819d34c2018-07-31 01:20:02 +0100137 """
138 raise AuthconnNotImplementedException("Should have implemented this")
139
Eduardo Sousa819d34c2018-07-31 01:20:02 +0100140 def validate_token(self, token):
141 """
142 Check if the token is valid.
143
144 :param token: token to validate
145 :return: dictionary with information associated with the token. If the
146 token is not valid, returns None.
147 """
148 raise AuthconnNotImplementedException("Should have implemented this")
149
150 def revoke_token(self, token):
151 """
152 Invalidate a token.
153
154 :param token: token to be revoked
155 """
156 raise AuthconnNotImplementedException("Should have implemented this")
157
delacruzramo01b15d32019-07-02 14:37:47 +0200158 def create_user(self, user_info):
Eduardo Sousa819d34c2018-07-31 01:20:02 +0100159 """
160 Create a user.
161
delacruzramo01b15d32019-07-02 14:37:47 +0200162 :param user_info: full user info.
Eduardo Sousa819d34c2018-07-31 01:20:02 +0100163 :raises AuthconnOperationException: if user creation failed.
164 """
165 raise AuthconnNotImplementedException("Should have implemented this")
166
delacruzramo01b15d32019-07-02 14:37:47 +0200167 def update_user(self, user_info):
Eduardo Sousa819d34c2018-07-31 01:20:02 +0100168 """
tiernocf042d32019-06-13 09:06:40 +0000169 Change the user name and/or password.
Eduardo Sousa819d34c2018-07-31 01:20:02 +0100170
delacruzramo01b15d32019-07-02 14:37:47 +0200171 :param user_info: user info modifications
172 :raises AuthconnNotImplementedException: if function not implemented
Eduardo Sousa819d34c2018-07-31 01:20:02 +0100173 """
174 raise AuthconnNotImplementedException("Should have implemented this")
175
Eduardo Sousa5c01e192019-05-08 02:35:47 +0100176 def delete_user(self, user_id):
Eduardo Sousa819d34c2018-07-31 01:20:02 +0100177 """
178 Delete user.
179
Eduardo Sousa5c01e192019-05-08 02:35:47 +0100180 :param user_id: user identifier.
Eduardo Sousa819d34c2018-07-31 01:20:02 +0100181 :raises AuthconnOperationException: if user deletion failed.
182 """
183 raise AuthconnNotImplementedException("Should have implemented this")
184
tiernocf042d32019-06-13 09:06:40 +0000185 def get_user_list(self, filter_q=None):
Eduardo Sousa5c01e192019-05-08 02:35:47 +0100186 """
187 Get user list.
188
tiernocf042d32019-06-13 09:06:40 +0000189 :param filter_q: dictionary to filter user list by name (username is also admited) and/or _id
Eduardo Sousa5c01e192019-05-08 02:35:47 +0100190 :return: returns a list of users.
191 """
192
delacruzramo01b15d32019-07-02 14:37:47 +0200193 def get_user(self, id, fail=True):
194 filt = {BaseTopic.id_field("users", id): id}
195 users = self.get_user_list(filt)
196 if not users:
197 if fail:
198 raise AuthconnNotFoundException("User with {} not found".format(filt), http_code=HTTPStatus.NOT_FOUND)
199 else:
200 return None
201 return users[0]
202
203 def create_role(self, role_info):
Eduardo Sousa819d34c2018-07-31 01:20:02 +0100204 """
205 Create a role.
206
delacruzramo01b15d32019-07-02 14:37:47 +0200207 :param role_info: full role info.
Eduardo Sousa819d34c2018-07-31 01:20:02 +0100208 :raises AuthconnOperationException: if role creation failed.
209 """
210 raise AuthconnNotImplementedException("Should have implemented this")
211
Eduardo Sousa5c01e192019-05-08 02:35:47 +0100212 def delete_role(self, role_id):
Eduardo Sousa819d34c2018-07-31 01:20:02 +0100213 """
214 Delete a role.
215
Eduardo Sousa5c01e192019-05-08 02:35:47 +0100216 :param role_id: role identifier.
Eduardo Sousa819d34c2018-07-31 01:20:02 +0100217 :raises AuthconnOperationException: if user deletion failed.
218 """
219 raise AuthconnNotImplementedException("Should have implemented this")
220
tierno1f029d82019-06-13 22:37:04 +0000221 def get_role_list(self, filter_q=None):
Eduardo Sousa5c01e192019-05-08 02:35:47 +0100222 """
223 Get all the roles.
224
tierno1f029d82019-06-13 22:37:04 +0000225 :param filter_q: dictionary to filter role list by _id and/or name.
Eduardo Sousa5c01e192019-05-08 02:35:47 +0100226 :return: list of roles
227 """
228 raise AuthconnNotImplementedException("Should have implemented this")
229
delacruzramo01b15d32019-07-02 14:37:47 +0200230 def get_role(self, id, fail=True):
231 filt = {BaseTopic.id_field("roles", id): id}
232 roles = self.get_role_list(filt)
233 if not roles:
234 if fail:
235 raise AuthconnNotFoundException("Role with {} not found".format(filt))
236 else:
237 return None
238 return roles[0]
239
240 def update_role(self, role_info):
tierno1f029d82019-06-13 22:37:04 +0000241 """
delacruzramo01b15d32019-07-02 14:37:47 +0200242 Change the information of a role
243 :param role_info: full role info
tierno1f029d82019-06-13 22:37:04 +0000244 :return: None
245 """
246 raise AuthconnNotImplementedException("Should have implemented this")
247
delacruzramo01b15d32019-07-02 14:37:47 +0200248 def create_project(self, project_info):
Eduardo Sousa819d34c2018-07-31 01:20:02 +0100249 """
250 Create a project.
251
delacruzramo01b15d32019-07-02 14:37:47 +0200252 :param project_info: full project info.
tierno4015b472019-06-10 13:57:29 +0000253 :return: the internal id of the created project
Eduardo Sousa819d34c2018-07-31 01:20:02 +0100254 :raises AuthconnOperationException: if project creation failed.
255 """
256 raise AuthconnNotImplementedException("Should have implemented this")
257
Eduardo Sousa5c01e192019-05-08 02:35:47 +0100258 def delete_project(self, project_id):
Eduardo Sousa819d34c2018-07-31 01:20:02 +0100259 """
260 Delete a project.
261
Eduardo Sousa5c01e192019-05-08 02:35:47 +0100262 :param project_id: project identifier.
Eduardo Sousa819d34c2018-07-31 01:20:02 +0100263 :raises AuthconnOperationException: if project deletion failed.
264 """
265 raise AuthconnNotImplementedException("Should have implemented this")
266
tierno38dcfeb2019-06-10 16:44:00 +0000267 def get_project_list(self, filter_q=None):
Eduardo Sousa5c01e192019-05-08 02:35:47 +0100268 """
269 Get all the projects.
270
tierno38dcfeb2019-06-10 16:44:00 +0000271 :param filter_q: dictionary to filter project list, by "name" and/or "_id"
Eduardo Sousa5c01e192019-05-08 02:35:47 +0100272 :return: list of projects
273 """
274 raise AuthconnNotImplementedException("Should have implemented this")
275
delacruzramo01b15d32019-07-02 14:37:47 +0200276 def get_project(self, id, fail=True):
277 filt = {BaseTopic.id_field("projects", id): id}
278 projs = self.get_project_list(filt)
279 if not projs:
280 if fail:
281 raise AuthconnNotFoundException("project with {} not found".format(filt))
282 else:
283 return None
284 return projs[0]
285
286 def update_project(self, project_id, project_info):
tierno4015b472019-06-10 13:57:29 +0000287 """
delacruzramo01b15d32019-07-02 14:37:47 +0200288 Change the information of a project
tierno4015b472019-06-10 13:57:29 +0000289 :param project_id: project to be changed
delacruzramo01b15d32019-07-02 14:37:47 +0200290 :param project_info: full project info
tierno4015b472019-06-10 13:57:29 +0000291 :return: None
292 """
293 raise AuthconnNotImplementedException("Should have implemented this")