1 """
2 Test cases for ldaptor.protocols.ldap.ldif module.
3 """
4
5 from twisted.trial import unittest
6 import sets
7 from ldaptor.protocols.ldap import ldifprotocol, distinguishedname
8
11 self.listOfCompleted = []
12 - def gotEntry(self, obj):
13 self.listOfCompleted.append(obj)
14
17 proto = LDIFDriver()
18 for line in (
19
20 "dn: cn=foo,dc=example,dc=com",
21 "objectClass: a",
22 "objectClass: b",
23 "aValue: a",
24 "aValue: b",
25 "bValue: c",
26 "",
27
28 "dn: cn=bar,dc=example,dc=com",
29 "objectClass: c",
30 "aValue:: IEZPTyE=",
31 "aValue: b",
32 "bValue: C",
33 "",
34
35 ):
36 proto.lineReceived(line)
37
38 self.failUnlessEqual(len(proto.listOfCompleted), 2)
39
40 o = proto.listOfCompleted.pop(0)
41 self.failUnlessEqual(str(o.dn), 'cn=foo,dc=example,dc=com')
42 self.failUnlessEqual(o['objectClass'], ['a', 'b'])
43 self.failUnlessEqual(o['aValue'], ['a', 'b'])
44 self.failUnlessEqual(o['bValue'], ['c'])
45
46 o = proto.listOfCompleted.pop(0)
47 self.failUnlessEqual(str(o.dn), 'cn=bar,dc=example,dc=com')
48 self.failUnlessEqual(o['objectClass'], ['c'])
49 self.failUnlessEqual(o['aValue'], [' FOO!', 'b'])
50 self.failUnlessEqual(o['bValue'], ['C'])
51
52 self.failUnlessEqual(proto.listOfCompleted, [])
53
55 proto = LDIFDriver()
56 for line in (
57
58 "dn: cn=foo,dc=ex",
59 " ample,dc=com",
60 "objectClass: a",
61 "ob",
62 " jectClass: b",
63 "",
64
65 ):
66 proto.lineReceived(line)
67
68 self.failUnlessEqual(len(proto.listOfCompleted), 1)
69
70 o = proto.listOfCompleted.pop(0)
71 self.failUnlessEqual(str(o.dn), 'cn=foo,dc=example,dc=com')
72 self.failUnlessEqual(o['objectClass'], ['a', 'b'])
73
74 self.failUnlessEqual(proto.listOfCompleted, [])
75
77 proto = LDIFDriver()
78 proto.dataReceived("""\
79 dn: cn=foo,dc=example,dc=com
80 objectClass: a
81 obJeCtClass: b
82 cn: foo
83 avalue: a
84 aValUe: b
85
86 """)
87
88 self.failUnlessEqual(len(proto.listOfCompleted), 1)
89
90 o = proto.listOfCompleted.pop(0)
91 self.failUnlessEqual(str(o.dn), 'cn=foo,dc=example,dc=com')
92 self.failUnlessEqual(o['objectClass'], ['a', 'b'])
93 self.failUnlessEqual(o['CN'], ['foo'])
94 self.failUnlessEqual(o['aValue'], ['a', 'b'])
95
96 self.failUnlessEqual(proto.listOfCompleted, [])
97
99 proto = LDIFDriver()
100 proto.dataReceived("""\
101 version: 1
102 dn: cn=foo,dc=example,dc=com
103 objectClass: a
104 objectClass: b
105 aValue: a
106 aValue: b
107 bValue: c
108
109 """)
110
111 self.failUnlessEqual(len(proto.listOfCompleted), 1)
112
113 o = proto.listOfCompleted.pop(0)
114 self.failUnlessEqual(str(o.dn), 'cn=foo,dc=example,dc=com')
115 self.failUnlessEqual(o['objectClass'], ['a', 'b'])
116 self.failUnlessEqual(o['aValue'], ['a', 'b'])
117 self.failUnlessEqual(o['bValue'], ['c'])
118
133
148
150 proto = LDIFDriver()
151 proto.dataReceived("""\
152 dn:cn=foo,dc=example,dc=com
153 objectClass:a
154 obJeCtClass:b
155 cn:foo
156 avalue:a
157 aValUe:b
158
159 """)
160
161 self.failUnlessEqual(len(proto.listOfCompleted), 1)
162
163 o = proto.listOfCompleted.pop(0)
164 self.failUnlessEqual(str(o.dn), 'cn=foo,dc=example,dc=com')
165 self.failUnlessEqual(o['objectClass'], ['a', 'b'])
166 self.failUnlessEqual(o['CN'], ['foo'])
167 self.failUnlessEqual(o['aValue'], ['a', 'b'])
168
169 self.failUnlessEqual(proto.listOfCompleted, [])
170
172 proto = LDIFDriver()
173 proto.dataReceived("""\
174 version: 1
175 dn: cn=foo,dc=example,dc=com
176 objectClass: a
177 objectClass: b
178 aValue: a
179 aValue: b
180 bValue: c
181 """)
182
183 self.failUnlessEqual(len(proto.listOfCompleted), 0)
184
185 self.assertRaises(ldifprotocol.LDIFTruncatedError,
186 proto.connectionLost)
187
189 examples = [
190 ( """Example 1: An simple LDAP file with two entries""",
191 """\
192 version: 1
193 dn: cn=Barbara Jensen, ou=Product Development, dc=airius, dc=com
194 objectclass: top
195 objectclass: person
196 objectclass: organizationalPerson
197 cn: Barbara Jensen
198 cn: Barbara J Jensen
199 cn: Babs Jensen
200 sn: Jensen
201 uid: bjensen
202 telephonenumber: +1 408 555 1212
203 description: A big sailing fan.
204
205 dn: cn=Bjorn Jensen, ou=Accounting, dc=airius, dc=com
206 objectclass: top
207 objectclass: person
208 objectclass: organizationalPerson
209 cn: Bjorn Jensen
210 sn: Jensen
211 telephonenumber: +1 408 555 1212
212
213 """,
214 [ ( 'cn=Barbara Jensen,ou=Product Development,dc=airius,dc=com',
215 { 'objectClass': ['top', 'person', 'organizationalPerson'],
216 'cn': ['Barbara Jensen',
217 'Barbara J Jensen',
218 'Babs Jensen'],
219 'sn': ['Jensen'],
220 'uid': ['bjensen'],
221 'telephonenumber': ['+1 408 555 1212'],
222 'description': ['A big sailing fan.'],
223 }),
224
225 ( 'cn=Bjorn Jensen,ou=Accounting,dc=airius,dc=com',
226 { 'objectClass': ['top', 'person', 'organizationalPerson'],
227 'cn': ['Bjorn Jensen'],
228 'sn': ['Jensen'],
229 'telephonenumber': ['+1 408 555 1212'],
230 }),
231 ]),
232
233 ( """Example 2: A file containing an entry with a folded attribute value""",
234 """\
235 version: 1
236 dn:cn=Barbara Jensen, ou=Product Development, dc=airius, dc=com
237 objectclass:top
238 objectclass:person
239 objectclass:organizationalPerson
240 cn:Barbara Jensen
241 cn:Barbara J Jensen
242 cn:Babs Jensen
243 sn:Jensen
244 uid:bjensen
245 telephonenumber:+1 408 555 1212
246 description:Babs is a big sailing fan, and travels extensively in sea
247 rch of perfect sailing conditions.
248 title:Product Manager, Rod and Reel Division
249
250 """,
251 [ ( 'cn=Barbara Jensen, ou=Product Development, dc=airius, dc=com',
252 { 'objectclass': ['top', 'person', 'organizationalPerson'],
253 'cn': ['Barbara Jensen', 'Barbara J Jensen', 'Babs Jensen'],
254 'sn': ['Jensen'],
255 'uid': ['bjensen'],
256 'telephonenumber': ['+1 408 555 1212'],
257 'description': ['Babs is a big sailing fan, and travels extensively in search of perfect sailing conditions.'],
258 'title': ['Product Manager, Rod and Reel Division'],
259 }),
260 ]),
261
262 ( """Example 3: A file containing a base-64-encoded value""",
263 """\
264 version: 1
265 dn: cn=Gern Jensen, ou=Product Testing, dc=airius, dc=com
266 objectclass: top
267 objectclass: person
268 objectclass: organizationalPerson
269 cn: Gern Jensen
270 cn: Gern O Jensen
271 sn: Jensen
272 uid: gernj
273 telephonenumber: +1 408 555 1212
274 description:: V2hhdCBhIGNhcmVmdWwgcmVhZGVyIHlvdSBhcmUhICBUaGlzIHZhbHVlIGlzIGJhc2UtNjQtZW5jb2RlZCBiZWNhdXNlIGl0IGhhcyBhIGNvbnRyb2wgY2hhcmFjdGVyIGluIGl0IChhIENSKS4NICBCeSB0aGUgd2F5LCB5b3Ugc2hvdWxkIHJlYWxseSBnZXQgb3V0IG1vcmUu
275
276 """,
277 [ ( 'cn=Gern Jensen, ou=Product Testing, dc=airius, dc=com',
278 { 'objectclass': ['top', 'person', 'organizationalPerson'],
279 'cn': ['Gern Jensen', 'Gern O Jensen'],
280 'sn': ['Jensen'],
281 'uid': ['gernj'],
282 'telephonenumber': ['+1 408 555 1212'],
283 'description': ['What a careful reader you are! This value is base-64-encoded because it has a control character in it (a CR).\r By the way, you should really get out more.'],
284 }),
285 ]),
286
287 ]
288
308
309 """
310 TODO more tests from RFC2849:
311
312 Example 4: A file containing an entries with UTF-8-encoded attribute
313 values, including language tags. Comments indicate the contents
314 of UTF-8-encoded attributes and distinguished names.
315
316 version: 1
317 dn:: b3U95Za25qWt6YOoLG89QWlyaXVz
318 # dn:: ou=<JapaneseOU>,o=Airius
319 objectclass: top
320 objectclass: organizationalUnit
321 ou:: 5Za25qWt6YOo
322 # ou:: <JapaneseOU>
323 ou;lang-ja:: 5Za25qWt6YOo
324 # ou;lang-ja:: <JapaneseOU>
325 ou;lang-ja;phonetic:: 44GI44GE44GO44KH44GG44G2
326
327 # ou;lang-ja:: <JapaneseOU_in_phonetic_representation>
328 ou;lang-en: Sales
329 description: Japanese office
330
331 dn:: dWlkPXJvZ2FzYXdhcmEsb3U95Za25qWt6YOoLG89QWlyaXVz
332 # dn:: uid=<uid>,ou=<JapaneseOU>,o=Airius
333 userpassword: {SHA}O3HSv1MusyL4kTjP+HKI5uxuNoM=
334 objectclass: top
335 objectclass: person
336 objectclass: organizationalPerson
337 objectclass: inetOrgPerson
338 uid: rogasawara
339 mail: rogasawara@airius.co.jp
340 givenname;lang-ja:: 44Ot44OJ44OL44O8
341 # givenname;lang-ja:: <JapaneseGivenname>
342 sn;lang-ja:: 5bCP56yg5Y6f
343 # sn;lang-ja:: <JapaneseSn>
344 cn;lang-ja:: 5bCP56yg5Y6fIOODreODieODi+ODvA==
345 # cn;lang-ja:: <JapaneseCn>
346 title;lang-ja:: 5Za25qWt6YOoIOmDqOmVtw==
347 # title;lang-ja:: <JapaneseTitle>
348 preferredlanguage: ja
349 givenname:: 44Ot44OJ44OL44O8
350 # givenname:: <JapaneseGivenname>
351 sn:: 5bCP56yg5Y6f
352 # sn:: <JapaneseSn>
353 cn:: 5bCP56yg5Y6fIOODreODieODi+ODvA==
354 # cn:: <JapaneseCn>
355 title:: 5Za25qWt6YOoIOmDqOmVtw==
356 # title:: <JapaneseTitle>
357 givenname;lang-ja;phonetic:: 44KN44Gp44Gr44O8
358 # givenname;lang-ja;phonetic::
359 <JapaneseGivenname_in_phonetic_representation_kana>
360 sn;lang-ja;phonetic:: 44GK44GM44GV44KP44KJ
361 # sn;lang-ja;phonetic:: <JapaneseSn_in_phonetic_representation_kana>
362 cn;lang-ja;phonetic:: 44GK44GM44GV44KP44KJIOOCjeOBqeOBq+ODvA==
363 # cn;lang-ja;phonetic:: <JapaneseCn_in_phonetic_representation_kana>
364 title;lang-ja;phonetic:: 44GI44GE44GO44KH44GG44G2IOOBtuOBoeOCh+OBhg==
365 # title;lang-ja;phonetic::
366 # <JapaneseTitle_in_phonetic_representation_kana>
367 givenname;lang-en: Rodney
368 sn;lang-en: Ogasawara
369 cn;lang-en: Rodney Ogasawara
370 title;lang-en: Sales, Director
371 """
372
373 """
374 Example 5: A file containing a reference to an external file
375
376 version: 1
377 dn: cn=Horatio Jensen, ou=Product Testing, dc=airius, dc=com
378 objectclass: top
379 objectclass: person
380 objectclass: organizationalPerson
381 cn: Horatio Jensen
382
383 cn: Horatio N Jensen
384 sn: Jensen
385 uid: hjensen
386 telephonenumber: +1 408 555 1212
387 jpegphoto:< file:///usr/local/directory/photos/hjensen.jpg
388 """
389
390 """
391 Example 6: A file containing a series of change records and comments
392
393 version: 1
394 # Add a new entry
395 dn: cn=Fiona Jensen, ou=Marketing, dc=airius, dc=com
396 changetype: add
397 objectclass: top
398 objectclass: person
399 objectclass: organizationalPerson
400 cn: Fiona Jensen
401 sn: Jensen
402 uid: fiona
403 telephonenumber: +1 408 555 1212
404 jpegphoto:< file:///usr/local/directory/photos/fiona.jpg
405
406 # Delete an existing entry
407 dn: cn=Robert Jensen, ou=Marketing, dc=airius, dc=com
408 changetype: delete
409
410 # Modify an entry's relative distinguished name
411 dn: cn=Paul Jensen, ou=Product Development, dc=airius, dc=com
412 changetype: modrdn
413 newrdn: cn=Paula Jensen
414 deleteoldrdn: 1
415
416 # Rename an entry and move all of its children to a new location in
417 # the directory tree (only implemented by LDAPv3 servers).
418 dn: ou=PD Accountants, ou=Product Development, dc=airius, dc=com
419 changetype: modrdn
420 newrdn: ou=Product Development Accountants
421 deleteoldrdn: 0
422 newsuperior: ou=Accounting, dc=airius, dc=com
423
424 # Modify an entry: add an additional value to the postaladdress
425 # attribute, completely delete the description attribute, replace
426 # the telephonenumber attribute with two values, and delete a specific
427 # value from the facsimiletelephonenumber attribute
428 dn: cn=Paula Jensen, ou=Product Development, dc=airius, dc=com
429 changetype: modify
430 add: postaladdress
431 postaladdress: 123 Anystreet $ Sunnyvale, CA $ 94086
432 -
433 delete: description
434 -
435 replace: telephonenumber
436 telephonenumber: +1 408 555 1234
437 telephonenumber: +1 408 555 5678
438 -
439 delete: facsimiletelephonenumber
440 facsimiletelephonenumber: +1 408 555 9876
441 -
442
443 # Modify an entry: replace the postaladdress attribute with an empty
444 # set of values (which will cause the attribute to be removed), and
445 # delete the entire description attribute. Note that the first will
446 # always succeed, while the second will only succeed if at least
447 # one value for the description attribute is present.
448 dn: cn=Ingrid Jensen, ou=Product Support, dc=airius, dc=com
449 changetype: modify
450 replace: postaladdress
451 -
452 delete: description
453 -
454 """
455
456 """
457 Example 7: An LDIF file containing a change record with a control
458 version: 1
459 # Delete an entry. The operation will attach the LDAPv3
460 # Tree Delete Control defined in [9]. The criticality
461 # field is "true" and the controlValue field is
462 # absent, as required by [9].
463 dn: ou=Product Development, dc=airius, dc=com
464 control: 1.2.840.113556.1.4.805 true
465 changetype: delete
466
467 """
468