489c0176504f2b425b174c0c66a9db593efbeedb
[nivanova/samba-autobuild/.git] / source4 / dsdb / tests / python / ldap.py
1 #!/usr/bin/env python
2 # -*- coding: utf-8 -*-
3 # This is a port of the original in testprogs/ejs/ldap.js
4
5 import optparse
6 import sys
7 import time
8 import base64
9 import os
10
11 sys.path.insert(0, "bin/python")
12 import samba
13 samba.ensure_external_module("testtools", "testtools")
14 samba.ensure_external_module("subunit", "subunit/python")
15
16 import samba.getopt as options
17
18 from samba.auth import system_session
19 from ldb import SCOPE_SUBTREE, SCOPE_ONELEVEL, SCOPE_BASE, LdbError
20 from ldb import ERR_NO_SUCH_OBJECT, ERR_ATTRIBUTE_OR_VALUE_EXISTS
21 from ldb import ERR_ENTRY_ALREADY_EXISTS, ERR_UNWILLING_TO_PERFORM
22 from ldb import ERR_NOT_ALLOWED_ON_NON_LEAF, ERR_OTHER, ERR_INVALID_DN_SYNTAX
23 from ldb import ERR_NO_SUCH_ATTRIBUTE, ERR_INVALID_ATTRIBUTE_SYNTAX
24 from ldb import ERR_OBJECT_CLASS_VIOLATION, ERR_NOT_ALLOWED_ON_RDN
25 from ldb import ERR_NAMING_VIOLATION, ERR_CONSTRAINT_VIOLATION
26 from ldb import Message, MessageElement, Dn
27 from ldb import FLAG_MOD_ADD, FLAG_MOD_REPLACE, FLAG_MOD_DELETE
28 from ldb import timestring
29 from samba import Ldb
30 from samba.samdb import SamDB
31 from samba.dsdb import (UF_NORMAL_ACCOUNT,
32     UF_WORKSTATION_TRUST_ACCOUNT,
33     UF_PASSWD_NOTREQD, UF_ACCOUNTDISABLE, ATYPE_NORMAL_ACCOUNT,
34     ATYPE_WORKSTATION_TRUST, SYSTEM_FLAG_DOMAIN_DISALLOW_MOVE,
35     SYSTEM_FLAG_CONFIG_ALLOW_RENAME, SYSTEM_FLAG_CONFIG_ALLOW_MOVE,
36     SYSTEM_FLAG_CONFIG_ALLOW_LIMITED_MOVE)
37
38 from subunit.run import SubunitTestRunner
39 import unittest
40
41 from samba.ndr import ndr_pack, ndr_unpack
42 from samba.dcerpc import security, lsa
43 from samba.tests import delete_force
44
45 parser = optparse.OptionParser("ldap.py [options] <host>")
46 sambaopts = options.SambaOptions(parser)
47 parser.add_option_group(sambaopts)
48 parser.add_option_group(options.VersionOptions(parser))
49 # use command line creds if available
50 credopts = options.CredentialsOptions(parser)
51 parser.add_option_group(credopts)
52 opts, args = parser.parse_args()
53
54 if len(args) < 1:
55     parser.print_usage()
56     sys.exit(1)
57
58 host = args[0]
59
60 lp = sambaopts.get_loadparm()
61 creds = credopts.get_credentials(lp)
62
63 class BasicTests(unittest.TestCase):
64
65     def setUp(self):
66         super(BasicTests, self).setUp()
67         self.ldb = ldb
68         self.gc_ldb = gc_ldb
69         self.base_dn = ldb.domain_dn()
70         self.configuration_dn = ldb.get_config_basedn().get_linearized()
71         self.schema_dn = ldb.get_schema_basedn().get_linearized()
72         self.domain_sid = security.dom_sid(ldb.get_domain_sid())
73
74         print "baseDN: %s\n" % self.base_dn
75
76         delete_force(self.ldb, "cn=posixuser,cn=users," + self.base_dn)
77         delete_force(self.ldb, "cn=ldaptestuser,cn=users," + self.base_dn)
78         delete_force(self.ldb, "cn=ldaptestuser2,cn=users," + self.base_dn)
79         delete_force(self.ldb, "cn=ldaptestuser3,cn=users," + self.base_dn)
80         delete_force(self.ldb, "cn=ldaptestuser4,cn=ldaptestcontainer," + self.base_dn)
81         delete_force(self.ldb, "cn=ldaptestuser4,cn=ldaptestcontainer2," + self.base_dn)
82         delete_force(self.ldb, "cn=ldaptestuser5,cn=users," + self.base_dn)
83         delete_force(self.ldb, "cn=ldaptestgroup,cn=users," + self.base_dn)
84         delete_force(self.ldb, "cn=ldaptestgroup2,cn=users," + self.base_dn)
85         delete_force(self.ldb, "cn=ldaptestcomputer,cn=computers," + self.base_dn)
86         delete_force(self.ldb, "cn=ldaptest2computer,cn=computers," + self.base_dn)
87         delete_force(self.ldb, "cn=ldaptestcomputer3,cn=computers," + self.base_dn)
88         delete_force(self.ldb, "cn=ldaptestutf8user èùéìòà,cn=users," + self.base_dn)
89         delete_force(self.ldb, "cn=ldaptestutf8user2  èùéìòà,cn=users," + self.base_dn)
90         delete_force(self.ldb, "cn=ldaptestcontainer," + self.base_dn)
91         delete_force(self.ldb, "cn=ldaptestcontainer2," + self.base_dn)
92         delete_force(self.ldb, "cn=parentguidtest,cn=users," + self.base_dn)
93         delete_force(self.ldb, "cn=parentguidtest,cn=testotherusers," + self.base_dn)
94         delete_force(self.ldb, "cn=testotherusers," + self.base_dn)
95         delete_force(self.ldb, "cn=ldaptestobject," + self.base_dn)
96         delete_force(self.ldb, "description=xyz,cn=users," + self.base_dn)
97         delete_force(self.ldb, "ou=testou,cn=users," + self.base_dn)
98         delete_force(self.ldb, "cn=Test Secret,cn=system," + self.base_dn)
99
100     def test_objectclasses(self):
101         """Test objectClass behaviour"""
102         print "Test objectClass behaviour"""
103
104         # We cannot create LSA-specific objects (oc "secret" or "trustedDomain")
105         try:
106             self.ldb.add({
107                 "dn": "cn=Test Secret,cn=system," + self.base_dn,
108                 "objectClass": "secret" })
109             self.fail()
110         except LdbError, (num, _):
111             self.assertEquals(num, ERR_UNWILLING_TO_PERFORM)
112
113         # Invalid objectclass specified
114         try:
115             self.ldb.add({
116                 "dn": "cn=ldaptestuser,cn=users," + self.base_dn,
117                 "objectClass": [] })
118             self.fail()
119         except LdbError, (num, _):
120             self.assertEquals(num, ERR_CONSTRAINT_VIOLATION)
121
122         # Invalid objectclass specified
123         try:
124             self.ldb.add({
125                 "dn": "cn=ldaptestuser,cn=users," + self.base_dn,
126                 "objectClass": "X" })
127             self.fail()
128         except LdbError, (num, _):
129             self.assertEquals(num, ERR_NO_SUCH_ATTRIBUTE)
130
131         # Invalid objectCategory specified
132         try:
133             self.ldb.add({
134                 "dn": "cn=ldaptestuser,cn=users," + self.base_dn,
135                 "objectClass": "person",
136                 "objectCategory": self.base_dn })
137             self.fail()
138         except LdbError, (num, _):
139             self.assertEquals(num, ERR_OBJECT_CLASS_VIOLATION)
140
141         # Multi-valued "systemFlags"
142         try:
143             self.ldb.add({
144                 "dn": "cn=ldaptestuser,cn=users," + self.base_dn,
145                 "objectClass": "person",
146                 "systemFlags": ["0", str(SYSTEM_FLAG_DOMAIN_DISALLOW_MOVE)] })
147             self.fail()
148         except LdbError, (num, _):
149             self.assertEquals(num, ERR_CONSTRAINT_VIOLATION)
150
151         # We cannot instanciate from an abstract objectclass
152         try:
153             self.ldb.add({
154                 "dn": "cn=ldaptestuser,cn=users," + self.base_dn,
155                 "objectClass": "connectionPoint" })
156             self.fail()
157         except LdbError, (num, _):
158             self.assertEquals(num, ERR_UNWILLING_TO_PERFORM)
159
160         # Test allowed system flags
161         self.ldb.add({
162              "dn": "cn=ldaptestuser,cn=users," + self.base_dn,
163              "objectClass": "person",
164              "systemFlags": str(~(SYSTEM_FLAG_CONFIG_ALLOW_RENAME | SYSTEM_FLAG_CONFIG_ALLOW_MOVE | SYSTEM_FLAG_CONFIG_ALLOW_LIMITED_MOVE)) })
165
166         res = ldb.search("cn=ldaptestuser,cn=users," + self.base_dn,
167                          scope=SCOPE_BASE, attrs=["systemFlags"])
168         self.assertTrue(len(res) == 1)
169         self.assertEquals(res[0]["systemFlags"][0], "0")
170
171         delete_force(self.ldb, "cn=ldaptestuser,cn=users," + self.base_dn)
172
173         self.ldb.add({
174              "dn": "cn=ldaptestuser,cn=users," + self.base_dn,
175              "objectClass": "person" })
176
177         # We can remove derivation classes of the structural objectclass
178         # but they're going to be readded afterwards
179         m = Message()
180         m.dn = Dn(ldb, "cn=ldaptestuser,cn=users," + self.base_dn)
181         m["objectClass"] = MessageElement("top", FLAG_MOD_DELETE,
182           "objectClass")
183         ldb.modify(m)
184
185         res = ldb.search("cn=ldaptestuser,cn=users," + self.base_dn,
186                          scope=SCOPE_BASE, attrs=["objectClass"])
187         self.assertTrue(len(res) == 1)
188         self.assertTrue("top" in res[0]["objectClass"])
189
190         # The top-most structural class cannot be deleted since there are
191         # attributes of it in use
192         m = Message()
193         m.dn = Dn(ldb, "cn=ldaptestuser,cn=users," + self.base_dn)
194         m["objectClass"] = MessageElement("person", FLAG_MOD_DELETE,
195           "objectClass")
196         try:
197             ldb.modify(m)
198             self.fail()
199         except LdbError, (num, _):
200             self.assertEquals(num, ERR_OBJECT_CLASS_VIOLATION)
201
202         # We cannot delete classes which weren't specified
203         m = Message()
204         m.dn = Dn(ldb, "cn=ldaptestuser,cn=users," + self.base_dn)
205         m["objectClass"] = MessageElement("computer", FLAG_MOD_DELETE,
206           "objectClass")
207         try:
208             ldb.modify(m)
209             self.fail()
210         except LdbError, (num, _):
211             self.assertEquals(num, ERR_NO_SUCH_ATTRIBUTE)
212
213         # An invalid class cannot be added
214         m = Message()
215         m.dn = Dn(ldb, "cn=ldaptestuser,cn=users," + self.base_dn)
216         m["objectClass"] = MessageElement("X", FLAG_MOD_ADD,
217           "objectClass")
218         try:
219             ldb.modify(m)
220             self.fail()
221         except LdbError, (num, _):
222             self.assertEquals(num, ERR_NO_SUCH_ATTRIBUTE)
223
224         # The top-most structural class cannot be changed by adding another
225         # structural one
226         m = Message()
227         m.dn = Dn(ldb, "cn=ldaptestuser,cn=users," + self.base_dn)
228         m["objectClass"] = MessageElement("user", FLAG_MOD_ADD,
229           "objectClass")
230         try:
231             ldb.modify(m)
232             self.fail()
233         except LdbError, (num, _):
234             self.assertEquals(num, ERR_OBJECT_CLASS_VIOLATION)
235
236         # An already specified objectclass cannot be added another time
237         m = Message()
238         m.dn = Dn(ldb, "cn=ldaptestuser,cn=users," + self.base_dn)
239         m["objectClass"] = MessageElement("person", FLAG_MOD_ADD,
240           "objectClass")
241         try:
242             ldb.modify(m)
243             self.fail()
244         except LdbError, (num, _):
245             self.assertEquals(num, ERR_ATTRIBUTE_OR_VALUE_EXISTS)
246
247         # Auxiliary classes can always be added
248         m = Message()
249         m.dn = Dn(ldb, "cn=ldaptestuser,cn=users," + self.base_dn)
250         m["objectClass"] = MessageElement("bootableDevice", FLAG_MOD_ADD,
251           "objectClass")
252         ldb.modify(m)
253
254         # It's only possible to replace with the same objectclass combination.
255         # So the replace action on "objectClass" attributes is really useless.
256         m = Message()
257         m.dn = Dn(ldb, "cn=ldaptestuser,cn=users," + self.base_dn)
258         m["objectClass"] = MessageElement(["top", "person", "bootableDevice"],
259           FLAG_MOD_REPLACE, "objectClass")
260         ldb.modify(m)
261
262         m = Message()
263         m.dn = Dn(ldb, "cn=ldaptestuser,cn=users," + self.base_dn)
264         m["objectClass"] = MessageElement(["person", "bootableDevice"],
265           FLAG_MOD_REPLACE, "objectClass")
266         ldb.modify(m)
267
268         m = Message()
269         m.dn = Dn(ldb, "cn=ldaptestuser,cn=users," + self.base_dn)
270         m["objectClass"] = MessageElement(["top", "person", "bootableDevice",
271           "connectionPoint"], FLAG_MOD_REPLACE, "objectClass")
272         try:
273             ldb.modify(m)
274             self.fail()
275         except LdbError, (num, _):
276             self.assertEquals(num, ERR_OBJECT_CLASS_VIOLATION)
277
278         # More than one change operation is allowed
279         m = Message()
280         m.dn = Dn(ldb, "cn=ldaptestuser,cn=users," + self.base_dn)
281         m.add(MessageElement("bootableDevice", FLAG_MOD_DELETE, "objectClass"))
282         m.add(MessageElement("bootableDevice", FLAG_MOD_ADD, "objectClass"))
283         ldb.modify(m)
284
285         # We cannot remove all object classes by an empty replace
286         m = Message()
287         m.dn = Dn(ldb, "cn=ldaptestuser,cn=users," + self.base_dn)
288         m["objectClass"] = MessageElement([], FLAG_MOD_REPLACE, "objectClass")
289         try:
290             ldb.modify(m)
291             self.fail()
292         except LdbError, (num, _):
293             self.assertEquals(num, ERR_OBJECT_CLASS_VIOLATION)
294
295         m = Message()
296         m.dn = Dn(ldb, "cn=ldaptestuser,cn=users," + self.base_dn)
297         m["objectClass"] = MessageElement(["top", "computer"], FLAG_MOD_REPLACE,
298           "objectClass")
299         try:
300             ldb.modify(m)
301             self.fail()
302         except LdbError, (num, _):
303             self.assertEquals(num, ERR_OBJECT_CLASS_VIOLATION)
304
305         # Classes can be removed unless attributes of them are used.
306         m = Message()
307         m.dn = Dn(ldb, "cn=ldaptestuser,cn=users," + self.base_dn)
308         m["objectClass"] = MessageElement("bootableDevice", FLAG_MOD_DELETE,
309           "objectClass")
310         ldb.modify(m)
311
312         res = ldb.search("cn=ldaptestuser,cn=users," + self.base_dn,
313                          scope=SCOPE_BASE, attrs=["objectClass"])
314         self.assertTrue(len(res) == 1)
315         self.assertFalse("bootableDevice" in res[0]["objectClass"])
316
317         m = Message()
318         m.dn = Dn(ldb, "cn=ldaptestuser,cn=users," + self.base_dn)
319         m["objectClass"] = MessageElement("bootableDevice", FLAG_MOD_ADD,
320           "objectClass")
321         ldb.modify(m)
322
323         # Add an attribute specific to the "bootableDevice" class
324         m = Message()
325         m.dn = Dn(ldb, "cn=ldaptestuser,cn=users," + self.base_dn)
326         m["bootParameter"] = MessageElement("test", FLAG_MOD_ADD,
327           "bootParameter")
328         ldb.modify(m)
329
330         # Classes can be removed unless attributes of them are used. Now there
331         # exist such attributes on the entry.
332         m = Message()
333         m.dn = Dn(ldb, "cn=ldaptestuser,cn=users," + self.base_dn)
334         m["objectClass"] = MessageElement("bootableDevice", FLAG_MOD_DELETE,
335           "objectClass")
336         try:
337             ldb.modify(m)
338             self.fail()
339         except LdbError, (num, _):
340             self.assertEquals(num, ERR_OBJECT_CLASS_VIOLATION)
341
342         # Remove the previously specified attribute
343         m = Message()
344         m.dn = Dn(ldb, "cn=ldaptestuser,cn=users," + self.base_dn)
345         m["bootParameter"] = MessageElement("test", FLAG_MOD_DELETE,
346           "bootParameter")
347         ldb.modify(m)
348
349         # Classes can be removed unless attributes of them are used.
350         m = Message()
351         m.dn = Dn(ldb, "cn=ldaptestuser,cn=users," + self.base_dn)
352         m["objectClass"] = MessageElement("bootableDevice", FLAG_MOD_DELETE,
353           "objectClass")
354         ldb.modify(m)
355
356         delete_force(self.ldb, "cn=ldaptestuser,cn=users," + self.base_dn)
357
358     def test_system_only(self):
359         """Test systemOnly objects"""
360         print "Test systemOnly objects"""
361
362         try:
363             self.ldb.add({
364                 "dn": "cn=ldaptestobject," + self.base_dn,
365                 "objectclass": "configuration"})
366             self.fail()
367         except LdbError, (num, _):
368             self.assertEquals(num, ERR_UNWILLING_TO_PERFORM)
369
370         try:
371             self.ldb.add({
372                 "dn": "cn=Test Secret,cn=system," + self.base_dn,
373                 "objectclass": "secret"})
374             self.fail()
375         except LdbError, (num, _):
376             self.assertEquals(num, ERR_UNWILLING_TO_PERFORM)
377
378         delete_force(self.ldb, "cn=ldaptestobject," + self.base_dn)
379         delete_force(self.ldb, "cn=Test Secret,cn=system," + self.base_dn)
380
381         # Create secret over LSA and try to change it
382
383         lsa_conn = lsa.lsarpc("ncacn_np:%s" % args[0], lp, creds)
384         lsa_handle = lsa_conn.OpenPolicy2(system_name="\\",
385                                           attr=lsa.ObjectAttribute(),
386                                           access_mask=security.SEC_FLAG_MAXIMUM_ALLOWED)
387         secret_name = lsa.String()
388         secret_name.string = "G$Test"
389         sec_handle = lsa_conn.CreateSecret(handle=lsa_handle,
390                                            name=secret_name,
391                                            access_mask=security.SEC_FLAG_MAXIMUM_ALLOWED)
392         lsa_conn.Close(lsa_handle)
393
394         m = Message()
395         m.dn = Dn(ldb, "cn=Test Secret,cn=system," + self.base_dn)
396         m["description"] = MessageElement("desc", FLAG_MOD_REPLACE,
397           "description")
398         try:
399             ldb.modify(m)
400             self.fail()
401         except LdbError, (num, _):
402             self.assertEquals(num, ERR_UNWILLING_TO_PERFORM)
403
404         delete_force(self.ldb, "cn=Test Secret,cn=system," + self.base_dn)
405
406         try:
407             self.ldb.add({
408                 "dn": "cn=ldaptestcontainer," + self.base_dn,
409                 "objectclass": "container",
410                 "isCriticalSystemObject": "TRUE"})
411             self.fail()
412         except LdbError, (num, _):
413             self.assertEquals(num, ERR_UNWILLING_TO_PERFORM)
414
415         self.ldb.add({
416             "dn": "cn=ldaptestcontainer," + self.base_dn,
417             "objectclass": "container"})
418
419         m = Message()
420         m.dn = Dn(ldb, "cn=ldaptestcontainer," + self.base_dn)
421         m["isCriticalSystemObject"] = MessageElement("TRUE", FLAG_MOD_REPLACE,
422           "isCriticalSystemObject")
423         try:
424             ldb.modify(m)
425             self.fail()
426         except LdbError, (num, _):
427             self.assertEquals(num, ERR_UNWILLING_TO_PERFORM)
428
429         delete_force(self.ldb, "cn=ldaptestcontainer," + self.base_dn)
430
431         # Proof if DC SAM object has "isCriticalSystemObject" set
432         res = self.ldb.search("", scope=SCOPE_BASE, attrs=["serverName"])
433         self.assertTrue(len(res) == 1)
434         self.assertTrue("serverName" in res[0])
435         res = self.ldb.search(res[0]["serverName"][0], scope=SCOPE_BASE,
436                               attrs=["serverReference"])
437         self.assertTrue(len(res) == 1)
438         self.assertTrue("serverReference" in res[0])
439         res = self.ldb.search(res[0]["serverReference"][0], scope=SCOPE_BASE,
440                               attrs=["isCriticalSystemObject"])
441         self.assertTrue(len(res) == 1)
442         self.assertTrue("isCriticalSystemObject" in res[0])
443         self.assertEquals(res[0]["isCriticalSystemObject"][0], "TRUE")
444
445     def test_invalid_parent(self):
446         """Test adding an object with invalid parent"""
447         print "Test adding an object with invalid parent"""
448
449         try:
450             self.ldb.add({
451                 "dn": "cn=ldaptestgroup,cn=thisdoesnotexist123,"
452                    + self.base_dn,
453                 "objectclass": "group"})
454             self.fail()
455         except LdbError, (num, _):
456             self.assertEquals(num, ERR_NO_SUCH_OBJECT)
457
458         delete_force(self.ldb, "cn=ldaptestgroup,cn=thisdoesnotexist123,"
459           + self.base_dn)
460
461         try:
462             self.ldb.add({
463                 "dn": "ou=testou,cn=users," + self.base_dn,
464                 "objectclass": "organizationalUnit"})
465             self.fail()
466         except LdbError, (num, _):
467             self.assertEquals(num, ERR_NAMING_VIOLATION)
468
469         delete_force(self.ldb, "ou=testou,cn=users," + self.base_dn)
470
471     def test_invalid_attribute(self):
472         """Test invalid attributes on schema/objectclasses"""
473         print "Test invalid attributes on schema/objectclasses"""
474
475         # attributes not in schema test
476
477         # add operation
478
479         try:
480             self.ldb.add({
481                 "dn": "cn=ldaptestgroup,cn=users," + self.base_dn,
482                 "objectclass": "group",
483                 "thisdoesnotexist": "x"})
484             self.fail()
485         except LdbError, (num, _):
486             self.assertEquals(num, ERR_NO_SUCH_ATTRIBUTE)
487
488         self.ldb.add({
489              "dn": "cn=ldaptestgroup,cn=users," + self.base_dn,
490              "objectclass": "group"})
491
492         # modify operation
493
494         m = Message()
495         m.dn = Dn(ldb, "cn=ldaptestgroup,cn=users," + self.base_dn)
496         m["thisdoesnotexist"] = MessageElement("x", FLAG_MOD_REPLACE,
497           "thisdoesnotexist")
498         try:
499             ldb.modify(m)
500             self.fail()
501         except LdbError, (num, _):
502             self.assertEquals(num, ERR_NO_SUCH_ATTRIBUTE)
503
504         delete_force(self.ldb, "cn=ldaptestgroup,cn=users," + self.base_dn)
505
506         # attributes not in objectclasses and mandatory attributes missing test
507         # Use here a non-SAM entry since it doesn't have special triggers
508         # associated which have an impact on the error results.
509
510         # add operations
511
512         # mandatory attribute missing
513         try:
514             self.ldb.add({
515                 "dn": "cn=ldaptestobject," + self.base_dn,
516                 "objectclass": "ipProtocol"})
517             self.fail()
518         except LdbError, (num, _):
519             self.assertEquals(num, ERR_OBJECT_CLASS_VIOLATION)
520
521         # inadequate but schema-valid attribute specified
522         try:
523             self.ldb.add({
524                 "dn": "cn=ldaptestobject," + self.base_dn,
525                 "objectclass": "ipProtocol",
526                 "ipProtocolNumber": "1",
527                 "uid" : "0"})
528             self.fail()
529         except LdbError, (num, _):
530             self.assertEquals(num, ERR_OBJECT_CLASS_VIOLATION)
531
532         self.ldb.add({
533             "dn": "cn=ldaptestobject," + self.base_dn,
534             "objectclass": "ipProtocol",
535             "ipProtocolNumber": "1"})
536
537         # modify operations
538
539         # inadequate but schema-valid attribute add trial
540         m = Message()
541         m.dn = Dn(ldb, "cn=ldaptestobject," + self.base_dn)
542         m["uid"] = MessageElement("0", FLAG_MOD_ADD, "uid")
543         try:
544             ldb.modify(m)
545             self.fail()
546         except LdbError, (num, _):
547             self.assertEquals(num, ERR_OBJECT_CLASS_VIOLATION)
548
549         # mandatory attribute delete trial
550         m = Message()
551         m.dn = Dn(ldb, "cn=ldaptestobject," + self.base_dn)
552         m["ipProtocolNumber"] = MessageElement([], FLAG_MOD_DELETE,
553           "ipProtocolNumber")
554         try:
555             ldb.modify(m)
556             self.fail()
557         except LdbError, (num, _):
558             self.assertEquals(num, ERR_OBJECT_CLASS_VIOLATION)
559
560         # mandatory attribute delete trial
561         m = Message()
562         m.dn = Dn(ldb, "cn=ldaptestobject," + self.base_dn)
563         m["ipProtocolNumber"] = MessageElement([], FLAG_MOD_REPLACE,
564           "ipProtocolNumber")
565         try:
566             ldb.modify(m)
567             self.fail()
568         except LdbError, (num, _):
569             self.assertEquals(num, ERR_OBJECT_CLASS_VIOLATION)
570
571         delete_force(self.ldb, "cn=ldaptestobject," + self.base_dn)
572
573     def test_single_valued_attributes(self):
574         """Test single-valued attributes"""
575         print "Test single-valued attributes"""
576
577         try:
578             self.ldb.add({
579                 "dn": "cn=ldaptestgroup,cn=users," + self.base_dn,
580                 "objectclass": "group",
581                 "sAMAccountName": ["nam1", "nam2"]})
582             self.fail()
583         except LdbError, (num, _):
584             self.assertEquals(num, ERR_CONSTRAINT_VIOLATION)
585
586         self.ldb.add({
587              "dn": "cn=ldaptestgroup,cn=users," + self.base_dn,
588              "objectclass": "group"})
589
590         m = Message()
591         m.dn = Dn(ldb, "cn=ldaptestgroup,cn=users," + self.base_dn)
592         m["sAMAccountName"] = MessageElement(["nam1","nam2"], FLAG_MOD_REPLACE,
593           "sAMAccountName")
594         try:
595             ldb.modify(m)
596             self.fail()
597         except LdbError, (num, _):
598             self.assertEquals(num, ERR_ATTRIBUTE_OR_VALUE_EXISTS)
599
600         m = Message()
601         m.dn = Dn(ldb, "cn=ldaptestgroup,cn=users," + self.base_dn)
602         m["sAMAccountName"] = MessageElement("testgroupXX", FLAG_MOD_REPLACE,
603           "sAMAccountName")
604         ldb.modify(m)
605
606         m = Message()
607         m.dn = Dn(ldb, "cn=ldaptestgroup,cn=users," + self.base_dn)
608         m["sAMAccountName"] = MessageElement("testgroupXX2", FLAG_MOD_ADD,
609           "sAMAccountName")
610         try:
611             ldb.modify(m)
612             self.fail()
613         except LdbError, (num, _):
614             self.assertEquals(num, ERR_ATTRIBUTE_OR_VALUE_EXISTS)
615
616         delete_force(self.ldb, "cn=ldaptestgroup,cn=users," + self.base_dn)
617
618     def test_attribute_ranges(self):
619         """Test attribute ranges"""
620         print "Test attribute ranges"""
621
622         # Too short (min. 1)
623         try:
624             ldb.add({
625                "dn": "cn=ldaptestuser,cn=users," + self.base_dn,
626                "objectClass": "person",
627                "sn": "" })
628             self.fail()
629         except LdbError, (num, _):
630             self.assertEquals(num, ERR_INVALID_ATTRIBUTE_SYNTAX)
631
632         # Too long (max. 64)
633 #        try:
634 #            ldb.add({
635 #               "dn": "cn=ldaptestuser,cn=users," + self.base_dn,
636 #               "objectClass": "person",
637 #               "sn": "xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx" })
638 #            self.fail()
639 #        except LdbError, (num, _):
640 #            self.assertEquals(num, ERR_CONSTRAINT_VIOLATION)
641
642         ldb.add({
643            "dn": "cn=ldaptestuser,cn=users," + self.base_dn,
644            "objectClass": "person" })
645
646         # Too short (min. 1)
647         m = Message()
648         m.dn = Dn(ldb, "cn=ldaptestuser,cn=users," + self.base_dn)
649         m["sn"] = MessageElement("", FLAG_MOD_REPLACE, "sn")
650         try:
651             ldb.modify(m)
652             self.fail()
653         except LdbError, (num, _):
654             self.assertEquals(num, ERR_INVALID_ATTRIBUTE_SYNTAX)
655
656         # Too long (max. 64)
657 #        m = Message()
658 #        m.dn = Dn(ldb, "cn=ldaptestuser,cn=users," + self.base_dn)
659 #        m["sn"] = MessageElement("xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx", FLAG_MOD_REPLACE, "sn")
660 #        try:
661 #            ldb.modify(m)
662 #            self.fail()
663 #        except LdbError, (num, _):
664 #            self.assertEquals(num, ERR_CONSTRAINT_VIOLATION)
665
666         m = Message()
667         m.dn = Dn(ldb, "cn=ldaptestuser,cn=users," + self.base_dn)
668         m["sn"] = MessageElement("x", FLAG_MOD_REPLACE, "sn")
669         ldb.modify(m)
670
671         delete_force(self.ldb, "cn=ldaptestuser,cn=users," + self.base_dn)
672
673     def test_empty_messages(self):
674         """Test empty messages"""
675         print "Test empty messages"""
676
677         m = Message()
678         m.dn = Dn(ldb, "cn=ldaptestgroup,cn=users," + self.base_dn)
679
680         try:
681             ldb.add(m)
682             self.fail()
683         except LdbError, (num, _):
684             self.assertEquals(num, ERR_OBJECT_CLASS_VIOLATION)
685
686         try:
687             ldb.modify(m)
688             self.fail()
689         except LdbError, (num, _):
690             self.assertEquals(num, ERR_UNWILLING_TO_PERFORM)
691
692         delete_force(self.ldb, "cn=ldaptestgroup,cn=users," + self.base_dn)
693
694     def test_empty_attributes(self):
695         """Test empty attributes"""
696         print "Test empty attributes"""
697
698         m = Message()
699         m.dn = Dn(ldb, "cn=ldaptestgroup,cn=users," + self.base_dn)
700         m["objectClass"] = MessageElement("group", FLAG_MOD_ADD, "objectClass")
701         m["description"] = MessageElement([], FLAG_MOD_ADD, "description")
702
703         try:
704             ldb.add(m)
705             self.fail()
706         except LdbError, (num, _):
707             self.assertEquals(num, ERR_CONSTRAINT_VIOLATION)
708
709         self.ldb.add({
710             "dn": "cn=ldaptestgroup,cn=users," + self.base_dn,
711             "objectclass": "group"})
712
713         m = Message()
714         m.dn = Dn(ldb, "cn=ldaptestgroup,cn=users," + self.base_dn)
715         m["description"] = MessageElement([], FLAG_MOD_ADD, "description")
716
717         try:
718             ldb.modify(m)
719             self.fail()
720         except LdbError, (num, _):
721             self.assertEquals(num, ERR_CONSTRAINT_VIOLATION)
722
723         m = Message()
724         m.dn = Dn(ldb, "cn=ldaptestgroup,cn=users," + self.base_dn)
725         m["description"] = MessageElement([], FLAG_MOD_REPLACE, "description")
726         ldb.modify(m)
727
728         m = Message()
729         m.dn = Dn(ldb, "cn=ldaptestgroup,cn=users," + self.base_dn)
730         m["description"] = MessageElement([], FLAG_MOD_DELETE, "description")
731         try:
732             ldb.modify(m)
733             self.fail()
734         except LdbError, (num, _):
735             self.assertEquals(num, ERR_NO_SUCH_ATTRIBUTE)
736
737         delete_force(self.ldb, "cn=ldaptestgroup,cn=users," + self.base_dn)
738
739     def test_instanceType(self):
740         """Tests the 'instanceType' attribute"""
741         print "Tests the 'instanceType' attribute"""
742
743         # The instance type is single-valued
744         try:
745             self.ldb.add({
746                 "dn": "cn=ldaptestgroup,cn=users," + self.base_dn,
747                 "objectclass": "group",
748                 "instanceType": ["0", "1"]})
749             self.fail()
750         except LdbError, (num, _):
751             self.assertEquals(num, ERR_UNWILLING_TO_PERFORM)
752
753         # The head NC flag cannot be set without the write flag
754         try:
755             self.ldb.add({
756                 "dn": "cn=ldaptestgroup,cn=users," + self.base_dn,
757                 "objectclass": "group",
758                 "instanceType": "1" })
759             self.fail()
760         except LdbError, (num, _):
761             self.assertEquals(num, ERR_UNWILLING_TO_PERFORM)
762
763         # We cannot manipulate NCs without the head NC flag
764         try:
765             self.ldb.add({
766                 "dn": "cn=ldaptestgroup,cn=users," + self.base_dn,
767                 "objectclass": "group",
768                 "instanceType": "32" })
769             self.fail()
770         except LdbError, (num, _):
771             self.assertEquals(num, ERR_UNWILLING_TO_PERFORM)
772
773         self.ldb.add({
774              "dn": "cn=ldaptestgroup,cn=users," + self.base_dn,
775              "objectclass": "group"})
776
777         m = Message()
778         m.dn = Dn(ldb, "cn=ldaptestgroup,cn=users," + self.base_dn)
779         m["instanceType"] = MessageElement("0", FLAG_MOD_REPLACE,
780           "instanceType")
781         try:
782             ldb.modify(m)
783             self.fail()
784         except LdbError, (num, _):
785             self.assertEquals(num, ERR_CONSTRAINT_VIOLATION)
786
787         m = Message()
788         m.dn = Dn(ldb, "cn=ldaptestgroup,cn=users," + self.base_dn)
789         m["instanceType"] = MessageElement([], FLAG_MOD_REPLACE,
790           "instanceType")
791         try:
792             ldb.modify(m)
793             self.fail()
794         except LdbError, (num, _):
795             self.assertEquals(num, ERR_CONSTRAINT_VIOLATION)
796
797         m = Message()
798         m.dn = Dn(ldb, "cn=ldaptestgroup,cn=users," + self.base_dn)
799         m["instanceType"] = MessageElement([], FLAG_MOD_DELETE, "instanceType")
800         try:
801             ldb.modify(m)
802             self.fail()
803         except LdbError, (num, _):
804             self.assertEquals(num, ERR_CONSTRAINT_VIOLATION)
805
806         delete_force(self.ldb, "cn=ldaptestgroup,cn=users," + self.base_dn)
807
808     def test_distinguished_name(self):
809         """Tests the 'distinguishedName' attribute"""
810         print "Tests the 'distinguishedName' attribute"""
811
812         # The "dn" shortcut isn't supported
813         m = Message()
814         m.dn = Dn(ldb, "cn=ldaptestgroup,cn=users," + self.base_dn)
815         m["objectClass"] = MessageElement("group", 0, "objectClass")
816         m["dn"] = MessageElement("cn=ldaptestgroup,cn=users," + self.base_dn, 0,
817           "dn")
818         try:
819             ldb.add(m)
820             self.fail()
821         except LdbError, (num, _):
822             self.assertEquals(num, ERR_NO_SUCH_ATTRIBUTE)
823
824         # a wrong "distinguishedName" attribute is obviously tolerated
825         self.ldb.add({
826               "dn": "cn=ldaptestgroup,cn=users," + self.base_dn,
827               "objectclass": "group",
828               "distinguishedName": "cn=ldaptest,cn=users," + self.base_dn})
829
830         # proof if the DN has been set correctly
831         res = ldb.search("cn=ldaptestgroup,cn=users," + self.base_dn,
832                          scope=SCOPE_BASE, attrs=["distinguishedName"])
833         self.assertTrue(len(res) == 1)
834         self.assertTrue("distinguishedName" in res[0])
835         self.assertTrue(Dn(ldb, res[0]["distinguishedName"][0])
836            == Dn(ldb, "cn=ldaptestgroup, cn=users," + self.base_dn))
837
838         # The "dn" shortcut isn't supported
839         m = Message()
840         m.dn = Dn(ldb, "cn=ldaptestgroup,cn=users," + self.base_dn)
841         m["dn"] = MessageElement(
842           "cn=ldaptestgroup,cn=users," + self.base_dn, FLAG_MOD_REPLACE,
843           "dn")
844         try:
845             ldb.modify(m)
846             self.fail()
847         except LdbError, (num, _):
848             self.assertEquals(num, ERR_NO_SUCH_ATTRIBUTE)
849
850         m = Message()
851         m.dn = Dn(ldb, "cn=ldaptestgroup,cn=users," + self.base_dn)
852         m["distinguishedName"] = MessageElement(
853           "cn=ldaptestuser,cn=users," + self.base_dn, FLAG_MOD_ADD,
854           "distinguishedName")
855
856         try:
857             ldb.modify(m)
858             self.fail()
859         except LdbError, (num, _):
860             self.assertEquals(num, ERR_CONSTRAINT_VIOLATION)
861
862         m = Message()
863         m.dn = Dn(ldb, "cn=ldaptestgroup,cn=users," + self.base_dn)
864         m["distinguishedName"] = MessageElement(
865           "cn=ldaptestuser,cn=users," + self.base_dn, FLAG_MOD_REPLACE,
866           "distinguishedName")
867
868         try:
869             ldb.modify(m)
870             self.fail()
871         except LdbError, (num, _):
872             self.assertEquals(num, ERR_CONSTRAINT_VIOLATION)
873
874         m = Message()
875         m.dn = Dn(ldb, "cn=ldaptestgroup,cn=users," + self.base_dn)
876         m["distinguishedName"] = MessageElement(
877           "cn=ldaptestuser,cn=users," + self.base_dn, FLAG_MOD_DELETE,
878           "distinguishedName")
879
880         try:
881             ldb.modify(m)
882             self.fail()
883         except LdbError, (num, _):
884             self.assertEquals(num, ERR_CONSTRAINT_VIOLATION)
885
886         delete_force(self.ldb, "cn=ldaptestgroup,cn=users," + self.base_dn)
887
888     def test_rdn_name(self):
889         """Tests the RDN"""
890         print "Tests the RDN"""
891
892         # empty RDN
893         try:
894             self.ldb.add({
895                  "dn": "=,cn=users," + self.base_dn,
896                  "objectclass": "group"})
897             self.fail()
898         except LdbError, (num, _):
899             self.assertEquals(num, ERR_INVALID_DN_SYNTAX)
900
901         # empty RDN name
902         try:
903             self.ldb.add({
904                  "dn": "=ldaptestgroup,cn=users," + self.base_dn,
905                  "objectclass": "group"})
906             self.fail()
907         except LdbError, (num, _):
908             self.assertEquals(num, ERR_INVALID_DN_SYNTAX)
909
910         # empty RDN value
911         try:
912             self.ldb.add({
913                  "dn": "cn=,cn=users," + self.base_dn,
914                  "objectclass": "group"})
915             self.fail()
916         except LdbError, (num, _):
917             self.assertEquals(num, ERR_INVALID_DN_SYNTAX)
918
919         # a wrong RDN candidate
920         try:
921             self.ldb.add({
922                  "dn": "description=xyz,cn=users," + self.base_dn,
923                  "objectclass": "group"})
924             self.fail()
925         except LdbError, (num, _):
926             self.assertEquals(num, ERR_NAMING_VIOLATION)
927
928         delete_force(self.ldb, "description=xyz,cn=users," + self.base_dn)
929
930         # a wrong "name" attribute is obviously tolerated
931         self.ldb.add({
932              "dn": "cn=ldaptestgroup,cn=users," + self.base_dn,
933              "objectclass": "group",
934              "name": "ldaptestgroupx"})
935
936         # proof if the name has been set correctly
937         res = ldb.search("cn=ldaptestgroup,cn=users," + self.base_dn,
938                          scope=SCOPE_BASE, attrs=["name"])
939         self.assertTrue(len(res) == 1)
940         self.assertTrue("name" in res[0])
941         self.assertTrue(res[0]["name"][0] == "ldaptestgroup")
942
943         # new empty RDN
944         try:
945             self.ldb.rename("cn=ldaptestgroup,cn=users," + self.base_dn,
946                             "=,cn=users," + self.base_dn)
947             self.fail()
948         except LdbError, (num, _):
949             self.assertEquals(num, ERR_INVALID_DN_SYNTAX)
950
951         # new empty RDN name
952         try:
953             self.ldb.rename("cn=ldaptestgroup,cn=users," + self.base_dn,
954                             "=ldaptestgroup,cn=users," + self.base_dn)
955             self.fail()
956         except LdbError, (num, _):
957             self.assertEquals(num, ERR_INVALID_DN_SYNTAX)
958
959         # new empty RDN value
960         try:
961             self.ldb.rename("cn=ldaptestgroup,cn=users," + self.base_dn,
962                             "cn=,cn=users," + self.base_dn)
963             self.fail()
964         except LdbError, (num, _):
965             self.assertEquals(num, ERR_NAMING_VIOLATION)
966
967         m = Message()
968         m.dn = Dn(ldb, "cn=ldaptestgroup,cn=users," + self.base_dn)
969         m["name"] = MessageElement("cn=ldaptestuser", FLAG_MOD_REPLACE,
970           "name")
971         try:
972             ldb.modify(m)
973             self.fail()
974         except LdbError, (num, _):
975             self.assertEquals(num, ERR_NOT_ALLOWED_ON_RDN)
976
977         m = Message()
978         m.dn = Dn(ldb, "cn=ldaptestgroup,cn=users," + self.base_dn)
979         m["cn"] = MessageElement("ldaptestuser",
980           FLAG_MOD_REPLACE, "cn")
981         try:
982             ldb.modify(m)
983             self.fail()
984         except LdbError, (num, _):
985             self.assertEquals(num, ERR_NOT_ALLOWED_ON_RDN)
986
987         delete_force(self.ldb, "cn=ldaptestgroup,cn=users," + self.base_dn)
988
989
990         # this test needs to be disabled until we really understand
991         # what the rDN length constraints are
992     def DISABLED_test_largeRDN(self):
993         """Testing large rDN (limit 64 characters)"""
994         rdn = "CN=a012345678901234567890123456789012345678901234567890123456789012";
995         delete_force(self.ldb, "%s,%s" % (rdn, self.base_dn))
996         ldif = """
997 dn: %s,%s""" % (rdn,self.base_dn) + """
998 objectClass: container
999 """
1000         self.ldb.add_ldif(ldif)
1001         delete_force(self.ldb, "%s,%s" % (rdn, self.base_dn))
1002
1003         rdn = "CN=a0123456789012345678901234567890123456789012345678901234567890120";
1004         delete_force(self.ldb, "%s,%s" % (rdn, self.base_dn))
1005         try:
1006             ldif = """
1007 dn: %s,%s""" % (rdn,self.base_dn) + """
1008 objectClass: container
1009 """
1010             self.ldb.add_ldif(ldif)
1011             self.fail()
1012         except LdbError, (num, _):
1013             self.assertEquals(num, ERR_CONSTRAINT_VIOLATION)
1014         delete_force(self.ldb, "%s,%s" % (rdn, self.base_dn))
1015
1016     def test_rename(self):
1017         """Tests the rename operation"""
1018         print "Tests the rename operations"""
1019
1020         try:
1021             # cannot rename to be a child of itself
1022             ldb.rename(self.base_dn, "dc=test," + self.base_dn)
1023             self.fail()
1024         except LdbError, (num, _):
1025             self.assertEquals(num, ERR_UNWILLING_TO_PERFORM)
1026
1027         try:
1028             # inexistent object
1029             ldb.rename("cn=ldaptestuser2,cn=users," + self.base_dn, "cn=ldaptestuser2,cn=users," + self.base_dn)
1030             self.fail()
1031         except LdbError, (num, _):
1032             self.assertEquals(num, ERR_NO_SUCH_OBJECT)
1033
1034         self.ldb.add({
1035              "dn": "cn=ldaptestuser2,cn=users," + self.base_dn,
1036              "objectclass": "user" })
1037
1038         ldb.rename("cn=ldaptestuser2,cn=users," + self.base_dn, "cn=ldaptestuser2,cn=users," + self.base_dn)
1039         ldb.rename("cn=ldaptestuser2,cn=users," + self.base_dn, "cn=ldaptestuser3,cn=users," + self.base_dn)
1040         ldb.rename("cn=ldaptestuser3,cn=users," + self.base_dn, "cn=ldaptestUSER3,cn=users," + self.base_dn)
1041
1042         try:
1043             # containment problem: a user entry cannot contain user entries
1044             ldb.rename("cn=ldaptestuser3,cn=users," + self.base_dn, "cn=ldaptestuser4,cn=ldaptestuser3,cn=users," + self.base_dn)
1045             self.fail()
1046         except LdbError, (num, _):
1047             self.assertEquals(num, ERR_NAMING_VIOLATION)
1048
1049         try:
1050             # invalid parent
1051             ldb.rename("cn=ldaptestuser3,cn=users," + self.base_dn, "cn=ldaptestuser3,cn=people,cn=users," + self.base_dn)
1052             self.fail()
1053         except LdbError, (num, _):
1054             self.assertEquals(num, ERR_OTHER)
1055
1056         try:
1057             # invalid target DN syntax
1058             ldb.rename("cn=ldaptestuser3,cn=users," + self.base_dn, ",cn=users," + self.base_dn)
1059             self.fail()
1060         except LdbError, (num, _):
1061             self.assertEquals(num, ERR_INVALID_DN_SYNTAX)
1062
1063         try:
1064             # invalid RDN name
1065             ldb.rename("cn=ldaptestuser3,cn=users," + self.base_dn, "ou=ldaptestuser3,cn=users," + self.base_dn)
1066             self.fail()
1067         except LdbError, (num, _):
1068             self.assertEquals(num, ERR_UNWILLING_TO_PERFORM)
1069
1070         delete_force(self.ldb, "cn=ldaptestuser3,cn=users," + self.base_dn)
1071
1072         # Performs some "systemFlags" testing
1073
1074         # Move failing since no "SYSTEM_FLAG_CONFIG_ALLOW_MOVE"
1075         try:
1076             ldb.rename("CN=DisplaySpecifiers," + self.configuration_dn, "CN=DisplaySpecifiers,CN=Services," + self.configuration_dn)
1077             self.fail()
1078         except LdbError, (num, _):
1079             self.assertEquals(num, ERR_UNWILLING_TO_PERFORM)
1080
1081         # Limited move failing since no "SYSTEM_FLAG_CONFIG_ALLOW_LIMITED_MOVE"
1082         try:
1083             ldb.rename("CN=Directory Service,CN=Windows NT,CN=Services," + self.configuration_dn, "CN=Directory Service,CN=RRAS,CN=Services," + self.configuration_dn)
1084             self.fail()
1085         except LdbError, (num, _):
1086             self.assertEquals(num, ERR_UNWILLING_TO_PERFORM)
1087
1088         # Rename failing since no "SYSTEM_FLAG_CONFIG_ALLOW_RENAME"
1089         try:
1090             ldb.rename("CN=DisplaySpecifiers," + self.configuration_dn, "CN=DisplaySpecifiers2," + self.configuration_dn)
1091             self.fail()
1092         except LdbError, (num, _):
1093             self.assertEquals(num, ERR_UNWILLING_TO_PERFORM)
1094
1095         # It's not really possible to test moves on the schema partition since
1096         # there don't exist subcontainers on it.
1097
1098         # Rename failing since "SYSTEM_FLAG_SCHEMA_BASE_OBJECT"
1099         try:
1100             ldb.rename("CN=Top," + self.schema_dn, "CN=Top2," + self.schema_dn)
1101             self.fail()
1102         except LdbError, (num, _):
1103             self.assertEquals(num, ERR_UNWILLING_TO_PERFORM)
1104
1105         # Move failing since "SYSTEM_FLAG_DOMAIN_DISALLOW_MOVE"
1106         try:
1107             ldb.rename("CN=Users," + self.base_dn, "CN=Users,CN=Computers," + self.base_dn)
1108             self.fail()
1109         except LdbError, (num, _):
1110             self.assertEquals(num, ERR_UNWILLING_TO_PERFORM)
1111
1112         # Rename failing since "SYSTEM_FLAG_DOMAIN_DISALLOW_RENAME"
1113         try:
1114             ldb.rename("CN=Users," + self.base_dn, "CN=Users2," + self.base_dn)
1115             self.fail()
1116         except LdbError, (num, _):
1117             self.assertEquals(num, ERR_UNWILLING_TO_PERFORM)
1118
1119         # Performs some other constraints testing
1120
1121         try:
1122             ldb.rename("CN=Policies,CN=System," + self.base_dn, "CN=Users2," + self.base_dn)
1123             self.fail()
1124         except LdbError, (num, _):
1125             self.assertEquals(num, ERR_OTHER)
1126
1127     def test_rename_twice(self):
1128         """Tests the rename operation twice - this corresponds to a past bug"""
1129         print "Tests the rename twice operation"""
1130
1131         self.ldb.add({
1132              "dn": "cn=ldaptestuser5,cn=users," + self.base_dn,
1133              "objectclass": "user" })
1134
1135         ldb.rename("cn=ldaptestuser5,cn=users," + self.base_dn, "cn=ldaptestUSER5,cn=users," + self.base_dn)
1136         delete_force(self.ldb, "cn=ldaptestuser5,cn=users," + self.base_dn)
1137         self.ldb.add({
1138              "dn": "cn=ldaptestuser5,cn=users," + self.base_dn,
1139              "objectclass": "user" })
1140         ldb.rename("cn=ldaptestuser5,cn=Users," + self.base_dn, "cn=ldaptestUSER5,cn=users," + self.base_dn)
1141         res = ldb.search(expression="cn=ldaptestuser5")
1142         print "Found %u records" % len(res)
1143         self.assertEquals(len(res), 1, "Wrong number of hits for cn=ldaptestuser5")
1144         res = ldb.search(expression="(&(cn=ldaptestuser5)(objectclass=user))")
1145         print "Found %u records" % len(res)
1146         self.assertEquals(len(res), 1, "Wrong number of hits for (&(cn=ldaptestuser5)(objectclass=user))")
1147         delete_force(self.ldb, "cn=ldaptestuser5,cn=users," + self.base_dn)
1148
1149     def test_objectGUID(self):
1150         """Test objectGUID behaviour"""
1151         print "Testing objectGUID behaviour\n"
1152
1153         # The objectGUID cannot directly be set
1154         try:
1155             self.ldb.add_ldif("""
1156 dn: cn=ldaptestcontainer,""" + self.base_dn + """
1157 objectClass: container
1158 objectGUID: bd3480c9-58af-4cd8-92df-bc4a18b6e44d
1159 """)
1160             self.fail()
1161         except LdbError, (num, _):
1162             self.assertEquals(num, ERR_UNWILLING_TO_PERFORM)
1163
1164         self.ldb.add({
1165             "dn": "cn=ldaptestcontainer," + self.base_dn,
1166             "objectClass": "container" })
1167
1168         res = ldb.search("cn=ldaptestcontainer," + self.base_dn,
1169                          scope=SCOPE_BASE,
1170                          attrs=["objectGUID", "uSNCreated", "uSNChanged", "whenCreated", "whenChanged"])
1171         self.assertTrue(len(res) == 1)
1172         self.assertTrue("objectGUID" in res[0])
1173         self.assertTrue("uSNCreated" in res[0])
1174         self.assertTrue("uSNChanged" in res[0])
1175         self.assertTrue("whenCreated" in res[0])
1176         self.assertTrue("whenChanged" in res[0])
1177
1178         delete_force(self.ldb, "cn=ldaptestcontainer," + self.base_dn)
1179
1180         # All the following attributes are specificable on add operations
1181         self.ldb.add({
1182             "dn": "cn=ldaptestcontainer," + self.base_dn,
1183             "objectClass": "container",
1184             "uSNCreated" : "1",
1185             "uSNChanged" : "1",
1186             "whenCreated": timestring(long(time.time())),
1187             "whenChanged": timestring(long(time.time())) })
1188
1189         res = ldb.search("cn=ldaptestcontainer," + self.base_dn,
1190                          scope=SCOPE_BASE,
1191                          attrs=["objectGUID", "uSNCreated", "uSNChanged", "whenCreated", "whenChanged"])
1192         self.assertTrue(len(res) == 1)
1193         self.assertTrue("objectGUID" in res[0])
1194         self.assertTrue("uSNCreated" in res[0])
1195         self.assertFalse(res[0]["uSNCreated"][0] == "1") # these are corrected
1196         self.assertTrue("uSNChanged" in res[0])
1197         self.assertFalse(res[0]["uSNChanged"][0] == "1") # these are corrected
1198
1199         delete_force(self.ldb, "cn=ldaptestcontainer," + self.base_dn)
1200
1201         # All this attributes are specificable on add operations
1202         self.ldb.add({
1203             "dn": "cn=ldaptestcontainer," + self.base_dn,
1204             "objectclass": "container",
1205             "uSNCreated" : "1",
1206             "uSNChanged" : "1",
1207             "whenCreated": timestring(long(time.time())),
1208             "whenChanged": timestring(long(time.time())) })
1209
1210         res = ldb.search("cn=ldaptestcontainer," + self.base_dn,
1211                          scope=SCOPE_BASE,
1212                          attrs=["objectGUID", "uSNCreated", "uSNChanged", "whenCreated", "whenChanged"])
1213         self.assertTrue(len(res) == 1)
1214         self.assertTrue("objectGUID" in res[0])
1215         self.assertTrue("uSNCreated" in res[0])
1216         self.assertFalse(res[0]["uSNCreated"][0] == "1") # these are corrected
1217         self.assertTrue("uSNChanged" in res[0])
1218         self.assertFalse(res[0]["uSNChanged"][0] == "1") # these are corrected
1219         self.assertTrue("whenCreated" in res[0])
1220         self.assertTrue("whenChanged" in res[0])
1221
1222         # The objectGUID cannot directly be changed
1223         try:
1224             self.ldb.modify_ldif("""
1225 dn: cn=ldaptestcontainer,""" + self.base_dn + """
1226 changetype: modify
1227 replace: objectGUID
1228 objectGUID: bd3480c9-58af-4cd8-92df-bc4a18b6e44d
1229 """)
1230             self.fail()
1231         except LdbError, (num, _):
1232             self.assertEquals(num, ERR_CONSTRAINT_VIOLATION)
1233
1234         delete_force(self.ldb, "cn=ldaptestcontainer," + self.base_dn)
1235
1236     def test_parentGUID(self):
1237         """Test parentGUID behaviour"""
1238         print "Testing parentGUID behaviour\n"
1239
1240         self.ldb.add({
1241             "dn": "cn=parentguidtest,cn=users," + self.base_dn,
1242             "objectclass":"user",
1243             "samaccountname":"parentguidtest"});
1244         res1 = ldb.search(base="cn=parentguidtest,cn=users," + self.base_dn, scope=SCOPE_BASE,
1245                           attrs=["parentGUID", "samaccountname"]);
1246         res2 = ldb.search(base="cn=users," + self.base_dn,scope=SCOPE_BASE,
1247                           attrs=["objectGUID"]);
1248         res3 = ldb.search(base=self.base_dn, scope=SCOPE_BASE,
1249                           attrs=["parentGUID"]);
1250         res4 = ldb.search(base=self.configuration_dn, scope=SCOPE_BASE,
1251                           attrs=["parentGUID"]);
1252         res5 = ldb.search(base=self.schema_dn, scope=SCOPE_BASE,
1253                           attrs=["parentGUID"]);
1254
1255         """Check if the parentGUID is valid """
1256         self.assertEquals(res1[0]["parentGUID"], res2[0]["objectGUID"]);
1257
1258         """Check if it returns nothing when there is no parent object - default NC"""
1259         has_parentGUID = False
1260         for key in res3[0].keys():
1261             if key == "parentGUID":
1262                 has_parentGUID = True
1263                 break
1264         self.assertFalse(has_parentGUID);
1265
1266         """Check if it returns nothing when there is no parent object - configuration NC"""
1267         has_parentGUID = False
1268         for key in res4[0].keys():
1269             if key == "parentGUID":
1270                 has_parentGUID = True
1271                 break
1272         self.assertFalse(has_parentGUID);
1273
1274         """Check if it returns nothing when there is no parent object - schema NC"""
1275         has_parentGUID = False
1276         for key in res5[0].keys():
1277             if key == "parentGUID":
1278                 has_parentGUID = True
1279                 break
1280         self.assertFalse(has_parentGUID);
1281
1282         """Ensures that if you look for another object attribute after the constructed
1283             parentGUID, it will return correctly"""
1284         has_another_attribute = False
1285         for key in res1[0].keys():
1286             if key == "sAMAccountName":
1287                 has_another_attribute = True
1288                 break
1289         self.assertTrue(has_another_attribute)
1290         self.assertTrue(len(res1[0]["samaccountname"]) == 1)
1291         self.assertEquals(res1[0]["samaccountname"][0], "parentguidtest");
1292
1293         print "Testing parentGUID behaviour on rename\n"
1294
1295         self.ldb.add({
1296             "dn": "cn=testotherusers," + self.base_dn,
1297             "objectclass":"container"});
1298         res1 = ldb.search(base="cn=testotherusers," + self.base_dn,scope=SCOPE_BASE,
1299                           attrs=["objectGUID"]);
1300         ldb.rename("cn=parentguidtest,cn=users," + self.base_dn,
1301                    "cn=parentguidtest,cn=testotherusers," + self.base_dn);
1302         res2 = ldb.search(base="cn=parentguidtest,cn=testotherusers," + self.base_dn,
1303                           scope=SCOPE_BASE,
1304                           attrs=["parentGUID"]);
1305         self.assertEquals(res1[0]["objectGUID"], res2[0]["parentGUID"]);
1306
1307         delete_force(self.ldb, "cn=parentguidtest,cn=testotherusers," + self.base_dn)
1308         delete_force(self.ldb, "cn=testotherusers," + self.base_dn)
1309
1310     def test_groupType_int32(self):
1311         """Test groupType (int32) behaviour (should appear to be casted to a 32 bit signed integer before comparsion)"""
1312         print "Testing groupType (int32) behaviour\n"
1313
1314         res1 = ldb.search(base=self.base_dn, scope=SCOPE_SUBTREE,
1315                           attrs=["groupType"], expression="groupType=2147483653");
1316
1317         res2 = ldb.search(base=self.base_dn, scope=SCOPE_SUBTREE,
1318                           attrs=["groupType"], expression="groupType=-2147483643");
1319
1320         self.assertEquals(len(res1), len(res2))
1321
1322         self.assertTrue(res1.count > 0)
1323
1324         self.assertEquals(res1[0]["groupType"][0], "-2147483643")
1325
1326     def test_linked_attributes(self):
1327         """This tests the linked attribute behaviour"""
1328         print "Testing linked attribute behaviour\n"
1329
1330         ldb.add({
1331             "dn": "cn=ldaptestgroup,cn=users," + self.base_dn,
1332             "objectclass": "group"})
1333
1334         # This should not work since "memberOf" is linked to "member"
1335         try:
1336             ldb.add({
1337                 "dn": "cn=ldaptestuser,cn=users," + self.base_dn,
1338                 "objectclass": "user",
1339                 "memberOf": "cn=ldaptestgroup,cn=users," + self.base_dn})
1340         except LdbError, (num, _):
1341             self.assertEquals(num, ERR_UNWILLING_TO_PERFORM)
1342
1343         ldb.add({
1344             "dn": "cn=ldaptestuser,cn=users," + self.base_dn,
1345             "objectclass": "user"})
1346
1347         m = Message()
1348         m.dn = Dn(ldb, "cn=ldaptestuser,cn=users," + self.base_dn)
1349         m["memberOf"] = MessageElement("cn=ldaptestgroup,cn=users," + self.base_dn,
1350           FLAG_MOD_ADD, "memberOf")
1351         try:
1352             ldb.modify(m)
1353             self.fail()
1354         except LdbError, (num, _):
1355             self.assertEquals(num, ERR_UNWILLING_TO_PERFORM)
1356
1357         m = Message()
1358         m.dn = Dn(ldb, "cn=ldaptestgroup,cn=users," + self.base_dn)
1359         m["member"] = MessageElement("cn=ldaptestuser,cn=users," + self.base_dn,
1360           FLAG_MOD_ADD, "member")
1361         ldb.modify(m)
1362
1363         m = Message()
1364         m.dn = Dn(ldb, "cn=ldaptestuser,cn=users," + self.base_dn)
1365         m["memberOf"] = MessageElement("cn=ldaptestgroup,cn=users," + self.base_dn,
1366           FLAG_MOD_REPLACE, "memberOf")
1367         try:
1368             ldb.modify(m)
1369             self.fail()
1370         except LdbError, (num, _):
1371             self.assertEquals(num, ERR_UNWILLING_TO_PERFORM)
1372
1373         m = Message()
1374         m.dn = Dn(ldb, "cn=ldaptestuser,cn=users," + self.base_dn)
1375         m["memberOf"] = MessageElement("cn=ldaptestgroup,cn=users," + self.base_dn,
1376           FLAG_MOD_DELETE, "memberOf")
1377         try:
1378             ldb.modify(m)
1379             self.fail()
1380         except LdbError, (num, _):
1381             self.assertEquals(num, ERR_UNWILLING_TO_PERFORM)
1382
1383         m = Message()
1384         m.dn = Dn(ldb, "cn=ldaptestgroup,cn=users," + self.base_dn)
1385         m["member"] = MessageElement("cn=ldaptestuser,cn=users," + self.base_dn,
1386           FLAG_MOD_DELETE, "member")
1387         ldb.modify(m)
1388
1389         # This should yield no results since the member attribute for
1390         # "ldaptestuser" should have been deleted
1391         res1 = ldb.search("cn=ldaptestgroup, cn=users," + self.base_dn,
1392                           scope=SCOPE_BASE,
1393                           expression="(member=cn=ldaptestuser,cn=users," + self.base_dn + ")",
1394                           attrs=[])
1395         self.assertTrue(len(res1) == 0)
1396
1397         delete_force(self.ldb, "cn=ldaptestgroup,cn=users," + self.base_dn)
1398
1399         ldb.add({
1400             "dn": "cn=ldaptestgroup,cn=users," + self.base_dn,
1401             "objectclass": "group",
1402             "member": "cn=ldaptestuser,cn=users," + self.base_dn})
1403
1404         delete_force(self.ldb, "cn=ldaptestuser,cn=users," + self.base_dn)
1405
1406         # Make sure that the "member" attribute for "ldaptestuser" has been
1407         # removed
1408         res = ldb.search("cn=ldaptestgroup,cn=users," + self.base_dn,
1409                           scope=SCOPE_BASE, attrs=["member"])
1410         self.assertTrue(len(res) == 1)
1411         self.assertFalse("member" in res[0])
1412
1413         delete_force(self.ldb, "cn=ldaptestgroup,cn=users," + self.base_dn)
1414
1415     def test_wkguid(self):
1416         """Test Well known GUID behaviours (including DN+Binary)"""
1417         print "Test Well known GUID behaviours (including DN+Binary)"""
1418
1419         res = self.ldb.search(base=("<WKGUID=ab1d30f3768811d1aded00c04fd8d5cd,%s>" % self.base_dn), scope=SCOPE_BASE, attrs=[])
1420         self.assertEquals(len(res), 1)
1421
1422         res2 = self.ldb.search(scope=SCOPE_BASE, attrs=["wellKnownObjects"], expression=("wellKnownObjects=B:32:ab1d30f3768811d1aded00c04fd8d5cd:%s" % res[0].dn))
1423         self.assertEquals(len(res2), 1)
1424
1425         # Prove that the matching rule is over the whole DN+Binary
1426         res2 = self.ldb.search(scope=SCOPE_BASE, attrs=["wellKnownObjects"], expression=("wellKnownObjects=B:32:ab1d30f3768811d1aded00c04fd8d5cd"))
1427         self.assertEquals(len(res2), 0)
1428         # Prove that the matching rule is over the whole DN+Binary
1429         res2 = self.ldb.search(scope=SCOPE_BASE, attrs=["wellKnownObjects"], expression=("wellKnownObjects=%s") % res[0].dn)
1430         self.assertEquals(len(res2), 0)
1431
1432     def test_subschemasubentry(self):
1433         """Test subSchemaSubEntry appears when requested, but not when not requested"""
1434         print "Test subSchemaSubEntry"""
1435
1436         res = self.ldb.search(base=self.base_dn, scope=SCOPE_BASE, attrs=["subSchemaSubEntry"])
1437         self.assertEquals(len(res), 1)
1438         self.assertEquals(res[0]["subSchemaSubEntry"][0], "CN=Aggregate,"+self.schema_dn)
1439
1440         res = self.ldb.search(base=self.base_dn, scope=SCOPE_BASE, attrs=["*"])
1441         self.assertEquals(len(res), 1)
1442         self.assertTrue("subScheamSubEntry" not in res[0])
1443
1444     def test_all(self):
1445         """Basic tests"""
1446
1447         print "Testing user add"
1448
1449         ldb.add({
1450             "dn": "cn=ldaptestuser,cn=uSers," + self.base_dn,
1451             "objectclass": "user",
1452             "cN": "LDAPtestUSER",
1453             "givenname": "ldap",
1454             "sn": "testy"})
1455
1456         ldb.add({
1457             "dn": "cn=ldaptestgroup,cn=uSers," + self.base_dn,
1458             "objectclass": "group",
1459             "member": "cn=ldaptestuser,cn=useRs," + self.base_dn})
1460
1461         ldb.add({
1462             "dn": "cn=ldaptestcomputer,cn=computers," + self.base_dn,
1463             "objectclass": "computer",
1464             "cN": "LDAPtestCOMPUTER"})
1465
1466         ldb.add({"dn": "cn=ldaptest2computer,cn=computers," + self.base_dn,
1467             "objectClass": "computer",
1468             "cn": "LDAPtest2COMPUTER",
1469             "userAccountControl": str(UF_WORKSTATION_TRUST_ACCOUNT),
1470             "displayname": "ldap testy"})
1471
1472         try:
1473             ldb.add({"dn": "cn=ldaptestcomputer3,cn=computers," + self.base_dn,
1474                      "objectClass": "computer",
1475                      "cn": "LDAPtest2COMPUTER"
1476                      })
1477             self.fail()
1478         except LdbError, (num, _):
1479             self.assertEquals(num, ERR_INVALID_DN_SYNTAX)
1480
1481         try:
1482             ldb.add({"dn": "cn=ldaptestcomputer3,cn=computers," + self.base_dn,
1483                      "objectClass": "computer",
1484                      "cn": "ldaptestcomputer3",
1485                      "sAMAccountType": str(ATYPE_NORMAL_ACCOUNT)
1486                 })
1487             self.fail()
1488         except LdbError, (num, _):
1489             self.assertEquals(num, ERR_UNWILLING_TO_PERFORM)
1490
1491         ldb.add({"dn": "cn=ldaptestcomputer3,cn=computers," + self.base_dn,
1492                  "objectClass": "computer",
1493                  "cn": "LDAPtestCOMPUTER3"
1494                  })
1495
1496         print "Testing ldb.search for (&(cn=ldaptestcomputer3)(objectClass=user))";
1497         res = ldb.search(self.base_dn, expression="(&(cn=ldaptestcomputer3)(objectClass=user))");
1498         self.assertEquals(len(res), 1, "Found only %d for (&(cn=ldaptestcomputer3)(objectClass=user))" % len(res))
1499
1500         self.assertEquals(str(res[0].dn), ("CN=ldaptestcomputer3,CN=Computers," + self.base_dn));
1501         self.assertEquals(res[0]["cn"][0], "ldaptestcomputer3");
1502         self.assertEquals(res[0]["name"][0], "ldaptestcomputer3");
1503         self.assertEquals(res[0]["objectClass"][0], "top");
1504         self.assertEquals(res[0]["objectClass"][1], "person");
1505         self.assertEquals(res[0]["objectClass"][2], "organizationalPerson");
1506         self.assertEquals(res[0]["objectClass"][3], "user");
1507         self.assertEquals(res[0]["objectClass"][4], "computer");
1508         self.assertTrue("objectGUID" in res[0])
1509         self.assertTrue("whenCreated" in res[0])
1510         self.assertEquals(res[0]["objectCategory"][0], ("CN=Computer,CN=Schema,CN=Configuration," + self.base_dn));
1511         self.assertEquals(int(res[0]["primaryGroupID"][0]), 513);
1512         self.assertEquals(int(res[0]["sAMAccountType"][0]), ATYPE_NORMAL_ACCOUNT);
1513         self.assertEquals(int(res[0]["userAccountControl"][0]), UF_NORMAL_ACCOUNT | UF_PASSWD_NOTREQD | UF_ACCOUNTDISABLE);
1514
1515         delete_force(self.ldb, "cn=ldaptestcomputer3,cn=computers," + self.base_dn)
1516
1517         print "Testing attribute or value exists behaviour"
1518         try:
1519             ldb.modify_ldif("""
1520 dn: cn=ldaptest2computer,cn=computers,""" + self.base_dn + """
1521 changetype: modify
1522 replace: servicePrincipalName
1523 servicePrincipalName: host/ldaptest2computer
1524 servicePrincipalName: host/ldaptest2computer
1525 servicePrincipalName: cifs/ldaptest2computer
1526 """)
1527             self.fail()
1528         except LdbError, (num, msg):
1529             self.assertEquals(num, ERR_ATTRIBUTE_OR_VALUE_EXISTS)
1530
1531         ldb.modify_ldif("""
1532 dn: cn=ldaptest2computer,cn=computers,""" + self.base_dn + """
1533 changetype: modify
1534 replace: servicePrincipalName
1535 servicePrincipalName: host/ldaptest2computer
1536 servicePrincipalName: cifs/ldaptest2computer
1537 """)
1538         try:
1539             ldb.modify_ldif("""
1540 dn: cn=ldaptest2computer,cn=computers,""" + self.base_dn + """
1541 changetype: modify
1542 add: servicePrincipalName
1543 servicePrincipalName: host/ldaptest2computer
1544 """)
1545             self.fail()
1546         except LdbError, (num, msg):
1547             self.assertEquals(num, ERR_ATTRIBUTE_OR_VALUE_EXISTS)
1548
1549         print "Testing ranged results"
1550         ldb.modify_ldif("""
1551 dn: cn=ldaptest2computer,cn=computers,""" + self.base_dn + """
1552 changetype: modify
1553 replace: servicePrincipalName
1554 """)
1555
1556         ldb.modify_ldif("""
1557 dn: cn=ldaptest2computer,cn=computers,""" + self.base_dn + """
1558 changetype: modify
1559 add: servicePrincipalName
1560 servicePrincipalName: host/ldaptest2computer0
1561 servicePrincipalName: host/ldaptest2computer1
1562 servicePrincipalName: host/ldaptest2computer2
1563 servicePrincipalName: host/ldaptest2computer3
1564 servicePrincipalName: host/ldaptest2computer4
1565 servicePrincipalName: host/ldaptest2computer5
1566 servicePrincipalName: host/ldaptest2computer6
1567 servicePrincipalName: host/ldaptest2computer7
1568 servicePrincipalName: host/ldaptest2computer8
1569 servicePrincipalName: host/ldaptest2computer9
1570 servicePrincipalName: host/ldaptest2computer10
1571 servicePrincipalName: host/ldaptest2computer11
1572 servicePrincipalName: host/ldaptest2computer12
1573 servicePrincipalName: host/ldaptest2computer13
1574 servicePrincipalName: host/ldaptest2computer14
1575 servicePrincipalName: host/ldaptest2computer15
1576 servicePrincipalName: host/ldaptest2computer16
1577 servicePrincipalName: host/ldaptest2computer17
1578 servicePrincipalName: host/ldaptest2computer18
1579 servicePrincipalName: host/ldaptest2computer19
1580 servicePrincipalName: host/ldaptest2computer20
1581 servicePrincipalName: host/ldaptest2computer21
1582 servicePrincipalName: host/ldaptest2computer22
1583 servicePrincipalName: host/ldaptest2computer23
1584 servicePrincipalName: host/ldaptest2computer24
1585 servicePrincipalName: host/ldaptest2computer25
1586 servicePrincipalName: host/ldaptest2computer26
1587 servicePrincipalName: host/ldaptest2computer27
1588 servicePrincipalName: host/ldaptest2computer28
1589 servicePrincipalName: host/ldaptest2computer29
1590 """)
1591
1592         res = ldb.search(self.base_dn, expression="(cn=ldaptest2computer))", scope=SCOPE_SUBTREE,
1593                          attrs=["servicePrincipalName;range=0-*"])
1594         self.assertEquals(len(res), 1, "Could not find (cn=ldaptest2computer)")
1595         #print len(res[0]["servicePrincipalName;range=0-*"])
1596         self.assertEquals(len(res[0]["servicePrincipalName;range=0-*"]), 30)
1597
1598         res = ldb.search(self.base_dn, expression="(cn=ldaptest2computer))", scope=SCOPE_SUBTREE, attrs=["servicePrincipalName;range=0-19"])
1599         self.assertEquals(len(res), 1, "Could not find (cn=ldaptest2computer)")
1600             # print res[0]["servicePrincipalName;range=0-19"].length
1601         self.assertEquals(len(res[0]["servicePrincipalName;range=0-19"]), 20)
1602
1603
1604         res = ldb.search(self.base_dn, expression="(cn=ldaptest2computer))", scope=SCOPE_SUBTREE, attrs=["servicePrincipalName;range=0-30"])
1605         self.assertEquals(len(res), 1, "Could not find (cn=ldaptest2computer)")
1606         self.assertEquals(len(res[0]["servicePrincipalName;range=0-*"]), 30)
1607
1608         res = ldb.search(self.base_dn, expression="(cn=ldaptest2computer))", scope=SCOPE_SUBTREE, attrs=["servicePrincipalName;range=0-40"])
1609         self.assertEquals(len(res), 1, "Could not find (cn=ldaptest2computer)")
1610         self.assertEquals(len(res[0]["servicePrincipalName;range=0-*"]), 30)
1611
1612         res = ldb.search(self.base_dn, expression="(cn=ldaptest2computer))", scope=SCOPE_SUBTREE, attrs=["servicePrincipalName;range=30-40"])
1613         self.assertEquals(len(res), 1, "Could not find (cn=ldaptest2computer)")
1614         self.assertEquals(len(res[0]["servicePrincipalName;range=30-*"]), 0)
1615
1616
1617         res = ldb.search(self.base_dn, expression="(cn=ldaptest2computer))", scope=SCOPE_SUBTREE, attrs=["servicePrincipalName;range=10-40"])
1618         self.assertEquals(len(res), 1, "Could not find (cn=ldaptest2computer)")
1619         self.assertEquals(len(res[0]["servicePrincipalName;range=10-*"]), 20)
1620         # pos_11 = res[0]["servicePrincipalName;range=10-*"][18]
1621
1622         res = ldb.search(self.base_dn, expression="(cn=ldaptest2computer))", scope=SCOPE_SUBTREE, attrs=["servicePrincipalName;range=11-40"])
1623         self.assertEquals(len(res), 1, "Could not find (cn=ldaptest2computer)")
1624         self.assertEquals(len(res[0]["servicePrincipalName;range=11-*"]), 19)
1625             # print res[0]["servicePrincipalName;range=11-*"][18]
1626             # print pos_11
1627             # self.assertEquals((res[0]["servicePrincipalName;range=11-*"][18]), pos_11)
1628
1629         res = ldb.search(self.base_dn, expression="(cn=ldaptest2computer))", scope=SCOPE_SUBTREE, attrs=["servicePrincipalName;range=11-15"])
1630         self.assertEquals(len(res), 1, "Could not find (cn=ldaptest2computer)")
1631         self.assertEquals(len(res[0]["servicePrincipalName;range=11-15"]), 5)
1632             # self.assertEquals(res[0]["servicePrincipalName;range=11-15"][4], pos_11)
1633
1634         res = ldb.search(self.base_dn, expression="(cn=ldaptest2computer))", scope=SCOPE_SUBTREE, attrs=["servicePrincipalName"])
1635         self.assertEquals(len(res), 1, "Could not find (cn=ldaptest2computer)")
1636             # print res[0]["servicePrincipalName"][18]
1637             # print pos_11
1638         self.assertEquals(len(res[0]["servicePrincipalName"]), 30)
1639             # self.assertEquals(res[0]["servicePrincipalName"][18], pos_11)
1640
1641         delete_force(self.ldb, "cn=ldaptestuser2,cn=users," + self.base_dn)
1642         ldb.add({
1643             "dn": "cn=ldaptestuser2,cn=useRs," + self.base_dn,
1644             "objectClass": "user",
1645             "cn": "LDAPtestUSER2",
1646             "givenname": "testy",
1647             "sn": "ldap user2"})
1648
1649         print "Testing Ambigious Name Resolution"
1650         # Testing ldb.search for (&(anr=ldap testy)(objectClass=user))
1651         res = ldb.search(expression="(&(anr=ldap testy)(objectClass=user))")
1652         self.assertEquals(len(res), 3, "Found only %d of 3 for (&(anr=ldap testy)(objectClass=user))" % len(res))
1653
1654         # Testing ldb.search for (&(anr=testy ldap)(objectClass=user))
1655         res = ldb.search(expression="(&(anr=testy ldap)(objectClass=user))")
1656         self.assertEquals(len(res), 2, "Found only %d of 2 for (&(anr=testy ldap)(objectClass=user))" % len(res))
1657
1658         # Testing ldb.search for (&(anr=ldap)(objectClass=user))
1659         res = ldb.search(expression="(&(anr=ldap)(objectClass=user))")
1660         self.assertEquals(len(res), 4, "Found only %d of 4 for (&(anr=ldap)(objectClass=user))" % len(res))
1661
1662         # Testing ldb.search for (&(anr==ldap)(objectClass=user))
1663         res = ldb.search(expression="(&(anr==ldap)(objectClass=user))")
1664         self.assertEquals(len(res), 1, "Could not find (&(anr==ldap)(objectClass=user)). Found only %d for (&(anr=ldap)(objectClass=user))" % len(res))
1665
1666         self.assertEquals(str(res[0].dn), ("CN=ldaptestuser,CN=Users," + self.base_dn))
1667         self.assertEquals(res[0]["cn"][0], "ldaptestuser")
1668         self.assertEquals(str(res[0]["name"]), "ldaptestuser")
1669
1670         # Testing ldb.search for (&(anr=testy)(objectClass=user))
1671         res = ldb.search(expression="(&(anr=testy)(objectClass=user))")
1672         self.assertEquals(len(res), 2, "Found only %d for (&(anr=testy)(objectClass=user))" % len(res))
1673
1674         # Testing ldb.search for (&(anr=testy ldap)(objectClass=user))
1675         res = ldb.search(expression="(&(anr=testy ldap)(objectClass=user))")
1676         self.assertEquals(len(res), 2, "Found only %d for (&(anr=testy ldap)(objectClass=user))" % len(res))
1677
1678         # Testing ldb.search for (&(anr==testy ldap)(objectClass=user))
1679 # this test disabled for the moment, as anr with == tests are not understood
1680 #        res = ldb.search(expression="(&(anr==testy ldap)(objectClass=user))")
1681 #        self.assertEquals(len(res), 1, "Found only %d for (&(anr==testy ldap)(objectClass=user))" % len(res))
1682
1683 #        self.assertEquals(str(res[0].dn), ("CN=ldaptestuser,CN=Users," + self.base_dn))
1684 #        self.assertEquals(res[0]["cn"][0], "ldaptestuser")
1685 #        self.assertEquals(res[0]["name"][0], "ldaptestuser")
1686
1687         # Testing ldb.search for (&(anr==testy ldap)(objectClass=user))
1688 #        res = ldb.search(expression="(&(anr==testy ldap)(objectClass=user))")
1689 #        self.assertEquals(len(res), 1, "Could not find (&(anr==testy ldap)(objectClass=user))")
1690
1691 #        self.assertEquals(str(res[0].dn), ("CN=ldaptestuser,CN=Users," + self.base_dn))
1692 #        self.assertEquals(res[0]["cn"][0], "ldaptestuser")
1693 #        self.assertEquals(res[0]["name"][0], "ldaptestuser")
1694
1695         # Testing ldb.search for (&(anr=testy ldap user)(objectClass=user))
1696         res = ldb.search(expression="(&(anr=testy ldap user)(objectClass=user))")
1697         self.assertEquals(len(res), 1, "Could not find (&(anr=testy ldap user)(objectClass=user))")
1698
1699         self.assertEquals(str(res[0].dn), ("CN=ldaptestuser2,CN=Users," + self.base_dn))
1700         self.assertEquals(str(res[0]["cn"]), "ldaptestuser2")
1701         self.assertEquals(str(res[0]["name"]), "ldaptestuser2")
1702
1703         # Testing ldb.search for (&(anr==testy ldap user2)(objectClass=user))
1704 #        res = ldb.search(expression="(&(anr==testy ldap user2)(objectClass=user))")
1705 #        self.assertEquals(len(res), 1, "Could not find (&(anr==testy ldap user2)(objectClass=user))")
1706
1707         self.assertEquals(str(res[0].dn), ("CN=ldaptestuser2,CN=Users," + self.base_dn))
1708         self.assertEquals(str(res[0]["cn"]), "ldaptestuser2")
1709         self.assertEquals(str(res[0]["name"]), "ldaptestuser2")
1710
1711         # Testing ldb.search for (&(anr==ldap user2)(objectClass=user))
1712 #        res = ldb.search(expression="(&(anr==ldap user2)(objectClass=user))")
1713 #        self.assertEquals(len(res), 1, "Could not find (&(anr==ldap user2)(objectClass=user))")
1714
1715         self.assertEquals(str(res[0].dn), ("CN=ldaptestuser2,CN=Users," + self.base_dn))
1716         self.assertEquals(str(res[0]["cn"]), "ldaptestuser2")
1717         self.assertEquals(str(res[0]["name"]), "ldaptestuser2")
1718
1719         # Testing ldb.search for (&(anr==not ldap user2)(objectClass=user))
1720 #        res = ldb.search(expression="(&(anr==not ldap user2)(objectClass=user))")
1721 #        self.assertEquals(len(res), 0, "Must not find (&(anr==not ldap user2)(objectClass=user))")
1722
1723         # Testing ldb.search for (&(anr=not ldap user2)(objectClass=user))
1724         res = ldb.search(expression="(&(anr=not ldap user2)(objectClass=user))")
1725         self.assertEquals(len(res), 0, "Must not find (&(anr=not ldap user2)(objectClass=user))")
1726
1727         # Testing ldb.search for (&(anr="testy ldap")(objectClass=user)) (ie, with quotes)
1728 #        res = ldb.search(expression="(&(anr==\"testy ldap\")(objectClass=user))")
1729 #        self.assertEquals(len(res), 0, "Found (&(anr==\"testy ldap\")(objectClass=user))")
1730
1731         print "Testing Renames"
1732
1733         attrs = ["objectGUID", "objectSid"]
1734         print "Testing ldb.search for (&(cn=ldaptestUSer2)(objectClass=user))"
1735         res_user = ldb.search(self.base_dn, expression="(&(cn=ldaptestUSer2)(objectClass=user))", scope=SCOPE_SUBTREE, attrs=attrs)
1736         self.assertEquals(len(res_user), 1, "Could not find (&(cn=ldaptestUSer2)(objectClass=user))")
1737
1738         # Check rename works with extended/alternate DN forms
1739         ldb.rename("<SID=" + ldb.schema_format_value("objectSID", res_user[0]["objectSID"][0]) + ">" , "cn=ldaptestUSER3,cn=users," + self.base_dn)
1740
1741         print "Testing ldb.search for (&(cn=ldaptestuser3)(objectClass=user))"
1742         res = ldb.search(expression="(&(cn=ldaptestuser3)(objectClass=user))")
1743         self.assertEquals(len(res), 1, "Could not find (&(cn=ldaptestuser3)(objectClass=user))")
1744
1745         self.assertEquals(str(res[0].dn), ("CN=ldaptestUSER3,CN=Users," + self.base_dn))
1746         self.assertEquals(str(res[0]["cn"]), "ldaptestUSER3")
1747         self.assertEquals(str(res[0]["name"]), "ldaptestUSER3")
1748
1749          #"Testing ldb.search for (&(&(cn=ldaptestuser3)(userAccountControl=*))(objectClass=user))"
1750         res = ldb.search(expression="(&(&(cn=ldaptestuser3)(userAccountControl=*))(objectClass=user))")
1751         self.assertEquals(len(res), 1, "(&(&(cn=ldaptestuser3)(userAccountControl=*))(objectClass=user))")
1752
1753         self.assertEquals(str(res[0].dn), ("CN=ldaptestUSER3,CN=Users," + self.base_dn))
1754         self.assertEquals(str(res[0]["cn"]), "ldaptestUSER3")
1755         self.assertEquals(str(res[0]["name"]), "ldaptestUSER3")
1756
1757          #"Testing ldb.search for (&(&(cn=ldaptestuser3)(userAccountControl=546))(objectClass=user))"
1758         res = ldb.search(expression="(&(&(cn=ldaptestuser3)(userAccountControl=546))(objectClass=user))")
1759         self.assertEquals(len(res), 1, "(&(&(cn=ldaptestuser3)(userAccountControl=546))(objectClass=user))")
1760
1761         self.assertEquals(str(res[0].dn), ("CN=ldaptestUSER3,CN=Users," + self.base_dn))
1762         self.assertEquals(str(res[0]["cn"]), "ldaptestUSER3")
1763         self.assertEquals(str(res[0]["name"]), "ldaptestUSER3")
1764
1765          #"Testing ldb.search for (&(&(cn=ldaptestuser3)(userAccountControl=547))(objectClass=user))"
1766         res = ldb.search(expression="(&(&(cn=ldaptestuser3)(userAccountControl=547))(objectClass=user))")
1767         self.assertEquals(len(res), 0, "(&(&(cn=ldaptestuser3)(userAccountControl=547))(objectClass=user))")
1768
1769         # This is a Samba special, and does not exist in real AD
1770         #    print "Testing ldb.search for (dn=CN=ldaptestUSER3,CN=Users," + self.base_dn + ")"
1771         #    res = ldb.search("(dn=CN=ldaptestUSER3,CN=Users," + self.base_dn + ")")
1772         #    if (res.error != 0 || len(res) != 1) {
1773         #        print "Could not find (dn=CN=ldaptestUSER3,CN=Users," + self.base_dn + ")"
1774         #        self.assertEquals(len(res), 1)
1775         #    }
1776         #    self.assertEquals(res[0].dn, ("CN=ldaptestUSER3,CN=Users," + self.base_dn))
1777         #    self.assertEquals(res[0].cn, "ldaptestUSER3")
1778         #    self.assertEquals(res[0].name, "ldaptestUSER3")
1779
1780         print "Testing ldb.search for (distinguishedName=CN=ldaptestUSER3,CN=Users," + self.base_dn + ")"
1781         res = ldb.search(expression="(distinguishedName=CN=ldaptestUSER3,CN=Users," + self.base_dn + ")")
1782         self.assertEquals(len(res), 1, "Could not find (dn=CN=ldaptestUSER3,CN=Users," + self.base_dn + ")")
1783         self.assertEquals(str(res[0].dn), ("CN=ldaptestUSER3,CN=Users," + self.base_dn))
1784         self.assertEquals(str(res[0]["cn"]), "ldaptestUSER3")
1785         self.assertEquals(str(res[0]["name"]), "ldaptestUSER3")
1786
1787         # ensure we cannot add it again
1788         try:
1789             ldb.add({"dn": "cn=ldaptestuser3,cn=userS," + self.base_dn,
1790                       "objectClass": "user",
1791                       "cn": "LDAPtestUSER3"})
1792             self.fail()
1793         except LdbError, (num, _):
1794             self.assertEquals(num, ERR_ENTRY_ALREADY_EXISTS)
1795
1796         # rename back
1797         ldb.rename("cn=ldaptestuser3,cn=users," + self.base_dn, "cn=ldaptestuser2,cn=users," + self.base_dn)
1798
1799         # ensure we cannot rename it twice
1800         try:
1801             ldb.rename("cn=ldaptestuser3,cn=users," + self.base_dn,
1802                        "cn=ldaptestuser2,cn=users," + self.base_dn)
1803             self.fail()
1804         except LdbError, (num, _):
1805             self.assertEquals(num, ERR_NO_SUCH_OBJECT)
1806
1807         # ensure can now use that name
1808         ldb.add({"dn": "cn=ldaptestuser3,cn=users," + self.base_dn,
1809                       "objectClass": "user",
1810                       "cn": "LDAPtestUSER3"})
1811
1812         # ensure we now cannot rename
1813         try:
1814             ldb.rename("cn=ldaptestuser2,cn=users," + self.base_dn, "cn=ldaptestuser3,cn=users," + self.base_dn)
1815             self.fail()
1816         except LdbError, (num, _):
1817             self.assertEquals(num, ERR_ENTRY_ALREADY_EXISTS)
1818         try:
1819             ldb.rename("cn=ldaptestuser3,cn=users," + self.base_dn, "cn=ldaptestuser3,cn=configuration," + self.base_dn)
1820             self.fail()
1821         except LdbError, (num, _):
1822             self.assertTrue(num in (71, 64))
1823
1824         ldb.rename("cn=ldaptestuser3,cn=users," + self.base_dn, "cn=ldaptestuser5,cn=users," + self.base_dn)
1825
1826         ldb.delete("cn=ldaptestuser5,cn=users," + self.base_dn)
1827
1828         delete_force(ldb, "cn=ldaptestgroup2,cn=users," + self.base_dn)
1829
1830         ldb.rename("cn=ldaptestgroup,cn=users," + self.base_dn, "cn=ldaptestgroup2,cn=users," + self.base_dn)
1831
1832         print "Testing subtree renames"
1833
1834         ldb.add({"dn": "cn=ldaptestcontainer," + self.base_dn,
1835                  "objectClass": "container"})
1836
1837         ldb.add({"dn": "CN=ldaptestuser4,CN=ldaptestcontainer," + self.base_dn,
1838                  "objectClass": "user",
1839                  "cn": "LDAPtestUSER4"})
1840
1841         # Here we don't enforce these hard "description" constraints
1842         ldb.modify_ldif("""
1843 dn: cn=ldaptestcontainer,""" + self.base_dn + """
1844 changetype: modify
1845 replace: description
1846 description: desc1
1847 description: desc2
1848 """)
1849
1850         ldb.modify_ldif("""
1851 dn: cn=ldaptestgroup2,cn=users,""" + self.base_dn + """
1852 changetype: modify
1853 add: member
1854 member: cn=ldaptestuser4,cn=ldaptestcontainer,""" + self.base_dn + """
1855 member: cn=ldaptestcomputer,cn=computers,""" + self.base_dn + """
1856 member: cn=ldaptestuser2,cn=users,""" + self.base_dn + """
1857 """)
1858
1859         print "Testing ldb.rename of cn=ldaptestcontainer," + self.base_dn + " to cn=ldaptestcontainer2," + self.base_dn
1860         ldb.rename("CN=ldaptestcontainer," + self.base_dn, "CN=ldaptestcontainer2," + self.base_dn)
1861
1862         print "Testing ldb.search for (&(cn=ldaptestuser4)(objectClass=user))"
1863         res = ldb.search(expression="(&(cn=ldaptestuser4)(objectClass=user))")
1864         self.assertEquals(len(res), 1, "Could not find (&(cn=ldaptestuser4)(objectClass=user))")
1865
1866         print "Testing subtree ldb.search for (&(cn=ldaptestuser4)(objectClass=user)) in (just renamed from) cn=ldaptestcontainer," + self.base_dn
1867         try:
1868             res = ldb.search("cn=ldaptestcontainer," + self.base_dn,
1869                     expression="(&(cn=ldaptestuser4)(objectClass=user))",
1870                     scope=SCOPE_SUBTREE)
1871             self.fail(res)
1872         except LdbError, (num, _):
1873             self.assertEquals(num, ERR_NO_SUCH_OBJECT)
1874
1875         print "Testing one-level ldb.search for (&(cn=ldaptestuser4)(objectClass=user)) in (just renamed from) cn=ldaptestcontainer," + self.base_dn
1876         try:
1877             res = ldb.search("cn=ldaptestcontainer," + self.base_dn,
1878                     expression="(&(cn=ldaptestuser4)(objectClass=user))", scope=SCOPE_ONELEVEL)
1879             self.fail()
1880         except LdbError, (num, _):
1881             self.assertEquals(num, ERR_NO_SUCH_OBJECT)
1882
1883         print "Testing ldb.search for (&(cn=ldaptestuser4)(objectClass=user)) in renamed container"
1884         res = ldb.search("cn=ldaptestcontainer2," + self.base_dn, expression="(&(cn=ldaptestuser4)(objectClass=user))", scope=SCOPE_SUBTREE)
1885         self.assertEquals(len(res), 1, "Could not find (&(cn=ldaptestuser4)(objectClass=user)) under cn=ldaptestcontainer2," + self.base_dn)
1886
1887         self.assertEquals(str(res[0].dn), ("CN=ldaptestuser4,CN=ldaptestcontainer2," + self.base_dn))
1888         self.assertEquals(res[0]["memberOf"][0].upper(), ("CN=ldaptestgroup2,CN=Users," + self.base_dn).upper())
1889
1890         time.sleep(4)
1891
1892         print "Testing ldb.search for (&(member=CN=ldaptestuser4,CN=ldaptestcontainer2," + self.base_dn + ")(objectclass=group)) to check subtree renames and linked attributes"
1893         res = ldb.search(self.base_dn, expression="(&(member=CN=ldaptestuser4,CN=ldaptestcontainer2," + self.base_dn + ")(objectclass=group))", scope=SCOPE_SUBTREE)
1894         self.assertEquals(len(res), 1, "Could not find (&(member=CN=ldaptestuser4,CN=ldaptestcontainer2," + self.base_dn + ")(objectclass=group)), perhaps linked attributes are not consistant with subtree renames?")
1895
1896         print "Testing ldb.rename (into itself) of cn=ldaptestcontainer2," + self.base_dn + " to cn=ldaptestcontainer,cn=ldaptestcontainer2," + self.base_dn
1897         try:
1898             ldb.rename("cn=ldaptestcontainer2," + self.base_dn, "cn=ldaptestcontainer,cn=ldaptestcontainer2," + self.base_dn)
1899             self.fail()
1900         except LdbError, (num, _):
1901             self.assertEquals(num, ERR_UNWILLING_TO_PERFORM)
1902
1903         print "Testing ldb.rename (into non-existent container) of cn=ldaptestcontainer2," + self.base_dn + " to cn=ldaptestcontainer,cn=ldaptestcontainer3," + self.base_dn
1904         try:
1905             ldb.rename("cn=ldaptestcontainer2," + self.base_dn, "cn=ldaptestcontainer,cn=ldaptestcontainer3," + self.base_dn)
1906             self.fail()
1907         except LdbError, (num, _):
1908             self.assertTrue(num in (ERR_UNWILLING_TO_PERFORM, ERR_OTHER))
1909
1910         print "Testing delete (should fail, not a leaf node) of renamed cn=ldaptestcontainer2," + self.base_dn
1911         try:
1912             ldb.delete("cn=ldaptestcontainer2," + self.base_dn)
1913             self.fail()
1914         except LdbError, (num, _):
1915             self.assertEquals(num, ERR_NOT_ALLOWED_ON_NON_LEAF)
1916
1917         print "Testing base ldb.search for CN=ldaptestuser4,CN=ldaptestcontainer2," + self.base_dn
1918         res = ldb.search(expression="(objectclass=*)", base=("CN=ldaptestuser4,CN=ldaptestcontainer2," + self.base_dn), scope=SCOPE_BASE)
1919         self.assertEquals(len(res), 1)
1920         res = ldb.search(expression="(cn=ldaptestuser40)", base=("CN=ldaptestuser4,CN=ldaptestcontainer2," + self.base_dn), scope=SCOPE_BASE)
1921         self.assertEquals(len(res), 0)
1922
1923         print "Testing one-level ldb.search for (&(cn=ldaptestuser4)(objectClass=user)) in cn=ldaptestcontainer2," + self.base_dn
1924         res = ldb.search(expression="(&(cn=ldaptestuser4)(objectClass=user))", base=("cn=ldaptestcontainer2," + self.base_dn), scope=SCOPE_ONELEVEL)
1925         # FIXME: self.assertEquals(len(res), 0)
1926
1927         print "Testing one-level ldb.search for (&(cn=ldaptestuser4)(objectClass=user)) in cn=ldaptestcontainer2," + self.base_dn
1928         res = ldb.search(expression="(&(cn=ldaptestuser4)(objectClass=user))", base=("cn=ldaptestcontainer2," + self.base_dn), scope=SCOPE_SUBTREE)
1929         # FIXME: self.assertEquals(len(res), 0)
1930
1931         print "Testing delete of subtree renamed "+("CN=ldaptestuser4,CN=ldaptestcontainer2," + self.base_dn)
1932         ldb.delete(("CN=ldaptestuser4,CN=ldaptestcontainer2," + self.base_dn))
1933         print "Testing delete of renamed cn=ldaptestcontainer2," + self.base_dn
1934         ldb.delete("cn=ldaptestcontainer2," + self.base_dn)
1935
1936         ldb.add({"dn": "cn=ldaptestutf8user èùéìòà,cn=users," + self.base_dn, "objectClass": "user"})
1937
1938         ldb.add({"dn": "cn=ldaptestutf8user2  èùéìòà,cn=users," + self.base_dn, "objectClass": "user"})
1939
1940         print "Testing ldb.search for (&(cn=ldaptestuser)(objectClass=user))"
1941         res = ldb.search(expression="(&(cn=ldaptestuser)(objectClass=user))")
1942         self.assertEquals(len(res), 1, "Could not find (&(cn=ldaptestuser)(objectClass=user))")
1943
1944         self.assertEquals(str(res[0].dn), ("CN=ldaptestuser,CN=Users," + self.base_dn))
1945         self.assertEquals(str(res[0]["cn"]), "ldaptestuser")
1946         self.assertEquals(str(res[0]["name"]), "ldaptestuser")
1947         self.assertEquals(set(res[0]["objectClass"]), set(["top", "person", "organizationalPerson", "user"]))
1948         self.assertTrue("objectGUID" in res[0])
1949         self.assertTrue("whenCreated" in res[0])
1950         self.assertEquals(str(res[0]["objectCategory"]), ("CN=Person,CN=Schema,CN=Configuration," + self.base_dn))
1951         self.assertEquals(int(res[0]["sAMAccountType"][0]), ATYPE_NORMAL_ACCOUNT)
1952         self.assertEquals(int(res[0]["userAccountControl"][0]), UF_NORMAL_ACCOUNT | UF_PASSWD_NOTREQD | UF_ACCOUNTDISABLE)
1953         self.assertEquals(res[0]["memberOf"][0].upper(), ("CN=ldaptestgroup2,CN=Users," + self.base_dn).upper())
1954         self.assertEquals(len(res[0]["memberOf"]), 1)
1955
1956         print "Testing ldb.search for (&(cn=ldaptestuser)(objectCategory=cn=person,cn=schema,cn=configuration," + self.base_dn + "))"
1957         res2 = ldb.search(expression="(&(cn=ldaptestuser)(objectCategory=cn=person,cn=schema,cn=configuration," + self.base_dn + "))")
1958         self.assertEquals(len(res2), 1, "Could not find (&(cn=ldaptestuser)(objectCategory=cn=person,cn=schema,cn=configuration," + self.base_dn + "))")
1959
1960         self.assertEquals(res[0].dn, res2[0].dn)
1961
1962         print "Testing ldb.search for (&(cn=ldaptestuser)(objectCategory=PerSon))"
1963         res3 = ldb.search(expression="(&(cn=ldaptestuser)(objectCategory=PerSon))")
1964         self.assertEquals(len(res3), 1, "Could not find (&(cn=ldaptestuser)(objectCategory=PerSon)): matched %d" % len(res3))
1965
1966         self.assertEquals(res[0].dn, res3[0].dn)
1967
1968         if gc_ldb is not None:
1969             print "Testing ldb.search for (&(cn=ldaptestuser)(objectCategory=PerSon)) in Global Catalog"
1970             res3gc = gc_ldb.search(expression="(&(cn=ldaptestuser)(objectCategory=PerSon))")
1971             self.assertEquals(len(res3gc), 1)
1972
1973             self.assertEquals(res[0].dn, res3gc[0].dn)
1974
1975         print "Testing ldb.search for (&(cn=ldaptestuser)(objectCategory=PerSon)) in with 'phantom root' control"
1976
1977         if gc_ldb is not None:
1978             res3control = gc_ldb.search(self.base_dn, expression="(&(cn=ldaptestuser)(objectCategory=PerSon))", scope=SCOPE_SUBTREE, attrs=["cn"], controls=["search_options:1:2"])
1979             self.assertEquals(len(res3control), 1, "Could not find (&(cn=ldaptestuser)(objectCategory=PerSon)) in Global Catalog")
1980
1981             self.assertEquals(res[0].dn, res3control[0].dn)
1982
1983         ldb.delete(res[0].dn)
1984
1985         print "Testing ldb.search for (&(cn=ldaptestcomputer)(objectClass=user))"
1986         res = ldb.search(expression="(&(cn=ldaptestcomputer)(objectClass=user))")
1987         self.assertEquals(len(res), 1, "Could not find (&(cn=ldaptestuser)(objectClass=user))")
1988
1989         self.assertEquals(str(res[0].dn), ("CN=ldaptestcomputer,CN=Computers," + self.base_dn))
1990         self.assertEquals(str(res[0]["cn"]), "ldaptestcomputer")
1991         self.assertEquals(str(res[0]["name"]), "ldaptestcomputer")
1992         self.assertEquals(set(res[0]["objectClass"]), set(["top", "person", "organizationalPerson", "user", "computer"]))
1993         self.assertTrue("objectGUID" in res[0])
1994         self.assertTrue("whenCreated" in res[0])
1995         self.assertEquals(str(res[0]["objectCategory"]), ("CN=Computer,CN=Schema,CN=Configuration," + self.base_dn))
1996         self.assertEquals(int(res[0]["primaryGroupID"][0]), 513)
1997         self.assertEquals(int(res[0]["sAMAccountType"][0]), ATYPE_NORMAL_ACCOUNT)
1998         self.assertEquals(int(res[0]["userAccountControl"][0]), UF_NORMAL_ACCOUNT | UF_PASSWD_NOTREQD | UF_ACCOUNTDISABLE)
1999         self.assertEquals(res[0]["memberOf"][0].upper(), ("CN=ldaptestgroup2,CN=Users," + self.base_dn).upper())
2000         self.assertEquals(len(res[0]["memberOf"]), 1)
2001
2002         print "Testing ldb.search for (&(cn=ldaptestcomputer)(objectCategory=cn=computer,cn=schema,cn=configuration," + self.base_dn + "))"
2003         res2 = ldb.search(expression="(&(cn=ldaptestcomputer)(objectCategory=cn=computer,cn=schema,cn=configuration," + self.base_dn + "))")
2004         self.assertEquals(len(res2), 1, "Could not find (&(cn=ldaptestcomputer)(objectCategory=cn=computer,cn=schema,cn=configuration," + self.base_dn + "))")
2005
2006         self.assertEquals(res[0].dn, res2[0].dn)
2007
2008         if gc_ldb is not None:
2009             print "Testing ldb.search for (&(cn=ldaptestcomputer)(objectCategory=cn=computer,cn=schema,cn=configuration," + self.base_dn + ")) in Global Catlog"
2010             res2gc = gc_ldb.search(expression="(&(cn=ldaptestcomputer)(objectCategory=cn=computer,cn=schema,cn=configuration," + self.base_dn + "))")
2011             self.assertEquals(len(res2gc), 1, "Could not find (&(cn=ldaptestcomputer)(objectCategory=cn=computer,cn=schema,cn=configuration," + self.base_dn + ")) in Global Catlog")
2012
2013             self.assertEquals(res[0].dn, res2gc[0].dn)
2014
2015         print "Testing ldb.search for (&(cn=ldaptestcomputer)(objectCategory=compuTER))"
2016         res3 = ldb.search(expression="(&(cn=ldaptestcomputer)(objectCategory=compuTER))")
2017         self.assertEquals(len(res3), 1, "Could not find (&(cn=ldaptestcomputer)(objectCategory=compuTER))")
2018
2019         self.assertEquals(res[0].dn, res3[0].dn)
2020
2021         if gc_ldb is not None:
2022             print "Testing ldb.search for (&(cn=ldaptestcomputer)(objectCategory=compuTER)) in Global Catalog"
2023             res3gc = gc_ldb.search(expression="(&(cn=ldaptestcomputer)(objectCategory=compuTER))")
2024             self.assertEquals(len(res3gc), 1, "Could not find (&(cn=ldaptestcomputer)(objectCategory=compuTER)) in Global Catalog")
2025
2026             self.assertEquals(res[0].dn, res3gc[0].dn)
2027
2028         print "Testing ldb.search for (&(cn=ldaptestcomp*r)(objectCategory=compuTER))"
2029         res4 = ldb.search(expression="(&(cn=ldaptestcomp*r)(objectCategory=compuTER))")
2030         self.assertEquals(len(res4), 1, "Could not find (&(cn=ldaptestcomp*r)(objectCategory=compuTER))")
2031
2032         self.assertEquals(res[0].dn, res4[0].dn)
2033
2034         print "Testing ldb.search for (&(cn=ldaptestcomput*)(objectCategory=compuTER))"
2035         res5 = ldb.search(expression="(&(cn=ldaptestcomput*)(objectCategory=compuTER))")
2036         self.assertEquals(len(res5), 1, "Could not find (&(cn=ldaptestcomput*)(objectCategory=compuTER))")
2037
2038         self.assertEquals(res[0].dn, res5[0].dn)
2039
2040         print "Testing ldb.search for (&(cn=*daptestcomputer)(objectCategory=compuTER))"
2041         res6 = ldb.search(expression="(&(cn=*daptestcomputer)(objectCategory=compuTER))")
2042         self.assertEquals(len(res6), 1, "Could not find (&(cn=*daptestcomputer)(objectCategory=compuTER))")
2043
2044         self.assertEquals(res[0].dn, res6[0].dn)
2045
2046         ldb.delete("<GUID=" + ldb.schema_format_value("objectGUID", res[0]["objectGUID"][0]) + ">")
2047
2048         print "Testing ldb.search for (&(cn=ldaptest2computer)(objectClass=user))"
2049         res = ldb.search(expression="(&(cn=ldaptest2computer)(objectClass=user))")
2050         self.assertEquals(len(res), 1, "Could not find (&(cn=ldaptest2computer)(objectClass=user))")
2051
2052         self.assertEquals(str(res[0].dn), "CN=ldaptest2computer,CN=Computers," + self.base_dn)
2053         self.assertEquals(str(res[0]["cn"]), "ldaptest2computer")
2054         self.assertEquals(str(res[0]["name"]), "ldaptest2computer")
2055         self.assertEquals(list(res[0]["objectClass"]), ["top", "person", "organizationalPerson", "user", "computer"])
2056         self.assertTrue("objectGUID" in res[0])
2057         self.assertTrue("whenCreated" in res[0])
2058         self.assertEquals(res[0]["objectCategory"][0], "CN=Computer,CN=Schema,CN=Configuration," + self.base_dn)
2059         self.assertEquals(int(res[0]["sAMAccountType"][0]), ATYPE_WORKSTATION_TRUST)
2060         self.assertEquals(int(res[0]["userAccountControl"][0]), UF_WORKSTATION_TRUST_ACCOUNT)
2061
2062         ldb.delete("<SID=" + ldb.schema_format_value("objectSID", res[0]["objectSID"][0]) + ">")
2063
2064         attrs = ["cn", "name", "objectClass", "objectGUID", "objectSID", "whenCreated", "nTSecurityDescriptor", "memberOf", "allowedAttributes", "allowedAttributesEffective"]
2065         print "Testing ldb.search for (&(cn=ldaptestUSer2)(objectClass=user))"
2066         res_user = ldb.search(self.base_dn, expression="(&(cn=ldaptestUSer2)(objectClass=user))", scope=SCOPE_SUBTREE, attrs=attrs)
2067         self.assertEquals(len(res_user), 1, "Could not find (&(cn=ldaptestUSer2)(objectClass=user))")
2068
2069         self.assertEquals(str(res_user[0].dn), ("CN=ldaptestuser2,CN=Users," + self.base_dn))
2070         self.assertEquals(str(res_user[0]["cn"]), "ldaptestuser2")
2071         self.assertEquals(str(res_user[0]["name"]), "ldaptestuser2")
2072         self.assertEquals(list(res_user[0]["objectClass"]), ["top", "person", "organizationalPerson", "user"])
2073         self.assertTrue("objectSid" in res_user[0])
2074         self.assertTrue("objectGUID" in res_user[0])
2075         self.assertTrue("whenCreated" in res_user[0])
2076         self.assertTrue("nTSecurityDescriptor" in res_user[0])
2077         self.assertTrue("allowedAttributes" in res_user[0])
2078         self.assertTrue("allowedAttributesEffective" in res_user[0])
2079         self.assertEquals(res_user[0]["memberOf"][0].upper(), ("CN=ldaptestgroup2,CN=Users," + self.base_dn).upper())
2080
2081         ldaptestuser2_sid = res_user[0]["objectSid"][0]
2082         ldaptestuser2_guid = res_user[0]["objectGUID"][0]
2083
2084         attrs = ["cn", "name", "objectClass", "objectGUID", "objectSID", "whenCreated", "nTSecurityDescriptor", "member", "allowedAttributes", "allowedAttributesEffective"]
2085         print "Testing ldb.search for (&(cn=ldaptestgroup2)(objectClass=group))"
2086         res = ldb.search(self.base_dn, expression="(&(cn=ldaptestgroup2)(objectClass=group))", scope=SCOPE_SUBTREE, attrs=attrs)
2087         self.assertEquals(len(res), 1, "Could not find (&(cn=ldaptestgroup2)(objectClass=group))")
2088
2089         self.assertEquals(str(res[0].dn), ("CN=ldaptestgroup2,CN=Users," + self.base_dn))
2090         self.assertEquals(str(res[0]["cn"]), "ldaptestgroup2")
2091         self.assertEquals(str(res[0]["name"]), "ldaptestgroup2")
2092         self.assertEquals(list(res[0]["objectClass"]), ["top", "group"])
2093         self.assertTrue("objectGUID" in res[0])
2094         self.assertTrue("objectSid" in res[0])
2095         self.assertTrue("whenCreated" in res[0])
2096         self.assertTrue("nTSecurityDescriptor" in res[0])
2097         self.assertTrue("allowedAttributes" in res[0])
2098         self.assertTrue("allowedAttributesEffective" in res[0])
2099         memberUP = []
2100         for m in res[0]["member"]:
2101             memberUP.append(m.upper())
2102         self.assertTrue(("CN=ldaptestuser2,CN=Users," + self.base_dn).upper() in memberUP)
2103
2104         res = ldb.search(self.base_dn, expression="(&(cn=ldaptestgroup2)(objectClass=group))", scope=SCOPE_SUBTREE, attrs=attrs, controls=["extended_dn:1:1"])
2105         self.assertEquals(len(res), 1, "Could not find (&(cn=ldaptestgroup2)(objectClass=group))")
2106
2107         print res[0]["member"]
2108         memberUP = []
2109         for m in res[0]["member"]:
2110             memberUP.append(m.upper())
2111         print ("<GUID=" + ldb.schema_format_value("objectGUID", ldaptestuser2_guid) + ">;<SID=" + ldb.schema_format_value("objectSid", ldaptestuser2_sid) + ">;CN=ldaptestuser2,CN=Users," + self.base_dn).upper()
2112
2113         self.assertTrue(("<GUID=" + ldb.schema_format_value("objectGUID", ldaptestuser2_guid) + ">;<SID=" + ldb.schema_format_value("objectSid", ldaptestuser2_sid) + ">;CN=ldaptestuser2,CN=Users," + self.base_dn).upper() in memberUP)
2114
2115         print "Quicktest for linked attributes"
2116         ldb.modify_ldif("""
2117 dn: cn=ldaptestgroup2,cn=users,""" + self.base_dn + """
2118 changetype: modify
2119 replace: member
2120 member: CN=ldaptestuser2,CN=Users,""" + self.base_dn + """
2121 member: CN=ldaptestutf8user èùéìòà,CN=Users,""" + self.base_dn + """
2122 """)
2123
2124         ldb.modify_ldif("""
2125 dn: <GUID=""" + ldb.schema_format_value("objectGUID", res[0]["objectGUID"][0]) + """>
2126 changetype: modify
2127 replace: member
2128 member: CN=ldaptestutf8user èùéìòà,CN=Users,""" + self.base_dn + """
2129 """)
2130
2131         ldb.modify_ldif("""
2132 dn: <SID=""" + ldb.schema_format_value("objectSid", res[0]["objectSid"][0]) + """>
2133 changetype: modify
2134 delete: member
2135 """)
2136
2137         ldb.modify_ldif("""
2138 dn: cn=ldaptestgroup2,cn=users,""" + self.base_dn + """
2139 changetype: modify
2140 add: member
2141 member: <GUID=""" + ldb.schema_format_value("objectGUID", res[0]["objectGUID"][0]) + """>
2142 member: CN=ldaptestutf8user èùéìòà,CN=Users,""" + self.base_dn + """
2143 """)
2144
2145         ldb.modify_ldif("""
2146 dn: cn=ldaptestgroup2,cn=users,""" + self.base_dn + """
2147 changetype: modify
2148 replace: member
2149 """)
2150
2151         ldb.modify_ldif("""
2152 dn: cn=ldaptestgroup2,cn=users,""" + self.base_dn + """
2153 changetype: modify
2154 add: member
2155 member: <SID=""" + ldb.schema_format_value("objectSid", res_user[0]["objectSid"][0]) + """>
2156 member: CN=ldaptestutf8user èùéìòà,CN=Users,""" + self.base_dn + """
2157 """)
2158
2159         ldb.modify_ldif("""
2160 dn: cn=ldaptestgroup2,cn=users,""" + self.base_dn + """
2161 changetype: modify
2162 delete: member
2163 member: CN=ldaptestutf8user èùéìòà,CN=Users,""" + self.base_dn + """
2164 """)
2165
2166         res = ldb.search(self.base_dn, expression="(&(cn=ldaptestgroup2)(objectClass=group))", scope=SCOPE_SUBTREE, attrs=attrs)
2167         self.assertEquals(len(res), 1, "Could not find (&(cn=ldaptestgroup2)(objectClass=group))")
2168
2169         self.assertEquals(str(res[0].dn), ("CN=ldaptestgroup2,CN=Users," + self.base_dn))
2170         self.assertEquals(res[0]["member"][0], ("CN=ldaptestuser2,CN=Users," + self.base_dn))
2171         self.assertEquals(len(res[0]["member"]), 1)
2172
2173         ldb.delete(("CN=ldaptestuser2,CN=Users," + self.base_dn))
2174
2175         time.sleep(4)
2176
2177         attrs = ["cn", "name", "objectClass", "objectGUID", "whenCreated", "nTSecurityDescriptor", "member"]
2178         print "Testing ldb.search for (&(cn=ldaptestgroup2)(objectClass=group)) to check linked delete"
2179         res = ldb.search(self.base_dn, expression="(&(cn=ldaptestgroup2)(objectClass=group))", scope=SCOPE_SUBTREE, attrs=attrs)
2180         self.assertEquals(len(res), 1, "Could not find (&(cn=ldaptestgroup2)(objectClass=group)) to check linked delete")
2181
2182         self.assertEquals(str(res[0].dn), ("CN=ldaptestgroup2,CN=Users," + self.base_dn))
2183         self.assertTrue("member" not in res[0])
2184
2185         print "Testing ldb.search for (&(cn=ldaptestutf8user ÈÙÉÌÒÀ)(objectClass=user))"
2186 # TODO UTF8 users don't seem to work fully anymore
2187 #        res = ldb.search(expression="(&(cn=ldaptestutf8user ÈÙÉÌÒÀ)(objectClass=user))")
2188         res = ldb.search(expression="(&(cn=ldaptestutf8user èùéìòà)(objectclass=user))")
2189         self.assertEquals(len(res), 1, "Could not find (&(cn=ldaptestutf8user ÈÙÉÌÒÀ)(objectClass=user))")
2190
2191         self.assertEquals(str(res[0].dn), ("CN=ldaptestutf8user èùéìòà,CN=Users," + self.base_dn))
2192         self.assertEquals(str(res[0]["cn"]), "ldaptestutf8user èùéìòà")
2193         self.assertEquals(str(res[0]["name"]), "ldaptestutf8user èùéìòà")
2194         self.assertEquals(list(res[0]["objectClass"]), ["top", "person", "organizationalPerson", "user"])
2195         self.assertTrue("objectGUID" in res[0])
2196         self.assertTrue("whenCreated" in res[0])
2197
2198         ldb.delete(res[0].dn)
2199
2200         print "Testing ldb.search for (&(cn=ldaptestutf8user2*)(objectClass=user))"
2201         res = ldb.search(expression="(&(cn=ldaptestutf8user2*)(objectClass=user))")
2202         self.assertEquals(len(res), 1, "Could not find (&(cn=ldaptestutf8user2*)(objectClass=user))")
2203
2204         ldb.delete(res[0].dn)
2205
2206         ldb.delete(("CN=ldaptestgroup2,CN=Users," + self.base_dn))
2207
2208         print "Testing ldb.search for (&(cn=ldaptestutf8user2 ÈÙÉÌÒÀ)(objectClass=user))"
2209 # TODO UTF8 users don't seem to work fully anymore
2210 #        res = ldb.search(expression="(&(cn=ldaptestutf8user ÈÙÉÌÒÀ)(objectClass=user))")
2211 #        self.assertEquals(len(res), 1, "Could not find (&(cn=ldaptestutf8user ÈÙÉÌÒÀ)(objectClass=user))")
2212
2213         print "Testing that we can't get at the configuration DN from the main search base"
2214         res = ldb.search(self.base_dn, expression="objectClass=crossRef", scope=SCOPE_SUBTREE, attrs=["cn"])
2215         self.assertEquals(len(res), 0)
2216
2217         print "Testing that we can get at the configuration DN from the main search base on the LDAP port with the 'phantom root' search_options control"
2218         res = ldb.search(self.base_dn, expression="objectClass=crossRef", scope=SCOPE_SUBTREE, attrs=["cn"], controls=["search_options:1:2"])
2219         self.assertTrue(len(res) > 0)
2220
2221         if gc_ldb is not None:
2222             print "Testing that we can get at the configuration DN from the main search base on the GC port with the search_options control == 0"
2223
2224             res = gc_ldb.search(self.base_dn, expression="objectClass=crossRef", scope=SCOPE_SUBTREE, attrs=["cn"], controls=["search_options:1:0"])
2225             self.assertTrue(len(res) > 0)
2226
2227             print "Testing that we do find configuration elements in the global catlog"
2228             res = gc_ldb.search(self.base_dn, expression="objectClass=crossRef", scope=SCOPE_SUBTREE, attrs=["cn"])
2229             self.assertTrue(len(res) > 0)
2230
2231             print "Testing that we do find configuration elements and user elements at the same time"
2232             res = gc_ldb.search(self.base_dn, expression="(|(objectClass=crossRef)(objectClass=person))", scope=SCOPE_SUBTREE, attrs=["cn"])
2233             self.assertTrue(len(res) > 0)
2234
2235             print "Testing that we do find configuration elements in the global catlog, with the configuration basedn"
2236             res = gc_ldb.search(self.configuration_dn, expression="objectClass=crossRef", scope=SCOPE_SUBTREE, attrs=["cn"])
2237             self.assertTrue(len(res) > 0)
2238
2239         print "Testing that we can get at the configuration DN on the main LDAP port"
2240         res = ldb.search(self.configuration_dn, expression="objectClass=crossRef", scope=SCOPE_SUBTREE, attrs=["cn"])
2241         self.assertTrue(len(res) > 0)
2242
2243         print "Testing objectCategory canonacolisation"
2244         res = ldb.search(self.configuration_dn, expression="objectCategory=ntDsDSA", scope=SCOPE_SUBTREE, attrs=["cn"])
2245         self.assertTrue(len(res) > 0, "Didn't find any records with objectCategory=ntDsDSA")
2246         self.assertTrue(len(res) != 0)
2247
2248         res = ldb.search(self.configuration_dn, expression="objectCategory=CN=ntDs-DSA," + self.schema_dn, scope=SCOPE_SUBTREE, attrs=["cn"])
2249         self.assertTrue(len(res) > 0, "Didn't find any records with objectCategory=CN=ntDs-DSA," + self.schema_dn)
2250         self.assertTrue(len(res) != 0)
2251
2252         print "Testing objectClass attribute order on "+ self.base_dn
2253         res = ldb.search(expression="objectClass=domain", base=self.base_dn,
2254                          scope=SCOPE_BASE, attrs=["objectClass"])
2255         self.assertEquals(len(res), 1)
2256
2257         self.assertEquals(list(res[0]["objectClass"]), ["top", "domain", "domainDNS"])
2258
2259     #  check enumeration
2260
2261         print "Testing ldb.search for objectCategory=person"
2262         res = ldb.search(self.base_dn, expression="objectCategory=person", scope=SCOPE_SUBTREE, attrs=["cn"])
2263         self.assertTrue(len(res) > 0)
2264
2265         print "Testing ldb.search for objectCategory=person with domain scope control"
2266         res = ldb.search(self.base_dn, expression="objectCategory=person", scope=SCOPE_SUBTREE, attrs=["cn"], controls=["domain_scope:1"])
2267         self.assertTrue(len(res) > 0)
2268
2269         print "Testing ldb.search for objectCategory=user"
2270         res = ldb.search(self.base_dn, expression="objectCategory=user", scope=SCOPE_SUBTREE, attrs=["cn"])
2271         self.assertTrue(len(res) > 0)
2272
2273         print "Testing ldb.search for objectCategory=user with domain scope control"
2274         res = ldb.search(self.base_dn, expression="objectCategory=user", scope=SCOPE_SUBTREE, attrs=["cn"], controls=["domain_scope:1"])
2275         self.assertTrue(len(res) > 0)
2276
2277         print "Testing ldb.search for objectCategory=group"
2278         res = ldb.search(self.base_dn, expression="objectCategory=group", scope=SCOPE_SUBTREE, attrs=["cn"])
2279         self.assertTrue(len(res) > 0)
2280
2281         print "Testing ldb.search for objectCategory=group with domain scope control"
2282         res = ldb.search(self.base_dn, expression="objectCategory=group", scope=SCOPE_SUBTREE, attrs=["cn"], controls=["domain_scope:1"])
2283         self.assertTrue(len(res) > 0)
2284
2285         print "Testing creating a user with the posixAccount objectClass"
2286         self.ldb.add_ldif("""dn: cn=posixuser,CN=Users,%s
2287 objectClass: top
2288 objectClass: person
2289 objectClass: posixAccount
2290 objectClass: user
2291 objectClass: organizationalPerson
2292 cn: posixuser
2293 uid: posixuser
2294 sn: posixuser
2295 uidNumber: 10126
2296 gidNumber: 10126
2297 homeDirectory: /home/posixuser
2298 loginShell: /bin/bash
2299 gecos: Posix User;;;
2300 description: A POSIX user"""% (self.base_dn))
2301
2302         print "Testing removing the posixAccount objectClass from an existing user"
2303         self.ldb.modify_ldif("""dn: cn=posixuser,CN=Users,%s
2304 changetype: modify
2305 delete: objectClass
2306 objectClass: posixAccount"""% (self.base_dn))
2307
2308         print "Testing adding the posixAccount objectClass to an existing user"
2309         self.ldb.modify_ldif("""dn: cn=posixuser,CN=Users,%s
2310 changetype: modify
2311 add: objectClass
2312 objectClass: posixAccount"""% (self.base_dn))
2313
2314         delete_force(self.ldb, "cn=posixuser,cn=users," + self.base_dn)
2315         delete_force(self.ldb, "cn=ldaptestuser,cn=users," + self.base_dn)
2316         delete_force(self.ldb, "cn=ldaptestuser2,cn=users," + self.base_dn)
2317         delete_force(self.ldb, "cn=ldaptestuser3,cn=users," + self.base_dn)
2318         delete_force(self.ldb, "cn=ldaptestuser4,cn=ldaptestcontainer," + self.base_dn)
2319         delete_force(self.ldb, "cn=ldaptestuser4,cn=ldaptestcontainer2," + self.base_dn)
2320         delete_force(self.ldb, "cn=ldaptestuser5,cn=users," + self.base_dn)
2321         delete_force(self.ldb, "cn=ldaptestgroup,cn=users," + self.base_dn)
2322         delete_force(self.ldb, "cn=ldaptestgroup2,cn=users," + self.base_dn)
2323         delete_force(self.ldb, "cn=ldaptestcomputer,cn=computers," + self.base_dn)
2324         delete_force(self.ldb, "cn=ldaptest2computer,cn=computers," + self.base_dn)
2325         delete_force(self.ldb, "cn=ldaptestcomputer3,cn=computers," + self.base_dn)
2326         delete_force(self.ldb, "cn=ldaptestutf8user èùéìòà,cn=users," + self.base_dn)
2327         delete_force(self.ldb, "cn=ldaptestutf8user2  èùéìòà,cn=users," + self.base_dn)
2328         delete_force(self.ldb, "cn=ldaptestcontainer," + self.base_dn)
2329         delete_force(self.ldb, "cn=ldaptestcontainer2," + self.base_dn)
2330
2331     def test_security_descriptor_add(self):
2332         """ Testing ldb.add_ldif() for nTSecurityDescriptor """
2333         user_name = "testdescriptoruser1"
2334         user_dn = "CN=%s,CN=Users,%s" % (user_name, self.base_dn)
2335         #
2336         # Test an empty security descriptor (naturally this shouldn't work)
2337         #
2338         delete_force(self.ldb, user_dn)
2339         try:
2340             self.ldb.add({ "dn": user_dn,
2341                            "objectClass": "user",
2342                            "sAMAccountName": user_name,
2343                            "nTSecurityDescriptor": [] })
2344             self.fail()
2345         except LdbError, (num, _):
2346             self.assertEquals(num, ERR_CONSTRAINT_VIOLATION)
2347         finally:
2348             delete_force(self.ldb, user_dn)
2349         #
2350         # Test add_ldif() with SDDL security descriptor input
2351         #
2352         try:
2353             sddl = "O:DUG:DUD:PAI(A;;RPWP;;;AU)S:PAI"
2354             self.ldb.add_ldif("""
2355 dn: """ + user_dn + """
2356 objectclass: user
2357 sAMAccountName: """ + user_name + """
2358 nTSecurityDescriptor: """ + sddl)
2359             res = self.ldb.search(base=user_dn, attrs=["nTSecurityDescriptor"])
2360             desc = res[0]["nTSecurityDescriptor"][0]
2361             desc = ndr_unpack( security.descriptor, desc )
2362             desc_sddl = desc.as_sddl( self.domain_sid )
2363             self.assertEqual(desc_sddl, sddl)
2364         finally:
2365             delete_force(self.ldb, user_dn)
2366         #
2367         # Test add_ldif() with BASE64 security descriptor
2368         #
2369         try:
2370             sddl = "O:DUG:DUD:PAI(A;;RPWP;;;AU)S:PAI"
2371             desc = security.descriptor.from_sddl(sddl, self.domain_sid)
2372             desc_binary = ndr_pack(desc)
2373             desc_base64 = base64.b64encode(desc_binary)
2374             self.ldb.add_ldif("""
2375 dn: """ + user_dn + """
2376 objectclass: user
2377 sAMAccountName: """ + user_name + """
2378 nTSecurityDescriptor:: """ + desc_base64)
2379             res = self.ldb.search(base=user_dn, attrs=["nTSecurityDescriptor"])
2380             desc = res[0]["nTSecurityDescriptor"][0]
2381             desc = ndr_unpack(security.descriptor, desc)
2382             desc_sddl = desc.as_sddl(self.domain_sid)
2383             self.assertEqual(desc_sddl, sddl)
2384         finally:
2385             delete_force(self.ldb, user_dn)
2386
2387     def test_security_descriptor_add_neg(self):
2388         """Test add_ldif() with BASE64 security descriptor input using WRONG domain SID
2389             Negative test
2390         """
2391         user_name = "testdescriptoruser1"
2392         user_dn = "CN=%s,CN=Users,%s" % (user_name, self.base_dn)
2393         delete_force(self.ldb, user_dn)
2394         try:
2395             sddl = "O:DUG:DUD:PAI(A;;RPWP;;;AU)S:PAI"
2396             desc = security.descriptor.from_sddl(sddl, security.dom_sid('S-1-5-21'))
2397             desc_base64 = base64.b64encode( ndr_pack(desc) )
2398             self.ldb.add_ldif("""
2399 dn: """ + user_dn + """
2400 objectclass: user
2401 sAMAccountName: """ + user_name + """
2402 nTSecurityDescriptor:: """ + desc_base64)
2403             res = self.ldb.search(base=user_dn, attrs=["nTSecurityDescriptor"])
2404             self.assertTrue("nTSecurityDescriptor" in res[0])
2405         finally:
2406             delete_force(self.ldb, user_dn)
2407
2408     def test_security_descriptor_modify(self):
2409         """ Testing ldb.modify_ldif() for nTSecurityDescriptor """
2410         user_name = "testdescriptoruser2"
2411         user_dn = "CN=%s,CN=Users,%s" % (user_name, self.base_dn)
2412         #
2413         # Test an empty security descriptor (naturally this shouldn't work)
2414         #
2415         delete_force(self.ldb, user_dn)
2416         self.ldb.add({ "dn": user_dn,
2417                        "objectClass": "user",
2418                        "sAMAccountName": user_name })
2419
2420         m = Message()
2421         m.dn = Dn(ldb, user_dn)
2422         m["nTSecurityDescriptor"] = MessageElement([], FLAG_MOD_ADD,
2423                                                    "nTSecurityDescriptor")
2424         try:
2425             self.ldb.modify(m)
2426             self.fail()
2427         except LdbError, (num, _):
2428             self.assertEquals(num, ERR_CONSTRAINT_VIOLATION)
2429
2430         m = Message()
2431         m.dn = Dn(ldb, user_dn)
2432         m["nTSecurityDescriptor"] = MessageElement([], FLAG_MOD_REPLACE,
2433                                                    "nTSecurityDescriptor")
2434         try:
2435             self.ldb.modify(m)
2436             self.fail()
2437         except LdbError, (num, _):
2438             self.assertEquals(num, ERR_UNWILLING_TO_PERFORM)
2439
2440         m = Message()
2441         m.dn = Dn(ldb, user_dn)
2442         m["nTSecurityDescriptor"] = MessageElement([], FLAG_MOD_DELETE,
2443                                                    "nTSecurityDescriptor")
2444         try:
2445             self.ldb.modify(m)
2446             self.fail()
2447         except LdbError, (num, _):
2448             self.assertEquals(num, ERR_UNWILLING_TO_PERFORM)
2449
2450         delete_force(self.ldb, user_dn)
2451         #
2452         # Test modify_ldif() with SDDL security descriptor input
2453         # Add ACE to the original descriptor test
2454         #
2455         try:
2456             self.ldb.add_ldif("""
2457 dn: """ + user_dn + """
2458 objectclass: user
2459 sAMAccountName: """ + user_name)
2460             # Modify descriptor
2461             res = self.ldb.search(base=user_dn, attrs=["nTSecurityDescriptor"])
2462             desc = res[0]["nTSecurityDescriptor"][0]
2463             desc = ndr_unpack(security.descriptor, desc)
2464             desc_sddl = desc.as_sddl(self.domain_sid)
2465             sddl = desc_sddl[:desc_sddl.find("(")] + "(A;;RPWP;;;AU)" + desc_sddl[desc_sddl.find("("):]
2466             mod = """
2467 dn: """ + user_dn + """
2468 changetype: modify
2469 replace: nTSecurityDescriptor
2470 nTSecurityDescriptor: """ + sddl
2471             self.ldb.modify_ldif(mod)
2472             # Read modified descriptor
2473             res = self.ldb.search(base=user_dn, attrs=["nTSecurityDescriptor"])
2474             desc = res[0]["nTSecurityDescriptor"][0]
2475             desc = ndr_unpack(security.descriptor, desc)
2476             desc_sddl = desc.as_sddl(self.domain_sid)
2477             self.assertEqual(desc_sddl, sddl)
2478         finally:
2479             delete_force(self.ldb, user_dn)
2480         #
2481         # Test modify_ldif() with SDDL security descriptor input
2482         # New desctiptor test
2483         #
2484         try:
2485             self.ldb.add_ldif("""
2486 dn: """ + user_dn + """
2487 objectclass: user
2488 sAMAccountName: """ + user_name)
2489             # Modify descriptor
2490             sddl = "O:DUG:DUD:PAI(A;;RPWP;;;AU)S:PAI"
2491             mod = """
2492 dn: """ + user_dn + """
2493 changetype: modify
2494 replace: nTSecurityDescriptor
2495 nTSecurityDescriptor: """ + sddl
2496             self.ldb.modify_ldif(mod)
2497             # Read modified descriptor
2498             res = self.ldb.search(base=user_dn, attrs=["nTSecurityDescriptor"])
2499             desc = res[0]["nTSecurityDescriptor"][0]
2500             desc = ndr_unpack(security.descriptor, desc)
2501             desc_sddl = desc.as_sddl(self.domain_sid)
2502             self.assertEqual(desc_sddl, sddl)
2503         finally:
2504             delete_force(self.ldb, user_dn)
2505         #
2506         # Test modify_ldif() with BASE64 security descriptor input
2507         # Add ACE to the original descriptor test
2508         #
2509         try:
2510             self.ldb.add_ldif("""
2511 dn: """ + user_dn + """
2512 objectclass: user
2513 sAMAccountName: """ + user_name)
2514             # Modify descriptor
2515             res = self.ldb.search(base=user_dn, attrs=["nTSecurityDescriptor"])
2516             desc = res[0]["nTSecurityDescriptor"][0]
2517             desc = ndr_unpack(security.descriptor, desc)
2518             desc_sddl = desc.as_sddl(self.domain_sid)
2519             sddl = desc_sddl[:desc_sddl.find("(")] + "(A;;RPWP;;;AU)" + desc_sddl[desc_sddl.find("("):]
2520             desc = security.descriptor.from_sddl(sddl, self.domain_sid)
2521             desc_base64 = base64.b64encode(ndr_pack(desc))
2522             mod = """
2523 dn: """ + user_dn + """
2524 changetype: modify
2525 replace: nTSecurityDescriptor
2526 nTSecurityDescriptor:: """ + desc_base64
2527             self.ldb.modify_ldif(mod)
2528             # Read modified descriptor
2529             res = self.ldb.search(base=user_dn, attrs=["nTSecurityDescriptor"])
2530             desc = res[0]["nTSecurityDescriptor"][0]
2531             desc = ndr_unpack(security.descriptor, desc)
2532             desc_sddl = desc.as_sddl(self.domain_sid)
2533             self.assertEqual(desc_sddl, sddl)
2534         finally:
2535             delete_force(self.ldb, user_dn)
2536         #
2537         # Test modify_ldif() with BASE64 security descriptor input
2538         # New descriptor test
2539         #
2540         try:
2541             delete_force(self.ldb, user_dn)
2542             self.ldb.add_ldif("""
2543 dn: """ + user_dn + """
2544 objectclass: user
2545 sAMAccountName: """ + user_name)
2546             # Modify descriptor
2547             sddl = "O:DUG:DUD:PAI(A;;RPWP;;;AU)S:PAI"
2548             desc = security.descriptor.from_sddl(sddl, self.domain_sid)
2549             desc_base64 = base64.b64encode(ndr_pack(desc))
2550             mod = """
2551 dn: """ + user_dn + """
2552 changetype: modify
2553 replace: nTSecurityDescriptor
2554 nTSecurityDescriptor:: """ + desc_base64
2555             self.ldb.modify_ldif(mod)
2556             # Read modified descriptor
2557             res = self.ldb.search(base=user_dn, attrs=["nTSecurityDescriptor"])
2558             desc = res[0]["nTSecurityDescriptor"][0]
2559             desc = ndr_unpack(security.descriptor, desc)
2560             desc_sddl = desc.as_sddl(self.domain_sid)
2561             self.assertEqual(desc_sddl, sddl)
2562         finally:
2563             delete_force(self.ldb, user_dn)
2564
2565     def test_dsheuristics(self):
2566         """Tests the 'dSHeuristics' attribute"""
2567         print "Tests the 'dSHeuristics' attribute"""
2568
2569         # Get the current value to restore it later
2570         dsheuristics = self.ldb.get_dsheuristics()
2571         # Should not be longer than 18 chars?
2572         try:
2573             self.ldb.set_dsheuristics("123ABC-+!1asdfg@#^12")
2574         except LdbError, (num, _):
2575             self.assertEquals(num, ERR_CONSTRAINT_VIOLATION)
2576         # If it is >= 10 chars, tenthChar should be 1
2577         try:
2578             self.ldb.set_dsheuristics("00020000000002")
2579         except LdbError, (num, _):
2580             self.assertEquals(num, ERR_CONSTRAINT_VIOLATION)
2581         # apart from the above, all char values are accepted
2582         self.ldb.set_dsheuristics("123ABC-+!1asdfg@#^")
2583         self.assertEquals(self.ldb.get_dsheuristics(), "123ABC-+!1asdfg@#^")
2584         # restore old value
2585         self.ldb.set_dsheuristics(dsheuristics)
2586
2587     def test_ldapControlReturn(self):
2588         """Testing that if we request a control that return a control it
2589            really return something"""
2590         res = self.ldb.search(attrs=["cn"],
2591                               controls=["paged_result:1:10"])
2592         self.assertEquals(len(res.controls), 1)
2593         self.assertEquals(res.controls[0].oid, "1.2.840.113556.1.4.319")
2594
2595
2596 class BaseDnTests(unittest.TestCase):
2597
2598     def setUp(self):
2599         super(BaseDnTests, self).setUp()
2600         self.ldb = ldb
2601
2602     def test_rootdse_attrs(self):
2603         """Testing for all rootDSE attributes"""
2604         res = self.ldb.search(scope=SCOPE_BASE, attrs=[])
2605         self.assertEquals(len(res), 1)
2606
2607     def test_highestcommittedusn(self):
2608         """Testing for highestCommittedUSN"""
2609         res = self.ldb.search("", scope=SCOPE_BASE, attrs=["highestCommittedUSN"])
2610         self.assertEquals(len(res), 1)
2611         self.assertTrue(int(res[0]["highestCommittedUSN"][0]) != 0)
2612
2613     def test_netlogon(self):
2614         """Testing for netlogon via LDAP"""
2615         res = self.ldb.search("", scope=SCOPE_BASE, attrs=["netlogon"])
2616         self.assertEquals(len(res), 0)
2617
2618     def test_netlogon_highestcommitted_usn(self):
2619         """Testing for netlogon and highestCommittedUSN via LDAP"""
2620         res = self.ldb.search("", scope=SCOPE_BASE,
2621                 attrs=["netlogon", "highestCommittedUSN"])
2622         self.assertEquals(len(res), 0)
2623
2624     def test_namingContexts(self):
2625         """Testing for namingContexts in rootDSE"""
2626         res = self.ldb.search("", scope=SCOPE_BASE,
2627                 attrs=["namingContexts", "defaultNamingContext", "schemaNamingContext", "configurationNamingContext"])
2628         self.assertEquals(len(res), 1)
2629
2630         ncs = set([])
2631         for nc in res[0]["namingContexts"]:
2632             self.assertTrue(nc not in ncs)
2633             ncs.add(nc)
2634
2635         self.assertTrue(res[0]["defaultNamingContext"][0] in ncs)
2636         self.assertTrue(res[0]["configurationNamingContext"][0] in ncs)
2637         self.assertTrue(res[0]["schemaNamingContext"][0] in ncs)
2638
2639     def test_serverPath(self):
2640         """Testing the server paths in rootDSE"""
2641         res = self.ldb.search("", scope=SCOPE_BASE,
2642                               attrs=["dsServiceName", "serverName"])
2643         self.assertEquals(len(res), 1)
2644
2645         self.assertTrue("CN=Servers" in res[0]["dsServiceName"][0])
2646         self.assertTrue("CN=Sites" in res[0]["dsServiceName"][0])
2647         self.assertTrue("CN=NTDS Settings" in res[0]["dsServiceName"][0])
2648         self.assertTrue("CN=Servers" in res[0]["serverName"][0])
2649         self.assertTrue("CN=Sites" in res[0]["serverName"][0])
2650         self.assertFalse("CN=NTDS Settings" in res[0]["serverName"][0])
2651
2652     def test_functionality(self):
2653         """Testing the server paths in rootDSE"""
2654         res = self.ldb.search("", scope=SCOPE_BASE,
2655                               attrs=["forestFunctionality", "domainFunctionality", "domainControllerFunctionality"])
2656         self.assertEquals(len(res), 1)
2657         self.assertEquals(len(res[0]["forestFunctionality"]), 1)
2658         self.assertEquals(len(res[0]["domainFunctionality"]), 1)
2659         self.assertEquals(len(res[0]["domainControllerFunctionality"]), 1)
2660
2661         self.assertTrue(int(res[0]["forestFunctionality"][0]) <= int(res[0]["domainFunctionality"][0]))
2662         self.assertTrue(int(res[0]["domainControllerFunctionality"][0]) >= int(res[0]["domainFunctionality"][0]))
2663
2664         res2 = self.ldb.search("", scope=SCOPE_BASE,
2665                               attrs=["dsServiceName", "serverName"])
2666         self.assertEquals(len(res2), 1)
2667         self.assertEquals(len(res2[0]["dsServiceName"]), 1)
2668
2669         res3 = self.ldb.search(res2[0]["dsServiceName"][0], scope=SCOPE_BASE, attrs=["msDS-Behavior-Version"])
2670         self.assertEquals(len(res3), 1)
2671         self.assertEquals(len(res3[0]["msDS-Behavior-Version"]), 1)
2672         self.assertEquals(int(res[0]["domainControllerFunctionality"][0]), int(res3[0]["msDS-Behavior-Version"][0]))
2673
2674         res4 = self.ldb.search(ldb.domain_dn(), scope=SCOPE_BASE, attrs=["msDS-Behavior-Version"])
2675         self.assertEquals(len(res4), 1)
2676         self.assertEquals(len(res4[0]["msDS-Behavior-Version"]), 1)
2677         self.assertEquals(int(res[0]["domainFunctionality"][0]), int(res4[0]["msDS-Behavior-Version"][0]))
2678
2679         res5 = self.ldb.search("cn=partitions," + str(ldb.get_config_basedn()), scope=SCOPE_BASE, attrs=["msDS-Behavior-Version"])
2680         self.assertEquals(len(res5), 1)
2681         self.assertEquals(len(res5[0]["msDS-Behavior-Version"]), 1)
2682         self.assertEquals(int(res[0]["forestFunctionality"][0]), int(res5[0]["msDS-Behavior-Version"][0]))
2683
2684     def test_dnsHostname(self):
2685         """Testing the DNS hostname in rootDSE"""
2686         res = self.ldb.search("", scope=SCOPE_BASE,
2687                               attrs=["dnsHostName", "serverName"])
2688         self.assertEquals(len(res), 1)
2689
2690         res2 = self.ldb.search(res[0]["serverName"][0], scope=SCOPE_BASE,
2691                                attrs=["dNSHostName"])
2692         self.assertEquals(len(res2), 1)
2693
2694         self.assertEquals(res[0]["dnsHostName"][0], res2[0]["dNSHostName"][0])
2695
2696     def test_ldapServiceName(self):
2697         """Testing the ldap service name in rootDSE"""
2698         res = self.ldb.search("", scope=SCOPE_BASE,
2699                               attrs=["ldapServiceName", "dNSHostName"])
2700         self.assertEquals(len(res), 1)
2701
2702         (hostname, _, dns_domainname) = res[0]["dNSHostName"][0].partition(".")
2703         self.assertTrue(":%s$@%s" % (hostname, dns_domainname.upper())
2704                         in res[0]["ldapServiceName"][0])
2705
2706 if not "://" in host:
2707     if os.path.isfile(host):
2708         host = "tdb://%s" % host
2709     else:
2710         host = "ldap://%s" % host
2711
2712 ldb = SamDB(host, credentials=creds, session_info=system_session(lp), lp=lp)
2713 if not "tdb://" in host:
2714     gc_ldb = Ldb("%s:3268" % host, credentials=creds,
2715                  session_info=system_session(lp), lp=lp)
2716 else:
2717     gc_ldb = None
2718
2719 runner = SubunitTestRunner()
2720 rc = 0
2721 if not runner.run(unittest.makeSuite(BaseDnTests)).wasSuccessful():
2722     rc = 1
2723 if not runner.run(unittest.makeSuite(BasicTests)).wasSuccessful():
2724     rc = 1
2725 sys.exit(rc)