Significant mods to LDAP#search
This commit is contained in:
parent
193f76e530
commit
7be5474f06
117
lib/net/ldap.rb
117
lib/net/ldap.rb
|
@ -23,6 +23,7 @@ require 'net/ldap/pdu'
|
|||
require 'net/ldap/filter'
|
||||
require 'net/ldap/dataset'
|
||||
require 'net/ldap/psw'
|
||||
require 'net/ldap/entry'
|
||||
|
||||
|
||||
module Net
|
||||
|
@ -372,17 +373,17 @@ module Net
|
|||
# Note that in the standalone case, we're permitting the caller
|
||||
# to modify the auth parms.
|
||||
#
|
||||
def search args
|
||||
def searchx args
|
||||
if @open_connection
|
||||
@result = @open_connection.search( args ) {|values|
|
||||
block_given? and yield( values )
|
||||
@result = @open_connection.searchx( args ) {|values|
|
||||
yield( values ) if block_given?
|
||||
}
|
||||
else
|
||||
@result = 0
|
||||
conn = Connection.new( :host => @host, :port => @port )
|
||||
if (@result = conn.bind( args[:auth] || @auth )) == 0
|
||||
@result = conn.search( args ) {|values|
|
||||
block_given? and yield( values )
|
||||
@result = conn.searchx( args ) {|values|
|
||||
yield( values ) if block_given?
|
||||
}
|
||||
end
|
||||
conn.close
|
||||
|
@ -391,6 +392,49 @@ module Net
|
|||
@result == 0
|
||||
end
|
||||
|
||||
#--
|
||||
# This is a re-implementation of search that replaces the
|
||||
# original one (now renamed searchx and possibly destined to go away).
|
||||
# The difference is that we return a dataset (or nil) from the
|
||||
# call, and pass _each entry_ as it is received from the server
|
||||
# to the caler-supplied block. This will probably make things
|
||||
# far faster as we can do useful work during the network latency
|
||||
# of the search. The downside is that we have no access to the
|
||||
# whole set while processing the blocks, so we can't do stuff
|
||||
# like sort the DNs until after the call completes.
|
||||
# It's also possible that this interacts badly with server timeouts.
|
||||
# We'll have to ensure that something reasonable happens if
|
||||
# the caller has processed half a result set when we throw a timeout
|
||||
# error.
|
||||
# Another important difference is that we return a result set from
|
||||
# this method rather than a T/F indication.
|
||||
# Since this can be very heavy-weight, we define an argument flag
|
||||
# that the caller can set to suppress the return of a result set,
|
||||
# if he's planning to process every entry as it comes from the server.
|
||||
#
|
||||
def search args
|
||||
result_set = (args and args[:return_result] == false) ? nil : {}
|
||||
|
||||
if @open_connection
|
||||
@result = @open_connection.search( args ) {|entry|
|
||||
result_set[entry.dn] = entry if result_set
|
||||
yield( entry ) if block_given?
|
||||
}
|
||||
else
|
||||
@result = 0
|
||||
conn = Connection.new( :host => @host, :port => @port )
|
||||
if (@result = conn.bind( args[:auth] || @auth )) == 0
|
||||
@result = conn.search( args ) {|entry|
|
||||
result_set[entry.dn] = entry if result_set
|
||||
yield( entry ) if block_given?
|
||||
}
|
||||
end
|
||||
conn.close
|
||||
end
|
||||
|
||||
@result == 0 and result_set
|
||||
end
|
||||
|
||||
#
|
||||
# bind
|
||||
# Bind and unbind.
|
||||
|
@ -505,7 +549,7 @@ module Net
|
|||
raise LdapError.new( "no connection to server" )
|
||||
end
|
||||
|
||||
block_given? and yield self
|
||||
yield self if block_given?
|
||||
end
|
||||
|
||||
|
||||
|
@ -552,15 +596,66 @@ module Net
|
|||
|
||||
#
|
||||
# search
|
||||
# Alternate implementation, this yields each search entry to the caller
|
||||
# as it are received.
|
||||
# TODO, certain search parameters are hardcoded.
|
||||
# TODO, if we mis-parse the server results or the results are wrong, we can block
|
||||
# forever. That's because we keep reading results until we get a type-5 packet,
|
||||
# which might never come. We need to support the time-limit in the protocol.
|
||||
#--
|
||||
# WARNING: this code substantially recapitulates the searchx method.
|
||||
#
|
||||
def search args
|
||||
search_filter = (args && args[:filter]) || Filter.eq( "objectclass", "*" )
|
||||
search_base = (args && args[:base]) || "dc=example,dc=com"
|
||||
search_attributes = ((args && args[:attributes]) || []).map {|attr| attr.to_s.to_ber}
|
||||
|
||||
request = [
|
||||
search_base.to_ber,
|
||||
2.to_ber_enumerated,
|
||||
0.to_ber_enumerated,
|
||||
0.to_ber,
|
||||
0.to_ber,
|
||||
false.to_ber,
|
||||
search_filter.to_ber,
|
||||
search_attributes.to_ber_sequence
|
||||
].to_ber_appsequence(3)
|
||||
pkt = [next_msgid.to_ber, request].to_ber_sequence
|
||||
@conn.write pkt
|
||||
|
||||
result_code = 0
|
||||
|
||||
while (be = @conn.read_ber(AsnSyntax)) && (pdu = LdapPdu.new( be ))
|
||||
case pdu.app_tag
|
||||
when 4 # search-data
|
||||
yield( pdu.search_entry ) if block_given?
|
||||
when 5 # search-result
|
||||
result_code = pdu.result_code
|
||||
break
|
||||
else
|
||||
raise LdapError.new( "invalid response-type in search: #{pdu.app_tag}" )
|
||||
end
|
||||
end
|
||||
|
||||
result_code
|
||||
end
|
||||
|
||||
|
||||
#
|
||||
# searchx
|
||||
# Original implementation, this doesn't return until all data have been
|
||||
# received from the server.
|
||||
# TODO, certain search parameters are hardcoded.
|
||||
# TODO, if we mis-parse the server results or the results are wrong, we can block
|
||||
# forever. That's because we keep reading results until we get a type-5 packet,
|
||||
# which might never come. We need to support the time-limit in the protocol.
|
||||
#--
|
||||
# WARNING: this code substantially recapitulates the search method.
|
||||
#
|
||||
def searchx args
|
||||
search_filter = (args && args[:filter]) || Filter.eq( "objectclass", "*" )
|
||||
search_base = (args && args[:base]) || "dc=example,dc=com"
|
||||
search_attributes = ((args && args[:attributes]) || []).map {|attr| attr.to_s.to_ber}
|
||||
request = [
|
||||
search_base.to_ber,
|
||||
2.to_ber_enumerated,
|
||||
|
@ -665,13 +760,3 @@ module Net
|
|||
end # module Net
|
||||
|
||||
|
||||
#------------------------------------------------------
|
||||
|
||||
if __FILE__ == $0
|
||||
puts "No default action"
|
||||
end
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
|
71
lib/net/ldap/entry.rb
Normal file
71
lib/net/ldap/entry.rb
Normal file
|
@ -0,0 +1,71 @@
|
|||
# $Id$
|
||||
#
|
||||
# LDAP Entry (search-result) support classes
|
||||
#
|
||||
#
|
||||
#----------------------------------------------------------------------------
|
||||
#
|
||||
# Copyright (C) 2006 by Francis Cianfrocca. All Rights Reserved.
|
||||
#
|
||||
# Gmail: garbagecat10
|
||||
#
|
||||
# This program is free software; you can redistribute it and/or modify
|
||||
# it under the terms of the GNU General Public License as published by
|
||||
# the Free Software Foundation; either version 2 of the License, or
|
||||
# (at your option) any later version.
|
||||
#
|
||||
# This program is distributed in the hope that it will be useful,
|
||||
# but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
# GNU General Public License for more details.
|
||||
#
|
||||
# You should have received a copy of the GNU General Public License
|
||||
# along with this program; if not, write to the Free Software
|
||||
# Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
|
||||
#
|
||||
#---------------------------------------------------------------------------
|
||||
#
|
||||
|
||||
|
||||
|
||||
|
||||
module Net
|
||||
class LDAP
|
||||
|
||||
|
||||
class Entry
|
||||
|
||||
def initialize dn = nil
|
||||
@myhash = Hash.new {|k,v| k[v] = [] }
|
||||
self[:dn] = [dn]
|
||||
end
|
||||
|
||||
|
||||
def []= name, value
|
||||
sym = name.to_s.downcase.intern
|
||||
@myhash[sym] = value
|
||||
end
|
||||
|
||||
def [] name
|
||||
unless name.is_a?(Symbol)
|
||||
name = name.to_s.downcase.intern
|
||||
end
|
||||
@myhash[name]
|
||||
end
|
||||
|
||||
def dn
|
||||
self[:dn].shift
|
||||
end
|
||||
|
||||
def attribute_names
|
||||
@myhash.keys
|
||||
end
|
||||
|
||||
|
||||
end # class Entry
|
||||
|
||||
|
||||
end # class LDAP
|
||||
end # module Net
|
||||
|
||||
|
|
@ -44,7 +44,7 @@ class LdapPdu
|
|||
ModifyRDNResponse = 13
|
||||
|
||||
attr_reader :msg_id, :app_tag
|
||||
attr_reader :search_dn, :search_attributes
|
||||
attr_reader :search_dn, :search_attributes, :search_entry
|
||||
|
||||
#
|
||||
# initialize
|
||||
|
@ -129,12 +129,17 @@ class LdapPdu
|
|||
# NOW OBSERVE CAREFULLY: WE ARE DOWNCASING THE RETURNED ATTRIBUTE NAMES.
|
||||
# This is to make them more predictable for user programs, but it
|
||||
# may not be a good idea. Maybe this should be configurable.
|
||||
# ALTERNATE IMPLEMENTATION: In addition to @search_dn and @search_attributes,
|
||||
# we also return @search_entry, which is an LDAP::Entry object.
|
||||
# If that works out well, then we'll remove the first two.
|
||||
#
|
||||
def parse_search_return sequence
|
||||
sequence.length >= 2 or raise LdapPduError
|
||||
@search_entry = LDAP::Entry.new( sequence[0] )
|
||||
@search_dn = sequence[0]
|
||||
@search_attributes = {}
|
||||
sequence[1].each {|seq|
|
||||
@search_entry[seq[0]] = seq[1]
|
||||
@search_attributes[seq[0].downcase.intern] = seq[1]
|
||||
}
|
||||
end
|
||||
|
|
Loading…
Reference in a new issue