ruby-activeldap 0.8.3 → 0.8.3.1

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 (177) hide show
  1. data/CHANGES +431 -0
  2. data/COPYING +340 -0
  3. data/LICENSE +58 -0
  4. data/README +104 -0
  5. data/Rakefile +165 -0
  6. data/TODO +22 -0
  7. data/benchmark/bench-al.rb +202 -0
  8. data/benchmark/config.yaml.sample +5 -0
  9. data/data/locale/en/LC_MESSAGES/active-ldap.mo +0 -0
  10. data/data/locale/ja/LC_MESSAGES/active-ldap.mo +0 -0
  11. data/examples/al-admin/README +182 -0
  12. data/examples/al-admin/Rakefile +10 -0
  13. data/examples/al-admin/app/controllers/account_controller.rb +50 -0
  14. data/examples/al-admin/app/controllers/application.rb +15 -0
  15. data/examples/al-admin/app/controllers/directory_controller.rb +22 -0
  16. data/examples/al-admin/app/controllers/users_controller.rb +38 -0
  17. data/examples/al-admin/app/controllers/welcome_controller.rb +4 -0
  18. data/examples/al-admin/app/helpers/account_helper.rb +2 -0
  19. data/examples/al-admin/app/helpers/application_helper.rb +6 -0
  20. data/examples/al-admin/app/helpers/directory_helper.rb +2 -0
  21. data/examples/al-admin/app/helpers/users_helper.rb +13 -0
  22. data/examples/al-admin/app/helpers/welcome_helper.rb +2 -0
  23. data/examples/al-admin/app/models/entry.rb +19 -0
  24. data/examples/al-admin/app/models/ldap_user.rb +49 -0
  25. data/examples/al-admin/app/models/user.rb +91 -0
  26. data/examples/al-admin/app/views/account/login.rhtml +12 -0
  27. data/examples/al-admin/app/views/account/sign_up.rhtml +22 -0
  28. data/examples/al-admin/app/views/directory/index.rhtml +5 -0
  29. data/examples/al-admin/app/views/directory/populate.rhtml +2 -0
  30. data/examples/al-admin/app/views/layouts/application.rhtml +41 -0
  31. data/examples/al-admin/app/views/users/_attribute_information.rhtml +22 -0
  32. data/examples/al-admin/app/views/users/_entry.rhtml +12 -0
  33. data/examples/al-admin/app/views/users/_form.rhtml +29 -0
  34. data/examples/al-admin/app/views/users/_object_class_information.rhtml +23 -0
  35. data/examples/al-admin/app/views/users/edit.rhtml +10 -0
  36. data/examples/al-admin/app/views/users/index.rhtml +9 -0
  37. data/examples/al-admin/app/views/users/show.rhtml +3 -0
  38. data/examples/al-admin/app/views/welcome/index.rhtml +16 -0
  39. data/examples/al-admin/config/boot.rb +45 -0
  40. data/examples/al-admin/config/database.yml.example +19 -0
  41. data/examples/al-admin/config/environment.rb +68 -0
  42. data/examples/al-admin/config/environments/development.rb +21 -0
  43. data/examples/al-admin/config/environments/production.rb +18 -0
  44. data/examples/al-admin/config/environments/test.rb +19 -0
  45. data/examples/al-admin/config/ldap.yml.example +21 -0
  46. data/examples/al-admin/config/routes.rb +26 -0
  47. data/examples/al-admin/db/migrate/001_create_users.rb +16 -0
  48. data/examples/al-admin/lib/accept_http_rails_relative_url_root.rb +9 -0
  49. data/examples/al-admin/lib/authenticated_system.rb +131 -0
  50. data/examples/al-admin/lib/authenticated_test_helper.rb +113 -0
  51. data/examples/al-admin/lib/tasks/gettext.rake +35 -0
  52. data/examples/al-admin/po/en/al-admin.po +190 -0
  53. data/examples/al-admin/po/ja/al-admin.po +190 -0
  54. data/examples/al-admin/po/nl/al-admin.po +202 -0
  55. data/examples/al-admin/public/.htaccess +40 -0
  56. data/examples/al-admin/public/404.html +30 -0
  57. data/examples/al-admin/public/500.html +30 -0
  58. data/examples/al-admin/public/dispatch.cgi +10 -0
  59. data/examples/al-admin/public/dispatch.fcgi +24 -0
  60. data/examples/al-admin/public/dispatch.rb +10 -0
  61. data/examples/al-admin/public/favicon.ico +0 -0
  62. data/examples/al-admin/public/images/rails.png +0 -0
  63. data/examples/al-admin/public/javascripts/application.js +2 -0
  64. data/examples/al-admin/public/javascripts/controls.js +833 -0
  65. data/examples/al-admin/public/javascripts/dragdrop.js +942 -0
  66. data/examples/al-admin/public/javascripts/effects.js +1088 -0
  67. data/examples/al-admin/public/javascripts/prototype.js +2515 -0
  68. data/examples/al-admin/public/robots.txt +1 -0
  69. data/examples/al-admin/public/stylesheets/rails.css +35 -0
  70. data/examples/al-admin/public/stylesheets/screen.css +52 -0
  71. data/examples/al-admin/script/about +3 -0
  72. data/examples/al-admin/script/breakpointer +3 -0
  73. data/examples/al-admin/script/console +3 -0
  74. data/examples/al-admin/script/destroy +3 -0
  75. data/examples/al-admin/script/generate +3 -0
  76. data/examples/al-admin/script/performance/benchmarker +3 -0
  77. data/examples/al-admin/script/performance/profiler +3 -0
  78. data/examples/al-admin/script/plugin +3 -0
  79. data/examples/al-admin/script/process/inspector +3 -0
  80. data/examples/al-admin/script/process/reaper +3 -0
  81. data/examples/al-admin/script/process/spawner +3 -0
  82. data/examples/al-admin/script/runner +3 -0
  83. data/examples/al-admin/script/server +3 -0
  84. data/examples/al-admin/test/fixtures/users.yml +9 -0
  85. data/examples/al-admin/test/functional/account_controller_test.rb +24 -0
  86. data/examples/al-admin/test/functional/directory_controller_test.rb +18 -0
  87. data/examples/al-admin/test/functional/users_controller_test.rb +18 -0
  88. data/examples/al-admin/test/functional/welcome_controller_test.rb +18 -0
  89. data/examples/al-admin/test/run-test.sh +3 -0
  90. data/examples/al-admin/test/test_helper.rb +28 -0
  91. data/examples/al-admin/test/unit/user_test.rb +13 -0
  92. data/examples/al-admin/vendor/plugins/exception_notification/README +111 -0
  93. data/examples/al-admin/vendor/plugins/exception_notification/init.rb +1 -0
  94. data/examples/al-admin/vendor/plugins/exception_notification/lib/exception_notifiable.rb +99 -0
  95. data/examples/al-admin/vendor/plugins/exception_notification/lib/exception_notifier.rb +67 -0
  96. data/examples/al-admin/vendor/plugins/exception_notification/lib/exception_notifier_helper.rb +77 -0
  97. data/examples/al-admin/vendor/plugins/exception_notification/test/exception_notifier_helper_test.rb +61 -0
  98. data/examples/al-admin/vendor/plugins/exception_notification/test/test_helper.rb +7 -0
  99. data/examples/al-admin/vendor/plugins/exception_notification/views/exception_notifier/_backtrace.rhtml +1 -0
  100. data/examples/al-admin/vendor/plugins/exception_notification/views/exception_notifier/_environment.rhtml +7 -0
  101. data/examples/al-admin/vendor/plugins/exception_notification/views/exception_notifier/_inspect_model.rhtml +16 -0
  102. data/examples/al-admin/vendor/plugins/exception_notification/views/exception_notifier/_request.rhtml +3 -0
  103. data/examples/al-admin/vendor/plugins/exception_notification/views/exception_notifier/_session.rhtml +2 -0
  104. data/examples/al-admin/vendor/plugins/exception_notification/views/exception_notifier/_title.rhtml +3 -0
  105. data/examples/al-admin/vendor/plugins/exception_notification/views/exception_notifier/exception_notification.rhtml +6 -0
  106. data/examples/config.yaml.example +5 -0
  107. data/examples/example.der +0 -0
  108. data/examples/example.jpg +0 -0
  109. data/examples/groupadd +41 -0
  110. data/examples/groupdel +35 -0
  111. data/examples/groupls +49 -0
  112. data/examples/groupmod +42 -0
  113. data/examples/lpasswd +55 -0
  114. data/examples/objects/group.rb +13 -0
  115. data/examples/objects/ou.rb +4 -0
  116. data/examples/objects/user.rb +20 -0
  117. data/examples/ouadd +38 -0
  118. data/examples/useradd +45 -0
  119. data/examples/useradd-binary +50 -0
  120. data/examples/userdel +34 -0
  121. data/examples/userls +50 -0
  122. data/examples/usermod +42 -0
  123. data/examples/usermod-binary-add +47 -0
  124. data/examples/usermod-binary-add-time +51 -0
  125. data/examples/usermod-binary-del +48 -0
  126. data/examples/usermod-lang-add +43 -0
  127. data/lib/active_ldap.rb +978 -0
  128. data/lib/active_ldap/adapter/base.rb +512 -0
  129. data/lib/active_ldap/adapter/ldap.rb +233 -0
  130. data/lib/active_ldap/adapter/ldap_ext.rb +69 -0
  131. data/lib/active_ldap/adapter/net_ldap.rb +290 -0
  132. data/lib/active_ldap/adapter/net_ldap_ext.rb +29 -0
  133. data/lib/active_ldap/association/belongs_to.rb +47 -0
  134. data/lib/active_ldap/association/belongs_to_many.rb +42 -0
  135. data/lib/active_ldap/association/collection.rb +83 -0
  136. data/lib/active_ldap/association/has_many.rb +31 -0
  137. data/lib/active_ldap/association/has_many_utils.rb +35 -0
  138. data/lib/active_ldap/association/has_many_wrap.rb +46 -0
  139. data/lib/active_ldap/association/proxy.rb +102 -0
  140. data/lib/active_ldap/associations.rb +172 -0
  141. data/lib/active_ldap/attributes.rb +211 -0
  142. data/lib/active_ldap/base.rb +1256 -0
  143. data/lib/active_ldap/callbacks.rb +19 -0
  144. data/lib/active_ldap/command.rb +48 -0
  145. data/lib/active_ldap/configuration.rb +114 -0
  146. data/lib/active_ldap/connection.rb +234 -0
  147. data/lib/active_ldap/distinguished_name.rb +250 -0
  148. data/lib/active_ldap/escape.rb +12 -0
  149. data/lib/active_ldap/get_text/parser.rb +142 -0
  150. data/lib/active_ldap/get_text_fallback.rb +53 -0
  151. data/lib/active_ldap/get_text_support.rb +12 -0
  152. data/lib/active_ldap/helper.rb +23 -0
  153. data/lib/active_ldap/ldap_error.rb +74 -0
  154. data/lib/active_ldap/object_class.rb +93 -0
  155. data/lib/active_ldap/operations.rb +419 -0
  156. data/lib/active_ldap/populate.rb +44 -0
  157. data/lib/active_ldap/schema.rb +427 -0
  158. data/lib/active_ldap/timeout.rb +75 -0
  159. data/lib/active_ldap/timeout_stub.rb +17 -0
  160. data/lib/active_ldap/user_password.rb +93 -0
  161. data/lib/active_ldap/validations.rb +112 -0
  162. data/po/en/active-ldap.po +3011 -0
  163. data/po/ja/active-ldap.po +3044 -0
  164. data/rails/plugin/active_ldap/README +54 -0
  165. data/rails/plugin/active_ldap/generators/scaffold_al/scaffold_al_generator.rb +7 -0
  166. data/rails/plugin/active_ldap/generators/scaffold_al/templates/ldap.yml +21 -0
  167. data/rails/plugin/active_ldap/init.rb +19 -0
  168. data/test/al-test-utils.rb +362 -0
  169. data/test/command.rb +62 -0
  170. data/test/config.yaml.sample +6 -0
  171. data/test/run-test.rb +31 -0
  172. data/test/test-unit-ext.rb +4 -0
  173. data/test/test-unit-ext/always-show-result.rb +28 -0
  174. data/test/test-unit-ext/backtrace-filter.rb +17 -0
  175. data/test/test-unit-ext/long-display-for-emacs.rb +25 -0
  176. data/test/test-unit-ext/priority.rb +163 -0
  177. metadata +211 -4
@@ -0,0 +1,44 @@
1
+ module ActiveLdap
2
+ module Populate
3
+ module_function
4
+ def ensure_base(base_class=nil)
5
+ base_class ||= Base
6
+ return unless base_class.search(:scope => :base).empty?
7
+
8
+ base_dn = DN.parse(base_class.base)
9
+ suffixes = []
10
+
11
+ base_dn.rdns.reverse_each do |rdn|
12
+ name, value = rdn.to_a[0]
13
+ prefix = suffixes.join(",")
14
+ suffixes.unshift("#{name}=#{value}")
15
+ next unless name == "dc"
16
+ dc_class = Class.new(base_class)
17
+ dc_class.ldap_mapping :dn_attribute => "dc",
18
+ :prefix => "",
19
+ :scope => :base,
20
+ :classes => ["top", "dcObject", "organization"]
21
+ dc_class.base = prefix
22
+ next if dc_class.exist?(value)
23
+ dc = dc_class.new(value)
24
+ dc.o = dc.dc
25
+ begin
26
+ dc.save
27
+ rescue ActiveLdap::OperationNotPermitted
28
+ end
29
+ end
30
+ end
31
+
32
+ def ensure_ou(name, base_class=nil)
33
+ base_class ||= Base
34
+ name = name.gsub(/\Aou\s*=\s*/, '')
35
+
36
+ ou_class = Class.new(base_class)
37
+ ou_class.ldap_mapping(:dn_attribute => "ou",
38
+ :prefix => "",
39
+ :classes => ["top", "organizationalUnit"])
40
+ return if ou_class.exist?(name)
41
+ ou_class.new(name).save
42
+ end
43
+ end
44
+ end
@@ -0,0 +1,427 @@
1
+ module ActiveLdap
2
+ class Schema
3
+ def initialize(entries)
4
+ @entries = default_entries.merge(entries || {})
5
+ @schema_info = {}
6
+ @class_attributes_info = {}
7
+ @cache = {}
8
+ end
9
+
10
+ def names(group)
11
+ alias_map(group).keys
12
+ end
13
+
14
+ def exist_name?(group, name)
15
+ alias_map(group).has_key?(normalize_schema_name(name))
16
+ end
17
+
18
+ def resolve_name(group, name)
19
+ alias_map(group)[normalize_schema_name(name)]
20
+ end
21
+
22
+ # fetch
23
+ #
24
+ # This is just like LDAP::Schema#attribute except that it allows
25
+ # look up in any of the given keys.
26
+ # e.g.
27
+ # fetch('attributeTypes', 'cn', 'DESC')
28
+ # fetch('ldapSyntaxes', '1.3.6.1.4.1.1466.115.121.1.5', 'DESC')
29
+ def fetch(group, id_or_name, attribute_name)
30
+ return [] if attribute_name.empty?
31
+ attribute_name = normalize_attribute_name(attribute_name)
32
+ value = entry(group, id_or_name)[attribute_name]
33
+ value ? value.dup : []
34
+ end
35
+ alias_method :[], :fetch
36
+
37
+ NUMERIC_OID_RE = "\\d[\\d\\.]+"
38
+ DESCRIPTION_RE = "[a-zA-Z][a-zA-Z\\d\\-]*"
39
+ OID_RE = "(?:#{NUMERIC_OID_RE}|#{DESCRIPTION_RE}-oid)"
40
+ def entry(group, id_or_name)
41
+ return {} if group.empty? or id_or_name.empty?
42
+
43
+ unless @entries.has_key?(group)
44
+ raise ArgumentError, _("Unknown schema group: %s") % group
45
+ end
46
+
47
+ # Initialize anything that is required
48
+ info, ids, aliases = ensure_schema_info(group)
49
+ id, name = determine_id_or_name(id_or_name, aliases)
50
+
51
+ # Check already parsed options first
52
+ return ids[id] if ids.has_key?(id)
53
+
54
+ schemata = @entries[group] || []
55
+ while schema = schemata.shift
56
+ next unless /\A\s*\(\s*(#{OID_RE})\s*(.*)\s*\)\s*\z/ =~ schema
57
+ schema_id = $1
58
+ rest = $2
59
+
60
+ if ids.has_key?(schema_id)
61
+ attributes = ids[schema_id]
62
+ else
63
+ attributes = {}
64
+ ids[schema_id] = attributes
65
+ end
66
+
67
+ parse_attributes(rest, attributes)
68
+ (attributes["NAME"] || []).each do |v|
69
+ normalized_name = normalize_schema_name(v)
70
+ aliases[normalized_name] = schema_id
71
+ id = schema_id if id.nil? and name == normalized_name
72
+ end
73
+
74
+ break if id == schema_id
75
+ end
76
+
77
+ ids[id || aliases[name]] || {}
78
+ end
79
+
80
+ def attribute(name)
81
+ cache([:attribute, name]) do
82
+ Attribute.new(name, self)
83
+ end
84
+ end
85
+
86
+ def attributes
87
+ cache([:attributes]) do
88
+ names("attributeTypes").collect do |name|
89
+ attribute(name)
90
+ end
91
+ end
92
+ end
93
+
94
+ def attribute_type(name, attribute_name)
95
+ cache([:attribute_type, name, attribute_name]) do
96
+ fetch("attributeTypes", name, attribute_name)
97
+ end
98
+ end
99
+
100
+ def object_class(name)
101
+ cache([:object_class, name]) do
102
+ ObjectClass.new(name, self)
103
+ end
104
+ end
105
+
106
+ def object_classes
107
+ cache([:object_classes]) do
108
+ names("objectClasses").collect do |name|
109
+ object_class(name)
110
+ end
111
+ end
112
+ end
113
+
114
+ def object_class_attribute(name, attribute_name)
115
+ cache([:object_class_attribute, name, attribute_name]) do
116
+ fetch("objectClasses", name, attribute_name)
117
+ end
118
+ end
119
+
120
+ def ldap_syntax(name)
121
+ cache([:ldap_syntax, name]) do
122
+ Syntax.new(name, self)
123
+ end
124
+ end
125
+
126
+ def ldap_syntaxes
127
+ cache([:ldap_syntaxes]) do
128
+ names("ldapSyntaxes").collect do |name|
129
+ ldap_syntax(name)
130
+ end
131
+ end
132
+ end
133
+
134
+ def ldap_syntax_attribute(name, attribute_name)
135
+ cache([:ldap_syntax_attribute, name, attribute_name]) do
136
+ fetch("ldapSyntaxes", name, attribute_name)
137
+ end
138
+ end
139
+
140
+ private
141
+ def cache(key)
142
+ (@cache[key] ||= [yield])[0]
143
+ end
144
+
145
+ def ensure_schema_info(group)
146
+ @schema_info[group] ||= {:ids => {}, :aliases => {}}
147
+ info = @schema_info[group]
148
+ [info, info[:ids], info[:aliases]]
149
+ end
150
+
151
+ def determine_id_or_name(id_or_name, aliases)
152
+ if /\A[\d\.]+\z/ =~ id_or_name
153
+ id = id_or_name
154
+ name = nil
155
+ else
156
+ name = normalize_schema_name(id_or_name)
157
+ id = aliases[name]
158
+ end
159
+ [id, name]
160
+ end
161
+
162
+ # from RFC 2252
163
+ attribute_type_description_reserved_names =
164
+ ["NAME", "DESC", "OBSOLETE", "SUP", "EQUALITY", "ORDERING", "SUBSTR",
165
+ "SYNTAX", "SINGLE-VALUE", "COLLECTIVE", "NO-USER-MODIFICATION", "USAGE"]
166
+ syntax_description_reserved_names = ["DESC"]
167
+ object_class_description_reserved_names =
168
+ ["NAME", "DESC", "OBSOLETE", "SUP", "ABSTRACT", "STRUCTURAL",
169
+ "AUXILIARY", "MUST", "MAY"]
170
+ matching_rule_description_reserved_names =
171
+ ["NAME", "DESC", "OBSOLETE", "SYNTAX"]
172
+ matching_rule_use_description_reserved_names =
173
+ ["NAME", "DESC", "OBSOLETE", "APPLIES"]
174
+ private_experiment_reserved_names = ["X-[A-Z\\-_]+"]
175
+ reserved_names =
176
+ (attribute_type_description_reserved_names +
177
+ syntax_description_reserved_names +
178
+ object_class_description_reserved_names +
179
+ matching_rule_description_reserved_names +
180
+ matching_rule_use_description_reserved_names +
181
+ private_experiment_reserved_names).uniq
182
+ RESERVED_NAMES_RE = /(?:#{reserved_names.join('|')})/
183
+
184
+ def parse_attributes(str, attributes)
185
+ str.scan(/([A-Z\-_]+)\s+
186
+ (?:\(\s*([\w\-]+(?:\s+\$\s+[\w\-]+)+)\s*\)|
187
+ \(\s*([^\)]*)\s*\)|
188
+ '([^\']*)'|
189
+ ((?!#{RESERVED_NAMES_RE})[a-zA-Z][a-zA-Z\d\-;]*)|
190
+ (\d[\d\.\{\}]+)|
191
+ ()
192
+ )/x
193
+ ) do |name, multi_amp, multi, string, literal, syntax, no_value|
194
+ case
195
+ when multi_amp
196
+ values = multi_amp.rstrip.split(/\s*\$\s*/)
197
+ when multi
198
+ values = multi.scan(/\s*'([^\']*)'\s*/).collect {|value| value[0]}
199
+ when string
200
+ values = [string]
201
+ when literal
202
+ values = [literal]
203
+ when syntax
204
+ values = [syntax]
205
+ when no_value
206
+ values = ["TRUE"]
207
+ end
208
+ attributes[normalize_attribute_name(name)] ||= []
209
+ attributes[normalize_attribute_name(name)].concat(values)
210
+ end
211
+ end
212
+
213
+ def alias_map(group)
214
+ ensure_parse(group)
215
+ return {} if @schema_info[group].nil?
216
+ @schema_info[group][:aliases] || {}
217
+ end
218
+
219
+ def ensure_parse(group)
220
+ return if @entries[group].nil?
221
+ unless @entries[group].empty?
222
+ fetch(group, 'nonexistent', 'nonexistent')
223
+ end
224
+ end
225
+
226
+ def normalize_schema_name(name)
227
+ name.downcase.sub(/;.*$/, '')
228
+ end
229
+
230
+ def normalize_attribute_name(name)
231
+ name.upcase.gsub(/_/, "-")
232
+ end
233
+
234
+ def default_entries
235
+ {
236
+ "objectClasses" => [],
237
+ "attributeTypes" => [],
238
+ "ldapSyntaxes" => [],
239
+ }
240
+ end
241
+
242
+ class Entry
243
+ include Comparable
244
+
245
+ attr_reader :id, :name, :aliases, :description
246
+ def initialize(name, schema, group)
247
+ @schema = schema
248
+ @name, *@aliases = attribute("NAME", name)
249
+ @name ||= name
250
+ @id = @schema.resolve_name(group, @name)
251
+ collect_info
252
+ @schema = nil
253
+ end
254
+
255
+ def eql?(other)
256
+ self.class == other.class and
257
+ id == other.id
258
+ end
259
+
260
+ def hash
261
+ id.hash
262
+ end
263
+
264
+ def <=>(other)
265
+ name <=> other.name
266
+ end
267
+ end
268
+
269
+ class Syntax < Entry
270
+ def initialize(name, schema)
271
+ super(name, schema, "ldapSyntaxes")
272
+ end
273
+
274
+ def binary_transfer_required?
275
+ @binary_transfer_required
276
+ end
277
+
278
+ def human_readable?
279
+ @human_readable
280
+ end
281
+
282
+ private
283
+ def attribute(attribute_name, name=@name)
284
+ @schema.ldap_syntax_attribute(name, attribute_name)
285
+ end
286
+
287
+ def collect_info
288
+ @description = attribute("DESC")[0]
289
+ @binary_transfer_required =
290
+ (attribute('X-BINARY-TRANSFER-REQUIRED')[0] == 'TRUE')
291
+ @human_readable = (attribute('X-NOT-HUMAN-READABLE')[0] != 'TRUE')
292
+ end
293
+ end
294
+
295
+ class Attribute < Entry
296
+ def initialize(name, schema)
297
+ super(name, schema, "attributeTypes")
298
+ end
299
+
300
+ # read_only?
301
+ #
302
+ # Returns true if an attribute is read-only
303
+ # NO-USER-MODIFICATION
304
+ def read_only?
305
+ @read_only
306
+ end
307
+
308
+ # single_value?
309
+ #
310
+ # Returns true if an attribute can only have one
311
+ # value defined
312
+ # SINGLE-VALUE
313
+ def single_value?
314
+ @single_value
315
+ end
316
+
317
+ # binary?
318
+ #
319
+ # Returns true if the given attribute's syntax
320
+ # is X-NOT-HUMAN-READABLE or X-BINARY-TRANSFER-REQUIRED
321
+ def binary?
322
+ @binary
323
+ end
324
+
325
+ # binary_required?
326
+ #
327
+ # Returns true if the value MUST be transferred in binary
328
+ def binary_required?
329
+ @binary_required
330
+ end
331
+
332
+ private
333
+ def attribute(attribute_name, name=@name)
334
+ @schema.attribute_type(name, attribute_name)
335
+ end
336
+
337
+ def collect_info
338
+ @description = attribute("DESC")[0]
339
+ @read_only = attribute('NO-USER-MODIFICATION')[0] == 'TRUE'
340
+ @single_value = attribute('SINGLE-VALUE')[0] == 'TRUE'
341
+ syntax = attribute("SYNTAX")[0]
342
+ syntax = @schema.ldap_syntax(syntax) if syntax
343
+ if syntax
344
+ @binary_required = syntax.binary_transfer_required?
345
+ @binary = (@binary_required or !syntax.human_readable?)
346
+ else
347
+ @binary_required = false
348
+ @binary = false
349
+ end
350
+ end
351
+ end
352
+
353
+ class ObjectClass < Entry
354
+ attr_reader :super_classes
355
+ def initialize(name, schema)
356
+ super(name, schema, "objectClasses")
357
+ end
358
+
359
+ def super_class?(object_class)
360
+ @super_classes.include?(object_class)
361
+ end
362
+
363
+ def must(include_super_class=true)
364
+ if include_super_class
365
+ @all_must
366
+ else
367
+ @must
368
+ end
369
+ end
370
+
371
+ def may(include_super_class=true)
372
+ if include_super_class
373
+ @all_may
374
+ else
375
+ @may
376
+ end
377
+ end
378
+
379
+ private
380
+ def collect_info
381
+ @description = attribute("DESC")[0]
382
+ @super_classes = collect_super_classes
383
+ @must, @may, @all_must, @all_may = collect_attributes
384
+ end
385
+
386
+ def collect_super_classes
387
+ super_classes = attribute('SUP')
388
+ loop do
389
+ start_size = super_classes.size
390
+ new_super_classes = []
391
+ super_classes.each do |super_class|
392
+ new_super_classes.concat(attribute('SUP', super_class))
393
+ end
394
+
395
+ super_classes.concat(new_super_classes)
396
+ super_classes.uniq!
397
+ break if super_classes.size == start_size
398
+ end
399
+ super_classes.collect do |name|
400
+ @schema.object_class(name)
401
+ end
402
+ end
403
+
404
+ def collect_attributes
405
+ must = attribute('MUST').collect {|name| @schema.attribute(name)}
406
+ may = attribute('MAY').collect {|name| @schema.attribute(name)}
407
+
408
+ all_must = must.dup
409
+ all_may = may.dup
410
+ @super_classes.each do |super_class|
411
+ all_must.concat(super_class.must(false))
412
+ all_may.concat(super_class.may(false))
413
+ end
414
+
415
+ # Clean out the dupes.
416
+ all_must.uniq!
417
+ all_may.uniq!
418
+
419
+ [must, may, all_must, all_may]
420
+ end
421
+
422
+ def attribute(attribute_name, name=@name)
423
+ @schema.object_class_attribute(name, attribute_name)
424
+ end
425
+ end
426
+ end
427
+ end