2 # -*- coding: utf-8 -*-
3 # Tests for LDAP syntaxes
12 sys.path.append("bin/python")
14 samba.ensure_external_module("testtools", "testtools")
15 samba.ensure_external_module("subunit", "subunit/python")
17 import samba.getopt as options
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
26 from samba.ndr import ndr_pack, ndr_unpack
27 from samba.dcerpc import security
29 from subunit.run import SubunitTestRunner
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()
48 lp = sambaopts.get_loadparm()
49 creds = credopts.get_credentials(lp)
52 class SyntaxTests(unittest.TestCase):
55 super(SyntaxTests, self).setUp()
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()
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("-", "")
68 dn: CN=%s,%s""" % (attr_name, self.schema_dn) + """
69 ldapDisplayName: """ + attr_ldap_display_name + """
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
76 omObjectClass: \x2A\x86\x48\x86\xF7\x14\x01\x01\x01\x0C
78 schemaIdGuid: """ + str(uuid.uuid4()) + """
81 self.ldb.add_ldif(ldif)
83 # search for created attribute
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])
90 class_name = "test-Class-DN-String" + time.strftime("%s", time.gmtime())
91 class_ldap_display_name = class_name.replace("-", "")
94 dn: CN=%s,%s""" % (class_name, self.schema_dn) + """
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 + """
107 self.ldb.add_ldif(ldif)
109 # search for created objectclass
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])
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
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("-", "")
128 dn: CN=%s,%s""" % (attr_name, self.schema_dn) + """
129 ldapDisplayName: """ + attr_ldap_display_name + """
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
136 omObjectClass: \x2A\x86\x48\x86\xF7\x14\x01\x01\x01\x0B
137 isSingleValued: FALSE
138 schemaIdGuid: """ + str(uuid.uuid4()) + """
141 self.ldb.add_ldif(ldif)
143 # search for created attribute
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])
150 class_name = "test-Class-DN-Binary" + time.strftime("%s", time.gmtime())
151 class_ldap_display_name = class_name.replace("-", "")
154 dn: CN=%s,%s""" % (class_name, self.schema_dn) + """
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 + """
167 self.ldb.add_ldif(ldif)
169 # search for created objectclass
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])
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
182 def _get_object_ldif(self, object_name, class_name, class_ldap_display_name, attr_name, attr_value):
183 # add object with correct syntax
185 dn: CN=%s,CN=Users,%s"""% (object_name, self.base_dn) + """
186 objectClass: organizationalPerson
188 objectClass: """ + class_ldap_display_name + """
190 cn: """ + object_name + """
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 + """
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)
206 # search by specifying the DN part only
207 res = ldb.search(base=self.base_dn,
209 expression="(%s=%s)" % (self.dn_string_attribute, self.base_dn))
210 self.assertEquals(len(res), 0)
212 # search by specifying the string part only
213 res = ldb.search(base=self.base_dn,
215 expression="(%s=S:5:ABCDE)" % self.dn_string_attribute)
216 self.assertEquals(len(res), 0)
218 # search by DN+Stirng
219 res = ldb.search(base=self.base_dn,
221 expression="(%s=S:5:ABCDE:%s)" % (self.dn_string_attribute, self.base_dn))
222 self.assertEquals(len(res), 1)
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)
229 self.ldb.add_ldif(ldif)
230 except LdbError, (num, _):
231 self.assertEquals(num, ERR_INVALID_ATTRIBUTE_SYNTAX)
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)
237 self.ldb.add_ldif(ldif)
238 except LdbError, (num, _):
239 self.assertEquals(num, ERR_ENTRY_ALREADY_EXISTS)
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)
245 self.ldb.add_ldif(ldif)
246 except LdbError, (num, _):
247 self.assertEquals(num, ERR_ENTRY_ALREADY_EXISTS)
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)
253 self.ldb.add_ldif(ldif)
254 except LdbError, (num, _):
255 self.assertEquals(num, ERR_ENTRY_ALREADY_EXISTS)
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)
261 self.ldb.add_ldif(ldif)
262 except LdbError, (num, _):
263 self.assertEquals(num, ERR_ENTRY_ALREADY_EXISTS)
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()))
270 self.ldb.add_ldif(ldif)
271 except LdbError, (num, _):
272 self.assertEquals(num, ERR_CONSTRAINT_VIOLATION)
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())
279 self.ldb.add_ldif(ldif)
280 except LdbError, (num, _):
281 self.assertEquals(num, ERR_CONSTRAINT_VIOLATION)
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")
288 self.ldb.add_ldif(ldif)
289 except LdbError, (num, _):
290 self.assertEquals(num, ERR_CONSTRAINT_VIOLATION)
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)
300 # search by specifyingthe DN part
301 res = ldb.search(base=self.base_dn,
303 expression="(%s=%s)" % (self.dn_binary_attribute, self.base_dn))
304 self.assertEquals(len(res), 0)
306 # search by specifying the binary part
307 res = ldb.search(base=self.base_dn,
309 expression="(%s=B:4:1234)" % self.dn_binary_attribute)
310 self.assertEquals(len(res), 0)
312 # search by DN+Binary
313 res = ldb.search(base=self.base_dn,
315 expression="(%s=B:4:1234:%s)" % (self.dn_binary_attribute, self.base_dn))
316 self.assertEquals(len(res), 1)
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)
323 self.ldb.add_ldif(ldif)
324 except LdbError, (num, _):
325 self.assertEquals(num, ERR_INVALID_ATTRIBUTE_SYNTAX)
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)
331 self.ldb.add_ldif(ldif)
332 except LdbError, (num, _):
333 self.assertEquals(num, ERR_ENTRY_ALREADY_EXISTS)
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)
339 self.ldb.add_ldif(ldif)
340 except LdbError, (num, _):
341 self.assertEquals(num, ERR_ENTRY_ALREADY_EXISTS)
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)
347 self.ldb.add_ldif(ldif)
348 except LdbError, (num, _):
349 self.assertEquals(num, ERR_ENTRY_ALREADY_EXISTS)
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()))
356 self.ldb.add_ldif(ldif)
357 except LdbError, (num, _):
358 self.assertEquals(num, ERR_CONSTRAINT_VIOLATION)
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())
365 self.ldb.add_ldif(ldif)
366 except LdbError, (num, _):
367 self.assertEquals(num, ERR_CONSTRAINT_VIOLATION)
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")
374 self.ldb.add_ldif(ldif)
375 except LdbError, (num, _):
376 self.assertEquals(num, ERR_CONSTRAINT_VIOLATION)
379 ldb = samba.tests.connect_samdb(host, credentials=creds, session_info=system_session(lp), lp=lp)
380 runner = SubunitTestRunner()
382 if not runner.run(unittest.makeSuite(SyntaxTests)).wasSuccessful():