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.
Files changed (65) hide show
  1. data/CHANGES +5 -0
  2. data/Manifest.txt +91 -25
  3. data/README +22 -0
  4. data/Rakefile +41 -8
  5. data/TODO +1 -6
  6. data/examples/config.yaml.example +5 -0
  7. data/examples/example.der +0 -0
  8. data/examples/example.jpg +0 -0
  9. data/examples/groupadd +41 -0
  10. data/examples/groupdel +35 -0
  11. data/examples/groupls +49 -0
  12. data/examples/groupmod +42 -0
  13. data/examples/lpasswd +55 -0
  14. data/examples/objects/group.rb +13 -0
  15. data/examples/objects/ou.rb +4 -0
  16. data/examples/objects/user.rb +20 -0
  17. data/examples/ouadd +38 -0
  18. data/examples/useradd +45 -0
  19. data/examples/useradd-binary +50 -0
  20. data/examples/userdel +34 -0
  21. data/examples/userls +50 -0
  22. data/examples/usermod +42 -0
  23. data/examples/usermod-binary-add +47 -0
  24. data/examples/usermod-binary-add-time +51 -0
  25. data/examples/usermod-binary-del +48 -0
  26. data/examples/usermod-lang-add +43 -0
  27. data/lib/active_ldap.rb +213 -214
  28. data/lib/active_ldap/adapter/base.rb +461 -0
  29. data/lib/active_ldap/adapter/ldap.rb +232 -0
  30. data/lib/active_ldap/adapter/ldap_ext.rb +69 -0
  31. data/lib/active_ldap/adapter/net_ldap.rb +288 -0
  32. data/lib/active_ldap/adapter/net_ldap_ext.rb +29 -0
  33. data/lib/active_ldap/association/belongs_to.rb +3 -1
  34. data/lib/active_ldap/association/belongs_to_many.rb +5 -6
  35. data/lib/active_ldap/association/has_many.rb +9 -17
  36. data/lib/active_ldap/association/has_many_wrap.rb +4 -5
  37. data/lib/active_ldap/attributes.rb +4 -0
  38. data/lib/active_ldap/base.rb +201 -56
  39. data/lib/active_ldap/configuration.rb +11 -1
  40. data/lib/active_ldap/connection.rb +15 -9
  41. data/lib/active_ldap/distinguished_name.rb +246 -0
  42. data/lib/active_ldap/ldap_error.rb +74 -0
  43. data/lib/active_ldap/object_class.rb +9 -5
  44. data/lib/active_ldap/schema.rb +50 -9
  45. data/lib/active_ldap/validations.rb +11 -13
  46. data/rails/plugin/active_ldap/generators/scaffold_al/scaffold_al_generator.rb +7 -0
  47. data/rails/plugin/active_ldap/generators/scaffold_al/templates/ldap.yml +21 -0
  48. data/rails/plugin/active_ldap/init.rb +10 -4
  49. data/test/al-test-utils.rb +46 -3
  50. data/test/run-test.rb +16 -4
  51. data/test/test-unit-ext/always-show-result.rb +28 -0
  52. data/test/test-unit-ext/priority.rb +163 -0
  53. data/test/test_adapter.rb +81 -0
  54. data/test/test_attributes.rb +8 -1
  55. data/test/test_base.rb +132 -3
  56. data/test/test_base_per_instance.rb +14 -3
  57. data/test/test_connection.rb +19 -0
  58. data/test/test_dn.rb +161 -0
  59. data/test/test_find.rb +24 -0
  60. data/test/test_object_class.rb +15 -2
  61. data/test/test_schema.rb +108 -1
  62. metadata +111 -41
  63. data/lib/active_ldap/adaptor/base.rb +0 -29
  64. data/lib/active_ldap/adaptor/ldap.rb +0 -466
  65. data/lib/active_ldap/ldap.rb +0 -113
@@ -4,6 +4,14 @@ class TestAttributes < Test::Unit::TestCase
4
4
  include AlTestUtils
5
5
 
6
6
  priority :must
7
+ def test_to_real_attribute_name
8
+ user = @user_class.new("user")
9
+ assert_nil(user.__send__(:to_real_attribute_name, "objectclass"))
10
+ assert_equal("objectClass",
11
+ user.__send__(:to_real_attribute_name, "objectclass", true))
12
+ end
13
+
14
+ priority :normal
7
15
  def test_protect_object_class_from_mass_assignment
8
16
  classes = @user_class.required_classes + ["inetOrgPerson"]
9
17
  user = @user_class.new(:uid => "XXX", :object_class => classes)
@@ -20,7 +28,6 @@ class TestAttributes < Test::Unit::TestCase
20
28
  assert_equal([], user.classes - @user_class.required_classes)
21
29
  end
22
30
 
23
- priority :normal
24
31
  def test_normalize_attribute
25
32
  assert_equal(["usercertificate", [{"binary" => []}]],
26
33
  ActiveLdap::Base.normalize_attribute("userCertificate", []))
data/test/test_base.rb CHANGED
@@ -4,6 +4,117 @@ class TestBase < Test::Unit::TestCase
4
4
  include AlTestUtils
5
5
 
6
6
  priority :must
7
+ def test_case_insensitive_nested_ou
8
+ ou_class("ou=Users").new("Sub").save!
9
+ make_temporary_user(:uid => "test-user,ou=SUB") do |user, password|
10
+ sub_user_class = Class.new(@user_class)
11
+ sub_user_class.ldap_mapping :prefix => "ou=sub"
12
+ assert_equal("uid=test-user,ou=sub,#{@user_class.base}",
13
+ sub_user_class.find(user.uid).dn)
14
+ end
15
+ end
16
+
17
+ priority :normal
18
+ def test_nested_ou
19
+ make_ou("units")
20
+ units = ou_class("ou=units")
21
+ units.new("one").save!
22
+ units.new("two").save!
23
+ units.new("three").save!
24
+
25
+ ous = units.find(:all, :scope => :sub).collect {|unit| unit.ou}
26
+ assert_equal(["one", "two", "three", "units"].sort, ous.sort)
27
+
28
+ ous = units.find(:all, :scope => :base).collect {|unit| unit.ou}
29
+ assert_equal(["units"].sort, ous.sort)
30
+
31
+ ous = units.find(:all, :scope => :one).collect {|unit| unit.ou}
32
+ assert_equal(["one", "two", "three"].sort, ous.sort)
33
+ end
34
+
35
+ def test_initialize_with_recommended_classes
36
+ mapping = {
37
+ :dn_attribute => "cn",
38
+ :prefix => "",
39
+ :scope => :one,
40
+ :classes => ["person"],
41
+ }
42
+ person_class = Class.new(ActiveLdap::Base)
43
+ person_class.ldap_mapping mapping
44
+
45
+ person_with_uid_class = Class.new(ActiveLdap::Base)
46
+ person_with_uid_mapping =
47
+ mapping.merge(:recommended_classes => ["uidObject"])
48
+ person_with_uid_class.ldap_mapping person_with_uid_mapping
49
+
50
+ name = "sample"
51
+ name_with_uid = "sample-with-uid"
52
+ uid = "1000"
53
+
54
+ person = person_class.new(name)
55
+ person.sn = name
56
+ assert(person.save)
57
+ assert_equal([name, name], [person.cn, person.sn])
58
+
59
+ person_with_uid = person_with_uid_class.new(name_with_uid)
60
+ person_with_uid.sn = name_with_uid
61
+ assert(!person_with_uid.save)
62
+ person_with_uid.uid = uid
63
+ assert(person_with_uid.save)
64
+ assert_equal([name_with_uid, name_with_uid],
65
+ [person_with_uid.cn, person_with_uid.sn])
66
+ assert_equal(uid, person_with_uid.uid)
67
+
68
+ assert_equal([person.dn, person_with_uid.dn],
69
+ person_class.search.collect {|dn, attrs| dn})
70
+ person_class.required_classes += ["uidObject"]
71
+ assert_equal([person_with_uid.dn],
72
+ person_class.search.collect {|dn, attrs| dn})
73
+
74
+ assert_equal([person.dn, person_with_uid.dn],
75
+ person_with_uid_class.search.collect {|dn, attrs| dn})
76
+ end
77
+
78
+ def test_search_with_object_class
79
+ ou_class = Class.new(ActiveLdap::Base)
80
+ ou_class.ldap_mapping :dn_attribute => "ou",
81
+ :prefix => "",
82
+ :scope => :one,
83
+ :classes => ["organizationalUnit"]
84
+
85
+ name = "sample"
86
+ ou = ou_class.new(name)
87
+ assert(ou.save)
88
+ assert_equal(name, ou.ou)
89
+
90
+ assert_equal([ou.dn],
91
+ ou_class.search(:value => name).collect {|dn, attrs| dn})
92
+ ou_class.required_classes += ["organization"]
93
+ assert_equal([],
94
+ ou_class.search(:value => name).collect {|dn, attrs| dn})
95
+ end
96
+
97
+ def test_new_without_argument
98
+ user = @user_class.new
99
+ assert_equal(@user_class_classes, user.classes)
100
+ assert(user.respond_to?(:cn))
101
+ end
102
+
103
+ def test_new_with_invalid_argument
104
+ user = @user_class.new
105
+ assert_raises(ArgumentError) do
106
+ @user_class.new(100)
107
+ end
108
+ end
109
+
110
+ def test_loose_dn
111
+ make_temporary_user do |user,|
112
+ assert(user.class.exists?(user.dn))
113
+ assert(user.class.exists?(user.dn.gsub(/,/, " , ")))
114
+ assert(user.class.exists?(user.dn.gsub(/=/, " = ")))
115
+ end
116
+ end
117
+
7
118
  def test_new_without_class
8
119
  no_class_class = Class.new(ActiveLdap::Base)
9
120
  no_class_class.ldap_mapping :dn_attribute => "dc", :prefix => "",
@@ -13,7 +124,6 @@ class TestBase < Test::Unit::TestCase
13
124
  end
14
125
  end
15
126
 
16
- priority :normal
17
127
  def test_save_for_dNSDomain
18
128
  domain_class = Class.new(ActiveLdap::Base)
19
129
  domain_class.ldap_mapping :dn_attribute => "dc", :prefix => "",
@@ -144,13 +254,32 @@ class TestBase < Test::Unit::TestCase
144
254
 
145
255
  assert(@user_class.exists?(user.dn))
146
256
  @user_class.required_classes += ["posixAccount"]
147
- assert(@user_class.exists?(user.dn))
148
- assert_raises(ActiveLdap::RequiredObjectClassMissed) do
257
+ assert(!@user_class.exists?(user.dn))
258
+ assert_raises(ActiveLdap::EntryNotFound) do
149
259
  @user_class.find(user.dn)
150
260
  end
151
261
  end
152
262
  end
153
263
 
264
+ def test_find_dns_without_required_object_class
265
+ make_temporary_user do |user1,|
266
+ make_temporary_user do |user2,|
267
+ make_temporary_user do |user3,|
268
+ @user_class.required_classes -= ["posixAccount"]
269
+ user1.remove_class("posixAccount")
270
+ assert(user1.save)
271
+
272
+ @user_class.required_classes += ["posixAccount"]
273
+ assert_raises(ActiveLdap::EntryNotFound) do
274
+ @user_class.find(user1.dn, user2.dn, user3.dn)
275
+ end
276
+ assert_equal([user2.dn, user3.dn],
277
+ @user_class.find(user2.dn, user3.dn).collect {|u| u.dn})
278
+ end
279
+ end
280
+ end
281
+ end
282
+
154
283
  def test_reload
155
284
  make_temporary_user do |user1,|
156
285
  user2 = @user_class.find(user1.uid)
@@ -3,9 +3,22 @@ require 'al-test-utils'
3
3
  class TestBasePerInstance < Test::Unit::TestCase
4
4
  include AlTestUtils
5
5
 
6
+ def setup
7
+ super
8
+ ou_class("ou=Users").new("Sub").save!
9
+ end
10
+
6
11
  priority :must
12
+ def test_loose_dn
13
+ user = @user_class.new("test-user , ou = Sub")
14
+ assert_equal("uid=test-user,ou=Sub,#{@user_class.base}", user.dn)
15
+
16
+ user = @user_class.new("test-user , ou = Sub, #{@user_class.base}")
17
+ assert_equal("uid=test-user,ou=Sub,#{@user_class.base}", user.dn)
18
+ end
19
+
20
+ priority :normal
7
21
  def test_exists?
8
- ou_class("ou=Users").new("Sub").save
9
22
  make_temporary_user(:uid => "test-user,ou=Sub") do |user, password|
10
23
  assert(@user_class.exists?(user.uid))
11
24
  assert(@user_class.exists?("uid=#{user.uid}"))
@@ -16,9 +29,7 @@ class TestBasePerInstance < Test::Unit::TestCase
16
29
  end
17
30
  end
18
31
 
19
- priority :normal
20
32
  def test_add
21
- ou_class("ou=Users").new("Sub").save
22
33
  make_temporary_user(:uid => "test-user,ou=Sub") do |user, password|
23
34
  assert_equal("uid=test-user,ou=Sub,#{@user_class.base}", user.dn)
24
35
  assert_equal("test-user", user.uid)
@@ -2,6 +2,7 @@ require 'al-test-utils'
2
2
 
3
3
  class TestConnection < Test::Unit::TestCase
4
4
  include AlTestUtils::Config
5
+ include AlTestUtils::MockLogger
5
6
 
6
7
  def setup
7
8
  super
@@ -12,6 +13,24 @@ class TestConnection < Test::Unit::TestCase
12
13
  super
13
14
  end
14
15
 
16
+ priority :must
17
+ def test_bind_format_check
18
+ connector = Class.new(ActiveLdap::Base)
19
+ assert(!connector.connected?)
20
+ exception = nil
21
+ assert_raises(ArgumentError) do
22
+ begin
23
+ connector.establish_connection(:bind_format => "uid=%s,dc=test",
24
+ :allow_anonymous => false)
25
+ rescue Exception
26
+ exception = $!
27
+ raise
28
+ end
29
+ end
30
+ assert_equal("Unknown key(s): bind_format", exception.message)
31
+ end
32
+
33
+ priority :normal
15
34
  def test_can_reconnect?
16
35
  assert(!ActiveLdap::Base.connected?)
17
36
 
data/test/test_dn.rb ADDED
@@ -0,0 +1,161 @@
1
+ require 'al-test-utils'
2
+
3
+ class TestDN < Test::Unit::TestCase
4
+ include AlTestUtils
5
+
6
+ def setup
7
+ end
8
+
9
+ def teardown
10
+ end
11
+
12
+ priority :must
13
+ def test_case_insensitive_dn_minus
14
+ assert_dn_minus("dc=xxx", "dc=xxx,dc=LoCaL,dc=net", "dc=LOCAL,dc=net")
15
+ end
16
+
17
+ priority :normal
18
+ def test_dn_hash
19
+ dn1 = ActiveLdap::DN.parse("o=xxx,dc=local,dc=net")
20
+ dn2 = ActiveLdap::DN.parse("O = xxx , DC = local , DC = net")
21
+ assert_equal(dn1.hash, dn2.hash)
22
+
23
+ hash = {dn1 => :dn}
24
+ assert_equal(:dn, hash[dn2])
25
+ end
26
+
27
+ def test_dn_to_s
28
+ assert_dn_to_s("dc=xxx,dc=local,dc=net",
29
+ "dc = xxx, dc = \"local\",dc=net")
30
+ assert_dn_to_s("dc=l\\,o\\=c\\+a\\<l\\>,dc=\\#n\\;e\\\\t",
31
+ "dc = \"l,o=c+a<l>\" , dc=\"#n;e\\\\t\"")
32
+ assert_dn_to_s("dc=\" l\\\"o c\\\\a l \",dc=\" n e t \"",
33
+ "dc = \" l\\\"o c\\\\a l \" , dc= \\20n\\20e\\20t\\20")
34
+ end
35
+
36
+ def test_dn_minus
37
+ assert_dn_minus("dc=xxx", "dc=xxx,dc=local,dc=net", "dc=local,dc=net")
38
+ assert_dn_minus_raise("dc=xxx,dc=net", "dc=local,dc=net")
39
+ end
40
+
41
+ def test_parse_good_manner_dn
42
+ assert_dn([["dc", "local"], ["dc", "net"]], "dc=local,dc=net")
43
+ assert_dn([["dc", "net"]], "dc=net")
44
+ assert_dn([], "")
45
+ end
46
+
47
+ def test_parse_dn_with_space
48
+ assert_dn([["dc", "net"]], "dc =net")
49
+ assert_dn([["dc", "net"]], "dc = net")
50
+ assert_dn([["dc", "local"], ["dc", "net"]], "dc = local , dc = net")
51
+ assert_dn([["dc", "local"], ["dc", "net "]], "dc = local , dc = net ")
52
+ end
53
+
54
+ def test_parse_dn_with_hex_pairs
55
+ assert_dn([["dc", "local"], ["dc", "net"]],
56
+ "dc = #6C6f63616C , dc = net")
57
+ assert_dn([["dc", "lo cal "], ["dc", "net"]],
58
+ "dc = #6C6f2063616C20 ,dc=net")
59
+ end
60
+
61
+ def test_parse_dn_with_quoted_attribute_value
62
+ assert_dn([["dc", " l o c a l "], ["dc", "+n,\"e\";t"]],
63
+ "dc = \" l o c a l \" , dc = \"+n,\\\"e\\\";t\"")
64
+ end
65
+
66
+ def test_parse_dn_in_rfc2253
67
+ assert_dn([
68
+ {"cn" => "Steve Kille"},
69
+ {"o" => "Isode Limited"},
70
+ {"c" => "GB"}
71
+ ],
72
+ "CN=Steve Kille,O=Isode Limited,C=GB")
73
+ assert_dn([
74
+ {"ou" => "Sales", "cn" => "J. Smith"},
75
+ {"o" => "Widget Inc."},
76
+ {"c" => "US"},
77
+ ],
78
+ "OU=Sales+CN=J. Smith,O=Widget Inc.,C=US")
79
+ assert_dn([
80
+ {"cn" => "L. Eagle"},
81
+ {"o" => "Sue, Grabbit and Runn"},
82
+ {"c" => "GB"},
83
+ ],
84
+ "CN=L. Eagle,O=Sue\\, Grabbit and Runn,C=GB")
85
+ assert_dn([
86
+ {"cn" => "Before\rAfter"},
87
+ {"o" => "Test"},
88
+ {"c" => "GB"}
89
+ ],
90
+ "CN=Before\\0DAfter,O=Test,C=GB")
91
+ assert_dn([
92
+ {"1.3.6.1.4.1.1466.0" => [0x04, 0x02, 0x48, 0x69].pack("C*")},
93
+ {"o" => "Test"},
94
+ {"c" => "GB"}
95
+ ],
96
+ "1.3.6.1.4.1.1466.0=#04024869,O=Test,C=GB")
97
+ assert_dn([{"sn" => "Lučić"}], "SN=Lu\\C4\\8Di\\C4\\87")
98
+ end
99
+
100
+ def test_parse_invalid_dn
101
+ assert_invalid_dn("attribute value is missing", "net")
102
+ assert_invalid_dn("attribute value is missing", "local,dc=net")
103
+ assert_invalid_dn("attribute value is missing", "dc=,dc=net")
104
+ assert_invalid_dn("attribute type is missing", "=local,dc=net")
105
+ assert_invalid_dn("name component is missing", ",dc=net")
106
+ assert_invalid_dn("name component is missing", "dc=local,")
107
+ assert_invalid_dn("found unmatched quotation", "dc=\"local")
108
+ assert_invalid_dn("found unmatched quotation", "dc=\"loc\\al\"")
109
+ end
110
+
111
+ def test_parse_quoted_comma_dn
112
+ assert_dn([["dc", "local,"]], "dc=local\\,")
113
+ end
114
+
115
+ def test_parser_collect_pairs
116
+ assert_dn_parser_collect_pairs(",", "\\,")
117
+ end
118
+
119
+ priority :normal
120
+
121
+ private
122
+ def assert_dn(expected, dn)
123
+ assert_equal(ActiveLdap::DN.new(*expected), ActiveLdap::DN.parse(dn))
124
+ end
125
+
126
+ def assert_invalid_dn(reason, dn)
127
+ exception = nil
128
+ assert_raise(ActiveLdap::DistinguishedNameInvalid) do
129
+ begin
130
+ ActiveLdap::DN.parse(dn)
131
+ rescue Exception
132
+ exception = $!
133
+ raise
134
+ end
135
+ end
136
+ assert_not_nil(exception)
137
+ assert_equal(dn, exception.dn)
138
+ assert_equal(reason, exception.reason)
139
+ end
140
+
141
+ def assert_dn_parser_collect_pairs(expected, source)
142
+ parser = ActiveLdap::DN::Parser.new(source)
143
+ assert_equal(expected,
144
+ parser.send(:collect_pairs, StringScanner.new(source)))
145
+ end
146
+
147
+ def assert_dn_minus(expected, subtrahend, minuend)
148
+ result = ActiveLdap::DN.parse(subtrahend) - ActiveLdap::DN.parse(minuend)
149
+ assert_equal(ActiveLdap::DN.parse(expected), result)
150
+ end
151
+
152
+ def assert_dn_minus_raise(subtrahend, minuend)
153
+ assert_raise(ArgumentError) do
154
+ ActiveLdap::DN.parse(subtrahend) - ActiveLdap::DN.parse(minuend)
155
+ end
156
+ end
157
+
158
+ def assert_dn_to_s(expected, dn)
159
+ assert_equal(expected, ActiveLdap::DN.parse(dn).to_s)
160
+ end
161
+ end
data/test/test_find.rb CHANGED
@@ -3,6 +3,29 @@ require 'al-test-utils'
3
3
  class TestFind < Test::Unit::TestCase
4
4
  include AlTestUtils
5
5
 
6
+ priority :must
7
+ def test_find_with_sort
8
+ make_temporary_user(:uid => "user1") do |user1,|
9
+ make_temporary_user(:uid => "user2") do |user2,|
10
+ users = @user_class.find(:all, :sort_by => "uid", :order => 'asc')
11
+ assert_equal(["user1", "user2"], users.collect {|u| u.uid})
12
+ users = @user_class.find(:all, :sort_by => "uid", :order => 'desc')
13
+ assert_equal(["user2", "user1"], users.collect {|u| u.uid})
14
+
15
+ users = @user_class.find(:all, :order => 'asc')
16
+ assert_equal(["user1", "user2"], users.collect {|u| u.uid})
17
+ users = @user_class.find(:all, :order => 'desc')
18
+ assert_equal(["user2", "user1"], users.collect {|u| u.uid})
19
+
20
+ users = @user_class.find(:all, :order => 'asc', :limit => 1)
21
+ assert_equal(["user1"], users.collect {|u| u.uid})
22
+ users = @user_class.find(:all, :order => 'desc', :limit => 1)
23
+ assert_equal(["user2"], users.collect {|u| u.uid})
24
+ end
25
+ end
26
+ end
27
+
28
+ priority :normal
6
29
  def test_split_search_value
7
30
  assert_split_search_value([nil, "test-user", nil], "test-user")
8
31
  assert_split_search_value([nil, "test-user", "ou=Sub"], "test-user,ou=Sub")
@@ -17,6 +40,7 @@ class TestFind < Test::Unit::TestCase
17
40
  assert_equal(user.uid, @user_class.find(user.uid).uid)
18
41
  options = {:attribute => "cn", :value => user.cn}
19
42
  assert_equal(user.uid, @user_class.find(:first, options).uid)
43
+ assert_equal(user.uid, @user_class.find(options).uid)
20
44
  assert_equal(user.to_ldif, @user_class.find(:first).to_ldif)
21
45
  assert_equal([user.uid], @user_class.find(:all).collect {|u| u.uid})
22
46