activeldap 1.0.2 → 1.0.9
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.
- data/CHANGES +32 -0
- data/README +8 -1
- data/data/locale/en/LC_MESSAGES/active-ldap.mo +0 -0
- data/data/locale/ja/LC_MESSAGES/active-ldap.mo +0 -0
- data/examples/al-admin/app/controllers/{application.rb → application_controller.rb} +3 -1
- data/examples/al-admin/app/views/account/sign_up.html.erb +6 -5
- data/examples/al-admin/config/boot.rb +1 -0
- data/examples/al-admin/config/environment.rb +4 -2
- data/examples/al-admin/config.ru +7 -0
- data/examples/al-admin/lib/ldap_test_helper.rb +38 -0
- data/examples/al-admin/lib/tasks/gettext.rake +3 -2
- data/examples/al-admin/lib/tasks/testing.rake +10 -0
- data/examples/al-admin/po/en/al-admin.po +4 -4
- data/examples/al-admin/po/ja/al-admin.po +4 -4
- data/examples/al-admin/po/nl/al-admin.po +3 -3
- data/examples/al-admin/public/dispatch.cgi +2 -2
- data/examples/al-admin/public/dispatch.fcgi +1 -1
- data/examples/al-admin/public/dispatch.rb +2 -2
- data/examples/al-admin/test/functional/account_controller_test.rb +2 -14
- data/examples/al-admin/test/functional/attributes_controller_test.rb +2 -12
- data/examples/al-admin/test/functional/directory_controller_test.rb +2 -12
- data/examples/al-admin/test/functional/object_classes_controller_test.rb +2 -12
- data/examples/al-admin/test/functional/syntaxes_controller_test.rb +2 -12
- data/examples/al-admin/test/functional/users_controller_test.rb +2 -12
- data/examples/al-admin/test/functional/welcome_controller_test.rb +2 -12
- data/examples/al-admin/test/integration/sign_up_test.rb +44 -0
- data/examples/al-admin/test/run-test.sh +1 -1
- data/examples/al-admin/test/test_helper.rb +25 -1
- data/examples/al-admin/test/unit/user_test.rb +1 -2
- data/examples/groupadd +2 -2
- data/examples/groupdel +2 -2
- data/examples/groupls +2 -2
- data/examples/groupmod +2 -2
- data/examples/lpasswd +2 -2
- data/examples/objects/group.rb +2 -2
- data/examples/objects/user.rb +1 -1
- data/examples/ouadd +2 -2
- data/examples/useradd +2 -2
- data/examples/useradd-binary +6 -3
- data/examples/userdel +2 -2
- data/examples/userls +2 -2
- data/examples/usermod +2 -2
- data/examples/usermod-binary-add +6 -3
- data/examples/usermod-binary-add-time +6 -3
- data/examples/usermod-binary-del +2 -2
- data/examples/usermod-lang-add +2 -2
- data/lib/active_ldap/adapter/base.rb +47 -23
- data/lib/active_ldap/adapter/jndi.rb +30 -28
- data/lib/active_ldap/adapter/jndi_connection.rb +6 -0
- data/lib/active_ldap/adapter/ldap.rb +25 -26
- data/lib/active_ldap/adapter/net_ldap.rb +28 -33
- data/lib/active_ldap/adapter/net_ldap_ext.rb +0 -6
- data/lib/active_ldap/association/proxy.rb +2 -1
- data/lib/active_ldap/attributes.rb +31 -0
- data/lib/active_ldap/base.rb +75 -31
- data/lib/active_ldap/compatible.rb +44 -0
- data/lib/active_ldap/configuration.rb +3 -3
- data/lib/active_ldap/connection.rb +41 -12
- data/lib/active_ldap/distinguished_name.rb +1 -0
- data/lib/active_ldap/get_text.rb +0 -7
- data/lib/active_ldap/ldif.rb +59 -44
- data/lib/active_ldap/operations.rb +41 -10
- data/lib/active_ldap/schema.rb +41 -6
- data/lib/active_ldap/user_password.rb +7 -7
- data/lib/active_ldap/validations.rb +24 -12
- data/lib/active_ldap/xml.rb +2 -2
- data/lib/active_ldap.rb +120 -139
- data/po/en/active-ldap.po +5 -5
- data/po/ja/active-ldap.po +5 -5
- data/rails/README +2 -2
- data/rails/init.rb +2 -2
- data/test/al-test-utils.rb +11 -4
- data/test/run-test.rb +6 -2
- data/test/test_associations.rb +4 -4
- data/test/test_attributes.rb +3 -1
- data/test/test_base.rb +75 -15
- data/test/test_base_per_instance.rb +7 -1
- data/test/test_bind.rb +4 -4
- data/test/test_connection.rb +36 -14
- data/test/test_connection_per_class.rb +5 -5
- data/test/test_connection_per_dn.rb +11 -5
- data/test/test_groupadd.rb +2 -2
- data/test/test_groupdel.rb +2 -2
- data/test/test_groupls.rb +1 -1
- data/test/test_groupmod.rb +2 -2
- data/test/test_ldif.rb +11 -1
- data/test/test_schema.rb +38 -2
- data/test/test_syntax.rb +12 -2
- data/test/test_useradd-binary.rb +1 -0
- data/test/test_usermod-binary-add-time.rb +1 -0
- data/test/test_usermod-binary-add.rb +1 -0
- data/test/test_validation.rb +24 -13
- data/test-unit/lib/test/unit/assertions.rb +97 -14
- data/test-unit/lib/test/unit/autorunner.rb +20 -4
- data/test-unit/lib/test/unit/priority.rb +21 -1
- data/test-unit/lib/test/unit/ui/console/testrunner.rb +7 -4
- data/test-unit/test/test_assertions.rb +52 -5
- metadata +10 -14
- data/rails/plugin/active_ldap/README +0 -54
- data/rails/plugin/active_ldap/generators/README +0 -2
- data/rails/plugin/active_ldap/generators/model_active_ldap/USAGE +0 -17
- data/rails/plugin/active_ldap/generators/model_active_ldap/model_active_ldap_generator.rb +0 -70
- data/rails/plugin/active_ldap/generators/model_active_ldap/templates/fixtures.yml +0 -11
- data/rails/plugin/active_ldap/generators/model_active_ldap/templates/model_active_ldap.rb +0 -3
- data/rails/plugin/active_ldap/generators/model_active_ldap/templates/unit_test.rb +0 -10
- data/rails/plugin/active_ldap/generators/scaffold_active_ldap/scaffold_active_ldap_generator.rb +0 -7
- data/rails/plugin/active_ldap/generators/scaffold_al/scaffold_al_generator.rb +0 -20
- data/rails/plugin/active_ldap/init.rb +0 -36
- data/rails_generators/scaffold_al/scaffold_al_generator.rb +0 -20
data/lib/active_ldap/ldif.rb
CHANGED
|
@@ -32,7 +32,10 @@ module ActiveLdap
|
|
|
32
32
|
|
|
33
33
|
module_function
|
|
34
34
|
def binary_value?(value)
|
|
35
|
-
if
|
|
35
|
+
if value.respond_to?(:encoding)
|
|
36
|
+
return true if value.encoding == Encoding.find("ascii-8bit")
|
|
37
|
+
end
|
|
38
|
+
if /\A#{Parser::SAFE_STRING}\z/ =~ value
|
|
36
39
|
false
|
|
37
40
|
else
|
|
38
41
|
true
|
|
@@ -45,7 +48,7 @@ module ActiveLdap
|
|
|
45
48
|
|
|
46
49
|
if value[-1, 1] == ' ' or binary_value?(value)
|
|
47
50
|
result << ":"
|
|
48
|
-
value = [value].pack("m").gsub(/\n
|
|
51
|
+
value = [value].pack("m").gsub(/\n/, '')
|
|
49
52
|
end
|
|
50
53
|
result << " "
|
|
51
54
|
|
|
@@ -61,7 +64,7 @@ module ActiveLdap
|
|
|
61
64
|
result << "#{first_line_value}\n"
|
|
62
65
|
return result if rest_value.nil?
|
|
63
66
|
|
|
64
|
-
rest_value.scan(/.{1,#{SIZE - 1}}/
|
|
67
|
+
rest_value.scan(/.{1,#{SIZE - 1}}/).each do |line| # FIXME
|
|
65
68
|
result << " #{line}\n"
|
|
66
69
|
end
|
|
67
70
|
result
|
|
@@ -95,19 +98,19 @@ module ActiveLdap
|
|
|
95
98
|
@source = source
|
|
96
99
|
end
|
|
97
100
|
|
|
98
|
-
ATTRIBUTE_TYPE_CHARS = /[a-zA-Z][a-zA-Z0-9\-]*/
|
|
99
|
-
SAFE_CHAR = /[\x01-\x09\x0B-\x0C\x0E-\x7F]/
|
|
100
|
-
SAFE_INIT_CHAR = /[\x01-\x09\x0B-\x0C\x0E-\x1F\x21-\x39\x3B\x3D-\x7F]/
|
|
101
|
-
SAFE_STRING = /#{SAFE_INIT_CHAR}#{SAFE_CHAR}*/
|
|
102
|
-
FILL = / */
|
|
101
|
+
ATTRIBUTE_TYPE_CHARS = /[a-zA-Z][a-zA-Z0-9\-]*/
|
|
102
|
+
SAFE_CHAR = /[\x01-\x09\x0B-\x0C\x0E-\x7F]/
|
|
103
|
+
SAFE_INIT_CHAR = /[\x01-\x09\x0B-\x0C\x0E-\x1F\x21-\x39\x3B\x3D-\x7F]/
|
|
104
|
+
SAFE_STRING = /#{SAFE_INIT_CHAR}#{SAFE_CHAR}*/
|
|
105
|
+
FILL = / */
|
|
103
106
|
def parse
|
|
104
107
|
return @ldif if @ldif
|
|
105
108
|
|
|
106
109
|
@scanner = Scanner.new(@source)
|
|
107
|
-
raise version_spec_is_missing unless @scanner.scan(/version:/
|
|
110
|
+
raise version_spec_is_missing unless @scanner.scan(/version:/)
|
|
108
111
|
@scanner.scan(FILL)
|
|
109
112
|
|
|
110
|
-
version = @scanner.scan(/\d+/
|
|
113
|
+
version = @scanner.scan(/\d+/)
|
|
111
114
|
raise version_number_is_missing if version.nil?
|
|
112
115
|
|
|
113
116
|
version = Integer(version)
|
|
@@ -122,13 +125,19 @@ module ActiveLdap
|
|
|
122
125
|
|
|
123
126
|
private
|
|
124
127
|
def read_base64_value
|
|
125
|
-
value = @scanner.scan(/[a-zA-Z0-9\+\/=]+/
|
|
128
|
+
value = @scanner.scan(/[a-zA-Z0-9\+\/=]+/)
|
|
126
129
|
return nil if value.nil?
|
|
127
|
-
value.
|
|
130
|
+
encoding = value.encoding if value.respond_to?(:encoding)
|
|
131
|
+
value = value.unpack("m")[0].chomp
|
|
132
|
+
if value.respond_to?(:force_encoding)
|
|
133
|
+
value.force_encoding(encoding)
|
|
134
|
+
value.force_encoding("ascii-8bit") unless value.valid_encoding?
|
|
135
|
+
end
|
|
136
|
+
value
|
|
128
137
|
end
|
|
129
138
|
|
|
130
139
|
def read_external_file
|
|
131
|
-
uri_string = @scanner.scan(URI::
|
|
140
|
+
uri_string = @scanner.scan(URI::ABS_URI)
|
|
132
141
|
raise uri_is_missing if uri_string.nil?
|
|
133
142
|
uri = nil
|
|
134
143
|
begin
|
|
@@ -138,7 +147,7 @@ module ActiveLdap
|
|
|
138
147
|
end
|
|
139
148
|
|
|
140
149
|
if uri.scheme == "file"
|
|
141
|
-
File.open(uri.path, "rb").read
|
|
150
|
+
File.open(uri.path, "rb") {|file| file.read}
|
|
142
151
|
else
|
|
143
152
|
uri.read
|
|
144
153
|
end
|
|
@@ -196,7 +205,7 @@ module ActiveLdap
|
|
|
196
205
|
|
|
197
206
|
def parse_options
|
|
198
207
|
options = []
|
|
199
|
-
while @scanner.scan(/;/
|
|
208
|
+
while @scanner.scan(/;/)
|
|
200
209
|
option = @scanner.scan(ATTRIBUTE_TYPE_CHARS)
|
|
201
210
|
raise option_is_missing if option.nil?
|
|
202
211
|
options << option
|
|
@@ -205,11 +214,11 @@ module ActiveLdap
|
|
|
205
214
|
end
|
|
206
215
|
|
|
207
216
|
def parse_attribute_value(accept_external_file=true)
|
|
208
|
-
raise attribute_value_separator_is_missing if @scanner.scan(/:/
|
|
209
|
-
if @scanner.scan(/:/
|
|
217
|
+
raise attribute_value_separator_is_missing if @scanner.scan(/:/).nil?
|
|
218
|
+
if @scanner.scan(/:/)
|
|
210
219
|
@scanner.scan(FILL)
|
|
211
220
|
read_base64_value
|
|
212
|
-
elsif accept_external_file and @scanner.scan(/</
|
|
221
|
+
elsif accept_external_file and @scanner.scan(/</)
|
|
213
222
|
@scanner.scan(FILL)
|
|
214
223
|
read_external_file
|
|
215
224
|
else
|
|
@@ -219,16 +228,16 @@ module ActiveLdap
|
|
|
219
228
|
end
|
|
220
229
|
|
|
221
230
|
def parse_control
|
|
222
|
-
return nil if @scanner.scan(/control:/
|
|
231
|
+
return nil if @scanner.scan(/control:/).nil?
|
|
223
232
|
@scanner.scan(FILL)
|
|
224
|
-
type = @scanner.scan(/\d+(?:\.\d+)*/
|
|
233
|
+
type = @scanner.scan(/\d+(?:\.\d+)*/)
|
|
225
234
|
raise control_type_is_missing if type.nil?
|
|
226
235
|
criticality = nil
|
|
227
|
-
if @scanner.scan(/ +/
|
|
228
|
-
criticality = @scanner.scan(/true|false/
|
|
236
|
+
if @scanner.scan(/ +/)
|
|
237
|
+
criticality = @scanner.scan(/true|false/)
|
|
229
238
|
raise criticality_is_missing if criticality.nil?
|
|
230
239
|
end
|
|
231
|
-
value = parse_attribute_value if @scanner.check(/:/
|
|
240
|
+
value = parse_attribute_value if @scanner.check(/:/)
|
|
232
241
|
raise separator_is_missing unless @scanner.scan_separator
|
|
233
242
|
ChangeRecord::Control.new(type, criticality, value)
|
|
234
243
|
end
|
|
@@ -244,11 +253,11 @@ module ActiveLdap
|
|
|
244
253
|
end
|
|
245
254
|
|
|
246
255
|
def parse_change_type
|
|
247
|
-
return nil unless @scanner.scan(/changetype:/
|
|
256
|
+
return nil unless @scanner.scan(/changetype:/)
|
|
248
257
|
@scanner.scan(FILL)
|
|
249
258
|
type = @scanner.check(ATTRIBUTE_TYPE_CHARS)
|
|
250
259
|
raise change_type_value_is_missing if type.nil?
|
|
251
|
-
unless @scanner.scan(/add|delete|modrdn|moddn|modify/
|
|
260
|
+
unless @scanner.scan(/add|delete|modrdn|moddn|modify/)
|
|
252
261
|
raise unknown_change_type(type)
|
|
253
262
|
end
|
|
254
263
|
|
|
@@ -257,20 +266,20 @@ module ActiveLdap
|
|
|
257
266
|
end
|
|
258
267
|
|
|
259
268
|
def parse_modify_name_record(klass, dn, controls)
|
|
260
|
-
raise new_rdn_mark_is_missing unless @scanner.scan(/newrdn\b/
|
|
269
|
+
raise new_rdn_mark_is_missing unless @scanner.scan(/newrdn\b/)
|
|
261
270
|
new_rdn = parse_attribute_value(false)
|
|
262
271
|
raise new_rdn_value_is_missing if new_rdn.nil?
|
|
263
272
|
raise separator_is_missing unless @scanner.scan_separator
|
|
264
273
|
|
|
265
|
-
unless @scanner.scan(/deleteoldrdn:/
|
|
274
|
+
unless @scanner.scan(/deleteoldrdn:/)
|
|
266
275
|
raise delete_old_rdn_mark_is_missing
|
|
267
276
|
end
|
|
268
277
|
@scanner.scan(FILL)
|
|
269
|
-
delete_old_rdn = @scanner.scan(/[01]/
|
|
278
|
+
delete_old_rdn = @scanner.scan(/[01]/)
|
|
270
279
|
raise delete_old_rdn_value_is_missing if delete_old_rdn.nil?
|
|
271
280
|
raise separator_is_missing unless @scanner.scan_separator
|
|
272
281
|
|
|
273
|
-
if @scanner.scan(/newsuperior\b/
|
|
282
|
+
if @scanner.scan(/newsuperior\b/)
|
|
274
283
|
@scanner.scan(FILL)
|
|
275
284
|
new_superior = parse_attribute_value(false)
|
|
276
285
|
raise new_superior_value_is_missing if new_superior.nil?
|
|
@@ -281,16 +290,16 @@ module ActiveLdap
|
|
|
281
290
|
end
|
|
282
291
|
|
|
283
292
|
def parse_modify_spec
|
|
284
|
-
return nil unless @scanner.check(/(#{ATTRIBUTE_TYPE_CHARS}):/
|
|
293
|
+
return nil unless @scanner.check(/(#{ATTRIBUTE_TYPE_CHARS}):/)
|
|
285
294
|
type = @scanner[1]
|
|
286
|
-
unless @scanner.scan(/(?:add|delete|replace):/
|
|
295
|
+
unless @scanner.scan(/(?:add|delete|replace):/)
|
|
287
296
|
raise unknown_modify_type(type)
|
|
288
297
|
end
|
|
289
298
|
@scanner.scan(FILL)
|
|
290
299
|
attribute, options = parse_attribute_description
|
|
291
300
|
raise separator_is_missing unless @scanner.scan_separator
|
|
292
|
-
attributes = parse_attributes {@scanner.check(/-/
|
|
293
|
-
raise modify_spec_separator_is_missing unless @scanner.scan(/-/
|
|
301
|
+
attributes = parse_attributes {@scanner.check(/-/)}
|
|
302
|
+
raise modify_spec_separator_is_missing unless @scanner.scan(/-/)
|
|
294
303
|
raise separator_is_missing unless @scanner.scan_separator
|
|
295
304
|
[type, attribute, options, attributes]
|
|
296
305
|
end
|
|
@@ -335,18 +344,18 @@ module ActiveLdap
|
|
|
335
344
|
end
|
|
336
345
|
|
|
337
346
|
def parse_record
|
|
338
|
-
raise dn_mark_is_missing unless @scanner.scan(/dn:/
|
|
339
|
-
if @scanner.scan(/:/
|
|
347
|
+
raise dn_mark_is_missing unless @scanner.scan(/dn:/)
|
|
348
|
+
if @scanner.scan(/:/)
|
|
340
349
|
@scanner.scan(FILL)
|
|
341
350
|
dn = read_base64_value
|
|
342
351
|
raise dn_is_missing if dn.nil?
|
|
343
352
|
dn = parse_dn(dn)
|
|
344
353
|
else
|
|
345
354
|
@scanner.scan(FILL)
|
|
346
|
-
dn = @scanner.scan(/#{SAFE_STRING}$/
|
|
355
|
+
dn = @scanner.scan(/#{SAFE_STRING}$/)
|
|
347
356
|
if dn.nil?
|
|
348
357
|
partial_dn = @scanner.scan(SAFE_STRING)
|
|
349
|
-
raise dn_has_invalid_character(@scanner.check(/./
|
|
358
|
+
raise dn_has_invalid_character(@scanner.check(/./)) if partial_dn
|
|
350
359
|
raise dn_is_missing
|
|
351
360
|
end
|
|
352
361
|
dn = parse_dn(dn)
|
|
@@ -485,8 +494,8 @@ module ActiveLdap
|
|
|
485
494
|
end
|
|
486
495
|
|
|
487
496
|
class Scanner
|
|
488
|
-
SEPARATOR = /(?:\r\n|\n)/
|
|
489
|
-
SEPARATORS = /(?:(?:^#.*)?#{SEPARATOR})+/
|
|
497
|
+
SEPARATOR = /(?:\r\n|\n)/
|
|
498
|
+
SEPARATORS = /(?:(?:^#.*)?#{SEPARATOR})+/
|
|
490
499
|
|
|
491
500
|
def initialize(source)
|
|
492
501
|
@source = source
|
|
@@ -543,7 +552,7 @@ module ActiveLdap
|
|
|
543
552
|
_consumed_source = consumed_source
|
|
544
553
|
return 1 if _consumed_source.empty?
|
|
545
554
|
|
|
546
|
-
n = _consumed_source.
|
|
555
|
+
n = Compatible.string_to_lines(_consumed_source).size
|
|
547
556
|
n += 1 if _consumed_source[-1, 1] == "\n"
|
|
548
557
|
n
|
|
549
558
|
end
|
|
@@ -556,21 +565,27 @@ module ActiveLdap
|
|
|
556
565
|
end
|
|
557
566
|
|
|
558
567
|
def position
|
|
559
|
-
|
|
568
|
+
sub_scanner_string = @sub_scanner.string
|
|
569
|
+
if sub_scanner_string.respond_to?(:bytesize)
|
|
570
|
+
sub_scanner_string_size = sub_scanner_string.bytesize
|
|
571
|
+
else
|
|
572
|
+
sub_scanner_string_size = sub_scanner_string.size
|
|
573
|
+
end
|
|
574
|
+
@scanner.pos - (sub_scanner_string_size - @sub_scanner.pos)
|
|
560
575
|
end
|
|
561
576
|
|
|
562
577
|
private
|
|
563
578
|
def next_segment
|
|
564
579
|
loop do
|
|
565
|
-
segment = @scanner.scan(/.+(?:#{SEPARATOR} .*)*#{SEPARATOR}?/
|
|
580
|
+
segment = @scanner.scan(/.+(?:#{SEPARATOR} .*)*#{SEPARATOR}?/)
|
|
566
581
|
return @sub_scanner if segment.nil?
|
|
567
582
|
next if segment[0, 1] == "#"
|
|
568
|
-
return StringScanner.new(segment.gsub(/\r?\n
|
|
583
|
+
return StringScanner.new(segment.gsub(/\r?\n /, ''))
|
|
569
584
|
end
|
|
570
585
|
end
|
|
571
586
|
|
|
572
587
|
def consumed_source
|
|
573
|
-
@source[0,
|
|
588
|
+
@source[0, position]
|
|
574
589
|
end
|
|
575
590
|
end
|
|
576
591
|
|
|
@@ -62,18 +62,18 @@ module ActiveLdap
|
|
|
62
62
|
}
|
|
63
63
|
|
|
64
64
|
options[:connection] ||= connection
|
|
65
|
-
options[:connection].search(search_options) do |dn, attrs|
|
|
65
|
+
values = options[:connection].search(search_options) do |dn, attrs|
|
|
66
66
|
attributes = {}
|
|
67
|
-
attrs.each do |key,
|
|
67
|
+
attrs.each do |key, _value|
|
|
68
68
|
normalized_attr, normalized_value =
|
|
69
|
-
normalize_attribute_options(key,
|
|
69
|
+
normalize_attribute_options(key, _value)
|
|
70
70
|
attributes[normalized_attr] ||= []
|
|
71
71
|
attributes[normalized_attr].concat(normalized_value)
|
|
72
72
|
end
|
|
73
|
-
|
|
74
|
-
value = yield(value) if block_given?
|
|
75
|
-
value
|
|
73
|
+
[dn, attributes]
|
|
76
74
|
end
|
|
75
|
+
values = values.collect {|_value| yield(_value)} if block_given?
|
|
76
|
+
values
|
|
77
77
|
end
|
|
78
78
|
|
|
79
79
|
def exist?(dn, options={})
|
|
@@ -196,14 +196,18 @@ module ActiveLdap
|
|
|
196
196
|
#
|
|
197
197
|
# Finds the first match for value where |value| is the value of some
|
|
198
198
|
# |field|, or the wildcard match. This is only useful for derived classes.
|
|
199
|
-
# usage: Subclass.find(:attribute => "cn", :value => "some*val")
|
|
200
|
-
# Subclass.find('some*val')
|
|
199
|
+
# usage: Subclass.find(:all, :attribute => "cn", :value => "some*val")
|
|
200
|
+
# Subclass.find(:all, 'some*val')
|
|
201
201
|
def find(*args)
|
|
202
202
|
options = extract_options_from_args!(args)
|
|
203
203
|
args = [:first] if args.empty? and !options.empty?
|
|
204
204
|
case args.first
|
|
205
205
|
when :first
|
|
206
|
+
options[:value] ||= args[1]
|
|
206
207
|
find_initial(options)
|
|
208
|
+
when :last
|
|
209
|
+
options[:value] ||= args[1]
|
|
210
|
+
find_last(options)
|
|
207
211
|
when :all
|
|
208
212
|
options[:value] ||= args[1]
|
|
209
213
|
find_every(options)
|
|
@@ -212,11 +216,38 @@ module ActiveLdap
|
|
|
212
216
|
end
|
|
213
217
|
end
|
|
214
218
|
|
|
219
|
+
# A convenience wrapper for <tt>find(:first,
|
|
220
|
+
# *args)</tt>. You can pass in all the same arguments
|
|
221
|
+
# to this method as you can to <tt>find(:first)</tt>.
|
|
222
|
+
def first(*args)
|
|
223
|
+
find(:first, *args)
|
|
224
|
+
end
|
|
225
|
+
|
|
226
|
+
# A convenience wrapper for <tt>find(:last,
|
|
227
|
+
# *args)</tt>. You can pass in all the same arguments
|
|
228
|
+
# to this method as you can to <tt>find(:last)</tt>.
|
|
229
|
+
def last(*args)
|
|
230
|
+
find(:last, *args)
|
|
231
|
+
end
|
|
232
|
+
|
|
233
|
+
# This is an alias for find(:all). You can pass in
|
|
234
|
+
# all the same arguments to this method as you can
|
|
235
|
+
# to find(:all)
|
|
236
|
+
def all(*args)
|
|
237
|
+
find(:all, *args)
|
|
238
|
+
end
|
|
239
|
+
|
|
215
240
|
private
|
|
216
241
|
def find_initial(options)
|
|
217
242
|
find_every(options.merge(:limit => 1)).first
|
|
218
243
|
end
|
|
219
244
|
|
|
245
|
+
def find_last(options)
|
|
246
|
+
order = options[:order] || self.order || 'ascend'
|
|
247
|
+
order = normalize_sort_order(order) == :ascend ? :descend : :ascend
|
|
248
|
+
find_initial(options.merge(:order => order))
|
|
249
|
+
end
|
|
250
|
+
|
|
220
251
|
def normalize_sort_order(value)
|
|
221
252
|
case value.to_s
|
|
222
253
|
when /\Aasc(?:end)?\z/i
|
|
@@ -509,9 +540,9 @@ module ActiveLdap
|
|
|
509
540
|
if dn.is_a?(Array)
|
|
510
541
|
i = -1
|
|
511
542
|
dns = dn
|
|
512
|
-
dns.collect do |
|
|
543
|
+
dns.collect do |_dn|
|
|
513
544
|
i += 1
|
|
514
|
-
update(
|
|
545
|
+
update(_dn, attributes[i], options)
|
|
515
546
|
end
|
|
516
547
|
else
|
|
517
548
|
object = find(dn, options)
|
data/lib/active_ldap/schema.rb
CHANGED
|
@@ -1,7 +1,9 @@
|
|
|
1
1
|
module ActiveLdap
|
|
2
2
|
class Schema
|
|
3
|
+
include GetTextSupport
|
|
4
|
+
|
|
3
5
|
def initialize(entries)
|
|
4
|
-
@entries =
|
|
6
|
+
@entries = normalize_entries(entries || {})
|
|
5
7
|
@schema_info = {}
|
|
6
8
|
@class_attributes_info = {}
|
|
7
9
|
@cache = {}
|
|
@@ -123,6 +125,12 @@ module ActiveLdap
|
|
|
123
125
|
end
|
|
124
126
|
end
|
|
125
127
|
|
|
128
|
+
def dit_content_rule_attribute(name, attribute_name)
|
|
129
|
+
cache([:dit_content_rule_attribute, name, attribute_name]) do
|
|
130
|
+
fetch("dITContentRules", name, attribute_name)
|
|
131
|
+
end
|
|
132
|
+
end
|
|
133
|
+
|
|
126
134
|
def ldap_syntax(name)
|
|
127
135
|
cache([:ldap_syntax, name]) do
|
|
128
136
|
Syntax.new(name, self)
|
|
@@ -143,6 +151,17 @@ module ActiveLdap
|
|
|
143
151
|
end
|
|
144
152
|
end
|
|
145
153
|
|
|
154
|
+
def dump(output=nil)
|
|
155
|
+
require 'pp'
|
|
156
|
+
output ||= STDOUT
|
|
157
|
+
if output.respond_to?(:write)
|
|
158
|
+
PP.pp(@entries, output)
|
|
159
|
+
else
|
|
160
|
+
open(output, "w") {|out| PP.pp(@entries, out)}
|
|
161
|
+
end
|
|
162
|
+
nil
|
|
163
|
+
end
|
|
164
|
+
|
|
146
165
|
private
|
|
147
166
|
def cache(key)
|
|
148
167
|
(@cache[key] ||= [yield])[0]
|
|
@@ -242,9 +261,23 @@ module ActiveLdap
|
|
|
242
261
|
"objectClasses" => [],
|
|
243
262
|
"attributeTypes" => [],
|
|
244
263
|
"ldapSyntaxes" => [],
|
|
264
|
+
"dITContentRules" => [],
|
|
265
|
+
"matchingRules" => [],
|
|
245
266
|
}
|
|
246
267
|
end
|
|
247
268
|
|
|
269
|
+
def normalize_entries(entries)
|
|
270
|
+
normalized_entries = default_entries
|
|
271
|
+
normalized_keys = normalized_entries.keys
|
|
272
|
+
entries.each do |name, values|
|
|
273
|
+
normalized_name = normalized_keys.find do |key|
|
|
274
|
+
key.downcase == name
|
|
275
|
+
end
|
|
276
|
+
normalized_entries[normalized_name || name] = values
|
|
277
|
+
end
|
|
278
|
+
normalized_entries
|
|
279
|
+
end
|
|
280
|
+
|
|
248
281
|
class Entry
|
|
249
282
|
include Comparable
|
|
250
283
|
|
|
@@ -260,11 +293,12 @@ module ActiveLdap
|
|
|
260
293
|
|
|
261
294
|
def eql?(other)
|
|
262
295
|
self.class == other.class and
|
|
263
|
-
id == other.id
|
|
296
|
+
(id == other.id or
|
|
297
|
+
(id.nil? and other.nil? and name == other.name))
|
|
264
298
|
end
|
|
265
299
|
|
|
266
300
|
def hash
|
|
267
|
-
id.hash
|
|
301
|
+
id.nil? ? name.hash : id.hash
|
|
268
302
|
end
|
|
269
303
|
|
|
270
304
|
def <=>(other)
|
|
@@ -615,9 +649,9 @@ module ActiveLdap
|
|
|
615
649
|
def collect_attributes
|
|
616
650
|
must = attribute('MUST').reject do |name|
|
|
617
651
|
UNWRITABLE_MUST_ATTRIBUTES.include?(name)
|
|
618
|
-
end
|
|
652
|
+
end.uniq
|
|
619
653
|
must = must.collect {|name| @schema.attribute(name)}
|
|
620
|
-
may = attribute('MAY').collect {|name| @schema.attribute(name)}
|
|
654
|
+
may = attribute('MAY').uniq.collect {|name| @schema.attribute(name)}
|
|
621
655
|
|
|
622
656
|
all_must = must.dup
|
|
623
657
|
all_may = may.dup
|
|
@@ -634,7 +668,8 @@ module ActiveLdap
|
|
|
634
668
|
end
|
|
635
669
|
|
|
636
670
|
def attribute(attribute_name, name=@name)
|
|
637
|
-
@schema.object_class_attribute(name, attribute_name)
|
|
671
|
+
@schema.object_class_attribute(name, attribute_name) +
|
|
672
|
+
@schema.dit_content_rule_attribute(name, attribute_name)
|
|
638
673
|
end
|
|
639
674
|
end
|
|
640
675
|
end
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
require 'English'
|
|
2
|
-
require 'md5'
|
|
3
|
-
require 'sha1'
|
|
2
|
+
require 'digest/md5'
|
|
3
|
+
require 'digest/sha1'
|
|
4
4
|
|
|
5
5
|
module ActiveLdap
|
|
6
6
|
module UserPassword
|
|
@@ -43,7 +43,7 @@ module ActiveLdap
|
|
|
43
43
|
end
|
|
44
44
|
|
|
45
45
|
def md5(password)
|
|
46
|
-
"{MD5}#{[MD5.
|
|
46
|
+
"{MD5}#{[Digest::MD5.digest(password)].pack('m').chomp}"
|
|
47
47
|
end
|
|
48
48
|
|
|
49
49
|
def smd5(password, salt=nil)
|
|
@@ -51,7 +51,7 @@ module ActiveLdap
|
|
|
51
51
|
raise ArgumentError, _("salt size must be == 4: %s") % salt.inspect
|
|
52
52
|
end
|
|
53
53
|
salt ||= Salt.generate(4)
|
|
54
|
-
md5_hash_with_salt = "#{MD5.
|
|
54
|
+
md5_hash_with_salt = "#{Digest::MD5.digest(password + salt)}#{salt}"
|
|
55
55
|
"{SMD5}#{[md5_hash_with_salt].pack('m').chomp}"
|
|
56
56
|
end
|
|
57
57
|
|
|
@@ -60,7 +60,7 @@ module ActiveLdap
|
|
|
60
60
|
end
|
|
61
61
|
|
|
62
62
|
def sha(password)
|
|
63
|
-
"{SHA}#{[SHA1.
|
|
63
|
+
"{SHA}#{[Digest::SHA1.digest(password)].pack('m').chomp}"
|
|
64
64
|
end
|
|
65
65
|
|
|
66
66
|
def ssha(password, salt=nil)
|
|
@@ -68,7 +68,7 @@ module ActiveLdap
|
|
|
68
68
|
raise ArgumentError, _("salt size must be == 4: %s") % salt.inspect
|
|
69
69
|
end
|
|
70
70
|
salt ||= Salt.generate(4)
|
|
71
|
-
sha1_hash_with_salt = "#{SHA1.
|
|
71
|
+
sha1_hash_with_salt = "#{Digest::SHA1.digest(password + salt)}#{salt}"
|
|
72
72
|
"{SSHA}#{[sha1_hash_with_salt].pack('m').chomp}"
|
|
73
73
|
end
|
|
74
74
|
|
|
@@ -77,7 +77,7 @@ module ActiveLdap
|
|
|
77
77
|
end
|
|
78
78
|
|
|
79
79
|
module Salt
|
|
80
|
-
CHARS = ['.', '/'
|
|
80
|
+
CHARS = ['.', '/'] + ['0'..'9', 'A'..'Z', 'a'..'z'].collect do |x|
|
|
81
81
|
x.to_a
|
|
82
82
|
end.flatten
|
|
83
83
|
|
|
@@ -1,5 +1,3 @@
|
|
|
1
|
-
require 'active_record/validations'
|
|
2
|
-
|
|
3
1
|
module ActiveLdap
|
|
4
2
|
module Validations
|
|
5
3
|
def self.append_features(base)
|
|
@@ -84,7 +82,10 @@ module ActiveLdap
|
|
|
84
82
|
return
|
|
85
83
|
end
|
|
86
84
|
if _dn and exist?
|
|
87
|
-
format = _("is duplicated: %s")
|
|
85
|
+
format = _("%{fn} is duplicated: %s")
|
|
86
|
+
unless ActiveLdap.get_text_supported?
|
|
87
|
+
format = format.sub(/^%\{fn\} /, '')
|
|
88
|
+
end
|
|
88
89
|
errors.add("dn", format % _dn)
|
|
89
90
|
end
|
|
90
91
|
end
|
|
@@ -92,9 +93,13 @@ module ActiveLdap
|
|
|
92
93
|
def validate_dn
|
|
93
94
|
dn
|
|
94
95
|
rescue DistinguishedNameInvalid
|
|
95
|
-
|
|
96
|
+
format = _("%{fn} is invalid: %s")
|
|
97
|
+
format = format.sub(/^%\{fn\} /, '') unless ActiveLdap.get_text_supported?
|
|
98
|
+
errors.add("dn", format % $!.message)
|
|
96
99
|
rescue DistinguishedNameNotSetError
|
|
97
|
-
|
|
100
|
+
format = _("%{fn} isn't set: %s")
|
|
101
|
+
format = format.sub(/^%\{fn\} /, '') unless ActiveLdap.get_text_supported?
|
|
102
|
+
errors.add("dn", format % $!.message)
|
|
98
103
|
end
|
|
99
104
|
|
|
100
105
|
def validate_excluded_classes
|
|
@@ -112,9 +117,10 @@ module ActiveLdap
|
|
|
112
117
|
names = unexpected_classes.collect do |object_class|
|
|
113
118
|
self.class.human_object_class_name(object_class)
|
|
114
119
|
end
|
|
115
|
-
format = n_("has excluded value: %s",
|
|
116
|
-
"has excluded values: %s",
|
|
120
|
+
format = n_("%{fn} has excluded value: %s",
|
|
121
|
+
"%{fn} has excluded values: %s",
|
|
117
122
|
names.size)
|
|
123
|
+
format = format.sub(/^%\{fn\} /, '') unless ActiveLdap.get_text_supported?
|
|
118
124
|
errors.add("objectClass", format % names.join(", "))
|
|
119
125
|
end
|
|
120
126
|
|
|
@@ -143,12 +149,15 @@ module ActiveLdap
|
|
|
143
149
|
end
|
|
144
150
|
args = [self.class.human_object_class_name(object_class)]
|
|
145
151
|
if aliases.empty?
|
|
146
|
-
format = _("is required attribute by objectClass '%s'")
|
|
152
|
+
format = _("%{fn} is required attribute by objectClass '%s'")
|
|
147
153
|
else
|
|
148
|
-
format = _("is required attribute by objectClass " \
|
|
154
|
+
format = _("%{fn} is required attribute by objectClass " \
|
|
149
155
|
"'%s': aliases: %s")
|
|
150
156
|
args << aliases.join(', ')
|
|
151
157
|
end
|
|
158
|
+
unless ActiveLdap.get_text_supported?
|
|
159
|
+
format = format.sub(/^%\{fn\} /, '')
|
|
160
|
+
end
|
|
152
161
|
errors.add(real_name, format % args)
|
|
153
162
|
end
|
|
154
163
|
end
|
|
@@ -157,7 +166,7 @@ module ActiveLdap
|
|
|
157
166
|
def validate_ldap_values
|
|
158
167
|
entry_attribute.schemata.each do |name, attribute|
|
|
159
168
|
value = self[name]
|
|
160
|
-
next if
|
|
169
|
+
next if self.class.blank_value?(value)
|
|
161
170
|
validate_ldap_value(attribute, name, value)
|
|
162
171
|
end
|
|
163
172
|
end
|
|
@@ -169,11 +178,14 @@ module ActiveLdap
|
|
|
169
178
|
self.class.human_syntax_description(attribute.syntax),
|
|
170
179
|
failed_reason]
|
|
171
180
|
if option
|
|
172
|
-
format = _("(%s) has invalid format: %s: required syntax: %s: %s")
|
|
181
|
+
format = _("%{fn}(%s) has invalid format: %s: required syntax: %s: %s")
|
|
173
182
|
else
|
|
174
|
-
format = _("has invalid format: %s: required syntax: %s: %s")
|
|
183
|
+
format = _("%{fn} has invalid format: %s: required syntax: %s: %s")
|
|
175
184
|
end
|
|
176
185
|
params.unshift(option) if option
|
|
186
|
+
unless ActiveLdap.get_text_supported?
|
|
187
|
+
format = format.sub(/^%\{fn\} ?/, '')
|
|
188
|
+
end
|
|
177
189
|
errors.add(name, format % params)
|
|
178
190
|
end
|
|
179
191
|
end
|
data/lib/active_ldap/xml.rb
CHANGED
|
@@ -5,7 +5,7 @@ require 'active_ldap/ldif'
|
|
|
5
5
|
module ActiveLdap
|
|
6
6
|
class Xml
|
|
7
7
|
class Serializer
|
|
8
|
-
PRINTABLE_STRING = /[\x20-\x7e\w\s]*/
|
|
8
|
+
PRINTABLE_STRING = /[\x20-\x7e\w\s]*/
|
|
9
9
|
|
|
10
10
|
def initialize(dn, attributes, schema, options={})
|
|
11
11
|
@dn = dn
|
|
@@ -64,7 +64,7 @@ module ActiveLdap
|
|
|
64
64
|
targets.concat(normalize_value(real_value, options))
|
|
65
65
|
end
|
|
66
66
|
else
|
|
67
|
-
if /\A#{PRINTABLE_STRING}\z/
|
|
67
|
+
if /\A#{PRINTABLE_STRING}\z/ !~ value
|
|
68
68
|
value = [value].pack("m").gsub(/\n/u, '')
|
|
69
69
|
options += ["base64"]
|
|
70
70
|
end
|