Skip to content

Commit ea124f2

Browse files
committed
Merge pull request #139 from ruby-ldap/search-connection-cleanup
Net::LDAP::Connection#search cleanup
2 parents 0aeceaf + 74bb8b3 commit ea124f2

File tree

3 files changed

+62
-41
lines changed

3 files changed

+62
-41
lines changed

lib/net/ldap/connection.rb

Lines changed: 57 additions & 38 deletions
Original file line numberDiff line numberDiff line change
@@ -311,26 +311,45 @@ def encode_sort_controls(sort_definitions)
311311
# type-5 packet, which might never come. We need to support the time-limit
312312
# in the protocol.
313313
#++
314-
def search(args = {})
315-
search_filter = (args && args[:filter]) ||
316-
Net::LDAP::Filter.eq("objectclass", "*")
317-
search_filter = Net::LDAP::Filter.construct(search_filter) if search_filter.is_a?(String)
318-
search_base = (args && args[:base]) || "dc=example, dc=com"
319-
search_attributes = ((args && args[:attributes]) || []).map { |attr| attr.to_s.to_ber}
320-
return_referrals = args && args[:return_referrals] == true
321-
sizelimit = (args && args[:size].to_i) || 0
322-
raise Net::LDAP::LdapError, "invalid search-size" unless sizelimit >= 0
323-
paged_searches_supported = (args && args[:paged_searches_supported])
324-
325-
attributes_only = (args and args[:attributes_only] == true)
326-
scope = args[:scope] || Net::LDAP::SearchScope_WholeSubtree
314+
def search(args = nil)
315+
args ||= {}
316+
317+
# filtering, scoping, search base
318+
# filter: https://tools.ietf.org/html/rfc4511#section-4.5.1.7
319+
# base: https://tools.ietf.org/html/rfc4511#section-4.5.1.1
320+
# scope: https://tools.ietf.org/html/rfc4511#section-4.5.1.2
321+
filter = args[:filter] || Net::LDAP::Filter.eq("objectClass", "*")
322+
base = args[:base]
323+
scope = args[:scope] || Net::LDAP::SearchScope_WholeSubtree
324+
325+
# attr handling
326+
# attrs: https://tools.ietf.org/html/rfc4511#section-4.5.1.8
327+
# attrs_only: https://tools.ietf.org/html/rfc4511#section-4.5.1.6
328+
attrs = Array(args[:attributes])
329+
attrs_only = args[:attributes_only] == true
330+
331+
# references
332+
# refs: https://tools.ietf.org/html/rfc4511#section-4.5.3
333+
# deref: https://tools.ietf.org/html/rfc4511#section-4.5.1.3
334+
refs = args[:return_referrals] == true
335+
deref = args[:deref] || Net::LDAP::DerefAliases_Never
336+
337+
# limiting, paging, sorting
338+
# size: https://tools.ietf.org/html/rfc4511#section-4.5.1.4
339+
size = args[:size].to_i
340+
paged = args[:paged_searches_supported]
341+
sort = args.fetch(:sort_controls, false)
342+
343+
# arg validation
344+
raise Net::LDAP::LdapError, "search base is required" unless base
345+
raise Net::LDAP::LdapError, "invalid search-size" unless size >= 0
327346
raise Net::LDAP::LdapError, "invalid search scope" unless Net::LDAP::SearchScopes.include?(scope)
347+
raise Net::LDAP::LdapError, "invalid alias dereferencing value" unless Net::LDAP::DerefAliasesArray.include?(deref)
328348

329-
sort_control = encode_sort_controls(args.fetch(:sort_controls){ false })
330-
331-
deref = args[:deref] || Net::LDAP::DerefAliases_Never
332-
raise Net::LDAP::LdapError.new( "invalid alias dereferencing value" ) unless Net::LDAP::DerefAliasesArray.include?(deref)
333-
349+
# arg transforms
350+
filter = Net::LDAP::Filter.construct(filter) if filter.is_a?(String)
351+
ber_attrs = attrs.map { |attr| attr.to_s.to_ber }
352+
ber_sort = encode_sort_controls(sort)
334353

335354
# An interesting value for the size limit would be close to A/D's
336355
# built-in page limit of 1000 records, but openLDAP newer than version
@@ -357,35 +376,35 @@ def search(args = {})
357376
n_results = 0
358377

359378
instrument "search.net_ldap_connection",
360-
:filter => search_filter,
361-
:base => search_base,
362-
:scope => scope,
363-
:limit => sizelimit,
364-
:sort => sort_control,
365-
:referrals => return_referrals,
366-
:deref => deref,
367-
:attributes => search_attributes do |payload|
379+
filter: filter,
380+
base: base,
381+
scope: scope,
382+
limit: size,
383+
sort: sort,
384+
referrals: refs,
385+
deref: deref,
386+
attributes: attrs do |payload|
368387
loop do
369388
# should collect this into a private helper to clarify the structure
370389
query_limit = 0
371-
if sizelimit > 0
372-
if paged_searches_supported
373-
query_limit = (((sizelimit - n_results) < 126) ? (sizelimit -
390+
if size > 0
391+
if paged
392+
query_limit = (((size - n_results) < 126) ? (size -
374393
n_results) : 0)
375394
else
376-
query_limit = sizelimit
395+
query_limit = size
377396
end
378397
end
379398

380399
request = [
381-
search_base.to_ber,
400+
base.to_ber,
382401
scope.to_ber_enumerated,
383402
deref.to_ber_enumerated,
384403
query_limit.to_ber, # size limit
385404
0.to_ber,
386-
attributes_only.to_ber,
387-
search_filter.to_ber,
388-
search_attributes.to_ber_sequence
405+
attrs_only.to_ber,
406+
filter.to_ber,
407+
ber_attrs.to_ber_sequence
389408
].to_ber_appsequence(3)
390409

391410
# rfc2696_cookie sometimes contains binary data from Microsoft Active Directory
@@ -399,8 +418,8 @@ def search(args = {})
399418
# Criticality MUST be false to interoperate with normal LDAPs.
400419
false.to_ber,
401420
rfc2696_cookie.map{ |v| v.to_ber}.to_ber_sequence.to_s.to_ber
402-
].to_ber_sequence if paged_searches_supported
403-
controls << sort_control if sort_control
421+
].to_ber_sequence if paged
422+
controls << ber_sort if ber_sort
404423
controls = controls.empty? ? nil : controls.to_ber_contextspecific(0)
405424

406425
write(request, controls)
@@ -414,7 +433,7 @@ def search(args = {})
414433
n_results += 1
415434
yield pdu.search_entry if block_given?
416435
when Net::LDAP::PDU::SearchResultReferral
417-
if return_referrals
436+
if refs
418437
if block_given?
419438
se = Net::LDAP::Entry.new
420439
se[:search_referrals] = (pdu.search_referrals || [])
@@ -424,7 +443,7 @@ def search(args = {})
424443
when Net::LDAP::PDU::SearchResult
425444
result_pdu = pdu
426445
controls = pdu.result_controls
427-
if return_referrals && pdu.result_code == 10
446+
if refs && pdu.result_code == 10
428447
if block_given?
429448
se = Net::LDAP::Entry.new
430449
se[:search_referrals] = (pdu.search_referrals || [])

test/integration/test_delete.rb

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -14,7 +14,9 @@ def setup
1414
sn: "delete-user1",
1515
1616
}
17-
assert @ldap.add(dn: @dn, attributes: attrs), @ldap.get_operation_result.inspect
17+
unless @ldap.search(base: @dn, scope: Net::LDAP::SearchScope_BaseObject)
18+
assert @ldap.add(dn: @dn, attributes: attrs), @ldap.get_operation_result.inspect
19+
end
1820
assert @ldap.search(base: @dn, scope: Net::LDAP::SearchScope_BaseObject)
1921
end
2022

test/test_ldap_connection.rb

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -186,7 +186,7 @@ def test_bind_net_ldap_connection_event
186186
def test_search_net_ldap_connection_event
187187
# search data
188188
search_data_ber = Net::BER::BerIdentifiedArray.new([2, [
189-
"uid=user1,ou=OrgUnit2,ou=OrgUnitTop,dc=openldap,dc=ghe,dc=local",
189+
"uid=user1,ou=People,dc=rubyldap,dc=com",
190190
[ ["uid", ["user1"]] ]
191191
]])
192192
search_data_ber.ber_identifier = Net::LDAP::PDU::SearchReturnedData
@@ -200,7 +200,7 @@ def test_search_net_ldap_connection_event
200200

201201
events = @service.subscribe "search.net_ldap_connection"
202202

203-
result = @connection.search(filter: "(uid=user1)")
203+
result = @connection.search(filter: "(uid=user1)", base: "ou=People,dc=rubyldap,dc=com")
204204
assert result.success?, "should be success"
205205

206206
# a search event

0 commit comments

Comments
 (0)