Rationalizing startup.
This commit is contained in:
parent
87a7cf1b6a
commit
31946c35c7
7 changed files with 66 additions and 139 deletions
|
@ -1,38 +1 @@
|
|||
require 'stringio'
|
||||
require 'openssl'
|
||||
require 'socket'
|
||||
require 'ostruct'
|
||||
require 'base64'
|
||||
require 'strscan'
|
||||
|
||||
if RUBY_VERSION =~ /^1.9/
|
||||
begin
|
||||
SHA1
|
||||
rescue NameError
|
||||
require 'digest/sha1'
|
||||
SHA1 = Digest::SHA1
|
||||
end
|
||||
|
||||
begin
|
||||
MD5
|
||||
rescue NameError
|
||||
require 'digest/md5'
|
||||
MD5 = Digest::MD5
|
||||
end
|
||||
end
|
||||
|
||||
if RUBY_VERSION =~ /^1.8/
|
||||
require 'md5'
|
||||
require 'sha1'
|
||||
end
|
||||
|
||||
module Net
|
||||
autoload :BER, 'net/ber'
|
||||
autoload :LDAP, 'net/ldap'
|
||||
autoload :LDIF, 'net/ldif'
|
||||
autoload :SNMP, 'net/snmp'
|
||||
module BER
|
||||
autoload :BERParser, 'net/ber/ber_parser'
|
||||
end
|
||||
end
|
||||
require 'net/ldap/core_ext/all'
|
||||
require 'net/ldap'
|
||||
|
|
|
@ -1,3 +1,5 @@
|
|||
require 'stringio'
|
||||
|
||||
module Net
|
||||
module BER
|
||||
module BERParser
|
||||
|
@ -105,4 +107,5 @@ module Net
|
|||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
|
|
103
lib/net/ldap.rb
103
lib/net/ldap.rb
|
@ -1,4 +1,5 @@
|
|||
require 'openssl'
|
||||
require 'ostruct'
|
||||
|
||||
require 'net/ber'
|
||||
require 'net/ldap/pdu'
|
||||
|
@ -9,7 +10,6 @@ require 'net/ldap/entry'
|
|||
require 'net/ldap/core_ext/all'
|
||||
|
||||
module Net
|
||||
|
||||
# == Net::LDAP
|
||||
#
|
||||
# This library provides a pure-Ruby implementation of the
|
||||
|
@ -231,14 +231,10 @@ module Net
|
|||
# and then disconnect from the server. The exception is Net::LDAP#open, which makes a connection
|
||||
# to the server and then keeps it open while it executes a user-supplied block. Net::LDAP#open
|
||||
# closes the connection on completion of the block.
|
||||
#
|
||||
|
||||
class LDAP
|
||||
|
||||
class LdapError < StandardError; end
|
||||
|
||||
VERSION = "0.0.5"
|
||||
|
||||
VERSION = "0.5.0"
|
||||
|
||||
SearchScope_BaseObject = 0
|
||||
SearchScope_SingleLevel = 1
|
||||
|
@ -322,23 +318,17 @@ module Net
|
|||
68 => "Entry Already Exists"
|
||||
}
|
||||
|
||||
|
||||
module LdapControls
|
||||
PagedResults = "1.2.840.113556.1.4.319" # Microsoft evil from RFC 2696
|
||||
end
|
||||
|
||||
|
||||
#
|
||||
# LDAP::result2string
|
||||
#
|
||||
def LDAP::result2string code # :nodoc:
|
||||
ResultStrings[code] || "unknown result (#{code})"
|
||||
end
|
||||
|
||||
|
||||
attr_accessor :host, :port, :base
|
||||
|
||||
|
||||
# Instantiate an object of type Net::LDAP to perform directory operations.
|
||||
# This constructor takes a Hash containing arguments, all of which are either optional or may be specified later with other methods as described below. The following arguments
|
||||
# are supported:
|
||||
|
@ -457,7 +447,6 @@ module Net
|
|||
@encryption = args
|
||||
end
|
||||
|
||||
|
||||
# #open takes the same parameters as #new. #open makes a network connection to the
|
||||
# LDAP server and then passes a newly-created Net::LDAP object to the caller-supplied block.
|
||||
# Within the block, you can call any of the instance methods of Net::LDAP to
|
||||
|
@ -478,24 +467,25 @@ module Net
|
|||
ldap1.open {|ldap| yield ldap }
|
||||
end
|
||||
|
||||
# Returns a meaningful result any time after
|
||||
# a protocol operation (#bind, #search, #add, #modify, #rename, #delete)
|
||||
# has completed.
|
||||
# It returns an #OpenStruct containing an LDAP result code (0 means success),
|
||||
# and a human-readable string.
|
||||
# Returns a meaningful result any time after a protocol operation
|
||||
# (#bind, #search, #add, #modify, #rename, #delete) has completed.
|
||||
# It returns an #OpenStruct containing an LDAP result code (0 means
|
||||
# success), and a human-readable string.
|
||||
#
|
||||
# unless ldap.bind
|
||||
# puts "Result: #{ldap.get_operation_result.code}"
|
||||
# puts "Message: #{ldap.get_operation_result.message}"
|
||||
# end
|
||||
#
|
||||
# Certain operations return additional information, accessible through members
|
||||
# of the object returned from #get_operation_result. Check #get_operation_result.error_message
|
||||
# and #get_operation_result.matched_dn.
|
||||
# Certain operations return additional information, accessible through
|
||||
# members of the object returned from #get_operation_result. Check
|
||||
# #get_operation_result.error_message and
|
||||
# #get_operation_result.matched_dn.
|
||||
#
|
||||
#--
|
||||
# Modified the implementation, 20Mar07. We might get a hash of LDAP response codes
|
||||
# instead of a simple numeric code.
|
||||
#
|
||||
# Modified the implementation, 20Mar07. We might get a hash of LDAP
|
||||
# response codes instead of a simple numeric code.
|
||||
#++
|
||||
def get_operation_result
|
||||
os = OpenStruct.new
|
||||
if @result.is_a?(Hash)
|
||||
|
@ -511,7 +501,6 @@ module Net
|
|||
os
|
||||
end
|
||||
|
||||
|
||||
# Opens a network connection to the server and then
|
||||
# passes <tt>self</tt> to the caller-supplied block. The connection is
|
||||
# closed when the block completes. Used for executing multiple
|
||||
|
@ -535,6 +524,7 @@ module Net
|
|||
# We then pass self to the caller's block, where he will execute
|
||||
# his LDAP operations. Of course they will all generate auth failures
|
||||
# if the bind was unsuccessful.
|
||||
#++
|
||||
def open
|
||||
raise LdapError.new( "open already in progress" ) if @open_connection
|
||||
begin
|
||||
|
@ -547,7 +537,6 @@ module Net
|
|||
end
|
||||
end
|
||||
|
||||
|
||||
# Searches the LDAP directory for directory entries.
|
||||
# Takes a hash argument with parameters. Supported parameters include:
|
||||
# * :base (a string specifying the tree-base for the search);
|
||||
|
@ -625,7 +614,7 @@ module Net
|
|||
# handle DNs. Change it to a plain array. Eventually we may
|
||||
# want to return a Dataset object that delegates to an internal
|
||||
# array, so we can provide sort methods and what-not.
|
||||
#
|
||||
#++
|
||||
def search args = {}
|
||||
unless args[:ignore_server_caps]
|
||||
args[:paged_searches_supported] = paged_searches_supported?
|
||||
|
@ -718,7 +707,7 @@ module Net
|
|||
# If there is an @open_connection, then perform the bind
|
||||
# on it. Otherwise, connect, bind, and disconnect.
|
||||
# The latter operation is obviously useful only as an auth check.
|
||||
#
|
||||
#++
|
||||
def bind(auth=@auth)
|
||||
if @open_connection
|
||||
@result = @open_connection.bind auth
|
||||
|
@ -734,7 +723,6 @@ module Net
|
|||
@result == 0
|
||||
end
|
||||
|
||||
|
||||
#
|
||||
# #bind_as is for testing authentication credentials.
|
||||
#
|
||||
|
@ -794,7 +782,6 @@ module Net
|
|||
result
|
||||
end
|
||||
|
||||
|
||||
# Adds a new entry to the remote LDAP server.
|
||||
# Supported arguments:
|
||||
# :dn :: Full DN of the new entry
|
||||
|
@ -821,7 +808,7 @@ module Net
|
|||
#--
|
||||
# Provisional modification: Connection#add returns a full hash with LDAP status values,
|
||||
# instead of the simple result number we're used to getting.
|
||||
#
|
||||
#++
|
||||
def add args
|
||||
if @open_connection
|
||||
@result = @open_connection.add( args )
|
||||
|
@ -839,7 +826,6 @@ module Net
|
|||
@result == 0
|
||||
end
|
||||
|
||||
|
||||
# Modifies the attribute values of a particular entry on the LDAP directory.
|
||||
# Takes a hash with arguments. Supported arguments are:
|
||||
# :dn :: (the full DN of the entry whose attributes are to be modified)
|
||||
|
@ -937,7 +923,6 @@ module Net
|
|||
@result == 0
|
||||
end
|
||||
|
||||
|
||||
# Add a value to an attribute.
|
||||
# Takes the full DN of the entry to modify,
|
||||
# the name (Symbol or String) of the attribute, and the value (String or
|
||||
|
@ -991,7 +976,6 @@ module Net
|
|||
modify :dn => dn, :operations => [[:delete, attribute, nil]]
|
||||
end
|
||||
|
||||
|
||||
# Rename an entry on the remote DIS by changing the last RDN of its DN.
|
||||
# _Documentation_ _stub_
|
||||
#
|
||||
|
@ -1045,7 +1029,6 @@ module Net
|
|||
@result == 0
|
||||
end
|
||||
|
||||
|
||||
# (Experimental, subject to change).
|
||||
# Return the rootDSE record from the LDAP server as a Net::LDAP::Entry, or an
|
||||
# empty Entry if the server doesn't return the record.
|
||||
|
@ -1058,7 +1041,7 @@ module Net
|
|||
# We may be called by #search itself, which may need to determine things like paged
|
||||
# search capabilities. So to avoid an infinite regress, set :ignore_server_caps,
|
||||
# which prevents us getting called recursively.
|
||||
#
|
||||
#++
|
||||
def search_root_dse
|
||||
rs = search(
|
||||
:ignore_server_caps=>true,
|
||||
|
@ -1069,7 +1052,6 @@ module Net
|
|||
(rs and rs.first) or Entry.new
|
||||
end
|
||||
|
||||
|
||||
# Return the root Subschema record from the LDAP server as a Net::LDAP::Entry,
|
||||
# or an empty Entry if the server doesn't return the record. On success, the
|
||||
# Net::LDAP::Entry returned from this call will have the attributes :dn,
|
||||
|
@ -1093,7 +1075,7 @@ module Net
|
|||
# The :dn attribute in the returned Entry is the subschema name as returned from
|
||||
# the server.
|
||||
# Set :ignore_server_caps, see the notes in search_root_dse.
|
||||
#
|
||||
#++
|
||||
def search_subschema_entry
|
||||
rs = search(
|
||||
:ignore_server_caps=>true,
|
||||
|
@ -1116,30 +1098,25 @@ module Net
|
|||
(rs and rs.first) or Entry.new
|
||||
end
|
||||
|
||||
|
||||
#--
|
||||
# Convenience method to query server capabilities.
|
||||
# Only do this once per Net::LDAP object.
|
||||
# Note, we call a search, and we might be called from inside a search!
|
||||
# MUST refactor the root_dse call out.
|
||||
#++
|
||||
def paged_searches_supported?
|
||||
@server_caps ||= search_root_dse
|
||||
@server_caps[:supportedcontrol].include?(LdapControls::PagedResults)
|
||||
end
|
||||
|
||||
end # class LDAP
|
||||
|
||||
class LDAP
|
||||
# This is a private class used internally by the library. It should not be called by user code.
|
||||
# This is a private class used internally by the library. It should not
|
||||
# be called by user code.
|
||||
class Connection # :nodoc:
|
||||
|
||||
LdapVersion = 3
|
||||
MaxSaslChallenges = 10
|
||||
|
||||
|
||||
#--
|
||||
# initialize
|
||||
#
|
||||
def initialize server
|
||||
begin
|
||||
@conn = TCPSocket.new( server[:host], server[:port] )
|
||||
|
@ -1159,6 +1136,7 @@ module Net
|
|||
getc.ord
|
||||
end
|
||||
end
|
||||
|
||||
def self.wrap_with_ssl(io)
|
||||
ctx = OpenSSL::SSL::SSLContext.new
|
||||
conn = OpenSSL::SSL::SSLSocket.new(io, ctx)
|
||||
|
@ -1195,7 +1173,7 @@ module Net
|
|||
# It does not require an alternative port for encrypted communications, as with
|
||||
# simple_tls.
|
||||
# Thanks for Kouhei Sutou for generously contributing the :start_tls path.
|
||||
#
|
||||
#++
|
||||
def setup_encryption args
|
||||
case args[:method]
|
||||
when :simple_tls
|
||||
|
@ -1226,6 +1204,7 @@ module Net
|
|||
# sure a connection object gets closed without waiting
|
||||
# for a GC to happen. Clients shouldn't have to call it,
|
||||
# but perhaps it will come in handy someday.
|
||||
#++
|
||||
def close
|
||||
@conn.close
|
||||
@conn = nil
|
||||
|
@ -1233,16 +1212,15 @@ module Net
|
|||
|
||||
#--
|
||||
# next_msgid
|
||||
#
|
||||
#++
|
||||
def next_msgid
|
||||
@msgid ||= 0
|
||||
@msgid += 1
|
||||
end
|
||||
|
||||
|
||||
#--
|
||||
# bind
|
||||
#
|
||||
#++
|
||||
def bind auth
|
||||
meth = auth[:method]
|
||||
if [:simple, :anonymous, :anon].include?( meth )
|
||||
|
@ -1260,7 +1238,7 @@ module Net
|
|||
# bind_simple
|
||||
# Implements a simple user/psw authentication.
|
||||
# Accessed by calling #bind with a method of :simple or :anonymous.
|
||||
#
|
||||
#++
|
||||
def bind_simple auth
|
||||
user,psw = if auth[:method] == :simple
|
||||
[auth[:username] || auth[:dn], auth[:password]]
|
||||
|
@ -1292,7 +1270,7 @@ module Net
|
|||
# field of the LDAP BindResponse packet. The challenge-response block may be called multiple
|
||||
# times during the course of a SASL authentication, and each time it must return a value
|
||||
# that will be passed back to the server as the credential data in the next BindRequest packet.
|
||||
#
|
||||
#++
|
||||
def bind_sasl auth
|
||||
mech,cred,chall = auth[:mechanism],auth[:initial_credential],auth[:challenge_response]
|
||||
raise LdapError.new( "invalid binding information" ) unless (mech && cred && chall)
|
||||
|
@ -1325,7 +1303,7 @@ module Net
|
|||
# :gss_spnego. It requires :username and :password attributes, just like the :simple
|
||||
# authentication method. It performs a GSS-SPNEGO authentication with the server, which
|
||||
# is presumed to be a Microsoft Active Directory.
|
||||
#
|
||||
#++
|
||||
def bind_gss_spnego auth
|
||||
require 'ntlm.rb'
|
||||
|
||||
|
@ -1365,7 +1343,7 @@ module Net
|
|||
# This implementation is kindof clunky and should probably be refactored.
|
||||
# Also, is it my imagination, or are A/Ds the slowest directory servers ever???
|
||||
# OpenLDAP newer than version 2.2.0 supports paged searches.
|
||||
#
|
||||
#++
|
||||
def search args = {}
|
||||
search_filter = (args && args[:filter]) || Filter.eq( "objectclass", "*" )
|
||||
search_filter = Filter.construct(search_filter) if search_filter.is_a?(String)
|
||||
|
@ -1496,8 +1474,6 @@ module Net
|
|||
result_code
|
||||
end
|
||||
|
||||
|
||||
|
||||
#--
|
||||
# modify
|
||||
# TODO, need to support a time limit, in case the server fails to respond.
|
||||
|
@ -1505,7 +1481,7 @@ module Net
|
|||
# Should return a proper error instead, probaby from farther up the chain.
|
||||
# TODO!!! If the user specifies a bogus opcode, we'll throw a
|
||||
# confusing error here ("to_ber_enumerated is not defined on nil").
|
||||
#
|
||||
#++
|
||||
def modify args
|
||||
modify_dn = args[:dn] or raise "Unable to modify empty DN"
|
||||
modify_ops = []
|
||||
|
@ -1524,7 +1500,6 @@ module Net
|
|||
pdu.result
|
||||
end
|
||||
|
||||
|
||||
#--
|
||||
# add
|
||||
# TODO, need to support a time limit, in case the server fails to respond.
|
||||
|
@ -1532,7 +1507,7 @@ module Net
|
|||
# than a simple result number. This is experimental, and eventually we'll want
|
||||
# to do this with all the others. The point is to have access to the error message
|
||||
# and the matched-DN returned by the server.
|
||||
#
|
||||
#++
|
||||
def add args
|
||||
add_dn = args[:dn] or raise LdapError.new("Unable to add empty DN")
|
||||
add_attrs = []
|
||||
|
@ -1548,11 +1523,10 @@ module Net
|
|||
pdu.result
|
||||
end
|
||||
|
||||
|
||||
#--
|
||||
# rename
|
||||
# TODO, need to support a time limit, in case the server fails to respond.
|
||||
#
|
||||
#++
|
||||
def rename args
|
||||
old_dn = args[:olddn] or raise "Unable to rename empty DN"
|
||||
new_rdn = args[:newrdn] or raise "Unable to rename to empty RDN"
|
||||
|
@ -1566,11 +1540,10 @@ module Net
|
|||
pdu.result_code
|
||||
end
|
||||
|
||||
|
||||
#--
|
||||
# delete
|
||||
# TODO, need to support a time limit, in case the server fails to respond.
|
||||
#
|
||||
#++
|
||||
def delete args
|
||||
dn = args[:dn] or raise "Unable to delete empty DN"
|
||||
|
||||
|
@ -1581,10 +1554,6 @@ module Net
|
|||
(be = @conn.read_ber(AsnSyntax)) && (pdu = LdapPdu.new( be )) && (pdu.app_tag == 11) or raise LdapError.new( "response missing or invalid" )
|
||||
pdu.result_code
|
||||
end
|
||||
|
||||
|
||||
end # class Connection
|
||||
end # class LDAP
|
||||
end # module Net
|
||||
|
||||
|
||||
|
|
|
@ -490,5 +490,3 @@ end # class Net::LDAP::FilterParser
|
|||
|
||||
end # class Net::LDAP
|
||||
end # module Net
|
||||
|
||||
|
||||
|
|
|
@ -1,4 +1,3 @@
|
|||
# $Id$
|
||||
#
|
||||
# LDAP PDU support classes
|
||||
#
|
||||
|
@ -24,12 +23,12 @@
|
|||
#
|
||||
#---------------------------------------------------------------------------
|
||||
|
||||
module Net
|
||||
require 'ostruct'
|
||||
|
||||
module Net
|
||||
class LdapPduError < StandardError; end
|
||||
|
||||
class LdapPdu
|
||||
|
||||
BindRequest = 0
|
||||
BindResult = 1
|
||||
UnbindRequest = 2
|
||||
|
|
|
@ -1,6 +1,3 @@
|
|||
# $Id$
|
||||
#
|
||||
#
|
||||
#----------------------------------------------------------------------------
|
||||
#
|
||||
# Copyright (C) 2006 by Francis Cianfrocca. All Rights Reserved.
|
||||
|
@ -22,41 +19,39 @@
|
|||
# Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
|
||||
#
|
||||
#---------------------------------------------------------------------------
|
||||
#
|
||||
#
|
||||
|
||||
require 'digest/sha1'
|
||||
require 'digest/md5'
|
||||
|
||||
module Net
|
||||
class LDAP
|
||||
class Password
|
||||
class << self
|
||||
|
||||
# Generate a password-hash suitable for inclusion in an LDAP attribute.
|
||||
# Pass a hash type (currently supported: :md5 and :sha) and a plaintext
|
||||
# password. This function will return a hashed representation.
|
||||
# STUB: This is here to fulfill the requirements of an RFC, which one?
|
||||
# TODO, gotta do salted-sha and (maybe) salted-md5.
|
||||
# Should we provide sha1 as a synonym for sha1? I vote no because then
|
||||
# should you also provide ssha1 for symmetry?
|
||||
def generate( type, str )
|
||||
# Generate a password-hash suitable for inclusion in an LDAP
|
||||
# attribute. Pass a hash type (currently supported: :md5 and :sha)
|
||||
# and a plaintext password. This function will return a hashed
|
||||
# representation.
|
||||
#
|
||||
# STUB: This is here to fulfill the requirements of an RFC, which
|
||||
# one?
|
||||
#
|
||||
# TODO, gotta do salted-sha and (maybe) salted-md5.
|
||||
# Should we provide sha1 as a synonym for sha1? I vote no because
|
||||
# then should you also provide ssha1 for symmetry?
|
||||
def generate(type, str)
|
||||
digest, digest_name = case type
|
||||
when :md5
|
||||
[Digest::MD5.new, 'MD5']
|
||||
when :sha
|
||||
[Digest::SHA1.new, 'SHA']
|
||||
# when ssha
|
||||
else
|
||||
raise Net::LDAP::LdapError.new( "unsupported password-hash type (#{type})" )
|
||||
end
|
||||
|
||||
when :md5
|
||||
[Digest::MD5.new, 'MD5']
|
||||
when :sha
|
||||
[Digest::SHA1.new, 'SHA']
|
||||
else
|
||||
raise Net::LDAP::LdapError.new("unsupported password-hash type (#{type})")
|
||||
end
|
||||
|
||||
digest << str.to_s
|
||||
return "{#{digest_name}}#{[digest.digest].pack('m').chomp }"
|
||||
end
|
||||
|
||||
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
|
||||
|
|
|
@ -1,3 +1,3 @@
|
|||
# Add 'lib' to load path.
|
||||
require 'test/unit'
|
||||
require 'net'
|
||||
require 'net/ldap'
|
||||
|
|
Loading…
Reference in a new issue