2 # -*- coding: utf-8 -*-
3 # This tests the password lockout behavior for AD implementations
5 # Copyright Matthias Dieter Wallnoefer 2010
6 # Copyright Andrew Bartlett 2013
7 # Copyright Stefan Metzmacher 2014
15 sys
.path
.insert(0, "bin/python")
18 from samba
.tests
.subunitrun
import TestProgram
, SubunitOptions
20 import samba
.getopt
as options
22 from samba
.auth
import system_session
23 from samba
.credentials
import Credentials
, DONT_USE_KERBEROS
, MUST_USE_KERBEROS
24 from ldb
import SCOPE_BASE
, LdbError
25 from ldb
import ERR_CONSTRAINT_VIOLATION
26 from ldb
import ERR_INVALID_CREDENTIALS
27 from ldb
import Message
, MessageElement
, Dn
28 from ldb
import FLAG_MOD_REPLACE
29 from samba
import gensec
, dsdb
30 from samba
.samdb
import SamDB
32 from samba
.tests
import delete_force
33 from samba
.dcerpc
import security
, samr
34 from samba
.ndr
import ndr_unpack
36 parser
= optparse
.OptionParser("passwords.py [options] <host>")
37 sambaopts
= options
.SambaOptions(parser
)
38 parser
.add_option_group(sambaopts
)
39 parser
.add_option_group(options
.VersionOptions(parser
))
40 # use command line creds if available
41 credopts
= options
.CredentialsOptions(parser
)
42 parser
.add_option_group(credopts
)
43 subunitopts
= SubunitOptions(parser
)
44 parser
.add_option_group(subunitopts
)
45 opts
, args
= parser
.parse_args()
53 lp
= sambaopts
.get_loadparm()
54 creds
= credopts
.get_credentials(lp
)
56 # Force an encrypted connection
57 creds
.set_gensec_features(creds
.get_gensec_features() | gensec
.FEATURE_SEAL
)
63 class PasswordTests(samba
.tests
.TestCase
):
65 def _open_samr_user(self
, res
):
66 self
.assertTrue("objectSid" in res
[0])
68 (domain_sid
, rid
) = ndr_unpack(security
.dom_sid
, res
[0]["objectSid"][0]).split()
69 self
.assertEquals(self
.domain_sid
, domain_sid
)
71 return self
.samr
.OpenUser(self
.samr_domain
, security
.SEC_FLAG_MAXIMUM_ALLOWED
, rid
)
73 def _reset_samr(self
, res
):
75 # Now reset the lockout, by removing ACB_AUTOLOCK (which removes the lock, despite being a generated attribute)
76 samr_user
= self
._open
_samr
_user
(res
)
77 acb_info
= self
.samr
.QueryUserInfo(samr_user
, 16)
78 acb_info
.acct_flags
&= ~samr
.ACB_AUTOLOCK
79 self
.samr
.SetUserInfo(samr_user
, 16, acb_info
)
80 self
.samr
.Close(samr_user
)
82 def _reset_ldap_lockoutTime(self
, res
):
83 self
.ldb
.modify_ldif("""
84 dn: """ + str(res
[0].dn
) + """
90 def _reset_ldap_userAccountControl(self
, res
):
91 self
.assertTrue("userAccountControl" in res
[0])
92 self
.assertTrue("msDS-User-Account-Control-Computed" in res
[0])
94 uac
= int(res
[0]["userAccountControl"][0])
95 uacc
= int(res
[0]["msDS-User-Account-Control-Computed"][0])
98 uac
= uac
& ~dsdb
.UF_LOCKOUT
100 self
.ldb
.modify_ldif("""
101 dn: """ + str(res
[0].dn
) + """
103 replace: userAccountControl
104 userAccountControl: %d
107 def _reset_by_method(self
, res
, method
):
108 if method
is "ldap_userAccountControl":
109 self
._reset
_ldap
_userAccountControl
(res
)
110 elif method
is "ldap_lockoutTime":
111 self
._reset
_ldap
_lockoutTime
(res
)
112 elif method
is "samr":
113 self
._reset
_samr
(res
)
115 self
.assertTrue(False, msg
="Invalid reset method[%s]" % method
)
117 def _check_attribute(self
, res
, name
, value
):
119 self
.assertTrue(name
not in res
[0],
120 msg
="attr[%s]=%r on dn[%s]" %
121 (name
, res
[0], res
[0].dn
))
124 if isinstance(value
, tuple):
125 (mode
, value
) = value
132 self
.assertTrue(name
in res
[0],
133 msg
="attr[%s] missing on dn[%s]" %
135 self
.assertTrue(len(res
[0][name
]) == 1,
136 msg
="attr[%s]=%r on dn[%s]" %
137 (name
, res
[0][name
], res
[0].dn
))
139 if mode
== "present":
142 self
.assertTrue(str(res
[0][name
][0]) == str(value
),
143 msg
="attr[%s]=[%s] != [%s] on dn[%s]" %
144 (name
, str(res
[0][name
][0]), str(value
), res
[0].dn
))
146 if mode
== "greater":
147 v
= int(res
[0][name
][0])
148 self
.assertTrue(v
> int(value
),
149 msg
="attr[%s]=[%s] <= [%s] on dn[%s]" %
150 (name
, v
, int(value
), res
[0].dn
))
153 v
= int(res
[0][name
][0])
154 self
.assertTrue(v
< int(value
),
155 msg
="attr[%s]=[%s] >= [%s] on dn[%s]" %
156 (name
, v
, int(value
), res
[0].dn
))
158 self
.assertEqual(mode
, not mode
, "Invalid Mode[%s]" % mode
)
160 def _check_account(self
, dn
,
162 badPasswordTime
=None,
164 userAccountControl
=None,
165 msDSUserAccountControlComputed
=None,
166 effective_bad_password_count
=None):
173 "userAccountControl",
174 "msDS-User-Account-Control-Computed"
177 # in order to prevent some time resolution problems we sleep for
181 res
= self
.ldb
.search(dn
, scope
=SCOPE_BASE
, attrs
=attrs
)
182 self
.assertTrue(len(res
) == 1)
183 self
._check
_attribute
(res
, "badPwdCount", badPwdCount
)
184 self
._check
_attribute
(res
, "badPasswordTime", badPasswordTime
)
185 self
._check
_attribute
(res
, "lockoutTime", lockoutTime
)
186 self
._check
_attribute
(res
, "userAccountControl", userAccountControl
)
187 self
._check
_attribute
(res
, "msDS-User-Account-Control-Computed",
188 msDSUserAccountControlComputed
)
190 samr_user
= self
._open
_samr
_user
(res
)
191 uinfo3
= self
.samr
.QueryUserInfo(samr_user
, 3)
192 uinfo5
= self
.samr
.QueryUserInfo(samr_user
, 5)
193 uinfo16
= self
.samr
.QueryUserInfo(samr_user
, 16)
194 uinfo21
= self
.samr
.QueryUserInfo(samr_user
, 21)
195 self
.samr
.Close(samr_user
)
197 expected_acb_info
= 0
198 if userAccountControl
& dsdb
.UF_NORMAL_ACCOUNT
:
199 expected_acb_info |
= samr
.ACB_NORMAL
200 if userAccountControl
& dsdb
.UF_ACCOUNTDISABLE
:
201 expected_acb_info |
= samr
.ACB_DISABLED
202 if userAccountControl
& dsdb
.UF_PASSWD_NOTREQD
:
203 expected_acb_info |
= samr
.ACB_PWNOTREQ
204 if msDSUserAccountControlComputed
& dsdb
.UF_LOCKOUT
:
205 expected_acb_info |
= samr
.ACB_AUTOLOCK
206 if msDSUserAccountControlComputed
& dsdb
.UF_PASSWORD_EXPIRED
:
207 expected_acb_info |
= samr
.ACB_PW_EXPIRED
209 expected_bad_password_count
= 0
210 if badPwdCount
is not None:
211 expected_bad_password_count
= badPwdCount
212 if effective_bad_password_count
is None:
213 effective_bad_password_count
= expected_bad_password_count
215 self
.assertEquals(uinfo3
.acct_flags
, expected_acb_info
)
216 self
.assertEquals(uinfo3
.bad_password_count
, expected_bad_password_count
)
218 self
.assertEquals(uinfo5
.acct_flags
, expected_acb_info
)
219 self
.assertEquals(uinfo5
.bad_password_count
, effective_bad_password_count
)
221 self
.assertEquals(uinfo16
.acct_flags
, expected_acb_info
)
223 self
.assertEquals(uinfo21
.acct_flags
, expected_acb_info
)
224 self
.assertEquals(uinfo21
.bad_password_count
, effective_bad_password_count
)
226 # check LDAP again and make sure the samr.QueryUserInfo
227 # doesn't have any impact.
228 res2
= self
.ldb
.search(dn
, scope
=SCOPE_BASE
, attrs
=attrs
)
229 self
.assertEquals(res
[0], res2
[0])
231 # in order to prevent some time resolution problems we sleep for
237 super(PasswordTests
, self
).setUp()
239 self
.ldb
= SamDB(url
=host_url
, session_info
=system_session(lp
), credentials
=creds
, lp
=lp
)
241 # Gets back the basedn
242 base_dn
= self
.ldb
.domain_dn()
244 # Gets back the configuration basedn
245 configuration_dn
= self
.ldb
.get_config_basedn().get_linearized()
247 # Get the old "dSHeuristics" if it was set
248 dsheuristics
= self
.ldb
.get_dsheuristics()
250 # Reset the "dSHeuristics" as they were before
251 self
.addCleanup(self
.ldb
.set_dsheuristics
, dsheuristics
)
253 res
= self
.ldb
.search(base_dn
,
254 scope
=SCOPE_BASE
, attrs
=["lockoutDuration", "lockOutObservationWindow", "lockoutThreshold"])
256 if "lockoutDuration" in res
[0]:
257 lockoutDuration
= res
[0]["lockoutDuration"][0]
261 if "lockoutObservationWindow" in res
[0]:
262 lockoutObservationWindow
= res
[0]["lockoutObservationWindow"][0]
264 lockoutObservationWindow
= 0
266 if "lockoutThreshold" in res
[0]:
267 lockoutThreshold
= res
[0]["lockoutThreshold"][0]
271 self
.addCleanup(self
.ldb
.modify_ldif
, """
272 dn: """ + base_dn
+ """
274 replace: lockoutDuration
275 lockoutDuration: """ + str(lockoutDuration
) + """
276 replace: lockoutObservationWindow
277 lockoutObservationWindow: """ + str(lockoutObservationWindow
) + """
278 replace: lockoutThreshold
279 lockoutThreshold: """ + str(lockoutThreshold
) + """
283 m
.dn
= Dn(self
.ldb
, base_dn
)
285 self
.account_lockout_duration
= 10
286 account_lockout_duration_ticks
= -int(self
.account_lockout_duration
* (1e7
))
288 m
["lockoutDuration"] = MessageElement(str(account_lockout_duration_ticks
),
289 FLAG_MOD_REPLACE
, "lockoutDuration")
291 account_lockout_threshold
= 3
292 m
["lockoutThreshold"] = MessageElement(str(account_lockout_threshold
),
293 FLAG_MOD_REPLACE
, "lockoutThreshold")
295 self
.lockout_observation_window
= 5
296 lockout_observation_window_ticks
= -int(self
.lockout_observation_window
* (1e7
))
298 m
["lockOutObservationWindow"] = MessageElement(str(lockout_observation_window_ticks
),
299 FLAG_MOD_REPLACE
, "lockOutObservationWindow")
303 # Set the "dSHeuristics" to activate the correct "userPassword" behaviour
304 self
.ldb
.set_dsheuristics("000000001")
306 # Get the old "minPwdAge"
307 minPwdAge
= self
.ldb
.get_minPwdAge()
309 # Reset the "minPwdAge" as it was before
310 self
.addCleanup(self
.ldb
.set_minPwdAge
, minPwdAge
)
312 # Set it temporarely to "0"
313 self
.ldb
.set_minPwdAge("0")
315 self
.base_dn
= self
.ldb
.domain_dn()
317 self
.domain_sid
= security
.dom_sid(self
.ldb
.get_domain_sid())
318 self
.samr
= samr
.samr("ncacn_ip_tcp:%s[sign]" % host
, lp
, creds
)
319 self
.samr_handle
= self
.samr
.Connect2(None, security
.SEC_FLAG_MAXIMUM_ALLOWED
)
320 self
.samr_domain
= self
.samr
.OpenDomain(self
.samr_handle
, security
.SEC_FLAG_MAXIMUM_ALLOWED
, self
.domain_sid
)
322 # (Re)adds the test user "testuser" with no password atm
323 delete_force(self
.ldb
, "cn=testuser,cn=users," + self
.base_dn
)
325 "dn": "cn=testuser,cn=users," + self
.base_dn
,
326 "objectclass": "user",
327 "sAMAccountName": "testuser"})
329 res
= self
._check
_account
("cn=testuser,cn=users," + self
.base_dn
,
333 dsdb
.UF_NORMAL_ACCOUNT |
334 dsdb
.UF_ACCOUNTDISABLE |
335 dsdb
.UF_PASSWD_NOTREQD
,
336 msDSUserAccountControlComputed
=
337 dsdb
.UF_PASSWORD_EXPIRED
)
339 # SAMR doesn't have any impact if dsdb.UF_LOCKOUT isn't present.
340 # It doesn't create "lockoutTime" = 0.
341 self
._reset
_samr
(res
)
343 res
= self
._check
_account
("cn=testuser,cn=users," + self
.base_dn
,
347 dsdb
.UF_NORMAL_ACCOUNT |
348 dsdb
.UF_ACCOUNTDISABLE |
349 dsdb
.UF_PASSWD_NOTREQD
,
350 msDSUserAccountControlComputed
=
351 dsdb
.UF_PASSWORD_EXPIRED
)
353 # Tests a password change when we don't have any password yet with a
356 self
.ldb
.modify_ldif("""
357 dn: cn=testuser,cn=users,""" + self
.base_dn
+ """
360 userPassword: noPassword
362 userPassword: thatsAcomplPASS2
365 except LdbError
, (num
, msg
):
366 self
.assertEquals(num
, ERR_CONSTRAINT_VIOLATION
)
367 # Windows (2008 at least) seems to have some small bug here: it
368 # returns "0000056A" on longer (always wrong) previous passwords.
369 self
.assertTrue('00000056' in msg
)
371 res
= self
._check
_account
("cn=testuser,cn=users," + self
.base_dn
,
373 badPasswordTime
=("greater", 0),
375 dsdb
.UF_NORMAL_ACCOUNT |
376 dsdb
.UF_ACCOUNTDISABLE |
377 dsdb
.UF_PASSWD_NOTREQD
,
378 msDSUserAccountControlComputed
=
379 dsdb
.UF_PASSWORD_EXPIRED
)
380 badPasswordTime
= int(res
[0]["badPasswordTime"][0])
382 # Sets the initial user password with a "special" password change
383 # I think that this internally is a password set operation and it can
384 # only be performed by someone which has password set privileges on the
385 # account (at least in s4 we do handle it like that).
386 self
.ldb
.modify_ldif("""
387 dn: cn=testuser,cn=users,""" + self
.base_dn
+ """
391 userPassword: thatsAcomplPASS1
394 res
= self
._check
_account
("cn=testuser,cn=users," + self
.base_dn
,
396 badPasswordTime
=badPasswordTime
,
398 dsdb
.UF_NORMAL_ACCOUNT |
399 dsdb
.UF_ACCOUNTDISABLE |
400 dsdb
.UF_PASSWD_NOTREQD
,
401 msDSUserAccountControlComputed
=0)
403 # Enables the user account
404 self
.ldb
.enable_account("(sAMAccountName=testuser)")
406 res
= self
._check
_account
("cn=testuser,cn=users," + self
.base_dn
,
408 badPasswordTime
=badPasswordTime
,
410 dsdb
.UF_NORMAL_ACCOUNT
,
411 msDSUserAccountControlComputed
=0)
413 # Open a second LDB connection with the user credentials. Use the
414 # command line credentials for informations like the domain, the realm
415 # and the workstation.
416 creds2
= Credentials()
417 creds2
.set_username("testuser")
418 creds2
.set_password("thatsAcomplPASS1")
419 creds2
.set_domain(creds
.get_domain())
420 creds2
.set_realm(creds
.get_realm())
421 creds2
.set_workstation(creds
.get_workstation())
422 creds2
.set_gensec_features(creds2
.get_gensec_features()
423 | gensec
.FEATURE_SEAL
)
425 self
.ldb2
= SamDB(url
=host_url
, credentials
=creds2
, lp
=lp
)
427 res
= self
._check
_account
("cn=testuser,cn=users," + self
.base_dn
,
429 badPasswordTime
=badPasswordTime
,
431 dsdb
.UF_NORMAL_ACCOUNT
,
432 msDSUserAccountControlComputed
=0)
434 # (Re)adds the test user "testuser3" with no password atm
435 delete_force(self
.ldb
, "cn=testuser3,cn=users," + self
.base_dn
)
437 "dn": "cn=testuser3,cn=users," + self
.base_dn
,
438 "objectclass": "user",
439 "sAMAccountName": "testuser3"})
441 res
= self
._check
_account
("cn=testuser3,cn=users," + self
.base_dn
,
445 dsdb
.UF_NORMAL_ACCOUNT |
446 dsdb
.UF_ACCOUNTDISABLE |
447 dsdb
.UF_PASSWD_NOTREQD
,
448 msDSUserAccountControlComputed
=
449 dsdb
.UF_PASSWORD_EXPIRED
)
451 # Tests a password change when we don't have any password yet with a
454 self
.ldb
.modify_ldif("""
455 dn: cn=testuser3,cn=users,""" + self
.base_dn
+ """
458 userPassword: noPassword
460 userPassword: thatsAcomplPASS2
463 except LdbError
, (num
, msg
):
464 self
.assertEquals(num
, ERR_CONSTRAINT_VIOLATION
)
465 # Windows (2008 at least) seems to have some small bug here: it
466 # returns "0000056A" on longer (always wrong) previous passwords.
467 self
.assertTrue('00000056' in msg
)
469 res
= self
._check
_account
("cn=testuser3,cn=users," + self
.base_dn
,
471 badPasswordTime
=("greater", 0),
473 dsdb
.UF_NORMAL_ACCOUNT |
474 dsdb
.UF_ACCOUNTDISABLE |
475 dsdb
.UF_PASSWD_NOTREQD
,
476 msDSUserAccountControlComputed
=
477 dsdb
.UF_PASSWORD_EXPIRED
)
478 badPasswordTime3
= int(res
[0]["badPasswordTime"][0])
480 # Sets the initial user password with a "special" password change
481 # I think that this internally is a password set operation and it can
482 # only be performed by someone which has password set privileges on the
483 # account (at least in s4 we do handle it like that).
484 self
.ldb
.modify_ldif("""
485 dn: cn=testuser3,cn=users,""" + self
.base_dn
+ """
489 userPassword: thatsAcomplPASS1
492 res
= self
._check
_account
("cn=testuser3,cn=users," + self
.base_dn
,
494 badPasswordTime
=badPasswordTime3
,
496 dsdb
.UF_NORMAL_ACCOUNT |
497 dsdb
.UF_ACCOUNTDISABLE |
498 dsdb
.UF_PASSWD_NOTREQD
,
499 msDSUserAccountControlComputed
=0)
501 # Enables the user account
502 self
.ldb
.enable_account("(sAMAccountName=testuser3)")
504 res
= self
._check
_account
("cn=testuser3,cn=users," + self
.base_dn
,
506 badPasswordTime
=badPasswordTime3
,
508 dsdb
.UF_NORMAL_ACCOUNT
,
509 msDSUserAccountControlComputed
=0)
511 # Open a second LDB connection with the user credentials. Use the
512 # command line credentials for informations like the domain, the realm
513 # and the workstation.
514 creds3
= Credentials()
515 creds3
.set_username("testuser3")
516 creds3
.set_password("thatsAcomplPASS1")
517 creds3
.set_domain(creds
.get_domain())
518 creds3
.set_realm(creds
.get_realm())
519 creds3
.set_workstation(creds
.get_workstation())
520 creds3
.set_gensec_features(creds3
.get_gensec_features()
521 | gensec
.FEATURE_SEAL
)
522 self
.ldb3
= SamDB(url
=host_url
, credentials
=creds3
, lp
=lp
)
524 res
= self
._check
_account
("cn=testuser3,cn=users," + self
.base_dn
,
526 badPasswordTime
=badPasswordTime3
,
528 dsdb
.UF_NORMAL_ACCOUNT
,
529 msDSUserAccountControlComputed
=0)
531 def _test_userPassword_lockout_with_clear_change(self
, method
):
532 print "Performs a password cleartext change operation on 'userPassword'"
533 # Notice: This works only against Windows if "dSHeuristics" has been set
536 res
= self
._check
_account
("cn=testuser,cn=users," + self
.base_dn
,
538 badPasswordTime
=("greater", 0),
540 dsdb
.UF_NORMAL_ACCOUNT
,
541 msDSUserAccountControlComputed
=0)
542 badPasswordTime
= int(res
[0]["badPasswordTime"][0])
544 # Change password on a connection as another user
548 self
.ldb3
.modify_ldif("""
549 dn: cn=testuser,cn=users,""" + self
.base_dn
+ """
552 userPassword: thatsAcomplPASS1x
554 userPassword: thatsAcomplPASS2
557 except LdbError
, (num
, msg
):
558 self
.assertTrue('00000056' in msg
)
559 self
.assertEquals(num
, ERR_CONSTRAINT_VIOLATION
)
561 res
= self
._check
_account
("cn=testuser,cn=users," + self
.base_dn
,
563 badPasswordTime
=("greater", badPasswordTime
),
565 dsdb
.UF_NORMAL_ACCOUNT
,
566 msDSUserAccountControlComputed
=0)
567 badPasswordTime
= int(res
[0]["badPasswordTime"][0])
569 # Correct old password
570 self
.ldb3
.modify_ldif("""
571 dn: cn=testuser,cn=users,""" + self
.base_dn
+ """
574 userPassword: thatsAcomplPASS1
576 userPassword: thatsAcomplPASS2
579 res
= self
._check
_account
("cn=testuser,cn=users," + self
.base_dn
,
581 badPasswordTime
=badPasswordTime
,
583 dsdb
.UF_NORMAL_ACCOUNT
,
584 msDSUserAccountControlComputed
=0)
588 self
.ldb3
.modify_ldif("""
589 dn: cn=testuser,cn=users,""" + self
.base_dn
+ """
592 userPassword: thatsAcomplPASS1x
594 userPassword: thatsAcomplPASS2
597 except LdbError
, (num
, msg
):
598 self
.assertTrue('00000056' in msg
)
599 self
.assertEquals(num
, ERR_CONSTRAINT_VIOLATION
)
601 res
= self
._check
_account
("cn=testuser,cn=users," + self
.base_dn
,
603 badPasswordTime
=("greater", badPasswordTime
),
605 dsdb
.UF_NORMAL_ACCOUNT
,
606 msDSUserAccountControlComputed
=0)
607 badPasswordTime
= int(res
[0]["badPasswordTime"][0])
609 print "two failed password change"
613 self
.ldb3
.modify_ldif("""
614 dn: cn=testuser,cn=users,""" + self
.base_dn
+ """
617 userPassword: thatsAcomplPASS1x
619 userPassword: thatsAcomplPASS2
622 except LdbError
, (num
, msg
):
623 self
.assertTrue('00000056' in msg
)
624 self
.assertEquals(num
, ERR_CONSTRAINT_VIOLATION
)
626 res
= self
._check
_account
("cn=testuser,cn=users," + self
.base_dn
,
628 badPasswordTime
=("greater", badPasswordTime
),
629 lockoutTime
=("greater", badPasswordTime
),
631 dsdb
.UF_NORMAL_ACCOUNT
,
632 msDSUserAccountControlComputed
=dsdb
.UF_LOCKOUT
)
633 badPasswordTime
= int(res
[0]["badPasswordTime"][0])
634 lockoutTime
= int(res
[0]["lockoutTime"][0])
638 self
.ldb3
.modify_ldif("""
639 dn: cn=testuser,cn=users,""" + self
.base_dn
+ """
642 userPassword: thatsAcomplPASS1x
644 userPassword: thatsAcomplPASS2
647 except LdbError
, (num
, msg
):
648 self
.assertEquals(num
, ERR_CONSTRAINT_VIOLATION
)
649 self
.assertTrue('00000775' in msg
)
651 res
= self
._check
_account
("cn=testuser,cn=users," + self
.base_dn
,
653 badPasswordTime
=badPasswordTime
,
654 lockoutTime
=lockoutTime
,
656 dsdb
.UF_NORMAL_ACCOUNT
,
657 msDSUserAccountControlComputed
=dsdb
.UF_LOCKOUT
)
661 self
.ldb3
.modify_ldif("""
662 dn: cn=testuser,cn=users,""" + self
.base_dn
+ """
665 userPassword: thatsAcomplPASS1x
667 userPassword: thatsAcomplPASS2
670 except LdbError
, (num
, msg
):
671 self
.assertEquals(num
, ERR_CONSTRAINT_VIOLATION
)
672 self
.assertTrue('00000775' in msg
)
674 res
= self
._check
_account
("cn=testuser,cn=users," + self
.base_dn
,
676 badPasswordTime
=badPasswordTime
,
677 lockoutTime
=lockoutTime
,
679 dsdb
.UF_NORMAL_ACCOUNT
,
680 msDSUserAccountControlComputed
=dsdb
.UF_LOCKOUT
)
683 # Correct old password
684 self
.ldb3
.modify_ldif("""
685 dn: cn=testuser,cn=users,""" + self
.base_dn
+ """
688 userPassword: thatsAcomplPASS2
690 userPassword: thatsAcomplPASS2x
693 except LdbError
, (num
, msg
):
694 self
.assertEquals(num
, ERR_CONSTRAINT_VIOLATION
)
695 self
.assertTrue('0000775' in msg
)
697 res
= self
._check
_account
("cn=testuser,cn=users," + self
.base_dn
,
699 badPasswordTime
=badPasswordTime
,
700 lockoutTime
=lockoutTime
,
702 dsdb
.UF_NORMAL_ACCOUNT
,
703 msDSUserAccountControlComputed
=dsdb
.UF_LOCKOUT
)
705 # Now reset the password, which does NOT change the lockout!
706 self
.ldb
.modify_ldif("""
707 dn: cn=testuser,cn=users,""" + self
.base_dn
+ """
709 replace: userPassword
710 userPassword: thatsAcomplPASS2
713 res
= self
._check
_account
("cn=testuser,cn=users," + self
.base_dn
,
715 badPasswordTime
=badPasswordTime
,
716 lockoutTime
=lockoutTime
,
718 dsdb
.UF_NORMAL_ACCOUNT
,
719 msDSUserAccountControlComputed
=dsdb
.UF_LOCKOUT
)
722 # Correct old password
723 self
.ldb3
.modify_ldif("""
724 dn: cn=testuser,cn=users,""" + self
.base_dn
+ """
727 userPassword: thatsAcomplPASS2
729 userPassword: thatsAcomplPASS2x
732 except LdbError
, (num
, msg
):
733 self
.assertEquals(num
, ERR_CONSTRAINT_VIOLATION
)
734 self
.assertTrue('0000775' in msg
)
736 res
= self
._check
_account
("cn=testuser,cn=users," + self
.base_dn
,
738 badPasswordTime
=badPasswordTime
,
739 lockoutTime
=lockoutTime
,
741 dsdb
.UF_NORMAL_ACCOUNT
,
742 msDSUserAccountControlComputed
=dsdb
.UF_LOCKOUT
)
745 m
.dn
= Dn(self
.ldb
, "cn=testuser,cn=users," + self
.base_dn
)
746 m
["userAccountControl"] = MessageElement(
747 str(dsdb
.UF_LOCKOUT
),
748 FLAG_MOD_REPLACE
, "userAccountControl")
752 # This shows that setting the UF_LOCKOUT flag alone makes no difference
753 res
= self
._check
_account
("cn=testuser,cn=users," + self
.base_dn
,
755 badPasswordTime
=badPasswordTime
,
756 lockoutTime
=lockoutTime
,
758 dsdb
.UF_NORMAL_ACCOUNT
,
759 msDSUserAccountControlComputed
=dsdb
.UF_LOCKOUT
)
761 # This shows that setting the UF_LOCKOUT flag makes no difference
763 # Correct old password
764 self
.ldb3
.modify_ldif("""
765 dn: cn=testuser,cn=users,""" + self
.base_dn
+ """
768 unicodePwd:: """ + base64
.b64encode("\"thatsAcomplPASS2\"".encode('utf-16-le')) + """
770 unicodePwd:: """ + base64
.b64encode("\"thatsAcomplPASS2x\"".encode('utf-16-le')) + """
773 except LdbError
, (num
, msg
):
774 self
.assertEquals(num
, ERR_CONSTRAINT_VIOLATION
)
775 self
.assertTrue('0000775' in msg
)
777 res
= self
._check
_account
("cn=testuser,cn=users," + self
.base_dn
,
779 badPasswordTime
=badPasswordTime
,
780 lockoutTime
=lockoutTime
,
782 dsdb
.UF_NORMAL_ACCOUNT
,
783 msDSUserAccountControlComputed
=dsdb
.UF_LOCKOUT
)
785 self
._reset
_by
_method
(res
, method
)
787 res
= self
._check
_account
("cn=testuser,cn=users," + self
.base_dn
,
789 badPasswordTime
=badPasswordTime
,
792 dsdb
.UF_NORMAL_ACCOUNT
,
793 msDSUserAccountControlComputed
=0)
795 # The correct password after doing the unlock
797 self
.ldb3
.modify_ldif("""
798 dn: cn=testuser,cn=users,""" + self
.base_dn
+ """
801 unicodePwd:: """ + base64
.b64encode("\"thatsAcomplPASS2\"".encode('utf-16-le')) + """
803 unicodePwd:: """ + base64
.b64encode("\"thatsAcomplPASS2x\"".encode('utf-16-le')) + """
806 res
= self
._check
_account
("cn=testuser,cn=users," + self
.base_dn
,
808 badPasswordTime
=badPasswordTime
,
811 dsdb
.UF_NORMAL_ACCOUNT
,
812 msDSUserAccountControlComputed
=0)
816 self
.ldb3
.modify_ldif("""
817 dn: cn=testuser,cn=users,""" + self
.base_dn
+ """
820 userPassword: thatsAcomplPASS1xyz
822 userPassword: thatsAcomplPASS2XYZ
825 except LdbError
, (num
, msg
):
826 self
.assertEquals(num
, ERR_CONSTRAINT_VIOLATION
)
827 self
.assertTrue('00000056' in msg
)
829 res
= self
._check
_account
("cn=testuser,cn=users," + self
.base_dn
,
831 badPasswordTime
=("greater", badPasswordTime
),
834 dsdb
.UF_NORMAL_ACCOUNT
,
835 msDSUserAccountControlComputed
=0)
836 badPasswordTime
= int(res
[0]["badPasswordTime"][0])
840 self
.ldb3
.modify_ldif("""
841 dn: cn=testuser,cn=users,""" + self
.base_dn
+ """
844 userPassword: thatsAcomplPASS1xyz
846 userPassword: thatsAcomplPASS2XYZ
849 except LdbError
, (num
, msg
):
850 self
.assertEquals(num
, ERR_CONSTRAINT_VIOLATION
)
851 self
.assertTrue('00000056' in msg
)
853 res
= self
._check
_account
("cn=testuser,cn=users," + self
.base_dn
,
855 badPasswordTime
=("greater", badPasswordTime
),
858 dsdb
.UF_NORMAL_ACCOUNT
,
859 msDSUserAccountControlComputed
=0)
860 badPasswordTime
= int(res
[0]["badPasswordTime"][0])
862 self
._reset
_ldap
_lockoutTime
(res
)
864 res
= self
._check
_account
("cn=testuser,cn=users," + self
.base_dn
,
866 badPasswordTime
=badPasswordTime
,
869 dsdb
.UF_NORMAL_ACCOUNT
,
870 msDSUserAccountControlComputed
=0)
872 def test_userPassword_lockout_with_clear_change_ldap_userAccountControl(self
):
873 self
._test
_userPassword
_lockout
_with
_clear
_change
("ldap_userAccountControl")
875 def test_userPassword_lockout_with_clear_change_ldap_lockoutTime(self
):
876 self
._test
_userPassword
_lockout
_with
_clear
_change
("ldap_lockoutTime")
878 def test_userPassword_lockout_with_clear_change_samr(self
):
879 self
._test
_userPassword
_lockout
_with
_clear
_change
("samr")
882 def test_unicodePwd_lockout_with_clear_change(self
):
883 print "Performs a password cleartext change operation on 'unicodePwd'"
885 res
= self
._check
_account
("cn=testuser,cn=users," + self
.base_dn
,
887 badPasswordTime
=("greater", 0),
889 dsdb
.UF_NORMAL_ACCOUNT
,
890 msDSUserAccountControlComputed
=0)
891 badPasswordTime
= int(res
[0]["badPasswordTime"][0])
893 # Change password on a connection as another user
897 self
.ldb3
.modify_ldif("""
898 dn: cn=testuser,cn=users,""" + self
.base_dn
+ """
901 unicodePwd:: """ + base64
.b64encode("\"thatsAcomplPASS1x\"".encode('utf-16-le')) + """
903 unicodePwd:: """ + base64
.b64encode("\"thatsAcomplPASS2\"".encode('utf-16-le')) + """
906 except LdbError
, (num
, msg
):
907 self
.assertTrue('00000056' in msg
)
908 self
.assertEquals(num
, ERR_CONSTRAINT_VIOLATION
)
910 res
= self
._check
_account
("cn=testuser,cn=users," + self
.base_dn
,
912 badPasswordTime
=("greater", badPasswordTime
),
914 dsdb
.UF_NORMAL_ACCOUNT
,
915 msDSUserAccountControlComputed
=0)
916 badPasswordTime
= int(res
[0]["badPasswordTime"][0])
918 # Correct old password
919 self
.ldb3
.modify_ldif("""
920 dn: cn=testuser,cn=users,""" + self
.base_dn
+ """
923 unicodePwd:: """ + base64
.b64encode("\"thatsAcomplPASS1\"".encode('utf-16-le')) + """
925 unicodePwd:: """ + base64
.b64encode("\"thatsAcomplPASS2\"".encode('utf-16-le')) + """
928 res
= self
._check
_account
("cn=testuser,cn=users," + self
.base_dn
,
930 badPasswordTime
=badPasswordTime
,
932 dsdb
.UF_NORMAL_ACCOUNT
,
933 msDSUserAccountControlComputed
=0)
937 self
.ldb3
.modify_ldif("""
938 dn: cn=testuser,cn=users,""" + self
.base_dn
+ """
941 unicodePwd:: """ + base64
.b64encode("\"thatsAcomplPASS1\"".encode('utf-16-le')) + """
943 unicodePwd:: """ + base64
.b64encode("\"thatsAcomplPASS2\"".encode('utf-16-le')) + """
946 except LdbError
, (num
, msg
):
947 self
.assertTrue('00000056' in msg
)
948 self
.assertEquals(num
, ERR_CONSTRAINT_VIOLATION
)
950 res
= self
._check
_account
("cn=testuser,cn=users," + self
.base_dn
,
952 badPasswordTime
=("greater", badPasswordTime
),
954 dsdb
.UF_NORMAL_ACCOUNT
,
955 msDSUserAccountControlComputed
=0)
956 badPasswordTime
= int(res
[0]["badPasswordTime"][0])
958 # SAMR doesn't have any impact if dsdb.UF_LOCKOUT isn't present.
959 # It doesn't create "lockoutTime" = 0 and doesn't
960 # reset "badPwdCount" = 0.
961 self
._reset
_samr
(res
)
963 res
= self
._check
_account
("cn=testuser,cn=users," + self
.base_dn
,
965 badPasswordTime
=badPasswordTime
,
967 dsdb
.UF_NORMAL_ACCOUNT
,
968 msDSUserAccountControlComputed
=0)
970 print "two failed password change"
974 self
.ldb3
.modify_ldif("""
975 dn: cn=testuser,cn=users,""" + self
.base_dn
+ """
978 unicodePwd:: """ + base64
.b64encode("\"thatsAcomplPASS1x\"".encode('utf-16-le')) + """
980 unicodePwd:: """ + base64
.b64encode("\"thatsAcomplPASS2\"".encode('utf-16-le')) + """
983 except LdbError
, (num
, msg
):
984 self
.assertTrue('00000056' in msg
)
985 self
.assertEquals(num
, ERR_CONSTRAINT_VIOLATION
)
987 # this is strange, why do we have lockoutTime=badPasswordTime here?
988 res
= self
._check
_account
("cn=testuser,cn=users," + self
.base_dn
,
990 badPasswordTime
=("greater", badPasswordTime
),
991 lockoutTime
=("greater", badPasswordTime
),
993 dsdb
.UF_NORMAL_ACCOUNT
,
994 msDSUserAccountControlComputed
=dsdb
.UF_LOCKOUT
)
995 badPasswordTime
= int(res
[0]["badPasswordTime"][0])
996 lockoutTime
= int(res
[0]["lockoutTime"][0])
1000 self
.ldb3
.modify_ldif("""
1001 dn: cn=testuser,cn=users,""" + self
.base_dn
+ """
1004 unicodePwd:: """ + base64
.b64encode("\"thatsAcomplPASS1x\"".encode('utf-16-le')) + """
1006 unicodePwd:: """ + base64
.b64encode("\"thatsAcomplPASS2\"".encode('utf-16-le')) + """
1009 except LdbError
, (num
, msg
):
1010 self
.assertEquals(num
, ERR_CONSTRAINT_VIOLATION
)
1011 self
.assertTrue('00000775' in msg
)
1013 res
= self
._check
_account
("cn=testuser,cn=users," + self
.base_dn
,
1015 badPasswordTime
=badPasswordTime
,
1016 lockoutTime
=lockoutTime
,
1018 dsdb
.UF_NORMAL_ACCOUNT
,
1019 msDSUserAccountControlComputed
=dsdb
.UF_LOCKOUT
)
1021 # Wrong old password
1023 self
.ldb3
.modify_ldif("""
1024 dn: cn=testuser,cn=users,""" + self
.base_dn
+ """
1027 unicodePwd:: """ + base64
.b64encode("\"thatsAcomplPASS1x\"".encode('utf-16-le')) + """
1029 unicodePwd:: """ + base64
.b64encode("\"thatsAcomplPASS2\"".encode('utf-16-le')) + """
1032 except LdbError
, (num
, msg
):
1033 self
.assertEquals(num
, ERR_CONSTRAINT_VIOLATION
)
1034 self
.assertTrue('00000775' in msg
)
1036 res
= self
._check
_account
("cn=testuser,cn=users," + self
.base_dn
,
1038 badPasswordTime
=badPasswordTime
,
1039 lockoutTime
=lockoutTime
,
1041 dsdb
.UF_NORMAL_ACCOUNT
,
1042 msDSUserAccountControlComputed
=dsdb
.UF_LOCKOUT
)
1045 # Correct old password
1046 self
.ldb3
.modify_ldif("""
1047 dn: cn=testuser,cn=users,""" + self
.base_dn
+ """
1050 unicodePwd:: """ + base64
.b64encode("\"thatsAcomplPASS2\"".encode('utf-16-le')) + """
1052 unicodePwd:: """ + base64
.b64encode("\"thatsAcomplPASS2x\"".encode('utf-16-le')) + """
1055 except LdbError
, (num
, msg
):
1056 self
.assertEquals(num
, ERR_CONSTRAINT_VIOLATION
)
1057 self
.assertTrue('0000775' in msg
)
1059 res
= self
._check
_account
("cn=testuser,cn=users," + self
.base_dn
,
1061 badPasswordTime
=badPasswordTime
,
1062 lockoutTime
=lockoutTime
,
1064 dsdb
.UF_NORMAL_ACCOUNT
,
1065 msDSUserAccountControlComputed
=dsdb
.UF_LOCKOUT
)
1067 # Now reset the lockout, by removing ACB_AUTOLOCK (which removes the lock, despite being a generated attribute)
1068 self
._reset
_samr
(res
);
1070 res
= self
._check
_account
("cn=testuser,cn=users," + self
.base_dn
,
1072 badPasswordTime
=badPasswordTime
,
1075 dsdb
.UF_NORMAL_ACCOUNT
,
1076 msDSUserAccountControlComputed
=0)
1078 # Correct old password
1079 self
.ldb3
.modify_ldif("""
1080 dn: cn=testuser,cn=users,""" + self
.base_dn
+ """
1083 unicodePwd:: """ + base64
.b64encode("\"thatsAcomplPASS2\"".encode('utf-16-le')) + """
1085 unicodePwd:: """ + base64
.b64encode("\"thatsAcomplPASS2x\"".encode('utf-16-le')) + """
1088 res
= self
._check
_account
("cn=testuser,cn=users," + self
.base_dn
,
1090 badPasswordTime
=badPasswordTime
,
1093 dsdb
.UF_NORMAL_ACCOUNT
,
1094 msDSUserAccountControlComputed
=0)
1096 # Wrong old password
1098 self
.ldb3
.modify_ldif("""
1099 dn: cn=testuser,cn=users,""" + self
.base_dn
+ """
1102 unicodePwd:: """ + base64
.b64encode("\"thatsAcomplPASS1x\"".encode('utf-16-le')) + """
1104 unicodePwd:: """ + base64
.b64encode("\"thatsAcomplPASS2\"".encode('utf-16-le')) + """
1107 except LdbError
, (num
, msg
):
1108 self
.assertTrue('00000056' in msg
)
1109 self
.assertEquals(num
, ERR_CONSTRAINT_VIOLATION
)
1111 res
= self
._check
_account
("cn=testuser,cn=users," + self
.base_dn
,
1113 badPasswordTime
=("greater", badPasswordTime
),
1116 dsdb
.UF_NORMAL_ACCOUNT
,
1117 msDSUserAccountControlComputed
=0)
1118 badPasswordTime
= int(res
[0]["badPasswordTime"][0])
1120 # Wrong old password
1122 self
.ldb3
.modify_ldif("""
1123 dn: cn=testuser,cn=users,""" + self
.base_dn
+ """
1126 unicodePwd:: """ + base64
.b64encode("\"thatsAcomplPASS1x\"".encode('utf-16-le')) + """
1128 unicodePwd:: """ + base64
.b64encode("\"thatsAcomplPASS2\"".encode('utf-16-le')) + """
1131 except LdbError
, (num
, msg
):
1132 self
.assertTrue('00000056' in msg
)
1133 self
.assertEquals(num
, ERR_CONSTRAINT_VIOLATION
)
1135 res
= self
._check
_account
("cn=testuser,cn=users," + self
.base_dn
,
1137 badPasswordTime
=("greater", badPasswordTime
),
1140 dsdb
.UF_NORMAL_ACCOUNT
,
1141 msDSUserAccountControlComputed
=0)
1142 badPasswordTime
= int(res
[0]["badPasswordTime"][0])
1144 # SAMR doesn't have any impact if dsdb.UF_LOCKOUT isn't present.
1145 # It doesn't reset "badPwdCount" = 0.
1146 self
._reset
_samr
(res
)
1148 res
= self
._check
_account
("cn=testuser,cn=users," + self
.base_dn
,
1150 badPasswordTime
=badPasswordTime
,
1153 dsdb
.UF_NORMAL_ACCOUNT
,
1154 msDSUserAccountControlComputed
=0)
1156 # Wrong old password
1158 self
.ldb3
.modify_ldif("""
1159 dn: cn=testuser,cn=users,""" + self
.base_dn
+ """
1162 unicodePwd:: """ + base64
.b64encode("\"thatsAcomplPASS1x\"".encode('utf-16-le')) + """
1164 unicodePwd:: """ + base64
.b64encode("\"thatsAcomplPASS2\"".encode('utf-16-le')) + """
1167 except LdbError
, (num
, msg
):
1168 self
.assertTrue('00000056' in msg
)
1169 self
.assertEquals(num
, ERR_CONSTRAINT_VIOLATION
)
1171 res
= self
._check
_account
("cn=testuser,cn=users," + self
.base_dn
,
1173 badPasswordTime
=("greater", badPasswordTime
),
1174 lockoutTime
=("greater", badPasswordTime
),
1176 dsdb
.UF_NORMAL_ACCOUNT
,
1177 msDSUserAccountControlComputed
=dsdb
.UF_LOCKOUT
)
1178 badPasswordTime
= int(res
[0]["badPasswordTime"][0])
1179 lockoutTime
= int(res
[0]["lockoutTime"][0])
1181 time
.sleep(self
.account_lockout_duration
+ 1)
1183 res
= self
._check
_account
("cn=testuser,cn=users," + self
.base_dn
,
1184 badPwdCount
=3, effective_bad_password_count
=0,
1185 badPasswordTime
=badPasswordTime
,
1186 lockoutTime
=lockoutTime
,
1188 dsdb
.UF_NORMAL_ACCOUNT
,
1189 msDSUserAccountControlComputed
=0)
1191 # SAMR doesn't have any impact if dsdb.UF_LOCKOUT isn't present.
1192 # It doesn't reset "lockoutTime" = 0 and doesn't
1193 # reset "badPwdCount" = 0.
1194 self
._reset
_samr
(res
)
1196 res
= self
._check
_account
("cn=testuser,cn=users," + self
.base_dn
,
1197 badPwdCount
=3, effective_bad_password_count
=0,
1198 badPasswordTime
=badPasswordTime
,
1199 lockoutTime
=lockoutTime
,
1201 dsdb
.UF_NORMAL_ACCOUNT
,
1202 msDSUserAccountControlComputed
=0)
1204 def _test_login_lockout(self
, use_kerberos
):
1205 # This unlocks by waiting for account_lockout_duration
1206 print "Performs a lockout attempt against LDAP using NTLM or Kerberos"
1208 # Change password on a connection as another user
1210 res
= self
._check
_account
("cn=testuser,cn=users," + self
.base_dn
,
1212 badPasswordTime
=("greater", 0),
1214 dsdb
.UF_NORMAL_ACCOUNT
,
1215 msDSUserAccountControlComputed
=0)
1216 badPasswordTime
= int(res
[0]["badPasswordTime"][0])
1218 # Open a second LDB connection with the user credentials. Use the
1219 # command line credentials for informations like the domain, the realm
1220 # and the workstation.
1221 creds_lockout
= Credentials()
1222 creds_lockout
.set_username("testuser")
1223 creds_lockout
.set_domain(creds
.get_domain())
1224 creds_lockout
.set_realm(creds
.get_realm())
1225 creds_lockout
.set_workstation(creds
.get_workstation())
1226 creds_lockout
.set_gensec_features(creds_lockout
.get_gensec_features()
1227 | gensec
.FEATURE_SEAL
)
1228 creds_lockout
.set_kerberos_state(use_kerberos
)
1230 # The wrong password
1231 creds_lockout
.set_password("thatsAcomplPASS1x")
1234 ldb_lockout
= SamDB(url
=host_url
, credentials
=creds_lockout
, lp
=lp
)
1236 except LdbError
, (num
, msg
):
1237 self
.assertEquals(num
, ERR_INVALID_CREDENTIALS
)
1239 res
= self
._check
_account
("cn=testuser,cn=users," + self
.base_dn
,
1241 badPasswordTime
=("greater", badPasswordTime
),
1243 dsdb
.UF_NORMAL_ACCOUNT
,
1244 msDSUserAccountControlComputed
=0)
1245 badPasswordTime
= int(res
[0]["badPasswordTime"][0])
1247 # Correct old password
1248 creds_lockout
.set_password("thatsAcomplPASS1")
1250 ldb_lockout
= SamDB(url
=host_url
, credentials
=creds_lockout
, lp
=lp
)
1252 res
= self
._check
_account
("cn=testuser,cn=users," + self
.base_dn
,
1254 badPasswordTime
=badPasswordTime
,
1256 dsdb
.UF_NORMAL_ACCOUNT
,
1257 msDSUserAccountControlComputed
=0)
1259 # The wrong password
1260 creds_lockout
.set_password("thatsAcomplPASS1x")
1263 ldb_lockout
= SamDB(url
=host_url
, credentials
=creds_lockout
, lp
=lp
)
1265 except LdbError
, (num
, msg
):
1266 self
.assertEquals(num
, ERR_INVALID_CREDENTIALS
)
1268 res
= self
._check
_account
("cn=testuser,cn=users," + self
.base_dn
,
1270 badPasswordTime
=("greater", badPasswordTime
),
1272 dsdb
.UF_NORMAL_ACCOUNT
,
1273 msDSUserAccountControlComputed
=0)
1274 badPasswordTime
= int(res
[0]["badPasswordTime"][0])
1276 # The wrong password
1277 creds_lockout
.set_password("thatsAcomplPASS1x")
1280 ldb_lockout
= SamDB(url
=host_url
, credentials
=creds_lockout
, lp
=lp
)
1283 except LdbError
, (num
, msg
):
1284 self
.assertEquals(num
, ERR_INVALID_CREDENTIALS
)
1286 res
= self
._check
_account
("cn=testuser,cn=users," + self
.base_dn
,
1288 badPasswordTime
=("greater", badPasswordTime
),
1290 dsdb
.UF_NORMAL_ACCOUNT
,
1291 msDSUserAccountControlComputed
=0)
1292 badPasswordTime
= int(res
[0]["badPasswordTime"][0])
1294 print "two failed password change"
1296 # The wrong password
1297 creds_lockout
.set_password("thatsAcomplPASS1x")
1300 ldb_lockout
= SamDB(url
=host_url
, credentials
=creds_lockout
, lp
=lp
)
1303 except LdbError
, (num
, msg
):
1304 self
.assertEquals(num
, ERR_INVALID_CREDENTIALS
)
1306 res
= self
._check
_account
("cn=testuser,cn=users," + self
.base_dn
,
1308 badPasswordTime
=("greater", badPasswordTime
),
1309 lockoutTime
=("greater", badPasswordTime
),
1311 dsdb
.UF_NORMAL_ACCOUNT
,
1312 msDSUserAccountControlComputed
=dsdb
.UF_LOCKOUT
)
1313 badPasswordTime
= int(res
[0]["badPasswordTime"][0])
1314 lockoutTime
= int(res
[0]["lockoutTime"][0])
1316 # The wrong password
1317 creds_lockout
.set_password("thatsAcomplPASS1x")
1319 ldb_lockout
= SamDB(url
=host_url
, credentials
=creds_lockout
, lp
=lp
)
1321 except LdbError
, (num
, msg
):
1322 self
.assertEquals(num
, ERR_INVALID_CREDENTIALS
)
1324 res
= self
._check
_account
("cn=testuser,cn=users," + self
.base_dn
,
1326 badPasswordTime
=badPasswordTime
,
1327 lockoutTime
=lockoutTime
,
1329 dsdb
.UF_NORMAL_ACCOUNT
,
1330 msDSUserAccountControlComputed
=dsdb
.UF_LOCKOUT
)
1332 # The wrong password
1333 creds_lockout
.set_password("thatsAcomplPASS1x")
1335 ldb_lockout
= SamDB(url
=host_url
, credentials
=creds_lockout
, lp
=lp
)
1337 except LdbError
, (num
, msg
):
1338 self
.assertEquals(num
, ERR_INVALID_CREDENTIALS
)
1340 res
= self
._check
_account
("cn=testuser,cn=users," + self
.base_dn
,
1342 badPasswordTime
=badPasswordTime
,
1343 lockoutTime
=lockoutTime
,
1345 dsdb
.UF_NORMAL_ACCOUNT
,
1346 msDSUserAccountControlComputed
=dsdb
.UF_LOCKOUT
)
1348 # The correct password
1349 creds_lockout
.set_password("thatsAcomplPASS1")
1351 ldb_lockout
= SamDB(url
=host_url
, credentials
=creds_lockout
, lp
=lp
)
1353 except LdbError
, (num
, msg
):
1354 self
.assertEquals(num
, ERR_INVALID_CREDENTIALS
)
1356 res
= self
._check
_account
("cn=testuser,cn=users," + self
.base_dn
,
1358 badPasswordTime
=badPasswordTime
,
1359 lockoutTime
=lockoutTime
,
1361 dsdb
.UF_NORMAL_ACCOUNT
,
1362 msDSUserAccountControlComputed
=dsdb
.UF_LOCKOUT
)
1364 time
.sleep(self
.account_lockout_duration
+ 1)
1366 res
= self
._check
_account
("cn=testuser,cn=users," + self
.base_dn
,
1367 badPwdCount
=3, effective_bad_password_count
=0,
1368 badPasswordTime
=badPasswordTime
,
1369 lockoutTime
=lockoutTime
,
1371 dsdb
.UF_NORMAL_ACCOUNT
,
1372 msDSUserAccountControlComputed
=0)
1374 # The correct password after letting the timeout expire
1375 creds_lockout
.set_password("thatsAcomplPASS1")
1376 ldb_lockout
= SamDB(url
=host_url
, credentials
=creds_lockout
, lp
=lp
)
1378 res
= self
._check
_account
("cn=testuser,cn=users," + self
.base_dn
,
1380 badPasswordTime
=badPasswordTime
,
1383 dsdb
.UF_NORMAL_ACCOUNT
,
1384 msDSUserAccountControlComputed
=0)
1386 # The wrong password
1387 creds_lockout
.set_password("thatsAcomplPASS1x")
1389 ldb_lockout
= SamDB(url
=host_url
, credentials
=creds_lockout
, lp
=lp
)
1391 except LdbError
, (num
, msg
):
1392 self
.assertEquals(num
, ERR_INVALID_CREDENTIALS
)
1394 res
= self
._check
_account
("cn=testuser,cn=users," + self
.base_dn
,
1396 badPasswordTime
=("greater", badPasswordTime
),
1399 dsdb
.UF_NORMAL_ACCOUNT
,
1400 msDSUserAccountControlComputed
=0)
1401 badPasswordTime
= int(res
[0]["badPasswordTime"][0])
1403 # The wrong password
1404 creds_lockout
.set_password("thatsAcomplPASS1x")
1406 ldb_lockout
= SamDB(url
=host_url
, credentials
=creds_lockout
, lp
=lp
)
1408 except LdbError
, (num
, msg
):
1409 self
.assertEquals(num
, ERR_INVALID_CREDENTIALS
)
1411 res
= self
._check
_account
("cn=testuser,cn=users," + self
.base_dn
,
1413 badPasswordTime
=("greater", badPasswordTime
),
1416 dsdb
.UF_NORMAL_ACCOUNT
,
1417 msDSUserAccountControlComputed
=0)
1418 badPasswordTime
= int(res
[0]["badPasswordTime"][0])
1420 time
.sleep(self
.lockout_observation_window
+ 1)
1422 res
= self
._check
_account
("cn=testuser,cn=users," + self
.base_dn
,
1423 badPwdCount
=2, effective_bad_password_count
=0,
1424 badPasswordTime
=badPasswordTime
,
1427 dsdb
.UF_NORMAL_ACCOUNT
,
1428 msDSUserAccountControlComputed
=0)
1430 # The wrong password
1431 creds_lockout
.set_password("thatsAcomplPASS1x")
1433 ldb_lockout
= SamDB(url
=host_url
, credentials
=creds_lockout
, lp
=lp
)
1435 except LdbError
, (num
, msg
):
1436 self
.assertEquals(num
, ERR_INVALID_CREDENTIALS
)
1438 res
= self
._check
_account
("cn=testuser,cn=users," + self
.base_dn
,
1440 badPasswordTime
=("greater", badPasswordTime
),
1443 dsdb
.UF_NORMAL_ACCOUNT
,
1444 msDSUserAccountControlComputed
=0)
1445 badPasswordTime
= int(res
[0]["badPasswordTime"][0])
1447 # The correct password without letting the timeout expire
1448 creds_lockout
.set_password("thatsAcomplPASS1")
1449 ldb_lockout
= SamDB(url
=host_url
, credentials
=creds_lockout
, lp
=lp
)
1451 res
= self
._check
_account
("cn=testuser,cn=users," + self
.base_dn
,
1453 badPasswordTime
=badPasswordTime
,
1456 dsdb
.UF_NORMAL_ACCOUNT
,
1457 msDSUserAccountControlComputed
=0)
1459 def test_login_lockout_ntlm(self
):
1460 self
._test
_login
_lockout
(DONT_USE_KERBEROS
)
1462 def test_login_lockout_kerberos(self
):
1463 self
._test
_login
_lockout
(MUST_USE_KERBEROS
)
1466 super(PasswordTests
, self
).tearDown()
1467 delete_force(self
.ldb
, "cn=testuser,cn=users," + self
.base_dn
)
1468 delete_force(self
.ldb
, "cn=testuser2,cn=users," + self
.base_dn
)
1469 delete_force(self
.ldb
, "cn=testuser3,cn=users," + self
.base_dn
)
1470 # Close the second LDB connection (with the user credentials)
1473 host_url
= "ldap://%s" % host
1475 TestProgram(module
=__name__
, opts
=subunitopts
)