rubinius-net-ldap 0.11
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +7 -0
- data/.gitignore +10 -0
- data/.rubocop.yml +5 -0
- data/.rubocop_todo.yml +462 -0
- data/.travis.yml +19 -0
- data/CONTRIBUTING.md +54 -0
- data/Contributors.rdoc +24 -0
- data/Gemfile +2 -0
- data/Hacking.rdoc +63 -0
- data/History.rdoc +260 -0
- data/License.rdoc +29 -0
- data/README.rdoc +65 -0
- data/Rakefile +17 -0
- data/lib/net-ldap.rb +2 -0
- data/lib/net/ber.rb +320 -0
- data/lib/net/ber/ber_parser.rb +182 -0
- data/lib/net/ber/core_ext.rb +55 -0
- data/lib/net/ber/core_ext/array.rb +96 -0
- data/lib/net/ber/core_ext/false_class.rb +10 -0
- data/lib/net/ber/core_ext/integer.rb +74 -0
- data/lib/net/ber/core_ext/string.rb +66 -0
- data/lib/net/ber/core_ext/true_class.rb +11 -0
- data/lib/net/ldap.rb +1229 -0
- data/lib/net/ldap/connection.rb +702 -0
- data/lib/net/ldap/dataset.rb +168 -0
- data/lib/net/ldap/dn.rb +225 -0
- data/lib/net/ldap/entry.rb +193 -0
- data/lib/net/ldap/error.rb +38 -0
- data/lib/net/ldap/filter.rb +778 -0
- data/lib/net/ldap/instrumentation.rb +23 -0
- data/lib/net/ldap/password.rb +38 -0
- data/lib/net/ldap/pdu.rb +297 -0
- data/lib/net/ldap/version.rb +5 -0
- data/lib/net/snmp.rb +264 -0
- data/rubinius-net-ldap.gemspec +37 -0
- data/script/install-openldap +112 -0
- data/script/package +7 -0
- data/script/release +16 -0
- data/test/ber/core_ext/test_array.rb +22 -0
- data/test/ber/core_ext/test_string.rb +25 -0
- data/test/ber/test_ber.rb +99 -0
- data/test/fixtures/cacert.pem +20 -0
- data/test/fixtures/openldap/memberof.ldif +33 -0
- data/test/fixtures/openldap/retcode.ldif +76 -0
- data/test/fixtures/openldap/slapd.conf.ldif +67 -0
- data/test/fixtures/seed.ldif +374 -0
- data/test/integration/test_add.rb +28 -0
- data/test/integration/test_ber.rb +30 -0
- data/test/integration/test_bind.rb +34 -0
- data/test/integration/test_delete.rb +31 -0
- data/test/integration/test_open.rb +88 -0
- data/test/integration/test_return_codes.rb +38 -0
- data/test/integration/test_search.rb +77 -0
- data/test/support/vm/openldap/.gitignore +1 -0
- data/test/support/vm/openldap/README.md +32 -0
- data/test/support/vm/openldap/Vagrantfile +33 -0
- data/test/test_dn.rb +44 -0
- data/test/test_entry.rb +65 -0
- data/test/test_filter.rb +223 -0
- data/test/test_filter_parser.rb +20 -0
- data/test/test_helper.rb +66 -0
- data/test/test_ldap.rb +60 -0
- data/test/test_ldap_connection.rb +404 -0
- data/test/test_ldif.rb +104 -0
- data/test/test_password.rb +10 -0
- data/test/test_rename.rb +77 -0
- data/test/test_search.rb +39 -0
- data/test/test_snmp.rb +119 -0
- data/test/test_ssl_ber.rb +40 -0
- data/test/testdata.ldif +101 -0
- data/testserver/ldapserver.rb +210 -0
- data/testserver/testdata.ldif +101 -0
- metadata +204 -0
data/test/test_filter.rb
ADDED
@@ -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
|
data/test/test_helper.rb
ADDED
@@ -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
|