Skip to content

Commit 0aeceaf

Browse files
committed
Merge pull request #131 from ruby-ldap/instrument-messages
Parse Net::LDAP::PDU when calling Net::LDAP::Connection#read, instrument PDU parsing
2 parents ed84f2b + 805520e commit 0aeceaf

File tree

4 files changed

+122
-19
lines changed

4 files changed

+122
-19
lines changed

lib/net/ldap/connection.rb

Lines changed: 43 additions & 19 deletions
Original file line numberDiff line numberDiff line change
@@ -89,9 +89,7 @@ def setup_encryption(args)
8989
when :start_tls
9090
request = [Net::LDAP::StartTlsOid.to_ber_contextspecific(0)].to_ber_appsequence(Net::LDAP::PDU::ExtendedRequest)
9191
write(request)
92-
be = read
93-
raise Net::LDAP::LdapError, "no start_tls result" if be.nil?
94-
pdu = Net::LDAP::PDU.new(be)
92+
pdu = read
9593
raise Net::LDAP::LdapError, "no start_tls result" if pdu.nil?
9694
if pdu.result_code.zero?
9795
@conn = self.class.wrap_with_ssl(@conn)
@@ -117,13 +115,25 @@ def close
117115
#
118116
# - syntax: the BER syntax to use to parse the read data with
119117
#
120-
# Returns basic BER objects.
118+
# Returns parsed Net::LDAP::PDU object.
121119
def read(syntax = Net::LDAP::AsnSyntax)
122-
instrument "read.net_ldap_connection", :syntax => syntax do |payload|
123-
@conn.read_ber(syntax) do |id, content_length|
124-
payload[:object_type_id] = id
125-
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
126126
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
127137
end
128138
end
129139
private :read
@@ -181,7 +191,8 @@ def bind_simple(auth)
181191
psw.to_ber_contextspecific(0)].to_ber_appsequence(0)
182192
write(request)
183193

184-
(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
185196

186197
pdu
187198
end
@@ -218,7 +229,9 @@ def bind_sasl(auth)
218229
request = [LdapVersion.to_ber, "".to_ber, sasl].to_ber_appsequence(0)
219230
write(request)
220231

221-
(be = read and pdu = Net::LDAP::PDU.new(be)) or raise Net::LDAP::LdapError, "no bind result"
232+
pdu = read
233+
raise Net::LDAP::LdapError, "no bind result" unless pdu
234+
222235
return pdu unless pdu.result_code == 14 # saslBindInProgress
223236
raise Net::LDAP::LdapError, "sasl-challenge overflow" if ((n += 1) > MaxSaslChallenges)
224237

@@ -395,7 +408,7 @@ def search(args = {})
395408
result_pdu = nil
396409
controls = []
397410

398-
while (be = read) && (pdu = Net::LDAP::PDU.new(be))
411+
while pdu = read
399412
case pdu.app_tag
400413
when Net::LDAP::PDU::SearchReturnedData
401414
n_results += 1
@@ -500,7 +513,11 @@ def modify(args)
500513
ops.to_ber_sequence ].to_ber_appsequence(6)
501514
write(request)
502515

503-
(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
504521

505522
pdu
506523
end
@@ -522,10 +539,11 @@ def add(args)
522539
request = [add_dn.to_ber, add_attrs.to_ber_sequence].to_ber_appsequence(8)
523540
write(request)
524541

525-
(be = read) &&
526-
(pdu = Net::LDAP::PDU.new(be)) &&
527-
(pdu.app_tag == Net::LDAP::PDU::AddResponse) or
542+
pdu = read
543+
544+
if !pdu || pdu.app_tag != Net::LDAP::PDU::AddResponse
528545
raise Net::LDAP::LdapError, "response missing or invalid"
546+
end
529547

530548
pdu
531549
end
@@ -544,9 +562,11 @@ def rename(args)
544562

545563
write(request.to_ber_appsequence(12))
546564

547-
(be = read) &&
548-
(pdu = Net::LDAP::PDU.new( be )) && (pdu.app_tag == Net::LDAP::PDU::ModifyRDNResponse) or
549-
raise Net::LDAP::LdapError.new( "response missing or invalid" )
565+
pdu = read
566+
567+
if !pdu || pdu.app_tag != Net::LDAP::PDU::ModifyRDNResponse
568+
raise Net::LDAP::LdapError.new "response missing or invalid"
569+
end
550570

551571
pdu
552572
end
@@ -560,7 +580,11 @@ def delete(args)
560580
request = dn.to_s.to_ber_application_string(10)
561581
write(request, controls)
562582

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

565589
pdu
566590
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+
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+
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: 22 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -144,6 +144,28 @@ def test_read_net_ldap_connection_event
144144
assert_equal read_result, result
145145
end
146146

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+
147169
def test_bind_net_ldap_connection_event
148170
ber = Net::BER::BerIdentifiedArray.new([0, "", ""])
149171
ber.ber_identifier = Net::LDAP::PDU::BindResult

0 commit comments

Comments
 (0)