]>
Commit | Line | Data |
---|---|---|
11fdf7f2 TL |
1 | # -*- coding: utf-8 -*- |
2 | # pylint: disable=too-many-arguments,too-many-return-statements | |
3 | # pylint: disable=too-many-branches, too-many-locals, too-many-statements | |
4 | from __future__ import absolute_import | |
5 | ||
6 | import errno | |
7 | import json | |
8 | import threading | |
9 | import time | |
10 | ||
11 | import bcrypt | |
12 | ||
13 | from mgr_module import CLIReadCommand, CLIWriteCommand | |
14 | ||
15 | from .. import mgr, logger | |
16 | from ..security import Scope, Permission | |
17 | from ..exceptions import RoleAlreadyExists, RoleDoesNotExist, ScopeNotValid, \ | |
18 | PermissionNotValid, RoleIsAssociatedWithUser, \ | |
19 | UserAlreadyExists, UserDoesNotExist, ScopeNotInRole, \ | |
20 | RoleNotInUser | |
21 | ||
22 | ||
23 | # password hashing algorithm | |
24 | def password_hash(password, salt_password=None): | |
25 | if not password: | |
26 | return None | |
27 | if not salt_password: | |
28 | salt_password = bcrypt.gensalt() | |
29 | else: | |
30 | salt_password = salt_password.encode('utf8') | |
31 | return bcrypt.hashpw(password.encode('utf8'), salt_password).decode('utf8') | |
32 | ||
33 | ||
34 | _P = Permission # short alias | |
35 | ||
36 | ||
37 | class Role(object): | |
38 | def __init__(self, name, description=None, scope_permissions=None): | |
39 | self.name = name | |
40 | self.description = description | |
41 | if scope_permissions is None: | |
42 | self.scopes_permissions = {} | |
43 | else: | |
44 | self.scopes_permissions = scope_permissions | |
45 | ||
46 | def __hash__(self): | |
47 | return hash(self.name) | |
48 | ||
49 | def __eq__(self, other): | |
50 | return self.name == other.name | |
51 | ||
52 | def set_scope_permissions(self, scope, permissions): | |
53 | if not Scope.valid_scope(scope): | |
54 | raise ScopeNotValid(scope) | |
55 | for perm in permissions: | |
56 | if not Permission.valid_permission(perm): | |
57 | raise PermissionNotValid(perm) | |
58 | ||
59 | permissions.sort() | |
60 | self.scopes_permissions[scope] = permissions | |
61 | ||
62 | def del_scope_permissions(self, scope): | |
63 | if scope not in self.scopes_permissions: | |
64 | raise ScopeNotInRole(scope, self.name) | |
65 | del self.scopes_permissions[scope] | |
66 | ||
67 | def reset_scope_permissions(self): | |
68 | self.scopes_permissions = {} | |
69 | ||
70 | def authorize(self, scope, permissions): | |
71 | if scope in self.scopes_permissions: | |
72 | role_perms = self.scopes_permissions[scope] | |
73 | for perm in permissions: | |
74 | if perm not in role_perms: | |
75 | return False | |
76 | return True | |
77 | return False | |
78 | ||
79 | def to_dict(self): | |
80 | return { | |
81 | 'name': self.name, | |
82 | 'description': self.description, | |
83 | 'scopes_permissions': self.scopes_permissions | |
84 | } | |
85 | ||
86 | @classmethod | |
87 | def from_dict(cls, r_dict): | |
88 | return Role(r_dict['name'], r_dict['description'], | |
89 | r_dict['scopes_permissions']) | |
90 | ||
91 | ||
92 | # static pre-defined system roles | |
93 | # this roles cannot be deleted nor updated | |
94 | ||
95 | # admin role provides all permissions for all scopes | |
96 | ADMIN_ROLE = Role('administrator', 'Administrator', { | |
97 | scope_name: Permission.all_permissions() | |
98 | for scope_name in Scope.all_scopes() | |
99 | }) | |
100 | ||
101 | ||
102 | # read-only role provides read-only permission for all scopes | |
103 | READ_ONLY_ROLE = Role('read-only', 'Read-Only', { | |
104 | scope_name: [_P.READ] for scope_name in Scope.all_scopes() | |
105 | if scope_name != Scope.DASHBOARD_SETTINGS | |
106 | }) | |
107 | ||
108 | ||
109 | # block manager role provides all permission for block related scopes | |
110 | BLOCK_MGR_ROLE = Role('block-manager', 'Block Manager', { | |
111 | Scope.RBD_IMAGE: [_P.READ, _P.CREATE, _P.UPDATE, _P.DELETE], | |
112 | Scope.POOL: [_P.READ], | |
113 | Scope.ISCSI: [_P.READ, _P.CREATE, _P.UPDATE, _P.DELETE], | |
114 | Scope.RBD_MIRRORING: [_P.READ, _P.CREATE, _P.UPDATE, _P.DELETE], | |
eafe8130 | 115 | Scope.GRAFANA: [_P.READ], |
11fdf7f2 TL |
116 | }) |
117 | ||
118 | ||
119 | # RadosGW manager role provides all permissions for block related scopes | |
120 | RGW_MGR_ROLE = Role('rgw-manager', 'RGW Manager', { | |
121 | Scope.RGW: [_P.READ, _P.CREATE, _P.UPDATE, _P.DELETE], | |
122 | Scope.CONFIG_OPT: [_P.READ], | |
eafe8130 | 123 | Scope.GRAFANA: [_P.READ], |
11fdf7f2 TL |
124 | }) |
125 | ||
126 | ||
127 | # Cluster manager role provides all permission for OSDs, Monitors, and | |
128 | # Config options | |
129 | CLUSTER_MGR_ROLE = Role('cluster-manager', 'Cluster Manager', { | |
130 | Scope.HOSTS: [_P.READ, _P.CREATE, _P.UPDATE, _P.DELETE], | |
131 | Scope.OSD: [_P.READ, _P.CREATE, _P.UPDATE, _P.DELETE], | |
132 | Scope.MONITOR: [_P.READ, _P.CREATE, _P.UPDATE, _P.DELETE], | |
133 | Scope.MANAGER: [_P.READ, _P.CREATE, _P.UPDATE, _P.DELETE], | |
134 | Scope.CONFIG_OPT: [_P.READ, _P.CREATE, _P.UPDATE, _P.DELETE], | |
135 | Scope.LOG: [_P.READ, _P.CREATE, _P.UPDATE, _P.DELETE], | |
eafe8130 | 136 | Scope.GRAFANA: [_P.READ], |
11fdf7f2 TL |
137 | }) |
138 | ||
139 | ||
140 | # Pool manager role provides all permissions for pool related scopes | |
141 | POOL_MGR_ROLE = Role('pool-manager', 'Pool Manager', { | |
142 | Scope.POOL: [_P.READ, _P.CREATE, _P.UPDATE, _P.DELETE], | |
143 | Scope.CONFIG_OPT: [_P.READ], | |
eafe8130 | 144 | Scope.GRAFANA: [_P.READ], |
11fdf7f2 TL |
145 | }) |
146 | ||
147 | # Pool manager role provides all permissions for CephFS related scopes | |
148 | CEPHFS_MGR_ROLE = Role('cephfs-manager', 'CephFS Manager', { | |
149 | Scope.CEPHFS: [_P.READ, _P.CREATE, _P.UPDATE, _P.DELETE], | |
150 | Scope.CONFIG_OPT: [_P.READ], | |
eafe8130 | 151 | Scope.GRAFANA: [_P.READ], |
11fdf7f2 TL |
152 | }) |
153 | ||
154 | GANESHA_MGR_ROLE = Role('ganesha-manager', 'NFS Ganesha Manager', { | |
155 | Scope.NFS_GANESHA: [_P.READ, _P.CREATE, _P.UPDATE, _P.DELETE], | |
156 | Scope.CEPHFS: [_P.READ, _P.CREATE, _P.UPDATE, _P.DELETE], | |
157 | Scope.RGW: [_P.READ, _P.CREATE, _P.UPDATE, _P.DELETE], | |
158 | Scope.CONFIG_OPT: [_P.READ], | |
eafe8130 | 159 | Scope.GRAFANA: [_P.READ], |
11fdf7f2 TL |
160 | }) |
161 | ||
162 | ||
163 | SYSTEM_ROLES = { | |
164 | ADMIN_ROLE.name: ADMIN_ROLE, | |
165 | READ_ONLY_ROLE.name: READ_ONLY_ROLE, | |
166 | BLOCK_MGR_ROLE.name: BLOCK_MGR_ROLE, | |
167 | RGW_MGR_ROLE.name: RGW_MGR_ROLE, | |
168 | CLUSTER_MGR_ROLE.name: CLUSTER_MGR_ROLE, | |
169 | POOL_MGR_ROLE.name: POOL_MGR_ROLE, | |
170 | CEPHFS_MGR_ROLE.name: CEPHFS_MGR_ROLE, | |
171 | GANESHA_MGR_ROLE.name: GANESHA_MGR_ROLE, | |
172 | } | |
173 | ||
174 | ||
175 | class User(object): | |
176 | def __init__(self, username, password, name=None, email=None, roles=None, | |
177 | lastUpdate=None): | |
178 | self.username = username | |
179 | self.password = password | |
180 | self.name = name | |
181 | self.email = email | |
182 | if roles is None: | |
183 | self.roles = set() | |
184 | else: | |
185 | self.roles = roles | |
186 | if lastUpdate is None: | |
187 | self.refreshLastUpdate() | |
188 | else: | |
189 | self.lastUpdate = lastUpdate | |
190 | ||
191 | def refreshLastUpdate(self): | |
81eedcae | 192 | self.lastUpdate = int(time.time()) |
11fdf7f2 TL |
193 | |
194 | def set_password(self, password): | |
195 | self.password = password_hash(password) | |
196 | self.refreshLastUpdate() | |
197 | ||
198 | def set_roles(self, roles): | |
199 | self.roles = set(roles) | |
200 | self.refreshLastUpdate() | |
201 | ||
202 | def add_roles(self, roles): | |
203 | self.roles = self.roles.union(set(roles)) | |
204 | self.refreshLastUpdate() | |
205 | ||
206 | def del_roles(self, roles): | |
207 | for role in roles: | |
208 | if role not in self.roles: | |
209 | raise RoleNotInUser(role.name, self.username) | |
210 | self.roles.difference_update(set(roles)) | |
211 | self.refreshLastUpdate() | |
212 | ||
213 | def authorize(self, scope, permissions): | |
214 | for role in self.roles: | |
215 | if role.authorize(scope, permissions): | |
216 | return True | |
217 | return False | |
218 | ||
219 | def permissions_dict(self): | |
220 | perms = {} | |
221 | for role in self.roles: | |
222 | for scope, perms_list in role.scopes_permissions.items(): | |
223 | if scope in perms: | |
224 | perms_tmp = set(perms[scope]).union(set(perms_list)) | |
225 | perms[scope] = list(perms_tmp) | |
226 | else: | |
227 | perms[scope] = perms_list | |
228 | ||
229 | return perms | |
230 | ||
231 | def to_dict(self): | |
232 | return { | |
233 | 'username': self.username, | |
234 | 'password': self.password, | |
235 | 'roles': sorted([r.name for r in self.roles]), | |
236 | 'name': self.name, | |
237 | 'email': self.email, | |
238 | 'lastUpdate': self.lastUpdate | |
239 | } | |
240 | ||
241 | @classmethod | |
242 | def from_dict(cls, u_dict, roles): | |
243 | return User(u_dict['username'], u_dict['password'], u_dict['name'], | |
244 | u_dict['email'], {roles[r] for r in u_dict['roles']}, | |
245 | u_dict['lastUpdate']) | |
246 | ||
247 | ||
248 | class AccessControlDB(object): | |
249 | VERSION = 1 | |
250 | ACDB_CONFIG_KEY = "accessdb_v" | |
251 | ||
252 | def __init__(self, version, users, roles): | |
253 | self.users = users | |
254 | self.version = version | |
255 | self.roles = roles | |
256 | self.lock = threading.RLock() | |
257 | ||
258 | def create_role(self, name, description=None): | |
259 | with self.lock: | |
260 | if name in SYSTEM_ROLES or name in self.roles: | |
261 | raise RoleAlreadyExists(name) | |
262 | role = Role(name, description) | |
263 | self.roles[name] = role | |
264 | return role | |
265 | ||
266 | def get_role(self, name): | |
267 | with self.lock: | |
268 | if name not in self.roles: | |
269 | raise RoleDoesNotExist(name) | |
270 | return self.roles[name] | |
271 | ||
272 | def delete_role(self, name): | |
273 | with self.lock: | |
274 | if name not in self.roles: | |
275 | raise RoleDoesNotExist(name) | |
276 | role = self.roles[name] | |
277 | ||
278 | # check if role is not associated with a user | |
279 | for username, user in self.users.items(): | |
280 | if role in user.roles: | |
281 | raise RoleIsAssociatedWithUser(name, username) | |
282 | ||
283 | del self.roles[name] | |
284 | ||
285 | def create_user(self, username, password, name, email): | |
286 | logger.debug("AC: creating user: username=%s", username) | |
287 | with self.lock: | |
288 | if username in self.users: | |
289 | raise UserAlreadyExists(username) | |
290 | user = User(username, password_hash(password), name, email) | |
291 | self.users[username] = user | |
292 | return user | |
293 | ||
294 | def get_user(self, username): | |
295 | with self.lock: | |
296 | if username not in self.users: | |
297 | raise UserDoesNotExist(username) | |
298 | return self.users[username] | |
299 | ||
300 | def delete_user(self, username): | |
301 | with self.lock: | |
302 | if username not in self.users: | |
303 | raise UserDoesNotExist(username) | |
304 | del self.users[username] | |
305 | ||
306 | def update_users_with_roles(self, role): | |
307 | with self.lock: | |
308 | if not role: | |
309 | return | |
310 | for _, user in self.users.items(): | |
311 | if role in user.roles: | |
312 | user.refreshLastUpdate() | |
313 | ||
314 | def save(self): | |
315 | with self.lock: | |
316 | db = { | |
317 | 'users': {un: u.to_dict() for un, u in self.users.items()}, | |
318 | 'roles': {rn: r.to_dict() for rn, r in self.roles.items()}, | |
319 | 'version': self.version | |
320 | } | |
321 | mgr.set_store(self.accessdb_config_key(), json.dumps(db)) | |
322 | ||
323 | @classmethod | |
324 | def accessdb_config_key(cls, version=None): | |
325 | if version is None: | |
326 | version = cls.VERSION | |
327 | return "{}{}".format(cls.ACDB_CONFIG_KEY, version) | |
328 | ||
329 | def check_and_update_db(self): | |
330 | logger.debug("AC: Checking for previews DB versions") | |
331 | if self.VERSION == 1: # current version | |
332 | # check if there is username/password from previous version | |
333 | username = mgr.get_module_option('username', None) | |
334 | password = mgr.get_module_option('password', None) | |
335 | if username and password: | |
336 | logger.debug("AC: Found single user credentials: user=%s", | |
337 | username) | |
338 | # found user credentials | |
339 | user = self.create_user(username, "", None, None) | |
340 | # password is already hashed, so setting manually | |
341 | user.password = password | |
342 | user.add_roles([ADMIN_ROLE]) | |
343 | self.save() | |
344 | else: | |
345 | raise NotImplementedError() | |
346 | ||
347 | @classmethod | |
348 | def load(cls): | |
349 | logger.info("AC: Loading user roles DB version=%s", cls.VERSION) | |
350 | ||
351 | json_db = mgr.get_store(cls.accessdb_config_key()) | |
352 | if json_db is None: | |
353 | logger.debug("AC: No DB v%s found, creating new...", cls.VERSION) | |
354 | db = cls(cls.VERSION, {}, {}) | |
355 | # check if we can update from a previous version database | |
356 | db.check_and_update_db() | |
357 | return db | |
358 | ||
359 | db = json.loads(json_db) | |
360 | roles = {rn: Role.from_dict(r) | |
361 | for rn, r in db.get('roles', {}).items()} | |
362 | users = {un: User.from_dict(u, dict(roles, **SYSTEM_ROLES)) | |
363 | for un, u in db.get('users', {}).items()} | |
364 | return cls(db['version'], users, roles) | |
365 | ||
366 | ||
367 | def load_access_control_db(): | |
368 | mgr.ACCESS_CTRL_DB = AccessControlDB.load() | |
369 | ||
370 | ||
371 | # CLI dashboard access control scope commands | |
372 | ||
373 | @CLIWriteCommand('dashboard set-login-credentials', | |
374 | 'name=username,type=CephString ' | |
375 | 'name=password,type=CephString', | |
376 | 'Set the login credentials') | |
377 | def set_login_credentials_cmd(_, username, password): | |
378 | try: | |
379 | user = mgr.ACCESS_CTRL_DB.get_user(username) | |
380 | user.set_password(password) | |
381 | except UserDoesNotExist: | |
382 | user = mgr.ACCESS_CTRL_DB.create_user(username, password, None, None) | |
383 | user.set_roles([ADMIN_ROLE]) | |
384 | ||
385 | mgr.ACCESS_CTRL_DB.save() | |
386 | ||
387 | return 0, '''\ | |
388 | ****************************************************************** | |
389 | *** WARNING: this command is deprecated. *** | |
390 | *** Please use the ac-user-* related commands to manage users. *** | |
391 | ****************************************************************** | |
392 | Username and password updated''', '' | |
393 | ||
394 | ||
395 | @CLIReadCommand('dashboard ac-role-show', | |
396 | 'name=rolename,type=CephString,req=false', | |
397 | 'Show role info') | |
398 | def ac_role_show_cmd(_, rolename=None): | |
399 | if not rolename: | |
400 | roles = dict(mgr.ACCESS_CTRL_DB.roles) | |
401 | roles.update(SYSTEM_ROLES) | |
402 | roles_list = [name for name, _ in roles.items()] | |
403 | return 0, json.dumps(roles_list), '' | |
404 | try: | |
405 | role = mgr.ACCESS_CTRL_DB.get_role(rolename) | |
406 | except RoleDoesNotExist as ex: | |
407 | if rolename not in SYSTEM_ROLES: | |
408 | return -errno.ENOENT, '', str(ex) | |
409 | role = SYSTEM_ROLES[rolename] | |
410 | return 0, json.dumps(role.to_dict()), '' | |
411 | ||
412 | ||
413 | @CLIWriteCommand('dashboard ac-role-create', | |
414 | 'name=rolename,type=CephString ' | |
415 | 'name=description,type=CephString,req=false', | |
416 | 'Create a new access control role') | |
417 | def ac_role_create_cmd(_, rolename, description=None): | |
418 | try: | |
419 | role = mgr.ACCESS_CTRL_DB.create_role(rolename, description) | |
420 | mgr.ACCESS_CTRL_DB.save() | |
421 | return 0, json.dumps(role.to_dict()), '' | |
422 | except RoleAlreadyExists as ex: | |
423 | return -errno.EEXIST, '', str(ex) | |
424 | ||
425 | ||
426 | @CLIWriteCommand('dashboard ac-role-delete', | |
427 | 'name=rolename,type=CephString', | |
428 | 'Delete an access control role') | |
429 | def ac_role_delete_cmd(_, rolename): | |
430 | try: | |
431 | mgr.ACCESS_CTRL_DB.delete_role(rolename) | |
432 | mgr.ACCESS_CTRL_DB.save() | |
433 | return 0, "Role '{}' deleted".format(rolename), "" | |
434 | except RoleDoesNotExist as ex: | |
435 | if rolename in SYSTEM_ROLES: | |
436 | return -errno.EPERM, '', "Cannot delete system role '{}'" \ | |
437 | .format(rolename) | |
438 | return -errno.ENOENT, '', str(ex) | |
439 | except RoleIsAssociatedWithUser as ex: | |
440 | return -errno.EPERM, '', str(ex) | |
441 | ||
442 | ||
443 | @CLIWriteCommand('dashboard ac-role-add-scope-perms', | |
444 | 'name=rolename,type=CephString ' | |
445 | 'name=scopename,type=CephString ' | |
446 | 'name=permissions,type=CephString,n=N', | |
447 | 'Add the scope permissions for a role') | |
448 | def ac_role_add_scope_perms_cmd(_, rolename, scopename, permissions): | |
449 | try: | |
450 | role = mgr.ACCESS_CTRL_DB.get_role(rolename) | |
451 | perms_array = [perm.strip() for perm in permissions] | |
452 | role.set_scope_permissions(scopename, perms_array) | |
453 | mgr.ACCESS_CTRL_DB.update_users_with_roles(role) | |
454 | mgr.ACCESS_CTRL_DB.save() | |
455 | return 0, json.dumps(role.to_dict()), '' | |
456 | except RoleDoesNotExist as ex: | |
457 | if rolename in SYSTEM_ROLES: | |
458 | return -errno.EPERM, '', "Cannot update system role '{}'" \ | |
459 | .format(rolename) | |
460 | return -errno.ENOENT, '', str(ex) | |
461 | except ScopeNotValid as ex: | |
462 | return -errno.EINVAL, '', str(ex) + "\n Possible values: {}" \ | |
463 | .format(Scope.all_scopes()) | |
464 | except PermissionNotValid as ex: | |
465 | return -errno.EINVAL, '', str(ex) + \ | |
466 | "\n Possible values: {}" \ | |
467 | .format(Permission.all_permissions()) | |
468 | ||
469 | ||
470 | @CLIWriteCommand('dashboard ac-role-del-scope-perms', | |
471 | 'name=rolename,type=CephString ' | |
472 | 'name=scopename,type=CephString', | |
473 | 'Delete the scope permissions for a role') | |
474 | def ac_role_del_scope_perms_cmd(_, rolename, scopename): | |
475 | try: | |
476 | role = mgr.ACCESS_CTRL_DB.get_role(rolename) | |
477 | role.del_scope_permissions(scopename) | |
478 | mgr.ACCESS_CTRL_DB.update_users_with_roles(role) | |
479 | mgr.ACCESS_CTRL_DB.save() | |
480 | return 0, json.dumps(role.to_dict()), '' | |
481 | except RoleDoesNotExist as ex: | |
482 | if rolename in SYSTEM_ROLES: | |
483 | return -errno.EPERM, '', "Cannot update system role '{}'" \ | |
484 | .format(rolename) | |
485 | return -errno.ENOENT, '', str(ex) | |
486 | except ScopeNotInRole as ex: | |
487 | return -errno.ENOENT, '', str(ex) | |
488 | ||
489 | ||
490 | @CLIReadCommand('dashboard ac-user-show', | |
491 | 'name=username,type=CephString,req=false', | |
492 | 'Show user info') | |
493 | def ac_user_show_cmd(_, username=None): | |
494 | if not username: | |
495 | users = mgr.ACCESS_CTRL_DB.users | |
496 | users_list = [name for name, _ in users.items()] | |
497 | return 0, json.dumps(users_list), '' | |
498 | try: | |
499 | user = mgr.ACCESS_CTRL_DB.get_user(username) | |
500 | return 0, json.dumps(user.to_dict()), '' | |
501 | except UserDoesNotExist as ex: | |
502 | return -errno.ENOENT, '', str(ex) | |
503 | ||
504 | ||
505 | @CLIWriteCommand('dashboard ac-user-create', | |
506 | 'name=username,type=CephString ' | |
507 | 'name=password,type=CephString,req=false ' | |
508 | 'name=rolename,type=CephString,req=false ' | |
509 | 'name=name,type=CephString,req=false ' | |
510 | 'name=email,type=CephString,req=false', | |
511 | 'Create a user') | |
512 | def ac_user_create_cmd(_, username, password=None, rolename=None, name=None, | |
513 | email=None): | |
514 | try: | |
515 | role = mgr.ACCESS_CTRL_DB.get_role(rolename) if rolename else None | |
516 | except RoleDoesNotExist as ex: | |
517 | if rolename not in SYSTEM_ROLES: | |
518 | return -errno.ENOENT, '', str(ex) | |
519 | role = SYSTEM_ROLES[rolename] | |
520 | ||
521 | try: | |
522 | user = mgr.ACCESS_CTRL_DB.create_user(username, password, name, email) | |
523 | except UserAlreadyExists as ex: | |
524 | return -errno.EEXIST, '', str(ex) | |
525 | ||
526 | if role: | |
527 | user.set_roles([role]) | |
528 | mgr.ACCESS_CTRL_DB.save() | |
529 | return 0, json.dumps(user.to_dict()), '' | |
530 | ||
531 | ||
532 | @CLIWriteCommand('dashboard ac-user-delete', | |
533 | 'name=username,type=CephString', | |
534 | 'Delete user') | |
535 | def ac_user_delete_cmd(_, username): | |
536 | try: | |
537 | mgr.ACCESS_CTRL_DB.delete_user(username) | |
538 | mgr.ACCESS_CTRL_DB.save() | |
539 | return 0, "User '{}' deleted".format(username), "" | |
540 | except UserDoesNotExist as ex: | |
541 | return -errno.ENOENT, '', str(ex) | |
542 | ||
543 | ||
544 | @CLIWriteCommand('dashboard ac-user-set-roles', | |
545 | 'name=username,type=CephString ' | |
546 | 'name=roles,type=CephString,n=N', | |
547 | 'Set user roles') | |
548 | def ac_user_set_roles_cmd(_, username, roles): | |
549 | rolesname = roles | |
550 | roles = [] | |
551 | for rolename in rolesname: | |
552 | try: | |
553 | roles.append(mgr.ACCESS_CTRL_DB.get_role(rolename)) | |
554 | except RoleDoesNotExist as ex: | |
555 | if rolename not in SYSTEM_ROLES: | |
556 | return -errno.ENOENT, '', str(ex) | |
557 | roles.append(SYSTEM_ROLES[rolename]) | |
558 | try: | |
559 | user = mgr.ACCESS_CTRL_DB.get_user(username) | |
560 | user.set_roles(roles) | |
561 | mgr.ACCESS_CTRL_DB.save() | |
562 | return 0, json.dumps(user.to_dict()), '' | |
563 | except UserDoesNotExist as ex: | |
564 | return -errno.ENOENT, '', str(ex) | |
565 | ||
566 | ||
567 | @CLIWriteCommand('dashboard ac-user-add-roles', | |
568 | 'name=username,type=CephString ' | |
569 | 'name=roles,type=CephString,n=N', | |
570 | 'Add roles to user') | |
571 | def ac_user_add_roles_cmd(_, username, roles): | |
572 | rolesname = roles | |
573 | roles = [] | |
574 | for rolename in rolesname: | |
575 | try: | |
576 | roles.append(mgr.ACCESS_CTRL_DB.get_role(rolename)) | |
577 | except RoleDoesNotExist as ex: | |
578 | if rolename not in SYSTEM_ROLES: | |
579 | return -errno.ENOENT, '', str(ex) | |
580 | roles.append(SYSTEM_ROLES[rolename]) | |
581 | try: | |
582 | user = mgr.ACCESS_CTRL_DB.get_user(username) | |
583 | user.add_roles(roles) | |
584 | mgr.ACCESS_CTRL_DB.save() | |
585 | return 0, json.dumps(user.to_dict()), '' | |
586 | except UserDoesNotExist as ex: | |
587 | return -errno.ENOENT, '', str(ex) | |
588 | ||
589 | ||
590 | @CLIWriteCommand('dashboard ac-user-del-roles', | |
591 | 'name=username,type=CephString ' | |
592 | 'name=roles,type=CephString,n=N', | |
593 | 'Delete roles from user') | |
594 | def ac_user_del_roles_cmd(_, username, roles): | |
595 | rolesname = roles | |
596 | roles = [] | |
597 | for rolename in rolesname: | |
598 | try: | |
599 | roles.append(mgr.ACCESS_CTRL_DB.get_role(rolename)) | |
600 | except RoleDoesNotExist as ex: | |
601 | if rolename not in SYSTEM_ROLES: | |
602 | return -errno.ENOENT, '', str(ex) | |
603 | roles.append(SYSTEM_ROLES[rolename]) | |
604 | try: | |
605 | user = mgr.ACCESS_CTRL_DB.get_user(username) | |
606 | user.del_roles(roles) | |
607 | mgr.ACCESS_CTRL_DB.save() | |
608 | return 0, json.dumps(user.to_dict()), '' | |
609 | except UserDoesNotExist as ex: | |
610 | return -errno.ENOENT, '', str(ex) | |
611 | except RoleNotInUser as ex: | |
612 | return -errno.ENOENT, '', str(ex) | |
613 | ||
614 | ||
615 | @CLIWriteCommand('dashboard ac-user-set-password', | |
616 | 'name=username,type=CephString ' | |
617 | 'name=password,type=CephString', | |
618 | 'Set user password') | |
619 | def ac_user_set_password(_, username, password): | |
620 | try: | |
621 | user = mgr.ACCESS_CTRL_DB.get_user(username) | |
622 | user.set_password(password) | |
623 | ||
624 | mgr.ACCESS_CTRL_DB.save() | |
625 | return 0, json.dumps(user.to_dict()), '' | |
626 | except UserDoesNotExist as ex: | |
627 | return -errno.ENOENT, '', str(ex) | |
628 | ||
629 | ||
630 | @CLIWriteCommand('dashboard ac-user-set-info', | |
631 | 'name=username,type=CephString ' | |
632 | 'name=name,type=CephString ' | |
633 | 'name=email,type=CephString', | |
634 | 'Set user info') | |
635 | def ac_user_set_info(_, username, name, email): | |
636 | try: | |
637 | user = mgr.ACCESS_CTRL_DB.get_user(username) | |
638 | if name: | |
639 | user.name = name | |
640 | if email: | |
641 | user.email = email | |
642 | mgr.ACCESS_CTRL_DB.save() | |
643 | return 0, json.dumps(user.to_dict()), '' | |
644 | except UserDoesNotExist as ex: | |
645 | return -errno.ENOENT, '', str(ex) | |
646 | ||
647 | ||
648 | class LocalAuthenticator(object): | |
649 | def __init__(self): | |
650 | load_access_control_db() | |
651 | ||
652 | def get_user(self, username): | |
653 | return mgr.ACCESS_CTRL_DB.get_user(username) | |
654 | ||
655 | def authenticate(self, username, password): | |
656 | try: | |
657 | user = mgr.ACCESS_CTRL_DB.get_user(username) | |
658 | if user.password: | |
659 | pass_hash = password_hash(password, user.password) | |
660 | if pass_hash == user.password: | |
661 | return user.permissions_dict() | |
662 | except UserDoesNotExist: | |
663 | logger.debug("User '%s' does not exist", username) | |
664 | return None | |
665 | ||
666 | def authorize(self, username, scope, permissions): | |
667 | user = mgr.ACCESS_CTRL_DB.get_user(username) | |
668 | return user.authorize(scope, permissions) |