Skip to content

Commit 9e651df

Browse files
committed
Implement custom tls options
This allows users of the API to either specify a simple CA-File for certificate verification, or a custom SSLContext in order for a more fine-grained control of the TLS options they want to use. As of now, no additional tests were added, but the existing tests were changed to reflect the changes in internal methods, so that they can still pass
1 parent 1dc2907 commit 9e651df

File tree

3 files changed

+29
-9
lines changed

3 files changed

+29
-9
lines changed

lib/net/ldap.rb

Lines changed: 11 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -537,10 +537,6 @@ def authenticate(username, password)
537537
# additional capabilities are added, more configuration values will be
538538
# added here.
539539
#
540-
# Currently, the only supported argument is { :method => :simple_tls }.
541-
# (Equivalently, you may pass the symbol :simple_tls all by itself,
542-
# without enclosing it in a Hash.)
543-
#
544540
# The :simple_tls encryption method encrypts <i>all</i> communications
545541
# with the LDAP server. It completely establishes SSL/TLS encryption with
546542
# the LDAP server before any LDAP-protocol data is exchanged. There is no
@@ -563,6 +559,17 @@ def authenticate(username, password)
563559
# The :start_tls like the :simple_tls encryption method also encrypts all
564560
# communcations with the LDAP server. With the exception that it operates
565561
# over the standard TCP port.
562+
#
563+
# In order to allow verification of server certificates and other TLS-related
564+
# options, the keys :cafile and :ssl_context can be used.
565+
#
566+
# The :cafile option is a single filename that points to one or more
567+
# PEM-encoded certificates. These certificates are used as a certificate auhority
568+
# to verify the server certificates.
569+
#
570+
# For fine-grained control of the TLS settings, it is also possible to use the
571+
# :ssl_context option to pass a custom OpenSSL::SSL::SSLContext. Consult the
572+
# OpenSSL documentation for more information on the available options.
566573
def encryption(args)
567574
case args
568575
when :simple_tls, :start_tls

lib/net/ldap/connection.rb

Lines changed: 17 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -17,6 +17,8 @@ def initialize(server)
1717
raise Net::LDAP::LdapError, "Server #{server[:host]} refused connection on port #{server[:port]}."
1818
rescue Errno::EHOSTUNREACH => error
1919
raise Net::LDAP::LdapError, "Host #{server[:host]} was unreachable (#{error.message})"
20+
rescue Errno::ETIMEDOUT
21+
raise Net::LDAP::LdapError, "Connection to #{server[:host]} timed out."
2022
end
2123

2224
if server[:encryption]
@@ -39,9 +41,20 @@ def close
3941
end
4042
end
4143

42-
def self.wrap_with_ssl(io)
44+
def self.wrap_with_ssl(io, ssl_context = nil, cafile = nil)
4345
raise Net::LDAP::LdapError, "OpenSSL is unavailable" unless Net::LDAP::HasOpenSSL
44-
ctx = OpenSSL::SSL::SSLContext.new
46+
if (ssl_context && cafile)
47+
raise Net::LDAP::LdapError, "Please specify only one of ssl_context or cafile"
48+
end
49+
50+
ctx = ssl_context ? ssl_context : OpenSSL::SSL::SSLContext.new
51+
52+
# OpenSSL automatically merges the given parameters with the default parameters
53+
# These include verification and some common workarounds
54+
if cafile
55+
ctx.set_params({:ca_file => cafile})
56+
end
57+
4558
conn = OpenSSL::SSL::SSLSocket.new(io, ctx)
4659
conn.connect
4760

@@ -83,7 +96,7 @@ def self.wrap_with_ssl(io)
8396
def setup_encryption(args)
8497
case args[:method]
8598
when :simple_tls
86-
@conn = self.class.wrap_with_ssl(@conn)
99+
@conn = self.class.wrap_with_ssl(@conn, args[:ssl_context], args[:cafile])
87100
# additional branches requiring server validation and peer certs, etc.
88101
# go here.
89102
when :start_tls
@@ -100,7 +113,7 @@ def setup_encryption(args)
100113
end
101114

102115
if pdu.result_code.zero?
103-
@conn = self.class.wrap_with_ssl(@conn)
116+
@conn = self.class.wrap_with_ssl(@conn, args[:ssl_context], args[:cafile])
104117
else
105118
raise Net::LDAP::LdapError, "start_tls failed: #{pdu.result_code}"
106119
end

test/test_ldap_connection.rb

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -202,7 +202,7 @@ def test_queued_read_setup_encryption_with_start_tls
202202
and_return(result2)
203203
mock.should_receive(:write)
204204
conn = Net::LDAP::Connection.new(:socket => mock)
205-
flexmock(Net::LDAP::Connection).should_receive(:wrap_with_ssl).with(mock).
205+
flexmock(Net::LDAP::Connection).should_receive(:wrap_with_ssl).with(mock, nil, nil).
206206
and_return(mock)
207207

208208
conn.next_msgid # simulates ongoing query

0 commit comments

Comments
 (0)