diff --git a/lib/net/ldap.rb b/lib/net/ldap.rb index 87c7eccb..b181d83d 100644 --- a/lib/net/ldap.rb +++ b/lib/net/ldap.rb @@ -537,10 +537,6 @@ 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 :simple_tls encryption method encrypts all communications # with the LDAP server. It completely establishes SSL/TLS encryption with # the LDAP server before any LDAP-protocol data is exchanged. There is no @@ -563,10 +559,30 @@ def authenticate(username, password) # The :start_tls like the :simple_tls encryption method also encrypts all # communcations with the LDAP server. With the exception that it operates # over the standard TCP port. + # + # In order to verify certificates and enable other TLS options, the + # :tls_options hash can be passed alongside :simple_tls or :start_tls. + # This hash contains any options that can be passed to + # OpenSSL::SSL::SSLContext#set_params(). The most common options passed + # should be OpenSSL::SSL::SSLContext::DEFAULT_PARAMS, or the :ca_file option, + # which contains a path to a Certificate Authority file (PEM-encoded). + # + # Example for a default setup without custom settings: + # { + # :method => :simple_tls, + # :tls_options => OpenSSL::SSL::SSLContext::DEFAULT_PARAMS + # } + # + # Example for specifying a CA-File and only allowing TLSv1.1 connections: + # + # { + # :method => :start_tls, + # :tls_options => { :ca_file => "/etc/cafile.pem", :ssl_version => "TLSv1_1" } + # } def encryption(args) case args when :simple_tls, :start_tls - args = { :method => args } + args = { :method => args, :tls_options => {} } end @encryption = args end diff --git a/lib/net/ldap/connection.rb b/lib/net/ldap/connection.rb index 508e37ac..6371f636 100644 --- a/lib/net/ldap/connection.rb +++ b/lib/net/ldap/connection.rb @@ -41,9 +41,15 @@ def close end end - def self.wrap_with_ssl(io) + def self.wrap_with_ssl(io, tls_options = {}) raise Net::LDAP::LdapError, "OpenSSL is unavailable" unless Net::LDAP::HasOpenSSL + ctx = OpenSSL::SSL::SSLContext.new + + # By default, we do not verify certificates. For a 1.0 release, this should probably be changed at some point. + # See discussion in https://github.com/ruby-ldap/ruby-net-ldap/pull/161 + ctx.set_params(tls_options) unless tls_options.empty? + conn = OpenSSL::SSL::SSLSocket.new(io, ctx) conn.connect @@ -85,7 +91,7 @@ def self.wrap_with_ssl(io) def setup_encryption(args) case args[:method] when :simple_tls - @conn = self.class.wrap_with_ssl(@conn) + @conn = self.class.wrap_with_ssl(@conn, args[:tls_options]) # additional branches requiring server validation and peer certs, etc. # go here. when :start_tls @@ -102,7 +108,7 @@ def setup_encryption(args) end if pdu.result_code.zero? - @conn = self.class.wrap_with_ssl(@conn) + @conn = self.class.wrap_with_ssl(@conn, args[:tls_options]) else raise Net::LDAP::LdapError, "start_tls failed: #{pdu.result_code}" end diff --git a/test/test_ldap_connection.rb b/test/test_ldap_connection.rb index 56dfe813..0bffb66a 100644 --- a/test/test_ldap_connection.rb +++ b/test/test_ldap_connection.rb @@ -202,7 +202,7 @@ def test_queued_read_setup_encryption_with_start_tls and_return(result2) mock.should_receive(:write) conn = Net::LDAP::Connection.new(:socket => mock) - flexmock(Net::LDAP::Connection).should_receive(:wrap_with_ssl).with(mock). + flexmock(Net::LDAP::Connection).should_receive(:wrap_with_ssl).with(mock, nil). and_return(mock) conn.next_msgid # simulates ongoing query