activeldap 3.1.1 → 3.2.0
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/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
|