Skip to content

Commit 49fd5c9

Browse files
committed
Merge branch 'master' into open-integration-tests
2 parents f16a4ff + 0aeceaf commit 49fd5c9

File tree

4 files changed

+160
-42
lines changed

4 files changed

+160
-42
lines changed

lib/net/ldap/connection.rb

Lines changed: 58 additions & 42 deletions
Original file line numberDiff line numberDiff line change
@@ -10,7 +10,7 @@ def initialize(server)
1010
@instrumentation_service = server[:instrumentation_service]
1111

1212
begin
13-
@conn = TCPSocket.new(server[:host], server[:port])
13+
@conn = server[:socket] || TCPSocket.new(server[:host], server[:port])
1414
rescue SocketError
1515
raise Net::LDAP::LdapError, "No such address or other socket error."
1616
rescue Errno::ECONNREFUSED
@@ -87,13 +87,9 @@ def setup_encryption(args)
8787
# additional branches requiring server validation and peer certs, etc.
8888
# go here.
8989
when :start_tls
90-
msgid = next_msgid.to_ber
9190
request = [Net::LDAP::StartTlsOid.to_ber_contextspecific(0)].to_ber_appsequence(Net::LDAP::PDU::ExtendedRequest)
92-
request_pkt = [msgid, request].to_ber_sequence
93-
write request_pkt
94-
be = read
95-
raise Net::LDAP::LdapError, "no start_tls result" if be.nil?
96-
pdu = Net::LDAP::PDU.new(be)
91+
write(request)
92+
pdu = read
9793
raise Net::LDAP::LdapError, "no start_tls result" if pdu.nil?
9894
if pdu.result_code.zero?
9995
@conn = self.class.wrap_with_ssl(@conn)
@@ -119,25 +115,40 @@ def close
119115
#
120116
# - syntax: the BER syntax to use to parse the read data with
121117
#
122-
# Returns basic BER objects.
118+
# Returns parsed Net::LDAP::PDU object.
123119
def read(syntax = Net::LDAP::AsnSyntax)
124-
instrument "read.net_ldap_connection", :syntax => syntax do |payload|
125-
@conn.read_ber(syntax) do |id, content_length|
126-
payload[:object_type_id] = id
127-
payload[:content_length] = content_length
120+
ber_object =
121+
instrument "read.net_ldap_connection", :syntax => syntax do |payload|
122+
@conn.read_ber(syntax) do |id, content_length|
123+
payload[:object_type_id] = id
124+
payload[:content_length] = content_length
125+
end
128126
end
127+
128+
return unless ber_object
129+
130+
instrument "parse_pdu.net_ldap_connection" do |payload|
131+
pdu = payload[:pdu] = Net::LDAP::PDU.new(ber_object)
132+
133+
payload[:message_id] = pdu.message_id
134+
payload[:app_tag] = pdu.app_tag
135+
136+
pdu
129137
end
130138
end
131139
private :read
132140

133-
# Internal: Writes the given packet to the configured connection.
141+
# Internal: Write a BER formatted packet with the next message id to the
142+
# configured connection.
134143
#
135-
# - packet: the BER data packet to write on the socket.
144+
# - request: required BER formatted request
145+
# - controls: optional BER formatted controls
136146
#
137147
# Returns the return value from writing to the connection, which in some
138148
# cases is the Integer number of bytes written to the socket.
139-
def write(packet)
149+
def write(request, controls = nil)
140150
instrument "write.net_ldap_connection" do |payload|
151+
packet = [next_msgid.to_ber, request, controls].compact.to_ber_sequence
141152
payload[:content_length] = @conn.write(packet)
142153
end
143154
end
@@ -176,13 +187,12 @@ def bind_simple(auth)
176187

177188
raise Net::LDAP::LdapError, "Invalid binding information" unless (user && psw)
178189

179-
msgid = next_msgid.to_ber
180190
request = [LdapVersion.to_ber, user.to_ber,
181191
psw.to_ber_contextspecific(0)].to_ber_appsequence(0)
182-
request_pkt = [msgid, request].to_ber_sequence
183-
write request_pkt
192+
write(request)
184193

185-
(be = read and pdu = Net::LDAP::PDU.new(be)) or raise Net::LDAP::LdapError, "no bind result"
194+
pdu = read
195+
raise Net::LDAP::LdapError, "no bind result" unless pdu
186196

187197
pdu
188198
end
@@ -215,13 +225,13 @@ def bind_sasl(auth)
215225

216226
n = 0
217227
loop {
218-
msgid = next_msgid.to_ber
219228
sasl = [mech.to_ber, cred.to_ber].to_ber_contextspecific(3)
220229
request = [LdapVersion.to_ber, "".to_ber, sasl].to_ber_appsequence(0)
221-
request_pkt = [msgid, request].to_ber_sequence
222-
write request_pkt
230+
write(request)
231+
232+
pdu = read
233+
raise Net::LDAP::LdapError, "no bind result" unless pdu
223234

224-
(be = read and pdu = Net::LDAP::PDU.new(be)) or raise Net::LDAP::LdapError, "no bind result"
225235
return pdu unless pdu.result_code == 14 # saslBindInProgress
226236
raise Net::LDAP::LdapError, "sasl-challenge overflow" if ((n += 1) > MaxSaslChallenges)
227237

@@ -393,13 +403,12 @@ def search(args = {})
393403
controls << sort_control if sort_control
394404
controls = controls.empty? ? nil : controls.to_ber_contextspecific(0)
395405

396-
pkt = [next_msgid.to_ber, request, controls].compact.to_ber_sequence
397-
write pkt
406+
write(request, controls)
398407

399408
result_pdu = nil
400409
controls = []
401410

402-
while (be = read) && (pdu = Net::LDAP::PDU.new(be))
411+
while pdu = read
403412
case pdu.app_tag
404413
when Net::LDAP::PDU::SearchReturnedData
405414
n_results += 1
@@ -502,10 +511,13 @@ def modify(args)
502511
ops = self.class.modify_ops args[:operations]
503512
request = [ modify_dn.to_ber,
504513
ops.to_ber_sequence ].to_ber_appsequence(6)
505-
pkt = [ next_msgid.to_ber, request ].to_ber_sequence
506-
write pkt
514+
write(request)
507515

508-
(be = read) && (pdu = Net::LDAP::PDU.new(be)) && (pdu.app_tag == Net::LDAP::PDU::ModifyResponse) or raise Net::LDAP::LdapError, "response missing or invalid"
516+
pdu = read
517+
518+
if !pdu || pdu.app_tag != Net::LDAP::PDU::ModifyResponse
519+
raise Net::LDAP::LdapError, "response missing or invalid"
520+
end
509521

510522
pdu
511523
end
@@ -525,13 +537,13 @@ def add(args)
525537
}
526538

527539
request = [add_dn.to_ber, add_attrs.to_ber_sequence].to_ber_appsequence(8)
528-
pkt = [next_msgid.to_ber, request].to_ber_sequence
529-
write pkt
540+
write(request)
541+
542+
pdu = read
530543

531-
(be = read) &&
532-
(pdu = Net::LDAP::PDU.new(be)) &&
533-
(pdu.app_tag == Net::LDAP::PDU::AddResponse) or
544+
if !pdu || pdu.app_tag != Net::LDAP::PDU::AddResponse
534545
raise Net::LDAP::LdapError, "response missing or invalid"
546+
end
535547

536548
pdu
537549
end
@@ -548,12 +560,13 @@ def rename(args)
548560
request = [old_dn.to_ber, new_rdn.to_ber, delete_attrs.to_ber]
549561
request << new_superior.to_ber_contextspecific(0) unless new_superior == nil
550562

551-
pkt = [next_msgid.to_ber, request.to_ber_appsequence(12)].to_ber_sequence
552-
write pkt
563+
write(request.to_ber_appsequence(12))
564+
565+
pdu = read
553566

554-
(be = read) &&
555-
(pdu = Net::LDAP::PDU.new( be )) && (pdu.app_tag == Net::LDAP::PDU::ModifyRDNResponse) or
556-
raise Net::LDAP::LdapError.new( "response missing or invalid" )
567+
if !pdu || pdu.app_tag != Net::LDAP::PDU::ModifyRDNResponse
568+
raise Net::LDAP::LdapError.new "response missing or invalid"
569+
end
557570

558571
pdu
559572
end
@@ -565,10 +578,13 @@ def delete(args)
565578
dn = args[:dn] or raise "Unable to delete empty DN"
566579
controls = args.include?(:control_codes) ? args[:control_codes].to_ber_control : nil #use nil so we can compact later
567580
request = dn.to_s.to_ber_application_string(10)
568-
pkt = [next_msgid.to_ber, request, controls].compact.to_ber_sequence
569-
write pkt
581+
write(request, controls)
582+
583+
pdu = read
570584

571-
(be = read) && (pdu = Net::LDAP::PDU.new(be)) && (pdu.app_tag == Net::LDAP::PDU::DeleteResponse) or raise Net::LDAP::LdapError, "response missing or invalid"
585+
if !pdu || pdu.app_tag != Net::LDAP::PDU::DeleteResponse
586+
raise Net::LDAP::LdapError, "response missing or invalid"
587+
end
572588

573589
pdu
574590
end

test/integration/test_add.rb

Lines changed: 28 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,28 @@
1+
require_relative '../test_helper'
2+
3+
class TestAddIntegration < LDAPIntegrationTestCase
4+
def setup
5+
super
6+
@ldap.authenticate "cn=admin,dc=rubyldap,dc=com", "passworD1"
7+
8+
@dn = "uid=added-user1,ou=People,dc=rubyldap,dc=com"
9+
end
10+
11+
def test_add
12+
attrs = {
13+
objectclass: %w(top inetOrgPerson organizationalPerson person),
14+
uid: "added-user1",
15+
cn: "added-user1",
16+
sn: "added-user1",
17+
mail: "added-user1@rubyldap.com"
18+
}
19+
20+
assert @ldap.add(dn: @dn, attributes: attrs), @ldap.get_operation_result.inspect
21+
22+
assert result = @ldap.search(base: @dn, scope: Net::LDAP::SearchScope_BaseObject).first
23+
end
24+
25+
def teardown
26+
@ldap.delete dn: @dn
27+
end
28+
end

test/integration/test_delete.rb

Lines changed: 29 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,29 @@
1+
require_relative '../test_helper'
2+
3+
class TestDeleteIntegration < LDAPIntegrationTestCase
4+
def setup
5+
super
6+
@ldap.authenticate "cn=admin,dc=rubyldap,dc=com", "passworD1"
7+
8+
@dn = "uid=delete-user1,ou=People,dc=rubyldap,dc=com"
9+
10+
attrs = {
11+
objectclass: %w(top inetOrgPerson organizationalPerson person),
12+
uid: "delete-user1",
13+
cn: "delete-user1",
14+
sn: "delete-user1",
15+
mail: "delete-user1@rubyldap.com"
16+
}
17+
assert @ldap.add(dn: @dn, attributes: attrs), @ldap.get_operation_result.inspect
18+
assert @ldap.search(base: @dn, scope: Net::LDAP::SearchScope_BaseObject)
19+
end
20+
21+
def test_delete
22+
assert @ldap.delete(dn: @dn), @ldap.get_operation_result.inspect
23+
refute @ldap.search(base: @dn, scope: Net::LDAP::SearchScope_BaseObject)
24+
25+
result = @ldap.get_operation_result
26+
assert_equal 32, result.code
27+
assert_equal Net::LDAP::ResultStrings[32], result.message
28+
end
29+
end

test/test_ldap_connection.rb

Lines changed: 45 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -42,6 +42,29 @@ def test_modify_ops_replace
4242
expected = [ "0#\n\x01\x020\x1E\x04\x04mail1\x16\x04\x14testuser@example.com" ]
4343
assert_equal(expected, result)
4444
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
4568
end
4669

4770

@@ -121,6 +144,28 @@ def test_read_net_ldap_connection_event
121144
assert_equal read_result, result
122145
end
123146

147+
def test_parse_pdu_net_ldap_connection_event
148+
ber = Net::BER::BerIdentifiedArray.new([0, "", ""])
149+
ber.ber_identifier = Net::LDAP::PDU::BindResult
150+
read_result = [2, ber]
151+
@tcp_socket.should_receive(:read_ber).and_return(read_result)
152+
153+
events = @service.subscribe "parse_pdu.net_ldap_connection"
154+
155+
result = @connection.bind(method: :anon)
156+
assert result.success?, "should be success"
157+
158+
# a parse_pdu event
159+
payload, result = events.pop
160+
assert payload.has_key?(:pdu)
161+
assert payload.has_key?(:app_tag)
162+
assert payload.has_key?(:message_id)
163+
assert_equal Net::LDAP::PDU::BindResult, payload[:app_tag]
164+
assert_equal 2, payload[:message_id]
165+
pdu = payload[:pdu]
166+
assert_equal 0, pdu.result_code
167+
end
168+
124169
def test_bind_net_ldap_connection_event
125170
ber = Net::BER::BerIdentifiedArray.new([0, "", ""])
126171
ber.ber_identifier = Net::LDAP::PDU::BindResult

0 commit comments

Comments
 (0)