ruby-activeldap 0.8.1 → 0.8.2
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 +5 -0
- data/Manifest.txt +91 -25
- data/README +22 -0
- data/Rakefile +41 -8
- data/TODO +1 -6
- data/examples/config.yaml.example +5 -0
- data/examples/example.der +0 -0
- data/examples/example.jpg +0 -0
- data/examples/groupadd +41 -0
- data/examples/groupdel +35 -0
- data/examples/groupls +49 -0
- data/examples/groupmod +42 -0
- data/examples/lpasswd +55 -0
- data/examples/objects/group.rb +13 -0
- data/examples/objects/ou.rb +4 -0
- data/examples/objects/user.rb +20 -0
- data/examples/ouadd +38 -0
- data/examples/useradd +45 -0
- data/examples/useradd-binary +50 -0
- data/examples/userdel +34 -0
- data/examples/userls +50 -0
- data/examples/usermod +42 -0
- data/examples/usermod-binary-add +47 -0
- data/examples/usermod-binary-add-time +51 -0
- data/examples/usermod-binary-del +48 -0
- data/examples/usermod-lang-add +43 -0
- data/lib/active_ldap.rb +213 -214
- data/lib/active_ldap/adapter/base.rb +461 -0
- data/lib/active_ldap/adapter/ldap.rb +232 -0
- data/lib/active_ldap/adapter/ldap_ext.rb +69 -0
- data/lib/active_ldap/adapter/net_ldap.rb +288 -0
- data/lib/active_ldap/adapter/net_ldap_ext.rb +29 -0
- data/lib/active_ldap/association/belongs_to.rb +3 -1
- data/lib/active_ldap/association/belongs_to_many.rb +5 -6
- data/lib/active_ldap/association/has_many.rb +9 -17
- data/lib/active_ldap/association/has_many_wrap.rb +4 -5
- data/lib/active_ldap/attributes.rb +4 -0
- data/lib/active_ldap/base.rb +201 -56
- data/lib/active_ldap/configuration.rb +11 -1
- data/lib/active_ldap/connection.rb +15 -9
- data/lib/active_ldap/distinguished_name.rb +246 -0
- data/lib/active_ldap/ldap_error.rb +74 -0
- data/lib/active_ldap/object_class.rb +9 -5
- data/lib/active_ldap/schema.rb +50 -9
- data/lib/active_ldap/validations.rb +11 -13
- data/rails/plugin/active_ldap/generators/scaffold_al/scaffold_al_generator.rb +7 -0
- data/rails/plugin/active_ldap/generators/scaffold_al/templates/ldap.yml +21 -0
- data/rails/plugin/active_ldap/init.rb +10 -4
- data/test/al-test-utils.rb +46 -3
- data/test/run-test.rb +16 -4
- data/test/test-unit-ext/always-show-result.rb +28 -0
- data/test/test-unit-ext/priority.rb +163 -0
- data/test/test_adapter.rb +81 -0
- data/test/test_attributes.rb +8 -1
- data/test/test_base.rb +132 -3
- data/test/test_base_per_instance.rb +14 -3
- data/test/test_connection.rb +19 -0
- data/test/test_dn.rb +161 -0
- data/test/test_find.rb +24 -0
- data/test/test_object_class.rb +15 -2
- data/test/test_schema.rb +108 -1
- metadata +111 -41
- data/lib/active_ldap/adaptor/base.rb +0 -29
- data/lib/active_ldap/adaptor/ldap.rb +0 -466
- data/lib/active_ldap/ldap.rb +0 -113
@@ -12,23 +12,20 @@ module ActiveLdap
|
|
12
12
|
validate :validate_required_values
|
13
13
|
|
14
14
|
class << self
|
15
|
-
|
16
|
-
|
17
|
-
def evaluate_condition(condition, entry)
|
18
|
-
evaluate_condition_for_active_record(condition, entry)
|
15
|
+
def evaluate_condition_with_active_ldap_support(condition, entry)
|
16
|
+
evaluate_condition_without_active_ldap_support(condition, entry)
|
19
17
|
rescue ActiveRecord::ActiveRecordError
|
20
18
|
raise Error, $!.message
|
21
19
|
end
|
20
|
+
alias_method_chain :evaluate_condition, :active_ldap_support
|
22
21
|
end
|
23
22
|
|
24
|
-
|
25
|
-
|
26
|
-
def save_with_validation!
|
27
|
-
save_with_validation_for_active_record!
|
23
|
+
def save_with_active_ldap_support!
|
24
|
+
save_without_active_ldap_support!
|
28
25
|
rescue ActiveRecord::RecordInvalid
|
29
26
|
raise EntryInvalid, $!.message
|
30
27
|
end
|
31
|
-
|
28
|
+
alias_method_chain :save!, :active_ldap_support
|
32
29
|
|
33
30
|
def valid?
|
34
31
|
ensure_apply_object_class
|
@@ -46,7 +43,8 @@ module ActiveLdap
|
|
46
43
|
@musts.each do |object_class, attributes|
|
47
44
|
attributes.each do |required_attribute|
|
48
45
|
# Normalize to ensure we catch schema problems
|
49
|
-
real_name = to_real_attribute_name(required_attribute)
|
46
|
+
real_name = to_real_attribute_name(required_attribute, true)
|
47
|
+
raise UnknownAttribute.new(required_attribute) if real_name.nil?
|
50
48
|
# # Set default if it wasn't yet set.
|
51
49
|
# @data[real_name] ||= [] # need?
|
52
50
|
value = @data[real_name] || []
|
@@ -66,12 +64,12 @@ module ActiveLdap
|
|
66
64
|
end
|
67
65
|
|
68
66
|
private
|
69
|
-
|
70
|
-
|
71
|
-
run_validations_for_active_record(validation_method)
|
67
|
+
def run_validations_with_active_ldap_support(validation_method)
|
68
|
+
run_validations_without_active_ldap_support(validation_method)
|
72
69
|
rescue ActiveRecord::ActiveRecordError
|
73
70
|
raise Error, $!.message
|
74
71
|
end
|
72
|
+
alias_method_chain :run_validations, :active_ldap_support
|
75
73
|
end
|
76
74
|
end
|
77
75
|
end
|
@@ -0,0 +1,21 @@
|
|
1
|
+
development:
|
2
|
+
host: 127.0.0.1
|
3
|
+
port: 389
|
4
|
+
base: dc=devel,dc=local,dc=net
|
5
|
+
bind_dn: cn=admin,dc=local,dc=net
|
6
|
+
password: secret
|
7
|
+
|
8
|
+
test:
|
9
|
+
host: 127.0.0.1
|
10
|
+
port: 389
|
11
|
+
base: dc=test,dc=local,dc=net
|
12
|
+
bind_dn: cn=admin,dc=local,dc=net
|
13
|
+
password: secret
|
14
|
+
|
15
|
+
production:
|
16
|
+
host: 127.0.0.1
|
17
|
+
port: 389
|
18
|
+
method: :tls
|
19
|
+
base: dc=production,dc=local,dc=net
|
20
|
+
bind_dn: cn=admin,dc=local,dc=net
|
21
|
+
password: secret
|
@@ -1,6 +1,12 @@
|
|
1
|
-
|
1
|
+
require_library_or_gem 'active_ldap'
|
2
2
|
ActiveLdap::Base.logger ||= RAILS_DEFAULT_LOGGER
|
3
3
|
ldap_configuration_file = File.join(RAILS_ROOT, 'config', 'ldap.yml')
|
4
|
-
|
5
|
-
|
6
|
-
ActiveLdap::Base.
|
4
|
+
if File.exist?(ldap_configuration_file)
|
5
|
+
configurations = YAML::load(ERB.new(IO.read(ldap_configuration_file)).result)
|
6
|
+
ActiveLdap::Base.configurations = configurations
|
7
|
+
ActiveLdap::Base.establish_connection
|
8
|
+
else
|
9
|
+
message = "You should run 'script/generator scaffold_al' " +
|
10
|
+
"to make #{ldap_configuration_file}"
|
11
|
+
ActiveLdap::Base.logger.error(message)
|
12
|
+
end
|
data/test/al-test-utils.rb
CHANGED
@@ -22,6 +22,7 @@ module AlTestUtils
|
|
22
22
|
include Populate
|
23
23
|
include TemporaryEntry
|
24
24
|
include CommandSupport
|
25
|
+
include MockLogger
|
25
26
|
end
|
26
27
|
end
|
27
28
|
|
@@ -47,7 +48,12 @@ module AlTestUtils
|
|
47
48
|
unless File.exist?(@config_file)
|
48
49
|
raise "config file for testing doesn't exist: #{@config_file}"
|
49
50
|
end
|
50
|
-
YAML.load(ERB.new(File.read(@config_file)).result)
|
51
|
+
config = YAML.load(ERB.new(File.read(@config_file)).result)
|
52
|
+
config.each do |key, value|
|
53
|
+
adapter = ENV["ACTIVE_LDAP_TEST_ADAPTER"]
|
54
|
+
value[:adapter] = adapter if adapter
|
55
|
+
end
|
56
|
+
config
|
51
57
|
end
|
52
58
|
end
|
53
59
|
|
@@ -112,7 +118,10 @@ module AlTestUtils
|
|
112
118
|
next if dc_class.exists?(value, :prefix => "dc=#{value}")
|
113
119
|
dc = dc_class.new(value)
|
114
120
|
dc.o = dc.dc
|
115
|
-
|
121
|
+
begin
|
122
|
+
dc.save
|
123
|
+
rescue ActiveLdap::OperationNotPermitted
|
124
|
+
end
|
116
125
|
end
|
117
126
|
end
|
118
127
|
|
@@ -136,10 +145,11 @@ module AlTestUtils
|
|
136
145
|
|
137
146
|
def populate_user_class
|
138
147
|
@user_class = Class.new(ActiveLdap::Base)
|
148
|
+
@user_class_classes = ["posixAccount", "person"]
|
139
149
|
@user_class.ldap_mapping :dn_attribute => "uid",
|
140
150
|
:prefix => "ou=Users",
|
141
151
|
:scope => :sub,
|
142
|
-
:classes =>
|
152
|
+
:classes => @user_class_classes
|
143
153
|
end
|
144
154
|
|
145
155
|
def populate_group_class
|
@@ -335,4 +345,37 @@ module AlTestUtils
|
|
335
345
|
Command.run(*args, &block)
|
336
346
|
end
|
337
347
|
end
|
348
|
+
|
349
|
+
module MockLogger
|
350
|
+
def make_mock_logger
|
351
|
+
logger = Object.new
|
352
|
+
class << logger
|
353
|
+
def messages(type)
|
354
|
+
@messages ||= {}
|
355
|
+
@messages[type] ||= []
|
356
|
+
@messages[type]
|
357
|
+
end
|
358
|
+
|
359
|
+
def info(content=nil)
|
360
|
+
messages(:info) << (block_given? ? yield : content)
|
361
|
+
end
|
362
|
+
def warn(content=nil)
|
363
|
+
messages(:warn) << (block_given? ? yield : content)
|
364
|
+
end
|
365
|
+
def error(content=nil)
|
366
|
+
messages(:error) << (block_given? ? yield : content)
|
367
|
+
end
|
368
|
+
end
|
369
|
+
logger
|
370
|
+
end
|
371
|
+
|
372
|
+
def with_mock_logger
|
373
|
+
original_logger = ActiveLdap::Base.logger
|
374
|
+
mock_logger = make_mock_logger
|
375
|
+
ActiveLdap::Base.logger = mock_logger
|
376
|
+
yield(mock_logger)
|
377
|
+
ensure
|
378
|
+
ActiveLdap::Base.logger = original_logger
|
379
|
+
end
|
380
|
+
end
|
338
381
|
end
|
data/test/run-test.rb
CHANGED
@@ -10,8 +10,20 @@ $LOAD_PATH.unshift(File.join(top_dir, "test"))
|
|
10
10
|
|
11
11
|
require 'test-unit-ext'
|
12
12
|
|
13
|
-
|
14
|
-
|
15
|
-
|
16
|
-
|
13
|
+
test_file = "test/test_*.rb"
|
14
|
+
Dir.glob(test_file) do |file|
|
15
|
+
require file
|
16
|
+
end
|
17
|
+
|
18
|
+
[nil, "ldap", "net-ldap"].each do |adapter|
|
19
|
+
ENV["ACTIVE_LDAP_TEST_ADAPTER"] = adapter
|
20
|
+
puts "using adapter: #{adapter ? adapter : 'default'}"
|
21
|
+
args = [File.dirname($0), ARGV.dup]
|
22
|
+
if Test::Unit::AutoRunner.respond_to?(:standalone?)
|
23
|
+
args.unshift(false)
|
24
|
+
else
|
25
|
+
args.unshift($0)
|
26
|
+
end
|
27
|
+
Test::Unit::AutoRunner.run(*args)
|
28
|
+
puts
|
17
29
|
end
|
@@ -0,0 +1,28 @@
|
|
1
|
+
require "test/unit/ui/testrunnermediator"
|
2
|
+
|
3
|
+
module Test
|
4
|
+
module Unit
|
5
|
+
module UI
|
6
|
+
class TestRunnerMediator
|
7
|
+
alias_method :original_run_suite, :run_suite
|
8
|
+
def run_suite
|
9
|
+
@notified_finished = false
|
10
|
+
begin_time = Time.now
|
11
|
+
original_run_suite
|
12
|
+
rescue Interrupt
|
13
|
+
unless @notified_finished
|
14
|
+
end_time = Time.now
|
15
|
+
elapsed_time = end_time - begin_time
|
16
|
+
notify_listeners(FINISHED, elapsed_time)
|
17
|
+
end
|
18
|
+
raise
|
19
|
+
end
|
20
|
+
|
21
|
+
def notify_listeners(channel_name, *arguments)
|
22
|
+
@notified_finished = true if channel_name == FINISHED
|
23
|
+
super
|
24
|
+
end
|
25
|
+
end
|
26
|
+
end
|
27
|
+
end
|
28
|
+
end
|
@@ -0,0 +1,163 @@
|
|
1
|
+
require "test/unit"
|
2
|
+
|
3
|
+
require "fileutils"
|
4
|
+
|
5
|
+
module Test
|
6
|
+
module Unit
|
7
|
+
class TestCase
|
8
|
+
class << self
|
9
|
+
def inherited(sub)
|
10
|
+
super
|
11
|
+
sub.instance_variable_set("@priority_initialized", true)
|
12
|
+
sub.instance_variable_set("@priority_table", {})
|
13
|
+
sub.priority :normal
|
14
|
+
end
|
15
|
+
|
16
|
+
def include(*args)
|
17
|
+
args.reverse_each do |mod|
|
18
|
+
super(mod)
|
19
|
+
next unless defined?(@priority_initialized)
|
20
|
+
mod.instance_methods(false).each do |name|
|
21
|
+
set_priority(name)
|
22
|
+
end
|
23
|
+
end
|
24
|
+
end
|
25
|
+
|
26
|
+
def method_added(name)
|
27
|
+
set_priority(name) if defined?(@priority_initialized)
|
28
|
+
end
|
29
|
+
|
30
|
+
def priority(name, *tests)
|
31
|
+
unless private_methods.include?(priority_check_method_name(name))
|
32
|
+
raise ArgumentError, "unknown priority: #{name}"
|
33
|
+
end
|
34
|
+
if tests.empty?
|
35
|
+
@current_priority = name
|
36
|
+
else
|
37
|
+
tests.each do |test|
|
38
|
+
set_priority(test, name)
|
39
|
+
end
|
40
|
+
end
|
41
|
+
end
|
42
|
+
|
43
|
+
def need_to_run?(test_name)
|
44
|
+
normalized_test_name = normalize_test_name(test_name)
|
45
|
+
priority = @priority_table[normalized_test_name]
|
46
|
+
return true unless priority
|
47
|
+
__send__(priority_check_method_name(priority), test_name)
|
48
|
+
end
|
49
|
+
|
50
|
+
private
|
51
|
+
def priority_check_method_name(priority_name)
|
52
|
+
"run_priority_#{priority_name}?"
|
53
|
+
end
|
54
|
+
|
55
|
+
def normalize_test_name(test_name)
|
56
|
+
"test_#{test_name.to_s.sub(/^test_/, '')}"
|
57
|
+
end
|
58
|
+
|
59
|
+
def set_priority(name, priority=@current_priority)
|
60
|
+
@priority_table[normalize_test_name(name)] = priority
|
61
|
+
end
|
62
|
+
|
63
|
+
def run_priority_must?(test_name)
|
64
|
+
true
|
65
|
+
end
|
66
|
+
|
67
|
+
def run_priority_important?(test_name)
|
68
|
+
rand > 0.1
|
69
|
+
end
|
70
|
+
|
71
|
+
def run_priority_high?(test_name)
|
72
|
+
rand > 0.3
|
73
|
+
end
|
74
|
+
|
75
|
+
def run_priority_normal?(test_name)
|
76
|
+
rand > 0.5
|
77
|
+
end
|
78
|
+
|
79
|
+
def run_priority_low?(test_name)
|
80
|
+
rand > 0.75
|
81
|
+
end
|
82
|
+
|
83
|
+
def run_priority_never?(test_name)
|
84
|
+
false
|
85
|
+
end
|
86
|
+
end
|
87
|
+
|
88
|
+
def need_to_run?
|
89
|
+
!previous_test_success? or self.class.need_to_run?(@method_name)
|
90
|
+
end
|
91
|
+
|
92
|
+
alias_method :original_run, :run
|
93
|
+
def run(result, &block)
|
94
|
+
original_run(result, &block)
|
95
|
+
ensure
|
96
|
+
if passed?
|
97
|
+
FileUtils.rm_f(not_passed_file)
|
98
|
+
else
|
99
|
+
FileUtils.touch(not_passed_file)
|
100
|
+
end
|
101
|
+
end
|
102
|
+
|
103
|
+
private
|
104
|
+
def previous_test_success?
|
105
|
+
not File.exist?(not_passed_file)
|
106
|
+
end
|
107
|
+
|
108
|
+
def result_dir
|
109
|
+
dir = File.join(File.dirname($0), ".test-result",
|
110
|
+
self.class.name, @method_name.to_s)
|
111
|
+
dir = File.expand_path(dir)
|
112
|
+
FileUtils.mkdir_p(dir)
|
113
|
+
dir
|
114
|
+
end
|
115
|
+
|
116
|
+
def not_passed_file
|
117
|
+
File.join(result_dir, "not-passed")
|
118
|
+
end
|
119
|
+
end
|
120
|
+
|
121
|
+
class TestSuite
|
122
|
+
@@priority_mode = false
|
123
|
+
|
124
|
+
class << self
|
125
|
+
def priority_mode=(bool)
|
126
|
+
@@priority_mode = bool
|
127
|
+
end
|
128
|
+
end
|
129
|
+
|
130
|
+
alias_method :original_run, :run
|
131
|
+
def run(*args, &block)
|
132
|
+
priority_mode = @@priority_mode
|
133
|
+
if priority_mode
|
134
|
+
@original_tests = @tests
|
135
|
+
apply_priority
|
136
|
+
end
|
137
|
+
original_run(*args, &block)
|
138
|
+
ensure
|
139
|
+
@tests = @original_tests if priority_mode
|
140
|
+
end
|
141
|
+
|
142
|
+
def apply_priority
|
143
|
+
@tests = @tests.reject {|test| !test.need_to_run?}
|
144
|
+
end
|
145
|
+
|
146
|
+
def need_to_run?
|
147
|
+
apply_priority
|
148
|
+
!@tests.empty?
|
149
|
+
end
|
150
|
+
end
|
151
|
+
|
152
|
+
class AutoRunner
|
153
|
+
alias_method :original_options, :options
|
154
|
+
def options
|
155
|
+
opts = original_options
|
156
|
+
opts.on("--[no-]priority", "use priority mode") do |bool|
|
157
|
+
TestSuite.priority_mode = bool
|
158
|
+
end
|
159
|
+
opts
|
160
|
+
end
|
161
|
+
end
|
162
|
+
end
|
163
|
+
end
|
@@ -0,0 +1,81 @@
|
|
1
|
+
require 'al-test-utils'
|
2
|
+
|
3
|
+
class TestAdapter < Test::Unit::TestCase
|
4
|
+
include AlTestUtils
|
5
|
+
|
6
|
+
def setup
|
7
|
+
end
|
8
|
+
|
9
|
+
def teardown
|
10
|
+
end
|
11
|
+
|
12
|
+
priority :must
|
13
|
+
|
14
|
+
priority :normal
|
15
|
+
def test_empty_filter
|
16
|
+
assert_parse_filter(nil, nil)
|
17
|
+
assert_parse_filter(nil, "")
|
18
|
+
assert_parse_filter(nil, " ")
|
19
|
+
end
|
20
|
+
|
21
|
+
def test_simple_filter
|
22
|
+
assert_parse_filter("(objectClass=*)", "objectClass=*")
|
23
|
+
assert_parse_filter("(objectClass=*)", "(objectClass=*)")
|
24
|
+
assert_parse_filter("(&(uid=bob)(objectClass=*))",
|
25
|
+
"(&(uid=bob)(objectClass=*))")
|
26
|
+
|
27
|
+
assert_parse_filter("(objectClass=*)", {:objectClass => "*"})
|
28
|
+
assert_parse_filter("(&(objectClass=*)(uid=bob))",
|
29
|
+
{:uid => "bob", :objectClass => "*"})
|
30
|
+
|
31
|
+
assert_parse_filter("(&(uid=bob)(objectClass=*))",
|
32
|
+
[:and, "uid=bob", "objectClass=*"])
|
33
|
+
assert_parse_filter("(&(uid=bob)(objectClass=*))",
|
34
|
+
[:&, "uid=bob", "objectClass=*"])
|
35
|
+
assert_parse_filter("(|(uid=bob)(objectClass=*))",
|
36
|
+
[:or, "uid=bob", "objectClass=*"])
|
37
|
+
assert_parse_filter("(|(uid=bob)(objectClass=*))",
|
38
|
+
[:|, "uid=bob", "objectClass=*"])
|
39
|
+
end
|
40
|
+
|
41
|
+
def test_multi_value_filter
|
42
|
+
assert_parse_filter("(&(objectClass=top)(objectClass=posixAccount))",
|
43
|
+
{:objectClass => ["top", "posixAccount"]})
|
44
|
+
|
45
|
+
assert_parse_filter("(&(objectClass=top)(objectClass=posixAccount))",
|
46
|
+
[[:objectClass, "top"],
|
47
|
+
[:objectClass, "posixAccount"]])
|
48
|
+
assert_parse_filter("(&(objectClass=top)(objectClass=posixAccount))",
|
49
|
+
[[:objectClass, ["top", "posixAccount"]]])
|
50
|
+
end
|
51
|
+
|
52
|
+
def test_nested_filter
|
53
|
+
assert_parse_filter("(&(objectClass=*)(uid=bob))",
|
54
|
+
[:and, {:uid => "bob", :objectClass => "*"}])
|
55
|
+
assert_parse_filter("(&(objectClass=*)(|(uid=bob)(uid=alice)))",
|
56
|
+
[:and, {:objectClass => "*"},
|
57
|
+
[:or, [:uid, "bob"], [:uid, "alice"]]])
|
58
|
+
assert_parse_filter("(&(objectClass=*)(|(uid=bob)(uid=alice)))",
|
59
|
+
[:and,
|
60
|
+
{:objectClass => "*",
|
61
|
+
:uid => [:or, "bob", "alice"]}])
|
62
|
+
assert_parse_filter("(&(gidNumber=100001)" +
|
63
|
+
"(|(uid=temp-user1)(uid=temp-user2)))",
|
64
|
+
[:and,
|
65
|
+
[:and, {"gidNumber"=>["100001"]}],
|
66
|
+
[:or, {"uid"=>["temp-user1", "temp-user2"]}]])
|
67
|
+
end
|
68
|
+
|
69
|
+
def test_invalid_operator
|
70
|
+
assert_raises(ArgumentError) do
|
71
|
+
assert_parse_filter("(&(objectClass=*)(uid=bob))",
|
72
|
+
[:xxx, {:uid => "bob", :objectClass => "*"}])
|
73
|
+
end
|
74
|
+
end
|
75
|
+
|
76
|
+
private
|
77
|
+
def assert_parse_filter(expected, filter)
|
78
|
+
adapter = ActiveLdap::Adapter::Base.new
|
79
|
+
assert_equal(expected, adapter.send(:parse_filter, filter))
|
80
|
+
end
|
81
|
+
end
|