diff --git a/lib/net/ldap.rb b/lib/net/ldap.rb index be21c1ef..4b42a83d 100644 --- a/lib/net/ldap.rb +++ b/lib/net/ldap.rb @@ -456,9 +456,8 @@ def authenticate(username, password) # additional capabilities are added, more configuration values will be # added here. # - # Currently, the only supported argument is { :method => :simple_tls }. - # (Equivalently, you may pass the symbol :simple_tls all by itself, - # without enclosing it in a Hash.) + # The supported methods are { :method => :simple_tls } and { :method => + # :start_tls }. # # The :simple_tls encryption method encrypts all communications # with the LDAP server. It completely establishes SSL/TLS encryption with @@ -479,9 +478,13 @@ def authenticate(username, password) # standard port for simple-TLS encrypted connections is 636. Be sure you # are using the correct port. # - # [Note: a future version of Net::LDAP will support the STARTTLS LDAP - # control, which will enable encrypted communications on the same TCP port - # used for unencrypted connections.] + # Using :start_tls you are able to verify the peer in the TLS + # negotiation. To verify the peer, you can add the :cafile element + # with the path to a file containing one or more valid PEM formatted + # CA certificates. For example: + # { :method => :start_tls, :cafile => '/etc/ssl/cafile.pem' } + # Net::Ldap will raise an exception if the CA file doesn't exist, or if + # the peer fails TLS verification. def encryption(args) case args when :simple_tls, :start_tls @@ -1160,9 +1163,19 @@ def getbyte end end - def self.wrap_with_ssl(io) + def self.wrap_with_ssl(io,*args) + raise Net::LDAP::LdapError, "OpenSSL is unavailable" unless Net::LDAP::HasOpenSSL ctx = OpenSSL::SSL::SSLContext.new + # If we've been given a cafile in the arguments hash, then we want to + # actually verify the TLS connection rather than just the default of + # NO_VERIFY. + if args.last.instance_of?(Hash) && args.last.has_key?(:cafile) + cafile = args.last[:cafile] + ctx.verify_mode = OpenSSL::SSL::VERIFY_PEER + raise "CA file '#{cafile}' doesn't exist" unless File.exists? cafile + ctx.ca_file = cafile + end conn = OpenSSL::SSL::SSLSocket.new(io, ctx) conn.connect conn.sync_close = true @@ -1213,8 +1226,11 @@ def setup_encryption(args) raise Net::LDAP::LdapError, "no start_tls result" if be.nil? pdu = Net::LDAP::PDU.new(be) raise Net::LDAP::LdapError, "no start_tls result" if pdu.nil? + + a = { :cafile => args[:cafile] } if args[:cafile] + if pdu.result_code.zero? - @conn = self.class.wrap_with_ssl(@conn) + @conn = self.class.wrap_with_ssl(@conn,a) else raise Net::LDAP::LdapError, "start_tls failed: #{pdu.result_code}" end