powerhome-activeldap 3.2.3

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (145) hide show
  1. checksums.yaml +7 -0
  2. data/.yardopts +6 -0
  3. data/COPYING +340 -0
  4. data/Gemfile +12 -0
  5. data/LICENSE +59 -0
  6. data/README.textile +140 -0
  7. data/TODO +32 -0
  8. data/benchmark/README.md +64 -0
  9. data/benchmark/bench-backend.rb +247 -0
  10. data/benchmark/bench-instantiate.rb +98 -0
  11. data/benchmark/config.yaml.sample +5 -0
  12. data/doc/text/development.textile +54 -0
  13. data/doc/text/news.textile +811 -0
  14. data/doc/text/rails.textile +144 -0
  15. data/doc/text/tutorial.textile +1010 -0
  16. data/examples/config.yaml.example +5 -0
  17. data/examples/example.der +0 -0
  18. data/examples/example.jpg +0 -0
  19. data/examples/groupadd +41 -0
  20. data/examples/groupdel +35 -0
  21. data/examples/groupls +49 -0
  22. data/examples/groupmod +42 -0
  23. data/examples/lpasswd +55 -0
  24. data/examples/objects/group.rb +13 -0
  25. data/examples/objects/ou.rb +4 -0
  26. data/examples/objects/user.rb +20 -0
  27. data/examples/ouadd +38 -0
  28. data/examples/useradd +45 -0
  29. data/examples/useradd-binary +53 -0
  30. data/examples/userdel +34 -0
  31. data/examples/userls +50 -0
  32. data/examples/usermod +42 -0
  33. data/examples/usermod-binary-add +50 -0
  34. data/examples/usermod-binary-add-time +54 -0
  35. data/examples/usermod-binary-del +48 -0
  36. data/examples/usermod-lang-add +43 -0
  37. data/lib/active_ldap.rb +85 -0
  38. data/lib/active_ldap/action_controller/ldap_benchmarking.rb +55 -0
  39. data/lib/active_ldap/acts/tree.rb +78 -0
  40. data/lib/active_ldap/adapter/base.rb +707 -0
  41. data/lib/active_ldap/adapter/jndi.rb +184 -0
  42. data/lib/active_ldap/adapter/jndi_connection.rb +185 -0
  43. data/lib/active_ldap/adapter/ldap.rb +290 -0
  44. data/lib/active_ldap/adapter/ldap_ext.rb +105 -0
  45. data/lib/active_ldap/adapter/net_ldap.rb +309 -0
  46. data/lib/active_ldap/adapter/net_ldap_ext.rb +23 -0
  47. data/lib/active_ldap/association/belongs_to.rb +47 -0
  48. data/lib/active_ldap/association/belongs_to_many.rb +58 -0
  49. data/lib/active_ldap/association/children.rb +21 -0
  50. data/lib/active_ldap/association/collection.rb +105 -0
  51. data/lib/active_ldap/association/has_many.rb +31 -0
  52. data/lib/active_ldap/association/has_many_utils.rb +44 -0
  53. data/lib/active_ldap/association/has_many_wrap.rb +75 -0
  54. data/lib/active_ldap/association/proxy.rb +107 -0
  55. data/lib/active_ldap/associations.rb +205 -0
  56. data/lib/active_ldap/attribute_methods.rb +23 -0
  57. data/lib/active_ldap/attribute_methods/before_type_cast.rb +24 -0
  58. data/lib/active_ldap/attribute_methods/dirty.rb +43 -0
  59. data/lib/active_ldap/attribute_methods/query.rb +31 -0
  60. data/lib/active_ldap/attribute_methods/read.rb +44 -0
  61. data/lib/active_ldap/attribute_methods/write.rb +38 -0
  62. data/lib/active_ldap/attributes.rb +176 -0
  63. data/lib/active_ldap/base.rb +1410 -0
  64. data/lib/active_ldap/callbacks.rb +71 -0
  65. data/lib/active_ldap/command.rb +49 -0
  66. data/lib/active_ldap/compatible.rb +44 -0
  67. data/lib/active_ldap/configuration.rb +147 -0
  68. data/lib/active_ldap/connection.rb +299 -0
  69. data/lib/active_ldap/distinguished_name.rb +291 -0
  70. data/lib/active_ldap/entry_attribute.rb +78 -0
  71. data/lib/active_ldap/escape.rb +12 -0
  72. data/lib/active_ldap/get_text.rb +20 -0
  73. data/lib/active_ldap/get_text/parser.rb +161 -0
  74. data/lib/active_ldap/helper.rb +92 -0
  75. data/lib/active_ldap/human_readable.rb +133 -0
  76. data/lib/active_ldap/ldap_error.rb +74 -0
  77. data/lib/active_ldap/ldif.rb +930 -0
  78. data/lib/active_ldap/log_subscriber.rb +50 -0
  79. data/lib/active_ldap/object_class.rb +95 -0
  80. data/lib/active_ldap/operations.rb +624 -0
  81. data/lib/active_ldap/persistence.rb +100 -0
  82. data/lib/active_ldap/populate.rb +53 -0
  83. data/lib/active_ldap/railtie.rb +43 -0
  84. data/lib/active_ldap/railties/controller_runtime.rb +48 -0
  85. data/lib/active_ldap/schema.rb +701 -0
  86. data/lib/active_ldap/schema/syntaxes.rb +422 -0
  87. data/lib/active_ldap/timeout.rb +75 -0
  88. data/lib/active_ldap/timeout_stub.rb +17 -0
  89. data/lib/active_ldap/user_password.rb +99 -0
  90. data/lib/active_ldap/validations.rb +200 -0
  91. data/lib/active_ldap/version.rb +3 -0
  92. data/lib/active_ldap/xml.rb +139 -0
  93. data/lib/rails/generators/active_ldap/model/USAGE +18 -0
  94. data/lib/rails/generators/active_ldap/model/model_generator.rb +47 -0
  95. data/lib/rails/generators/active_ldap/model/templates/model_active_ldap.rb +3 -0
  96. data/lib/rails/generators/active_ldap/scaffold/scaffold_generator.rb +14 -0
  97. data/lib/rails/generators/active_ldap/scaffold/templates/ldap.yml +19 -0
  98. data/po/en/active-ldap.po +4029 -0
  99. data/po/ja/active-ldap.po +4060 -0
  100. data/test/add-phonetic-attribute-options-to-slapd.ldif +10 -0
  101. data/test/al-test-utils.rb +428 -0
  102. data/test/command.rb +111 -0
  103. data/test/config.yaml.sample +6 -0
  104. data/test/fixtures/lower_case_object_class_schema.rb +802 -0
  105. data/test/run-test.rb +34 -0
  106. data/test/test_acts_as_tree.rb +60 -0
  107. data/test/test_adapter.rb +121 -0
  108. data/test/test_associations.rb +701 -0
  109. data/test/test_attributes.rb +117 -0
  110. data/test/test_base.rb +1214 -0
  111. data/test/test_base_per_instance.rb +61 -0
  112. data/test/test_bind.rb +62 -0
  113. data/test/test_callback.rb +31 -0
  114. data/test/test_configuration.rb +40 -0
  115. data/test/test_connection.rb +82 -0
  116. data/test/test_connection_per_class.rb +112 -0
  117. data/test/test_connection_per_dn.rb +112 -0
  118. data/test/test_dirty.rb +98 -0
  119. data/test/test_dn.rb +172 -0
  120. data/test/test_find.rb +176 -0
  121. data/test/test_groupadd.rb +50 -0
  122. data/test/test_groupdel.rb +46 -0
  123. data/test/test_groupls.rb +107 -0
  124. data/test/test_groupmod.rb +51 -0
  125. data/test/test_ldif.rb +1890 -0
  126. data/test/test_load.rb +133 -0
  127. data/test/test_lpasswd.rb +75 -0
  128. data/test/test_object_class.rb +74 -0
  129. data/test/test_persistence.rb +131 -0
  130. data/test/test_reflection.rb +175 -0
  131. data/test/test_schema.rb +559 -0
  132. data/test/test_syntax.rb +444 -0
  133. data/test/test_user.rb +217 -0
  134. data/test/test_user_password.rb +108 -0
  135. data/test/test_useradd-binary.rb +62 -0
  136. data/test/test_useradd.rb +57 -0
  137. data/test/test_userdel.rb +48 -0
  138. data/test/test_userls.rb +91 -0
  139. data/test/test_usermod-binary-add-time.rb +65 -0
  140. data/test/test_usermod-binary-add.rb +64 -0
  141. data/test/test_usermod-binary-del.rb +66 -0
  142. data/test/test_usermod-lang-add.rb +59 -0
  143. data/test/test_usermod.rb +58 -0
  144. data/test/test_validation.rb +274 -0
  145. metadata +379 -0
@@ -0,0 +1,559 @@
1
+ require 'al-test-utils'
2
+
3
+ class TestSchema < Test::Unit::TestCase
4
+ priority :must
5
+ def test_directory_operation
6
+ attributes_schema =
7
+ "( 2.5.18.1 NAME 'createTimestamp' " +
8
+ "DESC 'RFC4512: time which ob ject was created' " +
9
+ "EQUALITY generalizedTimeMatch " +
10
+ "ORDERING generalizedTimeOrderingMatch " +
11
+ "SYNTAX 1.3.6.1.4.1.1466.115.121.1.24 " +
12
+ "SINGLE-VALUE NO-USER-MODIFICATION USAGE directoryOperation )"
13
+
14
+ assert_attribute_type({
15
+ :read_only => true,
16
+ :single_value => true,
17
+ :binary => false,
18
+ :binary_required => false,
19
+ :directory_operation => true,
20
+ :syntax => "1.3.6.1.4.1.1466.115.121.1.24",
21
+ :syntax_description => nil,
22
+ },
23
+ "createTimestamp",
24
+ [attributes_schema])
25
+ end
26
+
27
+ priority :normal
28
+ def test_dit_content_rule
29
+ object_class_schema = "( 2.5.6.6 NAME 'person' DESC " +
30
+ "'RFC2256: a person' SUP top STRUCTURAL MUST sn " +
31
+ "MAY ( userPassword $ telephoneNumber ) )"
32
+ dit_content_rule_schema = "( 2.5.6.6 NAME 'person' MUST cn " +
33
+ "MAY ( seeAlso $ description ) )"
34
+ attributes_schema =
35
+ [
36
+ "( 2.5.4.3 NAME 'cn' SYNTAX '1.3.6.1.4.1.1466.115.121.1.15' SINGLE-VALUE )",
37
+ "( 2.5.4.4 NAME 'sn' SYNTAX '1.3.6.1.4.1.1466.115.121.1.15' SINGLE-VALUE )",
38
+ "( 2.5.4.35 NAME 'userPassword' SYNTAX '1.3.6.1.4.1.1466.115.121.1.40' )",
39
+ "( 2.5.4.20 NAME 'telephoneNumber' SYNTAX '1.3.6.1.4.1.1466.115.121.1.15' SINGLE-VALUE )",
40
+ "( 2.5.4.34 NAME 'seeAlso' SYNTAX '1.3.6.1.4.1.1466.115.121.1.12' )",
41
+ "( 2.5.4.13 NAME 'description' SYNTAX '1.3.6.1.4.1.1466.115.121.1.15' )",
42
+ ]
43
+
44
+ entry = {
45
+ "objectClasses" => [object_class_schema],
46
+ "dITContentRules" => [dit_content_rule_schema],
47
+ "attributeTypes" => attributes_schema,
48
+ }
49
+
50
+ schema = ActiveLdap::Schema.new(entry)
51
+ object_class = schema.object_class("person")
52
+ assert_equal({
53
+ :must => ["sn", "cn"],
54
+ :may => ["userPassword", "telephoneNumber",
55
+ "seeAlso", "description"],
56
+ },
57
+ {
58
+ :must => object_class.must.collect(&:name),
59
+ :may => object_class.may.collect(&:name),
60
+ })
61
+ end
62
+
63
+ def test_oid_list_with_just_only_one_oid
64
+ ou_schema = "( 2.5.6.5 NAME 'organizationalUnit' SUP top STRUCTURAL MUST " +
65
+ "(ou ) MAY (c $ l $ st $ street $ searchGuide $ businessCategory $ " +
66
+ "postalAddress $ postalCode $ postOfficeBox $ " +
67
+ "physicalDeliveryOfficeName $ telephoneNumber $ telexNumber $ " +
68
+ "teletexTerminalIdentifier $ facsimileTelephoneNumber $ x121Address $ " +
69
+ "internationalISDNNumber $ registeredAddress $ destinationIndicator $ " +
70
+ "preferredDeliveryMethod $ seeAlso $ userPassword $ co $ countryCode $ " +
71
+ "desktopProfile $ defaultGroup $ managedBy $ uPNSuffixes $ gPLink $ " +
72
+ "gPOptions $ msCOM-UserPartitionSetLink $ thumbnailLogo ) ) "
73
+
74
+ expect = {
75
+ :name => ["organizationalUnit"],
76
+ :sup => ["top"],
77
+ :structural => ["TRUE"],
78
+ :must => %w(ou),
79
+ :may => %w(c l st street searchGuide businessCategory
80
+ postalAddress postalCode postOfficeBox
81
+ physicalDeliveryOfficeName telephoneNumber telexNumber
82
+ teletexTerminalIdentifier facsimileTelephoneNumber
83
+ x121Address internationalISDNNumber registeredAddress
84
+ destinationIndicator preferredDeliveryMethod seeAlso
85
+ userPassword co countryCode desktopProfile defaultGroup
86
+ managedBy uPNSuffixes gPLink gPOptions
87
+ msCOM-UserPartitionSetLink thumbnailLogo),
88
+ }
89
+ assert_schema(expect, "2.5.6.5", ou_schema)
90
+ assert_schema(expect, "organizationalUnit", ou_schema)
91
+ end
92
+
93
+ def test_normalize_attribute_value
94
+ entry = {
95
+ "attributeTypes" =>
96
+ [
97
+ "( 0.9.2342.19200300.100.1.25 NAME ( 'dc' 'domainComponent' ) DESC " +
98
+ "'RFC1274/2247: domain component' EQUALITY caseIgnoreIA5Match SUBSTR " +
99
+ "caseIgnoreIA5SubstringsMatch SYNTAX 1.3.6.1.4.1.1466.115.121.1.26 " +
100
+ "SINGLE-VALUE )",
101
+ ],
102
+ "ldapSyntaxes" =>
103
+ [
104
+ "( 1.3.6.1.4.1.1466.109.114.1 NAME 'caseExactIA5Match' " +
105
+ "SYNTAX 1.3.6.1.4.1.1466.115.121.1.26 )",
106
+ ],
107
+ }
108
+
109
+ schema = ActiveLdap::Schema.new(entry)
110
+ dc = schema.attribute("dc")
111
+ assert_equal(["com"], dc.normalize_value("com"))
112
+ assert_equal(["com"], dc.normalize_value(["com"]))
113
+ assert_raise(ActiveLdap::AttributeValueInvalid) do
114
+ dc.normalize_value(["com", "co.jp"])
115
+ end
116
+ assert_equal([{"lang-en" => ["com"]},
117
+ {"lang-ja" => ["co.jp"]}],
118
+ dc.normalize_value([{"lang-en" => "com"},
119
+ {"lang-ja" => "co.jp"}]))
120
+ end
121
+
122
+ def test_syntax_validation
123
+ entry = {
124
+ "attributeTypes" =>
125
+ [
126
+ "( 2.5.4.34 NAME 'seeAlso' DESC 'RFC2256: DN of related object'" +
127
+ "SUP distinguishedName )",
128
+ "( 2.5.4.49 NAME 'distinguishedName' DESC 'RFC2256: common " +
129
+ "supertype of DN attributes' EQUALITY distinguishedNameMatch "+
130
+ "SYNTAX 1.3.6.1.4.1.1466.115.121.1.12 )",
131
+ ],
132
+ "ldapSyntaxes" =>
133
+ [
134
+ "( 1.3.6.1.4.1.1466.115.121.1.12 DESC 'Distinguished Name' )",
135
+ ],
136
+ }
137
+
138
+ schema = ActiveLdap::Schema.new(entry)
139
+ see_also = schema.attribute("seeAlso")
140
+ assert(see_also.valid?("cn=test,dc=example,dc=com"))
141
+ assert(!see_also.valid?("test"))
142
+ end
143
+
144
+ def test_super_class?
145
+ group = 'objectClasses'
146
+ entry = {
147
+ group => [
148
+ "( 2.5.6.6 NAME 'person' DESC 'RFC2256: a person' SUP " +
149
+ "top STRUCTURAL MUST ( sn $ cn ) MAY ( userPassword $ " +
150
+ "telephoneNumber $ seeAlso $ description ) )",
151
+
152
+ "( 2.5.6.7 NAME 'organizationalPerson' DESC 'RFC2256: " +
153
+ "an organizational person' SUP person STRUCTURAL MAY ( " +
154
+ "title $ x121Address $ registeredAddress $ " +
155
+ "destinationIndicator $ preferredDeliveryMethod $ " +
156
+ "telexNumber $ teletexTerminalIdentifier $ telephoneNumber " +
157
+ "$ internationaliSDNNumber $ facsimileTelephoneNumber $ " +
158
+ "street $ postOfficeBox $ postalCode $ postalAddress $ " +
159
+ "physicalDeliveryOfficeName $ ou $ st $ l ) )",
160
+
161
+ "( 2.16.840.1.113730.3.2.2 NAME 'inetOrgPerson' DESC " +
162
+ "'RFC2798: Internet Organizational Person' SUP " +
163
+ "organizationalPerson STRUCTURAL MAY ( audio $ " +
164
+ "businessCategory $ carLicense $ departmentNumber $ " +
165
+ "displayName $ employeeNumber $ employeeType $ givenName " +
166
+ "$ homePhone $ homePostalAddress $ initials $ jpegPhoto " +
167
+ "$ labeledURI $ mail $ manager $ mobile $ o $ pager $ " +
168
+ "photo $ roomNumber $ secretary $ uid $ userCertificate $ " +
169
+ "x500UniqueIdentifier $ preferredLanguage $ " +
170
+ "userSMIMECertificate $ userPKCS12 ) )",
171
+ ]
172
+ }
173
+ schema = ActiveLdap::Schema.new(entry)
174
+
175
+ person = schema.object_class('person')
176
+ organizational_person = schema.object_class("organizationalPerson")
177
+ inet_org_person = schema.object_class("inetOrgPerson")
178
+
179
+ assert_equal([false, false, false],
180
+ [person.super_class?(person),
181
+ person.super_class?(organizational_person),
182
+ person.super_class?(inet_org_person)])
183
+
184
+ assert_equal([true, false, false],
185
+ [organizational_person.super_class?(person),
186
+ organizational_person.super_class?(organizational_person),
187
+ organizational_person.super_class?(inet_org_person)])
188
+
189
+ assert_equal([true, true, false],
190
+ [inet_org_person.super_class?(person),
191
+ inet_org_person.super_class?(organizational_person),
192
+ inet_org_person.super_class?(inet_org_person)])
193
+ end
194
+
195
+ def test_duplicate_schema
196
+ sasNMASProductOptions_schema =
197
+ "( 2.16.840.1.113719.1.39.42.1.0.38 NAME 'sasNMASProductOptions' " +
198
+ "SYNTAX 1.3.6.1.4.1.1466.115.121.1.40{64512} SINGLE-VALUE " +
199
+ "X-NDS_PUBLIC_READ '1' )"
200
+ rADIUSActiveConnections_schema =
201
+ "( 2.16.840.1.113719.1.39.42.1.0.38 NAME 'rADIUSActiveConnections' " +
202
+ "SYNTAX 1.3.6.1.4.1.1466.115.121.1.40{64512} X-NDS_NAME " +
203
+ "'RADIUS:ActiveConnections' X-NDS_NOT_SCHED_SYNC_IMMEDIATE '1' )"
204
+
205
+ sasNMASProductOptions = 'sasNMASProductOptions'
206
+ rADIUSActiveConnections = 'rADIUSActiveConnections'
207
+ sasNMASProductOptions_aliases =
208
+ [sasNMASProductOptions, []]
209
+ rADIUSActiveConnections_aliases =
210
+ [rADIUSActiveConnections, []]
211
+ sas_radius_aliases = [sasNMASProductOptions, [rADIUSActiveConnections]]
212
+ radius_sas_aliases = [rADIUSActiveConnections, [sasNMASProductOptions]]
213
+
214
+ assert_attribute_aliases([sasNMASProductOptions_aliases],
215
+ [sasNMASProductOptions],
216
+ [sasNMASProductOptions_schema],
217
+ false)
218
+ assert_attribute_aliases([rADIUSActiveConnections_aliases],
219
+ [rADIUSActiveConnections],
220
+ [rADIUSActiveConnections_schema],
221
+ false)
222
+
223
+ assert_attribute_aliases([sasNMASProductOptions_aliases,
224
+ sas_radius_aliases],
225
+ [sasNMASProductOptions,
226
+ rADIUSActiveConnections],
227
+ [sasNMASProductOptions_schema,
228
+ rADIUSActiveConnections_schema],
229
+ false)
230
+ assert_attribute_aliases([rADIUSActiveConnections_aliases,
231
+ radius_sas_aliases],
232
+ [rADIUSActiveConnections,
233
+ sasNMASProductOptions],
234
+ [rADIUSActiveConnections_schema,
235
+ sasNMASProductOptions_schema],
236
+ false)
237
+
238
+ assert_attribute_aliases([sas_radius_aliases,
239
+ sas_radius_aliases],
240
+ [rADIUSActiveConnections,
241
+ sasNMASProductOptions],
242
+ [sasNMASProductOptions_schema,
243
+ rADIUSActiveConnections_schema],
244
+ false)
245
+ assert_attribute_aliases([radius_sas_aliases,
246
+ radius_sas_aliases],
247
+ [sasNMASProductOptions,
248
+ rADIUSActiveConnections],
249
+ [rADIUSActiveConnections_schema,
250
+ sasNMASProductOptions_schema],
251
+ false)
252
+
253
+ assert_attribute_aliases([sas_radius_aliases,
254
+ sas_radius_aliases],
255
+ [sasNMASProductOptions,
256
+ rADIUSActiveConnections],
257
+ [sasNMASProductOptions_schema,
258
+ rADIUSActiveConnections_schema],
259
+ true)
260
+ assert_attribute_aliases([radius_sas_aliases,
261
+ radius_sas_aliases],
262
+ [rADIUSActiveConnections,
263
+ sasNMASProductOptions],
264
+ [rADIUSActiveConnections_schema,
265
+ sasNMASProductOptions_schema],
266
+ true)
267
+ end
268
+
269
+ def test_empty_schema
270
+ assert_make_schema_with_empty_entries(nil)
271
+ assert_make_schema_with_empty_entries({})
272
+ assert_make_schema_with_empty_entries({"someValues" => ["aValue"]})
273
+ end
274
+
275
+ def test_empty_schema_value
276
+ schema = ActiveLdap::Schema.new({"attributeTypes" => nil})
277
+ assert_equal([], schema["attributeTypes", "cn", "DESC"])
278
+ end
279
+
280
+ def test_attribute_name_with_under_score
281
+ top_schema =
282
+ "( 2.5.6.0 NAME 'Top' STRUCTURAL MUST objectClass MAY ( " +
283
+ "cAPublicKey $ cAPrivateKey $ certificateValidityInterval $ " +
284
+ "authorityRevocation $ lastReferencedTime $ " +
285
+ "equivalentToMe $ ACL $ backLink $ binderyProperty $ " +
286
+ "Obituary $ Reference $ revision $ " +
287
+ "ndsCrossCertificatePair $ certificateRevocation $ " +
288
+ "usedBy $ GUID $ otherGUID $ DirXML-Associations $ " +
289
+ "creatorsName $ modifiersName $ unknownBaseClass $ " +
290
+ "unknownAuxiliaryClass $ auditFileLink $ " +
291
+ "masvProposedLabelel $ masvDefaultRange $ " +
292
+ "masvAuthorizedRange $ objectVersion $ " +
293
+ "auxClassCompatibility $ rbsAssignedRoles $ " +
294
+ "rbsOwnedCollections $ rbsAssignedRoles2 $ " +
295
+ "rbsOwnedCollections2 ) X-NDS_NONREMOVABLE '1' " +
296
+ "X-NDS_ACL_TEMPLATES '16#subtree#[Creator]#[Entry Rights]' )"
297
+
298
+ expect = {
299
+ :name => ["Top"],
300
+ :structural => ["TRUE"],
301
+ :must => ["objectClass"],
302
+ :x_nds_nonremovable => ["1"],
303
+ :x_nds_acl_templates => ['16#subtree#[Creator]#[Entry Rights]'],
304
+ }
305
+ assert_schema(expect, "Top", top_schema)
306
+ end
307
+
308
+ def test_sup_with_oid_start_with_upper_case
309
+ organizational_person_schema =
310
+ "( 2.5.6.7 NAME 'organizationalPerson' SUP Person STRUCTURAL MAY " +
311
+ "( facsimileTelephoneNumber $ l $ eMailAddress $ ou $ " +
312
+ "physicalDeliveryOfficeName $ postalAddress $ postalCode $ " +
313
+ "postOfficeBox $ st $ street $ title $ mailboxLocation $ " +
314
+ "mailboxID $ uid $ mail $ employeeNumber $ destinationIndicator $ " +
315
+ "internationaliSDNNumber $ preferredDeliveryMethod $ " +
316
+ "registeredAddress $ teletexTerminalIdentifier $ telexNumber $ " +
317
+ "x121Address $ businessCategory $ roomNumber $ x500UniqueIdentifier " +
318
+ ") X-NDS_NAMING ( 'cn' 'ou' 'uid' ) X-NDS_CONTAINMENT ( " +
319
+ "'Organization' 'organizationalUnit' 'domain' ) X-NDS_NAME " +
320
+ "'Organizational Person' X-NDS_NOT_CONTAINER '1' " +
321
+ "X-NDS_NONREMOVABLE '1' )"
322
+
323
+ expect = {
324
+ :name => ["organizationalPerson"],
325
+ :sup => ["Person"],
326
+ :structural => ["TRUE"],
327
+ :x_nds_naming => ["cn", "ou", "uid"],
328
+ :x_nds_containment => ["Organization", "organizationalUnit", "domain"],
329
+ :x_nds_name => ["Organizational Person"],
330
+ :x_nds_not_container => ["1"],
331
+ :x_nds_nonremovable => ["1"],
332
+ }
333
+ assert_schema(expect, "organizationalPerson",
334
+ organizational_person_schema)
335
+ end
336
+
337
+ def test_text_oid
338
+ text_oid_schema = "( mysite-oid NAME 'mysite' " +
339
+ "SUP groupofuniquenames STRUCTURAL " +
340
+ "MUST ( mysitelang $ mysiteurl ) " +
341
+ "MAY ( mysitealias $ mysitecmsurl ) " +
342
+ "X-ORIGIN 'user defined' )"
343
+ expect = {
344
+ :name => ["mysite"],
345
+ :sup => ["groupofuniquenames"],
346
+ :structural => ["TRUE"],
347
+ :must => %w(mysitelang mysiteurl),
348
+ :may => %w(mysitealias mysitecmsurl),
349
+ :x_origin => ["user defined"]
350
+ }
351
+ assert_schema(expect, "mysite", text_oid_schema)
352
+
353
+ text_oid_attribute_schema = "( mysiteurl-oid NAME 'mysiteurl' " +
354
+ "SYNTAX 1.3.6.1.4.1.1466.115.121.1.15 " +
355
+ "SINGLE-VALUE X-ORIGIN 'user defined' )"
356
+ expect = {
357
+ :name => ["mysiteurl"],
358
+ :syntax => ["1.3.6.1.4.1.1466.115.121.1.15"],
359
+ :single_value => ["TRUE"],
360
+ :x_origin => ["user defined"]
361
+ }
362
+ assert_schema(expect, "mysiteurl", text_oid_attribute_schema)
363
+ end
364
+
365
+ def test_name_as_key
366
+ top_schema = "( 2.5.6.0 NAME 'top' DESC 'top of the superclass chain' " +
367
+ "ABSTRACT MUST objectClass )"
368
+ expect = {
369
+ :name => ["top"],
370
+ :desc => ['top of the superclass chain'],
371
+ :abstract => ["TRUE"],
372
+ :must => ["objectClass"]
373
+ }
374
+ assert_schema(expect, "2.5.6.0", top_schema)
375
+ assert_schema(expect, "top", top_schema)
376
+ end
377
+
378
+ def test_name_as_key_for_multiple_name
379
+ uid_schema = "( 0.9.2342.19200300.100.1.1 NAME ( 'uid' 'userid' ) " +
380
+ "DESC 'RFC1274: user identifier' EQUALITY caseIgnoreMatch " +
381
+ "SUBSTR caseIgnoreSubstringsMatch " +
382
+ "SYNTAX 1.3.6.1.4.1.1466.115.121.1.15{256} )"
383
+
384
+ expect = {
385
+ :name => ["uid", "userid"],
386
+ :desc => ['RFC1274: user identifier'],
387
+ :equality => ["caseIgnoreMatch"],
388
+ :substr => ["caseIgnoreSubstringsMatch"],
389
+ :syntax => ["1.3.6.1.4.1.1466.115.121.1.15{256}"],
390
+ }
391
+ assert_schema(expect, "0.9.2342.19200300.100.1.1", uid_schema)
392
+ assert_schema(expect, "uid", uid_schema)
393
+ assert_schema(expect, "userid", uid_schema)
394
+ end
395
+
396
+ def test_dollar
397
+ dn_match_schema = "( 2.5.13.1 NAME 'distinguishedNameMatch' APPLIES " +
398
+ "( creatorsName $ modifiersName $ subschemaSubentry " +
399
+ "$ namingContexts $ aliasedObjectName $ " +
400
+ "distinguishedName $ seeAlso $ olcDefaultSearchBase $ " +
401
+ "olcRootDN $ olcSchemaDN $ olcSuffix $ olcUpdateDN $ " +
402
+ "member $ owner $ roleOccupant $ manager $ " +
403
+ "documentAuthor $ secretary $ associatedName $ " +
404
+ "dITRedirect ) )"
405
+
406
+ expect = {
407
+ :name => ["distinguishedNameMatch"],
408
+ :applies => %w(creatorsName modifiersName subschemaSubentry
409
+ namingContexts aliasedObjectName
410
+ distinguishedName seeAlso olcDefaultSearchBase
411
+ olcRootDN olcSchemaDN olcSuffix olcUpdateDN
412
+ member owner roleOccupant manager
413
+ documentAuthor secretary associatedName
414
+ dITRedirect),
415
+ }
416
+ assert_schema(expect, "2.5.13.1", dn_match_schema)
417
+ assert_schema(expect, "distinguishedNameMatch", dn_match_schema)
418
+ end
419
+
420
+ def test_dc_object
421
+ dc_object_schema = "( 1.3.6.1.4.1.1466.344 NAME 'dcObject' DESC " +
422
+ "'RFC2247: domain component object' SUP top " +
423
+ "AUXILIARY MUST dc )"
424
+
425
+ expect = {
426
+ :name => ["dcObject"],
427
+ :desc => ['RFC2247: domain component object'],
428
+ :auxiliary => ["TRUE"],
429
+ :must => ["dc"],
430
+ }
431
+ assert_schema(expect, "1.3.6.1.4.1.1466.344", dc_object_schema)
432
+ assert_schema(expect, "dcObject", dc_object_schema)
433
+ end
434
+
435
+ def test_organization
436
+ organization_schema = "( 2.5.6.4 NAME 'organization' DESC " +
437
+ "'RFC2256: an organization' SUP top STRUCTURAL " +
438
+ "MUST o MAY ( userPassword $ searchGuide $ " +
439
+ "seeAlso $ businessCategory $ x121Address $ " +
440
+ "registeredAddress $ destinationIndicator $ " +
441
+ "preferredDeliveryMethod $ telexNumber $ " +
442
+ "teletexTerminalIdentifier $ telephoneNumber $ " +
443
+ "internationaliSDNNumber $ " +
444
+ "facsimileTelephoneNumber $ street $ " +
445
+ "postOfficeBox $ postalCode $ postalAddress $ " +
446
+ "physicalDeliveryOfficeName $ st $ l $ " +
447
+ "description ) )"
448
+
449
+ expect = {
450
+ :name => ["organization"],
451
+ :desc => ['RFC2256: an organization'],
452
+ :sup => ["top"],
453
+ :structural => ["TRUE"],
454
+ :must => ["o"],
455
+ :may => %w(userPassword searchGuide seeAlso businessCategory
456
+ x121Address registeredAddress destinationIndicator
457
+ preferredDeliveryMethod telexNumber
458
+ teletexTerminalIdentifier telephoneNumber
459
+ internationaliSDNNumber
460
+ facsimileTelephoneNumber street
461
+ postOfficeBox postalCode postalAddress
462
+ physicalDeliveryOfficeName st l description),
463
+ }
464
+ assert_schema(expect, "2.5.6.4", organization_schema)
465
+ assert_schema(expect, "organization", organization_schema)
466
+ end
467
+
468
+ def test_posix_account
469
+ posix_account_schema = "( 1.3.6.1.1.1.2.0 NAME 'posixAccount' DESC " +
470
+ "'Abstraction of an account with POSIX " +
471
+ "attributes' SUP top AUXILIARY MUST ( cn $ " +
472
+ "uid $ uidNumber $ gidNumber $ homeDirectory " +
473
+ ") MAY ( userPassword $ loginShell $ gecos $ " +
474
+ "description ) )"
475
+ expect = {
476
+ :name => ["posixAccount"],
477
+ :desc => ['Abstraction of an account with POSIX attributes'],
478
+ :sup => ["top"],
479
+ :auxiliary => ["TRUE"],
480
+ :must => %w(cn uid uidNumber gidNumber homeDirectory),
481
+ :may => %w(userPassword loginShell gecos description),
482
+ }
483
+ assert_schema(expect, "1.3.6.1.1.1.2.0", posix_account_schema)
484
+ assert_schema(expect, "posixAccount", posix_account_schema)
485
+ end
486
+
487
+ def test_jpeg_photo
488
+ jpeg_photo_schema = "( 0.9.2342.19200300.100.1.60 NAME 'jpegPhoto' " +
489
+ "DESC 'RFC2798: a JPEG image' SYNTAX " +
490
+ "1.3.6.1.4.1.1466.115.121.1.28 )"
491
+ expect = {
492
+ :name => ["jpegPhoto"],
493
+ :desc => ['RFC2798: a JPEG image'],
494
+ :syntax => ["1.3.6.1.4.1.1466.115.121.1.28"],
495
+ }
496
+ assert_schema(expect, "0.9.2342.19200300.100.1.60", jpeg_photo_schema)
497
+ assert_schema(expect, "jpegPhoto", jpeg_photo_schema)
498
+
499
+ jpeg_schema = "( 1.3.6.1.4.1.1466.115.121.1.28 DESC 'JPEG' " +
500
+ "X-NOT-HUMAN-READABLE 'TRUE' )"
501
+
502
+ expect = {
503
+ :desc => ['JPEG'],
504
+ :x_not_human_readable => ["TRUE"],
505
+ }
506
+ assert_schema(expect, "1.3.6.1.4.1.1466.115.121.1.28", jpeg_schema)
507
+
508
+ schema = ActiveLdap::Schema.new({"attributeTypes" => [jpeg_photo_schema],
509
+ "ldapSyntaxes" => [jpeg_schema]})
510
+ assert(schema.attribute("jpegPhoto").binary?)
511
+ end
512
+
513
+ private
514
+ def assert_schema(expect, name, schema)
515
+ sub = "objectClasses"
516
+ entry = {sub => [schema]}
517
+ schema = ActiveLdap::Schema.new(entry)
518
+ actual = {}
519
+ normalized_expect = {}
520
+ expect.each do |key, value|
521
+ normalized_key = key.to_s.gsub(/_/, "-")
522
+ normalized_expect[normalized_key] = value
523
+ actual[normalized_key] = schema[sub, name, normalized_key]
524
+ end
525
+ assert_equal(normalized_expect, actual)
526
+ schema
527
+ end
528
+
529
+ def assert_make_schema_with_empty_entries(entries)
530
+ schema = ActiveLdap::Schema.new(entries)
531
+ assert_equal([], schema["attributeTypes", "cn", "DESC"])
532
+ assert_equal([], schema["ldapSyntaxes",
533
+ "1.3.6.1.4.1.1466.115.121.1.5",
534
+ "DESC"])
535
+ assert_equal([], schema["objectClasses", "posixAccount", "MUST"])
536
+ end
537
+
538
+ def assert_attribute_aliases(expected, keys, schemata, ensure_parse)
539
+ group = 'attributeTypes'
540
+ entry = {group => schemata}
541
+ schema = ActiveLdap::Schema.new(entry)
542
+ schema.send(:ensure_parse, group) if ensure_parse
543
+ result = keys.collect do |key|
544
+ attribute = schema.attribute(key)
545
+ [attribute.name, attribute.aliases]
546
+ end
547
+ assert_equal(expected, result)
548
+ end
549
+
550
+ def assert_attribute_type(expected, name, schemata)
551
+ group = 'attributeTypes'
552
+ entry = {group => schemata}
553
+ schema = ActiveLdap::Schema.new(entry)
554
+ attribute_hash = schema.attribute(name).to_hash
555
+ syntax = attribute_hash[:syntax]
556
+ attribute_hash[:syntax] = syntax.id if syntax
557
+ assert_equal(expected, attribute_hash)
558
+ end
559
+ end