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