ceph/qa/tasks/mgr/dashboard/test_user.py
Tatjana Dehler 0221241909 mgr/dashboard: add password expiration date
Add a 'pwd_expiration_date' field to the User object to be able
to set password expiration date per user.

There are two options to set a password expiration date for a
user:

1. Set the 'USER_PWD_EXPIRATION_SPAN' setting. If defined
   the expiration date of the password will be calculated
   automatically based on the given value. It will also be
   updated automatically when the user changes the password.
2. Set an expiration date by setting the 'pwdExpirationDate'
   field when creating a user.

Add two more settings in addition: USER_PWD_EXPIRATION_WARNING_1
and USER_PWD_EXPIRATION_WARNING_2. These two settings are
defining the amount of days to notify the user that his password
will expiration soon.

It's not possible to set the 'pwd_expiration_date' field to a
date in the past.

If the password of a user is already expired he is no longer
allowed to log into the dashboard.

Fixes: https://tracker.ceph.com/issues/40329
Signed-off-by: Tatjana Dehler <tdehler@suse.com>
2019-12-13 08:53:05 +01:00

392 lines
15 KiB
Python

# -*- coding: utf-8 -*-
from __future__ import absolute_import
import time
from datetime import datetime, timedelta
from .helper import DashboardTestCase
class UserTest(DashboardTestCase):
@classmethod
def _create_user(cls, username=None, password=None, name=None, email=None, roles=None,
enabled=True, pwd_expiration_date=None):
data = {}
if username:
data['username'] = username
if password:
data['password'] = password
if name:
data['name'] = name
if email:
data['email'] = email
if roles:
data['roles'] = roles
if pwd_expiration_date:
data['pwdExpirationDate'] = pwd_expiration_date
data['enabled'] = enabled
cls._post("/api/user", data)
@classmethod
def _reset_login_to_admin(cls, username=None):
cls.logout()
if username:
cls.delete_user(username)
cls.login('admin', 'admin')
def test_crud_user(self):
self._create_user(username='user1',
password='mypassword10#',
name='My Name',
email='my@email.com',
roles=['administrator'])
self.assertStatus(201)
user = self.jsonBody()
self._get('/api/user/user1')
self.assertStatus(200)
self.assertJsonBody({
'username': 'user1',
'name': 'My Name',
'email': 'my@email.com',
'roles': ['administrator'],
'lastUpdate': user['lastUpdate'],
'enabled': True,
'pwdExpirationDate': None
})
self._put('/api/user/user1', {
'name': 'My New Name',
'email': 'mynew@email.com',
'roles': ['block-manager'],
})
self.assertStatus(200)
user = self.jsonBody()
self.assertJsonBody({
'username': 'user1',
'name': 'My New Name',
'email': 'mynew@email.com',
'roles': ['block-manager'],
'lastUpdate': user['lastUpdate'],
'enabled': True,
'pwdExpirationDate': None
})
self._delete('/api/user/user1')
self.assertStatus(204)
def test_crd_disabled_user(self):
self._create_user(username='klara',
password='mypassword10#',
name='Klara Musterfrau',
email='klara@musterfrau.com',
roles=['administrator'],
enabled=False)
self.assertStatus(201)
user = self.jsonBody()
# Restart dashboard module.
self._unload_module('dashboard')
self._load_module('dashboard')
time.sleep(10)
self._get('/api/user/klara')
self.assertStatus(200)
self.assertJsonBody({
'username': 'klara',
'name': 'Klara Musterfrau',
'email': 'klara@musterfrau.com',
'roles': ['administrator'],
'lastUpdate': user['lastUpdate'],
'enabled': False,
'pwdExpirationDate': None
})
self._delete('/api/user/klara')
self.assertStatus(204)
def test_list_users(self):
self._get('/api/user')
self.assertStatus(200)
user = self.jsonBody()
self.assertEqual(len(user), 1)
user = user[0]
self.assertJsonBody([{
'username': 'admin',
'name': None,
'email': None,
'roles': ['administrator'],
'lastUpdate': user['lastUpdate'],
'enabled': True,
'pwdExpirationDate': None
}])
def test_create_user_already_exists(self):
self._create_user(username='admin',
password='mypassword10#',
name='administrator',
email='my@email.com',
roles=['administrator'])
self.assertStatus(400)
self.assertError(code='username_already_exists',
component='user')
def test_create_user_invalid_role(self):
self._create_user(username='user1',
password='mypassword10#',
name='My Name',
email='my@email.com',
roles=['invalid-role'])
self.assertStatus(400)
self.assertError(code='role_does_not_exist',
component='user')
def test_delete_user_does_not_exist(self):
self._delete('/api/user/user2')
self.assertStatus(404)
@DashboardTestCase.RunAs('test', 'test', [{'user': ['create', 'read', 'update', 'delete']}])
def test_delete_current_user(self):
self._delete('/api/user/test')
self.assertStatus(400)
self.assertError(code='cannot_delete_current_user',
component='user')
@DashboardTestCase.RunAs('test', 'test', [{'user': ['create', 'read', 'update', 'delete']}])
def test_disable_current_user(self):
self._put('/api/user/test', {'enabled': False})
self.assertStatus(400)
self.assertError(code='cannot_disable_current_user',
component='user')
def test_update_user_does_not_exist(self):
self._put('/api/user/user2', {'name': 'My New Name'})
self.assertStatus(404)
def test_update_user_invalid_role(self):
self._put('/api/user/admin', {'roles': ['invalid-role']})
self.assertStatus(400)
self.assertError(code='role_does_not_exist',
component='user')
def test_change_password_from_other_user(self):
self._post('/api/user/test2/change_password', {
'old_password': 'abc',
'new_password': 'xyz'
})
self.assertStatus(400)
self.assertError(code='invalid_user_context', component='user')
def test_change_password_old_not_match(self):
self._post('/api/user/admin/change_password', {
'old_password': 'foo',
'new_password': 'bar'
})
self.assertStatus(400)
self.assertError(code='invalid_old_password', component='user')
def test_change_password_as_old_password(self):
self.create_user('test1', 'mypassword10#', ['read-only'], force_password=False)
self.login('test1', 'mypassword10#')
self._post('/api/user/test1/change_password', {
'old_password': 'mypassword10#',
'new_password': 'mypassword10#'
})
self.assertStatus(400)
self.assertError('password_policy_validation_failed', 'user',
'Password cannot be the same as the previous one.')
self._reset_login_to_admin('test1')
def test_change_password_contains_username(self):
self.create_user('test1', 'mypassword10#', ['read-only'], force_password=False)
self.login('test1', 'mypassword10#')
self._post('/api/user/test1/change_password', {
'old_password': 'mypassword10#',
'new_password': 'mypasstest1@#'
})
self.assertStatus(400)
self.assertError('password_policy_validation_failed', 'user',
'Password cannot contain username.')
self._reset_login_to_admin('test1')
def test_change_password_contains_forbidden_words(self):
self.create_user('test1', 'mypassword10#', ['read-only'], force_password=False)
self.login('test1', 'mypassword10#')
self._post('/api/user/test1/change_password', {
'old_password': 'mypassword10#',
'new_password': 'mypassOSD01'
})
self.assertStatus(400)
self.assertError('password_policy_validation_failed', 'user',
'Password cannot contain keywords.')
self._reset_login_to_admin('test1')
def test_change_password_contains_sequential_characters(self):
self.create_user('test1', 'mypassword10#', ['read-only'], force_password=False)
self.login('test1', 'mypassword10#')
self._post('/api/user/test1/change_password', {
'old_password': 'mypassword10#',
'new_password': 'mypass123456!@$'
})
self.assertStatus(400)
self.assertError('password_policy_validation_failed', 'user',
'Password cannot contain sequential characters.')
self._reset_login_to_admin('test1')
def test_change_password_contains_repetetive_characters(self):
self.create_user('test1', 'mypassword10#', ['read-only'], force_password=False)
self.login('test1', 'mypassword10#')
self._post('/api/user/test1/change_password', {
'old_password': 'mypassword10#',
'new_password': 'aaaaA1@!#'
})
self.assertStatus(400)
self.assertError('password_policy_validation_failed', 'user',
'Password cannot contain repetitive characters.')
self._reset_login_to_admin('test1')
def test_change_password(self):
self.create_user('test1', 'mypassword10#', ['read-only'], force_password=False)
self.login('test1', 'mypassword10#')
self._post('/api/user/test1/change_password', {
'old_password': 'mypassword10#',
'new_password': 'newpassword01#'
})
self.assertStatus(200)
self.logout()
self._post('/api/auth', {'username': 'test1', 'password': 'mypassword10#'})
self.assertStatus(400)
self.assertError(code='invalid_credentials', component='auth')
self.delete_user('test1')
self.login('admin', 'admin')
def test_create_user_password_cli(self):
exitcode = self._ceph_cmd_result(['dashboard', 'ac-user-create',
'test1', 'mypassword10#'])
self.assertEqual(exitcode, 0)
self.delete_user('test1')
def test_change_user_password_cli(self):
self.create_user('test2', 'foo_bar_10#', force_password=False)
exitcode = self._ceph_cmd_result(['dashboard', 'ac-user-set-password',
'test2', 'foo_new-password01#'])
self.assertEqual(exitcode, 0)
self.delete_user('test2')
def test_create_user_password_force_cli(self):
exitcode = self._ceph_cmd_result(['dashboard', 'ac-user-create',
'--force-password', 'test11',
'bar'])
self.assertEqual(exitcode, 0)
self.delete_user('test11')
def test_change_user_password_force_cli(self):
self.create_user('test22', 'foo_bar_10#', force_password=False)
exitcode = self._ceph_cmd_result(['dashboard', 'ac-user-set-password',
'--force-password', 'test22',
'bar'])
self.assertEqual(exitcode, 0)
self.delete_user('test22')
def test_create_user_password_cli_fail(self):
exitcode = self._ceph_cmd_result(['dashboard', 'ac-user-create', 'test3', 'foo'])
self.assertNotEqual(exitcode, 0)
def test_change_user_password_cli_fail(self):
self.create_user('test4', 'x1z_tst+_10#', force_password=False)
exitcode = self._ceph_cmd_result(['dashboard', 'ac-user-set-password',
'test4', 'bar'])
self.assertNotEqual(exitcode, 0)
self.delete_user('test4')
def test_create_user_with_pwd_expiration_date(self):
future_date = datetime.utcnow() + timedelta(days=10)
future_date = int(time.mktime(future_date.timetuple()))
self._create_user(username='user1',
password='mypassword10#',
name='My Name',
email='my@email.com',
roles=['administrator'],
pwd_expiration_date=future_date)
self.assertStatus(201)
user = self.jsonBody()
self._get('/api/user/user1')
self.assertStatus(200)
self.assertJsonBody({
'username': 'user1',
'name': 'My Name',
'email': 'my@email.com',
'roles': ['administrator'],
'lastUpdate': user['lastUpdate'],
'enabled': True,
'pwdExpirationDate': future_date
})
self._delete('/api/user/user1')
def test_create_with_pwd_expiration_date_not_valid(self):
past_date = datetime.utcnow() - timedelta(days=10)
past_date = int(time.mktime(past_date.timetuple()))
self._create_user(username='user1',
password='mypassword10#',
name='My Name',
email='my@email.com',
roles=['administrator'],
pwd_expiration_date=past_date)
self.assertStatus(400)
self.assertError(code='pwd_past_expiration_date', component='user')
def test_create_with_default_expiration_date(self):
future_date_1 = datetime.utcnow() + timedelta(days=10)
future_date_1 = int(time.mktime(future_date_1.timetuple()))
future_date_2 = datetime.utcnow() + timedelta(days=11)
future_date_2 = int(time.mktime(future_date_2.timetuple()))
self._ceph_cmd(['dashboard', 'set-user-pwd-expiration-span', '10'])
self._create_user(username='user1',
password='mypassword10#',
name='My Name',
email='my@email.com',
roles=['administrator'])
self.assertStatus(201)
user = self._get('/api/user/user1')
self.assertStatus(200)
self.assertIsNotNone(user['pwdExpirationDate'])
self.assertGreater(user['pwdExpirationDate'], future_date_1)
self.assertLess(user['pwdExpirationDate'], future_date_2)
self._delete('/api/user/user1')
self._ceph_cmd(['dashboard', 'set-user-pwd-expiration-span', '0'])
def test_pwd_expiration_date_update(self):
self._ceph_cmd(['dashboard', 'set-user-pwd-expiration-span', '10'])
self._create_user(username='user1',
password='mypassword10#',
name='My Name',
email='my@email.com',
roles=['administrator'])
self.assertStatus(201)
user_1 = self._get('/api/user/user1')
self.assertStatus(200)
self.login('user1', 'mypassword10#')
self._post('/api/user/user1/change_password', {
'old_password': 'mypassword10#',
'new_password': 'newpassword01#'
})
self.assertStatus(200)
self._reset_login_to_admin()
user_2 = self._get('/api/user/user1')
self.assertStatus(200)
self.assertLess(user_1['pwdExpirationDate'], user_2['pwdExpirationDate'])
self._delete('/api/user/user1')
self._ceph_cmd(['dashboard', 'set-user-pwd-expiration-span', '0'])