1 from __future__ import print_function
4 from samba.auth import system_session
5 from samba.credentials import Credentials, DONT_USE_KERBEROS, MUST_USE_KERBEROS
6 from ldb import SCOPE_BASE, LdbError
7 from ldb import ERR_CONSTRAINT_VIOLATION
8 from ldb import ERR_INVALID_CREDENTIALS
9 from ldb import Message, MessageElement, Dn
10 from ldb import FLAG_MOD_REPLACE
11 from samba import gensec, dsdb
12 from samba.samdb import SamDB
14 from samba.tests import delete_force
15 from samba.dcerpc import security, samr
16 from samba.ndr import ndr_unpack
17 from samba.tests.password_test import PasswordTestCase
21 class BasePasswordTestCase(PasswordTestCase):
22 def _open_samr_user(self, res):
23 self.assertTrue("objectSid" in res[0])
25 (domain_sid, rid) = ndr_unpack(security.dom_sid, res[0]["objectSid"][0]).split()
26 self.assertEquals(self.domain_sid, domain_sid)
28 return self.samr.OpenUser(self.samr_domain, security.SEC_FLAG_MAXIMUM_ALLOWED, rid)
30 def _check_attribute(self, res, name, value):
32 self.assertTrue(name not in res[0],
33 msg="attr[%s]=%r on dn[%s]" %
34 (name, res[0], res[0].dn))
37 if isinstance(value, tuple):
46 self.assertFalse(name in res[0],
47 msg="attr[%s] not missing on dn[%s]" %
51 self.assertTrue(name in res[0],
52 msg="attr[%s] missing on dn[%s]" %
54 self.assertTrue(len(res[0][name]) == 1,
55 msg="attr[%s]=%r on dn[%s]" %
56 (name, res[0][name], res[0].dn))
59 print("%s = '%s'" % (name, res[0][name][0]))
65 v = int(res[0][name][0])
67 msg = ("attr[%s]=[%s] != [%s] on dn[%s]\n"
68 "(diff %d; actual value is %s than expected)" %
69 (name, v, value, res[0].dn, v - value,
70 ('less' if v < value else 'greater')))
72 self.assertTrue(v == value, msg)
76 v = int(res[0][name][0])
77 self.assertTrue(v > int(value),
78 msg="attr[%s]=[%s] <= [%s] on dn[%s] (diff %d)" %
79 (name, v, int(value), res[0].dn, v - int(value)))
82 v = int(res[0][name][0])
83 self.assertTrue(v < int(value),
84 msg="attr[%s]=[%s] >= [%s] on dn[%s] (diff %d)" %
85 (name, v, int(value), res[0].dn, v - int(value)))
87 self.assertEqual(mode, not mode, "Invalid Mode[%s]" % mode)
89 def _check_account_initial(self, userdn):
90 self._check_account(userdn,
95 lastLogonTimestamp=("absent", None),
97 dsdb.UF_NORMAL_ACCOUNT,
98 msDSUserAccountControlComputed=0)
100 def _check_account(self, dn,
102 badPasswordTime=None,
105 lastLogonTimestamp=None,
107 userAccountControl=None,
108 msDSUserAccountControlComputed=None,
109 effective_bad_password_count=None,
111 badPwdCountOnly=False):
114 print("\033[01;32m %s \033[00m\n" % msg)
120 "lastLogonTimestamp",
123 "userAccountControl",
124 "msDS-User-Account-Control-Computed"
127 # in order to prevent some time resolution problems we sleep for
131 res = self.ldb.search(dn, scope=SCOPE_BASE, attrs=attrs)
132 self.assertTrue(len(res) == 1)
133 self._check_attribute(res, "badPwdCount", badPwdCount)
134 self._check_attribute(res, "lockoutTime", lockoutTime)
135 self._check_attribute(res, "badPasswordTime", badPasswordTime)
136 if not badPwdCountOnly:
137 self._check_attribute(res, "logonCount", logonCount)
138 self._check_attribute(res, "lastLogon", lastLogon)
139 self._check_attribute(res, "lastLogonTimestamp", lastLogonTimestamp)
140 self._check_attribute(res, "userAccountControl", userAccountControl)
141 self._check_attribute(res, "msDS-User-Account-Control-Computed",
142 msDSUserAccountControlComputed)
144 lastLogon = int(res[0]["lastLogon"][0])
145 logonCount = int(res[0]["logonCount"][0])
147 samr_user = self._open_samr_user(res)
148 uinfo3 = self.samr.QueryUserInfo(samr_user, 3)
149 uinfo5 = self.samr.QueryUserInfo(samr_user, 5)
150 uinfo16 = self.samr.QueryUserInfo(samr_user, 16)
151 uinfo21 = self.samr.QueryUserInfo(samr_user, 21)
152 self.samr.Close(samr_user)
154 expected_acb_info = 0
155 if not badPwdCountOnly:
156 if userAccountControl & dsdb.UF_NORMAL_ACCOUNT:
157 expected_acb_info |= samr.ACB_NORMAL
158 if userAccountControl & dsdb.UF_ACCOUNTDISABLE:
159 expected_acb_info |= samr.ACB_DISABLED
160 if userAccountControl & dsdb.UF_PASSWD_NOTREQD:
161 expected_acb_info |= samr.ACB_PWNOTREQ
162 if msDSUserAccountControlComputed & dsdb.UF_LOCKOUT:
163 expected_acb_info |= samr.ACB_AUTOLOCK
164 if msDSUserAccountControlComputed & dsdb.UF_PASSWORD_EXPIRED:
165 expected_acb_info |= samr.ACB_PW_EXPIRED
167 self.assertEquals(uinfo3.acct_flags, expected_acb_info)
168 self.assertEquals(uinfo3.last_logon, lastLogon)
169 self.assertEquals(uinfo3.logon_count, logonCount)
171 expected_bad_password_count = 0
172 if badPwdCount is not None:
173 expected_bad_password_count = badPwdCount
174 if effective_bad_password_count is None:
175 effective_bad_password_count = expected_bad_password_count
177 self.assertEquals(uinfo3.bad_password_count, expected_bad_password_count)
179 if not badPwdCountOnly:
180 self.assertEquals(uinfo5.acct_flags, expected_acb_info)
181 self.assertEquals(uinfo5.bad_password_count, effective_bad_password_count)
182 self.assertEquals(uinfo5.last_logon, lastLogon)
183 self.assertEquals(uinfo5.logon_count, logonCount)
185 self.assertEquals(uinfo16.acct_flags, expected_acb_info)
187 self.assertEquals(uinfo21.acct_flags, expected_acb_info)
188 self.assertEquals(uinfo21.bad_password_count, effective_bad_password_count)
189 self.assertEquals(uinfo21.last_logon, lastLogon)
190 self.assertEquals(uinfo21.logon_count, logonCount)
193 # check LDAP again and make sure the samr.QueryUserInfo
194 # doesn't have any impact.
195 res2 = self.ldb.search(dn, scope=SCOPE_BASE, attrs=attrs)
196 self.assertEquals(res[0], res2[0])
198 # in order to prevent some time resolution problems we sleep for
203 def update_lockout_settings(self, threshold, duration, observation_window):
204 """Updates the global user lockout settings"""
206 m.dn = Dn(self.ldb, self.base_dn)
207 account_lockout_duration_ticks = -int(duration * (1e7))
208 m["lockoutDuration"] = MessageElement(str(account_lockout_duration_ticks),
209 FLAG_MOD_REPLACE, "lockoutDuration")
210 m["lockoutThreshold"] = MessageElement(str(threshold),
211 FLAG_MOD_REPLACE, "lockoutThreshold")
212 lockout_observation_window_ticks = -int(observation_window * (1e7))
213 m["lockOutObservationWindow"] = MessageElement(str(lockout_observation_window_ticks),
214 FLAG_MOD_REPLACE, "lockOutObservationWindow")
217 def _readd_user(self, creds, lockOutObservationWindow=0):
218 username = creds.get_username()
219 userpass = creds.get_password()
220 userdn = "cn=%s,cn=users,%s" % (username, self.base_dn)
222 delete_force(self.ldb, userdn)
225 "objectclass": "user",
226 "sAMAccountName": username})
228 self.addCleanup(delete_force, self.ldb, userdn)
230 # Sets the initial user password with a "special" password change
231 # I think that this internally is a password set operation and it can
232 # only be performed by someone which has password set privileges on the
233 # account (at least in s4 we do handle it like that).
234 self.ldb.modify_ldif("""
235 dn: """ + userdn + """
239 userPassword: """ + userpass + """
241 # Enables the user account
242 self.ldb.enable_account("(sAMAccountName=%s)" % username)
244 use_kerberos = creds.get_kerberos_state()
245 fail_creds = self.insta_creds(self.template_creds,
247 userpass=userpass + "X",
248 kerberos_state=use_kerberos)
249 self._check_account_initial(userdn)
251 # Fail once to get a badPasswordTime
253 ldb = SamDB(url=self.host_url, credentials=fail_creds, lp=self.lp)
255 except LdbError as e:
257 self.assertEquals(num, ERR_INVALID_CREDENTIALS)
259 # Succeed to reset everything to 0
260 ldb = SamDB(url=self.host_url, credentials=creds, lp=self.lp)
264 def assertLoginFailure(self, url, creds, lp, errno=ERR_INVALID_CREDENTIALS):
266 ldb = SamDB(url=url, credentials=creds, lp=lp)
267 self.fail("Login unexpectedly succeeded")
268 except LdbError as e1:
270 if errno is not None:
271 self.assertEquals(num, errno, ("Login failed in the wrong way"
272 "(got err %d, expected %d)" %
276 super(BasePasswordTestCase, self).setUp()
278 self.global_creds.set_gensec_features(self.global_creds.get_gensec_features() |
281 self.template_creds = Credentials()
282 self.template_creds.set_username("testuser")
283 self.template_creds.set_password("thatsAcomplPASS1")
284 self.template_creds.set_domain(self.global_creds.get_domain())
285 self.template_creds.set_realm(self.global_creds.get_realm())
286 self.template_creds.set_workstation(self.global_creds.get_workstation())
287 self.template_creds.set_gensec_features(self.global_creds.get_gensec_features())
288 self.template_creds.set_kerberos_state(self.global_creds.get_kerberos_state())
290 # Gets back the basedn
291 base_dn = self.ldb.domain_dn()
293 # Gets back the configuration basedn
294 configuration_dn = self.ldb.get_config_basedn().get_linearized()
296 res = self.ldb.search(base_dn,
297 scope=SCOPE_BASE, attrs=["lockoutDuration", "lockOutObservationWindow", "lockoutThreshold"])
299 if "lockoutDuration" in res[0]:
300 lockoutDuration = res[0]["lockoutDuration"][0]
304 if "lockoutObservationWindow" in res[0]:
305 lockoutObservationWindow = res[0]["lockoutObservationWindow"][0]
307 lockoutObservationWindow = 0
309 if "lockoutThreshold" in res[0]:
310 lockoutThreshold = res[0]["lockoutThreshold"][0]
314 self.addCleanup(self.ldb.modify_ldif, """
315 dn: """ + base_dn + """
317 replace: lockoutDuration
318 lockoutDuration: """ + str(lockoutDuration) + """
319 replace: lockoutObservationWindow
320 lockoutObservationWindow: """ + str(lockoutObservationWindow) + """
321 replace: lockoutThreshold
322 lockoutThreshold: """ + str(lockoutThreshold) + """
325 self.base_dn = self.ldb.domain_dn()
326 self.account_lockout_duration = 3
327 self.lockout_observation_window = 3
328 self.update_lockout_settings(threshold=3,
329 duration=self.account_lockout_duration,
330 observation_window=self.lockout_observation_window)
332 # update DC to allow password changes for the duration of this test
333 self.allow_password_changes()
335 self.domain_sid = security.dom_sid(self.ldb.get_domain_sid())
336 self.samr = samr.samr("ncacn_ip_tcp:%s[seal]" % self.host, self.lp, self.global_creds)
337 self.samr_handle = self.samr.Connect2(None, security.SEC_FLAG_MAXIMUM_ALLOWED)
338 self.samr_domain = self.samr.OpenDomain(self.samr_handle, security.SEC_FLAG_MAXIMUM_ALLOWED, self.domain_sid)
340 self.addCleanup(self.delete_ldb_connections)
342 # (Re)adds the test user accounts
343 self.lockout1krb5_creds = self.insta_creds(self.template_creds,
344 username="lockout1krb5",
345 userpass="thatsAcomplPASS0",
346 kerberos_state=MUST_USE_KERBEROS)
347 self.lockout1krb5_ldb = self._readd_user(self.lockout1krb5_creds)
348 self.lockout1ntlm_creds = self.insta_creds(self.template_creds,
349 username="lockout1ntlm",
350 userpass="thatsAcomplPASS0",
351 kerberos_state=DONT_USE_KERBEROS)
352 self.lockout1ntlm_ldb = self._readd_user(self.lockout1ntlm_creds)
354 def delete_ldb_connections(self):
355 del self.lockout1krb5_ldb
356 del self.lockout1ntlm_ldb
360 super(BasePasswordTestCase, self).tearDown()
362 def _test_login_lockout(self, creds):
363 username = creds.get_username()
364 userpass = creds.get_password()
365 userdn = "cn=%s,cn=users,%s" % (username, self.base_dn)
367 use_kerberos = creds.get_kerberos_state()
368 # This unlocks by waiting for account_lockout_duration
369 if use_kerberos == MUST_USE_KERBEROS:
370 logoncount_relation = 'greater'
371 lastlogon_relation = 'greater'
372 print("Performs a lockout attempt against LDAP using Kerberos")
374 logoncount_relation = 'equal'
375 lastlogon_relation = 'equal'
376 print("Performs a lockout attempt against LDAP using NTLM")
378 # Change password on a connection as another user
379 res = self._check_account(userdn,
381 badPasswordTime=("greater", 0),
382 logonCount=(logoncount_relation, 0),
383 lastLogon=("greater", 0),
384 lastLogonTimestamp=("greater", 0),
386 dsdb.UF_NORMAL_ACCOUNT,
387 msDSUserAccountControlComputed=0)
388 badPasswordTime = int(res[0]["badPasswordTime"][0])
389 logonCount = int(res[0]["logonCount"][0])
390 lastLogon = int(res[0]["lastLogon"][0])
391 firstLogon = lastLogon
392 lastLogonTimestamp = int(res[0]["lastLogonTimestamp"][0])
394 print(lastLogonTimestamp)
397 self.assertGreater(lastLogon, badPasswordTime)
398 self.assertGreaterEqual(lastLogon, lastLogonTimestamp)
400 # Open a second LDB connection with the user credentials. Use the
401 # command line credentials for informations like the domain, the realm
402 # and the workstation.
403 creds_lockout = self.insta_creds(creds)
406 creds_lockout.set_password("thatsAcomplPASS1x")
408 self.assertLoginFailure(self.host_url, creds_lockout, self.lp)
410 res = self._check_account(userdn,
412 badPasswordTime=("greater", badPasswordTime),
413 logonCount=logonCount,
415 lastLogonTimestamp=lastLogonTimestamp,
417 dsdb.UF_NORMAL_ACCOUNT,
418 msDSUserAccountControlComputed=0,
419 msg='lastlogontimestamp with wrong password')
420 badPasswordTime = int(res[0]["badPasswordTime"][0])
422 # Correct old password
423 creds_lockout.set_password(userpass)
425 ldb_lockout = SamDB(url=self.host_url, credentials=creds_lockout, lp=self.lp)
427 # lastLogonTimestamp should not change
428 # lastLogon increases if badPwdCount is non-zero (!)
429 res = self._check_account(userdn,
431 badPasswordTime=badPasswordTime,
432 logonCount=(logoncount_relation, logonCount),
433 lastLogon=('greater', lastLogon),
434 lastLogonTimestamp=lastLogonTimestamp,
436 dsdb.UF_NORMAL_ACCOUNT,
437 msDSUserAccountControlComputed=0,
438 msg='LLTimestamp is updated to lastlogon')
440 logonCount = int(res[0]["logonCount"][0])
441 lastLogon = int(res[0]["lastLogon"][0])
442 self.assertGreater(lastLogon, badPasswordTime)
443 self.assertGreaterEqual(lastLogon, lastLogonTimestamp)
446 creds_lockout.set_password("thatsAcomplPASS1x")
448 self.assertLoginFailure(self.host_url, creds_lockout, self.lp)
450 res = self._check_account(userdn,
452 badPasswordTime=("greater", badPasswordTime),
453 logonCount=logonCount,
455 lastLogonTimestamp=lastLogonTimestamp,
457 dsdb.UF_NORMAL_ACCOUNT,
458 msDSUserAccountControlComputed=0)
459 badPasswordTime = int(res[0]["badPasswordTime"][0])
462 creds_lockout.set_password("thatsAcomplPASS1x")
465 ldb_lockout = SamDB(url=self.host_url, credentials=creds_lockout, lp=self.lp)
468 except LdbError as e2:
470 self.assertEquals(num, ERR_INVALID_CREDENTIALS)
472 res = self._check_account(userdn,
474 badPasswordTime=("greater", badPasswordTime),
475 logonCount=logonCount,
477 lastLogonTimestamp=lastLogonTimestamp,
479 dsdb.UF_NORMAL_ACCOUNT,
480 msDSUserAccountControlComputed=0)
481 badPasswordTime = int(res[0]["badPasswordTime"][0])
483 print("two failed password change")
486 creds_lockout.set_password("thatsAcomplPASS1x")
489 ldb_lockout = SamDB(url=self.host_url, credentials=creds_lockout, lp=self.lp)
492 except LdbError as e3:
494 self.assertEquals(num, ERR_INVALID_CREDENTIALS)
496 res = self._check_account(userdn,
498 badPasswordTime=("greater", badPasswordTime),
499 logonCount=logonCount,
501 lastLogonTimestamp=lastLogonTimestamp,
502 lockoutTime=("greater", badPasswordTime),
504 dsdb.UF_NORMAL_ACCOUNT,
505 msDSUserAccountControlComputed=dsdb.UF_LOCKOUT)
506 badPasswordTime = int(res[0]["badPasswordTime"][0])
507 lockoutTime = int(res[0]["lockoutTime"][0])
510 creds_lockout.set_password("thatsAcomplPASS1x")
512 ldb_lockout = SamDB(url=self.host_url, credentials=creds_lockout, lp=self.lp)
514 except LdbError as e4:
516 self.assertEquals(num, ERR_INVALID_CREDENTIALS)
518 res = self._check_account(userdn,
520 badPasswordTime=badPasswordTime,
521 logonCount=logonCount,
523 lastLogonTimestamp=lastLogonTimestamp,
524 lockoutTime=lockoutTime,
526 dsdb.UF_NORMAL_ACCOUNT,
527 msDSUserAccountControlComputed=dsdb.UF_LOCKOUT)
530 creds_lockout.set_password("thatsAcomplPASS1x")
532 ldb_lockout = SamDB(url=self.host_url, credentials=creds_lockout, lp=self.lp)
534 except LdbError as e5:
536 self.assertEquals(num, ERR_INVALID_CREDENTIALS)
538 res = self._check_account(userdn,
540 badPasswordTime=badPasswordTime,
541 logonCount=logonCount,
543 lastLogonTimestamp=lastLogonTimestamp,
544 lockoutTime=lockoutTime,
546 dsdb.UF_NORMAL_ACCOUNT,
547 msDSUserAccountControlComputed=dsdb.UF_LOCKOUT)
549 # The correct password, but we are locked out
550 creds_lockout.set_password(userpass)
552 ldb_lockout = SamDB(url=self.host_url, credentials=creds_lockout, lp=self.lp)
554 except LdbError as e6:
556 self.assertEquals(num, ERR_INVALID_CREDENTIALS)
558 res = self._check_account(userdn,
560 badPasswordTime=badPasswordTime,
561 logonCount=logonCount,
563 lastLogonTimestamp=lastLogonTimestamp,
564 lockoutTime=lockoutTime,
566 dsdb.UF_NORMAL_ACCOUNT,
567 msDSUserAccountControlComputed=dsdb.UF_LOCKOUT)
569 # wait for the lockout to end
570 time.sleep(self.account_lockout_duration + 1)
571 print(self.account_lockout_duration + 1)
573 res = self._check_account(userdn,
574 badPwdCount=3, effective_bad_password_count=0,
575 badPasswordTime=badPasswordTime,
576 logonCount=logonCount,
577 lockoutTime=lockoutTime,
579 lastLogonTimestamp=lastLogonTimestamp,
581 dsdb.UF_NORMAL_ACCOUNT,
582 msDSUserAccountControlComputed=0)
584 # The correct password after letting the timeout expire
586 creds_lockout.set_password(userpass)
588 creds_lockout2 = self.insta_creds(creds_lockout)
590 ldb_lockout = SamDB(url=self.host_url, credentials=creds_lockout2, lp=self.lp)
593 res = self._check_account(userdn,
595 badPasswordTime=badPasswordTime,
596 logonCount=(logoncount_relation, logonCount),
597 lastLogon=(lastlogon_relation, lastLogon),
598 lastLogonTimestamp=lastLogonTimestamp,
601 dsdb.UF_NORMAL_ACCOUNT,
602 msDSUserAccountControlComputed=0,
603 msg="lastLogon is way off")
605 logonCount = int(res[0]["logonCount"][0])
606 lastLogon = int(res[0]["lastLogon"][0])
609 creds_lockout.set_password("thatsAcomplPASS1x")
611 ldb_lockout = SamDB(url=self.host_url, credentials=creds_lockout, lp=self.lp)
613 except LdbError as e7:
615 self.assertEquals(num, ERR_INVALID_CREDENTIALS)
617 res = self._check_account(userdn,
619 badPasswordTime=("greater", badPasswordTime),
620 logonCount=logonCount,
623 lastLogonTimestamp=lastLogonTimestamp,
625 dsdb.UF_NORMAL_ACCOUNT,
626 msDSUserAccountControlComputed=0)
627 badPasswordTime = int(res[0]["badPasswordTime"][0])
630 creds_lockout.set_password("thatsAcomplPASS1x")
632 ldb_lockout = SamDB(url=self.host_url, credentials=creds_lockout, lp=self.lp)
634 except LdbError as e8:
636 self.assertEquals(num, ERR_INVALID_CREDENTIALS)
638 res = self._check_account(userdn,
640 badPasswordTime=("greater", badPasswordTime),
641 logonCount=logonCount,
644 lastLogonTimestamp=lastLogonTimestamp,
646 dsdb.UF_NORMAL_ACCOUNT,
647 msDSUserAccountControlComputed=0)
648 badPasswordTime = int(res[0]["badPasswordTime"][0])
650 time.sleep(self.lockout_observation_window + 1)
652 res = self._check_account(userdn,
653 badPwdCount=2, effective_bad_password_count=0,
654 badPasswordTime=badPasswordTime,
655 logonCount=logonCount,
658 lastLogonTimestamp=lastLogonTimestamp,
660 dsdb.UF_NORMAL_ACCOUNT,
661 msDSUserAccountControlComputed=0)
664 creds_lockout.set_password("thatsAcomplPASS1x")
666 ldb_lockout = SamDB(url=self.host_url, credentials=creds_lockout, lp=self.lp)
668 except LdbError as e9:
670 self.assertEquals(num, ERR_INVALID_CREDENTIALS)
672 res = self._check_account(userdn,
674 badPasswordTime=("greater", badPasswordTime),
675 logonCount=logonCount,
678 lastLogonTimestamp=lastLogonTimestamp,
680 dsdb.UF_NORMAL_ACCOUNT,
681 msDSUserAccountControlComputed=0)
682 badPasswordTime = int(res[0]["badPasswordTime"][0])
684 # The correct password without letting the timeout expire
685 creds_lockout.set_password(userpass)
686 ldb_lockout = SamDB(url=self.host_url, credentials=creds_lockout, lp=self.lp)
688 res = self._check_account(userdn,
690 badPasswordTime=badPasswordTime,
691 logonCount=(logoncount_relation, logonCount),
693 lastLogon=("greater", lastLogon),
694 lastLogonTimestamp=lastLogonTimestamp,
696 dsdb.UF_NORMAL_ACCOUNT,
697 msDSUserAccountControlComputed=0)
699 def _test_multiple_logon(self, creds):
700 # Test the happy case in which a user logs on correctly, then
701 # logs on correctly again, so that the bad password and
702 # lockout times are both zero the second time. The lastlogon
703 # time should increase.
705 # Open a second LDB connection with the user credentials. Use the
706 # command line credentials for informations like the domain, the realm
707 # and the workstation.
708 username = creds.get_username()
709 userdn = "cn=%s,cn=users,%s" % (username, self.base_dn)
711 use_kerberos = creds.get_kerberos_state()
712 if use_kerberos == MUST_USE_KERBEROS:
713 print("Testing multiple logon with Kerberos")
714 logoncount_relation = 'greater'
715 lastlogon_relation = 'greater'
717 print("Testing multiple logon with NTLM")
718 logoncount_relation = 'equal'
719 lastlogon_relation = 'equal'
721 SamDB(url=self.host_url, credentials=self.insta_creds(creds), lp=self.lp)
723 res = self._check_account(userdn,
725 badPasswordTime=("greater", 0),
726 logonCount=(logoncount_relation, 0),
727 lastLogon=("greater", 0),
728 lastLogonTimestamp=("greater", 0),
730 dsdb.UF_NORMAL_ACCOUNT,
731 msDSUserAccountControlComputed=0)
732 badPasswordTime = int(res[0]["badPasswordTime"][0])
733 logonCount = int(res[0]["logonCount"][0])
734 lastLogon = int(res[0]["lastLogon"][0])
735 lastLogonTimestamp = int(res[0]["lastLogonTimestamp"][0])
736 firstLogon = lastLogon
737 print("last logon is %d" % lastLogon)
738 self.assertGreater(lastLogon, badPasswordTime)
739 self.assertGreaterEqual(lastLogon, lastLogonTimestamp)
742 SamDB(url=self.host_url, credentials=self.insta_creds(creds), lp=self.lp)
744 res = self._check_account(userdn,
746 badPasswordTime=badPasswordTime,
747 logonCount=(logoncount_relation, logonCount),
748 lastLogon=(lastlogon_relation, lastLogon),
749 lastLogonTimestamp=lastLogonTimestamp,
751 dsdb.UF_NORMAL_ACCOUNT,
752 msDSUserAccountControlComputed=0,
753 msg=("second logon, firstlogon was %s" %
757 lastLogon = int(res[0]["lastLogon"][0])
761 SamDB(url=self.host_url, credentials=self.insta_creds(creds), lp=self.lp)
763 res = self._check_account(userdn,
765 badPasswordTime=badPasswordTime,
766 logonCount=(logoncount_relation, logonCount),
767 lastLogon=(lastlogon_relation, lastLogon),
768 lastLogonTimestamp=lastLogonTimestamp,
770 dsdb.UF_NORMAL_ACCOUNT,
771 msDSUserAccountControlComputed=0)