activeldap 3.1.1 → 3.2.0
Sign up to get free protection for your applications and to get access to all the features.
- data/Gemfile +1 -14
- data/benchmark/README.md +64 -0
- data/benchmark/{bench-al.rb → bench-backend.rb} +6 -22
- data/benchmark/bench-instantiate.rb +98 -0
- data/benchmark/config.yaml.sample +2 -2
- data/doc/text/news.textile +38 -0
- data/lib/active_ldap.rb +17 -8
- data/lib/active_ldap/association/has_many_wrap.rb +15 -2
- data/lib/active_ldap/attribute_methods.rb +23 -0
- data/lib/active_ldap/attribute_methods/before_type_cast.rb +24 -0
- data/lib/active_ldap/attribute_methods/dirty.rb +43 -0
- data/lib/active_ldap/attribute_methods/query.rb +31 -0
- data/lib/active_ldap/attribute_methods/read.rb +44 -0
- data/lib/active_ldap/attribute_methods/write.rb +38 -0
- data/lib/active_ldap/attributes.rb +18 -26
- data/lib/active_ldap/base.rb +42 -163
- data/lib/active_ldap/connection.rb +6 -1
- data/lib/active_ldap/get_text.rb +18 -7
- data/lib/active_ldap/operations.rb +63 -49
- data/lib/active_ldap/persistence.rb +17 -0
- data/lib/active_ldap/railtie.rb +3 -0
- data/lib/active_ldap/schema.rb +2 -0
- data/lib/active_ldap/schema/syntaxes.rb +7 -7
- data/lib/active_ldap/validations.rb +2 -2
- data/lib/active_ldap/version.rb +3 -0
- data/lib/active_ldap/xml.rb +24 -7
- data/lib/rails/generators/active_ldap/model/model_generator.rb +3 -3
- data/test/add-phonetic-attribute-options-to-slapd.ldif +10 -0
- data/test/al-test-utils.rb +428 -0
- data/test/command.rb +111 -0
- data/test/config.yaml.sample +6 -0
- data/test/fixtures/lower_case_object_class_schema.rb +802 -0
- data/test/run-test.rb +29 -0
- data/test/test_associations.rb +37 -0
- data/test/test_base.rb +113 -51
- data/test/test_dirty.rb +84 -0
- data/test/test_ldif.rb +0 -1
- data/test/test_load.rb +0 -1
- data/test/test_reflection.rb +7 -14
- data/test/test_syntax.rb +104 -43
- data/test/test_usermod-binary-del.rb +1 -1
- data/test/test_usermod-lang-add.rb +0 -1
- metadata +272 -224
- data/lib/active_ldap/get_text_fallback.rb +0 -60
- data/lib/active_ldap/get_text_support.rb +0 -22
@@ -167,6 +167,7 @@ module ActiveLdap
|
|
167
167
|
|
168
168
|
def reset_runtime
|
169
169
|
active_connections.inject(0) do |result, (name, connection)|
|
170
|
+
_ = name # for suppress a warning on Ruby 1.9.3
|
170
171
|
result + connection.reset_runtime
|
171
172
|
end
|
172
173
|
end
|
@@ -211,7 +212,7 @@ module ActiveLdap
|
|
211
212
|
end
|
212
213
|
end
|
213
214
|
if !ruby_ldap_available and Object.const_defined?(:Gem)
|
214
|
-
ruby_ldap_available =
|
215
|
+
ruby_ldap_available = gem_available?("ruby-ldap")
|
215
216
|
end
|
216
217
|
if ruby_ldap_available
|
217
218
|
"ldap"
|
@@ -220,6 +221,10 @@ module ActiveLdap
|
|
220
221
|
end
|
221
222
|
end
|
222
223
|
end
|
224
|
+
|
225
|
+
def gem_available?(name)
|
226
|
+
not Gem::Specification.find_all_by_name(name).empty?
|
227
|
+
end
|
223
228
|
end
|
224
229
|
|
225
230
|
def setup_connection(config=nil)
|
data/lib/active_ldap/get_text.rb
CHANGED
@@ -1,9 +1,20 @@
|
|
1
|
-
|
2
|
-
ActiveLdap.const_set("GetText", FastGettext)
|
3
|
-
end
|
1
|
+
require "gettext"
|
4
2
|
|
5
|
-
|
6
|
-
|
7
|
-
|
3
|
+
module ActiveLdap
|
4
|
+
class << self
|
5
|
+
def get_text_supported?
|
6
|
+
true
|
7
|
+
end
|
8
|
+
end
|
8
9
|
|
9
|
-
|
10
|
+
module GetTextSupport
|
11
|
+
class << self
|
12
|
+
def included(base)
|
13
|
+
base.class_eval do
|
14
|
+
include(GetText)
|
15
|
+
bindtextdomain("active-ldap")
|
16
|
+
end
|
17
|
+
end
|
18
|
+
end
|
19
|
+
end
|
20
|
+
end
|
@@ -8,7 +8,9 @@ module ActiveLdap
|
|
8
8
|
extend(Find)
|
9
9
|
extend(LDIF)
|
10
10
|
extend(Delete)
|
11
|
+
extend(ClassOnlyDelete)
|
11
12
|
extend(Update)
|
13
|
+
extend(ClassOnlyUpdate)
|
12
14
|
|
13
15
|
include(Common)
|
14
16
|
include(Find)
|
@@ -22,7 +24,7 @@ module ActiveLdap
|
|
22
24
|
module Common
|
23
25
|
VALID_SEARCH_OPTIONS = [:attribute, :value, :filter, :prefix,
|
24
26
|
:classes, :scope, :limit, :attributes,
|
25
|
-
:sort_by, :order, :connection, :base]
|
27
|
+
:sort_by, :order, :connection, :base, :offset]
|
26
28
|
|
27
29
|
def search(options={}, &block)
|
28
30
|
validate_search_options(options)
|
@@ -31,6 +33,7 @@ module ActiveLdap
|
|
31
33
|
filter = options[:filter]
|
32
34
|
prefix = options[:prefix]
|
33
35
|
classes = options[:classes]
|
36
|
+
requested_attributes = options[:attributes]
|
34
37
|
|
35
38
|
value = value.first if value.is_a?(Array) and value.first.size == 1
|
36
39
|
|
@@ -56,20 +59,25 @@ module ActiveLdap
|
|
56
59
|
:scope => options[:scope] || scope,
|
57
60
|
:filter => filter,
|
58
61
|
:limit => options[:limit],
|
59
|
-
:attributes =>
|
62
|
+
:attributes => requested_attributes,
|
60
63
|
:sort_by => options[:sort_by] || sort_by,
|
61
64
|
:order => options[:order] || order,
|
62
65
|
}
|
63
|
-
|
64
66
|
options[:connection] ||= connection
|
65
67
|
values = []
|
68
|
+
requested_all_attributes_p =
|
69
|
+
(requested_attributes.nil? or requested_attributes.include?('*'))
|
66
70
|
options[:connection].search(search_options) do |dn, attrs|
|
67
71
|
attributes = {}
|
68
72
|
attrs.each do |key, _value|
|
69
|
-
|
70
|
-
|
71
|
-
|
72
|
-
|
73
|
+
if requested_all_attributes_p or requested_attributes.include?(key)
|
74
|
+
normalized_attribute, normalized_value =
|
75
|
+
normalize_attribute_options(key, _value)
|
76
|
+
attributes[normalized_attribute] ||= []
|
77
|
+
attributes[normalized_attribute].concat(normalized_value)
|
78
|
+
else
|
79
|
+
next
|
80
|
+
end
|
73
81
|
end
|
74
82
|
values << [dn, attributes]
|
75
83
|
end
|
@@ -280,8 +288,9 @@ module ActiveLdap
|
|
280
288
|
sort_by = options.delete(:sort_by) || self.sort_by
|
281
289
|
order = options.delete(:order) || self.order
|
282
290
|
limit = options.delete(:limit) if sort_by or order
|
283
|
-
options
|
284
|
-
|
291
|
+
offset = options.delete(:offset) || offset
|
292
|
+
options[:attributes] = options.delete(:attributes) || ['*']
|
293
|
+
options[:attributes] |= ['objectClass']
|
285
294
|
results = search(options).collect do |dn, attrs|
|
286
295
|
instantiate([dn, attrs, {:connection => options[:connection]}])
|
287
296
|
end
|
@@ -295,6 +304,7 @@ module ActiveLdap
|
|
295
304
|
end
|
296
305
|
|
297
306
|
results.reverse! if normalize_sort_order(order || "ascend") == :descend
|
307
|
+
results = results[offset, results.size] if offset
|
298
308
|
results = results[0, limit] if limit
|
299
309
|
results
|
300
310
|
end
|
@@ -479,13 +489,6 @@ module ActiveLdap
|
|
479
489
|
end
|
480
490
|
|
481
491
|
module Delete
|
482
|
-
def destroy(targets, options={})
|
483
|
-
targets = [targets] unless targets.is_a?(Array)
|
484
|
-
targets.each do |target|
|
485
|
-
find(target, options).destroy
|
486
|
-
end
|
487
|
-
end
|
488
|
-
|
489
492
|
def destroy_all(options_or_filter=nil, deprecated_options=nil)
|
490
493
|
if deprecated_options.nil?
|
491
494
|
if options_or_filter.is_a?(String)
|
@@ -504,24 +507,6 @@ module ActiveLdap
|
|
504
507
|
end
|
505
508
|
end
|
506
509
|
|
507
|
-
def delete(targets, options={})
|
508
|
-
targets = [targets] unless targets.is_a?(Array)
|
509
|
-
targets = targets.collect do |target|
|
510
|
-
ensure_dn_attribute(ensure_base(target))
|
511
|
-
end
|
512
|
-
delete_entry(targets, options)
|
513
|
-
end
|
514
|
-
|
515
|
-
def delete_entry(dn, options={})
|
516
|
-
options[:connection] ||= connection
|
517
|
-
begin
|
518
|
-
options[:connection].delete(dn, options)
|
519
|
-
rescue Error
|
520
|
-
format = _("Failed to delete LDAP entry: <%s>: %s")
|
521
|
-
raise DeleteError.new(format % [dn.inspect, $!.message])
|
522
|
-
end
|
523
|
-
end
|
524
|
-
|
525
510
|
def delete_all(options_or_filter=nil, deprecated_options=nil)
|
526
511
|
if deprecated_options.nil?
|
527
512
|
if options_or_filter.is_a?(String)
|
@@ -540,6 +525,33 @@ module ActiveLdap
|
|
540
525
|
|
541
526
|
delete_entry(targets, options)
|
542
527
|
end
|
528
|
+
|
529
|
+
def delete_entry(dn, options={})
|
530
|
+
options[:connection] ||= connection
|
531
|
+
begin
|
532
|
+
options[:connection].delete(dn, options)
|
533
|
+
rescue Error
|
534
|
+
format = _("Failed to delete LDAP entry: <%s>: %s")
|
535
|
+
raise DeleteError.new(format % [dn.inspect, $!.message])
|
536
|
+
end
|
537
|
+
end
|
538
|
+
end
|
539
|
+
|
540
|
+
module ClassOnlyDelete
|
541
|
+
def destroy(targets, options={})
|
542
|
+
targets = [targets] unless targets.is_a?(Array)
|
543
|
+
targets.each do |target|
|
544
|
+
find(target, options).destroy
|
545
|
+
end
|
546
|
+
end
|
547
|
+
|
548
|
+
def delete(targets, options={})
|
549
|
+
targets = [targets] unless targets.is_a?(Array)
|
550
|
+
targets = targets.collect do |target|
|
551
|
+
ensure_dn_attribute(ensure_base(target))
|
552
|
+
end
|
553
|
+
delete_entry(targets, options)
|
554
|
+
end
|
543
555
|
end
|
544
556
|
|
545
557
|
module Update
|
@@ -566,21 +578,6 @@ module ActiveLdap
|
|
566
578
|
new_superior, options)
|
567
579
|
end
|
568
580
|
|
569
|
-
def update(dn, attributes, options={})
|
570
|
-
if dn.is_a?(Array)
|
571
|
-
i = -1
|
572
|
-
dns = dn
|
573
|
-
dns.collect do |_dn|
|
574
|
-
i += 1
|
575
|
-
update(_dn, attributes[i], options)
|
576
|
-
end
|
577
|
-
else
|
578
|
-
object = find(dn, options)
|
579
|
-
object.update_attributes(attributes)
|
580
|
-
object
|
581
|
-
end
|
582
|
-
end
|
583
|
-
|
584
581
|
def update_all(attributes, filter=nil, options={})
|
585
582
|
search_options = options.dup
|
586
583
|
if filter
|
@@ -606,5 +603,22 @@ module ActiveLdap
|
|
606
603
|
end
|
607
604
|
end
|
608
605
|
end
|
606
|
+
|
607
|
+
module ClassOnlyUpdate
|
608
|
+
def update(dn, attributes, options={})
|
609
|
+
if dn.is_a?(Array)
|
610
|
+
i = -1
|
611
|
+
dns = dn
|
612
|
+
dns.collect do |_dn|
|
613
|
+
i += 1
|
614
|
+
update(_dn, attributes[i], options)
|
615
|
+
end
|
616
|
+
else
|
617
|
+
object = find(dn, options)
|
618
|
+
object.update_attributes(attributes)
|
619
|
+
object
|
620
|
+
end
|
621
|
+
end
|
622
|
+
end
|
609
623
|
end
|
610
624
|
end
|
@@ -72,5 +72,22 @@ module ActiveLdap
|
|
72
72
|
true
|
73
73
|
end
|
74
74
|
end
|
75
|
+
|
76
|
+
def reload
|
77
|
+
clear_association_cache
|
78
|
+
_, attributes = search(:value => id).find do |_dn, _attributes|
|
79
|
+
dn == _dn
|
80
|
+
end
|
81
|
+
if attributes.nil?
|
82
|
+
raise EntryNotFound, _("Can't find DN '%s' to reload") % dn
|
83
|
+
end
|
84
|
+
|
85
|
+
@ldap_data.update(attributes)
|
86
|
+
classes, attributes = extract_object_class(attributes)
|
87
|
+
self.classes = classes
|
88
|
+
self.attributes = attributes
|
89
|
+
@new_entry = false
|
90
|
+
self
|
91
|
+
end
|
75
92
|
end # Persistence
|
76
93
|
end # ActiveLdap
|
data/lib/active_ldap/railtie.rb
CHANGED
data/lib/active_ldap/schema.rb
CHANGED
@@ -12,6 +12,7 @@ module ActiveLdap
|
|
12
12
|
def ids(group)
|
13
13
|
ensure_parse(group)
|
14
14
|
info, ids, aliases = ensure_schema_info(group)
|
15
|
+
_ = info = aliases # for suppress a warning on Ruby 1.9.3
|
15
16
|
ids.keys
|
16
17
|
end
|
17
18
|
|
@@ -54,6 +55,7 @@ module ActiveLdap
|
|
54
55
|
|
55
56
|
# Initialize anything that is required
|
56
57
|
info, ids, aliases = ensure_schema_info(group)
|
58
|
+
_ = info # for suppress a warning on Ruby 1.9.3
|
57
59
|
id, name = determine_id_or_name(id_or_name, aliases)
|
58
60
|
|
59
61
|
# Check already parsed options first
|
@@ -180,10 +180,10 @@ module ActiveLdap
|
|
180
180
|
return value if value.nil? or value.is_a?(Time)
|
181
181
|
match_data = FORMAT.match(value)
|
182
182
|
if match_data
|
183
|
-
required_components = match_data.to_a[1,
|
183
|
+
required_components = match_data.to_a[1, 5]
|
184
184
|
return value if required_components.any?(&:nil?)
|
185
|
-
year, month, day, hour, minute
|
186
|
-
|
185
|
+
year, month, day, hour, minute = required_components.collect(&:to_i)
|
186
|
+
second = match_data[-3].to_i
|
187
187
|
fraction = match_data[-2]
|
188
188
|
fraction = fraction.to_f if fraction
|
189
189
|
time_zone = match_data[-1]
|
@@ -224,11 +224,11 @@ module ActiveLdap
|
|
224
224
|
def validate_normalized_value(value, original_value)
|
225
225
|
match_data = FORMAT.match(value)
|
226
226
|
if match_data
|
227
|
-
|
228
|
-
match_data.to_a[1..-1]
|
227
|
+
date_data = match_data.to_a[1..-1]
|
229
228
|
missing_components = []
|
230
|
-
%w(year month day hour minute
|
231
|
-
|
229
|
+
required_components = %w(year month day hour minute)
|
230
|
+
required_components.each_with_index do |component, i|
|
231
|
+
missing_components << component unless date_data[i]
|
232
232
|
end
|
233
233
|
if missing_components.empty?
|
234
234
|
nil
|
data/lib/active_ldap/xml.rb
CHANGED
@@ -6,7 +6,7 @@ require 'active_ldap/ldif'
|
|
6
6
|
module ActiveLdap
|
7
7
|
class Xml
|
8
8
|
class Serializer
|
9
|
-
PRINTABLE_STRING = /[\x20-\x7e\
|
9
|
+
PRINTABLE_STRING = /[\x20-\x7e\t\r\n]*/n
|
10
10
|
|
11
11
|
def initialize(dn, attributes, schema, options={})
|
12
12
|
@dn = dn
|
@@ -23,6 +23,7 @@ module ActiveLdap
|
|
23
23
|
target_attributes.each do |key, values|
|
24
24
|
values = normalize_values(values).sort_by {|value, _| value}
|
25
25
|
if @schema.attribute(key).single_value?
|
26
|
+
next if values.empty?
|
26
27
|
serialize_attribute_value(xml, key, *values[0])
|
27
28
|
else
|
28
29
|
serialize_attribute_values(xml, key, values)
|
@@ -34,13 +35,29 @@ module ActiveLdap
|
|
34
35
|
private
|
35
36
|
def target_attributes
|
36
37
|
except_dn = false
|
37
|
-
|
38
|
-
|
39
|
-
|
40
|
-
|
41
|
-
|
42
|
-
|
38
|
+
only = @options[:only] || []
|
39
|
+
except = @options[:except] || []
|
40
|
+
if !only.empty?
|
41
|
+
attributes = []
|
42
|
+
except_dn = true
|
43
|
+
only.each do |name|
|
44
|
+
if name == "dn"
|
45
|
+
except_dn = false
|
46
|
+
elsif @attributes.has_key?(name)
|
47
|
+
attributes << [name, @attributes[name]]
|
48
|
+
end
|
43
49
|
end
|
50
|
+
elsif !except.empty?
|
51
|
+
attributes = @attributes.dup
|
52
|
+
except.each do |name|
|
53
|
+
if name == "dn"
|
54
|
+
except_dn = true
|
55
|
+
else
|
56
|
+
attributes.delete(name)
|
57
|
+
end
|
58
|
+
end
|
59
|
+
else
|
60
|
+
attributes = @attributes.dup
|
44
61
|
end
|
45
62
|
attributes = attributes.sort_by {|key, values| key}
|
46
63
|
attributes.unshift(["dn", [@dn]]) unless except_dn
|
@@ -33,10 +33,10 @@ module ActiveLdap
|
|
33
33
|
|
34
34
|
def ldap_mapping(indent=' ')
|
35
35
|
mapping = "ldap_mapping "
|
36
|
-
mapping_options = [
|
37
|
-
mapping_options <<
|
36
|
+
mapping_options = [key_value(:dn_attribute, options[:dn_attribute].dump)]
|
37
|
+
mapping_options << key_value(:prefix, prefix.dump)
|
38
38
|
if options[:classes]
|
39
|
-
mapping_options <<
|
39
|
+
mapping_options << key_value(:classes, options[:classes].inspect)
|
40
40
|
end
|
41
41
|
mapping_options = mapping_options.join(",\n#{indent}#{' ' * mapping.size}")
|
42
42
|
"#{indent}#{mapping}#{mapping_options}"
|
@@ -0,0 +1,10 @@
|
|
1
|
+
# Your LDAP server need to accept 'phonetic' attribute option for test.
|
2
|
+
# This is a LDIF file for OpenLDAP to do the confiugration.
|
3
|
+
# You can use this file by the following command linne on Debian GNU/Linux
|
4
|
+
# or Ubuntu:
|
5
|
+
# % sudo -H ldapmodify -Y EXTERNAL -H ldapi:/// -f test/add-phonetic-attribute-options-to-slapd.ldif
|
6
|
+
version: 1
|
7
|
+
dn: cn=config
|
8
|
+
changetype: modify
|
9
|
+
add: olcAttributeOptions
|
10
|
+
olcAttributeOptions: phonetic lang-
|
@@ -0,0 +1,428 @@
|
|
1
|
+
require 'test-unit'
|
2
|
+
|
3
|
+
require 'erb'
|
4
|
+
require 'yaml'
|
5
|
+
require 'socket'
|
6
|
+
require 'rbconfig'
|
7
|
+
require 'tempfile'
|
8
|
+
|
9
|
+
require 'active_ldap'
|
10
|
+
|
11
|
+
require File.join(File.expand_path(File.dirname(__FILE__)), "command")
|
12
|
+
|
13
|
+
LDAP_ENV = "test" unless defined?(LDAP_ENV)
|
14
|
+
|
15
|
+
module AlTestUtils
|
16
|
+
def self.included(base)
|
17
|
+
base.class_eval do
|
18
|
+
include ActiveLdap::GetTextSupport
|
19
|
+
include Utilities
|
20
|
+
include Config
|
21
|
+
include Connection
|
22
|
+
include Populate
|
23
|
+
include TemporaryEntry
|
24
|
+
include CommandSupport
|
25
|
+
include MockLogger
|
26
|
+
end
|
27
|
+
end
|
28
|
+
|
29
|
+
module Utilities
|
30
|
+
def dn(string)
|
31
|
+
ActiveLdap::DN.parse(string)
|
32
|
+
end
|
33
|
+
end
|
34
|
+
|
35
|
+
module Config
|
36
|
+
def setup
|
37
|
+
super
|
38
|
+
@base_dir = File.expand_path(File.dirname(__FILE__))
|
39
|
+
@top_dir = File.expand_path(File.join(@base_dir, ".."))
|
40
|
+
@example_dir = File.join(@top_dir, "examples")
|
41
|
+
@fixtures_dir = File.join(@base_dir, "fixtures")
|
42
|
+
@config_file = File.join(@base_dir, "config.yaml")
|
43
|
+
ActiveLdap::Base.configurations = read_config
|
44
|
+
end
|
45
|
+
|
46
|
+
def teardown
|
47
|
+
super
|
48
|
+
end
|
49
|
+
|
50
|
+
def current_configuration
|
51
|
+
ActiveLdap::Base.configurations[LDAP_ENV]
|
52
|
+
end
|
53
|
+
|
54
|
+
def read_config
|
55
|
+
unless File.exist?(@config_file)
|
56
|
+
raise "config file for testing doesn't exist: #{@config_file}"
|
57
|
+
end
|
58
|
+
erb = ERB.new(File.read(@config_file))
|
59
|
+
erb.filename = @config_file
|
60
|
+
config = YAML.load(erb.result)
|
61
|
+
_adapter = adapter
|
62
|
+
config.each do |key, value|
|
63
|
+
value["adapter"] = _adapter if _adapter
|
64
|
+
end
|
65
|
+
config
|
66
|
+
end
|
67
|
+
|
68
|
+
def adapter
|
69
|
+
ENV["ACTIVE_LDAP_TEST_ADAPTER"]
|
70
|
+
end
|
71
|
+
|
72
|
+
def fixture(*components)
|
73
|
+
File.join(@fixtures_dir, *components)
|
74
|
+
end
|
75
|
+
end
|
76
|
+
|
77
|
+
module ExampleFile
|
78
|
+
def certificate_path
|
79
|
+
File.join(@example_dir, 'example.der')
|
80
|
+
end
|
81
|
+
|
82
|
+
@@certificate = nil
|
83
|
+
def certificate
|
84
|
+
return @@certificate if @@certificate
|
85
|
+
if File.exists?(certificate_path)
|
86
|
+
@@certificate = read_binary_file(certificate_path)
|
87
|
+
return @@certificate
|
88
|
+
end
|
89
|
+
|
90
|
+
require 'openssl'
|
91
|
+
rsa = OpenSSL::PKey::RSA.new(512)
|
92
|
+
comment = "Generated by Ruby/OpenSSL"
|
93
|
+
|
94
|
+
cert = OpenSSL::X509::Certificate.new
|
95
|
+
cert.version = 3
|
96
|
+
cert.serial = 0
|
97
|
+
subject = [["OU", "test"],
|
98
|
+
["CN", Socket.gethostname]]
|
99
|
+
name = OpenSSL::X509::Name.new(subject)
|
100
|
+
cert.subject = name
|
101
|
+
cert.issuer = name
|
102
|
+
cert.not_before = Time.now
|
103
|
+
cert.not_after = Time.now + (365*24*60*60)
|
104
|
+
cert.public_key = rsa.public_key
|
105
|
+
|
106
|
+
ef = OpenSSL::X509::ExtensionFactory.new(nil, cert)
|
107
|
+
ef.issuer_certificate = cert
|
108
|
+
cert.extensions = [
|
109
|
+
ef.create_extension("basicConstraints","CA:FALSE"),
|
110
|
+
ef.create_extension("keyUsage", "keyEncipherment"),
|
111
|
+
ef.create_extension("subjectKeyIdentifier", "hash"),
|
112
|
+
ef.create_extension("extendedKeyUsage", "serverAuth"),
|
113
|
+
ef.create_extension("nsComment", comment),
|
114
|
+
]
|
115
|
+
aki = ef.create_extension("authorityKeyIdentifier",
|
116
|
+
"keyid:always,issuer:always")
|
117
|
+
cert.add_extension(aki)
|
118
|
+
cert.sign(rsa, OpenSSL::Digest::SHA1.new)
|
119
|
+
|
120
|
+
@@certificate = cert.to_der
|
121
|
+
@@certificate
|
122
|
+
end
|
123
|
+
|
124
|
+
def jpeg_photo_path
|
125
|
+
File.join(@example_dir, 'example.jpg')
|
126
|
+
end
|
127
|
+
|
128
|
+
def jpeg_photo
|
129
|
+
read_binary_file(jpeg_photo_path)
|
130
|
+
end
|
131
|
+
|
132
|
+
def read_binary_file(path)
|
133
|
+
File.open(path, "rb") do |input|
|
134
|
+
input.set_encoding("ascii-8bit") if input.respond_to?(:set_encoding)
|
135
|
+
input.read
|
136
|
+
end
|
137
|
+
end
|
138
|
+
end
|
139
|
+
|
140
|
+
module Connection
|
141
|
+
def setup
|
142
|
+
super
|
143
|
+
ActiveLdap::Base.setup_connection
|
144
|
+
end
|
145
|
+
|
146
|
+
def teardown
|
147
|
+
ActiveLdap::Base.remove_active_connections!
|
148
|
+
super
|
149
|
+
end
|
150
|
+
end
|
151
|
+
|
152
|
+
module Populate
|
153
|
+
def setup
|
154
|
+
@dumped_data = nil
|
155
|
+
super
|
156
|
+
begin
|
157
|
+
@dumped_data = ActiveLdap::Base.dump(:scope => :sub)
|
158
|
+
rescue ActiveLdap::ConnectionError
|
159
|
+
end
|
160
|
+
ActiveLdap::Base.delete_all(nil, :scope => :sub)
|
161
|
+
populate
|
162
|
+
end
|
163
|
+
|
164
|
+
def teardown
|
165
|
+
if @dumped_data
|
166
|
+
ActiveLdap::Base.setup_connection
|
167
|
+
ActiveLdap::Base.delete_all(nil, :scope => :sub)
|
168
|
+
ActiveLdap::Base.load(@dumped_data)
|
169
|
+
end
|
170
|
+
super
|
171
|
+
end
|
172
|
+
|
173
|
+
def populate
|
174
|
+
populate_base
|
175
|
+
populate_ou
|
176
|
+
populate_user_class
|
177
|
+
populate_group_class
|
178
|
+
populate_associations
|
179
|
+
end
|
180
|
+
|
181
|
+
def populate_base
|
182
|
+
ActiveLdap::Populate.ensure_base
|
183
|
+
end
|
184
|
+
|
185
|
+
def ou_class(prefix="")
|
186
|
+
ou_class = Class.new(ActiveLdap::Base)
|
187
|
+
ou_class.ldap_mapping(:dn_attribute => "ou",
|
188
|
+
:prefix => prefix,
|
189
|
+
:classes => ["top", "organizationalUnit"])
|
190
|
+
ou_class
|
191
|
+
end
|
192
|
+
|
193
|
+
def dc_class(prefix="")
|
194
|
+
dc_class = Class.new(ActiveLdap::Base)
|
195
|
+
dc_class.ldap_mapping(:dn_attribute => "dc",
|
196
|
+
:prefix => prefix,
|
197
|
+
:classes => ["top", "dcObject", "organization"])
|
198
|
+
dc_class
|
199
|
+
end
|
200
|
+
|
201
|
+
def entry_class(prefix="")
|
202
|
+
entry_class = Class.new(ActiveLdap::Base)
|
203
|
+
entry_class.ldap_mapping(:prefix => prefix,
|
204
|
+
:scope => :sub,
|
205
|
+
:classes => ["top"])
|
206
|
+
entry_class.dn_attribute = nil
|
207
|
+
entry_class
|
208
|
+
end
|
209
|
+
|
210
|
+
def populate_ou
|
211
|
+
%w(Users Groups).each do |name|
|
212
|
+
make_ou(name)
|
213
|
+
end
|
214
|
+
end
|
215
|
+
|
216
|
+
def make_ou(name)
|
217
|
+
ActiveLdap::Populate.ensure_ou(name)
|
218
|
+
end
|
219
|
+
|
220
|
+
def make_dc(name)
|
221
|
+
ActiveLdap::Populate.ensure_dc(name)
|
222
|
+
end
|
223
|
+
|
224
|
+
def populate_user_class
|
225
|
+
@user_class = Class.new(ActiveLdap::Base)
|
226
|
+
@user_class_classes = ["posixAccount", "person"]
|
227
|
+
@user_class.ldap_mapping :dn_attribute => "uid",
|
228
|
+
:prefix => "ou=Users",
|
229
|
+
:scope => :sub,
|
230
|
+
:classes => @user_class_classes
|
231
|
+
assign_class_name(@user_class, "User")
|
232
|
+
end
|
233
|
+
|
234
|
+
def populate_group_class
|
235
|
+
@group_class = Class.new(ActiveLdap::Base)
|
236
|
+
@group_class.ldap_mapping :prefix => "ou=Groups",
|
237
|
+
:scope => :sub,
|
238
|
+
:classes => ["posixGroup"]
|
239
|
+
assign_class_name(@group_class, "Group")
|
240
|
+
end
|
241
|
+
|
242
|
+
def populate_associations
|
243
|
+
@user_class.belongs_to :groups, :many => "memberUid"
|
244
|
+
@user_class.belongs_to :primary_group,
|
245
|
+
:foreign_key => "gidNumber",
|
246
|
+
:primary_key => "gidNumber"
|
247
|
+
@group_class.has_many :members, :wrap => "memberUid"
|
248
|
+
@group_class.has_many :primary_members,
|
249
|
+
:foreign_key => "gidNumber",
|
250
|
+
:primary_key => "gidNumber"
|
251
|
+
@user_class.set_associated_class(:groups, @group_class)
|
252
|
+
@user_class.set_associated_class(:primary_group, @group_class)
|
253
|
+
@group_class.set_associated_class(:members, @user_class)
|
254
|
+
@group_class.set_associated_class(:primary_members, @user_class)
|
255
|
+
end
|
256
|
+
|
257
|
+
def assign_class_name(klass, name)
|
258
|
+
singleton_class = class << klass; self; end
|
259
|
+
singleton_class.send(:define_method, :name) do
|
260
|
+
name
|
261
|
+
end
|
262
|
+
if Object.const_defined?(klass.name)
|
263
|
+
Object.send(:remove_const, klass.name)
|
264
|
+
end
|
265
|
+
Object.const_set(klass.name, klass)
|
266
|
+
end
|
267
|
+
end
|
268
|
+
|
269
|
+
module TemporaryEntry
|
270
|
+
include ExampleFile
|
271
|
+
|
272
|
+
def setup
|
273
|
+
super
|
274
|
+
@user_index = 0
|
275
|
+
@group_index = 0
|
276
|
+
end
|
277
|
+
|
278
|
+
def make_temporary_user(config={})
|
279
|
+
@user_index += 1
|
280
|
+
uid = config[:uid] || "temp-user#{@user_index}"
|
281
|
+
ensure_delete_user(uid) do
|
282
|
+
password = config[:password] || "password#{@user_index}"
|
283
|
+
uid_number = config[:uid_number] || default_uid
|
284
|
+
gid_number = config[:gid_number] || default_gid
|
285
|
+
home_directory = config[:home_directory] || "/nonexistent"
|
286
|
+
see_also = config[:see_also]
|
287
|
+
_wrap_assertion do
|
288
|
+
assert(!@user_class.exists?(uid))
|
289
|
+
assert_raise(ActiveLdap::EntryNotFound) do
|
290
|
+
@user_class.find(uid).dn
|
291
|
+
end
|
292
|
+
user = @user_class.new(uid)
|
293
|
+
assert(user.new_entry?)
|
294
|
+
user.cn = user.uid
|
295
|
+
user.sn = user.uid
|
296
|
+
user.uid_number = uid_number
|
297
|
+
user.gid_number = gid_number
|
298
|
+
user.home_directory = home_directory
|
299
|
+
user.user_password = ActiveLdap::UserPassword.ssha(password)
|
300
|
+
user.see_also = see_also
|
301
|
+
unless config[:simple]
|
302
|
+
user.add_class('shadowAccount', 'inetOrgPerson',
|
303
|
+
'organizationalPerson')
|
304
|
+
user.user_certificate = certificate
|
305
|
+
user.jpeg_photo = jpeg_photo
|
306
|
+
end
|
307
|
+
user.save
|
308
|
+
assert(!user.new_entry?)
|
309
|
+
yield(@user_class.find(user.uid), password)
|
310
|
+
end
|
311
|
+
end
|
312
|
+
end
|
313
|
+
|
314
|
+
def make_temporary_group(config={})
|
315
|
+
@group_index += 1
|
316
|
+
cn = config[:cn] || "temp-group#{@group_index}"
|
317
|
+
ensure_delete_group(cn) do
|
318
|
+
gid_number = config[:gid_number] || default_gid
|
319
|
+
_wrap_assertion do
|
320
|
+
assert(!@group_class.exists?(cn))
|
321
|
+
assert_raise(ActiveLdap::EntryNotFound) do
|
322
|
+
@group_class.find(cn)
|
323
|
+
end
|
324
|
+
group = @group_class.new(cn)
|
325
|
+
assert(group.new_entry?)
|
326
|
+
group.gid_number = gid_number
|
327
|
+
assert(group.save)
|
328
|
+
assert(!group.new_entry?)
|
329
|
+
yield(@group_class.find(group.cn))
|
330
|
+
end
|
331
|
+
end
|
332
|
+
end
|
333
|
+
|
334
|
+
def ensure_delete_user(uid)
|
335
|
+
yield(uid)
|
336
|
+
ensure
|
337
|
+
if @user_class.exists?(uid)
|
338
|
+
@user_class.search(:value => uid) do |dn, attribute|
|
339
|
+
@user_class.remove_connection(dn)
|
340
|
+
@user_class.delete(dn)
|
341
|
+
end
|
342
|
+
end
|
343
|
+
end
|
344
|
+
|
345
|
+
def ensure_delete_group(cn)
|
346
|
+
yield(cn)
|
347
|
+
ensure
|
348
|
+
@group_class.delete(cn) if @group_class.exists?(cn)
|
349
|
+
end
|
350
|
+
|
351
|
+
def default_uid
|
352
|
+
"10000#{@user_index}"
|
353
|
+
end
|
354
|
+
|
355
|
+
def default_gid
|
356
|
+
"10000#{@group_index}"
|
357
|
+
end
|
358
|
+
end
|
359
|
+
|
360
|
+
module CommandSupport
|
361
|
+
def setup
|
362
|
+
super
|
363
|
+
@fakeroot = "fakeroot"
|
364
|
+
@ruby = File.join(::RbConfig::CONFIG["bindir"],
|
365
|
+
::RbConfig::CONFIG["RUBY_INSTALL_NAME"])
|
366
|
+
@top_dir = File.expand_path(File.join(File.dirname(__FILE__), ".."))
|
367
|
+
@examples_dir = File.join(@top_dir, "examples")
|
368
|
+
@lib_dir = File.join(@top_dir, "lib")
|
369
|
+
@ruby_args = [
|
370
|
+
"-I", @examples_dir,
|
371
|
+
"-I", @lib_dir,
|
372
|
+
]
|
373
|
+
end
|
374
|
+
|
375
|
+
def run_command(*args, &block)
|
376
|
+
file = Tempfile.new("al-command-support")
|
377
|
+
file.open
|
378
|
+
file.puts(ActiveLdap::Base.configurations["test"].to_yaml)
|
379
|
+
file.close
|
380
|
+
run_ruby(*[@command, "--config", file.path, *args], &block)
|
381
|
+
end
|
382
|
+
|
383
|
+
def run_ruby(*ruby_args, &block)
|
384
|
+
args = [@ruby, *@ruby_args]
|
385
|
+
args.concat(ruby_args)
|
386
|
+
Command.run(*args, &block)
|
387
|
+
end
|
388
|
+
|
389
|
+
def run_ruby_with_fakeroot(*ruby_args, &block)
|
390
|
+
args = [@fakeroot, @ruby, *@ruby_args]
|
391
|
+
args.concat(ruby_args)
|
392
|
+
Command.run(*args, &block)
|
393
|
+
end
|
394
|
+
end
|
395
|
+
|
396
|
+
module MockLogger
|
397
|
+
def make_mock_logger
|
398
|
+
logger = Object.new
|
399
|
+
class << logger
|
400
|
+
def messages(type)
|
401
|
+
@messages ||= {}
|
402
|
+
@messages[type] ||= []
|
403
|
+
@messages[type]
|
404
|
+
end
|
405
|
+
|
406
|
+
def info(content=nil)
|
407
|
+
messages(:info) << (block_given? ? yield : content)
|
408
|
+
end
|
409
|
+
def warn(content=nil)
|
410
|
+
messages(:warn) << (block_given? ? yield : content)
|
411
|
+
end
|
412
|
+
def error(content=nil)
|
413
|
+
messages(:error) << (block_given? ? yield : content)
|
414
|
+
end
|
415
|
+
end
|
416
|
+
logger
|
417
|
+
end
|
418
|
+
|
419
|
+
def with_mock_logger
|
420
|
+
original_logger = ActiveLdap::Base.logger
|
421
|
+
mock_logger = make_mock_logger
|
422
|
+
ActiveLdap::Base.logger = mock_logger
|
423
|
+
yield(mock_logger)
|
424
|
+
ensure
|
425
|
+
ActiveLdap::Base.logger = original_logger
|
426
|
+
end
|
427
|
+
end
|
428
|
+
end
|