Compare commits
57 Commits
Author | SHA1 | Date |
---|---|---|
Denis Knauf | 7438a2ab45 | |
Rory O'Connell | 8a182675f4 | |
Rory O'Connell | ccd7b6da5b | |
Rory O'Connell | 8acd4acc5b | |
Rory O'Connell | 8ddb2d7c84 | |
Rory O'Connell | 9de9bc755b | |
Rory O'Connell | b6d9fbebfd | |
Esa-Matti Suuronen | 717132f224 | |
Harold A. Jones II | 656039cee0 | |
Francisco R. Santos | d6aa24ebea | |
Markus Bucher | b63e5c4930 | |
Jesse Callaway | aa677d0471 | |
Rory OConnell | 51597eae9a | |
Rory OConnell | a102054bbf | |
Rory OConnell | 4ab764558f | |
David J. Lee | 9fa0b982b7 | |
David J. Lee | 9a9d5f0742 | |
David J. Lee | c46c93777e | |
Rory OConnell | 3345c58dfb | |
Rory OConnell | 373304d812 | |
Rory OConnell | cba57eb50d | |
Rory OConnell | 5467ecf6cd | |
Rory OConnell | 995ddaa4e2 | |
MichaelBaker | ad4493b104 | |
MichaelBaker | 09e372ee63 | |
Christopher Dwan | b13c71d265 | |
Chris Dwan | 4c24b4ea36 | |
Rory O'Connell | 76a81cce4a | |
Oleg Barenboim | 8a106ca64f | |
Rory O'Connell | a1bf790784 | |
Ivar Vasara | b94bba9773 | |
Michael Baker | 40f0e1857e | |
Michael Baker | 2763040162 | |
Michael Baker | 63db8c836a | |
radixhound | 528ef30801 | |
Chris Dwan | 58bd212918 | |
Chris Dwan | b6b7985d6e | |
Chris Dwan | 463ac436a8 | |
Rory O'Connell | 6bb9fa6ae6 | |
Daniel Abrahamsson | 2a74577d5f | |
Rory O'Connell | 5344d73543 | |
Rory O'Connell | dac73f46d2 | |
Rory O'Connell | 6d7be69653 | |
Rory O'Connell | 5c3cbb7fe6 | |
Daniel Abrahamsson | 2336188503 | |
Daniel Abrahamsson | a4819e525f | |
Daniel Abrahamsson | 42bdeb93d8 | |
Martin Carpenter | d2e00dfd58 | |
Daniel Abrahamsson | 3a8b8a2e00 | |
Daniel Abrahamsson | c90821a7bd | |
Daniel Abrahamsson | c11ec44258 | |
Ian Yang | f102f50d9c | |
Martin Carpenter | 41bee0a690 | |
Martin Carpenter | 41b230d9bc | |
Rory O'Connell | 7dd6c3a107 | |
dulanov | c9bd8b4b3d | |
Austin Ziegler | 028cdeebbd |
|
@ -9,3 +9,4 @@ publish/
|
|||
coverage/
|
||||
coverage.info
|
||||
.rake_tasks~
|
||||
Gemfile.lock
|
||||
|
|
|
@ -19,3 +19,4 @@ Contributions since:
|
|||
* Derek Harmel (derekharmel)
|
||||
* Erik Hetzner (egh)
|
||||
* nowhereman
|
||||
* David J. Lee (DavidJLee)
|
||||
|
|
18
History.rdoc
18
History.rdoc
|
@ -1,3 +1,21 @@
|
|||
=== Net::LDAP 0.3.1 / 2012-02-15
|
||||
* Bug Fixes:
|
||||
* Bundler should now work again
|
||||
|
||||
=== Net::LDAP 0.3.0 / 2012-02-14
|
||||
* Major changes:
|
||||
* Now uses UTF-8 strings instead of ASCII-8 per the LDAP RFC
|
||||
* Major Enhancements:
|
||||
* Adding continuation reference processing
|
||||
* Bug Fixes:
|
||||
* Fixes usupported object type #139
|
||||
* Fixes Net::LDAP namespace errors
|
||||
* Return nil instead of an empty array if the search fails
|
||||
|
||||
=== Net::LDAP 0.2.2 / 2011-03-26
|
||||
* Bug Fixes:
|
||||
* Fixed the call to Net::LDAP.modify_ops from Net::LDAP#modify.
|
||||
|
||||
=== Net::LDAP 0.2.1 / 2011-03-23
|
||||
* Bug Fixes:
|
||||
* Net::LDAP.modify_ops was broken and is now fixed.
|
||||
|
|
3
Rakefile
3
Rakefile
|
@ -6,7 +6,6 @@ require 'hoe'
|
|||
Hoe.plugin :doofus
|
||||
Hoe.plugin :git
|
||||
Hoe.plugin :gemspec
|
||||
Hoe.plugin :rubyforge
|
||||
|
||||
Hoe.spec 'net-ldap' do |spec|
|
||||
spec.rubyforge_name = spec.name
|
||||
|
@ -20,7 +19,7 @@ Hoe.spec 'net-ldap' do |spec|
|
|||
spec.remote_rdoc_dir = ''
|
||||
spec.rsync_args << ' --exclude=statsvn/'
|
||||
|
||||
spec.url = %W(http://net-ldap.rubyforge.org/ https://github.com/ruby-ldap/ruby-net-ldap)
|
||||
spec.url = %W(http://rubyldap.com/ https://github.com/ruby-ldap/ruby-net-ldap)
|
||||
|
||||
spec.history_file = 'History.rdoc'
|
||||
spec.readme_file = 'README.rdoc'
|
||||
|
|
|
@ -106,7 +106,7 @@ module Net # :nodoc:
|
|||
# <tr><th>BMPString</th><th>C</th><td>30: 62 (0x3e, 0b00111110)</td></tr>
|
||||
# </table>
|
||||
module BER
|
||||
VERSION = '0.2.1'
|
||||
VERSION = '0.4.0'
|
||||
|
||||
##
|
||||
# Used for BER-encoding the length and content bytes of a Fixnum integer
|
||||
|
@ -295,6 +295,8 @@ class Net::BER::BerIdentifiedString < String
|
|||
attr_accessor :ber_identifier
|
||||
def initialize args
|
||||
super args
|
||||
# LDAP uses UTF-8 encoded strings
|
||||
force_encoding('UTF-8') if respond_to?(:encoding)
|
||||
end
|
||||
end
|
||||
|
||||
|
|
|
@ -79,4 +79,18 @@ module Net::BER::Extensions::Array
|
|||
oid = ary.pack("w*")
|
||||
[6, oid.length].pack("CC") + oid
|
||||
end
|
||||
|
||||
##
|
||||
# Converts an array into a set of ber control codes
|
||||
# The expected format is [[control_oid, criticality, control_value(optional)]]
|
||||
# [['1.2.840.113556.1.4.805',true]]
|
||||
#
|
||||
def to_ber_control
|
||||
#if our array does not contain at least one array then wrap it in an array before going forward
|
||||
ary = self[0].kind_of?(Array) ? self : [self]
|
||||
ary = ary.collect do |control_sequence|
|
||||
control_sequence.collect{|element| element.to_ber}.to_ber_sequence.reject_empty_ber_arrays
|
||||
end
|
||||
ary.to_ber_sequence.reject_empty_ber_arrays
|
||||
end
|
||||
end
|
||||
|
|
|
@ -12,9 +12,33 @@ module Net::BER::Extensions::String
|
|||
# User code should call either #to_ber_application_string or
|
||||
# #to_ber_contextspecific.
|
||||
def to_ber(code = 0x04)
|
||||
[code].pack('C') + length.to_ber_length_encoding + self
|
||||
raw_string = raw_utf8_encoded
|
||||
[code].pack('C') + raw_string.length.to_ber_length_encoding + raw_string
|
||||
end
|
||||
|
||||
##
|
||||
# Converts a string to a BER string but does *not* encode to UTF-8 first.
|
||||
# This is required for proper representation of binary data for Microsoft
|
||||
# Active Directory
|
||||
def to_ber_bin(code = 0x04)
|
||||
[code].pack('C') + length.to_ber_length_encoding + self
|
||||
end
|
||||
|
||||
def raw_utf8_encoded
|
||||
if self.respond_to?(:encode)
|
||||
# Strings should be UTF-8 encoded according to LDAP.
|
||||
# However, the BER code is not necessarily valid UTF-8
|
||||
begin
|
||||
self.encode('UTF-8').force_encoding('ASCII-8BIT')
|
||||
rescue Encoding::UndefinedConversionError
|
||||
self
|
||||
end
|
||||
else
|
||||
self
|
||||
end
|
||||
end
|
||||
private :raw_utf8_encoded
|
||||
|
||||
##
|
||||
# Creates an application-specific BER string encoded value with the
|
||||
# provided syntax code value.
|
||||
|
@ -34,15 +58,19 @@ module Net::BER::Extensions::String
|
|||
def read_ber(syntax = nil)
|
||||
StringIO.new(self).read_ber(syntax)
|
||||
end
|
||||
|
||||
|
||||
##
|
||||
# Destructively reads a BER object from the string.
|
||||
# Destructively reads a BER object from the string.
|
||||
def read_ber!(syntax = nil)
|
||||
io = StringIO.new(self)
|
||||
|
||||
result = io.read_ber(syntax)
|
||||
self.slice!(0...io.pos)
|
||||
|
||||
|
||||
return result
|
||||
end
|
||||
|
||||
def reject_empty_ber_arrays
|
||||
self.gsub(/0\000/n,'')
|
||||
end
|
||||
end
|
||||
|
|
259
lib/net/ldap.rb
259
lib/net/ldap.rb
|
@ -241,9 +241,36 @@ require 'net/ldap/entry'
|
|||
# and then keeps it open while it executes a user-supplied block.
|
||||
# Net::LDAP#open closes the connection on completion of the block.
|
||||
class Net::LDAP
|
||||
VERSION = "0.2.1"
|
||||
VERSION = "0.4.0"
|
||||
|
||||
class LdapError < StandardError; end
|
||||
class AlreadyOpenedError < LdapError; end
|
||||
class SocketError < LdapError; end
|
||||
class ConnectionRefusedError < LdapError; end
|
||||
class NoOpenSSLError < LdapError; end
|
||||
class NoStartTLSResultError < LdapError; end
|
||||
class StartTLSError < LdapError; end
|
||||
class EncryptionUnsupportedError < LdapError; end
|
||||
class EncMethodUnsupportedError < LdapError; end
|
||||
class AuthMethodUnsupportedError < LdapError; end
|
||||
class BindingInformationInvalidError < LdapError; end
|
||||
class NoBindResultError < LdapError; end
|
||||
class SASLChallengeOverflowError < LdapError; end
|
||||
class SearchSizeInvalidError < LdapError; end
|
||||
class SearchScopeInvalidError < LdapError; end
|
||||
class ResponseTypeInvalidError < LdapError; end
|
||||
class ResponseMissingOrInvalidError < LdapError; end
|
||||
class EmptyDNError < LdapError; end
|
||||
class HashTypeUnsupportedError < LdapError; end
|
||||
class OperatorError < LdapError; end
|
||||
class SubstringFilterError < LdapError; end
|
||||
class SearchFilterError < LdapError; end
|
||||
class BERInvalidError < LdapError; end
|
||||
class SearchFilterTypeUnknownError < LdapError; end
|
||||
class BadAttributeError < LdapError; end
|
||||
class FilterTypeUnknownError < LdapError; end
|
||||
class FilterSyntaxInvalidError < LdapError; end
|
||||
class EntryOverflowError < LdapError; end
|
||||
|
||||
SearchScope_BaseObject = 0
|
||||
SearchScope_SingleLevel = 1
|
||||
|
@ -308,6 +335,7 @@ class Net::LDAP
|
|||
DefaultPort = 389
|
||||
DefaultAuth = { :method => :anonymous }
|
||||
DefaultTreebase = "dc=com"
|
||||
DefaultForceNoPage = false
|
||||
|
||||
StartTlsOid = "1.3.6.1.4.1.1466.20037"
|
||||
|
||||
|
@ -317,10 +345,12 @@ class Net::LDAP
|
|||
2 => "Protocol Error",
|
||||
3 => "Time Limit Exceeded",
|
||||
4 => "Size Limit Exceeded",
|
||||
10 => "Referral",
|
||||
12 => "Unavailable crtical extension",
|
||||
14 => "saslBindInProgress",
|
||||
16 => "No Such Attribute",
|
||||
17 => "Undefined Attribute Type",
|
||||
19 => "Constraint Violation",
|
||||
20 => "Attribute or Value Exists",
|
||||
32 => "No Such Object",
|
||||
34 => "Invalid DN Syntax",
|
||||
|
@ -334,8 +364,11 @@ class Net::LDAP
|
|||
68 => "Entry Already Exists"
|
||||
}
|
||||
|
||||
module LdapControls
|
||||
PagedResults = "1.2.840.113556.1.4.319" # Microsoft evil from RFC 2696
|
||||
module LDAPControls
|
||||
PAGED_RESULTS = "1.2.840.113556.1.4.319" # Microsoft evil from RFC 2696
|
||||
SORT_REQUEST = "1.2.840.113556.1.4.473"
|
||||
SORT_RESPONSE = "1.2.840.113556.1.4.474"
|
||||
DELETE_TREE = "1.2.840.113556.1.4.805"
|
||||
end
|
||||
|
||||
def self.result2string(code) #:nodoc:
|
||||
|
@ -369,6 +402,8 @@ class Net::LDAP
|
|||
# specifying the Hash {:method => :simple_tls}. There is a fairly large
|
||||
# range of potential values that may be given for this parameter. See
|
||||
# #encryption for details.
|
||||
# * :force_no_page => Set to true to prevent paged results even if your
|
||||
# server says it supports them. This is a fix for MS Active Directory
|
||||
#
|
||||
# Instantiating a Net::LDAP object does <i>not</i> result in network
|
||||
# traffic to the LDAP server. It simply stores the connection and binding
|
||||
|
@ -379,6 +414,7 @@ class Net::LDAP
|
|||
@verbose = false # Make this configurable with a switch on the class.
|
||||
@auth = args[:auth] || DefaultAuth
|
||||
@base = args[:base] || DefaultTreebase
|
||||
@force_no_page = args[:force_no_page] || DefaultForceNoPage
|
||||
encryption args[:encryption] # may be nil
|
||||
|
||||
if pr = @auth[:password] and pr.respond_to?(:call)
|
||||
|
@ -515,15 +551,17 @@ class Net::LDAP
|
|||
# response codes instead of a simple numeric code.
|
||||
#++
|
||||
def get_operation_result
|
||||
result = @result
|
||||
result = result.result if result.is_a?(Net::LDAP::PDU)
|
||||
os = OpenStruct.new
|
||||
if @result.is_a?(Hash)
|
||||
if result.is_a?(Hash)
|
||||
# We might get a hash of LDAP response codes instead of a simple
|
||||
# numeric code.
|
||||
os.code = (@result[:resultCode] || "").to_i
|
||||
os.error_message = @result[:errorMessage]
|
||||
os.matched_dn = @result[:matchedDN]
|
||||
elsif @result
|
||||
os.code = @result
|
||||
os.code = (result[:resultCode] || "").to_i
|
||||
os.error_message = result[:errorMessage]
|
||||
os.matched_dn = result[:matchedDN]
|
||||
elsif result
|
||||
os.code = result
|
||||
else
|
||||
os.code = 0
|
||||
end
|
||||
|
@ -552,7 +590,7 @@ class Net::LDAP
|
|||
# anything with the bind results. 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.
|
||||
raise Net::LDAP::LdapError, "Open already in progress" if @open_connection
|
||||
raise Net::LDAP::AlreadyOpenedError, "Open already in progress" if @open_connection
|
||||
|
||||
begin
|
||||
@open_connection = Net::LDAP::Connection.new(:host => @host,
|
||||
|
@ -619,7 +657,8 @@ class Net::LDAP
|
|||
end
|
||||
|
||||
args[:base] ||= @base
|
||||
result_set = (args and args[:return_result] == false) ? nil : []
|
||||
return_result_set = args[:return_result] != false
|
||||
result_set = return_result_set ? [] : nil
|
||||
|
||||
if @open_connection
|
||||
@result = @open_connection.search(args) { |entry|
|
||||
|
@ -627,11 +666,10 @@ class Net::LDAP
|
|||
yield entry if block_given?
|
||||
}
|
||||
else
|
||||
@result = 0
|
||||
begin
|
||||
conn = Net::LDAP::Connection.new(:host => @host, :port => @port,
|
||||
:encryption => @encryption)
|
||||
if (@result = conn.bind(args[:auth] || @auth)) == 0
|
||||
if (@result = conn.bind(args[:auth] || @auth)).result_code == 0
|
||||
@result = conn.search(args) { |entry|
|
||||
result_set << entry if result_set
|
||||
yield entry if block_given?
|
||||
|
@ -642,7 +680,11 @@ class Net::LDAP
|
|||
end
|
||||
end
|
||||
|
||||
@result == 0 and result_set
|
||||
if return_result_set
|
||||
(!@result.nil? && @result.result_code == 0) ? result_set : nil
|
||||
else
|
||||
@result.success?
|
||||
end
|
||||
end
|
||||
|
||||
# #bind connects to an LDAP server and requests authentication based on
|
||||
|
@ -715,7 +757,7 @@ class Net::LDAP
|
|||
end
|
||||
end
|
||||
|
||||
@result == 0
|
||||
@result.success?
|
||||
end
|
||||
|
||||
# #bind_as is for testing authentication credentials.
|
||||
|
@ -810,14 +852,14 @@ class Net::LDAP
|
|||
begin
|
||||
conn = Connection.new(:host => @host, :port => @port,
|
||||
:encryption => @encryption)
|
||||
if (@result = conn.bind(args[:auth] || @auth)) == 0
|
||||
if (@result = conn.bind(args[:auth] || @auth)).result_code == 0
|
||||
@result = conn.add(args)
|
||||
end
|
||||
ensure
|
||||
conn.close if conn
|
||||
end
|
||||
end
|
||||
@result == 0
|
||||
@result.success?
|
||||
end
|
||||
|
||||
# Modifies the attribute values of a particular entry on the LDAP
|
||||
|
@ -908,14 +950,15 @@ class Net::LDAP
|
|||
begin
|
||||
conn = Connection.new(:host => @host, :port => @port,
|
||||
:encryption => @encryption)
|
||||
if (@result = conn.bind(args[:auth] || @auth)) == 0
|
||||
if (@result = conn.bind(args[:auth] || @auth)).result_code == 0
|
||||
@result = conn.modify(args)
|
||||
end
|
||||
ensure
|
||||
conn.close if conn
|
||||
end
|
||||
end
|
||||
@result == 0
|
||||
|
||||
@result.success?
|
||||
end
|
||||
|
||||
# Add a value to an attribute. Takes the full DN of the entry to modify,
|
||||
|
@ -979,14 +1022,14 @@ class Net::LDAP
|
|||
begin
|
||||
conn = Connection.new(:host => @host, :port => @port,
|
||||
:encryption => @encryption)
|
||||
if (@result = conn.bind(args[:auth] || @auth)) == 0
|
||||
if (@result = conn.bind(args[:auth] || @auth)).result_code == 0
|
||||
@result = conn.rename(args)
|
||||
end
|
||||
ensure
|
||||
conn.close if conn
|
||||
end
|
||||
end
|
||||
@result == 0
|
||||
@result.success?
|
||||
end
|
||||
alias_method :modify_rdn, :rename
|
||||
|
||||
|
@ -1007,16 +1050,29 @@ class Net::LDAP
|
|||
begin
|
||||
conn = Connection.new(:host => @host, :port => @port,
|
||||
:encryption => @encryption)
|
||||
if (@result = conn.bind(args[:auth] || @auth)) == 0
|
||||
if (@result = conn.bind(args[:auth] || @auth)).result_code == 0
|
||||
@result = conn.delete(args)
|
||||
end
|
||||
ensure
|
||||
conn.close
|
||||
end
|
||||
end
|
||||
@result == 0
|
||||
@result.success?
|
||||
end
|
||||
|
||||
# Delete an entry from the LDAP directory along with all subordinate entries.
|
||||
# the regular delete method will fail to delete an entry if it has subordinate
|
||||
# entries. This method sends an extra control code to tell the LDAP server
|
||||
# to do a tree delete. ('1.2.840.113556.1.4.805')
|
||||
#
|
||||
# Returns True or False to indicate whether the delete succeeded. Extended
|
||||
# status information is available by calling #get_operation_result.
|
||||
#
|
||||
# dn = "mail=deleteme@example.com, ou=people, dc=example, dc=com"
|
||||
# ldap.delete_tree :dn => dn
|
||||
def delete_tree(args)
|
||||
delete(args.merge(:control_codes => [[Net::LDAP::LDAPControls::DELETE_TREE, true]]))
|
||||
end
|
||||
# This method is experimental and 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.
|
||||
|
@ -1086,8 +1142,12 @@ class Net::LDAP
|
|||
# MUST refactor the root_dse call out.
|
||||
#++
|
||||
def paged_searches_supported?
|
||||
# active directory returns that it supports paged results. However
|
||||
# it returns binary data in the rfc2696_cookie which throws an
|
||||
# encoding exception breaking searching.
|
||||
return false if @force_no_page
|
||||
@server_caps ||= search_root_dse
|
||||
@server_caps[:supportedcontrol].include?(Net::LDAP::LdapControls::PagedResults)
|
||||
@server_caps[:supportedcontrol].include?(Net::LDAP::LDAPControls::PAGED_RESULTS)
|
||||
end
|
||||
end # class LDAP
|
||||
|
||||
|
@ -1101,9 +1161,9 @@ class Net::LDAP::Connection #:nodoc:
|
|||
begin
|
||||
@conn = TCPSocket.new(server[:host], server[:port])
|
||||
rescue SocketError
|
||||
raise Net::LDAP::LdapError, "No such address or other socket error."
|
||||
raise Net::LDAP::SocketError, "No such address or other socket error."
|
||||
rescue Errno::ECONNREFUSED
|
||||
raise Net::LDAP::LdapError, "Server #{server[:host]} refused connection on port #{server[:port]}."
|
||||
raise Net::LDAP::ConnectionRefusedError, "Server #{server[:host]} refused connection on port #{server[:port]}."
|
||||
end
|
||||
|
||||
if server[:encryption]
|
||||
|
@ -1120,7 +1180,7 @@ class Net::LDAP::Connection #:nodoc:
|
|||
end
|
||||
|
||||
def self.wrap_with_ssl(io)
|
||||
raise Net::LDAP::LdapError, "OpenSSL is unavailable" unless Net::LDAP::HasOpenSSL
|
||||
raise Net::LDAP::NoOpenSSLError, "OpenSSL is unavailable" unless Net::LDAP::HasOpenSSL
|
||||
ctx = OpenSSL::SSL::SSLContext.new
|
||||
conn = OpenSSL::SSL::SSLSocket.new(io, ctx)
|
||||
conn.connect
|
||||
|
@ -1169,16 +1229,16 @@ class Net::LDAP::Connection #:nodoc:
|
|||
request_pkt = [msgid, request].to_ber_sequence
|
||||
@conn.write request_pkt
|
||||
be = @conn.read_ber(Net::LDAP::AsnSyntax)
|
||||
raise Net::LDAP::LdapError, "no start_tls result" if be.nil?
|
||||
raise Net::LDAP::NoStartTLSResultError, "no start_tls result" if be.nil?
|
||||
pdu = Net::LDAP::PDU.new(be)
|
||||
raise Net::LDAP::LdapError, "no start_tls result" if pdu.nil?
|
||||
raise Net::LDAP::NoStartTLSResultError, "no start_tls result" if pdu.nil?
|
||||
if pdu.result_code.zero?
|
||||
@conn = self.class.wrap_with_ssl(@conn)
|
||||
else
|
||||
raise Net::LDAP::LdapError, "start_tls failed: #{pdu.result_code}"
|
||||
raise Net::LDAP::StartTLSError, "start_tls failed: #{pdu.result_code}"
|
||||
end
|
||||
else
|
||||
raise Net::LDAP::LdapError, "unsupported encryption method #{args[:method]}"
|
||||
raise Net::LDAP::EncryptionUnsupportedError, "unsupported encryption method #{args[:method]}"
|
||||
end
|
||||
end
|
||||
|
||||
|
@ -1206,7 +1266,7 @@ class Net::LDAP::Connection #:nodoc:
|
|||
elsif meth == :gss_spnego
|
||||
bind_gss_spnego(auth)
|
||||
else
|
||||
raise Net::LDAP::LdapError, "Unsupported auth method (#{meth})"
|
||||
raise Net::LDAP::AuthMethodUnsupportedError, "Unsupported auth method (#{meth})"
|
||||
end
|
||||
end
|
||||
|
||||
|
@ -1221,7 +1281,7 @@ class Net::LDAP::Connection #:nodoc:
|
|||
["", ""]
|
||||
end
|
||||
|
||||
raise Net::LDAP::LdapError, "Invalid binding information" unless (user && psw)
|
||||
raise Net::LDAP::BindingInformationInvalidError, "Invalid binding information" unless (user && psw)
|
||||
|
||||
msgid = next_msgid.to_ber
|
||||
request = [LdapVersion.to_ber, user.to_ber,
|
||||
|
@ -1229,9 +1289,9 @@ class Net::LDAP::Connection #:nodoc:
|
|||
request_pkt = [msgid, request].to_ber_sequence
|
||||
@conn.write request_pkt
|
||||
|
||||
(be = @conn.read_ber(Net::LDAP::AsnSyntax) and pdu = Net::LDAP::PDU.new(be)) or raise Net::LDAP::LdapError, "no bind result"
|
||||
(be = @conn.read_ber(Net::LDAP::AsnSyntax) and pdu = Net::LDAP::PDU.new(be)) or raise Net::LDAP::NoBindResultError, "no bind result"
|
||||
|
||||
pdu.result_code
|
||||
pdu
|
||||
end
|
||||
|
||||
#--
|
||||
|
@ -1258,7 +1318,7 @@ class Net::LDAP::Connection #:nodoc:
|
|||
def bind_sasl(auth)
|
||||
mech, cred, chall = auth[:mechanism], auth[:initial_credential],
|
||||
auth[:challenge_response]
|
||||
raise Net::LDAP::LdapError, "Invalid binding information" unless (mech && cred && chall)
|
||||
raise Net::LDAP::BindingInformationInvalidError, "Invalid binding information" unless (mech && cred && chall)
|
||||
|
||||
n = 0
|
||||
loop {
|
||||
|
@ -1268,9 +1328,9 @@ class Net::LDAP::Connection #:nodoc:
|
|||
request_pkt = [msgid, request].to_ber_sequence
|
||||
@conn.write request_pkt
|
||||
|
||||
(be = @conn.read_ber(Net::LDAP::AsnSyntax) and pdu = Net::LDAP::PDU.new(be)) or raise Net::LDAP::LdapError, "no bind result"
|
||||
return pdu.result_code unless pdu.result_code == 14 # saslBindInProgress
|
||||
raise Net::LDAP::LdapError, "sasl-challenge overflow" if ((n += 1) > MaxSaslChallenges)
|
||||
(be = @conn.read_ber(Net::LDAP::AsnSyntax) and pdu = Net::LDAP::PDU.new(be)) or raise Net::LDAP::NoBindResultError, "no bind result"
|
||||
return pdu unless pdu.result_code == 14 # saslBindInProgress
|
||||
raise Net::LDAP::SASLChallengeOverflowError, "sasl-challenge overflow" if ((n += 1) > MaxSaslChallenges)
|
||||
|
||||
cred = chall.call(pdu.result_server_sasl_creds)
|
||||
}
|
||||
|
@ -1294,7 +1354,7 @@ class Net::LDAP::Connection #:nodoc:
|
|||
require 'ntlm'
|
||||
|
||||
user, psw = [auth[:username] || auth[:dn], auth[:password]]
|
||||
raise Net::LDAP::LdapError, "Invalid binding information" unless (user && psw)
|
||||
raise Net::LDAP::BindingInformationInvalidError, "Invalid binding information" unless (user && psw)
|
||||
|
||||
nego = proc { |challenge|
|
||||
t2_msg = NTLM::Message.parse(challenge)
|
||||
|
@ -1309,6 +1369,35 @@ class Net::LDAP::Connection #:nodoc:
|
|||
end
|
||||
private :bind_gss_spnego
|
||||
|
||||
|
||||
#--
|
||||
# Allow the caller to specify a sort control
|
||||
#
|
||||
# The format of the sort control needs to be:
|
||||
#
|
||||
# :sort_control => ["cn"] # just a string
|
||||
# or
|
||||
# :sort_control => [["cn", "matchingRule", true]] #attribute, matchingRule, direction (true / false)
|
||||
# or
|
||||
# :sort_control => ["givenname","sn"] #multiple strings or arrays
|
||||
#
|
||||
def encode_sort_controls(sort_definitions)
|
||||
return sort_definitions unless sort_definitions
|
||||
|
||||
sort_control_values = sort_definitions.map do |control|
|
||||
control = Array(control) # if there is only an attribute name as a string then infer the orderinrule and reverseorder
|
||||
control[0] = String(control[0]).to_ber,
|
||||
control[1] = String(control[1]).to_ber,
|
||||
control[2] = (control[2] == true).to_ber
|
||||
control.to_ber_sequence
|
||||
end
|
||||
sort_control = [
|
||||
Net::LDAP::LDAPControls::SORT_REQUEST.to_ber,
|
||||
false.to_ber,
|
||||
sort_control_values.to_ber_sequence.to_s.to_ber
|
||||
].to_ber_sequence
|
||||
end
|
||||
|
||||
#--
|
||||
# Alternate implementation, this yields each search entry to the caller as
|
||||
# it are received.
|
||||
|
@ -1320,20 +1409,21 @@ class Net::LDAP::Connection #:nodoc:
|
|||
# in the protocol.
|
||||
#++
|
||||
def search(args = {})
|
||||
search_filter = (args && args[:filter]) ||
|
||||
search_filter = (args && args[:filter]) ||
|
||||
Net::LDAP::Filter.eq("objectclass", "*")
|
||||
search_filter = Net::LDAP::Filter.construct(search_filter) if search_filter.is_a?(String)
|
||||
search_base = (args && args[:base]) || "dc=example, dc=com"
|
||||
search_attributes = ((args && args[:attributes]) || []).map { |attr| attr.to_s.to_ber}
|
||||
return_referrals = args && args[:return_referrals] == true
|
||||
sizelimit = (args && args[:size].to_i) || 0
|
||||
raise Net::LDAP::LdapError, "invalid search-size" unless sizelimit >= 0
|
||||
raise Net::LDAP::SearchSizeInvalidError, "invalid search-size" unless sizelimit >= 0
|
||||
paged_searches_supported = (args && args[:paged_searches_supported])
|
||||
|
||||
attributes_only = (args and args[:attributes_only] == true)
|
||||
scope = args[:scope] || Net::LDAP::SearchScope_WholeSubtree
|
||||
raise Net::LDAP::LdapError, "invalid search scope" unless Net::LDAP::SearchScopes.include?(scope)
|
||||
raise Net::LDAP::SearchScopeInvalidError, "invalid search scope" unless Net::LDAP::SearchScopes.include?(scope)
|
||||
|
||||
sort_control = encode_sort_controls(args.fetch(:sort_controls){ false })
|
||||
# An interesting value for the size limit would be close to A/D's
|
||||
# built-in page limit of 1000 records, but openLDAP newer than version
|
||||
# 2.2.0 chokes on anything bigger than 126. You get a silent error that
|
||||
|
@ -1355,7 +1445,7 @@ class Net::LDAP::Connection #:nodoc:
|
|||
# to do a root-DSE record search and not do a paged search if the LDAP
|
||||
# doesn't support it. Yuck.
|
||||
rfc2696_cookie = [126, ""]
|
||||
result_code = 0
|
||||
result_pdu = nil
|
||||
n_results = 0
|
||||
|
||||
loop {
|
||||
|
@ -1381,20 +1471,25 @@ class Net::LDAP::Connection #:nodoc:
|
|||
search_attributes.to_ber_sequence
|
||||
].to_ber_appsequence(3)
|
||||
|
||||
# rfc2696_cookie sometimes contains binary data from Microsoft Active Directory
|
||||
# this breaks when calling to_ber. (Can't force binary data to UTF-8)
|
||||
# we have to disable paging (even though server supports it) to get around this...
|
||||
|
||||
controls = []
|
||||
controls <<
|
||||
[
|
||||
Net::LDAP::LdapControls::PagedResults.to_ber,
|
||||
Net::LDAP::LDAPControls::PAGED_RESULTS.to_ber,
|
||||
# Criticality MUST be false to interoperate with normal LDAPs.
|
||||
false.to_ber,
|
||||
rfc2696_cookie.map{ |v| v.to_ber}.to_ber_sequence.to_s.to_ber
|
||||
].to_ber_sequence if paged_searches_supported
|
||||
controls = controls.to_ber_contextspecific(0)
|
||||
controls << sort_control if sort_control
|
||||
controls = controls.empty? ? nil : controls.to_ber_contextspecific(0)
|
||||
|
||||
pkt = [next_msgid.to_ber, request, controls].to_ber_sequence
|
||||
pkt = [next_msgid.to_ber, request, controls].compact.to_ber_sequence
|
||||
@conn.write pkt
|
||||
|
||||
result_code = 0
|
||||
result_pdu = nil
|
||||
controls = []
|
||||
|
||||
while (be = @conn.read_ber(Net::LDAP::AsnSyntax)) && (pdu = Net::LDAP::PDU.new(be))
|
||||
|
@ -1411,11 +1506,18 @@ class Net::LDAP::Connection #:nodoc:
|
|||
end
|
||||
end
|
||||
when 5 # search-result
|
||||
result_code = pdu.result_code
|
||||
result_pdu = pdu
|
||||
controls = pdu.result_controls
|
||||
if return_referrals && result_code == 10
|
||||
if block_given?
|
||||
se = Net::LDAP::Entry.new
|
||||
se[:search_referrals] = (pdu.search_referrals || [])
|
||||
yield se
|
||||
end
|
||||
end
|
||||
break
|
||||
else
|
||||
raise Net::LDAP::LdapError, "invalid response-type in search: #{pdu.app_tag}"
|
||||
raise Net::LDAP::ResponseTypeInvalidError, "invalid response-type in search: #{pdu.app_tag}"
|
||||
end
|
||||
end
|
||||
|
||||
|
@ -1430,9 +1532,9 @@ class Net::LDAP::Connection #:nodoc:
|
|||
# of type OCTET STRING, covered in the default syntax supported by
|
||||
# read_ber, so I guess we're ok.
|
||||
more_pages = false
|
||||
if result_code == 0 and controls
|
||||
if result_pdu.result_code == 0 and controls
|
||||
controls.each do |c|
|
||||
if c.oid == Net::LDAP::LdapControls::PagedResults
|
||||
if c.oid == Net::LDAP::LDAPControls::PAGED_RESULTS
|
||||
# just in case some bogus server sends us more than 1 of these.
|
||||
more_pages = false
|
||||
if c.value and c.value.length > 0
|
||||
|
@ -1449,7 +1551,7 @@ class Net::LDAP::Connection #:nodoc:
|
|||
break unless more_pages
|
||||
} # loop
|
||||
|
||||
result_code
|
||||
result_pdu || OpenStruct.new(:status => :failure, :result_code => 1, :message => "Invalid search")
|
||||
end
|
||||
|
||||
MODIFY_OPERATIONS = { #:nodoc:
|
||||
|
@ -1459,7 +1561,7 @@ class Net::LDAP::Connection #:nodoc:
|
|||
}
|
||||
|
||||
def self.modify_ops(operations)
|
||||
modify_ops = []
|
||||
ops = []
|
||||
if operations
|
||||
operations.each { |op, attrib, values|
|
||||
# TODO, fix the following line, which gives a bogus error if the
|
||||
|
@ -1467,10 +1569,10 @@ class Net::LDAP::Connection #:nodoc:
|
|||
op_ber = MODIFY_OPERATIONS[op.to_sym].to_ber_enumerated
|
||||
values = [ values ].flatten.map { |v| v.to_ber if v }.to_ber_set
|
||||
values = [ attrib.to_s.to_ber, values ].to_ber_sequence
|
||||
modify_ops << [ op_ber, values ].to_ber
|
||||
ops << [ op_ber, values ].to_ber
|
||||
}
|
||||
end
|
||||
modify_ops
|
||||
ops
|
||||
end
|
||||
|
||||
#--
|
||||
|
@ -1482,14 +1584,15 @@ class Net::LDAP::Connection #:nodoc:
|
|||
#++
|
||||
def modify(args)
|
||||
modify_dn = args[:dn] or raise "Unable to modify empty DN"
|
||||
modify_ops = modify_ops args[:operations]
|
||||
ops = self.class.modify_ops args[:operations]
|
||||
request = [ modify_dn.to_ber,
|
||||
modify_ops.to_ber_sequence ].to_ber_appsequence(6)
|
||||
ops.to_ber_sequence ].to_ber_appsequence(6)
|
||||
pkt = [ next_msgid.to_ber, request ].to_ber_sequence
|
||||
@conn.write pkt
|
||||
|
||||
(be = @conn.read_ber(Net::LDAP::AsnSyntax)) && (pdu = Net::LDAP::PDU.new(be)) && (pdu.app_tag == 7) or raise Net::LDAP::LdapError, "response missing or invalid"
|
||||
pdu.result_code
|
||||
(be = @conn.read_ber(Net::LDAP::AsnSyntax)) && (pdu = Net::LDAP::PDU.new(be)) && (pdu.app_tag == 7) or raise Net::LDAP::ResponseMissingOrInvalidError, "response missing or invalid"
|
||||
|
||||
pdu
|
||||
end
|
||||
|
||||
#--
|
||||
|
@ -1500,7 +1603,7 @@ class Net::LDAP::Connection #:nodoc:
|
|||
# to the error message and the matched-DN returned by the server.
|
||||
#++
|
||||
def add(args)
|
||||
add_dn = args[:dn] or raise Net::LDAP::LdapError, "Unable to add empty DN"
|
||||
add_dn = args[:dn] or raise Net::LDAP::EmptyDNError, "Unable to add empty DN"
|
||||
add_attrs = []
|
||||
a = args[:attributes] and a.each { |k, v|
|
||||
add_attrs << [ k.to_s.to_ber, Array(v).map { |m| m.to_ber}.to_ber_set ].to_ber_sequence
|
||||
|
@ -1510,27 +1613,34 @@ class Net::LDAP::Connection #:nodoc:
|
|||
pkt = [next_msgid.to_ber, request].to_ber_sequence
|
||||
@conn.write pkt
|
||||
|
||||
(be = @conn.read_ber(Net::LDAP::AsnSyntax)) && (pdu = Net::LDAP::PDU.new(be)) && (pdu.app_tag == 9) or raise Net::LDAP::LdapError, "response missing or invalid"
|
||||
pdu.result_code
|
||||
(be = @conn.read_ber(Net::LDAP::AsnSyntax)) &&
|
||||
(pdu = Net::LDAP::PDU.new(be)) &&
|
||||
(pdu.app_tag == 9) or
|
||||
raise Net::LDAP::ResponseMissingOrInvalidError, "response missing or invalid"
|
||||
|
||||
pdu
|
||||
end
|
||||
|
||||
#--
|
||||
# TODO: need to support a time limit, in case the server fails to respond.
|
||||
#++
|
||||
def rename args
|
||||
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"
|
||||
delete_attrs = args[:delete_attributes] ? true : false
|
||||
new_superior = args[:new_superior]
|
||||
new_superior = args[:new_superior]
|
||||
|
||||
request = [old_dn.to_ber, new_rdn.to_ber, delete_attrs.to_ber]
|
||||
request << new_superior.to_ber_contextspecific(0) unless new_superior == nil
|
||||
|
||||
request = [old_dn.to_ber, new_rdn.to_ber, delete_attrs.to_ber]
|
||||
request << new_superior.to_ber unless new_superior == nil
|
||||
|
||||
pkt = [next_msgid.to_ber, request.to_ber_appsequence(12)].to_ber_sequence
|
||||
@conn.write pkt
|
||||
|
||||
(be = @conn.read_ber(AsnSyntax)) && (pdu = LdapPdu.new( be )) && (pdu.app_tag == 13) or raise LdapError.new( "response missing or invalid" )
|
||||
pdu.result_code
|
||||
(be = @conn.read_ber(Net::LDAP::AsnSyntax)) &&
|
||||
(pdu = Net::LDAP::PDU.new( be )) && (pdu.app_tag == 13) or
|
||||
raise Net::LDAP::ResponseMissingOrInvalidError.new( "response missing or invalid" )
|
||||
|
||||
pdu
|
||||
end
|
||||
|
||||
#--
|
||||
|
@ -1538,12 +1648,13 @@ class Net::LDAP::Connection #:nodoc:
|
|||
#++
|
||||
def delete(args)
|
||||
dn = args[:dn] or raise "Unable to delete empty DN"
|
||||
|
||||
controls = args.include?(:control_codes) ? args[:control_codes].to_ber_control : nil #use nil so we can compact later
|
||||
request = dn.to_s.to_ber_application_string(10)
|
||||
pkt = [next_msgid.to_ber, request].to_ber_sequence
|
||||
pkt = [next_msgid.to_ber, request, controls].compact.to_ber_sequence
|
||||
@conn.write pkt
|
||||
|
||||
(be = @conn.read_ber(Net::LDAP::AsnSyntax)) && (pdu = Net::LDAP::PDU.new(be)) && (pdu.app_tag == 11) or raise Net::LDAP::LdapError, "response missing or invalid"
|
||||
pdu.result_code
|
||||
(be = @conn.read_ber(Net::LDAP::AsnSyntax)) && (pdu = Net::LDAP::PDU.new(be)) && (pdu.app_tag == 11) or raise Net::LDAP::ResponseMissingOrInvalidError, "response missing or invalid"
|
||||
|
||||
pdu
|
||||
end
|
||||
end # class Connection
|
||||
|
|
|
@ -117,8 +117,8 @@ class Net::LDAP::Dataset < Hash
|
|||
while line
|
||||
new_line = io.gets
|
||||
|
||||
if new_line =~ /^[\s]+/
|
||||
line << " " << $'
|
||||
if new_line =~ /^ /
|
||||
line << $'
|
||||
else
|
||||
nextline = new_line
|
||||
|
||||
|
|
|
@ -71,7 +71,7 @@ class Net::LDAP::Entry
|
|||
|
||||
return nil if ds.empty?
|
||||
|
||||
raise Net::LDAP::LdapError, "Too many LDIF entries" unless ds.size == 1
|
||||
raise Net::LDAP::EntryOverflowError, "Too many LDIF entries" unless ds.size == 1
|
||||
|
||||
entry = ds.to_entries.first
|
||||
|
||||
|
|
|
@ -23,11 +23,11 @@
|
|||
class Net::LDAP::Filter
|
||||
##
|
||||
# Known filter types.
|
||||
FilterTypes = [ :ne, :eq, :ge, :le, :and, :or, :not, :ex ]
|
||||
FilterTypes = [ :ne, :eq, :ge, :le, :and, :or, :not, :ex, :bineq ]
|
||||
|
||||
def initialize(op, left, right) #:nodoc:
|
||||
unless FilterTypes.include?(op)
|
||||
raise Net::LDAP::LdapError, "Invalid or unsupported operator #{op.inspect} in LDAP Filter."
|
||||
raise Net::LDAP::OperatorError, "Invalid or unsupported operator #{op.inspect} in LDAP Filter."
|
||||
end
|
||||
@op = op
|
||||
@left = left
|
||||
|
@ -65,6 +65,23 @@ class Net::LDAP::Filter
|
|||
new(:eq, attribute, value)
|
||||
end
|
||||
|
||||
##
|
||||
# Creates a Filter object indicating a binary comparison.
|
||||
# this prevents the search data from being forced into a UTF-8 string.
|
||||
#
|
||||
# This is primarily used for Microsoft Active Directory to compare
|
||||
# GUID values.
|
||||
#
|
||||
# # for guid represented as hex charecters
|
||||
# guid = "6a31b4a12aa27a41aca9603f27dd5116"
|
||||
# guid_bin = [guid].pack("H*")
|
||||
# f = Net::LDAP::Filter.bineq("objectGUID", guid_bin)
|
||||
#
|
||||
# This filter does not perform any escaping.
|
||||
def bineq(attribute, value)
|
||||
new(:bineq, attribute, value)
|
||||
end
|
||||
|
||||
##
|
||||
# Creates a Filter object indicating extensible comparison. This Filter
|
||||
# object is currently considered EXPERIMENTAL.
|
||||
|
@ -273,7 +290,7 @@ class Net::LDAP::Filter
|
|||
ber.last.each { |b|
|
||||
case b.ber_identifier
|
||||
when 0x80 # context-specific primitive 0, SubstringFilter "initial"
|
||||
raise Net::LDAP::LdapError, "Unrecognized substring filter; bad initial value." if str.length > 0
|
||||
raise Net::LDAP::SubstringFilterError, "Unrecognized substring filter; bad initial value." if str.length > 0
|
||||
str += b
|
||||
when 0x81 # context-specific primitive 0, SubstringFilter "any"
|
||||
str += "*#{b}"
|
||||
|
@ -292,7 +309,7 @@ class Net::LDAP::Filter
|
|||
# call to_s to get rid of the BER-identifiedness of the incoming string.
|
||||
present?(ber.to_s)
|
||||
when 0xa9 # context-specific constructed 9, "extensible comparison"
|
||||
raise Net::LDAP::LdapError, "Invalid extensible search filter, should be at least two elements" if ber.size<2
|
||||
raise Net::LDAP::SearchFilterError, "Invalid extensible search filter, should be at least two elements" if ber.size<2
|
||||
|
||||
# Reassembles the extensible filter parts
|
||||
# (["sn", "2.4.6.8.10", "Barbara Jones", '1'])
|
||||
|
@ -313,7 +330,7 @@ class Net::LDAP::Filter
|
|||
|
||||
ex(attribute, value)
|
||||
else
|
||||
raise Net::LDAP::LdapError, "Invalid BER tag-value (#{ber.ber_identifier}) in search filter."
|
||||
raise Net::LDAP::BERInvalidError, "Invalid BER tag-value (#{ber.ber_identifier}) in search filter."
|
||||
end
|
||||
end
|
||||
|
||||
|
@ -340,7 +357,7 @@ class Net::LDAP::Filter
|
|||
when 0xa3 # equalityMatch. context-specific constructed 3.
|
||||
eq(obj[0], obj[1])
|
||||
else
|
||||
raise Net::LDAP::LdapError, "Unknown LDAP search-filter type: #{obj.ber_identifier}"
|
||||
raise Net::LDAP::SearchFilterTypeUnknownError, "Unknown LDAP search-filter type: #{obj.ber_identifier}"
|
||||
end
|
||||
end
|
||||
end
|
||||
|
@ -399,6 +416,8 @@ class Net::LDAP::Filter
|
|||
"!(#{@left}=#{@right})"
|
||||
when :eq
|
||||
"#{@left}=#{@right}"
|
||||
when :bineq
|
||||
"#{@left}=#{@right}"
|
||||
when :ex
|
||||
"#{@left}:=#{@right}"
|
||||
when :ge
|
||||
|
@ -508,11 +527,14 @@ class Net::LDAP::Filter
|
|||
else # equality
|
||||
[@left.to_s.to_ber, unescape(@right).to_ber].to_ber_contextspecific(3)
|
||||
end
|
||||
when :bineq
|
||||
# make sure data is not forced to UTF-8
|
||||
[@left.to_s.to_ber, unescape(@right).to_ber_bin].to_ber_contextspecific(3)
|
||||
when :ex
|
||||
seq = []
|
||||
|
||||
unless @left =~ /^([-;\w]*)(:dn)?(:(\w+|[.\w]+))?$/
|
||||
raise Net::LDAP::LdapError, "Bad attribute #{@left}"
|
||||
raise Net::LDAP::BadAttributeError, "Bad attribute #{@left}"
|
||||
end
|
||||
type, dn, rule = $1, $2, $4
|
||||
|
||||
|
@ -619,7 +641,7 @@ class Net::LDAP::Filter
|
|||
l = entry[@left] and l = Array(l) and l.index(@right)
|
||||
end
|
||||
else
|
||||
raise Net::LDAP::LdapError, "Unknown filter type in match: #{@op}"
|
||||
raise Net::LDAP::FilterTypeUnknownError, "Unknown filter type in match: #{@op}"
|
||||
end
|
||||
end
|
||||
|
||||
|
@ -652,7 +674,7 @@ class Net::LDAP::Filter
|
|||
def initialize(str)
|
||||
require 'strscan' # Don't load strscan until we need it.
|
||||
@filter = parse(StringScanner.new(str))
|
||||
raise Net::LDAP::LdapError, "Invalid filter syntax." unless @filter
|
||||
raise Net::LDAP::FilterSyntaxInvalidError, "Invalid filter syntax." unless @filter
|
||||
end
|
||||
|
||||
##
|
||||
|
@ -733,7 +755,7 @@ class Net::LDAP::Filter
|
|||
scanner.scan(/\s*/)
|
||||
if op = scanner.scan(/<=|>=|!=|:=|=/)
|
||||
scanner.scan(/\s*/)
|
||||
if value = scanner.scan(/(?:[-\w*.+@=,#\$%&!'\s]|\\[a-fA-F\d]{2})+/)
|
||||
if value = scanner.scan(/(?:[-\w*.+@=,#\$%&!'\s\xC3\x80-\xCA\xAF]|\\[a-fA-F\d]{2})+/)
|
||||
# 20100313 AZ: Assumes that "(uid=george*)" is the same as
|
||||
# "(uid=george* )". The standard doesn't specify, but I can find
|
||||
# no examples that suggest otherwise.
|
||||
|
|
|
@ -1,31 +1,37 @@
|
|||
# -*- ruby encoding: utf-8 -*-
|
||||
require 'digest/sha1'
|
||||
require 'digest/md5'
|
||||
require 'base64'
|
||||
|
||||
class Net::LDAP::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
|
||||
# Pass a hash type as a symbol (:md5, :sha, :ssha) 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?
|
||||
# TODO:
|
||||
# * maybe salted-md5
|
||||
# * Should we provide sha1 as a synonym for sha1? I vote no because then
|
||||
# should you also provide ssha1 for symmetry?
|
||||
#
|
||||
attribute_value = ""
|
||||
def generate(type, str)
|
||||
digest, digest_name = case type
|
||||
when :md5
|
||||
[Digest::MD5.new, 'MD5']
|
||||
when :sha
|
||||
[Digest::SHA1.new, 'SHA']
|
||||
else
|
||||
raise Net::LDAP::LdapError, "Unsupported password-hash type (#{type})"
|
||||
end
|
||||
digest << str.to_s
|
||||
return "{#{digest_name}}#{[digest.digest].pack('m').chomp }"
|
||||
case type
|
||||
when :md5
|
||||
attribute_value = '{MD5}' + Base64.encode64(Digest::MD5.digest(str)).chomp!
|
||||
when :sha
|
||||
attribute_value = '{SHA}' + Base64.encode64(Digest::SHA1.digest(str)).chomp!
|
||||
when :ssha
|
||||
srand; salt = (rand * 1000).to_i.to_s
|
||||
attribute_value = '{SSHA}' + Base64.encode64(Digest::SHA1.digest(str + salt) + salt).chomp!
|
||||
else
|
||||
raise Net::LDAP::HashTypeUnsupportedError, "Unsupported password-hash type (#{type})"
|
||||
end
|
||||
return attribute_value
|
||||
end
|
||||
end
|
||||
end
|
||||
|
|
|
@ -112,6 +112,10 @@ class Net::LDAP::PDU
|
|||
@ldap_result || {}
|
||||
end
|
||||
|
||||
def error_message
|
||||
result[:errorMessage] || ""
|
||||
end
|
||||
|
||||
##
|
||||
# This returns an LDAP result code taken from the PDU, but it will be nil
|
||||
# if there wasn't a result code. That can easily happen depending on the
|
||||
|
@ -120,6 +124,18 @@ class Net::LDAP::PDU
|
|||
@ldap_result and @ldap_result[code]
|
||||
end
|
||||
|
||||
def status
|
||||
result_code == 0 ? :success : :failure
|
||||
end
|
||||
|
||||
def success?
|
||||
status == :success
|
||||
end
|
||||
|
||||
def failure?
|
||||
!success?
|
||||
end
|
||||
|
||||
##
|
||||
# Return serverSaslCreds, which are only present in BindResponse packets.
|
||||
#--
|
||||
|
@ -136,6 +152,7 @@ class Net::LDAP::PDU
|
|||
:matchedDN => sequence[1],
|
||||
:errorMessage => sequence[2]
|
||||
}
|
||||
parse_search_referral(sequence[3]) if @ldap_result[:resultCode] == 10
|
||||
end
|
||||
private :parse_ldap_result
|
||||
|
||||
|
|
|
@ -2,7 +2,7 @@
|
|||
# :stopdoc:
|
||||
module Net
|
||||
class SNMP
|
||||
VERSION = '0.2.1'
|
||||
VERSION = '0.4.0'
|
||||
|
||||
AsnSyntax = Net::BER.compile_syntax({
|
||||
:application => {
|
||||
|
|
|
@ -1,12 +1,11 @@
|
|||
# -*- encoding: utf-8 -*-
|
||||
|
||||
Gem::Specification.new do |s|
|
||||
s.name = %q{net-ldap}
|
||||
s.version = "0.2.20110317223538"
|
||||
s.version = "0.4.0"
|
||||
|
||||
s.required_rubygems_version = Gem::Requirement.new(">= 0") if s.respond_to? :required_rubygems_version=
|
||||
s.authors = ["Francis Cianfrocca", "Emiel van de Laar", "Rory O'Connell", "Kaspar Schiess", "Austin Ziegler"]
|
||||
s.date = %q{2011-03-17}
|
||||
s.date = %q{2012-02-28}
|
||||
s.description = %q{Net::LDAP for Ruby (also called net-ldap) implements client access for the
|
||||
Lightweight Directory Access Protocol (LDAP), an IETF standard protocol for
|
||||
accessing distributed directory services. Net::LDAP is written completely in
|
||||
|
@ -20,8 +19,8 @@ Our roadmap for Net::LDAP 1.0 is to gain full <em>client</em> compliance with
|
|||
the most recent LDAP RFCs (4510–4519, plutions of 4520–4532).}
|
||||
s.email = ["blackhedd@rubyforge.org", "gemiel@gmail.com", "rory.ocon@gmail.com", "kaspar.schiess@absurd.li", "austin@rubyforge.org"]
|
||||
s.extra_rdoc_files = ["Manifest.txt", "Contributors.rdoc", "Hacking.rdoc", "History.rdoc", "License.rdoc", "README.rdoc"]
|
||||
s.files = [".autotest", ".rspec", "Contributors.rdoc", "Hacking.rdoc", "History.rdoc", "License.rdoc", "Manifest.txt", "README.rdoc", "Rakefile", "autotest/discover.rb", "lib/net-ldap.rb", "lib/net/ber.rb", "lib/net/ber/ber_parser.rb", "lib/net/ber/core_ext.rb", "lib/net/ber/core_ext/array.rb", "lib/net/ber/core_ext/bignum.rb", "lib/net/ber/core_ext/false_class.rb", "lib/net/ber/core_ext/fixnum.rb", "lib/net/ber/core_ext/string.rb", "lib/net/ber/core_ext/true_class.rb", "lib/net/ldap.rb", "lib/net/ldap/dataset.rb", "lib/net/ldap/dn.rb", "lib/net/ldap/entry.rb", "lib/net/ldap/filter.rb", "lib/net/ldap/password.rb", "lib/net/ldap/pdu.rb", "lib/net/snmp.rb", "net-ldap.gemspec", "spec/integration/ssl_ber_spec.rb", "spec/spec.opts", "spec/spec_helper.rb", "spec/unit/ber/ber_spec.rb", "spec/unit/ber/core_ext/string_spec.rb", "spec/unit/ldap/dn_spec.rb", "spec/unit/ldap/entry_spec.rb", "spec/unit/ldap/filter_spec.rb", "spec/unit/ldap_spec.rb", "test/common.rb", "test/test_entry.rb", "test/test_filter.rb", "test/test_ldap_connection.rb", "test/test_ldif.rb", "test/test_password.rb", "test/test_rename.rb", "test/test_snmp.rb", "test/testdata.ldif", "testserver/ldapserver.rb", "testserver/testdata.ldif", ".gemtest"]
|
||||
s.homepage = %q{http://net-ldap.rubyforge.org/}
|
||||
s.files = [".autotest", ".rspec", "Contributors.rdoc", "Hacking.rdoc", "History.rdoc", "License.rdoc", "Manifest.txt", "README.rdoc", "Rakefile", "autotest/discover.rb", "lib/net-ldap.rb", "lib/net/ber.rb", "lib/net/ber/ber_parser.rb", "lib/net/ber/core_ext.rb", "lib/net/ber/core_ext/array.rb", "lib/net/ber/core_ext/bignum.rb", "lib/net/ber/core_ext/false_class.rb", "lib/net/ber/core_ext/fixnum.rb", "lib/net/ber/core_ext/string.rb", "lib/net/ber/core_ext/true_class.rb", "lib/net/ldap.rb", "lib/net/ldap/dataset.rb", "lib/net/ldap/dn.rb", "lib/net/ldap/entry.rb", "lib/net/ldap/filter.rb", "lib/net/ldap/password.rb", "lib/net/ldap/pdu.rb", "lib/net/snmp.rb", "net-ldap.gemspec", "spec/integration/ssl_ber_spec.rb", "spec/spec.opts", "spec/spec_helper.rb", "spec/unit/ber/ber_spec.rb", "spec/unit/ber/core_ext/string_spec.rb", "spec/unit/ldap/dn_spec.rb", "spec/unit/ldap/entry_spec.rb", "spec/unit/ldap/filter_spec.rb", "spec/unit/ldap_spec.rb", "test/common.rb", "test/test_entry.rb", "test/test_filter.rb", "test/test_ldap_connection.rb", "test/test_ldif.rb", "test/test_password.rb", "test/test_rename.rb", "test/test_snmp.rb", "test/testdata.ldif", "testserver/ldapserver.rb", "testserver/testdata.ldif"]
|
||||
s.homepage = %q{http://github.com.org/ruby-ldap/ruby-net-ldap}
|
||||
s.rdoc_options = ["--main", "README.rdoc"]
|
||||
s.require_paths = ["lib"]
|
||||
s.required_ruby_version = Gem::Requirement.new(">= 1.8.7")
|
||||
|
|
|
@ -75,6 +75,26 @@ describe "BER encoding of" do
|
|||
end
|
||||
end
|
||||
end
|
||||
if "Ruby 1.9".respond_to?(:encoding)
|
||||
context "strings" do
|
||||
it "should properly encode UTF-8 strings" do
|
||||
"\u00e5".force_encoding("UTF-8").to_ber.should ==
|
||||
"\x04\x02\xC3\xA5"
|
||||
end
|
||||
it "should properly encode strings encodable as UTF-8" do
|
||||
"teststring".encode("US-ASCII").to_ber.should == "\x04\nteststring"
|
||||
end
|
||||
it "should properly encode binary data strings using to_ber_bin" do
|
||||
# This is used for searching for GUIDs in Active Directory
|
||||
["6a31b4a12aa27a41aca9603f27dd5116"].pack("H*").to_ber_bin.should ==
|
||||
"\x04\x10" + "j1\xB4\xA1*\xA2zA\xAC\xA9`?'\xDDQ\x16"
|
||||
end
|
||||
it "should fail on strings that can not be converted to UTF-8" do
|
||||
error = Encoding::UndefinedConversionError
|
||||
lambda {"\x81".to_ber }.should raise_exception(error)
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
describe "BER decoding of" do
|
||||
|
@ -91,4 +111,4 @@ describe "BER decoding of" do
|
|||
[1, [3, "Administrator", "ad_is_bogus"]]
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
|
|
|
@ -0,0 +1,24 @@
|
|||
require 'spec_helper'
|
||||
require 'metaid'
|
||||
|
||||
describe Array, "when extended with BER core extensions" do
|
||||
|
||||
it "should correctly convert a control code array" do
|
||||
control_codes = []
|
||||
control_codes << ['1.2.3'.to_ber, true.to_ber].to_ber_sequence
|
||||
control_codes << ['1.7.9'.to_ber, false.to_ber].to_ber_sequence
|
||||
control_codes = control_codes.to_ber_sequence
|
||||
res = [['1.2.3', true],['1.7.9',false]].to_ber_control
|
||||
res.should eq(control_codes)
|
||||
end
|
||||
|
||||
it "should wrap the array in another array if a nested array is not passed" do
|
||||
result1 = ['1.2.3', true].to_ber_control
|
||||
result2 = [['1.2.3', true]].to_ber_control
|
||||
result1.should eq(result2)
|
||||
end
|
||||
|
||||
it "should return an empty string if an empty array is passed" do
|
||||
[].to_ber_control.should be_empty
|
||||
end
|
||||
end
|
|
@ -0,0 +1,35 @@
|
|||
# -*- ruby encoding: utf-8 -*-
|
||||
|
||||
describe Net::LDAP, "search method" do
|
||||
class FakeConnection
|
||||
def search(args)
|
||||
OpenStruct.new(:result_code => 1, :message => "error")
|
||||
end
|
||||
end
|
||||
|
||||
before(:each) do
|
||||
@connection = Net::LDAP.new
|
||||
@connection.instance_variable_set(:@open_connection, FakeConnection.new)
|
||||
end
|
||||
|
||||
context "when :return_result => true" do
|
||||
it "should return nil upon error" do
|
||||
result_set = @connection.search(:return_result => true)
|
||||
result_set.should be_nil
|
||||
end
|
||||
end
|
||||
|
||||
context "when :return_result => false" do
|
||||
it "should return false upon error" do
|
||||
result = @connection.search(:return_result => false)
|
||||
result.result_code.should == 1
|
||||
end
|
||||
end
|
||||
|
||||
context "When :return_result is not given" do
|
||||
it "should return nil upon error" do
|
||||
result_set = @connection.search
|
||||
result_set.should be_nil
|
||||
end
|
||||
end
|
||||
end
|
|
@ -7,11 +7,11 @@ describe Net::LDAP::Connection do
|
|||
flexmock(TCPSocket).
|
||||
should_receive(:new).and_raise(Errno::ECONNREFUSED)
|
||||
end
|
||||
|
||||
|
||||
it "should raise LdapError" do
|
||||
lambda {
|
||||
Net::LDAP::Connection.new(
|
||||
:server => 'test.mocked.com',
|
||||
:server => 'test.mocked.com',
|
||||
:port => 636)
|
||||
}.should raise_error(Net::LDAP::LdapError)
|
||||
end
|
||||
|
@ -21,11 +21,11 @@ describe Net::LDAP::Connection do
|
|||
flexmock(TCPSocket).
|
||||
should_receive(:new).and_raise(SocketError)
|
||||
end
|
||||
|
||||
|
||||
it "should raise LdapError" do
|
||||
lambda {
|
||||
Net::LDAP::Connection.new(
|
||||
:server => 'test.mocked.com',
|
||||
:server => 'test.mocked.com',
|
||||
:port => 636)
|
||||
}.should raise_error(Net::LDAP::LdapError)
|
||||
end
|
||||
|
@ -35,14 +35,44 @@ describe Net::LDAP::Connection do
|
|||
flexmock(TCPSocket).
|
||||
should_receive(:new).and_raise(NameError)
|
||||
end
|
||||
|
||||
|
||||
it "should rethrow the exception" do
|
||||
lambda {
|
||||
Net::LDAP::Connection.new(
|
||||
:server => 'test.mocked.com',
|
||||
:server => 'test.mocked.com',
|
||||
:port => 636)
|
||||
}.should raise_error(NameError)
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
context "populate error messages" do
|
||||
before do
|
||||
@tcp_socket = flexmock(:connection)
|
||||
@tcp_socket.should_receive(:write)
|
||||
flexmock(TCPSocket).should_receive(:new).and_return(@tcp_socket)
|
||||
end
|
||||
|
||||
subject { Net::LDAP::Connection.new(:server => 'test.mocked.com', :port => 636) }
|
||||
|
||||
it "should get back error messages if operation fails" do
|
||||
ber = Net::BER::BerIdentifiedArray.new([53, "", "The provided password value was rejected by a password validator: The provided password did not contain enough characters from the character set 'ABCDEFGHIJKLMNOPQRSTUVWXYZ'. The minimum number of characters from that set that must be present in user passwords is 1"])
|
||||
ber.ber_identifier = 7
|
||||
@tcp_socket.should_receive(:read_ber).and_return([2, ber])
|
||||
|
||||
result = subject.modify(:dn => "1", :operations => [[:replace, "mail", "something@sothsdkf.com"]])
|
||||
result.should be_failure
|
||||
result.error_message.should == "The provided password value was rejected by a password validator: The provided password did not contain enough characters from the character set 'ABCDEFGHIJKLMNOPQRSTUVWXYZ'. The minimum number of characters from that set that must be present in user passwords is 1"
|
||||
end
|
||||
|
||||
it "shouldn't get back error messages if operation succeeds" do
|
||||
ber = Net::BER::BerIdentifiedArray.new([0, "", ""])
|
||||
ber.ber_identifier = 7
|
||||
@tcp_socket.should_receive(:read_ber).and_return([2, ber])
|
||||
|
||||
result = subject.modify(:dn => "1", :operations => [[:replace, "mail", "something@sothsdkf.com"]])
|
||||
result.should be_success
|
||||
result.error_message.should == ""
|
||||
end
|
||||
end
|
||||
end
|
||||
|
|
|
@ -9,11 +9,11 @@ class TestFilter < Test::Unit::TestCase
|
|||
end
|
||||
|
||||
def test_invalid_filter_string
|
||||
assert_raises(Net::LDAP::LdapError) { Filter.from_rfc2254("") }
|
||||
assert_raises(Net::LDAP::FilterSyntaxInvalidError) { Filter.from_rfc2254("") }
|
||||
end
|
||||
|
||||
def test_invalid_filter
|
||||
assert_raises(Net::LDAP::LdapError) {
|
||||
assert_raises(Net::LDAP::OperatorError) {
|
||||
# This test exists to prove that our constructor blocks unknown filter
|
||||
# types. All filters must be constructed using helpers.
|
||||
Filter.__send__(:new, :xx, nil, nil)
|
||||
|
@ -31,92 +31,92 @@ class TestFilter < Test::Unit::TestCase
|
|||
assert_equal("(uid=*\\5C*)", Filter.contains("uid", "\\").to_s)
|
||||
end
|
||||
|
||||
def test_c2
|
||||
def test_c2
|
||||
assert_equal("(uid=george *)",
|
||||
Filter.from_rfc2254("uid=george *").to_rfc2254)
|
||||
assert_equal("(uid:=george *)",
|
||||
Filter.from_rfc2254("uid:=george *").to_rfc2254)
|
||||
assert_equal("(uid=george*)",
|
||||
Filter.from_rfc2254(" ( uid = george* ) ").to_rfc2254)
|
||||
assert_equal("(!(uid=george*))",
|
||||
assert_equal("(!(uid=george*))",
|
||||
Filter.from_rfc2254("uid!=george*").to_rfc2254)
|
||||
assert_equal("(uid<=george*)",
|
||||
assert_equal("(uid<=george*)",
|
||||
Filter.from_rfc2254("uid <= george*").to_rfc2254)
|
||||
assert_equal("(uid>=george*)",
|
||||
assert_equal("(uid>=george*)",
|
||||
Filter.from_rfc2254("uid>=george*").to_rfc2254)
|
||||
assert_equal("(&(uid=george*)(mail=*))",
|
||||
assert_equal("(&(uid=george*)(mail=*))",
|
||||
Filter.from_rfc2254("(& (uid=george* ) (mail=*))").to_rfc2254)
|
||||
assert_equal("(|(uid=george*)(mail=*))",
|
||||
assert_equal("(|(uid=george*)(mail=*))",
|
||||
Filter.from_rfc2254("(| (uid=george* ) (mail=*))").to_rfc2254)
|
||||
assert_equal("(!(mail=*))",
|
||||
assert_equal("(!(mail=*))",
|
||||
Filter.from_rfc2254("(! (mail=*))").to_rfc2254)
|
||||
end
|
||||
end
|
||||
|
||||
def test_filter_with_single_clause
|
||||
assert_equal("(cn=name)", Net::LDAP::Filter.construct("(&(cn=name))").to_s)
|
||||
def test_filter_with_single_clause
|
||||
assert_equal("(cn=name)", Net::LDAP::Filter.construct("(&(cn=name))").to_s)
|
||||
end
|
||||
|
||||
def test_filters_from_ber
|
||||
[
|
||||
Net::LDAP::Filter.eq("objectclass", "*"),
|
||||
Net::LDAP::Filter.pres("objectclass"),
|
||||
Net::LDAP::Filter.eq("objectclass", "ou"),
|
||||
Net::LDAP::Filter.ge("uid", "500"),
|
||||
Net::LDAP::Filter.le("uid", "500"),
|
||||
(~ Net::LDAP::Filter.pres("objectclass")),
|
||||
(Net::LDAP::Filter.pres("objectclass") & Net::LDAP::Filter.pres("ou")),
|
||||
(Net::LDAP::Filter.pres("objectclass") & Net::LDAP::Filter.pres("ou") & Net::LDAP::Filter.pres("sn")),
|
||||
(Net::LDAP::Filter.pres("objectclass") | Net::LDAP::Filter.pres("ou") | Net::LDAP::Filter.pres("sn")),
|
||||
|
||||
Net::LDAP::Filter.eq("objectclass", "*aaa"),
|
||||
Net::LDAP::Filter.eq("objectclass", "*aaa*bbb"),
|
||||
Net::LDAP::Filter.eq("objectclass", "*aaa*bbb*ccc"),
|
||||
Net::LDAP::Filter.eq("objectclass", "aaa*bbb"),
|
||||
Net::LDAP::Filter.eq("objectclass", "aaa*bbb*ccc"),
|
||||
Net::LDAP::Filter.eq("objectclass", "abc*def*1111*22*g"),
|
||||
Net::LDAP::Filter.eq("objectclass", "*aaa*"),
|
||||
Net::LDAP::Filter.eq("objectclass", "*aaa*bbb*"),
|
||||
Net::LDAP::Filter.eq("objectclass", "*aaa*bbb*ccc*"),
|
||||
Net::LDAP::Filter.eq("objectclass", "aaa*"),
|
||||
Net::LDAP::Filter.eq("objectclass", "aaa*bbb*"),
|
||||
Net::LDAP::Filter.eq("objectclass", "aaa*bbb*ccc*"),
|
||||
].each do |ber|
|
||||
f = Net::LDAP::Filter.parse_ber(ber.to_ber.read_ber(Net::LDAP::AsnSyntax))
|
||||
assert(f == ber)
|
||||
assert_equal(f.to_ber, ber.to_ber)
|
||||
end
|
||||
end
|
||||
|
||||
def test_filters_from_ber
|
||||
[
|
||||
Net::LDAP::Filter.eq("objectclass", "*"),
|
||||
Net::LDAP::Filter.pres("objectclass"),
|
||||
Net::LDAP::Filter.eq("objectclass", "ou"),
|
||||
Net::LDAP::Filter.ge("uid", "500"),
|
||||
Net::LDAP::Filter.le("uid", "500"),
|
||||
(~ Net::LDAP::Filter.pres("objectclass")),
|
||||
(Net::LDAP::Filter.pres("objectclass") & Net::LDAP::Filter.pres("ou")),
|
||||
(Net::LDAP::Filter.pres("objectclass") & Net::LDAP::Filter.pres("ou") & Net::LDAP::Filter.pres("sn")),
|
||||
(Net::LDAP::Filter.pres("objectclass") | Net::LDAP::Filter.pres("ou") | Net::LDAP::Filter.pres("sn")),
|
||||
def test_ber_from_rfc2254_filter
|
||||
[
|
||||
Net::LDAP::Filter.construct("objectclass=*"),
|
||||
Net::LDAP::Filter.construct("objectclass=ou"),
|
||||
Net::LDAP::Filter.construct("uid >= 500"),
|
||||
Net::LDAP::Filter.construct("uid <= 500"),
|
||||
Net::LDAP::Filter.construct("(!(uid=*))"),
|
||||
Net::LDAP::Filter.construct("(&(uid=*)(objectclass=*))"),
|
||||
Net::LDAP::Filter.construct("(&(uid=*)(objectclass=*)(sn=*))"),
|
||||
Net::LDAP::Filter.construct("(|(uid=*)(objectclass=*))"),
|
||||
Net::LDAP::Filter.construct("(|(uid=*)(objectclass=*)(sn=*))"),
|
||||
|
||||
Net::LDAP::Filter.eq("objectclass", "*aaa"),
|
||||
Net::LDAP::Filter.eq("objectclass", "*aaa*bbb"),
|
||||
Net::LDAP::Filter.eq("objectclass", "*aaa*bbb*ccc"),
|
||||
Net::LDAP::Filter.eq("objectclass", "aaa*bbb"),
|
||||
Net::LDAP::Filter.eq("objectclass", "aaa*bbb*ccc"),
|
||||
Net::LDAP::Filter.eq("objectclass", "abc*def*1111*22*g"),
|
||||
Net::LDAP::Filter.eq("objectclass", "*aaa*"),
|
||||
Net::LDAP::Filter.eq("objectclass", "*aaa*bbb*"),
|
||||
Net::LDAP::Filter.eq("objectclass", "*aaa*bbb*ccc*"),
|
||||
Net::LDAP::Filter.eq("objectclass", "aaa*"),
|
||||
Net::LDAP::Filter.eq("objectclass", "aaa*bbb*"),
|
||||
Net::LDAP::Filter.eq("objectclass", "aaa*bbb*ccc*"),
|
||||
].each do |ber|
|
||||
f = Net::LDAP::Filter.parse_ber(ber.to_ber.read_ber(Net::LDAP::AsnSyntax))
|
||||
assert(f == ber)
|
||||
assert_equal(f.to_ber, ber.to_ber)
|
||||
end
|
||||
end
|
||||
|
||||
def test_ber_from_rfc2254_filter
|
||||
[
|
||||
Net::LDAP::Filter.construct("objectclass=*"),
|
||||
Net::LDAP::Filter.construct("objectclass=ou"),
|
||||
Net::LDAP::Filter.construct("uid >= 500"),
|
||||
Net::LDAP::Filter.construct("uid <= 500"),
|
||||
Net::LDAP::Filter.construct("(!(uid=*))"),
|
||||
Net::LDAP::Filter.construct("(&(uid=*)(objectclass=*))"),
|
||||
Net::LDAP::Filter.construct("(&(uid=*)(objectclass=*)(sn=*))"),
|
||||
Net::LDAP::Filter.construct("(|(uid=*)(objectclass=*))"),
|
||||
Net::LDAP::Filter.construct("(|(uid=*)(objectclass=*)(sn=*))"),
|
||||
|
||||
Net::LDAP::Filter.construct("objectclass=*aaa"),
|
||||
Net::LDAP::Filter.construct("objectclass=*aaa*bbb"),
|
||||
Net::LDAP::Filter.construct("objectclass=*aaa bbb"),
|
||||
Net::LDAP::Filter.construct("objectclass=*aaa bbb"),
|
||||
Net::LDAP::Filter.construct("objectclass=*aaa*bbb*ccc"),
|
||||
Net::LDAP::Filter.construct("objectclass=aaa*bbb"),
|
||||
Net::LDAP::Filter.construct("objectclass=aaa*bbb*ccc"),
|
||||
Net::LDAP::Filter.construct("objectclass=abc*def*1111*22*g"),
|
||||
Net::LDAP::Filter.construct("objectclass=*aaa*"),
|
||||
Net::LDAP::Filter.construct("objectclass=*aaa*bbb*"),
|
||||
Net::LDAP::Filter.construct("objectclass=*aaa*bbb*ccc*"),
|
||||
Net::LDAP::Filter.construct("objectclass=aaa*"),
|
||||
Net::LDAP::Filter.construct("objectclass=aaa*bbb*"),
|
||||
Net::LDAP::Filter.construct("objectclass=aaa*bbb*ccc*"),
|
||||
].each do |ber|
|
||||
f = Net::LDAP::Filter.parse_ber(ber.to_ber.read_ber(Net::LDAP::AsnSyntax))
|
||||
assert(f == ber)
|
||||
assert_equal(f.to_ber, ber.to_ber)
|
||||
end
|
||||
end
|
||||
Net::LDAP::Filter.construct("objectclass=*aaa"),
|
||||
Net::LDAP::Filter.construct("objectclass=*aaa*bbb"),
|
||||
Net::LDAP::Filter.construct("objectclass=*aaa bbb"),
|
||||
Net::LDAP::Filter.construct("objectclass=*aaa bbb"),
|
||||
Net::LDAP::Filter.construct("objectclass=*aaa*bbb*ccc"),
|
||||
Net::LDAP::Filter.construct("objectclass=aaa*bbb"),
|
||||
Net::LDAP::Filter.construct("objectclass=aaa*bbb*ccc"),
|
||||
Net::LDAP::Filter.construct("objectclass=abc*def*1111*22*g"),
|
||||
Net::LDAP::Filter.construct("objectclass=*aaa*"),
|
||||
Net::LDAP::Filter.construct("objectclass=*aaa*bbb*"),
|
||||
Net::LDAP::Filter.construct("objectclass=*aaa*bbb*ccc*"),
|
||||
Net::LDAP::Filter.construct("objectclass=aaa*"),
|
||||
Net::LDAP::Filter.construct("objectclass=aaa*bbb*"),
|
||||
Net::LDAP::Filter.construct("objectclass=aaa*bbb*ccc*"),
|
||||
].each do |ber|
|
||||
f = Net::LDAP::Filter.parse_ber(ber.to_ber.read_ber(Net::LDAP::AsnSyntax))
|
||||
assert(f == ber)
|
||||
assert_equal(f.to_ber, ber.to_ber)
|
||||
end
|
||||
end
|
||||
end
|
||||
|
|
|
@ -31,8 +31,20 @@ class TestLdif < Test::Unit::TestCase
|
|||
end
|
||||
|
||||
def test_ldif_with_continuation_lines
|
||||
ds = Net::LDAP::Dataset::read_ldif(StringIO.new("dn: abcdefg\r\n hijklmn\r\n\r\n"))
|
||||
assert_equal(true, ds.has_key?("abcdefg hijklmn"))
|
||||
ds = Net::LDAP::Dataset::read_ldif(StringIO.new("dn: abcdefg\r\n hijklmn\r\n\r\n"))
|
||||
assert_equal(true, ds.has_key?("abcdefghijklmn"))
|
||||
end
|
||||
|
||||
def test_ldif_with_continuation_lines_and_extra_whitespace
|
||||
ds1 = Net::LDAP::Dataset::read_ldif(StringIO.new("dn: abcdefg\r\n hijklmn\r\n\r\n"))
|
||||
assert_equal(true, ds1.has_key?("abcdefg hijklmn"))
|
||||
ds2 = Net::LDAP::Dataset::read_ldif(StringIO.new("dn: abcdefg\r\n hij klmn\r\n\r\n"))
|
||||
assert_equal(true, ds2.has_key?("abcdefghij klmn"))
|
||||
end
|
||||
|
||||
def test_ldif_tab_is_not_continuation
|
||||
ds = Net::LDAP::Dataset::read_ldif(StringIO.new("dn: key\r\n\tnotcontinued\r\n\r\n"))
|
||||
assert_equal(true, ds.has_key?("key"))
|
||||
end
|
||||
|
||||
# TODO, INADEQUATE. We need some more tests
|
||||
|
|
Loading…
Reference in New Issue