]> git.proxmox.com Git - ceph.git/blame - ceph/qa/tasks/mgr/dashboard/test_user.py
import ceph 16.2.7
[ceph.git] / ceph / qa / tasks / mgr / dashboard / test_user.py
CommitLineData
11fdf7f2 1# -*- coding: utf-8 -*-
f67539c2 2# pylint: disable=too-many-public-methods
11fdf7f2
TL
3
4from __future__ import absolute_import
5
9f95a23c 6import time
9f95a23c
TL
7from datetime import datetime, timedelta
8
f67539c2 9from .helper import DashboardTestCase
11fdf7f2
TL
10
11
12class UserTest(DashboardTestCase):
9f95a23c
TL
13 @classmethod
14 def setUpClass(cls):
15 super(UserTest, cls).setUpClass()
16 cls._ceph_cmd(['dashboard', 'set-pwd-policy-enabled', 'true'])
17 cls._ceph_cmd(['dashboard', 'set-pwd-policy-check-length-enabled', 'true'])
18 cls._ceph_cmd(['dashboard', 'set-pwd-policy-check-oldpwd-enabled', 'true'])
19 cls._ceph_cmd(['dashboard', 'set-pwd-policy-check-username-enabled', 'true'])
20 cls._ceph_cmd(['dashboard', 'set-pwd-policy-check-exclusion-list-enabled', 'true'])
21 cls._ceph_cmd(['dashboard', 'set-pwd-policy-check-complexity-enabled', 'true'])
22 cls._ceph_cmd(['dashboard', 'set-pwd-policy-check-sequential-chars-enabled', 'true'])
23 cls._ceph_cmd(['dashboard', 'set-pwd-policy-check-repetitive-chars-enabled', 'true'])
24
25 @classmethod
26 def tearDownClass(cls):
27 cls._ceph_cmd(['dashboard', 'set-pwd-policy-check-username-enabled', 'false'])
28 cls._ceph_cmd(['dashboard', 'set-pwd-policy-check-exclusion-list-enabled', 'false'])
29 cls._ceph_cmd(['dashboard', 'set-pwd-policy-check-complexity-enabled', 'false'])
30 cls._ceph_cmd(['dashboard', 'set-pwd-policy-check-sequential-chars-enabled', 'false'])
31 cls._ceph_cmd(['dashboard', 'set-pwd-policy-check-repetitive-chars-enabled', 'false'])
32 super(UserTest, cls).tearDownClass()
11fdf7f2
TL
33
34 @classmethod
9f95a23c
TL
35 def _create_user(cls, username=None, password=None, name=None, email=None, roles=None,
36 enabled=True, pwd_expiration_date=None, pwd_update_required=False):
11fdf7f2
TL
37 data = {}
38 if username:
39 data['username'] = username
40 if password:
41 data['password'] = password
42 if name:
43 data['name'] = name
44 if email:
45 data['email'] = email
46 if roles:
47 data['roles'] = roles
9f95a23c
TL
48 if pwd_expiration_date:
49 data['pwdExpirationDate'] = pwd_expiration_date
50 data['pwdUpdateRequired'] = pwd_update_required
51 data['enabled'] = enabled
11fdf7f2
TL
52 cls._post("/api/user", data)
53
9f95a23c
TL
54 @classmethod
55 def _reset_login_to_admin(cls, username=None):
56 cls.logout()
57 if username:
58 cls.delete_user(username)
59 cls.login('admin', 'admin')
60
11fdf7f2
TL
61 def test_crud_user(self):
62 self._create_user(username='user1',
9f95a23c 63 password='mypassword10#',
11fdf7f2
TL
64 name='My Name',
65 email='my@email.com',
66 roles=['administrator'])
67 self.assertStatus(201)
68 user = self.jsonBody()
69
70 self._get('/api/user/user1')
71 self.assertStatus(200)
72 self.assertJsonBody({
73 'username': 'user1',
74 'name': 'My Name',
75 'email': 'my@email.com',
76 'roles': ['administrator'],
9f95a23c
TL
77 'lastUpdate': user['lastUpdate'],
78 'enabled': True,
79 'pwdExpirationDate': None,
80 'pwdUpdateRequired': False
11fdf7f2
TL
81 })
82
83 self._put('/api/user/user1', {
84 'name': 'My New Name',
85 'email': 'mynew@email.com',
86 'roles': ['block-manager'],
87 })
88 self.assertStatus(200)
89 user = self.jsonBody()
90 self.assertJsonBody({
91 'username': 'user1',
92 'name': 'My New Name',
93 'email': 'mynew@email.com',
94 'roles': ['block-manager'],
9f95a23c
TL
95 'lastUpdate': user['lastUpdate'],
96 'enabled': True,
97 'pwdExpirationDate': None,
98 'pwdUpdateRequired': False
11fdf7f2
TL
99 })
100
101 self._delete('/api/user/user1')
102 self.assertStatus(204)
103
9f95a23c
TL
104 def test_crd_disabled_user(self):
105 self._create_user(username='klara',
106 password='mypassword10#',
107 name='Klara Musterfrau',
108 email='klara@musterfrau.com',
109 roles=['administrator'],
110 enabled=False)
111 self.assertStatus(201)
112 user = self.jsonBody()
113
114 # Restart dashboard module.
115 self._unload_module('dashboard')
116 self._load_module('dashboard')
117 time.sleep(10)
118
119 self._get('/api/user/klara')
120 self.assertStatus(200)
121 self.assertJsonBody({
122 'username': 'klara',
123 'name': 'Klara Musterfrau',
124 'email': 'klara@musterfrau.com',
125 'roles': ['administrator'],
126 'lastUpdate': user['lastUpdate'],
127 'enabled': False,
128 'pwdExpirationDate': None,
129 'pwdUpdateRequired': False
130 })
131
132 self._delete('/api/user/klara')
133 self.assertStatus(204)
134
11fdf7f2
TL
135 def test_list_users(self):
136 self._get('/api/user')
137 self.assertStatus(200)
138 user = self.jsonBody()
139 self.assertEqual(len(user), 1)
140 user = user[0]
141 self.assertJsonBody([{
142 'username': 'admin',
143 'name': None,
144 'email': None,
145 'roles': ['administrator'],
9f95a23c
TL
146 'lastUpdate': user['lastUpdate'],
147 'enabled': True,
148 'pwdExpirationDate': None,
149 'pwdUpdateRequired': False
11fdf7f2
TL
150 }])
151
152 def test_create_user_already_exists(self):
153 self._create_user(username='admin',
9f95a23c 154 password='mypassword10#',
11fdf7f2
TL
155 name='administrator',
156 email='my@email.com',
157 roles=['administrator'])
158 self.assertStatus(400)
159 self.assertError(code='username_already_exists',
160 component='user')
161
162 def test_create_user_invalid_role(self):
163 self._create_user(username='user1',
9f95a23c 164 password='mypassword10#',
11fdf7f2
TL
165 name='My Name',
166 email='my@email.com',
167 roles=['invalid-role'])
168 self.assertStatus(400)
169 self.assertError(code='role_does_not_exist',
170 component='user')
171
f67539c2
TL
172 def test_create_user_invalid_chars_in_name(self):
173 self._create_user(username='userö',
174 password='mypassword10#',
175 name='administrator',
176 email='my@email.com',
177 roles=['administrator'])
178 self.assertStatus(400)
179 self.assertError(code='ceph_type_not_valid',
180 component='user')
181
11fdf7f2
TL
182 def test_delete_user_does_not_exist(self):
183 self._delete('/api/user/user2')
184 self.assertStatus(404)
185
186 @DashboardTestCase.RunAs('test', 'test', [{'user': ['create', 'read', 'update', 'delete']}])
187 def test_delete_current_user(self):
188 self._delete('/api/user/test')
189 self.assertStatus(400)
190 self.assertError(code='cannot_delete_current_user',
191 component='user')
192
9f95a23c
TL
193 @DashboardTestCase.RunAs('test', 'test', [{'user': ['create', 'read', 'update', 'delete']}])
194 def test_disable_current_user(self):
195 self._put('/api/user/test', {'enabled': False})
196 self.assertStatus(400)
197 self.assertError(code='cannot_disable_current_user',
198 component='user')
199
11fdf7f2
TL
200 def test_update_user_does_not_exist(self):
201 self._put('/api/user/user2', {'name': 'My New Name'})
202 self.assertStatus(404)
203
204 def test_update_user_invalid_role(self):
205 self._put('/api/user/admin', {'roles': ['invalid-role']})
206 self.assertStatus(400)
207 self.assertError(code='role_does_not_exist',
208 component='user')
9f95a23c
TL
209
210 def test_change_password_from_other_user(self):
211 self._post('/api/user/test2/change_password', {
212 'old_password': 'abc',
213 'new_password': 'xyz'
214 })
215 self.assertStatus(400)
216 self.assertError(code='invalid_user_context', component='user')
217
218 def test_change_password_old_not_match(self):
219 self._post('/api/user/admin/change_password', {
220 'old_password': 'foo',
221 'new_password': 'bar'
222 })
223 self.assertStatus(400)
224 self.assertError(code='invalid_old_password', component='user')
225
226 def test_change_password_as_old_password(self):
227 self.create_user('test1', 'mypassword10#', ['read-only'], force_password=False)
228 self.login('test1', 'mypassword10#')
229 self._post('/api/user/test1/change_password', {
230 'old_password': 'mypassword10#',
231 'new_password': 'mypassword10#'
232 })
233 self.assertStatus(400)
234 self.assertError('password_policy_validation_failed', 'user',
235 'Password must not be the same as the previous one.')
236 self._reset_login_to_admin('test1')
237
238 def test_change_password_contains_username(self):
239 self.create_user('test1', 'mypassword10#', ['read-only'], force_password=False)
240 self.login('test1', 'mypassword10#')
241 self._post('/api/user/test1/change_password', {
242 'old_password': 'mypassword10#',
243 'new_password': 'mypasstest1@#'
244 })
245 self.assertStatus(400)
246 self.assertError('password_policy_validation_failed', 'user',
247 'Password must not contain username.')
248 self._reset_login_to_admin('test1')
249
250 def test_change_password_contains_forbidden_words(self):
251 self.create_user('test1', 'mypassword10#', ['read-only'], force_password=False)
252 self.login('test1', 'mypassword10#')
253 self._post('/api/user/test1/change_password', {
254 'old_password': 'mypassword10#',
255 'new_password': 'mypassOSD01'
256 })
257 self.assertStatus(400)
258 self.assertError('password_policy_validation_failed', 'user',
259 'Password must not contain the keyword "OSD".')
260 self._reset_login_to_admin('test1')
261
262 def test_change_password_contains_sequential_characters(self):
263 self.create_user('test1', 'mypassword10#', ['read-only'], force_password=False)
264 self.login('test1', 'mypassword10#')
265 self._post('/api/user/test1/change_password', {
266 'old_password': 'mypassword10#',
267 'new_password': 'mypass123456!@$'
268 })
269 self.assertStatus(400)
270 self.assertError('password_policy_validation_failed', 'user',
271 'Password must not contain sequential characters.')
272 self._reset_login_to_admin('test1')
273
274 def test_change_password_contains_repetetive_characters(self):
275 self.create_user('test1', 'mypassword10#', ['read-only'], force_password=False)
276 self.login('test1', 'mypassword10#')
277 self._post('/api/user/test1/change_password', {
278 'old_password': 'mypassword10#',
279 'new_password': 'aaaaA1@!#'
280 })
281 self.assertStatus(400)
282 self.assertError('password_policy_validation_failed', 'user',
283 'Password must not contain repetitive characters.')
284 self._reset_login_to_admin('test1')
285
286 @DashboardTestCase.RunAs('test1', 'mypassword10#', ['read-only'], False)
287 def test_change_password(self):
288 self._post('/api/user/test1/change_password', {
289 'old_password': 'mypassword10#',
290 'new_password': 'newpassword01#'
291 })
292 self.assertStatus(200)
293 self.logout()
294 self._post('/api/auth', {'username': 'test1', 'password': 'mypassword10#'})
295 self.assertStatus(400)
296 self.assertError(code='invalid_credentials', component='auth')
297
298 def test_create_user_password_cli(self):
cd265ab1
TL
299 exitcode = self._ceph_cmd_with_secret(['dashboard', 'ac-user-create',
300 'test1'],
301 'mypassword10#',
302 return_exit_code=True)
9f95a23c
TL
303 self.assertEqual(exitcode, 0)
304 self.delete_user('test1')
305
306 @DashboardTestCase.RunAs('test2', 'foo_bar_10#', force_password=False, login=False)
307 def test_change_user_password_cli(self):
cd265ab1
TL
308 exitcode = self._ceph_cmd_with_secret(['dashboard', 'ac-user-set-password',
309 'test2'],
310 'foo_new-password01#',
311 return_exit_code=True)
9f95a23c
TL
312 self.assertEqual(exitcode, 0)
313
314 def test_create_user_password_force_cli(self):
cd265ab1
TL
315 exitcode = self._ceph_cmd_with_secret(['dashboard', 'ac-user-create',
316 '--force-password', 'test11'],
317 'bar',
318 return_exit_code=True)
9f95a23c
TL
319 self.assertEqual(exitcode, 0)
320 self.delete_user('test11')
321
322 @DashboardTestCase.RunAs('test22', 'foo_bar_10#', force_password=False, login=False)
323 def test_change_user_password_force_cli(self):
cd265ab1
TL
324 exitcode = self._ceph_cmd_with_secret(['dashboard', 'ac-user-set-password',
325 '--force-password', 'test22'],
326 'bar',
327 return_exit_code=True)
9f95a23c
TL
328 self.assertEqual(exitcode, 0)
329
330 def test_create_user_password_cli_fail(self):
cd265ab1
TL
331 exitcode = self._ceph_cmd_with_secret(['dashboard', 'ac-user-create',
332 'test3'],
333 'foo',
334 return_exit_code=True)
9f95a23c
TL
335 self.assertNotEqual(exitcode, 0)
336
337 @DashboardTestCase.RunAs('test4', 'x1z_tst+_10#', force_password=False, login=False)
338 def test_change_user_password_cli_fail(self):
cd265ab1
TL
339 exitcode = self._ceph_cmd_with_secret(['dashboard', 'ac-user-set-password',
340 'test4'],
341 'bar',
342 return_exit_code=True)
9f95a23c
TL
343 self.assertNotEqual(exitcode, 0)
344
345 def test_create_user_with_pwd_expiration_date(self):
346 future_date = datetime.utcnow() + timedelta(days=10)
347 future_date = int(time.mktime(future_date.timetuple()))
348
349 self._create_user(username='user1',
350 password='mypassword10#',
351 name='My Name',
352 email='my@email.com',
353 roles=['administrator'],
354 pwd_expiration_date=future_date)
355 self.assertStatus(201)
356 user = self.jsonBody()
357
358 self._get('/api/user/user1')
359 self.assertStatus(200)
360 self.assertJsonBody({
361 'username': 'user1',
362 'name': 'My Name',
363 'email': 'my@email.com',
364 'roles': ['administrator'],
365 'lastUpdate': user['lastUpdate'],
366 'enabled': True,
367 'pwdExpirationDate': future_date,
368 'pwdUpdateRequired': False
369 })
370 self._delete('/api/user/user1')
371
372 def test_create_with_pwd_expiration_date_not_valid(self):
373 past_date = datetime.utcnow() - timedelta(days=10)
374 past_date = int(time.mktime(past_date.timetuple()))
375
376 self._create_user(username='user1',
377 password='mypassword10#',
378 name='My Name',
379 email='my@email.com',
380 roles=['administrator'],
381 pwd_expiration_date=past_date)
382 self.assertStatus(400)
383 self.assertError(code='pwd_past_expiration_date', component='user')
384
385 def test_create_with_default_expiration_date(self):
386 future_date_1 = datetime.utcnow() + timedelta(days=9)
387 future_date_1 = int(time.mktime(future_date_1.timetuple()))
388 future_date_2 = datetime.utcnow() + timedelta(days=11)
389 future_date_2 = int(time.mktime(future_date_2.timetuple()))
390
391 self._ceph_cmd(['dashboard', 'set-user-pwd-expiration-span', '10'])
392 self._create_user(username='user1',
393 password='mypassword10#',
394 name='My Name',
395 email='my@email.com',
396 roles=['administrator'])
397 self.assertStatus(201)
398
399 user = self._get('/api/user/user1')
400 self.assertStatus(200)
401 self.assertIsNotNone(user['pwdExpirationDate'])
402 self.assertGreater(user['pwdExpirationDate'], future_date_1)
403 self.assertLess(user['pwdExpirationDate'], future_date_2)
404
405 self._delete('/api/user/user1')
406 self._ceph_cmd(['dashboard', 'set-user-pwd-expiration-span', '0'])
407
408 def test_pwd_expiration_date_update(self):
409 self._ceph_cmd(['dashboard', 'set-user-pwd-expiration-span', '10'])
410 self.create_user('user1', 'mypassword10#', ['administrator'])
411
412 user_1 = self._get('/api/user/user1')
413 self.assertStatus(200)
414
a4b75251
TL
415 # Let's wait 1 s to ensure pwd expiration date is not the same
416 time.sleep(1)
417
9f95a23c
TL
418 self.login('user1', 'mypassword10#')
419 self._post('/api/user/user1/change_password', {
420 'old_password': 'mypassword10#',
421 'new_password': 'newpassword01#'
422 })
423 self.assertStatus(200)
424
425 # Compare password expiration dates.
426 self._reset_login_to_admin()
427 user_1_pwd_changed = self._get('/api/user/user1')
428 self.assertStatus(200)
429 self.assertLess(user_1['pwdExpirationDate'], user_1_pwd_changed['pwdExpirationDate'])
430
431 # Cleanup
432 self.delete_user('user1')
433 self._ceph_cmd(['dashboard', 'set-user-pwd-expiration-span', '0'])
434
435 def test_pwd_update_required(self):
436 self._create_user(username='user1',
437 password='mypassword10#',
438 name='My Name',
439 email='my@email.com',
440 roles=['administrator'],
441 pwd_update_required=True)
442 self.assertStatus(201)
443
444 user_1 = self._get('/api/user/user1')
445 self.assertStatus(200)
446 self.assertEqual(user_1['pwdUpdateRequired'], True)
447
448 self.login('user1', 'mypassword10#')
449 self.assertStatus(201)
450
451 self._get('/api/osd')
452 self.assertStatus(403)
453 self._reset_login_to_admin('user1')
454
455 def test_pwd_update_required_change_pwd(self):
456 self._create_user(username='user1',
457 password='mypassword10#',
458 name='My Name',
459 email='my@email.com',
460 roles=['administrator'],
461 pwd_update_required=True)
462 self.assertStatus(201)
463
464 self.login('user1', 'mypassword10#')
465 self._post('/api/user/user1/change_password', {
466 'old_password': 'mypassword10#',
467 'new_password': 'newpassword01#'
468 })
469
470 self.login('user1', 'newpassword01#')
471 user_1 = self._get('/api/user/user1')
472 self.assertStatus(200)
473 self.assertEqual(user_1['pwdUpdateRequired'], False)
474 self._get('/api/osd')
475 self.assertStatus(200)
476 self._reset_login_to_admin('user1')
477
478 def test_validate_password_weak(self):
479 self._post('/api/user/validate_password', {
480 'password': 'mypassword1'
481 })
482 self.assertStatus(200)
483 self.assertJsonBody({
484 'valid': True,
485 'credits': 11,
486 'valuation': 'Weak'
487 })
488
489 def test_validate_password_ok(self):
490 self._post('/api/user/validate_password', {
491 'password': 'mypassword1!@'
492 })
493 self.assertStatus(200)
494 self.assertJsonBody({
495 'valid': True,
496 'credits': 17,
497 'valuation': 'OK'
498 })
499
500 def test_validate_password_strong(self):
501 self._post('/api/user/validate_password', {
502 'password': 'testpassword0047!@'
503 })
504 self.assertStatus(200)
505 self.assertJsonBody({
506 'valid': True,
507 'credits': 22,
508 'valuation': 'Strong'
509 })
510
511 def test_validate_password_very_strong(self):
512 self._post('/api/user/validate_password', {
513 'password': 'testpassword#!$!@$'
514 })
515 self.assertStatus(200)
516 self.assertJsonBody({
517 'valid': True,
518 'credits': 30,
519 'valuation': 'Very strong'
520 })
521
522 def test_validate_password_fail(self):
523 self._post('/api/user/validate_password', {
524 'password': 'foo'
525 })
526 self.assertStatus(200)
527 self.assertJsonBody({
528 'valid': False,
529 'credits': 0,
530 'valuation': 'Password is too weak.'
531 })
532
533 def test_validate_password_fail_name(self):
534 self._post('/api/user/validate_password', {
535 'password': 'x1zhugo_10',
536 'username': 'hugo'
537 })
538 self.assertStatus(200)
539 self.assertJsonBody({
540 'valid': False,
541 'credits': 0,
542 'valuation': 'Password must not contain username.'
543 })
544
545 def test_validate_password_fail_oldpwd(self):
546 self._post('/api/user/validate_password', {
547 'password': 'x1zt-st10',
548 'old_password': 'x1zt-st10'
549 })
550 self.assertStatus(200)
551 self.assertJsonBody({
552 'valid': False,
553 'credits': 0,
554 'valuation': 'Password must not be the same as the previous one.'
555 })
556
557 def test_create_user_pwd_update_required(self):
558 self.create_user('foo', 'bar', cmd_args=['--pwd_update_required'])
559 self._get('/api/user/foo')
560 self.assertStatus(200)
561 self.assertJsonSubset({
562 'username': 'foo',
563 'pwdUpdateRequired': True
564 })
565 self.delete_user('foo')