blob: 13b5161a9d3cd5da5ac9ee9ac7b18acebe60f310 [file] [log] [blame]
Jane Zadorozhna9c938c62015-07-01 17:06:16 +03001# Copyright 2015 OpenStack Foundation
2# All Rights Reserved.
3#
4# Licensed under the Apache License, Version 2.0 (the "License"); you may
5# not use this file except in compliance with the License. You may obtain
6# a copy of the License at
7#
8# http://www.apache.org/licenses/LICENSE-2.0
9#
10# Unless required by applicable law or agreed to in writing, software
11# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
12# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
13# License for the specific language governing permissions and limitations
14# under the License.
15
Lance Bragstada2c4ebc2015-10-05 20:34:39 +000016import time
Jane Zadorozhna9c938c62015-07-01 17:06:16 +030017
Rodrigo Duarte Sousa2d78e8e2016-09-28 10:38:08 -030018import testtools
19
Jane Zadorozhna9c938c62015-07-01 17:06:16 +030020from tempest.api.identity import base
Rodrigo Duarte Sousa2d78e8e2016-09-28 10:38:08 -030021from tempest import config
Andrea Frittoli (andreaf)db9672e2016-02-23 14:07:24 -050022from tempest.lib.common.utils import data_utils
Ken'ichi Ohmichi44f01272017-01-27 18:44:14 -080023from tempest.lib import decorators
Andrea Frittoli (andreaf)db9672e2016-02-23 14:07:24 -050024from tempest.lib import exceptions
Jane Zadorozhna9c938c62015-07-01 17:06:16 +030025
26
Rodrigo Duarte Sousa2d78e8e2016-09-28 10:38:08 -030027CONF = config.CONF
28
29
Jane Zadorozhna9c938c62015-07-01 17:06:16 +030030class IdentityV3UsersTest(base.BaseIdentityV3Test):
31
32 @classmethod
33 def resource_setup(cls):
34 super(IdentityV3UsersTest, cls).resource_setup()
Jordan Pittier8160d312017-04-18 11:52:23 +020035 cls.creds = cls.os_primary.credentials
Jane Zadorozhna9c938c62015-07-01 17:06:16 +030036 cls.user_id = cls.creds.user_id
Jane Zadorozhna9c938c62015-07-01 17:06:16 +030037
Rodrigo Duarte Sousa2d78e8e2016-09-28 10:38:08 -030038 def _update_password(self, original_password, password):
Daniel Mellado7aea5342016-02-09 09:10:12 +000039 self.non_admin_users_client.update_user_password(
Rodrigo Duarte Sousa2d78e8e2016-09-28 10:38:08 -030040 self.user_id,
41 password=password,
42 original_password=original_password)
Lance Bragstad144c2f42015-11-19 16:42:37 +000043
Morgan Fainberg5b2c7452016-02-02 20:15:47 -080044 # NOTE(morganfainberg): Fernet tokens are not subsecond aware and
45 # Keystone should only be precise to the second. Sleep to ensure
Yaroslav Lobankovcbcb6112016-03-08 12:30:01 -060046 # we are passing the second boundary.
Lance Bragstada2c4ebc2015-10-05 20:34:39 +000047 time.sleep(1)
48
Jane Zadorozhna9c938c62015-07-01 17:06:16 +030049 # check authorization with new password
Rodrigo Duarte Sousa2d78e8e2016-09-28 10:38:08 -030050 self.non_admin_token.auth(user_id=self.user_id, password=password)
51
52 # Reset auth to get a new token with the new password
53 self.non_admin_users_client.auth_provider.clear_auth()
54 self.non_admin_users_client.auth_provider.credentials.password = (
55 password)
56
57 def _restore_password(self, old_pass, new_pass):
58 if CONF.identity_feature_enabled.security_compliance:
59 # First we need to clear the password history
60 unique_count = CONF.identity.user_unique_last_password_count
zhufl8e9a0732017-01-26 16:15:21 +080061 for _ in range(unique_count):
Rodrigo Duarte Sousa2d78e8e2016-09-28 10:38:08 -030062 random_pass = data_utils.rand_password()
63 self._update_password(
64 original_password=new_pass, password=random_pass)
65 new_pass = random_pass
66
67 self._update_password(original_password=new_pass, password=old_pass)
68 # Reset auth again to verify the password restore does work.
69 # Clear auth restores the original credentials and deletes
70 # cached auth data
71 self.non_admin_users_client.auth_provider.clear_auth()
72 # NOTE(lbragstad): Fernet tokens are not subsecond aware and
73 # Keystone should only be precise to the second. Sleep to ensure we
74 # are passing the second boundary before attempting to
75 # authenticate.
76 time.sleep(1)
77 self.non_admin_users_client.auth_provider.set_auth()
78
Ken'ichi Ohmichi44f01272017-01-27 18:44:14 -080079 @decorators.idempotent_id('ad71bd23-12ad-426b-bb8b-195d2b635f27')
Rodrigo Duarte Sousa2d78e8e2016-09-28 10:38:08 -030080 def test_user_update_own_password(self):
81 old_pass = self.creds.password
82 old_token = self.non_admin_client.token
83 new_pass = data_utils.rand_password()
84
Ken'ichi Ohmichi553d7cb2018-07-13 22:53:03 +000085 # to change password back. important for use_dynamic_credentials=false
Rodrigo Duarte Sousa2d78e8e2016-09-28 10:38:08 -030086 self.addCleanup(self._restore_password, old_pass, new_pass)
87
88 # user updates own password
89 self._update_password(original_password=old_pass, password=new_pass)
Jane Zadorozhna9c938c62015-07-01 17:06:16 +030090
91 # authorize with old token should lead to IdentityError (404 code)
92 self.assertRaises(exceptions.IdentityError,
93 self.non_admin_token.auth,
Rodrigo Duarte Sousa2d78e8e2016-09-28 10:38:08 -030094 token=old_token)
Jane Zadorozhna9c938c62015-07-01 17:06:16 +030095
96 # authorize with old password should lead to Unauthorized
97 self.assertRaises(exceptions.Unauthorized,
98 self.non_admin_token.auth,
99 user_id=self.user_id,
100 password=old_pass)
Rodrigo Duarte Sousa2d78e8e2016-09-28 10:38:08 -0300101
102 @testtools.skipUnless(CONF.identity_feature_enabled.security_compliance,
103 'Security compliance not available.')
Ken'ichi Ohmichi44f01272017-01-27 18:44:14 -0800104 @decorators.idempotent_id('941784ee-5342-4571-959b-b80dd2cea516')
Rodrigo Duarte Sousa2d78e8e2016-09-28 10:38:08 -0300105 def test_password_history_check_self_service_api(self):
106 old_pass = self.creds.password
107 new_pass1 = data_utils.rand_password()
108 new_pass2 = data_utils.rand_password()
109
110 self.addCleanup(self._restore_password, old_pass, new_pass2)
111
112 # Update password
113 self._update_password(original_password=old_pass, password=new_pass1)
114
115 if CONF.identity.user_unique_last_password_count > 1:
116 # Can not reuse a previously set password
117 self.assertRaises(exceptions.BadRequest,
118 self.non_admin_users_client.update_user_password,
119 self.user_id,
120 password=new_pass1,
121 original_password=new_pass1)
122
123 self.assertRaises(exceptions.BadRequest,
124 self.non_admin_users_client.update_user_password,
125 self.user_id,
126 password=old_pass,
127 original_password=new_pass1)
128
129 # A different password can be set
130 self._update_password(original_password=new_pass1, password=new_pass2)
131
132 @testtools.skipUnless(CONF.identity_feature_enabled.security_compliance,
133 'Security compliance not available.')
Ken'ichi Ohmichi44f01272017-01-27 18:44:14 -0800134 @decorators.idempotent_id('a7ad8bbf-2cff-4520-8c1d-96332e151658')
Rodrigo Duarte Sousa2d78e8e2016-09-28 10:38:08 -0300135 def test_user_account_lockout(self):
zhufl270c25a2018-10-18 14:56:16 +0800136 if (CONF.identity.user_lockout_failure_attempts <= 0 or
137 CONF.identity.user_lockout_duration <= 0):
138 raise self.skipException(
139 "Both CONF.identity.user_lockout_failure_attempts and "
140 "CONF.identity.user_lockout_duration should be greater than "
141 "zero to test this feature")
142
Rodrigo Duarte Sousa2d78e8e2016-09-28 10:38:08 -0300143 password = self.creds.password
144
145 # First, we login using the correct credentials
146 self.non_admin_token.auth(user_id=self.user_id, password=password)
147
148 # Lock user account by using the wrong password to login
149 bad_password = data_utils.rand_password()
zhufl8e9a0732017-01-26 16:15:21 +0800150 for _ in range(CONF.identity.user_lockout_failure_attempts):
Rodrigo Duarte Sousa2d78e8e2016-09-28 10:38:08 -0300151 self.assertRaises(exceptions.Unauthorized,
152 self.non_admin_token.auth,
153 user_id=self.user_id,
154 password=bad_password)
155
156 # The user account must be locked, so now it is not possible to login
157 # even using the correct password
158 self.assertRaises(exceptions.Unauthorized,
159 self.non_admin_token.auth,
160 user_id=self.user_id,
161 password=password)
162
163 # If we wait the required time, the user account will be unlocked
164 time.sleep(CONF.identity.user_lockout_duration + 1)
Rodrigo Duarte Sousa36f68822017-01-05 16:05:00 -0300165 self.non_admin_token.auth(user_id=self.user_id, password=password)