rubinius-net-ldap 0.11

Sign up to get free protection for your applications and to get access to all the features.
Files changed (73) hide show
  1. checksums.yaml +7 -0
  2. data/.gitignore +10 -0
  3. data/.rubocop.yml +5 -0
  4. data/.rubocop_todo.yml +462 -0
  5. data/.travis.yml +19 -0
  6. data/CONTRIBUTING.md +54 -0
  7. data/Contributors.rdoc +24 -0
  8. data/Gemfile +2 -0
  9. data/Hacking.rdoc +63 -0
  10. data/History.rdoc +260 -0
  11. data/License.rdoc +29 -0
  12. data/README.rdoc +65 -0
  13. data/Rakefile +17 -0
  14. data/lib/net-ldap.rb +2 -0
  15. data/lib/net/ber.rb +320 -0
  16. data/lib/net/ber/ber_parser.rb +182 -0
  17. data/lib/net/ber/core_ext.rb +55 -0
  18. data/lib/net/ber/core_ext/array.rb +96 -0
  19. data/lib/net/ber/core_ext/false_class.rb +10 -0
  20. data/lib/net/ber/core_ext/integer.rb +74 -0
  21. data/lib/net/ber/core_ext/string.rb +66 -0
  22. data/lib/net/ber/core_ext/true_class.rb +11 -0
  23. data/lib/net/ldap.rb +1229 -0
  24. data/lib/net/ldap/connection.rb +702 -0
  25. data/lib/net/ldap/dataset.rb +168 -0
  26. data/lib/net/ldap/dn.rb +225 -0
  27. data/lib/net/ldap/entry.rb +193 -0
  28. data/lib/net/ldap/error.rb +38 -0
  29. data/lib/net/ldap/filter.rb +778 -0
  30. data/lib/net/ldap/instrumentation.rb +23 -0
  31. data/lib/net/ldap/password.rb +38 -0
  32. data/lib/net/ldap/pdu.rb +297 -0
  33. data/lib/net/ldap/version.rb +5 -0
  34. data/lib/net/snmp.rb +264 -0
  35. data/rubinius-net-ldap.gemspec +37 -0
  36. data/script/install-openldap +112 -0
  37. data/script/package +7 -0
  38. data/script/release +16 -0
  39. data/test/ber/core_ext/test_array.rb +22 -0
  40. data/test/ber/core_ext/test_string.rb +25 -0
  41. data/test/ber/test_ber.rb +99 -0
  42. data/test/fixtures/cacert.pem +20 -0
  43. data/test/fixtures/openldap/memberof.ldif +33 -0
  44. data/test/fixtures/openldap/retcode.ldif +76 -0
  45. data/test/fixtures/openldap/slapd.conf.ldif +67 -0
  46. data/test/fixtures/seed.ldif +374 -0
  47. data/test/integration/test_add.rb +28 -0
  48. data/test/integration/test_ber.rb +30 -0
  49. data/test/integration/test_bind.rb +34 -0
  50. data/test/integration/test_delete.rb +31 -0
  51. data/test/integration/test_open.rb +88 -0
  52. data/test/integration/test_return_codes.rb +38 -0
  53. data/test/integration/test_search.rb +77 -0
  54. data/test/support/vm/openldap/.gitignore +1 -0
  55. data/test/support/vm/openldap/README.md +32 -0
  56. data/test/support/vm/openldap/Vagrantfile +33 -0
  57. data/test/test_dn.rb +44 -0
  58. data/test/test_entry.rb +65 -0
  59. data/test/test_filter.rb +223 -0
  60. data/test/test_filter_parser.rb +20 -0
  61. data/test/test_helper.rb +66 -0
  62. data/test/test_ldap.rb +60 -0
  63. data/test/test_ldap_connection.rb +404 -0
  64. data/test/test_ldif.rb +104 -0
  65. data/test/test_password.rb +10 -0
  66. data/test/test_rename.rb +77 -0
  67. data/test/test_search.rb +39 -0
  68. data/test/test_snmp.rb +119 -0
  69. data/test/test_ssl_ber.rb +40 -0
  70. data/test/testdata.ldif +101 -0
  71. data/testserver/ldapserver.rb +210 -0
  72. data/testserver/testdata.ldif +101 -0
  73. metadata +204 -0
@@ -0,0 +1,223 @@
1
+ require File.expand_path('../test_helper', __FILE__)
2
+
3
+ class TestFilter < Test::Unit::TestCase
4
+ Filter = Net::LDAP::Filter
5
+
6
+ def test_bug_7534_rfc2254
7
+ assert_equal("(cn=Tim Wizard)",
8
+ Filter.from_rfc2254("(cn=Tim Wizard)").to_rfc2254)
9
+ end
10
+
11
+ def test_invalid_filter_string
12
+ assert_raises(Net::LDAP::FilterSyntaxInvalidError) { Filter.from_rfc2254("") }
13
+ end
14
+
15
+ def test_invalid_filter
16
+ assert_raises(Net::LDAP::OperatorError) {
17
+ # This test exists to prove that our constructor blocks unknown filter
18
+ # types. All filters must be constructed using helpers.
19
+ Filter.__send__(:new, :xx, nil, nil)
20
+ }
21
+ end
22
+
23
+ def test_to_s
24
+ assert_equal("(uid=george *)", Filter.eq("uid", "george *").to_s)
25
+ end
26
+
27
+ def test_convenience_filters
28
+ assert_equal("(uid=\\2A)", Filter.equals("uid", "*").to_s)
29
+ assert_equal("(uid=\\28*)", Filter.begins("uid", "(").to_s)
30
+ assert_equal("(uid=*\\29)", Filter.ends("uid", ")").to_s)
31
+ assert_equal("(uid=*\\5C*)", Filter.contains("uid", "\\").to_s)
32
+ end
33
+
34
+ def test_c2
35
+ assert_equal("(uid=george *)",
36
+ Filter.from_rfc2254("uid=george *").to_rfc2254)
37
+ assert_equal("(uid:=george *)",
38
+ Filter.from_rfc2254("uid:=george *").to_rfc2254)
39
+ assert_equal("(uid=george*)",
40
+ Filter.from_rfc2254(" ( uid = george* ) ").to_rfc2254)
41
+ assert_equal("(!(uid=george*))",
42
+ Filter.from_rfc2254("uid!=george*").to_rfc2254)
43
+ assert_equal("(uid<=george*)",
44
+ Filter.from_rfc2254("uid <= george*").to_rfc2254)
45
+ assert_equal("(uid>=george*)",
46
+ Filter.from_rfc2254("uid>=george*").to_rfc2254)
47
+ assert_equal("(&(uid=george*)(mail=*))",
48
+ Filter.from_rfc2254("(& (uid=george* ) (mail=*))").to_rfc2254)
49
+ assert_equal("(|(uid=george*)(mail=*))",
50
+ Filter.from_rfc2254("(| (uid=george* ) (mail=*))").to_rfc2254)
51
+ assert_equal("(!(mail=*))",
52
+ Filter.from_rfc2254("(! (mail=*))").to_rfc2254)
53
+ end
54
+
55
+ def test_filter_with_single_clause
56
+ assert_equal("(cn=name)", Net::LDAP::Filter.construct("(&(cn=name))").to_s)
57
+ end
58
+
59
+ def test_filters_from_ber
60
+ [
61
+ Net::LDAP::Filter.eq("objectclass", "*"),
62
+ Net::LDAP::Filter.pres("objectclass"),
63
+ Net::LDAP::Filter.eq("objectclass", "ou"),
64
+ Net::LDAP::Filter.ge("uid", "500"),
65
+ Net::LDAP::Filter.le("uid", "500"),
66
+ (~ Net::LDAP::Filter.pres("objectclass")),
67
+ (Net::LDAP::Filter.pres("objectclass") & Net::LDAP::Filter.pres("ou")),
68
+ (Net::LDAP::Filter.pres("objectclass") & Net::LDAP::Filter.pres("ou") & Net::LDAP::Filter.pres("sn")),
69
+ (Net::LDAP::Filter.pres("objectclass") | Net::LDAP::Filter.pres("ou") | Net::LDAP::Filter.pres("sn")),
70
+
71
+ Net::LDAP::Filter.eq("objectclass", "*aaa"),
72
+ Net::LDAP::Filter.eq("objectclass", "*aaa*bbb"),
73
+ Net::LDAP::Filter.eq("objectclass", "*aaa*bbb*ccc"),
74
+ Net::LDAP::Filter.eq("objectclass", "aaa*bbb"),
75
+ Net::LDAP::Filter.eq("objectclass", "aaa*bbb*ccc"),
76
+ Net::LDAP::Filter.eq("objectclass", "abc*def*1111*22*g"),
77
+ Net::LDAP::Filter.eq("objectclass", "*aaa*"),
78
+ Net::LDAP::Filter.eq("objectclass", "*aaa*bbb*"),
79
+ Net::LDAP::Filter.eq("objectclass", "*aaa*bbb*ccc*"),
80
+ Net::LDAP::Filter.eq("objectclass", "aaa*"),
81
+ Net::LDAP::Filter.eq("objectclass", "aaa*bbb*"),
82
+ Net::LDAP::Filter.eq("objectclass", "aaa*bbb*ccc*"),
83
+ ].each do |ber|
84
+ f = Net::LDAP::Filter.parse_ber(ber.to_ber.read_ber(Net::LDAP::AsnSyntax))
85
+ assert(f == ber)
86
+ assert_equal(f.to_ber, ber.to_ber)
87
+ end
88
+ end
89
+
90
+ def test_ber_from_rfc2254_filter
91
+ [
92
+ Net::LDAP::Filter.construct("objectclass=*"),
93
+ Net::LDAP::Filter.construct("objectclass=ou"),
94
+ Net::LDAP::Filter.construct("uid >= 500"),
95
+ Net::LDAP::Filter.construct("uid <= 500"),
96
+ Net::LDAP::Filter.construct("(!(uid=*))"),
97
+ Net::LDAP::Filter.construct("(&(uid=*)(objectclass=*))"),
98
+ Net::LDAP::Filter.construct("(&(uid=*)(objectclass=*)(sn=*))"),
99
+ Net::LDAP::Filter.construct("(|(uid=*)(objectclass=*))"),
100
+ Net::LDAP::Filter.construct("(|(uid=*)(objectclass=*)(sn=*))"),
101
+
102
+ Net::LDAP::Filter.construct("objectclass=*aaa"),
103
+ Net::LDAP::Filter.construct("objectclass=*aaa*bbb"),
104
+ Net::LDAP::Filter.construct("objectclass=*aaa bbb"),
105
+ Net::LDAP::Filter.construct("objectclass=*aaa bbb"),
106
+ Net::LDAP::Filter.construct("objectclass=*aaa*bbb*ccc"),
107
+ Net::LDAP::Filter.construct("objectclass=aaa*bbb"),
108
+ Net::LDAP::Filter.construct("objectclass=aaa*bbb*ccc"),
109
+ Net::LDAP::Filter.construct("objectclass=abc*def*1111*22*g"),
110
+ Net::LDAP::Filter.construct("objectclass=*aaa*"),
111
+ Net::LDAP::Filter.construct("objectclass=*aaa*bbb*"),
112
+ Net::LDAP::Filter.construct("objectclass=*aaa*bbb*ccc*"),
113
+ Net::LDAP::Filter.construct("objectclass=aaa*"),
114
+ Net::LDAP::Filter.construct("objectclass=aaa*bbb*"),
115
+ Net::LDAP::Filter.construct("objectclass=aaa*bbb*ccc*"),
116
+ ].each do |ber|
117
+ f = Net::LDAP::Filter.parse_ber(ber.to_ber.read_ber(Net::LDAP::AsnSyntax))
118
+ assert(f == ber)
119
+ assert_equal(f.to_ber, ber.to_ber)
120
+ end
121
+ end
122
+ end
123
+
124
+ # tests ported over from rspec. Not sure if these overlap with the above
125
+ # https://github.com/ruby-ldap/ruby-net-ldap/pull/121
126
+ class TestFilterRSpec < Test::Unit::TestCase
127
+ def test_ex_convert
128
+ assert_equal '(foo:=bar)', Net::LDAP::Filter.ex('foo', 'bar').to_s
129
+ end
130
+
131
+ def test_ex_rfc2254_roundtrip
132
+ filter = Net::LDAP::Filter.ex('foo', 'bar')
133
+ assert_equal filter, Net::LDAP::Filter.from_rfc2254(filter.to_s)
134
+ end
135
+
136
+ def test_ber_conversion
137
+ filter = Net::LDAP::Filter.ex('foo', 'bar')
138
+ ber = filter.to_ber
139
+ assert_equal filter, Net::LDAP::Filter.parse_ber(ber.read_ber(Net::LDAP::AsnSyntax))
140
+ end
141
+
142
+ [
143
+ '(o:dn:=Ace Industry)',
144
+ '(:dn:2.4.8.10:=Dino)',
145
+ '(cn:dn:1.2.3.4.5:=John Smith)',
146
+ '(sn:dn:2.4.6.8.10:=Barbara Jones)',
147
+ '(&(sn:dn:2.4.6.8.10:=Barbara Jones))'
148
+ ].each_with_index do |filter_str, index|
149
+ define_method "test_decode_filter_#{index}" do
150
+ filter = Net::LDAP::Filter.from_rfc2254(filter_str)
151
+ assert_kind_of Net::LDAP::Filter, filter
152
+ end
153
+
154
+ define_method "test_ber_conversion_#{index}" do
155
+ filter = Net::LDAP::Filter.from_rfc2254(filter_str)
156
+ ber = Net::LDAP::Filter.from_rfc2254(filter_str).to_ber
157
+ assert_equal filter, Net::LDAP::Filter.parse_ber(ber.read_ber(Net::LDAP::AsnSyntax))
158
+ end
159
+ end
160
+
161
+ def test_apostrophes
162
+ assert_equal "(uid=O'Keefe)", Net::LDAP::Filter.construct("uid=O'Keefe").to_rfc2254
163
+ end
164
+
165
+ def test_equals
166
+ assert_equal Net::LDAP::Filter.eq('dn', 'f\2Aoo'), Net::LDAP::Filter.equals('dn', 'f*oo')
167
+ end
168
+
169
+ def test_begins
170
+ assert_equal Net::LDAP::Filter.eq('dn', 'f\2Aoo*'), Net::LDAP::Filter.begins('dn', 'f*oo')
171
+ end
172
+
173
+ def test_ends
174
+ assert_equal Net::LDAP::Filter.eq('dn', '*f\2Aoo'), Net::LDAP::Filter.ends('dn', 'f*oo')
175
+ end
176
+
177
+ def test_contains
178
+ assert_equal Net::LDAP::Filter.eq('dn', '*f\2Aoo*'), Net::LDAP::Filter.contains('dn', 'f*oo')
179
+ end
180
+
181
+ def test_escape
182
+ # escapes nul, *, (, ) and \\
183
+ assert_equal "\\00\\2A\\28\\29\\5C", Net::LDAP::Filter.escape("\0*()\\")
184
+ end
185
+
186
+ def test_well_known_ber_string
187
+ ber = "\xa4\x2d" \
188
+ "\x04\x0b" "objectclass" \
189
+ "\x30\x1e" \
190
+ "\x80\x08" "foo" "*\\" "bar" \
191
+ "\x81\x08" "foo" "*\\" "bar" \
192
+ "\x82\x08" "foo" "*\\" "bar".b
193
+
194
+ [
195
+ "foo" "\\2A\\5C" "bar",
196
+ "foo" "\\2a\\5c" "bar",
197
+ "foo" "\\2A\\5c" "bar",
198
+ "foo" "\\2a\\5C" "bar"
199
+ ].each do |escaped|
200
+ # unescapes escaped characters
201
+ filter = Net::LDAP::Filter.eq("objectclass", "#{escaped}*#{escaped}*#{escaped}")
202
+ assert_equal ber, filter.to_ber
203
+ end
204
+ end
205
+
206
+ def test_parse_ber_escapes_characters
207
+ ber = "\xa4\x2d" \
208
+ "\x04\x0b" "objectclass" \
209
+ "\x30\x1e" \
210
+ "\x80\x08" "foo" "*\\" "bar" \
211
+ "\x81\x08" "foo" "*\\" "bar" \
212
+ "\x82\x08" "foo" "*\\" "bar".b
213
+
214
+ escaped = Net::LDAP::Filter.escape("foo" "*\\" "bar")
215
+ filter = Net::LDAP::Filter.parse_ber(ber.read_ber(Net::LDAP::AsnSyntax))
216
+ assert_equal "(objectclass=#{escaped}*#{escaped}*#{escaped})", filter.to_s
217
+ end
218
+
219
+ def test_unescape_fixnums
220
+ filter = Net::LDAP::Filter.eq("objectclass", 3)
221
+ assert_equal "\xA3\x10\x04\vobjectclass\x04\x013".b, filter.to_ber
222
+ end
223
+ end
@@ -0,0 +1,20 @@
1
+ # encoding: utf-8
2
+ require File.expand_path('../test_helper', __FILE__)
3
+
4
+ class TestFilterParser < Test::Unit::TestCase
5
+ def test_ascii
6
+ assert_kind_of Net::LDAP::Filter, Net::LDAP::Filter::FilterParser.parse("(cn=name)")
7
+ end
8
+
9
+ def test_multibyte_characters
10
+ assert_kind_of Net::LDAP::Filter, Net::LDAP::Filter::FilterParser.parse("(cn=名前)")
11
+ end
12
+
13
+ def test_brackets
14
+ assert_kind_of Net::LDAP::Filter, Net::LDAP::Filter::FilterParser.parse("(cn=[{something}])")
15
+ end
16
+
17
+ def test_colons
18
+ assert_kind_of Net::LDAP::Filter, Net::LDAP::Filter::FilterParser.parse("(ismemberof=cn=edu:berkeley:app:calmessages:deans,ou=campus groups,dc=berkeley,dc=edu)")
19
+ end
20
+ end
@@ -0,0 +1,66 @@
1
+ # Add 'lib' to load path.
2
+ require 'test/unit'
3
+ require 'net/ldap'
4
+ require 'flexmock/test_unit'
5
+
6
+ # Whether integration tests should be run.
7
+ INTEGRATION = ENV.fetch("INTEGRATION", "skip") != "skip"
8
+
9
+ # The CA file to verify certs against for tests.
10
+ # Override with CA_FILE env variable; otherwise checks for the VM-specific path
11
+ # and falls back to the test/fixtures/cacert.pem for local testing.
12
+ CA_FILE =
13
+ ENV.fetch("CA_FILE") do
14
+ if File.exist?("/etc/ssl/certs/cacert.pem")
15
+ "/etc/ssl/certs/cacert.pem"
16
+ else
17
+ File.expand_path("fixtures/cacert.pem", File.dirname(__FILE__))
18
+ end
19
+ end
20
+
21
+ if RUBY_VERSION < "2.0"
22
+ class String
23
+ def b
24
+ self
25
+ end
26
+ end
27
+ end
28
+
29
+ class MockInstrumentationService
30
+ def initialize
31
+ @events = {}
32
+ end
33
+
34
+ def instrument(event, payload)
35
+ result = yield(payload)
36
+ @events[event] ||= []
37
+ @events[event] << [payload, result]
38
+ result
39
+ end
40
+
41
+ def subscribe(event)
42
+ @events[event] ||= []
43
+ @events[event]
44
+ end
45
+ end
46
+
47
+ class LDAPIntegrationTestCase < Test::Unit::TestCase
48
+ # If integration tests aren't enabled, noop these tests.
49
+ if !INTEGRATION
50
+ def run(*)
51
+ self
52
+ end
53
+ end
54
+
55
+ def setup
56
+ @service = MockInstrumentationService.new
57
+ @ldap = Net::LDAP.new \
58
+ :host => ENV.fetch('INTEGRATION_HOST', 'localhost'),
59
+ :port => 389,
60
+ :admin_user => 'uid=admin,dc=rubyldap,dc=com',
61
+ :admin_password => 'passworD1',
62
+ :search_domains => %w(dc=rubyldap,dc=com),
63
+ :uid => 'uid',
64
+ :instrumentation_service => @service
65
+ end
66
+ end
data/test/test_ldap.rb ADDED
@@ -0,0 +1,60 @@
1
+ require 'test_helper'
2
+
3
+ class TestLDAPInstrumentation < Test::Unit::TestCase
4
+ def setup
5
+ @connection = flexmock(:connection, :close => true)
6
+ flexmock(Net::LDAP::Connection).should_receive(:new).and_return(@connection)
7
+
8
+ @service = MockInstrumentationService.new
9
+ @subject = Net::LDAP.new \
10
+ :host => "test.mocked.com", :port => 636,
11
+ :force_no_page => true, # so server capabilities are not queried
12
+ :instrumentation_service => @service
13
+ end
14
+
15
+ def test_instrument_bind
16
+ events = @service.subscribe "bind.net_ldap"
17
+
18
+ bind_result = flexmock(:bind_result, :success? => true)
19
+ flexmock(@connection).should_receive(:bind).with(Hash).and_return(bind_result)
20
+
21
+ assert @subject.bind
22
+
23
+ payload, result = events.pop
24
+ assert result
25
+ assert_equal bind_result, payload[:bind]
26
+ end
27
+
28
+ def test_instrument_search
29
+ events = @service.subscribe "search.net_ldap"
30
+
31
+ flexmock(@connection).should_receive(:bind).and_return(flexmock(:bind_result, :result_code => Net::LDAP::ResultCodeSuccess))
32
+ flexmock(@connection).should_receive(:search).with(Hash, Proc).
33
+ yields(entry = Net::LDAP::Entry.new("uid=user1,ou=users,dc=example,dc=com")).
34
+ and_return(flexmock(:search_result, :success? => true, :result_code => Net::LDAP::ResultCodeSuccess))
35
+
36
+ assert_not_nil @subject.search(:filter => "(uid=user1)")
37
+
38
+ payload, result = events.pop
39
+ assert_equal [entry], result
40
+ assert_equal [entry], payload[:result]
41
+ assert_equal "(uid=user1)", payload[:filter]
42
+ end
43
+
44
+ def test_instrument_search_with_size
45
+ events = @service.subscribe "search.net_ldap"
46
+
47
+ flexmock(@connection).should_receive(:bind).and_return(flexmock(:bind_result, :result_code => Net::LDAP::ResultCodeSuccess))
48
+ flexmock(@connection).should_receive(:search).with(Hash, Proc).
49
+ yields(entry = Net::LDAP::Entry.new("uid=user1,ou=users,dc=example,dc=com")).
50
+ and_return(flexmock(:search_result, :success? => true, :result_code => Net::LDAP::ResultCodeSizeLimitExceeded))
51
+
52
+ assert_not_nil @subject.search(:filter => "(uid=user1)", :size => 1)
53
+
54
+ payload, result = events.pop
55
+ assert_equal [entry], result
56
+ assert_equal [entry], payload[:result]
57
+ assert_equal "(uid=user1)", payload[:filter]
58
+ assert_equal result.size, payload[:size]
59
+ end
60
+ end
@@ -0,0 +1,404 @@
1
+ require File.expand_path('../test_helper', __FILE__)
2
+
3
+ class TestLDAPConnection < Test::Unit::TestCase
4
+ def test_unresponsive_host
5
+ assert_raise Net::LDAP::Error do
6
+ Net::LDAP::Connection.new(:host => 'test.mocked.com', :port => 636)
7
+ end
8
+ end
9
+
10
+ def test_blocked_port
11
+ flexmock(TCPSocket).should_receive(:new).and_raise(SocketError)
12
+ assert_raise Net::LDAP::Error do
13
+ Net::LDAP::Connection.new(:host => 'test.mocked.com', :port => 636)
14
+ end
15
+ end
16
+
17
+ def test_raises_unknown_exceptions
18
+ error = Class.new(StandardError)
19
+ flexmock(TCPSocket).should_receive(:new).and_raise(error)
20
+ assert_raise error do
21
+ Net::LDAP::Connection.new(:host => 'test.mocked.com', :port => 636)
22
+ end
23
+ end
24
+
25
+ def test_modify_ops_delete
26
+ args = { :operations => [ [ :delete, "mail" ] ] }
27
+ result = Net::LDAP::Connection.modify_ops(args[:operations])
28
+ expected = [ "0\r\n\x01\x010\b\x04\x04mail1\x00" ]
29
+ assert_equal(expected, result)
30
+ end
31
+
32
+ def test_modify_ops_add
33
+ args = { :operations => [ [ :add, "mail", "testuser@example.com" ] ] }
34
+ result = Net::LDAP::Connection.modify_ops(args[:operations])
35
+ expected = [ "0#\n\x01\x000\x1E\x04\x04mail1\x16\x04\x14testuser@example.com" ]
36
+ assert_equal(expected, result)
37
+ end
38
+
39
+ def test_modify_ops_replace
40
+ args = { :operations =>[ [ :replace, "mail", "testuser@example.com" ] ] }
41
+ result = Net::LDAP::Connection.modify_ops(args[:operations])
42
+ expected = [ "0#\n\x01\x020\x1E\x04\x04mail1\x16\x04\x14testuser@example.com" ]
43
+ assert_equal(expected, result)
44
+ end
45
+
46
+ def test_write
47
+ mock = flexmock("socket")
48
+ mock.should_receive(:write).with([1.to_ber, "request"].to_ber_sequence).and_return(true)
49
+ conn = Net::LDAP::Connection.new(:socket => mock)
50
+ conn.send(:write, "request")
51
+ end
52
+
53
+ def test_write_with_controls
54
+ mock = flexmock("socket")
55
+ mock.should_receive(:write).with([1.to_ber, "request", "controls"].to_ber_sequence).and_return(true)
56
+ conn = Net::LDAP::Connection.new(:socket => mock)
57
+ conn.send(:write, "request", "controls")
58
+ end
59
+
60
+ def test_write_increments_msgid
61
+ mock = flexmock("socket")
62
+ mock.should_receive(:write).with([1.to_ber, "request1"].to_ber_sequence).and_return(true)
63
+ mock.should_receive(:write).with([2.to_ber, "request2"].to_ber_sequence).and_return(true)
64
+ conn = Net::LDAP::Connection.new(:socket => mock)
65
+ conn.send(:write, "request1")
66
+ conn.send(:write, "request2")
67
+ end
68
+ end
69
+
70
+ class TestLDAPConnectionSocketReads < Test::Unit::TestCase
71
+ def make_message(message_id, options = {})
72
+ options = {
73
+ :app_tag => Net::LDAP::PDU::SearchResult,
74
+ :code => Net::LDAP::ResultCodeSuccess,
75
+ :matched_dn => "",
76
+ :error_message => ""
77
+ }.merge(options)
78
+ result = Net::BER::BerIdentifiedArray.new([options[:code], options[:matched_dn], options[:error_message]])
79
+ result.ber_identifier = options[:app_tag]
80
+ [message_id, result]
81
+ end
82
+
83
+ def test_queued_read_drains_queue_before_read
84
+ result1a = make_message(1, :error_message => "one")
85
+ result1b = make_message(1, :error_message => "two")
86
+
87
+ mock = flexmock("socket")
88
+ mock.should_receive(:read_ber).and_return(result1b)
89
+ conn = Net::LDAP::Connection.new(:socket => mock)
90
+
91
+ conn.message_queue[1].push Net::LDAP::PDU.new(result1a)
92
+
93
+ assert msg1 = conn.queued_read(1)
94
+ assert msg2 = conn.queued_read(1)
95
+
96
+ assert_equal 1, msg1.message_id
97
+ assert_equal "one", msg1.error_message
98
+ assert_equal 1, msg2.message_id
99
+ assert_equal "two", msg2.error_message
100
+ end
101
+
102
+ def test_queued_read_reads_until_message_id_match
103
+ result1 = make_message(1)
104
+ result2 = make_message(2)
105
+
106
+ mock = flexmock("socket")
107
+ mock.should_receive(:read_ber).
108
+ and_return(result1).
109
+ and_return(result2)
110
+ conn = Net::LDAP::Connection.new(:socket => mock)
111
+
112
+ assert result = conn.queued_read(2)
113
+ assert_equal 2, result.message_id
114
+ assert_equal 1, conn.queued_read(1).message_id
115
+ end
116
+
117
+ def test_queued_read_modify
118
+ result1 = make_message(1, :app_tag => Net::LDAP::PDU::SearchResult)
119
+ result2 = make_message(2, :app_tag => Net::LDAP::PDU::ModifyResponse)
120
+
121
+ mock = flexmock("socket")
122
+ mock.should_receive(:read_ber).
123
+ and_return(result1).
124
+ and_return(result2)
125
+ mock.should_receive(:write)
126
+ conn = Net::LDAP::Connection.new(:socket => mock)
127
+
128
+ conn.next_msgid # simulates ongoing query
129
+
130
+ conn.instance_variable_get("@msgid")
131
+
132
+ assert result = conn.modify(:dn => "uid=modified-user1,ou=People,dc=rubyldap,dc=com",
133
+ :operations => [[:add, :mail, "modified-user1@example.com"]])
134
+ assert result.success?
135
+ assert_equal 2, result.message_id
136
+ end
137
+
138
+ def test_queued_read_add
139
+ result1 = make_message(1, :app_tag => Net::LDAP::PDU::SearchResult)
140
+ result2 = make_message(2, :app_tag => Net::LDAP::PDU::AddResponse)
141
+
142
+ mock = flexmock("socket")
143
+ mock.should_receive(:read_ber).
144
+ and_return(result1).
145
+ and_return(result2)
146
+ mock.should_receive(:write)
147
+ conn = Net::LDAP::Connection.new(:socket => mock)
148
+
149
+ conn.next_msgid # simulates ongoing query
150
+
151
+ assert result = conn.add(:dn => "uid=added-user1,ou=People,dc=rubyldap,dc=com")
152
+ assert result.success?
153
+ assert_equal 2, result.message_id
154
+ end
155
+
156
+ def test_queued_read_rename
157
+ result1 = make_message(1, :app_tag => Net::LDAP::PDU::SearchResult)
158
+ result2 = make_message(2, :app_tag => Net::LDAP::PDU::ModifyRDNResponse)
159
+
160
+ mock = flexmock("socket")
161
+ mock.should_receive(:read_ber).
162
+ and_return(result1).
163
+ and_return(result2)
164
+ mock.should_receive(:write)
165
+ conn = Net::LDAP::Connection.new(:socket => mock)
166
+
167
+ conn.next_msgid # simulates ongoing query
168
+
169
+ assert result = conn.rename(
170
+ :olddn => "uid=renamable-user1,ou=People,dc=rubyldap,dc=com",
171
+ :newrdn => "uid=renamed-user1"
172
+ )
173
+ assert result.success?
174
+ assert_equal 2, result.message_id
175
+ end
176
+
177
+ def test_queued_read_delete
178
+ result1 = make_message(1, :app_tag => Net::LDAP::PDU::SearchResult)
179
+ result2 = make_message(2, :app_tag => Net::LDAP::PDU::DeleteResponse)
180
+
181
+ mock = flexmock("socket")
182
+ mock.should_receive(:read_ber).
183
+ and_return(result1).
184
+ and_return(result2)
185
+ mock.should_receive(:write)
186
+ conn = Net::LDAP::Connection.new(:socket => mock)
187
+
188
+ conn.next_msgid # simulates ongoing query
189
+
190
+ assert result = conn.delete(:dn => "uid=deletable-user1,ou=People,dc=rubyldap,dc=com")
191
+ assert result.success?
192
+ assert_equal 2, result.message_id
193
+ end
194
+
195
+ def test_queued_read_setup_encryption_with_start_tls
196
+ result1 = make_message(1, :app_tag => Net::LDAP::PDU::SearchResult)
197
+ result2 = make_message(2, :app_tag => Net::LDAP::PDU::ExtendedResponse)
198
+
199
+ mock = flexmock("socket")
200
+ mock.should_receive(:read_ber).
201
+ and_return(result1).
202
+ and_return(result2)
203
+ mock.should_receive(:write)
204
+ conn = Net::LDAP::Connection.new(:socket => mock)
205
+ flexmock(Net::LDAP::Connection).should_receive(:wrap_with_ssl).with(mock, {}).
206
+ and_return(mock)
207
+
208
+ conn.next_msgid # simulates ongoing query
209
+
210
+ assert result = conn.setup_encryption(:method => :start_tls)
211
+ assert_equal mock, result
212
+ end
213
+
214
+ def test_queued_read_bind_simple
215
+ result1 = make_message(1, :app_tag => Net::LDAP::PDU::SearchResult)
216
+ result2 = make_message(2, :app_tag => Net::LDAP::PDU::BindResult)
217
+
218
+ mock = flexmock("socket")
219
+ mock.should_receive(:read_ber).
220
+ and_return(result1).
221
+ and_return(result2)
222
+ mock.should_receive(:write)
223
+ conn = Net::LDAP::Connection.new(:socket => mock)
224
+
225
+ conn.next_msgid # simulates ongoing query
226
+
227
+ assert result = conn.bind(
228
+ :method => :simple,
229
+ :username => "uid=user1,ou=People,dc=rubyldap,dc=com",
230
+ :password => "passworD1")
231
+ assert result.success?
232
+ assert_equal 2, result.message_id
233
+ end
234
+
235
+ def test_queued_read_bind_sasl
236
+ result1 = make_message(1, :app_tag => Net::LDAP::PDU::SearchResult)
237
+ result2 = make_message(2, :app_tag => Net::LDAP::PDU::BindResult)
238
+
239
+ mock = flexmock("socket")
240
+ mock.should_receive(:read_ber).
241
+ and_return(result1).
242
+ and_return(result2)
243
+ mock.should_receive(:write)
244
+ conn = Net::LDAP::Connection.new(:socket => mock)
245
+
246
+ conn.next_msgid # simulates ongoing query
247
+
248
+ assert result = conn.bind(
249
+ :method => :sasl,
250
+ :mechanism => "fake",
251
+ :initial_credential => "passworD1",
252
+ :challenge_response => flexmock("challenge proc"))
253
+ assert result.success?
254
+ assert_equal 2, result.message_id
255
+ end
256
+ end
257
+
258
+ class TestLDAPConnectionErrors < Test::Unit::TestCase
259
+ def setup
260
+ @tcp_socket = flexmock(:connection)
261
+ @tcp_socket.should_receive(:write)
262
+ flexmock(TCPSocket).should_receive(:new).and_return(@tcp_socket)
263
+ @connection = Net::LDAP::Connection.new(:host => 'test.mocked.com', :port => 636)
264
+ end
265
+
266
+ def test_error_failed_operation
267
+ ber = Net::BER::BerIdentifiedArray.new([Net::LDAP::ResultCodeUnwillingToPerform, "", "The provided password value was rejected by a password validator: The provided password did not contain enough characters from the character set 'ABCDEFGHIJKLMNOPQRSTUVWXYZ'. The minimum number of characters from that set that must be present in user passwords is 1"])
268
+ ber.ber_identifier = Net::LDAP::PDU::ModifyResponse
269
+ @tcp_socket.should_receive(:read_ber).and_return([1, ber])
270
+
271
+ result = @connection.modify(:dn => "1", :operations => [[:replace, "mail", "something@sothsdkf.com"]])
272
+ assert result.failure?, "should be failure"
273
+ assert_equal "The provided password value was rejected by a password validator: The provided password did not contain enough characters from the character set 'ABCDEFGHIJKLMNOPQRSTUVWXYZ'. The minimum number of characters from that set that must be present in user passwords is 1", result.error_message
274
+ end
275
+
276
+ def test_no_error_on_success
277
+ ber = Net::BER::BerIdentifiedArray.new([Net::LDAP::ResultCodeSuccess, "", ""])
278
+ ber.ber_identifier = Net::LDAP::PDU::ModifyResponse
279
+ @tcp_socket.should_receive(:read_ber).and_return([1, ber])
280
+
281
+ result = @connection.modify(:dn => "1", :operations => [[:replace, "mail", "something@sothsdkf.com"]])
282
+ assert result.success?, "should be success"
283
+ assert_equal "", result.error_message
284
+ end
285
+ end
286
+
287
+ class TestLDAPConnectionInstrumentation < Test::Unit::TestCase
288
+ def setup
289
+ @tcp_socket = flexmock(:connection)
290
+ @tcp_socket.should_receive(:write)
291
+ flexmock(TCPSocket).should_receive(:new).and_return(@tcp_socket)
292
+
293
+ @service = MockInstrumentationService.new
294
+ @connection = Net::LDAP::Connection.new \
295
+ :host => 'test.mocked.com',
296
+ :port => 636,
297
+ :instrumentation_service => @service
298
+ end
299
+
300
+ def test_write_net_ldap_connection_event
301
+ ber = Net::BER::BerIdentifiedArray.new([Net::LDAP::ResultCodeSuccess, "", ""])
302
+ ber.ber_identifier = Net::LDAP::PDU::BindResult
303
+ read_result = [1, ber]
304
+ @tcp_socket.should_receive(:read_ber).and_return(read_result)
305
+
306
+ events = @service.subscribe "write.net_ldap_connection"
307
+
308
+ result = @connection.bind(:method => :anon)
309
+ assert result.success?, "should be success"
310
+
311
+ # a write event
312
+ payload, result = events.pop
313
+ assert payload.has_key?(:result)
314
+ assert payload.has_key?(:content_length)
315
+ end
316
+
317
+ def test_read_net_ldap_connection_event
318
+ ber = Net::BER::BerIdentifiedArray.new([Net::LDAP::ResultCodeSuccess, "", ""])
319
+ ber.ber_identifier = Net::LDAP::PDU::BindResult
320
+ read_result = [1, ber]
321
+ @tcp_socket.should_receive(:read_ber).and_return(read_result)
322
+
323
+ events = @service.subscribe "read.net_ldap_connection"
324
+
325
+ result = @connection.bind(:method => :anon)
326
+ assert result.success?, "should be success"
327
+
328
+ # a read event
329
+ payload, result = events.pop
330
+ assert payload.has_key?(:result)
331
+ assert_equal read_result, result
332
+ end
333
+
334
+ def test_parse_pdu_net_ldap_connection_event
335
+ ber = Net::BER::BerIdentifiedArray.new([Net::LDAP::ResultCodeSuccess, "", ""])
336
+ ber.ber_identifier = Net::LDAP::PDU::BindResult
337
+ read_result = [1, ber]
338
+ @tcp_socket.should_receive(:read_ber).and_return(read_result)
339
+
340
+ events = @service.subscribe "parse_pdu.net_ldap_connection"
341
+
342
+ result = @connection.bind(:method => :anon)
343
+ assert result.success?, "should be success"
344
+
345
+ # a parse_pdu event
346
+ payload, result = events.pop
347
+ assert payload.has_key?(:pdu)
348
+ assert payload.has_key?(:app_tag)
349
+ assert payload.has_key?(:message_id)
350
+ assert_equal Net::LDAP::PDU::BindResult, payload[:app_tag]
351
+ assert_equal 1, payload[:message_id]
352
+ pdu = payload[:pdu]
353
+ assert_equal Net::LDAP::ResultCodeSuccess, pdu.result_code
354
+ end
355
+
356
+ def test_bind_net_ldap_connection_event
357
+ ber = Net::BER::BerIdentifiedArray.new([Net::LDAP::ResultCodeSuccess, "", ""])
358
+ ber.ber_identifier = Net::LDAP::PDU::BindResult
359
+ bind_result = [1, ber]
360
+ @tcp_socket.should_receive(:read_ber).and_return(bind_result)
361
+
362
+ events = @service.subscribe "bind.net_ldap_connection"
363
+
364
+ result = @connection.bind(:method => :anon)
365
+ assert result.success?, "should be success"
366
+
367
+ # a read event
368
+ payload, result = events.pop
369
+ assert payload.has_key?(:result)
370
+ assert result.success?, "should be success"
371
+ end
372
+
373
+ def test_search_net_ldap_connection_event
374
+ # search data
375
+ search_data_ber = Net::BER::BerIdentifiedArray.new([1, [
376
+ "uid=user1,ou=People,dc=rubyldap,dc=com",
377
+ [ ["uid", ["user1"]] ]
378
+ ]])
379
+ search_data_ber.ber_identifier = Net::LDAP::PDU::SearchReturnedData
380
+ search_data = [1, search_data_ber]
381
+ # search result (end of results)
382
+ search_result_ber = Net::BER::BerIdentifiedArray.new([Net::LDAP::ResultCodeSuccess, "", ""])
383
+ search_result_ber.ber_identifier = Net::LDAP::PDU::SearchResult
384
+ search_result = [1, search_result_ber]
385
+ @tcp_socket.should_receive(:read_ber).and_return(search_data).
386
+ and_return(search_result)
387
+
388
+ events = @service.subscribe "search.net_ldap_connection"
389
+ unread = @service.subscribe "search_messages_unread.net_ldap_connection"
390
+
391
+ result = @connection.search(:filter => "(uid=user1)", :base => "ou=People,dc=rubyldap,dc=com")
392
+ assert result.success?, "should be success"
393
+
394
+ # a search event
395
+ payload, result = events.pop
396
+ assert payload.has_key?(:result)
397
+ assert payload.has_key?(:filter)
398
+ assert_equal "(uid=user1)", payload[:filter].to_s
399
+ assert result
400
+
401
+ # ensure no unread
402
+ assert unread.empty?, "should not have any leftover unread messages"
403
+ end
404
+ end