63296c86168e6c90ff36d59b18ea94b51db938b5
[kai/samba-autobuild/.git] / source4 / dsdb / tests / python / ldap_syntaxes.py
1 #!/usr/bin/env python
2 # -*- coding: utf-8 -*-
3 # Tests for LDAP syntaxes
4
5 import optparse
6 import sys
7 import time
8 import random
9 import os
10 import uuid
11
12 sys.path.append("bin/python")
13 import samba
14 samba.ensure_external_module("testtools", "testtools")
15 samba.ensure_external_module("subunit", "subunit/python")
16
17 import samba.getopt as options
18
19 from samba.auth import system_session
20 from ldb import SCOPE_ONELEVEL, SCOPE_BASE, SCOPE_SUBTREE, LdbError
21 from ldb import ERR_NO_SUCH_OBJECT
22 from ldb import ERR_CONSTRAINT_VIOLATION
23 from ldb import ERR_INVALID_ATTRIBUTE_SYNTAX
24 from ldb import ERR_ENTRY_ALREADY_EXISTS
25
26 from samba.ndr import ndr_pack, ndr_unpack
27 from samba.dcerpc import security
28
29 from subunit.run import SubunitTestRunner
30 import unittest
31
32 import samba.tests
33
34 parser = optparse.OptionParser("ldap [options] <host>")
35 sambaopts = options.SambaOptions(parser)
36 parser.add_option_group(sambaopts)
37 parser.add_option_group(options.VersionOptions(parser))
38 # use command line creds if available
39 credopts = options.CredentialsOptions(parser)
40 parser.add_option_group(credopts)
41 opts, args = parser.parse_args()
42
43 if len(args) < 1:
44     parser.print_usage()
45     sys.exit(1)
46
47 host = args[0]
48 lp = sambaopts.get_loadparm()
49 creds = credopts.get_credentials(lp)
50
51
52 class SyntaxTests(unittest.TestCase):
53
54     def setUp(self):
55         super(SyntaxTests, self).setUp()
56         self.ldb = ldb
57         self.base_dn = ldb.domain_dn()
58         self.schema_dn = ldb.get_schema_basedn().get_linearized()
59         self._setup_dn_string_test()
60         self._setup_dn_binary_test()
61
62     def _setup_dn_string_test(self):
63         """Testing DN+String syntax"""
64         attr_name = "test-Attr-DN-String" + time.strftime("%s", time.gmtime())
65         attr_ldap_display_name = attr_name.replace("-", "")
66
67         ldif = """
68 dn: CN=%s,%s""" % (attr_name, self.schema_dn) + """
69 ldapDisplayName: """ + attr_ldap_display_name + """
70 objectClass: top
71 objectClass: attributeSchema
72 cn: """ + attr_name + """
73 attributeId: 1.2.840.""" + str(random.randint(1,100000)) + """.1.5.9940
74 attributeSyntax: 2.5.5.14
75 omSyntax: 127
76 omObjectClass: \x2A\x86\x48\x86\xF7\x14\x01\x01\x01\x0C
77 isSingleValued: FALSE
78 schemaIdGuid: """ + str(uuid.uuid4()) + """
79 systemOnly: FALSE
80 """
81         self.ldb.add_ldif(ldif)
82
83         # search for created attribute
84         res = []
85         res = self.ldb.search("cn=%s,%s" % (attr_name, self.schema_dn), scope=SCOPE_BASE, attrs=["*"])
86         self.assertEquals(len(res), 1)
87         self.assertEquals(res[0]["lDAPDisplayName"][0], attr_ldap_display_name)
88         self.assertTrue("schemaIDGUID" in res[0])
89
90         class_name = "test-Class-DN-String" + time.strftime("%s", time.gmtime())
91         class_ldap_display_name = class_name.replace("-", "")
92
93         ldif = """
94 dn: CN=%s,%s""" % (class_name, self.schema_dn) + """
95 objectClass: top
96 objectClass: classSchema
97 adminDescription: """ + class_name + """
98 adminDisplayName: """ + class_name + """
99 cn: """ + class_name + """
100 governsId: 1.2.840.""" + str(random.randint(1,100000)) + """.1.5.9939
101 schemaIdGuid: """ + str(uuid.uuid4()) + """
102 objectClassCategory: 1
103 subClassOf: organizationalPerson
104 systemMayContain: """ + attr_ldap_display_name + """
105 systemOnly: FALSE
106 """
107         self.ldb.add_ldif(ldif)
108
109         # search for created objectclass
110         res = []
111         res = self.ldb.search("cn=%s,%s" % (class_name, self.schema_dn), scope=SCOPE_BASE, attrs=["*"])
112         self.assertEquals(len(res), 1)
113         self.assertEquals(res[0]["lDAPDisplayName"][0], class_ldap_display_name)
114         self.assertEquals(res[0]["defaultObjectCategory"][0], res[0]["distinguishedName"][0])
115         self.assertTrue("schemaIDGUID" in res[0])
116
117         # store the class and the attribute
118         self.dn_string_class_ldap_display_name = class_ldap_display_name
119         self.dn_string_attribute = attr_ldap_display_name
120         self.dn_string_class_name = class_name
121
122     def _setup_dn_binary_test(self):
123         """Testing DN+Binary syntaxes"""
124         attr_name = "test-Attr-DN-Binary" + time.strftime("%s", time.gmtime())
125         attr_ldap_display_name = attr_name.replace("-", "")
126
127         ldif = """
128 dn: CN=%s,%s""" % (attr_name, self.schema_dn) + """
129 ldapDisplayName: """ + attr_ldap_display_name + """
130 objectClass: top
131 objectClass: attributeSchema
132 cn: """ + attr_name + """
133 attributeId: 1.2.840.""" + str(random.randint(1,100000)) + """.1.5.9940
134 attributeSyntax: 2.5.5.7
135 omSyntax: 127
136 omObjectClass: \x2A\x86\x48\x86\xF7\x14\x01\x01\x01\x0B
137 isSingleValued: FALSE
138 schemaIdGuid: """ + str(uuid.uuid4()) + """
139 systemOnly: FALSE
140 """
141         self.ldb.add_ldif(ldif)
142
143         # search for created attribute
144         res = []
145         res = self.ldb.search("cn=%s,%s" % (attr_name, self.schema_dn), scope=SCOPE_BASE, attrs=["*"])
146         self.assertEquals(len(res), 1)
147         self.assertEquals(res[0]["lDAPDisplayName"][0], attr_ldap_display_name)
148         self.assertTrue("schemaIDGUID" in res[0])
149
150         class_name = "test-Class-DN-Binary" + time.strftime("%s", time.gmtime())
151         class_ldap_display_name = class_name.replace("-", "")
152
153         ldif = """
154 dn: CN=%s,%s""" % (class_name, self.schema_dn) + """
155 objectClass: top
156 objectClass: classSchema
157 adminDescription: """ + class_name + """
158 adminDisplayName: """ + class_name + """
159 cn: """ + class_name + """
160 governsId: 1.2.840.""" + str(random.randint(1,100000)) + """.1.5.9939
161 schemaIdGuid: """ + str(uuid.uuid4()) + """
162 objectClassCategory: 1
163 subClassOf: organizationalPerson
164 systemMayContain: """ + attr_ldap_display_name + """
165 systemOnly: FALSE
166 """
167         self.ldb.add_ldif(ldif)
168
169         # search for created objectclass
170         res = []
171         res = self.ldb.search("cn=%s,%s" % (class_name, self.schema_dn), scope=SCOPE_BASE, attrs=["*"])
172         self.assertEquals(len(res), 1)
173         self.assertEquals(res[0]["lDAPDisplayName"][0], class_ldap_display_name)
174         self.assertEquals(res[0]["defaultObjectCategory"][0], res[0]["distinguishedName"][0])
175         self.assertTrue("schemaIDGUID" in res[0])
176
177         # store the class and the attribute
178         self.dn_binary_class_ldap_display_name = class_ldap_display_name
179         self.dn_binary_attribute = attr_ldap_display_name
180         self.dn_binary_class_name = class_name
181
182     def _get_object_ldif(self, object_name, class_name, class_ldap_display_name, attr_name, attr_value):
183         # add object with correct syntax
184         ldif = """
185 dn: CN=%s,CN=Users,%s"""% (object_name, self.base_dn) + """
186 objectClass: organizationalPerson
187 objectClass: person
188 objectClass: """ + class_ldap_display_name + """
189 objectClass: top
190 cn: """ + object_name + """
191 instanceType: 4
192 objectCategory: CN=%s,%s"""% (class_name, self.schema_dn) + """
193 distinguishedName: CN=%s,CN=Users,%s"""% (object_name, self.base_dn) + """
194 name: """ + object_name + """
195 """ + attr_name + attr_value  + """
196 """
197         return ldif
198
199     def test_dn_string(self):
200         # add obeject with correct value
201         object_name1 = "obj-DN-String1" + time.strftime("%s", time.gmtime())
202         ldif = self._get_object_ldif(object_name1, self.dn_string_class_name, self.dn_string_class_ldap_display_name,
203                                self.dn_string_attribute, ": S:5:ABCDE:" + self.base_dn)
204         self.ldb.add_ldif(ldif)
205
206         # search by specifying the DN part only
207         res = ldb.search(base=self.base_dn,
208                          scope=SCOPE_SUBTREE,
209                          expression="(%s=%s)" % (self.dn_string_attribute, self.base_dn))
210         self.assertEquals(len(res), 0)
211
212         # search by specifying the string part only
213         res = ldb.search(base=self.base_dn,
214                          scope=SCOPE_SUBTREE,
215                          expression="(%s=S:5:ABCDE)" % self.dn_string_attribute)
216         self.assertEquals(len(res), 0)
217
218         # search by DN+Stirng
219         res = ldb.search(base=self.base_dn,
220                          scope=SCOPE_SUBTREE,
221                          expression="(%s=S:5:ABCDE:%s)" % (self.dn_string_attribute, self.base_dn))
222         self.assertEquals(len(res), 1)
223
224         # add object with wrong format
225         object_name2 = "obj-DN-String2" + time.strftime("%s", time.gmtime())
226         ldif = self._get_object_ldif(object_name2, self.dn_string_class_name, self.dn_string_class_ldap_display_name,
227                                self.dn_string_attribute, ": S:5:ABCD:" + self.base_dn)
228         try:
229             self.ldb.add_ldif(ldif)
230         except LdbError, (num, _):
231             self.assertEquals(num, ERR_INVALID_ATTRIBUTE_SYNTAX)
232
233         # add object with the same dn but with different string value in case
234         ldif = self._get_object_ldif(object_name1, self.dn_string_class_name, self.dn_string_class_ldap_display_name,
235                                self.dn_string_attribute, ": S:5:abcde:" + self.base_dn)
236         try:
237             self.ldb.add_ldif(ldif)
238         except LdbError, (num, _):
239             self.assertEquals(num, ERR_ENTRY_ALREADY_EXISTS)
240
241         # add object with the same dn but with different string value
242         ldif = self._get_object_ldif(object_name1, self.dn_string_class_name, self.dn_string_class_ldap_display_name,
243                                self.dn_string_attribute, ": S:5:FGHIJ:" + self.base_dn)
244         try:
245             self.ldb.add_ldif(ldif)
246         except LdbError, (num, _):
247             self.assertEquals(num, ERR_ENTRY_ALREADY_EXISTS)
248
249         # add object with the same dn but with different dn and string value
250         ldif = self._get_object_ldif(object_name1, self.dn_string_class_name, self.dn_string_class_ldap_display_name,
251                                self.dn_string_attribute, ": S:5:FGHIJ:" + self.schema_dn)
252         try:
253             self.ldb.add_ldif(ldif)
254         except LdbError, (num, _):
255             self.assertEquals(num, ERR_ENTRY_ALREADY_EXISTS)
256
257         # add object with the same dn but with different dn value
258         ldif = self._get_object_ldif(object_name1, self.dn_string_class_name, self.dn_string_class_ldap_display_name,
259                                self.dn_string_attribute, ": S:5:ABCDE:" + self.schema_dn)
260         try:
261             self.ldb.add_ldif(ldif)
262         except LdbError, (num, _):
263             self.assertEquals(num, ERR_ENTRY_ALREADY_EXISTS)
264
265         # add object with GUID instead of DN
266         object_name3 = "obj-DN-String3" + time.strftime("%s", time.gmtime())
267         ldif = self._get_object_ldif(object_name3, self.dn_string_class_name, self.dn_string_class_ldap_display_name,
268                                self.dn_string_attribute, ": S:5:ABCDE:<GUID=%s>" % str(uuid.uuid4()))
269         try:
270             self.ldb.add_ldif(ldif)
271         except LdbError, (num, _):
272             self.assertEquals(num, ERR_CONSTRAINT_VIOLATION)
273
274         # add object with SID instead of DN
275         object_name4 = "obj-DN-String4" + time.strftime("%s", time.gmtime())
276         ldif = self._get_object_ldif(object_name4, self.dn_string_class_name, self.dn_string_class_ldap_display_name,
277                                self.dn_string_attribute, ": S:5:ABCDE:<SID=%s>" % self.ldb.get_domain_sid())
278         try:
279             self.ldb.add_ldif(ldif)
280         except LdbError, (num, _):
281             self.assertEquals(num, ERR_CONSTRAINT_VIOLATION)
282
283         # add object with random string instead of DN
284         object_name5 = "obj-DN-String5" + time.strftime("%s", time.gmtime())
285         ldif = self._get_object_ldif(object_name5, self.dn_string_class_name, self.dn_string_class_ldap_display_name,
286                                self.dn_string_attribute, ": S:5:ABCDE:randomSTRING")
287         try:
288             self.ldb.add_ldif(ldif)
289         except LdbError, (num, _):
290             self.assertEquals(num, ERR_CONSTRAINT_VIOLATION)
291         pass
292
293     def test_dn_binary(self):
294         # add obeject with correct value
295         object_name1 = "obj-DN-Binary1" + time.strftime("%s", time.gmtime())
296         ldif = self._get_object_ldif(object_name1, self.dn_binary_class_name, self.dn_binary_class_ldap_display_name,
297                                self.dn_binary_attribute, ": B:4:1234:" + self.base_dn)
298         self.ldb.add_ldif(ldif)
299
300         # search by specifyingthe DN part
301         res = ldb.search(base=self.base_dn,
302                          scope=SCOPE_SUBTREE,
303                          expression="(%s=%s)" % (self.dn_binary_attribute, self.base_dn))
304         self.assertEquals(len(res), 0)
305
306         # search by specifying the binary part
307         res = ldb.search(base=self.base_dn,
308                          scope=SCOPE_SUBTREE,
309                          expression="(%s=B:4:1234)" % self.dn_binary_attribute)
310         self.assertEquals(len(res), 0)
311
312         # search by DN+Binary
313         res = ldb.search(base=self.base_dn,
314                          scope=SCOPE_SUBTREE,
315                          expression="(%s=B:4:1234:%s)" % (self.dn_binary_attribute, self.base_dn))
316         self.assertEquals(len(res), 1)
317
318         # add object with wrong format - 5 bytes instead of 4, 8, 16, 32...
319         object_name2 = "obj-DN-Binary2" + time.strftime("%s", time.gmtime())
320         ldif = self._get_object_ldif(object_name2, self.dn_binary_class_name, self.dn_binary_class_ldap_display_name,
321                                self.dn_binary_attribute, ": B:5:67890:" + self.base_dn)
322         try:
323             self.ldb.add_ldif(ldif)
324         except LdbError, (num, _):
325             self.assertEquals(num, ERR_INVALID_ATTRIBUTE_SYNTAX)
326
327         # add object with the same dn but with different binary value
328         ldif = self._get_object_ldif(object_name1, self.dn_binary_class_name, self.dn_binary_class_ldap_display_name,
329                                self.dn_binary_attribute, ": B:4:5678:" + self.base_dn)
330         try:
331             self.ldb.add_ldif(ldif)
332         except LdbError, (num, _):
333             self.assertEquals(num, ERR_ENTRY_ALREADY_EXISTS)
334
335         # add object with the same dn but with different binary and dn value
336         ldif = self._get_object_ldif(object_name1, self.dn_binary_class_name, self.dn_binary_class_ldap_display_name,
337                                self.dn_binary_attribute, ": B:4:5678:" + self.schema_dn)
338         try:
339             self.ldb.add_ldif(ldif)
340         except LdbError, (num, _):
341             self.assertEquals(num, ERR_ENTRY_ALREADY_EXISTS)
342
343         # add object with the same dn but with different dn value
344         ldif = self._get_object_ldif(object_name1, self.dn_binary_class_name, self.dn_binary_class_ldap_display_name,
345                                self.dn_binary_attribute, ": B:4:1234:" + self.schema_dn)
346         try:
347             self.ldb.add_ldif(ldif)
348         except LdbError, (num, _):
349             self.assertEquals(num, ERR_ENTRY_ALREADY_EXISTS)
350
351         # add object with GUID instead of DN
352         object_name3 = "obj-DN-Binary3" + time.strftime("%s", time.gmtime())
353         ldif = self._get_object_ldif(object_name3, self.dn_binary_class_name, self.dn_binary_class_ldap_display_name,
354                                self.dn_binary_attribute, ": B:4:1234:<GUID=%s>" % str(uuid.uuid4()))
355         try:
356             self.ldb.add_ldif(ldif)
357         except LdbError, (num, _):
358             self.assertEquals(num, ERR_CONSTRAINT_VIOLATION)
359
360         # add object with SID instead of DN
361         object_name4 = "obj-DN-Binary4" + time.strftime("%s", time.gmtime())
362         ldif = self._get_object_ldif(object_name4, self.dn_binary_class_name, self.dn_binary_class_ldap_display_name,
363                                self.dn_binary_attribute, ": B:4:1234:<SID=%s>" % self.ldb.get_domain_sid())
364         try:
365             self.ldb.add_ldif(ldif)
366         except LdbError, (num, _):
367             self.assertEquals(num, ERR_CONSTRAINT_VIOLATION)
368
369         # add object with random string instead of DN
370         object_name5 = "obj-DN-Binary5" + time.strftime("%s", time.gmtime())
371         ldif = self._get_object_ldif(object_name5, self.dn_binary_class_name, self.dn_binary_class_ldap_display_name,
372                                self.dn_binary_attribute, ": B:4:1234:randomSTRING")
373         try:
374             self.ldb.add_ldif(ldif)
375         except LdbError, (num, _):
376             self.assertEquals(num, ERR_CONSTRAINT_VIOLATION)
377         pass
378
379 ldb = samba.tests.connect_samdb(host, credentials=creds, session_info=system_session(lp), lp=lp)
380 runner = SubunitTestRunner()
381 rc = 0
382 if not runner.run(unittest.makeSuite(SyntaxTests)).wasSuccessful():
383     rc = 1
384
385 sys.exit(rc)