time.sleep(0.01)
return res
+ def _readd_user(self):
+ # (Re)adds the test user "testuser" with no password atm
+ delete_force(self.ldb, "cn=testuser,cn=users," + self.base_dn)
+ self.ldb.add({
+ "dn": "cn=testuser,cn=users," + self.base_dn,
+ "objectclass": "user",
+ "sAMAccountName": "testuser"})
+
+ res = self._check_account("cn=testuser,cn=users," + self.base_dn,
+ badPwdCount=0,
+ badPasswordTime=0,
+ lastLogon=0,
+ lastLogonTimestamp=('absent', None),
+ userAccountControl=
+ dsdb.UF_NORMAL_ACCOUNT |
+ dsdb.UF_ACCOUNTDISABLE |
+ dsdb.UF_PASSWD_NOTREQD,
+ msDSUserAccountControlComputed=
+ dsdb.UF_PASSWORD_EXPIRED)
+
+ # SAMR doesn't have any impact if dsdb.UF_LOCKOUT isn't present.
+ # It doesn't create "lockoutTime" = 0.
+ self._reset_samr(res)
+
+ res = self._check_account("cn=testuser,cn=users," + self.base_dn,
+ badPwdCount=0,
+ badPasswordTime=0,
+ lastLogon=0,
+ lastLogonTimestamp=('absent', None),
+ userAccountControl=
+ dsdb.UF_NORMAL_ACCOUNT |
+ dsdb.UF_ACCOUNTDISABLE |
+ dsdb.UF_PASSWD_NOTREQD,
+ msDSUserAccountControlComputed=
+ dsdb.UF_PASSWORD_EXPIRED)
+
+ # Tests a password change when we don't have any password yet with a
+ # wrong old password
+ try:
+ self.ldb.modify_ldif("""
+dn: cn=testuser,cn=users,""" + self.base_dn + """
+changetype: modify
+delete: userPassword
+userPassword: noPassword
+add: userPassword
+userPassword: thatsAcomplPASS2
+""")
+ self.fail()
+ except LdbError, (num, msg):
+ self.assertEquals(num, ERR_CONSTRAINT_VIOLATION)
+ # Windows (2008 at least) seems to have some small bug here: it
+ # returns "0000056A" on longer (always wrong) previous passwords.
+ self.assertTrue('00000056' in msg, msg)
+
+ res = self._check_account("cn=testuser,cn=users," + self.base_dn,
+ badPwdCount=1,
+ badPasswordTime=("greater", 0),
+ lastLogon=0,
+ lastLogonTimestamp=('absent', None),
+ userAccountControl=
+ dsdb.UF_NORMAL_ACCOUNT |
+ dsdb.UF_ACCOUNTDISABLE |
+ dsdb.UF_PASSWD_NOTREQD,
+ msDSUserAccountControlComputed=
+ dsdb.UF_PASSWORD_EXPIRED)
+ badPasswordTime = int(res[0]["badPasswordTime"][0])
+
+ # Sets the initial user password with a "special" password change
+ # I think that this internally is a password set operation and it can
+ # only be performed by someone which has password set privileges on the
+ # account (at least in s4 we do handle it like that).
+ self.ldb.modify_ldif("""
+dn: cn=testuser,cn=users,""" + self.base_dn + """
+changetype: modify
+delete: userPassword
+add: userPassword
+userPassword: thatsAcomplPASS1
+""")
+
+ res = self._check_account("cn=testuser,cn=users," + self.base_dn,
+ badPwdCount=1,
+ badPasswordTime=badPasswordTime,
+ lastLogon=0,
+ lastLogonTimestamp=('absent', None),
+ userAccountControl=
+ dsdb.UF_NORMAL_ACCOUNT |
+ dsdb.UF_ACCOUNTDISABLE |
+ dsdb.UF_PASSWD_NOTREQD,
+ msDSUserAccountControlComputed=0)
+
+ # Enables the user account
+ self.ldb.enable_account("(sAMAccountName=testuser)")
+
+ res = self._check_account("cn=testuser,cn=users," + self.base_dn,
+ badPwdCount=1,
+ badPasswordTime=badPasswordTime,
+ lastLogon=0,
+ lastLogonTimestamp=('absent', None),
+ userAccountControl=
+ dsdb.UF_NORMAL_ACCOUNT,
+ msDSUserAccountControlComputed=0)
+
+ # Open a second LDB connection with the user credentials. Use the
+ # command line credentials for informations like the domain, the realm
+ # and the workstation.
+ creds2 = insta_creds()
+
+ self.ldb2 = SamDB(url=host_url, credentials=creds2, lp=lp)
+
+ res = self._check_account("cn=testuser,cn=users," + self.base_dn,
+ badPwdCount=0,
+ badPasswordTime=badPasswordTime,
+ lastLogon=('greater', 0),
+ lastLogonTimestamp=('greater', 0),
+ userAccountControl=
+ dsdb.UF_NORMAL_ACCOUNT,
+ msDSUserAccountControlComputed=0)
+
+ lastLogon = int(res[0]["lastLogon"][0])
+ self.assertGreater(lastLogon, badPasswordTime)
+
def assertLoginFailure(self, url, creds, lp, errno=ERR_INVALID_CREDENTIALS):
try:
ldb = SamDB(url=url, credentials=creds, lp=lp)