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