ruby-activeldap 0.8.1 → 0.8.2

Sign up to get free protection for your applications and to get access to all the features.
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