2 # -*- coding: utf-8 -*-
3 # This is a port of the original in testprogs/ejs/ldap.js
5 # Copyright (C) Jelmer Vernooij <jelmer@samba.org> 2008-2011
6 # Copyright (C) Catalyst.Net Ltd 2017
8 # This program is free software; you can redistribute it and/or modify
9 # it under the terms of the GNU General Public License as published by
10 # the Free Software Foundation; either version 3 of the License, or
11 # (at your option) any later version.
13 # This program is distributed in the hope that it will be useful,
14 # but WITHOUT ANY WARRANTY; without even the implied warranty of
15 # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
16 # GNU General Public License for more details.
18 # You should have received a copy of the GNU General Public License
19 # along with this program. If not, see <http://www.gnu.org/licenses/>.
29 sys.path.insert(0, "bin/python")
31 from samba.tests.subunitrun import TestProgram, SubunitOptions
33 import samba.getopt as options
35 from samba.auth import system_session
36 from ldb import SCOPE_ONELEVEL, SCOPE_BASE, LdbError
37 from ldb import ERR_NO_SUCH_OBJECT
38 from ldb import ERR_UNWILLING_TO_PERFORM
39 from ldb import ERR_ENTRY_ALREADY_EXISTS
40 from ldb import ERR_CONSTRAINT_VIOLATION
41 from ldb import ERR_OBJECT_CLASS_VIOLATION
42 from ldb import Message, MessageElement, Dn
43 from ldb import FLAG_MOD_REPLACE
44 from samba.samdb import SamDB
45 from samba.dsdb import DS_DOMAIN_FUNCTION_2003
46 from samba.tests import delete_force
47 from samba.ndr import ndr_unpack
48 from samba.dcerpc import drsblobs
50 parser = optparse.OptionParser("ldap_schema.py [options] <host>")
51 sambaopts = options.SambaOptions(parser)
52 parser.add_option_group(sambaopts)
53 parser.add_option_group(options.VersionOptions(parser))
54 # use command line creds if available
55 credopts = options.CredentialsOptions(parser)
56 parser.add_option_group(credopts)
57 subunitopts = SubunitOptions(parser)
58 parser.add_option_group(subunitopts)
59 opts, args = parser.parse_args()
67 lp = sambaopts.get_loadparm()
68 creds = credopts.get_credentials(lp)
71 class SchemaTests(samba.tests.TestCase):
74 super(SchemaTests, self).setUp()
75 self.ldb = SamDB(host, credentials=creds,
76 session_info=system_session(lp), lp=lp, options=ldb_options)
77 self.base_dn = self.ldb.domain_dn()
78 self.schema_dn = self.ldb.get_schema_basedn().get_linearized()
80 def test_generated_schema(self):
81 """Testing we can read the generated schema via LDAP"""
82 res = self.ldb.search("cn=aggregate,"+self.schema_dn, scope=SCOPE_BASE,
83 attrs=["objectClasses", "attributeTypes", "dITContentRules"])
84 self.assertEquals(len(res), 1)
85 self.assertTrue("dITContentRules" in res[0])
86 self.assertTrue("objectClasses" in res[0])
87 self.assertTrue("attributeTypes" in res[0])
89 def test_generated_schema_is_operational(self):
90 """Testing we don't get the generated schema via LDAP by default"""
91 # Must keep the "*" form
92 res = self.ldb.search("cn=aggregate,"+self.schema_dn, scope=SCOPE_BASE,
94 self.assertEquals(len(res), 1)
95 self.assertFalse("dITContentRules" in res[0])
96 self.assertFalse("objectClasses" in res[0])
97 self.assertFalse("attributeTypes" in res[0])
99 def test_schemaUpdateNow(self):
100 """Testing schemaUpdateNow"""
101 rand = str(random.randint(1,100000))
102 attr_name = "test-Attr" + time.strftime("%s", time.gmtime()) + "-" + rand
103 attr_ldap_display_name = attr_name.replace("-", "")
106 dn: CN=%s,%s""" % (attr_name, self.schema_dn) + """
108 objectClass: attributeSchema
109 adminDescription: """ + attr_name + """
110 adminDisplayName: """ + attr_name + """
111 cn: """ + attr_name + """
112 attributeId: 1.3.6.1.4.1.7165.4.6.1.6.1.""" + rand + """
113 attributeSyntax: 2.5.5.12
119 self.ldb.add_ldif(ldif)
120 # We must do a schemaUpdateNow otherwise it's not 100% sure that the schema
121 # will contain the new attribute
128 self.ldb.modify_ldif(ldif)
130 # Search for created attribute
132 res = self.ldb.search("cn=%s,%s" % (attr_name, self.schema_dn), scope=SCOPE_BASE,
133 attrs=["lDAPDisplayName","schemaIDGUID", "msDS-IntID"])
134 self.assertEquals(len(res), 1)
135 self.assertEquals(res[0]["lDAPDisplayName"][0], attr_ldap_display_name)
136 self.assertTrue("schemaIDGUID" in res[0])
137 if "msDS-IntId" in res[0]:
138 msDS_IntId = int(res[0]["msDS-IntId"][0])
140 msDS_IntId += (1 << 32)
144 class_name = "test-Class" + time.strftime("%s", time.gmtime())
145 class_ldap_display_name = class_name.replace("-", "")
147 # First try to create a class with a wrong "defaultObjectCategory"
149 dn: CN=%s,%s""" % (class_name, self.schema_dn) + """
151 objectClass: classSchema
152 defaultObjectCategory: CN=_
153 adminDescription: """ + class_name + """
154 adminDisplayName: """ + class_name + """
155 cn: """ + class_name + """
156 governsId: 1.3.6.1.4.1.7165.4.6.2.6.1.""" + str(random.randint(1,100000)) + """
158 objectClassCategory: 1
159 subClassOf: organizationalPerson
162 systemMustContain: cn
163 systemMustContain: """ + attr_ldap_display_name + """
167 self.ldb.add_ldif(ldif)
169 except LdbError as e1:
171 self.assertEquals(num, ERR_CONSTRAINT_VIOLATION)
174 dn: CN=%s,%s""" % (class_name, self.schema_dn) + """
176 objectClass: classSchema
177 adminDescription: """ + class_name + """
178 adminDisplayName: """ + class_name + """
179 cn: """ + class_name + """
180 governsId: 1.3.6.1.4.1.7165.4.6.2.6.2.""" + str(random.randint(1,100000)) + """
182 objectClassCategory: 1
183 subClassOf: organizationalPerson
186 systemMustContain: cn
187 systemMustContain: """ + attr_ldap_display_name + """
190 self.ldb.add_ldif(ldif)
192 # Search for created objectclass
194 res = self.ldb.search("cn=%s,%s" % (class_name, self.schema_dn), scope=SCOPE_BASE,
195 attrs=["lDAPDisplayName", "defaultObjectCategory", "schemaIDGUID", "distinguishedName"])
196 self.assertEquals(len(res), 1)
197 self.assertEquals(res[0]["lDAPDisplayName"][0], class_ldap_display_name)
198 self.assertEquals(res[0]["defaultObjectCategory"][0], res[0]["distinguishedName"][0])
199 self.assertTrue("schemaIDGUID" in res[0])
207 self.ldb.modify_ldif(ldif)
209 object_name = "obj" + time.strftime("%s", time.gmtime())
212 dn: CN=%s,CN=Users,%s"""% (object_name, self.base_dn) + """
213 objectClass: organizationalPerson
215 objectClass: """ + class_ldap_display_name + """
217 cn: """ + object_name + """
219 objectCategory: CN=%s,%s"""% (class_name, self.schema_dn) + """
220 distinguishedName: CN=%s,CN=Users,%s"""% (object_name, self.base_dn) + """
221 name: """ + object_name + """
222 """ + attr_ldap_display_name + """: test
224 self.ldb.add_ldif(ldif)
226 # Search for created object
227 obj_res = self.ldb.search("cn=%s,cn=Users,%s" % (object_name, self.base_dn), scope=SCOPE_BASE, attrs=["replPropertyMetaData"])
229 self.assertEquals(len(obj_res), 1)
230 self.assertTrue("replPropertyMetaData" in obj_res[0])
231 val = obj_res[0]["replPropertyMetaData"][0]
232 repl = ndr_unpack(drsblobs.replPropertyMetaDataBlob, str(val))
235 # Windows 2000 functional level won't have this. It is too
236 # hard to work it out from the prefixmap however, so we skip
237 # this test in that case.
238 if msDS_IntId is not None:
240 for o in repl.ctr.array:
241 if o.attid == msDS_IntId:
244 self.assertTrue(found, "Did not find 0x%08x in replPropertyMetaData" % msDS_IntId)
246 delete_force(self.ldb, "cn=%s,cn=Users,%s" % (object_name, self.base_dn))
248 def test_subClassOf(self):
249 """ Testing usage of custom child schamaClass
252 class_name = "my-Class" + time.strftime("%s", time.gmtime())
253 class_ldap_display_name = class_name.replace("-", "")
256 dn: CN=%s,%s""" % (class_name, self.schema_dn) + """
258 objectClass: classSchema
259 adminDescription: """ + class_name + """
260 adminDisplayName: """ + class_name + """
261 cn: """ + class_name + """
262 governsId: 1.3.6.1.4.1.7165.4.6.2.6.3.""" + str(random.randint(1,100000)) + """
264 objectClassCategory: 1
265 subClassOf: organizationalUnit
269 self.ldb.add_ldif(ldif)
271 # Search for created objectclass
273 res = self.ldb.search("cn=%s,%s" % (class_name, self.schema_dn), scope=SCOPE_BASE,
274 attrs=["lDAPDisplayName", "defaultObjectCategory",
275 "schemaIDGUID", "distinguishedName"])
276 self.assertEquals(len(res), 1)
277 self.assertEquals(res[0]["lDAPDisplayName"][0], class_ldap_display_name)
278 self.assertEquals(res[0]["defaultObjectCategory"][0], res[0]["distinguishedName"][0])
279 self.assertTrue("schemaIDGUID" in res[0])
287 self.ldb.modify_ldif(ldif)
289 object_name = "org" + time.strftime("%s", time.gmtime())
292 dn: OU=%s,%s""" % (object_name, self.base_dn) + """
293 objectClass: """ + class_ldap_display_name + """
294 ou: """ + object_name + """
297 self.ldb.add_ldif(ldif)
299 # Search for created object
301 res = self.ldb.search("ou=%s,%s" % (object_name, self.base_dn), scope=SCOPE_BASE, attrs=["dn"])
302 self.assertEquals(len(res), 1)
304 delete_force(self.ldb, "ou=%s,%s" % (object_name, self.base_dn))
307 def test_duplicate_attributeID(self):
308 """Testing creating a duplicate attribute"""
309 rand = str(random.randint(1,100000))
310 attr_name = "test-Attr" + time.strftime("%s", time.gmtime()) + "-" + rand
311 attr_ldap_display_name = attr_name.replace("-", "")
312 attributeID = "1.3.6.1.4.1.7165.4.6.1.6.2." + rand
314 dn: CN=%s,%s""" % (attr_name, self.schema_dn) + """
316 objectClass: attributeSchema
317 adminDescription: """ + attr_name + """
318 adminDisplayName: """ + attr_name + """
319 cn: """ + attr_name + """
320 attributeId: """ + attributeID + """
321 attributeSyntax: 2.5.5.12
327 self.ldb.add_ldif(ldif)
330 dn: CN=%s-dup,%s""" % (attr_name, self.schema_dn) + """
332 objectClass: attributeSchema
333 adminDescription: """ + attr_name + """dup
334 adminDisplayName: """ + attr_name + """dup
335 cn: """ + attr_name + """-dup
336 attributeId: """ + attributeID + """
337 attributeSyntax: 2.5.5.12
344 self.ldb.add_ldif(ldif)
345 self.fail("Should have failed to add duplicate attributeID value")
346 except LdbError as e2:
347 (enum, estr) = e2.args
348 self.assertEquals(enum, ERR_UNWILLING_TO_PERFORM)
351 def test_duplicate_attributeID_governsID(self):
352 """Testing creating a duplicate attribute and class"""
353 rand = str(random.randint(1,100000))
354 attr_name = "test-Attr" + time.strftime("%s", time.gmtime()) + "-" + rand
355 attr_ldap_display_name = attr_name.replace("-", "")
356 attributeID = "1.3.6.1.4.1.7165.4.6.1.6.3." + rand
358 dn: CN=%s,%s""" % (attr_name, self.schema_dn) + """
360 objectClass: attributeSchema
361 adminDescription: """ + attr_name + """
362 adminDisplayName: """ + attr_name + """
363 cn: """ + attr_name + """
364 attributeId: """ + attributeID + """
365 attributeSyntax: 2.5.5.12
371 self.ldb.add_ldif(ldif)
374 dn: CN=%s-dup,%s""" % (attr_name, self.schema_dn) + """
376 objectClass: classSchema
377 adminDescription: """ + attr_name + """dup
378 adminDisplayName: """ + attr_name + """dup
379 cn: """ + attr_name + """-dup
380 governsId: """ + attributeID + """
382 objectClassCategory: 1
383 subClassOf: organizationalPerson
385 systemMustContain: cn
389 self.ldb.add_ldif(ldif)
390 self.fail("Should have failed to add duplicate governsID conflicting with attributeID value")
391 except LdbError as e3:
392 (enum, estr) = e3.args
393 self.assertEquals(enum, ERR_UNWILLING_TO_PERFORM)
396 def test_duplicate_cn(self):
397 """Testing creating a duplicate attribute"""
398 rand = str(random.randint(1,100000))
399 attr_name = "test-Attr" + time.strftime("%s", time.gmtime()) + "-" + rand
400 attr_ldap_display_name = attr_name.replace("-", "")
401 attributeID = "1.3.6.1.4.1.7165.4.6.1.6.4." + rand
403 dn: CN=%s,%s""" % (attr_name, self.schema_dn) + """
405 objectClass: attributeSchema
406 adminDescription: """ + attr_name + """
407 adminDisplayName: """ + attr_name + """
408 cn: """ + attr_name + """
409 attributeId: """ + attributeID + """
410 attributeSyntax: 2.5.5.12
416 self.ldb.add_ldif(ldif)
419 dn: CN=%s,%s""" % (attr_name, self.schema_dn) + """
421 objectClass: attributeSchema
422 adminDescription: """ + attr_name + """dup
423 adminDisplayName: """ + attr_name + """dup
424 cn: """ + attr_name + """
425 attributeId: """ + attributeID + """.1
426 attributeSyntax: 2.5.5.12
433 self.ldb.add_ldif(ldif)
434 self.fail("Should have failed to add attribute with duplicate CN")
435 except LdbError as e4:
436 (enum, estr) = e4.args
437 self.assertEquals(enum, ERR_ENTRY_ALREADY_EXISTS)
439 def test_duplicate_implicit_ldapdisplayname(self):
440 """Testing creating a duplicate attribute ldapdisplayname"""
441 rand = str(random.randint(1,100000))
442 attr_name = "test-Attr" + time.strftime("%s", time.gmtime()) + "-" + rand
443 attr_ldap_display_name = attr_name.replace("-", "")
444 attributeID = "1.3.6.1.4.1.7165.4.6.1.6.5." + rand
446 dn: CN=%s,%s""" % (attr_name, self.schema_dn) + """
448 objectClass: attributeSchema
449 adminDescription: """ + attr_name + """
450 adminDisplayName: """ + attr_name + """
451 cn: """ + attr_name + """
452 attributeId: """ + attributeID + """
453 attributeSyntax: 2.5.5.12
459 self.ldb.add_ldif(ldif)
462 dn: CN=%s-dup,%s""" % (attr_name, self.schema_dn) + """
464 objectClass: attributeSchema
465 adminDescription: """ + attr_name + """dup
466 adminDisplayName: """ + attr_name + """dup
467 cn: """ + attr_name + """-dup
468 ldapDisplayName: """ + attr_ldap_display_name + """
469 attributeId: """ + attributeID + """.1
470 attributeSyntax: 2.5.5.12
477 self.ldb.add_ldif(ldif)
478 self.fail("Should have failed to add attribute with duplicate of the implicit ldapDisplayName")
479 except LdbError as e5:
480 (enum, estr) = e5.args
481 self.assertEquals(enum, ERR_UNWILLING_TO_PERFORM)
484 def test_duplicate_explicit_ldapdisplayname(self):
485 """Testing creating a duplicate attribute ldapdisplayname"""
486 rand = str(random.randint(1,100000))
487 attr_name = "test-Attr" + time.strftime("%s", time.gmtime()) + "-" + rand
488 attr_ldap_display_name = attr_name.replace("-", "")
489 attributeID = "1.3.6.1.4.1.7165.4.6.1.6.6." + rand
491 dn: CN=%s,%s""" % (attr_name, self.schema_dn) + """
493 objectClass: attributeSchema
494 adminDescription: """ + attr_name + """
495 adminDisplayName: """ + attr_name + """
496 cn: """ + attr_name + """
497 attributeId: """ + attributeID + """
498 attributeSyntax: 2.5.5.12
499 ldapDisplayName: """ + attr_ldap_display_name + """
505 self.ldb.add_ldif(ldif)
508 dn: CN=%s-dup,%s""" % (attr_name, self.schema_dn) + """
510 objectClass: attributeSchema
511 adminDescription: """ + attr_name + """dup
512 adminDisplayName: """ + attr_name + """dup
513 cn: """ + attr_name + """-dup
514 ldapDisplayName: """ + attr_ldap_display_name + """
515 attributeId: """ + attributeID + """.1
516 attributeSyntax: 2.5.5.12
523 self.ldb.add_ldif(ldif)
524 self.fail("Should have failed to add attribute with duplicate ldapDisplayName")
525 except LdbError as e6:
526 (enum, estr) = e6.args
527 self.assertEquals(enum, ERR_UNWILLING_TO_PERFORM)
530 def test_duplicate_explicit_ldapdisplayname_with_class(self):
531 """Testing creating a duplicate attribute ldapdisplayname between
532 and attribute and a class"""
533 rand = str(random.randint(1,100000))
534 attr_name = "test-Attr" + time.strftime("%s", time.gmtime()) + "-" + rand
535 attr_ldap_display_name = attr_name.replace("-", "")
536 attributeID = "1.3.6.1.4.1.7165.4.6.1.6.7." + rand
537 governsID = "1.3.6.1.4.1.7165.4.6.2.6.4." + rand
539 dn: CN=%s,%s""" % (attr_name, self.schema_dn) + """
541 objectClass: attributeSchema
542 adminDescription: """ + attr_name + """
543 adminDisplayName: """ + attr_name + """
544 cn: """ + attr_name + """
545 attributeId: """ + attributeID + """
546 attributeSyntax: 2.5.5.12
547 ldapDisplayName: """ + attr_ldap_display_name + """
553 self.ldb.add_ldif(ldif)
556 dn: CN=%s-dup,%s""" % (attr_name, self.schema_dn) + """
558 objectClass: classSchema
559 adminDescription: """ + attr_name + """dup
560 adminDisplayName: """ + attr_name + """dup
561 cn: """ + attr_name + """-dup
562 ldapDisplayName: """ + attr_ldap_display_name + """
563 governsID: """ + governsID + """
565 objectClassCategory: 1
566 subClassOf: organizationalPerson
568 systemMustContain: cn
572 self.ldb.add_ldif(ldif)
573 self.fail("Should have failed to add class with duplicate ldapDisplayName")
574 except LdbError as e7:
575 (enum, estr) = e7.args
576 self.assertEquals(enum, ERR_UNWILLING_TO_PERFORM)
579 def test_duplicate_via_rename_ldapdisplayname(self):
580 """Testing creating a duplicate attribute ldapdisplayname"""
581 rand = str(random.randint(1,100000))
582 attr_name = "test-Attr" + time.strftime("%s", time.gmtime()) + "-" + rand
583 attr_ldap_display_name = attr_name.replace("-", "")
584 attributeID = "1.3.6.1.4.1.7165.4.6.1.6.8." + rand
586 dn: CN=%s,%s""" % (attr_name, self.schema_dn) + """
588 objectClass: attributeSchema
589 adminDescription: """ + attr_name + """
590 adminDisplayName: """ + attr_name + """
591 cn: """ + attr_name + """
592 attributeId: """ + attributeID + """
593 attributeSyntax: 2.5.5.12
594 ldapDisplayName: """ + attr_ldap_display_name + """
600 self.ldb.add_ldif(ldif)
603 dn: CN=%s-dup,%s""" % (attr_name, self.schema_dn) + """
605 objectClass: attributeSchema
606 adminDescription: """ + attr_name + """dup
607 adminDisplayName: """ + attr_name + """dup
608 cn: """ + attr_name + """-dup
609 ldapDisplayName: """ + attr_ldap_display_name + """dup
610 attributeId: """ + attributeID + """.1
611 attributeSyntax: 2.5.5.12
617 self.ldb.add_ldif(ldif)
620 dn: CN=%s-dup,%s""" % (attr_name, self.schema_dn) + """
622 replace: ldapDisplayName
623 ldapDisplayName: """ + attr_ldap_display_name + """
627 self.ldb.modify_ldif(ldif)
628 self.fail("Should have failed to modify schema to have attribute with duplicate ldapDisplayName")
629 except LdbError as e8:
630 (enum, estr) = e8.args
631 self.assertEquals(enum, ERR_UNWILLING_TO_PERFORM)
634 def test_duplicate_via_rename_attributeID(self):
635 """Testing creating a duplicate attributeID"""
636 rand = str(random.randint(1,100000))
637 attr_name = "test-Attr" + time.strftime("%s", time.gmtime()) + "-" + rand
638 attr_ldap_display_name = attr_name.replace("-", "")
639 attributeID = "1.3.6.1.4.1.7165.4.6.1.6.9." + rand
641 dn: CN=%s,%s""" % (attr_name, self.schema_dn) + """
643 objectClass: attributeSchema
644 adminDescription: """ + attr_name + """
645 adminDisplayName: """ + attr_name + """
646 cn: """ + attr_name + """
647 attributeId: """ + attributeID + """
648 attributeSyntax: 2.5.5.12
649 ldapDisplayName: """ + attr_ldap_display_name + """
655 self.ldb.add_ldif(ldif)
658 dn: CN=%s-dup,%s""" % (attr_name, self.schema_dn) + """
660 objectClass: attributeSchema
661 adminDescription: """ + attr_name + """dup
662 adminDisplayName: """ + attr_name + """dup
663 cn: """ + attr_name + """-dup
664 ldapDisplayName: """ + attr_ldap_display_name + """dup
665 attributeId: """ + attributeID + """.1
666 attributeSyntax: 2.5.5.12
672 self.ldb.add_ldif(ldif)
675 dn: CN=%s-dup,%s""" % (attr_name, self.schema_dn) + """
678 attributeId: """ + attributeID + """
682 self.ldb.modify_ldif(ldif)
683 self.fail("Should have failed to modify schema to have attribute with duplicate attributeID")
684 except LdbError as e9:
685 (enum, estr) = e9.args
686 self.assertEquals(enum, ERR_CONSTRAINT_VIOLATION)
688 def test_remove_ldapdisplayname(self):
689 """Testing removing the ldapdisplayname"""
690 rand = str(random.randint(1,100000))
691 attr_name = "test-Attr" + time.strftime("%s", time.gmtime()) + "-" + rand
692 attr_ldap_display_name = attr_name.replace("-", "")
693 attributeID = "1.3.6.1.4.1.7165.4.6.1.6.10." + rand
695 dn: CN=%s,%s""" % (attr_name, self.schema_dn) + """
697 objectClass: attributeSchema
698 adminDescription: """ + attr_name + """
699 adminDisplayName: """ + attr_name + """
700 cn: """ + attr_name + """
701 attributeId: """ + attributeID + """
702 attributeSyntax: 2.5.5.12
703 ldapDisplayName: """ + attr_ldap_display_name + """
709 self.ldb.add_ldif(ldif)
712 dn: CN=%s,%s""" % (attr_name, self.schema_dn) + """
714 replace: ldapDisplayName
718 self.ldb.modify_ldif(ldif)
719 self.fail("Should have failed to remove the ldapdisplayname")
720 except LdbError as e10:
721 (enum, estr) = e10.args
722 self.assertEquals(enum, ERR_OBJECT_CLASS_VIOLATION)
724 def test_rename_ldapdisplayname(self):
725 """Testing renaming ldapdisplayname"""
726 rand = str(random.randint(1,100000))
727 attr_name = "test-Attr" + time.strftime("%s", time.gmtime()) + "-" + rand
728 attr_ldap_display_name = attr_name.replace("-", "")
729 attributeID = "1.3.6.1.4.1.7165.4.6.1.6.11." + rand
731 dn: CN=%s,%s""" % (attr_name, self.schema_dn) + """
733 objectClass: attributeSchema
734 adminDescription: """ + attr_name + """
735 adminDisplayName: """ + attr_name + """
736 cn: """ + attr_name + """
737 attributeId: """ + attributeID + """
738 attributeSyntax: 2.5.5.12
739 ldapDisplayName: """ + attr_ldap_display_name + """
745 self.ldb.add_ldif(ldif)
748 dn: CN=%s,%s""" % (attr_name, self.schema_dn) + """
750 replace: ldapDisplayName
751 ldapDisplayName: """ + attr_ldap_display_name + """2
754 self.ldb.modify_ldif(ldif)
757 def test_change_attributeID(self):
758 """Testing change the attributeID"""
759 rand = str(random.randint(1,100000))
760 attr_name = "test-Attr" + time.strftime("%s", time.gmtime()) + "-" + rand
761 attr_ldap_display_name = attr_name.replace("-", "")
762 attributeID = "1.3.6.1.4.1.7165.4.6.1.6.12." + rand
764 dn: CN=%s,%s""" % (attr_name, self.schema_dn) + """
766 objectClass: attributeSchema
767 adminDescription: """ + attr_name + """
768 adminDisplayName: """ + attr_name + """
769 cn: """ + attr_name + """
770 attributeId: """ + attributeID + """
771 attributeSyntax: 2.5.5.12
772 ldapDisplayName: """ + attr_ldap_display_name + """
778 self.ldb.add_ldif(ldif)
781 dn: CN=%s,%s""" % (attr_name, self.schema_dn) + """
784 attributeId: """ + attributeID + """.1
788 self.ldb.modify_ldif(ldif)
789 self.fail("Should have failed to modify schema to have different attributeID")
790 except LdbError as e11:
791 (enum, estr) = e11.args
792 self.assertEquals(enum, ERR_CONSTRAINT_VIOLATION)
795 def test_change_attributeID_same(self):
796 """Testing change the attributeID to the same value"""
797 rand = str(random.randint(1,100000))
798 attr_name = "test-Attr" + time.strftime("%s", time.gmtime()) + "-" + rand
799 attr_ldap_display_name = attr_name.replace("-", "")
800 attributeID = "1.3.6.1.4.1.7165.4.6.1.6.13." + rand
802 dn: CN=%s,%s""" % (attr_name, self.schema_dn) + """
804 objectClass: attributeSchema
805 adminDescription: """ + attr_name + """
806 adminDisplayName: """ + attr_name + """
807 cn: """ + attr_name + """
808 attributeId: """ + attributeID + """
809 attributeSyntax: 2.5.5.12
810 ldapDisplayName: """ + attr_ldap_display_name + """
816 self.ldb.add_ldif(ldif)
819 dn: CN=%s,%s""" % (attr_name, self.schema_dn) + """
822 attributeId: """ + attributeID + """
826 self.ldb.modify_ldif(ldif)
827 self.fail("Should have failed to modify schema to have the same attributeID")
828 except LdbError as e12:
829 (enum, estr) = e12.args
830 self.assertEquals(enum, ERR_CONSTRAINT_VIOLATION)
833 def test_generated_linkID(self):
835 Test that we automatically generate a linkID if the
836 OID "1.2.840.113556.1.2.50" is given as the linkID
837 of a new attribute, and that we don't get/can't add
838 duplicate linkIDs. Also test that we can add a backlink
839 by providing the attributeID or ldapDisplayName of
840 a forwards link in the linkID attribute.
843 # linkID generation isn't available before 2003
844 res = self.ldb.search(base="", expression="", scope=SCOPE_BASE,
845 attrs=["domainControllerFunctionality"])
846 self.assertEquals(len(res), 1)
847 dc_level = int(res[0]["domainControllerFunctionality"][0])
848 if dc_level < DS_DOMAIN_FUNCTION_2003:
851 rand = str(random.randint(1,100000))
853 attr_name_1 = "test-generated-linkID" + time.strftime("%s", time.gmtime()) + "-" + rand
854 attr_ldap_display_name_1 = attr_name_1.replace("-", "")
855 attributeID_1 = "1.3.6.1.4.1.7165.4.6.1.6.16." + rand
857 dn: CN=%s,%s""" % (attr_name_1, self.schema_dn) + """
859 objectClass: attributeSchema
860 adminDescription: """ + attr_name_1 + """
861 adminDisplayName: """ + attr_name_1 + """
862 cn: """ + attr_name_1 + """
863 attributeId: """ + attributeID_1 + """
864 linkID: 1.2.840.113556.1.2.50
865 attributeSyntax: 2.5.5.1
866 ldapDisplayName: """ + attr_ldap_display_name_1 + """
874 self.ldb.add_ldif(ldif)
875 except LdbError as e13:
876 (enum, estr) = e13.args
879 attr_name_2 = "test-generated-linkID-2" + time.strftime("%s", time.gmtime()) + "-" + rand
880 attr_ldap_display_name_2 = attr_name_2.replace("-", "")
881 attributeID_2 = "1.3.6.1.4.1.7165.4.6.1.6.17." + rand
883 dn: CN=%s,%s""" % (attr_name_2, self.schema_dn) + """
885 objectClass: attributeSchema
886 adminDescription: """ + attr_name_2 + """
887 adminDisplayName: """ + attr_name_2 + """
888 cn: """ + attr_name_2 + """
889 attributeId: """ + attributeID_2 + """
890 linkID: 1.2.840.113556.1.2.50
891 attributeSyntax: 2.5.5.1
892 ldapDisplayName: """ + attr_ldap_display_name_2 + """
900 self.ldb.add_ldif(ldif)
901 except LdbError as e14:
902 (enum, estr) = e14.args
905 res = self.ldb.search("CN=%s,%s" % (attr_name_1, self.schema_dn),
908 self.assertEquals(len(res), 1)
909 linkID_1 = int(res[0]["linkID"][0])
911 res = self.ldb.search("CN=%s,%s" % (attr_name_2, self.schema_dn),
914 self.assertEquals(len(res), 1)
915 linkID_2 = int(res[0]["linkID"][0])
917 # 0 should never be generated as a linkID
918 self.assertFalse(linkID_1 == 0)
919 self.assertFalse(linkID_2 == 0)
921 # The generated linkID should always be even, because
922 # it should assume we're adding a forward link.
923 self.assertTrue(linkID_1 % 2 == 0)
924 self.assertTrue(linkID_2 % 2 == 0)
926 self.assertFalse(linkID_1 == linkID_2)
928 # This is only necessary against Windows, since we depend
929 # on the previously added links in the next ones and Windows
930 # won't refresh the schema as we add them.
934 replace: schemaupdatenow
937 self.ldb.modify_ldif(ldif)
939 # If we add a new link with the same linkID, it should fail
940 attr_name = "test-generated-linkID-duplicate" + time.strftime("%s", time.gmtime()) + "-" + rand
941 attr_ldap_display_name = attr_name.replace("-", "")
942 attributeID = "1.3.6.1.4.1.7165.4.6.1.6.18." + rand
944 dn: CN=%s,%s""" % (attr_name, self.schema_dn) + """
946 objectClass: attributeSchema
947 adminDescription: """ + attr_name + """
948 adminDisplayName: """ + attr_name + """
949 cn: """ + attr_name + """
950 attributeId: """ + attributeID + """
951 linkID: """ + str(linkID_1) + """
952 attributeSyntax: 2.5.5.1
953 ldapDisplayName: """ + attr_ldap_display_name + """
961 self.ldb.add_ldif(ldif)
962 self.fail("Should have failed to add duplicate linkID value")
963 except LdbError as e15:
964 (enum, estr) = e15.args
965 self.assertEquals(enum, ERR_UNWILLING_TO_PERFORM)
967 # If we add another attribute with the attributeID or lDAPDisplayName
968 # of a forward link in its linkID field, it should add as a backlink
970 attr_name_3 = "test-generated-linkID-backlink" + time.strftime("%s", time.gmtime()) + "-" + rand
971 attr_ldap_display_name_3 = attr_name_3.replace("-", "")
972 attributeID_3 = "1.3.6.1.4.1.7165.4.6.1.6.19." + rand
974 dn: CN=%s,%s""" % (attr_name_3, self.schema_dn) + """
976 objectClass: attributeSchema
977 adminDescription: """ + attr_name_3 + """
978 adminDisplayName: """ + attr_name_3 + """
979 cn: """ + attr_name_3 + """
980 attributeId: """ + attributeID_3 + """
981 linkID: """ + str(linkID_1+1) + """
982 attributeSyntax: 2.5.5.1
983 ldapDisplayName: """ + attr_ldap_display_name_3 + """
991 self.ldb.add_ldif(ldif)
992 except LdbError as e16:
993 (enum, estr) = e16.args
996 res = self.ldb.search("CN=%s,%s" % (attr_name_3, self.schema_dn),
999 self.assertEquals(len(res), 1)
1000 linkID = int(res[0]["linkID"][0])
1001 self.assertEquals(linkID, linkID_1 + 1)
1003 attr_name_4 = "test-generated-linkID-backlink-2" + time.strftime("%s", time.gmtime()) + "-" + rand
1004 attr_ldap_display_name_4 = attr_name_4.replace("-", "")
1005 attributeID_4 = "1.3.6.1.4.1.7165.4.6.1.6.20." + rand
1007 dn: CN=%s,%s""" % (attr_name_4, self.schema_dn) + """
1009 objectClass: attributeSchema
1010 adminDescription: """ + attr_name_4 + """
1011 adminDisplayName: """ + attr_name_4 + """
1012 cn: """ + attr_name_4 + """
1013 attributeId: """ + attributeID_4 + """
1014 linkID: """ + attr_ldap_display_name_2 + """
1015 attributeSyntax: 2.5.5.1
1016 ldapDisplayName: """ + attr_ldap_display_name_4 + """
1019 isSingleValued: TRUE
1024 self.ldb.add_ldif(ldif)
1025 except LdbError as e17:
1026 (enum, estr) = e17.args
1029 res = self.ldb.search("CN=%s,%s" % (attr_name_4, self.schema_dn),
1032 self.assertEquals(len(res), 1)
1033 linkID = int(res[0]["linkID"][0])
1034 self.assertEquals(linkID, linkID_2 + 1)
1036 # If we then try to add another backlink in the same way
1037 # for the same forwards link, we should fail.
1039 attr_name = "test-generated-linkID-backlink-duplicate" + time.strftime("%s", time.gmtime()) + "-" + rand
1040 attr_ldap_display_name = attr_name.replace("-", "")
1041 attributeID = "1.3.6.1.4.1.7165.4.6.1.6.21." + rand
1043 dn: CN=%s,%s""" % (attr_name, self.schema_dn) + """
1045 objectClass: attributeSchema
1046 adminDescription: """ + attr_name + """
1047 adminDisplayName: """ + attr_name + """
1048 cn: """ + attr_name + """
1049 attributeId: """ + attributeID + """
1050 linkID: """ + attributeID_1 + """
1051 attributeSyntax: 2.5.5.1
1052 ldapDisplayName: """ + attr_ldap_display_name + """
1055 isSingleValued: TRUE
1060 self.ldb.add_ldif(ldif)
1061 self.fail("Should have failed to add duplicate backlink")
1062 except LdbError as e18:
1063 (enum, estr) = e18.args
1064 self.assertEquals(enum, ERR_UNWILLING_TO_PERFORM)
1066 # If we try to supply the attributeID or ldapDisplayName
1067 # of an existing backlink in the linkID field of a new link,
1070 attr_name = "test-generated-linkID-backlink-invalid" + time.strftime("%s", time.gmtime()) + "-" + rand
1071 attr_ldap_display_name = attr_name.replace("-", "")
1072 attributeID = "1.3.6.1.4.1.7165.4.6.1.6.22." + rand
1074 dn: CN=%s,%s""" % (attr_name, self.schema_dn) + """
1076 objectClass: attributeSchema
1077 adminDescription: """ + attr_name + """
1078 adminDisplayName: """ + attr_name + """
1079 cn: """ + attr_name + """
1080 attributeId: """ + attributeID + """
1081 linkID: """ + attributeID_3 + """
1082 attributeSyntax: 2.5.5.1
1083 ldapDisplayName: """ + attr_ldap_display_name + """
1086 isSingleValued: TRUE
1091 self.ldb.add_ldif(ldif)
1092 self.fail("Should have failed to add backlink of backlink")
1093 except LdbError as e19:
1094 (enum, estr) = e19.args
1095 self.assertEquals(enum, ERR_UNWILLING_TO_PERFORM)
1097 attr_name = "test-generated-linkID-backlink-invalid-2" + time.strftime("%s", time.gmtime()) + "-" + rand
1098 attr_ldap_display_name = attr_name.replace("-", "")
1099 attributeID = "1.3.6.1.4.1.7165.4.6.1.6.23." + rand
1101 dn: CN=%s,%s""" % (attr_name, self.schema_dn) + """
1103 objectClass: attributeSchema
1104 adminDescription: """ + attr_name + """
1105 adminDisplayName: """ + attr_name + """
1106 cn: """ + attr_name + """
1107 attributeId: """ + attributeID + """
1108 linkID: """ + attr_ldap_display_name_4 + """
1109 attributeSyntax: 2.5.5.1
1110 ldapDisplayName: """ + attr_ldap_display_name + """
1113 isSingleValued: TRUE
1118 self.ldb.add_ldif(ldif)
1119 self.fail("Should have failed to add backlink of backlink")
1120 except LdbError as e20:
1121 (enum, estr) = e20.args
1122 self.assertEquals(enum, ERR_UNWILLING_TO_PERFORM)
1124 def test_generated_mAPIID(self):
1126 Test that we automatically generate a mAPIID if the
1127 OID "1.2.840.113556.1.2.49" is given as the mAPIID
1128 of a new attribute, and that we don't get/can't add
1132 rand = str(random.randint(1,100000))
1134 attr_name_1 = "test-generated-mAPIID" + time.strftime("%s", time.gmtime()) + "-" + rand
1135 attr_ldap_display_name_1 = attr_name_1.replace("-", "")
1136 attributeID_1 = "1.3.6.1.4.1.7165.4.6.1.6.24." + rand
1138 dn: CN=%s,%s""" % (attr_name_1, self.schema_dn) + """
1140 objectClass: attributeSchema
1141 adminDescription: """ + attr_name_1 + """
1142 adminDisplayName: """ + attr_name_1 + """
1143 cn: """ + attr_name_1 + """
1144 attributeId: """ + attributeID_1 + """
1145 mAPIID: 1.2.840.113556.1.2.49
1146 attributeSyntax: 2.5.5.1
1147 ldapDisplayName: """ + attr_ldap_display_name_1 + """
1150 isSingleValued: TRUE
1155 self.ldb.add_ldif(ldif)
1156 except LdbError as e21:
1157 (enum, estr) = e21.args
1160 res = self.ldb.search("CN=%s,%s" % (attr_name_1, self.schema_dn),
1163 self.assertEquals(len(res), 1)
1164 mAPIID_1 = int(res[0]["mAPIID"][0])
1169 replace: schemaupdatenow
1172 self.ldb.modify_ldif(ldif)
1174 # If we add a new attribute with the same mAPIID, it should fail
1175 attr_name = "test-generated-mAPIID-duplicate" + time.strftime("%s", time.gmtime()) + "-" + rand
1176 attr_ldap_display_name = attr_name.replace("-", "")
1177 attributeID = "1.3.6.1.4.1.7165.4.6.1.6.25." + rand
1179 dn: CN=%s,%s""" % (attr_name, self.schema_dn) + """
1181 objectClass: attributeSchema
1182 adminDescription: """ + attr_name + """
1183 adminDisplayName: """ + attr_name + """
1184 cn: """ + attr_name + """
1185 attributeId: """ + attributeID + """
1186 mAPIID: """ + str(mAPIID_1) + """
1187 attributeSyntax: 2.5.5.1
1188 ldapDisplayName: """ + attr_ldap_display_name + """
1191 isSingleValued: TRUE
1196 self.ldb.add_ldif(ldif)
1197 self.fail("Should have failed to add duplicate mAPIID value")
1198 except LdbError as e22:
1199 (enum, estr) = e22.args
1200 self.assertEquals(enum, ERR_UNWILLING_TO_PERFORM)
1203 def test_change_governsID(self):
1204 """Testing change the governsID"""
1205 rand = str(random.randint(1,100000))
1206 class_name = "test-Class" + time.strftime("%s", time.gmtime()) + "-" + rand
1207 class_ldap_display_name = class_name.replace("-", "")
1208 governsID = "1.3.6.1.4.1.7165.4.6.2.6.5." + rand
1210 dn: CN=%s,%s""" % (class_name, self.schema_dn) + """
1212 objectClass: classSchema
1213 adminDescription: """ + class_name + """
1214 adminDisplayName: """ + class_name + """
1215 cn: """ + class_name + """
1216 governsId: """ + governsID + """
1217 ldapDisplayName: """ + class_ldap_display_name + """
1219 objectClassCategory: 1
1220 subClassOf: organizationalPerson
1222 systemMustContain: cn
1225 self.ldb.add_ldif(ldif)
1228 dn: CN=%s,%s""" % (class_name, self.schema_dn) + """
1231 governsId: """ + governsID + """.1
1235 self.ldb.modify_ldif(ldif)
1236 self.fail("Should have failed to modify schema to have different governsID")
1237 except LdbError as e23:
1238 (enum, estr) = e23.args
1239 self.assertEquals(enum, ERR_CONSTRAINT_VIOLATION)
1242 def test_change_governsID_same(self):
1243 """Testing change the governsID"""
1244 rand = str(random.randint(1,100000))
1245 class_name = "test-Class" + time.strftime("%s", time.gmtime()) + "-" + rand
1246 class_ldap_display_name = class_name.replace("-", "")
1247 governsID = "1.3.6.1.4.1.7165.4.6.2.6.6." + rand
1249 dn: CN=%s,%s""" % (class_name, self.schema_dn) + """
1251 objectClass: classSchema
1252 adminDescription: """ + class_name + """
1253 adminDisplayName: """ + class_name + """
1254 cn: """ + class_name + """
1255 governsId: """ + governsID + """
1256 ldapDisplayName: """ + class_ldap_display_name + """
1258 objectClassCategory: 1
1259 subClassOf: organizationalPerson
1261 systemMustContain: cn
1264 self.ldb.add_ldif(ldif)
1267 dn: CN=%s,%s""" % (class_name, self.schema_dn) + """
1270 governsId: """ + governsID + """.1
1274 self.ldb.modify_ldif(ldif)
1275 self.fail("Should have failed to modify schema to have the same governsID")
1276 except LdbError as e24:
1277 (enum, estr) = e24.args
1278 self.assertEquals(enum, ERR_CONSTRAINT_VIOLATION)
1281 def test_subClassOf(self):
1282 """ Testing usage of custom child classSchema
1285 class_name = "my-Class" + time.strftime("%s", time.gmtime())
1286 class_ldap_display_name = class_name.replace("-", "")
1289 dn: CN=%s,%s""" % (class_name, self.schema_dn) + """
1291 objectClass: classSchema
1292 adminDescription: """ + class_name + """
1293 adminDisplayName: """ + class_name + """
1294 cn: """ + class_name + """
1295 governsId: 1.3.6.1.4.1.7165.4.6.2.6.7.""" + str(random.randint(1,100000)) + """
1297 objectClassCategory: 1
1298 subClassOf: organizationalUnit
1302 self.ldb.add_ldif(ldif)
1304 # Search for created objectclass
1306 res = self.ldb.search("cn=%s,%s" % (class_name, self.schema_dn), scope=SCOPE_BASE,
1307 attrs=["lDAPDisplayName", "defaultObjectCategory",
1308 "schemaIDGUID", "distinguishedName"])
1309 self.assertEquals(len(res), 1)
1310 self.assertEquals(res[0]["lDAPDisplayName"][0], class_ldap_display_name)
1311 self.assertEquals(res[0]["defaultObjectCategory"][0], res[0]["distinguishedName"][0])
1312 self.assertTrue("schemaIDGUID" in res[0])
1317 add: schemaUpdateNow
1320 self.ldb.modify_ldif(ldif)
1322 object_name = "org" + time.strftime("%s", time.gmtime())
1325 dn: OU=%s,%s""" % (object_name, self.base_dn) + """
1326 objectClass: """ + class_ldap_display_name + """
1327 ou: """ + object_name + """
1330 self.ldb.add_ldif(ldif)
1332 # Search for created object
1334 res = self.ldb.search("ou=%s,%s" % (object_name, self.base_dn), scope=SCOPE_BASE, attrs=["dn"])
1335 self.assertEquals(len(res), 1)
1337 delete_force(self.ldb, "ou=%s,%s" % (object_name, self.base_dn))
1340 class SchemaTests_msDS_IntId(samba.tests.TestCase):
1343 super(SchemaTests_msDS_IntId, self).setUp()
1344 self.ldb = SamDB(host, credentials=creds,
1345 session_info=system_session(lp), lp=lp, options=ldb_options)
1346 res = self.ldb.search(base="", expression="", scope=SCOPE_BASE,
1347 attrs=["schemaNamingContext", "defaultNamingContext",
1348 "forestFunctionality"])
1349 self.assertEquals(len(res), 1)
1350 self.schema_dn = res[0]["schemaNamingContext"][0]
1351 self.base_dn = res[0]["defaultNamingContext"][0]
1352 self.forest_level = int(res[0]["forestFunctionality"][0])
1354 def _ldap_schemaUpdateNow(self):
1358 add: schemaUpdateNow
1361 self.ldb.modify_ldif(ldif)
1363 def _make_obj_names(self, prefix):
1364 class_name = prefix + time.strftime("%s", time.gmtime())
1365 class_ldap_name = class_name.replace("-", "")
1366 class_dn = "CN=%s,%s" % (class_name, self.schema_dn)
1367 return (class_name, class_ldap_name, class_dn)
1369 def _is_schema_base_object(self, ldb_msg):
1370 """Test systemFlags for SYSTEM_FLAG_SCHEMA_BASE_OBJECT (16)"""
1372 if "systemFlags" in ldb_msg:
1373 systemFlags = int(ldb_msg["systemFlags"][0])
1374 return (systemFlags & 16) != 0
1376 def _make_attr_ldif(self, attr_name, attr_dn):
1378 dn: """ + attr_dn + """
1380 objectClass: attributeSchema
1381 adminDescription: """ + attr_name + """
1382 adminDisplayName: """ + attr_name + """
1383 cn: """ + attr_name + """
1384 attributeId: 1.3.6.1.4.1.7165.4.6.1.6.14.""" + str(random.randint(1,100000)) + """
1385 attributeSyntax: 2.5.5.12
1388 isSingleValued: TRUE
1393 def test_msDS_IntId_on_attr(self):
1394 """Testing msDs-IntId creation for Attributes.
1395 See MS-ADTS - 3.1.1.Attributes
1397 This test should verify that:
1398 - Creating attribute with 'msDS-IntId' fails with ERR_UNWILLING_TO_PERFORM
1399 - Adding 'msDS-IntId' on existing attribute fails with ERR_CONSTRAINT_VIOLATION
1400 - Creating attribute with 'msDS-IntId' set and FLAG_SCHEMA_BASE_OBJECT flag
1401 set fails with ERR_UNWILLING_TO_PERFORM
1402 - Attributes created with FLAG_SCHEMA_BASE_OBJECT not set have
1403 'msDS-IntId' attribute added internally
1406 # 1. Create attribute without systemFlags
1407 # msDS-IntId should be created if forest functional
1408 # level is >= DS_DOMAIN_FUNCTION_2003
1409 # and missing otherwise
1410 (attr_name, attr_ldap_name, attr_dn) = self._make_obj_names("msDS-IntId-Attr-1-")
1411 ldif = self._make_attr_ldif(attr_name, attr_dn)
1413 # try to add msDS-IntId during Attribute creation
1414 ldif_fail = ldif + "msDS-IntId: -1993108831\n"
1416 self.ldb.add_ldif(ldif_fail)
1417 self.fail("Adding attribute with preset msDS-IntId should fail")
1418 except LdbError as e25:
1420 self.assertEquals(num, ERR_UNWILLING_TO_PERFORM)
1422 # add the new attribute and update schema
1423 self.ldb.add_ldif(ldif)
1424 self._ldap_schemaUpdateNow()
1426 # Search for created attribute
1428 res = self.ldb.search(attr_dn, scope=SCOPE_BASE,
1429 attrs=["lDAPDisplayName", "msDS-IntId", "systemFlags"])
1430 self.assertEquals(len(res), 1)
1431 self.assertEquals(res[0]["lDAPDisplayName"][0], attr_ldap_name)
1432 if self.forest_level >= DS_DOMAIN_FUNCTION_2003:
1433 if self._is_schema_base_object(res[0]):
1434 self.assertTrue("msDS-IntId" not in res[0])
1436 self.assertTrue("msDS-IntId" in res[0])
1438 self.assertTrue("msDS-IntId" not in res[0])
1441 msg.dn = Dn(self.ldb, attr_dn)
1442 msg["msDS-IntId"] = MessageElement("-1993108831", FLAG_MOD_REPLACE, "msDS-IntId")
1444 self.ldb.modify(msg)
1445 self.fail("Modifying msDS-IntId should return error")
1446 except LdbError as e26:
1448 self.assertEquals(num, ERR_CONSTRAINT_VIOLATION)
1450 # 2. Create attribute with systemFlags = FLAG_SCHEMA_BASE_OBJECT
1451 # msDS-IntId should be created if forest functional
1452 # level is >= DS_DOMAIN_FUNCTION_2003
1453 # and missing otherwise
1454 (attr_name, attr_ldap_name, attr_dn) = self._make_obj_names("msDS-IntId-Attr-2-")
1455 ldif = self._make_attr_ldif(attr_name, attr_dn)
1456 ldif += "systemFlags: 16\n"
1458 # try to add msDS-IntId during Attribute creation
1459 ldif_fail = ldif + "msDS-IntId: -1993108831\n"
1461 self.ldb.add_ldif(ldif_fail)
1462 self.fail("Adding attribute with preset msDS-IntId should fail")
1463 except LdbError as e27:
1465 self.assertEquals(num, ERR_UNWILLING_TO_PERFORM)
1467 # add the new attribute and update schema
1468 self.ldb.add_ldif(ldif)
1469 self._ldap_schemaUpdateNow()
1471 # Search for created attribute
1473 res = self.ldb.search(attr_dn, scope=SCOPE_BASE,
1474 attrs=["lDAPDisplayName", "msDS-IntId"])
1475 self.assertEquals(len(res), 1)
1476 self.assertEquals(res[0]["lDAPDisplayName"][0], attr_ldap_name)
1477 if self.forest_level >= DS_DOMAIN_FUNCTION_2003:
1478 if self._is_schema_base_object(res[0]):
1479 self.assertTrue("msDS-IntId" not in res[0])
1481 self.assertTrue("msDS-IntId" in res[0])
1483 self.assertTrue("msDS-IntId" not in res[0])
1486 msg.dn = Dn(self.ldb, attr_dn)
1487 msg["msDS-IntId"] = MessageElement("-1993108831", FLAG_MOD_REPLACE, "msDS-IntId")
1489 self.ldb.modify(msg)
1490 self.fail("Modifying msDS-IntId should return error")
1491 except LdbError as e28:
1493 self.assertEquals(num, ERR_CONSTRAINT_VIOLATION)
1496 def _make_class_ldif(self, class_dn, class_name, sub_oid):
1498 dn: """ + class_dn + """
1500 objectClass: classSchema
1501 adminDescription: """ + class_name + """
1502 adminDisplayName: """ + class_name + """
1503 cn: """ + class_name + """
1504 governsId: 1.3.6.1.4.1.7165.4.6.2.6.%d.""" % sub_oid + str(random.randint(1,100000)) + """
1506 objectClassCategory: 1
1507 subClassOf: organizationalPerson
1509 systemMustContain: cn
1514 def test_msDS_IntId_on_class(self):
1515 """Testing msDs-IntId creation for Class
1516 Reference: MS-ADTS - 3.1.1.2.4.8 Class classSchema"""
1518 # 1. Create Class without systemFlags
1519 # msDS-IntId should be created if forest functional
1520 # level is >= DS_DOMAIN_FUNCTION_2003
1521 # and missing otherwise
1522 (class_name, class_ldap_name, class_dn) = self._make_obj_names("msDS-IntId-Class-1-")
1523 ldif = self._make_class_ldif(class_dn, class_name, 8)
1525 # try to add msDS-IntId during Class creation
1526 ldif_add = ldif + "msDS-IntId: -1993108831\n"
1527 self.ldb.add_ldif(ldif_add)
1528 self._ldap_schemaUpdateNow()
1530 res = self.ldb.search(class_dn, scope=SCOPE_BASE, attrs=["msDS-IntId"])
1531 self.assertEquals(len(res), 1)
1532 self.assertEquals(res[0]["msDS-IntId"][0], "-1993108831")
1534 # add a new Class and update schema
1535 (class_name, class_ldap_name, class_dn) = self._make_obj_names("msDS-IntId-Class-2-")
1536 ldif = self._make_class_ldif(class_dn, class_name, 9)
1538 self.ldb.add_ldif(ldif)
1539 self._ldap_schemaUpdateNow()
1541 # Search for created Class
1542 res = self.ldb.search(class_dn, scope=SCOPE_BASE, attrs=["msDS-IntId"])
1543 self.assertEquals(len(res), 1)
1544 self.assertFalse("msDS-IntId" in res[0])
1547 msg.dn = Dn(self.ldb, class_dn)
1548 msg["msDS-IntId"] = MessageElement("-1993108831", FLAG_MOD_REPLACE, "msDS-IntId")
1550 self.ldb.modify(msg)
1551 self.fail("Modifying msDS-IntId should return error")
1552 except LdbError as e29:
1554 self.assertEquals(num, ERR_CONSTRAINT_VIOLATION)
1556 # 2. Create Class with systemFlags = FLAG_SCHEMA_BASE_OBJECT
1557 # msDS-IntId should be created if forest functional
1558 # level is >= DS_DOMAIN_FUNCTION_2003
1559 # and missing otherwise
1560 (class_name, class_ldap_name, class_dn) = self._make_obj_names("msDS-IntId-Class-3-")
1561 ldif = self._make_class_ldif(class_dn, class_name, 10)
1562 ldif += "systemFlags: 16\n"
1564 # try to add msDS-IntId during Class creation
1565 ldif_add = ldif + "msDS-IntId: -1993108831\n"
1566 self.ldb.add_ldif(ldif_add)
1568 res = self.ldb.search(class_dn, scope=SCOPE_BASE, attrs=["msDS-IntId"])
1569 self.assertEquals(len(res), 1)
1570 self.assertEquals(res[0]["msDS-IntId"][0], "-1993108831")
1572 # add the new Class and update schema
1573 (class_name, class_ldap_name, class_dn) = self._make_obj_names("msDS-IntId-Class-4-")
1574 ldif = self._make_class_ldif(class_dn, class_name, 11)
1575 ldif += "systemFlags: 16\n"
1577 self.ldb.add_ldif(ldif)
1578 self._ldap_schemaUpdateNow()
1580 # Search for created Class
1581 res = self.ldb.search(class_dn, scope=SCOPE_BASE, attrs=["msDS-IntId"])
1582 self.assertEquals(len(res), 1)
1583 self.assertFalse("msDS-IntId" in res[0])
1586 msg.dn = Dn(self.ldb, class_dn)
1587 msg["msDS-IntId"] = MessageElement("-1993108831", FLAG_MOD_REPLACE, "msDS-IntId")
1589 self.ldb.modify(msg)
1590 self.fail("Modifying msDS-IntId should return error")
1591 except LdbError as e30:
1593 self.assertEquals(num, ERR_CONSTRAINT_VIOLATION)
1594 res = self.ldb.search(class_dn, scope=SCOPE_BASE, attrs=["msDS-IntId"])
1595 self.assertEquals(len(res), 1)
1596 self.assertFalse("msDS-IntId" in res[0])
1599 def test_verify_msDS_IntId(self):
1600 """Verify msDS-IntId exists only on attributes without FLAG_SCHEMA_BASE_OBJECT flag set"""
1602 res = self.ldb.search(self.schema_dn, scope=SCOPE_ONELEVEL,
1603 expression="objectClass=attributeSchema",
1604 attrs=["systemFlags", "msDS-IntId", "attributeID", "cn"])
1605 self.assertTrue(len(res) > 1)
1607 if self.forest_level >= DS_DOMAIN_FUNCTION_2003:
1608 if self._is_schema_base_object(ldb_msg):
1609 self.assertTrue("msDS-IntId" not in ldb_msg)
1611 # don't assert here as there are plenty of
1612 # attributes under w2k8 that are not part of
1613 # Base Schema (SYSTEM_FLAG_SCHEMA_BASE_OBJECT flag not set)
1614 # has not msDS-IntId attribute set
1615 #self.assertTrue("msDS-IntId" in ldb_msg, "msDS-IntId expected on: %s" % ldb_msg.dn)
1616 if "msDS-IntId" not in ldb_msg:
1618 print "%3d warning: msDS-IntId expected on: %-30s %s" % (count, ldb_msg["attributeID"], ldb_msg["cn"])
1620 self.assertTrue("msDS-IntId" not in ldb_msg)
1623 class SchemaTests_msDS_isRODC(samba.tests.TestCase):
1626 super(SchemaTests_msDS_isRODC, self).setUp()
1627 self.ldb = SamDB(host, credentials=creds,
1628 session_info=system_session(lp), lp=lp, options=ldb_options)
1629 res = self.ldb.search(base="", expression="", scope=SCOPE_BASE, attrs=["defaultNamingContext"])
1630 self.assertEquals(len(res), 1)
1631 self.base_dn = res[0]["defaultNamingContext"][0]
1633 def test_objectClass_ntdsdsa(self):
1634 res = self.ldb.search(self.base_dn, expression="objectClass=nTDSDSA",
1635 attrs=["msDS-isRODC"], controls=["search_options:1:2"])
1637 self.assertTrue("msDS-isRODC" in ldb_msg)
1639 def test_objectClass_server(self):
1640 res = self.ldb.search(self.base_dn, expression="objectClass=server",
1641 attrs=["msDS-isRODC"], controls=["search_options:1:2"])
1643 ntds_search_dn = "CN=NTDS Settings,%s" % ldb_msg['dn']
1645 res_check = self.ldb.search(ntds_search_dn, attrs=["objectCategory"])
1646 except LdbError as e:
1648 self.assertEquals(num, ERR_NO_SUCH_OBJECT)
1649 print("Server entry %s doesn't have a NTDS settings object" % res[0]['dn'])
1651 self.assertTrue("objectCategory" in res_check[0])
1652 self.assertTrue("msDS-isRODC" in ldb_msg)
1654 def test_objectClass_computer(self):
1655 res = self.ldb.search(self.base_dn, expression="objectClass=computer",
1656 attrs=["serverReferenceBL","msDS-isRODC"], controls=["search_options:1:2"])
1658 if "serverReferenceBL" not in ldb_msg:
1659 print("Computer entry %s doesn't have a serverReferenceBL attribute" % ldb_msg['dn'])
1661 self.assertTrue("msDS-isRODC" in ldb_msg)
1663 if not "://" in host:
1664 if os.path.isfile(host):
1665 host = "tdb://%s" % host
1667 host = "ldap://%s" % host
1670 if host.startswith("ldap://"):
1671 # user 'paged_search' module when connecting remotely
1672 ldb_options = ["modules:paged_searches"]
1674 TestProgram(module=__name__, opts=subunitopts)