diff options
author | Andrew Bartlett <abartlet@samba.org> | 2018-09-02 18:03:06 +1200 |
---|---|---|
committer | Andrew Bartlett <abartlet@samba.org> | 2018-09-03 06:14:55 +0200 |
commit | 74357bf347348d3a8b7483c58e5250e98f7e8810 (patch) | |
tree | a7233981d9656ad19877598789412867190d49bd /source4 | |
parent | a740a6131c967f9640b19a6964fd5d6f85ce853a (diff) | |
download | samba-74357bf347348d3a8b7483c58e5250e98f7e8810.tar.gz |
selftest: Split up password_lockout into tests with and without a call to sleep()
This means we can have a long observation window for many of the tests and
so make them much more reliable. Many of these cause frustrating flapping
failures in our CI systems.
Signed-off-by: Andrew Bartlett <abartlet@samba.org>
Reviewed-by: Gary Lockyer <gary@catalyst.net.nz>
Autobuild-User(master): Andrew Bartlett <abartlet@samba.org>
Autobuild-Date(master): Mon Sep 3 06:14:55 CEST 2018 on sn-devel-144
Diffstat (limited to 'source4')
-rwxr-xr-x | source4/dsdb/tests/python/password_lockout.py | 299 |
1 files changed, 157 insertions, 142 deletions
diff --git a/source4/dsdb/tests/python/password_lockout.py b/source4/dsdb/tests/python/password_lockout.py index be3e3fa53e2..aceebd66072 100755 --- a/source4/dsdb/tests/python/password_lockout.py +++ b/source4/dsdb/tests/python/password_lockout.py @@ -89,6 +89,42 @@ class PasswordTests(password_lockout_base.BasePasswordTestCase): self.lockout2ntlm_ldb = self._readd_user(self.lockout2ntlm_creds, lockOutObservationWindow=self.lockout_observation_window) + + def use_pso_lockout_settings(self, creds): + + # create a PSO with the lockout settings the test cases normally expect + # + # Some test cases sleep() for self.account_lockout_duration + pso = PasswordSettings("lockout-PSO", self.ldb, lockout_attempts=3, + lockout_duration=self.account_lockout_duration) + self.addCleanup(self.ldb.delete, pso.dn) + + userdn = "cn=%s,cn=users,%s" % (creds.get_username(), self.base_dn) + pso.apply_to(userdn) + + # update the global lockout settings to be wildly different to what + # the test cases normally expect + self.update_lockout_settings(threshold=10, duration=600, + observation_window=600) + + def _reset_samr(self, res): + + # Now reset the lockout, by removing ACB_AUTOLOCK (which removes the lock, despite being a generated attribute) + samr_user = self._open_samr_user(res) + acb_info = self.samr.QueryUserInfo(samr_user, 16) + acb_info.acct_flags &= ~samr.ACB_AUTOLOCK + self.samr.SetUserInfo(samr_user, 16, acb_info) + self.samr.Close(samr_user) + + +class PasswordTestsWithoutSleep(PasswordTests): + def setUp(self): + # The tests in this class do not sleep, so we can have a + # longer window and not flap on slower hosts + self.account_lockout_duration = 30 + self.lockout_observation_window = 30 + super(PasswordTestsWithoutSleep, self).setUp() + def _reset_ldap_lockoutTime(self, res): self.ldb.modify_ldif(""" dn: """ + str(res[0].dn) + """ @@ -599,22 +635,130 @@ userPassword: thatsAcomplPASS2XYZ "samr", initial_lastlogon_relation='greater') - def use_pso_lockout_settings(self, creds): + def test_multiple_logon_krb5(self): + self._test_multiple_logon(self.lockout1krb5_creds) - # create a PSO with the lockout settings the test cases normally expect - # - # Some test cases sleep() for self.account_lockout_duration - pso = PasswordSettings("lockout-PSO", self.ldb, lockout_attempts=3, - lockout_duration=self.account_lockout_duration) - self.addCleanup(self.ldb.delete, pso.dn) + def test_multiple_logon_ntlm(self): + self._test_multiple_logon(self.lockout1ntlm_creds) - userdn = "cn=%s,cn=users,%s" % (creds.get_username(), self.base_dn) - pso.apply_to(userdn) + def _test_samr_password_change(self, creds, other_creds, lockout_threshold=3): + """Tests user lockout by using bad password in SAMR password_change""" - # update the global lockout settings to be wildly different to what - # the test cases normally expect - self.update_lockout_settings(threshold=10, duration=600, - observation_window=600) + # create a connection for SAMR using another user's credentials + lp = self.get_loadparm() + net = Net(other_creds, lp, server=self.host) + + # work out the initial account values for this user + username = creds.get_username() + userdn = "cn=%s,cn=users,%s" % (username, self.base_dn) + res = self._check_account(userdn, + badPwdCount=0, + badPasswordTime=("greater", 0), + badPwdCountOnly=True) + badPasswordTime = int(res[0]["badPasswordTime"][0]) + logonCount = int(res[0]["logonCount"][0]) + lastLogon = int(res[0]["lastLogon"][0]) + lastLogonTimestamp = int(res[0]["lastLogonTimestamp"][0]) + + # prove we can change the user password (using the correct password) + new_password = "thatsAcomplPASS2" + net.change_password(newpassword=new_password.encode('utf-8'), + username=username, + oldpassword=creds.get_password()) + creds.set_password(new_password) + + # try entering 'x' many bad passwords in a row to lock the user out + new_password = "thatsAcomplPASS3" + for i in range(lockout_threshold): + badPwdCount = i + 1 + try: + print("Trying bad password, attempt #%u" % badPwdCount) + net.change_password(newpassword=new_password.encode('utf-8'), + username=creds.get_username(), + oldpassword="bad-password") + self.fail("Invalid SAMR change_password accepted") + except NTSTATUSError as e: + enum = ctypes.c_uint32(e[0]).value + self.assertEquals(enum, ntstatus.NT_STATUS_WRONG_PASSWORD) + + # check the status of the account is updated after each bad attempt + account_flags = 0 + lockoutTime = None + if badPwdCount >= lockout_threshold: + account_flags = dsdb.UF_LOCKOUT + lockoutTime = ("greater", badPasswordTime) + + res = self._check_account(userdn, + badPwdCount=badPwdCount, + badPasswordTime=("greater", badPasswordTime), + logonCount=logonCount, + lastLogon=lastLogon, + lastLogonTimestamp=lastLogonTimestamp, + lockoutTime=lockoutTime, + userAccountControl=dsdb.UF_NORMAL_ACCOUNT, + msDSUserAccountControlComputed=account_flags) + badPasswordTime = int(res[0]["badPasswordTime"][0]) + + # the user is now locked out + lockoutTime = int(res[0]["lockoutTime"][0]) + + # check the user remains locked out regardless of whether they use a + # good or a bad password now + for password in (creds.get_password(), "bad-password"): + try: + print("Trying password %s" % password) + net.change_password(newpassword=new_password.encode('utf-8'), + username=creds.get_username(), + oldpassword=password) + self.fail("Invalid SAMR change_password accepted") + except NTSTATUSError as e: + enum = ctypes.c_uint32(e[0]).value + self.assertEquals(enum, ntstatus.NT_STATUS_ACCOUNT_LOCKED_OUT) + + res = self._check_account(userdn, + badPwdCount=lockout_threshold, + badPasswordTime=badPasswordTime, + logonCount=logonCount, + lastLogon=lastLogon, + lastLogonTimestamp=lastLogonTimestamp, + lockoutTime=lockoutTime, + userAccountControl=dsdb.UF_NORMAL_ACCOUNT, + msDSUserAccountControlComputed=dsdb.UF_LOCKOUT) + + # reset the user account lockout + self._reset_samr(res) + + # check bad password counts are reset + res = self._check_account(userdn, + badPwdCount=0, + badPasswordTime=badPasswordTime, + logonCount=logonCount, + lockoutTime=0, + lastLogon=lastLogon, + lastLogonTimestamp=lastLogonTimestamp, + userAccountControl=dsdb.UF_NORMAL_ACCOUNT, + msDSUserAccountControlComputed=0) + + # check we can change the user password successfully now + net.change_password(newpassword=new_password.encode('utf-8'), + username=username, + oldpassword=creds.get_password()) + creds.set_password(new_password) + + def test_samr_change_password(self): + self._test_samr_password_change(self.lockout1ntlm_creds, + other_creds=self.lockout2ntlm_creds) + + # same as above, but use a PSO to enforce the lockout + def test_pso_samr_change_password(self): + self.use_pso_lockout_settings(self.lockout1ntlm_creds) + self._test_samr_password_change(self.lockout1ntlm_creds, + other_creds=self.lockout2ntlm_creds) + + +class PasswordTestsWithSleep(PasswordTests): + def setUp(self): + super(PasswordTestsWithSleep, self).setUp() def _test_unicodePwd_lockout_with_clear_change(self, creds, other_ldb, initial_logoncount_relation=None): @@ -1032,12 +1176,6 @@ unicodePwd:: """ + base64.b64encode(new_utf16).decode('utf8') + """ self.use_pso_lockout_settings(self.lockout1ntlm_creds) self._test_login_lockout(self.lockout1ntlm_creds) - def test_multiple_logon_krb5(self): - self._test_multiple_logon(self.lockout1krb5_creds) - - def test_multiple_logon_ntlm(self): - self._test_multiple_logon(self.lockout1ntlm_creds) - def _testing_add_user(self, creds, lockOutObservationWindow=0): username = creds.get_username() userpass = creds.get_password() @@ -1207,15 +1345,6 @@ userPassword: """ + userpass + """ msDSUserAccountControlComputed=0) return ldb - def _reset_samr(self, res): - - # Now reset the lockout, by removing ACB_AUTOLOCK (which removes the lock, despite being a generated attribute) - samr_user = self._open_samr_user(res) - acb_info = self.samr.QueryUserInfo(samr_user, 16) - acb_info.acct_flags &= ~samr.ACB_AUTOLOCK - self.samr.SetUserInfo(samr_user, 16, acb_info) - self.samr.Close(samr_user) - def test_lockout_observation_window(self): lockout3krb5_creds = self.insta_creds(self.template_creds, username="lockout3krb5", @@ -1242,120 +1371,6 @@ userPassword: """ + userpass + """ self._testing_add_user(lockout4ntlm_creds, lockOutObservationWindow=self.lockout_observation_window) - def _test_samr_password_change(self, creds, other_creds, lockout_threshold=3): - """Tests user lockout by using bad password in SAMR password_change""" - - # create a connection for SAMR using another user's credentials - lp = self.get_loadparm() - net = Net(other_creds, lp, server=self.host) - - # work out the initial account values for this user - username = creds.get_username() - userdn = "cn=%s,cn=users,%s" % (username, self.base_dn) - res = self._check_account(userdn, - badPwdCount=0, - badPasswordTime=("greater", 0), - badPwdCountOnly=True) - badPasswordTime = int(res[0]["badPasswordTime"][0]) - logonCount = int(res[0]["logonCount"][0]) - lastLogon = int(res[0]["lastLogon"][0]) - lastLogonTimestamp = int(res[0]["lastLogonTimestamp"][0]) - - # prove we can change the user password (using the correct password) - new_password = "thatsAcomplPASS2" - net.change_password(newpassword=new_password.encode('utf-8'), - username=username, - oldpassword=creds.get_password()) - creds.set_password(new_password) - - # try entering 'x' many bad passwords in a row to lock the user out - new_password = "thatsAcomplPASS3" - for i in range(lockout_threshold): - badPwdCount = i + 1 - try: - print("Trying bad password, attempt #%u" % badPwdCount) - net.change_password(newpassword=new_password.encode('utf-8'), - username=creds.get_username(), - oldpassword="bad-password") - self.fail("Invalid SAMR change_password accepted") - except NTSTATUSError as e: - enum = ctypes.c_uint32(e[0]).value - self.assertEquals(enum, ntstatus.NT_STATUS_WRONG_PASSWORD) - - # check the status of the account is updated after each bad attempt - account_flags = 0 - lockoutTime = None - if badPwdCount >= lockout_threshold: - account_flags = dsdb.UF_LOCKOUT - lockoutTime = ("greater", badPasswordTime) - - res = self._check_account(userdn, - badPwdCount=badPwdCount, - badPasswordTime=("greater", badPasswordTime), - logonCount=logonCount, - lastLogon=lastLogon, - lastLogonTimestamp=lastLogonTimestamp, - lockoutTime=lockoutTime, - userAccountControl=dsdb.UF_NORMAL_ACCOUNT, - msDSUserAccountControlComputed=account_flags) - badPasswordTime = int(res[0]["badPasswordTime"][0]) - - # the user is now locked out - lockoutTime = int(res[0]["lockoutTime"][0]) - - # check the user remains locked out regardless of whether they use a - # good or a bad password now - for password in (creds.get_password(), "bad-password"): - try: - print("Trying password %s" % password) - net.change_password(newpassword=new_password.encode('utf-8'), - username=creds.get_username(), - oldpassword=password) - self.fail("Invalid SAMR change_password accepted") - except NTSTATUSError as e: - enum = ctypes.c_uint32(e[0]).value - self.assertEquals(enum, ntstatus.NT_STATUS_ACCOUNT_LOCKED_OUT) - - res = self._check_account(userdn, - badPwdCount=lockout_threshold, - badPasswordTime=badPasswordTime, - logonCount=logonCount, - lastLogon=lastLogon, - lastLogonTimestamp=lastLogonTimestamp, - lockoutTime=lockoutTime, - userAccountControl=dsdb.UF_NORMAL_ACCOUNT, - msDSUserAccountControlComputed=dsdb.UF_LOCKOUT) - - # reset the user account lockout - self._reset_samr(res) - - # check bad password counts are reset - res = self._check_account(userdn, - badPwdCount=0, - badPasswordTime=badPasswordTime, - logonCount=logonCount, - lockoutTime=0, - lastLogon=lastLogon, - lastLogonTimestamp=lastLogonTimestamp, - userAccountControl=dsdb.UF_NORMAL_ACCOUNT, - msDSUserAccountControlComputed=0) - - # check we can change the user password successfully now - net.change_password(newpassword=new_password.encode('utf-8'), - username=username, - oldpassword=creds.get_password()) - creds.set_password(new_password) - - def test_samr_change_password(self): - self._test_samr_password_change(self.lockout1ntlm_creds, - other_creds=self.lockout2ntlm_creds) - - # same as above, but use a PSO to enforce the lockout - def test_pso_samr_change_password(self): - self.use_pso_lockout_settings(self.lockout1ntlm_creds) - self._test_samr_password_change(self.lockout1ntlm_creds, - other_creds=self.lockout2ntlm_creds) - host_url = "ldap://%s" % host |