]> git.proxmox.com Git - ceph.git/blob - ceph/src/pybind/mgr/dashboard/controllers/user.py
Import ceph 15.2.8
[ceph.git] / ceph / src / pybind / mgr / dashboard / controllers / user.py
1 # -*- coding: utf-8 -*-
2 from __future__ import absolute_import
3
4 from datetime import datetime
5
6 import time
7
8 import cherrypy
9
10 from . import BaseController, ApiController, RESTController, Endpoint, allow_empty_body
11 from .. import mgr
12 from ..exceptions import DashboardException, UserAlreadyExists, \
13 UserDoesNotExist, PasswordPolicyException, PwdExpirationDateNotValid
14 from ..security import Scope
15 from ..services.access_control import SYSTEM_ROLES, PasswordPolicy
16 from ..services.auth import JwtManager
17
18
19 def validate_password_policy(password, username=None, old_password=None):
20 """
21 :param password: The password to validate.
22 :param username: The name of the user (optional).
23 :param old_password: The old password (optional).
24 :return: Returns the password complexity credits.
25 :rtype: int
26 :raises DashboardException: If a password policy fails.
27 """
28 pw_policy = PasswordPolicy(password, username, old_password)
29 try:
30 pw_policy.check_all()
31 return pw_policy.complexity_credits
32 except PasswordPolicyException as ex:
33 raise DashboardException(msg=str(ex),
34 code='password_policy_validation_failed',
35 component='user')
36
37
38 @ApiController('/user', Scope.USER)
39 class User(RESTController):
40
41 @staticmethod
42 def _user_to_dict(user):
43 result = user.to_dict()
44 del result['password']
45 return result
46
47 @staticmethod
48 def _get_user_roles(roles):
49 all_roles = dict(mgr.ACCESS_CTRL_DB.roles)
50 all_roles.update(SYSTEM_ROLES)
51 try:
52 return [all_roles[rolename] for rolename in roles]
53 except KeyError:
54 raise DashboardException(msg='Role does not exist',
55 code='role_does_not_exist',
56 component='user')
57
58 def list(self):
59 users = mgr.ACCESS_CTRL_DB.users
60 result = [User._user_to_dict(u) for _, u in users.items()]
61 return result
62
63 def get(self, username):
64 try:
65 user = mgr.ACCESS_CTRL_DB.get_user(username)
66 except UserDoesNotExist:
67 raise cherrypy.HTTPError(404)
68 return User._user_to_dict(user)
69
70 def create(self, username=None, password=None, name=None, email=None,
71 roles=None, enabled=True, pwdExpirationDate=None, pwdUpdateRequired=True):
72 if not username:
73 raise DashboardException(msg='Username is required',
74 code='username_required',
75 component='user')
76 user_roles = None
77 if roles:
78 user_roles = User._get_user_roles(roles)
79 if password:
80 validate_password_policy(password, username)
81 try:
82 user = mgr.ACCESS_CTRL_DB.create_user(username, password, name,
83 email, enabled, pwdExpirationDate,
84 pwdUpdateRequired)
85 except UserAlreadyExists:
86 raise DashboardException(msg='Username already exists',
87 code='username_already_exists',
88 component='user')
89 except PwdExpirationDateNotValid:
90 raise DashboardException(msg='Password expiration date must not be in '
91 'the past',
92 code='pwd_past_expiration_date',
93 component='user')
94
95 if user_roles:
96 user.set_roles(user_roles)
97 mgr.ACCESS_CTRL_DB.save()
98 return User._user_to_dict(user)
99
100 def delete(self, username):
101 session_username = JwtManager.get_username()
102 if session_username == username:
103 raise DashboardException(msg='Cannot delete current user',
104 code='cannot_delete_current_user',
105 component='user')
106 try:
107 mgr.ACCESS_CTRL_DB.delete_user(username)
108 except UserDoesNotExist:
109 raise cherrypy.HTTPError(404)
110 mgr.ACCESS_CTRL_DB.save()
111
112 def set(self, username, password=None, name=None, email=None, roles=None,
113 enabled=None, pwdExpirationDate=None, pwdUpdateRequired=False):
114 if JwtManager.get_username() == username and enabled is False:
115 raise DashboardException(msg='You are not allowed to disable your user',
116 code='cannot_disable_current_user',
117 component='user')
118
119 try:
120 user = mgr.ACCESS_CTRL_DB.get_user(username)
121 except UserDoesNotExist:
122 raise cherrypy.HTTPError(404)
123 user_roles = []
124 if roles:
125 user_roles = User._get_user_roles(roles)
126 if password:
127 validate_password_policy(password, username)
128 user.set_password(password)
129 if pwdExpirationDate and \
130 (pwdExpirationDate < int(time.mktime(datetime.utcnow().timetuple()))):
131 raise DashboardException(
132 msg='Password expiration date must not be in the past',
133 code='pwd_past_expiration_date', component='user')
134 user.name = name
135 user.email = email
136 if enabled is not None:
137 user.enabled = enabled
138 user.pwd_expiration_date = pwdExpirationDate
139 user.set_roles(user_roles)
140 user.pwd_update_required = pwdUpdateRequired
141 mgr.ACCESS_CTRL_DB.save()
142 return User._user_to_dict(user)
143
144
145 @ApiController('/user')
146 class UserPasswordPolicy(RESTController):
147
148 @Endpoint('POST')
149 @allow_empty_body
150 def validate_password(self, password, username=None, old_password=None):
151 """
152 Check if the password meets the password policy.
153 :param password: The password to validate.
154 :param username: The name of the user (optional).
155 :param old_password: The old password (optional).
156 :return: An object with the properties valid, credits and valuation.
157 'credits' contains the password complexity credits and
158 'valuation' the textual summary of the validation.
159 """
160 result = {'valid': False, 'credits': 0, 'valuation': None}
161 try:
162 result['credits'] = validate_password_policy(password, username, old_password)
163 if result['credits'] < 15:
164 result['valuation'] = 'Weak'
165 elif result['credits'] < 20:
166 result['valuation'] = 'OK'
167 elif result['credits'] < 25:
168 result['valuation'] = 'Strong'
169 else:
170 result['valuation'] = 'Very strong'
171 result['valid'] = True
172 except DashboardException as ex:
173 result['valuation'] = str(ex)
174 return result
175
176
177 @ApiController('/user/{username}')
178 class UserChangePassword(BaseController):
179
180 @Endpoint('POST')
181 def change_password(self, username, old_password, new_password):
182 session_username = JwtManager.get_username()
183 if username != session_username:
184 raise DashboardException(msg='Invalid user context',
185 code='invalid_user_context',
186 component='user')
187 try:
188 user = mgr.ACCESS_CTRL_DB.get_user(session_username)
189 except UserDoesNotExist:
190 raise cherrypy.HTTPError(404)
191 if not user.compare_password(old_password):
192 raise DashboardException(msg='Invalid old password',
193 code='invalid_old_password',
194 component='user')
195 validate_password_policy(new_password, username, old_password)
196 user.set_password(new_password)
197 mgr.ACCESS_CTRL_DB.save()