blob: f5b357c32a70d6ee36320237a95ece59379deecd [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
23from tempest.lib import exceptions
Jane Zadorozhna9c938c62015-07-01 17:06:16 +030024from tempest import test
25
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()
35 cls.creds = cls.os.credentials
36 cls.user_id = cls.creds.user_id
37 cls.username = cls.creds.username
38 cls.password = cls.creds.password
39
Rodrigo Duarte Sousa2d78e8e2016-09-28 10:38:08 -030040 def _update_password(self, original_password, password):
Daniel Mellado7aea5342016-02-09 09:10:12 +000041 self.non_admin_users_client.update_user_password(
Rodrigo Duarte Sousa2d78e8e2016-09-28 10:38:08 -030042 self.user_id,
43 password=password,
44 original_password=original_password)
Lance Bragstad144c2f42015-11-19 16:42:37 +000045
Morgan Fainberg5b2c7452016-02-02 20:15:47 -080046 # NOTE(morganfainberg): Fernet tokens are not subsecond aware and
47 # Keystone should only be precise to the second. Sleep to ensure
Yaroslav Lobankovcbcb6112016-03-08 12:30:01 -060048 # we are passing the second boundary.
Lance Bragstada2c4ebc2015-10-05 20:34:39 +000049 time.sleep(1)
50
Jane Zadorozhna9c938c62015-07-01 17:06:16 +030051 # check authorization with new password
Rodrigo Duarte Sousa2d78e8e2016-09-28 10:38:08 -030052 self.non_admin_token.auth(user_id=self.user_id, password=password)
53
54 # Reset auth to get a new token with the new password
55 self.non_admin_users_client.auth_provider.clear_auth()
56 self.non_admin_users_client.auth_provider.credentials.password = (
57 password)
58
59 def _restore_password(self, old_pass, new_pass):
60 if CONF.identity_feature_enabled.security_compliance:
61 # First we need to clear the password history
62 unique_count = CONF.identity.user_unique_last_password_count
63 for i in range(unique_count):
64 random_pass = data_utils.rand_password()
65 self._update_password(
66 original_password=new_pass, password=random_pass)
67 new_pass = random_pass
68
69 self._update_password(original_password=new_pass, password=old_pass)
70 # Reset auth again to verify the password restore does work.
71 # Clear auth restores the original credentials and deletes
72 # cached auth data
73 self.non_admin_users_client.auth_provider.clear_auth()
74 # NOTE(lbragstad): Fernet tokens are not subsecond aware and
75 # Keystone should only be precise to the second. Sleep to ensure we
76 # are passing the second boundary before attempting to
77 # authenticate.
78 time.sleep(1)
79 self.non_admin_users_client.auth_provider.set_auth()
80
81 @test.idempotent_id('ad71bd23-12ad-426b-bb8b-195d2b635f27')
82 def test_user_update_own_password(self):
83 old_pass = self.creds.password
84 old_token = self.non_admin_client.token
85 new_pass = data_utils.rand_password()
86
87 # to change password back. important for allow_tenant_isolation = false
88 self.addCleanup(self._restore_password, old_pass, new_pass)
89
90 # user updates own password
91 self._update_password(original_password=old_pass, password=new_pass)
Jane Zadorozhna9c938c62015-07-01 17:06:16 +030092
93 # authorize with old token should lead to IdentityError (404 code)
94 self.assertRaises(exceptions.IdentityError,
95 self.non_admin_token.auth,
Rodrigo Duarte Sousa2d78e8e2016-09-28 10:38:08 -030096 token=old_token)
Jane Zadorozhna9c938c62015-07-01 17:06:16 +030097
98 # authorize with old password should lead to Unauthorized
99 self.assertRaises(exceptions.Unauthorized,
100 self.non_admin_token.auth,
101 user_id=self.user_id,
102 password=old_pass)
Rodrigo Duarte Sousa2d78e8e2016-09-28 10:38:08 -0300103
104 @testtools.skipUnless(CONF.identity_feature_enabled.security_compliance,
105 'Security compliance not available.')
106 @test.idempotent_id('941784ee-5342-4571-959b-b80dd2cea516')
107 def test_password_history_check_self_service_api(self):
108 old_pass = self.creds.password
109 new_pass1 = data_utils.rand_password()
110 new_pass2 = data_utils.rand_password()
111
112 self.addCleanup(self._restore_password, old_pass, new_pass2)
113
114 # Update password
115 self._update_password(original_password=old_pass, password=new_pass1)
116
117 if CONF.identity.user_unique_last_password_count > 1:
118 # Can not reuse a previously set password
119 self.assertRaises(exceptions.BadRequest,
120 self.non_admin_users_client.update_user_password,
121 self.user_id,
122 password=new_pass1,
123 original_password=new_pass1)
124
125 self.assertRaises(exceptions.BadRequest,
126 self.non_admin_users_client.update_user_password,
127 self.user_id,
128 password=old_pass,
129 original_password=new_pass1)
130
131 # A different password can be set
132 self._update_password(original_password=new_pass1, password=new_pass2)
133
134 @testtools.skipUnless(CONF.identity_feature_enabled.security_compliance,
135 'Security compliance not available.')
136 @test.idempotent_id('a7ad8bbf-2cff-4520-8c1d-96332e151658')
137 def test_user_account_lockout(self):
138 password = self.creds.password
139
140 # First, we login using the correct credentials
141 self.non_admin_token.auth(user_id=self.user_id, password=password)
142
143 # Lock user account by using the wrong password to login
144 bad_password = data_utils.rand_password()
145 for i in range(CONF.identity.user_lockout_failure_attempts):
146 self.assertRaises(exceptions.Unauthorized,
147 self.non_admin_token.auth,
148 user_id=self.user_id,
149 password=bad_password)
150
151 # The user account must be locked, so now it is not possible to login
152 # even using the correct password
153 self.assertRaises(exceptions.Unauthorized,
154 self.non_admin_token.auth,
155 user_id=self.user_id,
156 password=password)
157
158 # If we wait the required time, the user account will be unlocked
159 time.sleep(CONF.identity.user_lockout_duration + 1)
160 self.token.auth(user_id=self.user_id, password=password)