test: fixed several tests to use samba.tests
[samba.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 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_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 from subunit.run import SubunitTestRunner
25 import unittest
26
27 import samba.tests
28
29 parser = optparse.OptionParser("ldap [options] <host>")
30 sambaopts = options.SambaOptions(parser)
31 parser.add_option_group(sambaopts)
32 parser.add_option_group(options.VersionOptions(parser))
33 # use command line creds if available
34 credopts = options.CredentialsOptions(parser)
35 parser.add_option_group(credopts)
36 opts, args = parser.parse_args()
37
38 if len(args) < 1:
39     parser.print_usage()
40     sys.exit(1)
41
42 host = args[0]
43 lp = sambaopts.get_loadparm()
44 creds = credopts.get_credentials(lp)
45
46
47 class SyntaxTests(samba.tests.TestCase):
48
49     def setUp(self):
50         super(SyntaxTests, self).setUp()
51         self.ldb = ldb
52         self.base_dn = ldb.domain_dn()
53         self.schema_dn = 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.2.840.""" + str(random.randint(1,100000)) + """.1.5.9940
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.2.840.""" + str(random.randint(1,100000)) + """.1.5.9939
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.2.840.""" + str(random.randint(1,100000)) + """.1.5.9940
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.2.840.""" + str(random.randint(1,100000)) + """.1.5.9939
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 obeject 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 = 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 = 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 = 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, (num, _):
226             self.assertEquals(num, ERR_INVALID_ATTRIBUTE_SYNTAX)
227
228         # add object with the same dn but with different string value in case
229         ldif = self._get_object_ldif(object_name1, self.dn_string_class_name, self.dn_string_class_ldap_display_name,
230                                self.dn_string_attribute, ": S:5:abcde:" + self.base_dn)
231         try:
232             self.ldb.add_ldif(ldif)
233         except LdbError, (num, _):
234             self.assertEquals(num, ERR_ENTRY_ALREADY_EXISTS)
235
236         # add object with the same dn but with different string value
237         ldif = self._get_object_ldif(object_name1, self.dn_string_class_name, self.dn_string_class_ldap_display_name,
238                                self.dn_string_attribute, ": S:5:FGHIJ:" + self.base_dn)
239         try:
240             self.ldb.add_ldif(ldif)
241         except LdbError, (num, _):
242             self.assertEquals(num, ERR_ENTRY_ALREADY_EXISTS)
243
244         # add object with the same dn but with different dn and string value
245         ldif = self._get_object_ldif(object_name1, self.dn_string_class_name, self.dn_string_class_ldap_display_name,
246                                self.dn_string_attribute, ": S:5:FGHIJ:" + self.schema_dn)
247         try:
248             self.ldb.add_ldif(ldif)
249         except LdbError, (num, _):
250             self.assertEquals(num, ERR_ENTRY_ALREADY_EXISTS)
251
252         # add object with the same dn but with different dn value
253         ldif = self._get_object_ldif(object_name1, self.dn_string_class_name, self.dn_string_class_ldap_display_name,
254                                self.dn_string_attribute, ": S:5:ABCDE:" + self.schema_dn)
255         try:
256             self.ldb.add_ldif(ldif)
257         except LdbError, (num, _):
258             self.assertEquals(num, ERR_ENTRY_ALREADY_EXISTS)
259
260         # add object with GUID instead of DN
261         object_name3 = "obj-DN-String3" + time.strftime("%s", time.gmtime())
262         ldif = self._get_object_ldif(object_name3, self.dn_string_class_name, self.dn_string_class_ldap_display_name,
263                                self.dn_string_attribute, ": S:5:ABCDE:<GUID=%s>" % str(uuid.uuid4()))
264         try:
265             self.ldb.add_ldif(ldif)
266         except LdbError, (num, _):
267             self.assertEquals(num, ERR_CONSTRAINT_VIOLATION)
268
269         # add object with SID instead of DN
270         object_name4 = "obj-DN-String4" + time.strftime("%s", time.gmtime())
271         ldif = self._get_object_ldif(object_name4, self.dn_string_class_name, self.dn_string_class_ldap_display_name,
272                                self.dn_string_attribute, ": S:5:ABCDE:<SID=%s>" % self.ldb.get_domain_sid())
273         try:
274             self.ldb.add_ldif(ldif)
275         except LdbError, (num, _):
276             self.assertEquals(num, ERR_CONSTRAINT_VIOLATION)
277
278         # add object with random string instead of DN
279         object_name5 = "obj-DN-String5" + time.strftime("%s", time.gmtime())
280         ldif = self._get_object_ldif(object_name5, self.dn_string_class_name, self.dn_string_class_ldap_display_name,
281                                self.dn_string_attribute, ": S:5:ABCDE:randomSTRING")
282         try:
283             self.ldb.add_ldif(ldif)
284         except LdbError, (num, _):
285             self.assertEquals(num, ERR_CONSTRAINT_VIOLATION)
286         pass
287
288     def test_dn_binary(self):
289         # add obeject with correct value
290         object_name1 = "obj-DN-Binary1" + time.strftime("%s", time.gmtime())
291         ldif = self._get_object_ldif(object_name1, self.dn_binary_class_name, self.dn_binary_class_ldap_display_name,
292                                self.dn_binary_attribute, ": B:4:1234:" + self.base_dn)
293         self.ldb.add_ldif(ldif)
294
295         # search by specifyingthe DN part
296         res = ldb.search(base=self.base_dn,
297                          scope=SCOPE_SUBTREE,
298                          expression="(%s=%s)" % (self.dn_binary_attribute, self.base_dn))
299         self.assertEquals(len(res), 0)
300
301         # search by specifying the binary part
302         res = ldb.search(base=self.base_dn,
303                          scope=SCOPE_SUBTREE,
304                          expression="(%s=B:4:1234)" % self.dn_binary_attribute)
305         self.assertEquals(len(res), 0)
306
307         # search by DN+Binary
308         res = ldb.search(base=self.base_dn,
309                          scope=SCOPE_SUBTREE,
310                          expression="(%s=B:4:1234:%s)" % (self.dn_binary_attribute, self.base_dn))
311         self.assertEquals(len(res), 1)
312
313         # add object with wrong format - 5 bytes instead of 4, 8, 16, 32...
314         object_name2 = "obj-DN-Binary2" + time.strftime("%s", time.gmtime())
315         ldif = self._get_object_ldif(object_name2, self.dn_binary_class_name, self.dn_binary_class_ldap_display_name,
316                                self.dn_binary_attribute, ": B:5:67890:" + self.base_dn)
317         try:
318             self.ldb.add_ldif(ldif)
319         except LdbError, (num, _):
320             self.assertEquals(num, ERR_INVALID_ATTRIBUTE_SYNTAX)
321
322         # add object with the same dn but with different binary value
323         ldif = self._get_object_ldif(object_name1, self.dn_binary_class_name, self.dn_binary_class_ldap_display_name,
324                                self.dn_binary_attribute, ": B:4:5678:" + self.base_dn)
325         try:
326             self.ldb.add_ldif(ldif)
327         except LdbError, (num, _):
328             self.assertEquals(num, ERR_ENTRY_ALREADY_EXISTS)
329
330         # add object with the same dn but with different binary and dn 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.schema_dn)
333         try:
334             self.ldb.add_ldif(ldif)
335         except LdbError, (num, _):
336             self.assertEquals(num, ERR_ENTRY_ALREADY_EXISTS)
337
338         # add object with the same dn but with different dn value
339         ldif = self._get_object_ldif(object_name1, self.dn_binary_class_name, self.dn_binary_class_ldap_display_name,
340                                self.dn_binary_attribute, ": B:4:1234:" + self.schema_dn)
341         try:
342             self.ldb.add_ldif(ldif)
343         except LdbError, (num, _):
344             self.assertEquals(num, ERR_ENTRY_ALREADY_EXISTS)
345
346         # add object with GUID instead of DN
347         object_name3 = "obj-DN-Binary3" + time.strftime("%s", time.gmtime())
348         ldif = self._get_object_ldif(object_name3, self.dn_binary_class_name, self.dn_binary_class_ldap_display_name,
349                                self.dn_binary_attribute, ": B:4:1234:<GUID=%s>" % str(uuid.uuid4()))
350         try:
351             self.ldb.add_ldif(ldif)
352         except LdbError, (num, _):
353             self.assertEquals(num, ERR_CONSTRAINT_VIOLATION)
354
355         # add object with SID instead of DN
356         object_name4 = "obj-DN-Binary4" + time.strftime("%s", time.gmtime())
357         ldif = self._get_object_ldif(object_name4, self.dn_binary_class_name, self.dn_binary_class_ldap_display_name,
358                                self.dn_binary_attribute, ": B:4:1234:<SID=%s>" % self.ldb.get_domain_sid())
359         try:
360             self.ldb.add_ldif(ldif)
361         except LdbError, (num, _):
362             self.assertEquals(num, ERR_CONSTRAINT_VIOLATION)
363
364         # add object with random string instead of DN
365         object_name5 = "obj-DN-Binary5" + time.strftime("%s", time.gmtime())
366         ldif = self._get_object_ldif(object_name5, self.dn_binary_class_name, self.dn_binary_class_ldap_display_name,
367                                self.dn_binary_attribute, ": B:4:1234:randomSTRING")
368         try:
369             self.ldb.add_ldif(ldif)
370         except LdbError, (num, _):
371             self.assertEquals(num, ERR_CONSTRAINT_VIOLATION)
372         pass
373
374 ldb = samba.tests.connect_samdb(host, credentials=creds, session_info=system_session(lp), lp=lp)
375 runner = SubunitTestRunner()
376 rc = 0
377 if not runner.run(unittest.makeSuite(SyntaxTests)).wasSuccessful():
378     rc = 1
379
380 sys.exit(rc)