net-ldap 0.8.0 → 0.9.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.

Potentially problematic release.


This version of net-ldap might be problematic. Click here for more details.

Files changed (73) hide show
  1. checksums.yaml +4 -4
  2. data/.gitignore +7 -0
  3. data/.travis.yml +19 -1
  4. data/CONTRIBUTING.md +54 -0
  5. data/Hacking.rdoc +2 -4
  6. data/History.rdoc +37 -0
  7. data/Manifest.txt +0 -4
  8. data/README.rdoc +8 -0
  9. data/Rakefile +1 -3
  10. data/lib/net/ber/core_ext.rb +5 -5
  11. data/lib/net/ber/core_ext/string.rb +7 -7
  12. data/lib/net/ber/core_ext/true_class.rb +2 -3
  13. data/lib/net/ldap.rb +134 -620
  14. data/lib/net/ldap/connection.rb +692 -0
  15. data/lib/net/ldap/dataset.rb +18 -4
  16. data/lib/net/ldap/entry.rb +1 -1
  17. data/lib/net/ldap/filter.rb +7 -7
  18. data/lib/net/ldap/password.rb +11 -11
  19. data/lib/net/ldap/pdu.rb +28 -4
  20. data/lib/net/ldap/version.rb +1 -1
  21. data/lib/net/snmp.rb +235 -241
  22. data/net-ldap.gemspec +7 -33
  23. data/script/install-openldap +47 -0
  24. data/script/package +7 -0
  25. data/script/release +16 -0
  26. data/test/ber/core_ext/test_array.rb +22 -0
  27. data/test/ber/core_ext/test_string.rb +25 -0
  28. data/test/ber/test_ber.rb +126 -0
  29. data/test/fixtures/openldap/memberof.ldif +33 -0
  30. data/test/fixtures/openldap/retcode.ldif +76 -0
  31. data/test/fixtures/openldap/slapd.conf.ldif +67 -0
  32. data/test/fixtures/seed.ldif +374 -0
  33. data/test/integration/test_add.rb +28 -0
  34. data/test/integration/test_ber.rb +30 -0
  35. data/test/integration/test_bind.rb +22 -0
  36. data/test/integration/test_delete.rb +31 -0
  37. data/test/integration/test_open.rb +88 -0
  38. data/test/integration/test_return_codes.rb +38 -0
  39. data/test/integration/test_search.rb +77 -0
  40. data/test/support/vm/openldap/.gitignore +1 -0
  41. data/test/support/vm/openldap/README.md +32 -0
  42. data/test/support/vm/openldap/Vagrantfile +33 -0
  43. data/test/test_dn.rb +44 -0
  44. data/test/test_entry.rb +62 -56
  45. data/test/test_filter.rb +98 -2
  46. data/test/test_filter_parser.rb +16 -0
  47. data/test/test_helper.rb +54 -0
  48. data/test/test_ldap.rb +60 -0
  49. data/test/test_ldap_connection.rb +382 -2
  50. data/test/test_ldif.rb +26 -1
  51. data/test/test_password.rb +3 -10
  52. data/test/test_rename.rb +2 -2
  53. data/test/test_search.rb +39 -0
  54. data/test/test_snmp.rb +1 -1
  55. data/test/test_ssl_ber.rb +40 -0
  56. metadata +70 -75
  57. data/.autotest +0 -11
  58. data/.gemtest +0 -0
  59. data/.rspec +0 -2
  60. data/autotest/discover.rb +0 -1
  61. data/spec/integration/ssl_ber_spec.rb +0 -39
  62. data/spec/spec.opts +0 -2
  63. data/spec/spec_helper.rb +0 -28
  64. data/spec/unit/ber/ber_spec.rb +0 -141
  65. data/spec/unit/ber/core_ext/array_spec.rb +0 -24
  66. data/spec/unit/ber/core_ext/string_spec.rb +0 -51
  67. data/spec/unit/ldap/dn_spec.rb +0 -80
  68. data/spec/unit/ldap/entry_spec.rb +0 -51
  69. data/spec/unit/ldap/filter_parser_spec.rb +0 -26
  70. data/spec/unit/ldap/filter_spec.rb +0 -115
  71. data/spec/unit/ldap/search_spec.rb +0 -49
  72. data/spec/unit/ldap_spec.rb +0 -223
  73. data/test/common.rb +0 -3
@@ -1,4 +1,4 @@
1
- require 'common'
1
+ require_relative 'test_helper'
2
2
 
3
3
  class TestFilter < Test::Unit::TestCase
4
4
  Filter = Net::LDAP::Filter
@@ -28,7 +28,7 @@ class TestFilter < Test::Unit::TestCase
28
28
  assert_equal("(uid=\\2A)", Filter.equals("uid", "*").to_s)
29
29
  assert_equal("(uid=\\28*)", Filter.begins("uid", "(").to_s)
30
30
  assert_equal("(uid=*\\29)", Filter.ends("uid", ")").to_s)
31
- assert_equal("(uid=*\\5C*)", Filter.contains("uid", "\\").to_s)
31
+ assert_equal("(uid=*\\5C*)", Filter.contains("uid", "\\").to_s)
32
32
  end
33
33
 
34
34
  def test_c2
@@ -120,3 +120,99 @@ class TestFilter < Test::Unit::TestCase
120
120
  end
121
121
  end
122
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
+ end
@@ -0,0 +1,16 @@
1
+ # encoding: utf-8
2
+ require_relative 'test_helper'
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_colons
14
+ 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)")
15
+ end
16
+ end
@@ -0,0 +1,54 @@
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
+ if RUBY_VERSION < "2.0"
10
+ class String
11
+ def b
12
+ self
13
+ end
14
+ end
15
+ end
16
+
17
+ class MockInstrumentationService
18
+ def initialize
19
+ @events = {}
20
+ end
21
+
22
+ def instrument(event, payload)
23
+ result = yield(payload)
24
+ @events[event] ||= []
25
+ @events[event] << [payload, result]
26
+ result
27
+ end
28
+
29
+ def subscribe(event)
30
+ @events[event] ||= []
31
+ @events[event]
32
+ end
33
+ end
34
+
35
+ class LDAPIntegrationTestCase < Test::Unit::TestCase
36
+ # If integration tests aren't enabled, noop these tests.
37
+ if !INTEGRATION
38
+ def run(*)
39
+ self
40
+ end
41
+ end
42
+
43
+ def setup
44
+ @service = MockInstrumentationService.new
45
+ @ldap = Net::LDAP.new \
46
+ host: ENV.fetch('INTEGRATION_HOST', 'localhost'),
47
+ port: 389,
48
+ admin_user: 'uid=admin,dc=rubyldap,dc=com',
49
+ admin_password: 'passworD1',
50
+ search_domains: %w(dc=rubyldap,dc=com),
51
+ uid: 'uid',
52
+ instrumentation_service: @service
53
+ end
54
+ end
@@ -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
+ refute_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
+ refute_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
@@ -1,6 +1,27 @@
1
- require 'common'
1
+ require_relative 'test_helper'
2
+
3
+ class TestLDAPConnection < Test::Unit::TestCase
4
+ def test_unresponsive_host
5
+ assert_raise Net::LDAP::LdapError 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::LdapError 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
2
24
 
3
- class TestLDAP < Test::Unit::TestCase
4
25
  def test_modify_ops_delete
5
26
  args = { :operations => [ [ :delete, "mail" ] ] }
6
27
  result = Net::LDAP::Connection.modify_ops(args[:operations])
@@ -21,4 +42,363 @@ class TestLDAP < Test::Unit::TestCase
21
42
  expected = [ "0#\n\x01\x020\x1E\x04\x04mail1\x16\x04\x14testuser@example.com" ]
22
43
  assert_equal(expected, result)
23
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
24
404
  end