Skip to content

Commit 0b73377

Browse files
committed
Merge pull request #144 from ruby-ldap/queue-reads-everywhere
Queue reads everywhere
2 parents eedec06 + d124182 commit 0b73377

File tree

3 files changed

+287
-36
lines changed

3 files changed

+287
-36
lines changed

lib/net/ldap/connection.rb

Lines changed: 56 additions & 29 deletions
Original file line numberDiff line numberDiff line change
@@ -87,10 +87,18 @@ def setup_encryption(args)
8787
# additional branches requiring server validation and peer certs, etc.
8888
# go here.
8989
when :start_tls
90-
request = [Net::LDAP::StartTlsOid.to_ber_contextspecific(0)].to_ber_appsequence(Net::LDAP::PDU::ExtendedRequest)
91-
write(request)
92-
pdu = read
93-
raise Net::LDAP::LdapError, "no start_tls result" if pdu.nil?
90+
message_id = next_msgid
91+
request = [
92+
Net::LDAP::StartTlsOid.to_ber_contextspecific(0)
93+
].to_ber_appsequence(Net::LDAP::PDU::ExtendedRequest)
94+
95+
write(request, nil, message_id)
96+
pdu = queued_read(message_id)
97+
98+
if pdu.nil? || pdu.app_tag != Net::LDAP::PDU::ExtendedResponse
99+
raise Net::LDAP::LdapError, "no start_tls result"
100+
end
101+
94102
if pdu.result_code.zero?
95103
@conn = self.class.wrap_with_ssl(@conn)
96104
else
@@ -226,12 +234,18 @@ def bind_simple(auth)
226234

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

229-
request = [LdapVersion.to_ber, user.to_ber,
230-
psw.to_ber_contextspecific(0)].to_ber_appsequence(Net::LDAP::PDU::BindRequest)
231-
write(request)
237+
message_id = next_msgid
238+
request = [
239+
LdapVersion.to_ber, user.to_ber,
240+
psw.to_ber_contextspecific(0)
241+
].to_ber_appsequence(Net::LDAP::PDU::BindRequest)
232242

233-
pdu = read
234-
raise Net::LDAP::LdapError, "no bind result" unless pdu
243+
write(request, nil, message_id)
244+
pdu = queued_read(message_id)
245+
246+
if !pdu || pdu.app_tag != Net::LDAP::PDU::BindResult
247+
raise Net::LDAP::LdapError, "no bind result"
248+
end
235249

236250
pdu
237251
end
@@ -262,14 +276,21 @@ def bind_sasl(auth)
262276
auth[:challenge_response]
263277
raise Net::LDAP::LdapError, "Invalid binding information" unless (mech && cred && chall)
264278

279+
message_id = next_msgid
280+
265281
n = 0
266282
loop {
267283
sasl = [mech.to_ber, cred.to_ber].to_ber_contextspecific(3)
268-
request = [LdapVersion.to_ber, "".to_ber, sasl].to_ber_appsequence(Net::LDAP::PDU::BindRequest)
269-
write(request)
284+
request = [
285+
LdapVersion.to_ber, "".to_ber, sasl
286+
].to_ber_appsequence(Net::LDAP::PDU::BindRequest)
270287

271-
pdu = read
272-
raise Net::LDAP::LdapError, "no bind result" unless pdu
288+
write(request, nil, message_id)
289+
pdu = queued_read(message_id)
290+
291+
if !pdu || pdu.app_tag != Net::LDAP::PDU::BindResult
292+
raise Net::LDAP::LdapError, "no bind result"
293+
end
273294

274295
return pdu unless pdu.result_code == Net::LDAP::ResultCodeSaslBindInProgress
275296
raise Net::LDAP::LdapError, "sasl-challenge overflow" if ((n += 1) > MaxSaslChallenges)
@@ -583,11 +604,15 @@ def self.modify_ops(operations)
583604
def modify(args)
584605
modify_dn = args[:dn] or raise "Unable to modify empty DN"
585606
ops = self.class.modify_ops args[:operations]
586-
request = [ modify_dn.to_ber,
587-
ops.to_ber_sequence ].to_ber_appsequence(Net::LDAP::PDU::ModifyRequest)
588-
write(request)
589607

590-
pdu = read
608+
message_id = next_msgid
609+
request = [
610+
modify_dn.to_ber,
611+
ops.to_ber_sequence
612+
].to_ber_appsequence(Net::LDAP::PDU::ModifyRequest)
613+
614+
write(request, nil, message_id)
615+
pdu = queued_read(message_id)
591616

592617
if !pdu || pdu.app_tag != Net::LDAP::PDU::ModifyResponse
593618
raise Net::LDAP::LdapError, "response missing or invalid"
@@ -610,10 +635,11 @@ def add(args)
610635
add_attrs << [ k.to_s.to_ber, Array(v).map { |m| m.to_ber}.to_ber_set ].to_ber_sequence
611636
}
612637

613-
request = [add_dn.to_ber, add_attrs.to_ber_sequence].to_ber_appsequence(Net::LDAP::PDU::AddRequest)
614-
write(request)
638+
message_id = next_msgid
639+
request = [add_dn.to_ber, add_attrs.to_ber_sequence].to_ber_appsequence(Net::LDAP::PDU::AddRequest)
615640

616-
pdu = read
641+
write(request, nil, message_id)
642+
pdu = queued_read(message_id)
617643

618644
if !pdu || pdu.app_tag != Net::LDAP::PDU::AddResponse
619645
raise Net::LDAP::LdapError, "response missing or invalid"
@@ -631,12 +657,12 @@ def rename(args)
631657
delete_attrs = args[:delete_attributes] ? true : false
632658
new_superior = args[:new_superior]
633659

634-
request = [old_dn.to_ber, new_rdn.to_ber, delete_attrs.to_ber]
635-
request << new_superior.to_ber_contextspecific(0) unless new_superior == nil
636-
637-
write(request.to_ber_appsequence(Net::LDAP::PDU::ModifyRDNRequest))
660+
message_id = next_msgid
661+
request = [old_dn.to_ber, new_rdn.to_ber, delete_attrs.to_ber]
662+
request << new_superior.to_ber_contextspecific(0) unless new_superior == nil
638663

639-
pdu = read
664+
write(request.to_ber_appsequence(Net::LDAP::PDU::ModifyRDNRequest), nil, message_id)
665+
pdu = queued_read(message_id)
640666

641667
if !pdu || pdu.app_tag != Net::LDAP::PDU::ModifyRDNResponse
642668
raise Net::LDAP::LdapError.new "response missing or invalid"
@@ -650,11 +676,12 @@ def rename(args)
650676
#++
651677
def delete(args)
652678
dn = args[:dn] or raise "Unable to delete empty DN"
653-
controls = args.include?(:control_codes) ? args[:control_codes].to_ber_control : nil #use nil so we can compact later
654-
request = dn.to_s.to_ber_application_string(Net::LDAP::PDU::DeleteRequest)
655-
write(request, controls)
679+
controls = args.include?(:control_codes) ? args[:control_codes].to_ber_control : nil #use nil so we can compact later
680+
message_id = next_msgid
681+
request = dn.to_s.to_ber_application_string(Net::LDAP::PDU::DeleteRequest)
656682

657-
pdu = read
683+
write(request, controls, message_id)
684+
pdu = queued_read(message_id)
658685

659686
if !pdu || pdu.app_tag != Net::LDAP::PDU::DeleteResponse
660687
raise Net::LDAP::LdapError, "response missing or invalid"

test/integration/test_open.rb

Lines changed: 37 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -21,6 +21,10 @@ def test_binds_with_open
2121
assert_equal 1, events.size
2222
end
2323

24+
# NOTE: query for two or more entries so that the socket must be read
25+
# multiple times.
26+
# See The Problem: https://github.com/ruby-ldap/ruby-net-ldap/issues/136
27+
2428
def test_nested_search_without_open
2529
entries = []
2630
nested_entry = nil
@@ -48,4 +52,37 @@ def test_nested_search_with_open
4852
assert_equal "user3", nested_entry.uid.first
4953
assert_equal %w(user1 user2), entries
5054
end
55+
56+
def test_nested_add_with_open
57+
entries = []
58+
nested_entry = nil
59+
60+
dn = "uid=nested-open-added-user1,ou=People,dc=rubyldap,dc=com"
61+
attrs = {
62+
objectclass: %w(top inetOrgPerson organizationalPerson person),
63+
uid: "nested-open-added-user1",
64+
cn: "nested-open-added-user1",
65+
sn: "nested-open-added-user1",
66+
67+
}
68+
69+
@ldap.authenticate "cn=admin,dc=rubyldap,dc=com", "passworD1"
70+
@ldap.delete dn: dn
71+
72+
@ldap.open do
73+
@ldap.search(filter: "(|(uid=user1)(uid=user2))", base: "ou=People,dc=rubyldap,dc=com") do |entry|
74+
entries << entry.uid.first
75+
76+
nested_entry ||= begin
77+
assert @ldap.add(dn: dn, attributes: attrs), @ldap.get_operation_result.inspect
78+
@ldap.search(base: dn, scope: Net::LDAP::SearchScope_BaseObject).first
79+
end
80+
end
81+
end
82+
83+
assert_equal %w(user1 user2), entries
84+
assert_equal "nested-open-added-user1", nested_entry.uid.first
85+
ensure
86+
@ldap.delete dn: dn
87+
end
5188
end

0 commit comments

Comments
 (0)