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