2
# -*- coding: utf-8 -*-
3
# This tests the password changes over LDAP for AD implementations
5
# Copyright Matthias Dieter Wallnoefer 2010
7
# Notice: This tests will also work against Windows Server if the connection is
8
# secured enough (SASL with a minimum of 128 Bit encryption) - consider
17
sys.path.insert(0, "bin/python")
19
samba.ensure_external_module("testtools", "testtools")
20
samba.ensure_external_module("subunit", "subunit/python")
22
import samba.getopt as options
24
from samba.auth import system_session
25
from samba.credentials import Credentials
26
from ldb import SCOPE_BASE, LdbError
27
from ldb import ERR_ATTRIBUTE_OR_VALUE_EXISTS
28
from ldb import ERR_UNWILLING_TO_PERFORM, ERR_INSUFFICIENT_ACCESS_RIGHTS
29
from ldb import ERR_NO_SUCH_ATTRIBUTE
30
from ldb import ERR_CONSTRAINT_VIOLATION
31
from ldb import Message, MessageElement, Dn
32
from ldb import FLAG_MOD_ADD, FLAG_MOD_REPLACE, FLAG_MOD_DELETE
33
from samba import gensec
34
from samba.samdb import SamDB
36
from samba.tests import delete_force
37
from subunit.run import SubunitTestRunner
40
parser = optparse.OptionParser("passwords.py [options] <host>")
41
sambaopts = options.SambaOptions(parser)
42
parser.add_option_group(sambaopts)
43
parser.add_option_group(options.VersionOptions(parser))
44
# use command line creds if available
45
credopts = options.CredentialsOptions(parser)
46
parser.add_option_group(credopts)
47
opts, args = parser.parse_args()
55
lp = sambaopts.get_loadparm()
56
creds = credopts.get_credentials(lp)
58
# Force an encrypted connection
59
creds.set_gensec_features(creds.get_gensec_features() | gensec.FEATURE_SEAL)
65
class PasswordTests(samba.tests.TestCase):
68
super(PasswordTests, self).setUp()
70
self.base_dn = ldb.domain_dn()
72
# (Re)adds the test user "testuser" with no password atm
73
delete_force(self.ldb, "cn=testuser,cn=users," + self.base_dn)
75
"dn": "cn=testuser,cn=users," + self.base_dn,
76
"objectclass": "user",
77
"sAMAccountName": "testuser"})
79
# Tests a password change when we don't have any password yet with a
82
self.ldb.modify_ldif("""
83
dn: cn=testuser,cn=users,""" + self.base_dn + """
86
userPassword: noPassword
88
userPassword: thatsAcomplPASS2
91
except LdbError, (num, msg):
92
self.assertEquals(num, ERR_CONSTRAINT_VIOLATION)
93
# Windows (2008 at least) seems to have some small bug here: it
94
# returns "0000056A" on longer (always wrong) previous passwords.
95
self.assertTrue('00000056' in msg)
97
# Sets the initial user password with a "special" password change
98
# I think that this internally is a password set operation and it can
99
# only be performed by someone which has password set privileges on the
100
# account (at least in s4 we do handle it like that).
101
self.ldb.modify_ldif("""
102
dn: cn=testuser,cn=users,""" + self.base_dn + """
106
userPassword: thatsAcomplPASS1
109
# But in the other way around this special syntax doesn't work
111
self.ldb.modify_ldif("""
112
dn: cn=testuser,cn=users,""" + self.base_dn + """
115
userPassword: thatsAcomplPASS1
119
except LdbError, (num, _):
120
self.assertEquals(num, ERR_CONSTRAINT_VIOLATION)
122
# Enables the user account
123
self.ldb.enable_account("(sAMAccountName=testuser)")
125
# Open a second LDB connection with the user credentials. Use the
126
# command line credentials for informations like the domain, the realm
127
# and the workstation.
128
creds2 = Credentials()
129
creds2.set_username("testuser")
130
creds2.set_password("thatsAcomplPASS1")
131
creds2.set_domain(creds.get_domain())
132
creds2.set_realm(creds.get_realm())
133
creds2.set_workstation(creds.get_workstation())
134
creds2.set_gensec_features(creds2.get_gensec_features()
135
| gensec.FEATURE_SEAL)
136
self.ldb2 = SamDB(url=host, credentials=creds2, lp=lp)
138
def test_unicodePwd_hash_set(self):
139
print "Performs a password hash set operation on 'unicodePwd' which should be prevented"
140
# Notice: Direct hash password sets should never work
143
m.dn = Dn(ldb, "cn=testuser,cn=users," + self.base_dn)
144
m["unicodePwd"] = MessageElement("XXXXXXXXXXXXXXXX", FLAG_MOD_REPLACE,
149
except LdbError, (num, _):
150
self.assertEquals(num, ERR_UNWILLING_TO_PERFORM)
152
def test_unicodePwd_hash_change(self):
153
print "Performs a password hash change operation on 'unicodePwd' which should be prevented"
154
# Notice: Direct hash password changes should never work
156
# Hash password changes should never work
158
self.ldb2.modify_ldif("""
159
dn: cn=testuser,cn=users,""" + self.base_dn + """
162
unicodePwd: XXXXXXXXXXXXXXXX
164
unicodePwd: YYYYYYYYYYYYYYYY
167
except LdbError, (num, _):
168
self.assertEquals(num, ERR_CONSTRAINT_VIOLATION)
170
def test_unicodePwd_clear_set(self):
171
print "Performs a password cleartext set operation on 'unicodePwd'"
174
m.dn = Dn(ldb, "cn=testuser,cn=users," + self.base_dn)
175
m["unicodePwd"] = MessageElement("\"thatsAcomplPASS2\"".encode('utf-16-le'),
176
FLAG_MOD_REPLACE, "unicodePwd")
179
def test_unicodePwd_clear_change(self):
180
print "Performs a password cleartext change operation on 'unicodePwd'"
182
self.ldb2.modify_ldif("""
183
dn: cn=testuser,cn=users,""" + self.base_dn + """
186
unicodePwd:: """ + base64.b64encode("\"thatsAcomplPASS1\"".encode('utf-16-le')) + """
188
unicodePwd:: """ + base64.b64encode("\"thatsAcomplPASS2\"".encode('utf-16-le')) + """
193
self.ldb2.modify_ldif("""
194
dn: cn=testuser,cn=users,""" + self.base_dn + """
197
unicodePwd:: """ + base64.b64encode("\"thatsAcomplPASS3\"".encode('utf-16-le')) + """
199
unicodePwd:: """ + base64.b64encode("\"thatsAcomplPASS4\"".encode('utf-16-le')) + """
202
except LdbError, (num, msg):
203
self.assertEquals(num, ERR_CONSTRAINT_VIOLATION)
204
self.assertTrue('00000056' in msg)
206
# A change to the same password again will not work (password history)
208
self.ldb2.modify_ldif("""
209
dn: cn=testuser,cn=users,""" + self.base_dn + """
212
unicodePwd:: """ + base64.b64encode("\"thatsAcomplPASS2\"".encode('utf-16-le')) + """
214
unicodePwd:: """ + base64.b64encode("\"thatsAcomplPASS2\"".encode('utf-16-le')) + """
217
except LdbError, (num, msg):
218
self.assertEquals(num, ERR_CONSTRAINT_VIOLATION)
219
self.assertTrue('0000052D' in msg)
221
def test_dBCSPwd_hash_set(self):
222
print "Performs a password hash set operation on 'dBCSPwd' which should be prevented"
223
# Notice: Direct hash password sets should never work
226
m.dn = Dn(ldb, "cn=testuser,cn=users," + self.base_dn)
227
m["dBCSPwd"] = MessageElement("XXXXXXXXXXXXXXXX", FLAG_MOD_REPLACE,
232
except LdbError, (num, _):
233
self.assertEquals(num, ERR_UNWILLING_TO_PERFORM)
235
def test_dBCSPwd_hash_change(self):
236
print "Performs a password hash change operation on 'dBCSPwd' which should be prevented"
237
# Notice: Direct hash password changes should never work
240
self.ldb2.modify_ldif("""
241
dn: cn=testuser,cn=users,""" + self.base_dn + """
244
dBCSPwd: XXXXXXXXXXXXXXXX
246
dBCSPwd: YYYYYYYYYYYYYYYY
249
except LdbError, (num, _):
250
self.assertEquals(num, ERR_UNWILLING_TO_PERFORM)
252
def test_userPassword_clear_set(self):
253
print "Performs a password cleartext set operation on 'userPassword'"
254
# Notice: This works only against Windows if "dSHeuristics" has been set
258
m.dn = Dn(ldb, "cn=testuser,cn=users," + self.base_dn)
259
m["userPassword"] = MessageElement("thatsAcomplPASS2", FLAG_MOD_REPLACE,
263
def test_userPassword_clear_change(self):
264
print "Performs a password cleartext change operation on 'userPassword'"
265
# Notice: This works only against Windows if "dSHeuristics" has been set
268
self.ldb2.modify_ldif("""
269
dn: cn=testuser,cn=users,""" + self.base_dn + """
272
userPassword: thatsAcomplPASS1
274
userPassword: thatsAcomplPASS2
279
self.ldb2.modify_ldif("""
280
dn: cn=testuser,cn=users,""" + self.base_dn + """
283
userPassword: thatsAcomplPASS3
285
userPassword: thatsAcomplPASS4
288
except LdbError, (num, msg):
289
self.assertEquals(num, ERR_CONSTRAINT_VIOLATION)
290
self.assertTrue('00000056' in msg)
292
# A change to the same password again will not work (password history)
294
self.ldb2.modify_ldif("""
295
dn: cn=testuser,cn=users,""" + self.base_dn + """
298
userPassword: thatsAcomplPASS2
300
userPassword: thatsAcomplPASS2
303
except LdbError, (num, msg):
304
self.assertEquals(num, ERR_CONSTRAINT_VIOLATION)
305
self.assertTrue('0000052D' in msg)
307
def test_clearTextPassword_clear_set(self):
308
print "Performs a password cleartext set operation on 'clearTextPassword'"
309
# Notice: This never works against Windows - only supported by us
313
m.dn = Dn(ldb, "cn=testuser,cn=users," + self.base_dn)
314
m["clearTextPassword"] = MessageElement("thatsAcomplPASS2".encode('utf-16-le'),
315
FLAG_MOD_REPLACE, "clearTextPassword")
317
# this passes against s4
318
except LdbError, (num, msg):
319
# "NO_SUCH_ATTRIBUTE" is returned by Windows -> ignore it
320
if num != ERR_NO_SUCH_ATTRIBUTE:
321
raise LdbError(num, msg)
323
def test_clearTextPassword_clear_change(self):
324
print "Performs a password cleartext change operation on 'clearTextPassword'"
325
# Notice: This never works against Windows - only supported by us
328
self.ldb2.modify_ldif("""
329
dn: cn=testuser,cn=users,""" + self.base_dn + """
331
delete: clearTextPassword
332
clearTextPassword:: """ + base64.b64encode("thatsAcomplPASS1".encode('utf-16-le')) + """
333
add: clearTextPassword
334
clearTextPassword:: """ + base64.b64encode("thatsAcomplPASS2".encode('utf-16-le')) + """
336
# this passes against s4
337
except LdbError, (num, msg):
338
# "NO_SUCH_ATTRIBUTE" is returned by Windows -> ignore it
339
if num != ERR_NO_SUCH_ATTRIBUTE:
340
raise LdbError(num, msg)
344
self.ldb2.modify_ldif("""
345
dn: cn=testuser,cn=users,""" + self.base_dn + """
347
delete: clearTextPassword
348
clearTextPassword:: """ + base64.b64encode("thatsAcomplPASS3".encode('utf-16-le')) + """
349
add: clearTextPassword
350
clearTextPassword:: """ + base64.b64encode("thatsAcomplPASS4".encode('utf-16-le')) + """
353
except LdbError, (num, msg):
354
# "NO_SUCH_ATTRIBUTE" is returned by Windows -> ignore it
355
if num != ERR_NO_SUCH_ATTRIBUTE:
356
self.assertEquals(num, ERR_CONSTRAINT_VIOLATION)
357
self.assertTrue('00000056' in msg)
359
# A change to the same password again will not work (password history)
361
self.ldb2.modify_ldif("""
362
dn: cn=testuser,cn=users,""" + self.base_dn + """
364
delete: clearTextPassword
365
clearTextPassword:: """ + base64.b64encode("thatsAcomplPASS2".encode('utf-16-le')) + """
366
add: clearTextPassword
367
clearTextPassword:: """ + base64.b64encode("thatsAcomplPASS2".encode('utf-16-le')) + """
370
except LdbError, (num, msg):
371
# "NO_SUCH_ATTRIBUTE" is returned by Windows -> ignore it
372
if num != ERR_NO_SUCH_ATTRIBUTE:
373
self.assertEquals(num, ERR_CONSTRAINT_VIOLATION)
374
self.assertTrue('0000052D' in msg)
376
def test_failures(self):
377
print "Performs some failure testing"
381
dn: cn=testuser,cn=users,""" + self.base_dn + """
384
userPassword: thatsAcomplPASS1
387
except LdbError, (num, _):
388
self.assertEquals(num, ERR_CONSTRAINT_VIOLATION)
391
self.ldb2.modify_ldif("""
392
dn: cn=testuser,cn=users,""" + self.base_dn + """
395
userPassword: thatsAcomplPASS1
398
except LdbError, (num, _):
399
self.assertEquals(num, ERR_CONSTRAINT_VIOLATION)
403
dn: cn=testuser,cn=users,""" + self.base_dn + """
408
except LdbError, (num, _):
409
self.assertEquals(num, ERR_CONSTRAINT_VIOLATION)
412
self.ldb2.modify_ldif("""
413
dn: cn=testuser,cn=users,""" + self.base_dn + """
418
except LdbError, (num, _):
419
self.assertEquals(num, ERR_CONSTRAINT_VIOLATION)
423
dn: cn=testuser,cn=users,""" + self.base_dn + """
426
userPassword: thatsAcomplPASS1
429
except LdbError, (num, _):
430
self.assertEquals(num, ERR_UNWILLING_TO_PERFORM)
433
self.ldb2.modify_ldif("""
434
dn: cn=testuser,cn=users,""" + self.base_dn + """
437
userPassword: thatsAcomplPASS1
440
except LdbError, (num, _):
441
self.assertEquals(num, ERR_INSUFFICIENT_ACCESS_RIGHTS)
445
dn: cn=testuser,cn=users,""" + self.base_dn + """
448
userPassword: thatsAcomplPASS1
450
userPassword: thatsAcomplPASS2
451
userPassword: thatsAcomplPASS2
454
except LdbError, (num, _):
455
self.assertEquals(num, ERR_CONSTRAINT_VIOLATION)
458
self.ldb2.modify_ldif("""
459
dn: cn=testuser,cn=users,""" + self.base_dn + """
462
userPassword: thatsAcomplPASS1
464
userPassword: thatsAcomplPASS2
465
userPassword: thatsAcomplPASS2
468
except LdbError, (num, _):
469
self.assertEquals(num, ERR_CONSTRAINT_VIOLATION)
473
dn: cn=testuser,cn=users,""" + self.base_dn + """
476
userPassword: thatsAcomplPASS1
477
userPassword: thatsAcomplPASS1
479
userPassword: thatsAcomplPASS2
482
except LdbError, (num, _):
483
self.assertEquals(num, ERR_CONSTRAINT_VIOLATION)
486
self.ldb2.modify_ldif("""
487
dn: cn=testuser,cn=users,""" + self.base_dn + """
490
userPassword: thatsAcomplPASS1
491
userPassword: thatsAcomplPASS1
493
userPassword: thatsAcomplPASS2
496
except LdbError, (num, _):
497
self.assertEquals(num, ERR_CONSTRAINT_VIOLATION)
501
dn: cn=testuser,cn=users,""" + self.base_dn + """
504
userPassword: thatsAcomplPASS1
506
userPassword: thatsAcomplPASS2
508
userPassword: thatsAcomplPASS2
511
except LdbError, (num, _):
512
self.assertEquals(num, ERR_UNWILLING_TO_PERFORM)
515
self.ldb2.modify_ldif("""
516
dn: cn=testuser,cn=users,""" + self.base_dn + """
519
userPassword: thatsAcomplPASS1
521
userPassword: thatsAcomplPASS2
523
userPassword: thatsAcomplPASS2
526
except LdbError, (num, _):
527
self.assertEquals(num, ERR_INSUFFICIENT_ACCESS_RIGHTS)
531
dn: cn=testuser,cn=users,""" + self.base_dn + """
534
userPassword: thatsAcomplPASS1
536
userPassword: thatsAcomplPASS1
538
userPassword: thatsAcomplPASS2
541
except LdbError, (num, _):
542
self.assertEquals(num, ERR_UNWILLING_TO_PERFORM)
545
self.ldb2.modify_ldif("""
546
dn: cn=testuser,cn=users,""" + self.base_dn + """
549
userPassword: thatsAcomplPASS1
551
userPassword: thatsAcomplPASS1
553
userPassword: thatsAcomplPASS2
556
except LdbError, (num, _):
557
self.assertEquals(num, ERR_INSUFFICIENT_ACCESS_RIGHTS)
561
dn: cn=testuser,cn=users,""" + self.base_dn + """
564
userPassword: thatsAcomplPASS1
566
userPassword: thatsAcomplPASS2
567
replace: userPassword
568
userPassword: thatsAcomplPASS3
571
except LdbError, (num, _):
572
self.assertEquals(num, ERR_UNWILLING_TO_PERFORM)
575
self.ldb2.modify_ldif("""
576
dn: cn=testuser,cn=users,""" + self.base_dn + """
579
userPassword: thatsAcomplPASS1
581
userPassword: thatsAcomplPASS2
582
replace: userPassword
583
userPassword: thatsAcomplPASS3
586
except LdbError, (num, _):
587
self.assertEquals(num, ERR_INSUFFICIENT_ACCESS_RIGHTS)
589
# Reverse order does work
590
self.ldb2.modify_ldif("""
591
dn: cn=testuser,cn=users,""" + self.base_dn + """
594
userPassword: thatsAcomplPASS2
596
userPassword: thatsAcomplPASS1
600
self.ldb2.modify_ldif("""
601
dn: cn=testuser,cn=users,""" + self.base_dn + """
604
userPassword: thatsAcomplPASS2
606
unicodePwd:: """ + base64.b64encode("\"thatsAcomplPASS3\"".encode('utf-16-le')) + """
608
# this passes against s4
609
except LdbError, (num, _):
610
self.assertEquals(num, ERR_ATTRIBUTE_OR_VALUE_EXISTS)
613
self.ldb2.modify_ldif("""
614
dn: cn=testuser,cn=users,""" + self.base_dn + """
617
unicodePwd:: """ + base64.b64encode("\"thatsAcomplPASS3\"".encode('utf-16-le')) + """
619
userPassword: thatsAcomplPASS4
621
# this passes against s4
622
except LdbError, (num, _):
623
self.assertEquals(num, ERR_NO_SUCH_ATTRIBUTE)
625
# Several password changes at once are allowed
627
dn: cn=testuser,cn=users,""" + self.base_dn + """
629
replace: userPassword
630
userPassword: thatsAcomplPASS1
631
userPassword: thatsAcomplPASS2
634
# Several password changes at once are allowed
636
dn: cn=testuser,cn=users,""" + self.base_dn + """
638
replace: userPassword
639
userPassword: thatsAcomplPASS1
640
userPassword: thatsAcomplPASS2
641
replace: userPassword
642
userPassword: thatsAcomplPASS3
643
replace: userPassword
644
userPassword: thatsAcomplPASS4
647
# This surprisingly should work
648
delete_force(self.ldb, "cn=testuser2,cn=users," + self.base_dn)
650
"dn": "cn=testuser2,cn=users," + self.base_dn,
651
"objectclass": "user",
652
"userPassword": ["thatsAcomplPASS1", "thatsAcomplPASS2"] })
654
# This surprisingly should work
655
delete_force(self.ldb, "cn=testuser2,cn=users," + self.base_dn)
657
"dn": "cn=testuser2,cn=users," + self.base_dn,
658
"objectclass": "user",
659
"userPassword": ["thatsAcomplPASS1", "thatsAcomplPASS1"] })
661
def test_empty_passwords(self):
662
print "Performs some empty passwords testing"
666
"dn": "cn=testuser2,cn=users," + self.base_dn,
667
"objectclass": "user",
670
except LdbError, (num, _):
671
self.assertEquals(num, ERR_CONSTRAINT_VIOLATION)
675
"dn": "cn=testuser2,cn=users," + self.base_dn,
676
"objectclass": "user",
679
except LdbError, (num, _):
680
self.assertEquals(num, ERR_CONSTRAINT_VIOLATION)
684
"dn": "cn=testuser2,cn=users," + self.base_dn,
685
"objectclass": "user",
686
"userPassword": [] })
688
except LdbError, (num, _):
689
self.assertEquals(num, ERR_CONSTRAINT_VIOLATION)
693
"dn": "cn=testuser2,cn=users," + self.base_dn,
694
"objectclass": "user",
695
"clearTextPassword": [] })
697
except LdbError, (num, _):
698
self.assertTrue(num == ERR_CONSTRAINT_VIOLATION or
699
num == ERR_NO_SUCH_ATTRIBUTE) # for Windows
701
delete_force(self.ldb, "cn=testuser2,cn=users," + self.base_dn)
704
m.dn = Dn(ldb, "cn=testuser,cn=users," + self.base_dn)
705
m["unicodePwd"] = MessageElement([], FLAG_MOD_ADD, "unicodePwd")
709
except LdbError, (num, _):
710
self.assertEquals(num, ERR_CONSTRAINT_VIOLATION)
713
m.dn = Dn(ldb, "cn=testuser,cn=users," + self.base_dn)
714
m["dBCSPwd"] = MessageElement([], FLAG_MOD_ADD, "dBCSPwd")
718
except LdbError, (num, _):
719
self.assertEquals(num, ERR_CONSTRAINT_VIOLATION)
722
m.dn = Dn(ldb, "cn=testuser,cn=users," + self.base_dn)
723
m["userPassword"] = MessageElement([], FLAG_MOD_ADD, "userPassword")
727
except LdbError, (num, _):
728
self.assertEquals(num, ERR_CONSTRAINT_VIOLATION)
731
m.dn = Dn(ldb, "cn=testuser,cn=users," + self.base_dn)
732
m["clearTextPassword"] = MessageElement([], FLAG_MOD_ADD, "clearTextPassword")
736
except LdbError, (num, _):
737
self.assertTrue(num == ERR_CONSTRAINT_VIOLATION or
738
num == ERR_NO_SUCH_ATTRIBUTE) # for Windows
741
m.dn = Dn(ldb, "cn=testuser,cn=users," + self.base_dn)
742
m["unicodePwd"] = MessageElement([], FLAG_MOD_REPLACE, "unicodePwd")
746
except LdbError, (num, _):
747
self.assertEquals(num, ERR_UNWILLING_TO_PERFORM)
750
m.dn = Dn(ldb, "cn=testuser,cn=users," + self.base_dn)
751
m["dBCSPwd"] = MessageElement([], FLAG_MOD_REPLACE, "dBCSPwd")
755
except LdbError, (num, _):
756
self.assertEquals(num, ERR_UNWILLING_TO_PERFORM)
759
m.dn = Dn(ldb, "cn=testuser,cn=users," + self.base_dn)
760
m["userPassword"] = MessageElement([], FLAG_MOD_REPLACE, "userPassword")
764
except LdbError, (num, _):
765
self.assertEquals(num, ERR_UNWILLING_TO_PERFORM)
768
m.dn = Dn(ldb, "cn=testuser,cn=users," + self.base_dn)
769
m["clearTextPassword"] = MessageElement([], FLAG_MOD_REPLACE, "clearTextPassword")
773
except LdbError, (num, _):
774
self.assertTrue(num == ERR_UNWILLING_TO_PERFORM or
775
num == ERR_NO_SUCH_ATTRIBUTE) # for Windows
778
m.dn = Dn(ldb, "cn=testuser,cn=users," + self.base_dn)
779
m["unicodePwd"] = MessageElement([], FLAG_MOD_DELETE, "unicodePwd")
783
except LdbError, (num, _):
784
self.assertEquals(num, ERR_UNWILLING_TO_PERFORM)
787
m.dn = Dn(ldb, "cn=testuser,cn=users," + self.base_dn)
788
m["dBCSPwd"] = MessageElement([], FLAG_MOD_DELETE, "dBCSPwd")
792
except LdbError, (num, _):
793
self.assertEquals(num, ERR_UNWILLING_TO_PERFORM)
796
m.dn = Dn(ldb, "cn=testuser,cn=users," + self.base_dn)
797
m["userPassword"] = MessageElement([], FLAG_MOD_DELETE, "userPassword")
801
except LdbError, (num, _):
802
self.assertEquals(num, ERR_CONSTRAINT_VIOLATION)
805
m.dn = Dn(ldb, "cn=testuser,cn=users," + self.base_dn)
806
m["clearTextPassword"] = MessageElement([], FLAG_MOD_DELETE, "clearTextPassword")
810
except LdbError, (num, _):
811
self.assertTrue(num == ERR_CONSTRAINT_VIOLATION or
812
num == ERR_NO_SUCH_ATTRIBUTE) # for Windows
814
def test_plain_userPassword(self):
815
print "Performs testing about the standard 'userPassword' behaviour"
817
# Delete the "dSHeuristics"
818
ldb.set_dsheuristics(None)
820
time.sleep(1) # This switching time is strictly needed!
823
m.dn = Dn(ldb, "cn=testuser,cn=users," + self.base_dn)
824
m["userPassword"] = MessageElement("myPassword", FLAG_MOD_ADD,
828
res = ldb.search("cn=testuser,cn=users," + self.base_dn,
829
scope=SCOPE_BASE, attrs=["userPassword"])
830
self.assertTrue(len(res) == 1)
831
self.assertTrue("userPassword" in res[0])
832
self.assertEquals(res[0]["userPassword"][0], "myPassword")
835
m.dn = Dn(ldb, "cn=testuser,cn=users," + self.base_dn)
836
m["userPassword"] = MessageElement("myPassword2", FLAG_MOD_REPLACE,
840
res = ldb.search("cn=testuser,cn=users," + self.base_dn,
841
scope=SCOPE_BASE, attrs=["userPassword"])
842
self.assertTrue(len(res) == 1)
843
self.assertTrue("userPassword" in res[0])
844
self.assertEquals(res[0]["userPassword"][0], "myPassword2")
847
m.dn = Dn(ldb, "cn=testuser,cn=users," + self.base_dn)
848
m["userPassword"] = MessageElement([], FLAG_MOD_DELETE,
852
res = ldb.search("cn=testuser,cn=users," + self.base_dn,
853
scope=SCOPE_BASE, attrs=["userPassword"])
854
self.assertTrue(len(res) == 1)
855
self.assertFalse("userPassword" in res[0])
857
# Set the test "dSHeuristics" to deactivate "userPassword" pwd changes
858
ldb.set_dsheuristics("000000000")
861
m.dn = Dn(ldb, "cn=testuser,cn=users," + self.base_dn)
862
m["userPassword"] = MessageElement("myPassword3", FLAG_MOD_REPLACE,
866
res = ldb.search("cn=testuser,cn=users," + self.base_dn,
867
scope=SCOPE_BASE, attrs=["userPassword"])
868
self.assertTrue(len(res) == 1)
869
self.assertTrue("userPassword" in res[0])
870
self.assertEquals(res[0]["userPassword"][0], "myPassword3")
872
# Set the test "dSHeuristics" to deactivate "userPassword" pwd changes
873
ldb.set_dsheuristics("000000002")
876
m.dn = Dn(ldb, "cn=testuser,cn=users," + self.base_dn)
877
m["userPassword"] = MessageElement("myPassword4", FLAG_MOD_REPLACE,
881
res = ldb.search("cn=testuser,cn=users," + self.base_dn,
882
scope=SCOPE_BASE, attrs=["userPassword"])
883
self.assertTrue(len(res) == 1)
884
self.assertTrue("userPassword" in res[0])
885
self.assertEquals(res[0]["userPassword"][0], "myPassword4")
887
# Reset the test "dSHeuristics" (reactivate "userPassword" pwd changes)
888
ldb.set_dsheuristics("000000001")
890
def test_zero_length(self):
891
# Get the old "minPwdLength"
892
minPwdLength = ldb.get_minPwdLength()
893
# Set it temporarely to "0"
894
ldb.set_minPwdLength("0")
896
# Get the old "pwdProperties"
897
pwdProperties = ldb.get_pwdProperties()
898
# Set them temporarely to "0" (to deactivate eventually the complexity)
899
ldb.set_pwdProperties("0")
901
ldb.setpassword("(sAMAccountName=testuser)", "")
903
# Reset the "pwdProperties" as they were before
904
ldb.set_pwdProperties(pwdProperties)
906
# Reset the "minPwdLength" as it was before
907
ldb.set_minPwdLength(minPwdLength)
910
super(PasswordTests, self).tearDown()
911
delete_force(self.ldb, "cn=testuser,cn=users," + self.base_dn)
912
delete_force(self.ldb, "cn=testuser2,cn=users," + self.base_dn)
913
# Close the second LDB connection (with the user credentials)
916
if not "://" in host:
917
if os.path.isfile(host):
918
host = "tdb://%s" % host
920
host = "ldap://%s" % host
922
ldb = SamDB(url=host, session_info=system_session(lp), credentials=creds, lp=lp)
924
# Gets back the basedn
925
base_dn = ldb.domain_dn()
927
# Gets back the configuration basedn
928
configuration_dn = ldb.get_config_basedn().get_linearized()
930
# Get the old "dSHeuristics" if it was set
931
dsheuristics = ldb.get_dsheuristics()
933
# Set the "dSHeuristics" to activate the correct "userPassword" behaviour
934
ldb.set_dsheuristics("000000001")
936
# Get the old "minPwdAge"
937
minPwdAge = ldb.get_minPwdAge()
939
# Set it temporarely to "0"
940
ldb.set_minPwdAge("0")
942
runner = SubunitTestRunner()
944
if not runner.run(unittest.makeSuite(PasswordTests)).wasSuccessful():
947
# Reset the "dSHeuristics" as they were before
948
ldb.set_dsheuristics(dsheuristics)
950
# Reset the "minPwdAge" as it was before
951
ldb.set_minPwdAge(minPwdAge)