Skip to content

Instantly share code, notes, and snippets.

Embed
What would you like to do?
Verify the certificate of secure LDAP server using net-ldap ruby gem
class Net::LDAP
def initialize(args = {})
@host = args[:host] || DefaultHost
@port = args[:port] || DefaultPort
@verbose = false # Make this configurable with a switch on the class.
@auth = args[:auth] || DefaultAuth
@base = args[:base] || DefaultTreebase
encryption args[:encryption] # may be nil
# Certificate authority store - should of class OpenSSL::X509::Store
# Used to store the root CA certificate, which can later be used to authenticate the peer certificate
# of secure LDAP certificate
cert_store args[:cert_store] # may be nil #ADDED
if pr = @auth[:password] and pr.respond_to?(:call)
@auth[:password] = pr.call
end
# This variable is only set when we are created with LDAP::open. All of
# our internal methods will connect using it, or else they will create
# their own.
@open_connection = nil
end
# Function to set certificate store as instance variable
def cert_store(args) #ADDED
@encryption[:cert_store] = args
end
end
class Net::LDAP::Connection
def self.wrap_with_ssl(io,cert_store=nil) #CHANGED
raise Net::LDAP::LdapError, "OpenSSL is unavailable" unless Net::LDAP::HasOpenSSL
ctx = OpenSSL::SSL::SSLContext.new
# Set the cert_store and force OpenSSL to verifiy the server certificate using it if cert_store is defined
ctx.cert_store = cert_store if cert_store #ADDED
ctx.verify_mode = OpenSSL::SSL::VERIFY_PEER if cert_store #ADDED
conn = OpenSSL::SSL::SSLSocket.new(io, ctx)
conn.connect
conn.sync_close = true
conn.extend(GetbyteForSSLSocket) unless conn.respond_to?(:getbyte)
conn
end
def setup_encryption(args)
case args[:method]
when :simple_tls
@conn = self.class.wrap_with_ssl(@conn, args[:cert_store]) #CHANGED
# additional branches requiring server validation and peer certs, etc.
# go here.
when :start_tls
msgid = next_msgid.to_ber
request = [Net::LDAP::StartTlsOid.to_ber].to_ber_appsequence(Net::LDAP::PDU::ExtendedRequest)
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?
pdu = Net::LDAP::PDU.new(be)
raise Net::LDAP::LdapError, "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}"
end
else
raise Net::LDAP::LdapError, "unsupported encryption method #{args[:method]}"
end
end
end
@hasan-ally

This comment has been minimized.

Copy link
Owner Author

@hasan-ally hasan-ally commented Apr 2, 2014

Place the above file in your config/initializers directory if you are using it in rails app.

Note the lines marked with #ADDED and #CHANGED comments to see the difference with original code

Usage:

# peer_cert is the public certificate which openssl uses to decrypt the data which is sent over ssl
# Find the root CA of the ldap server and add it as cert_store
cert_store = OpenSSL::X509::Store.new if options["cert_store"]

cert_store.add_cert OpenSSL::X509::Certificate.new(root_ca_cert_content)

ldap = Net::LDAP.new({
                        :host => host, 
                        :port => port,
                        :auth => { :method => :simple,  :username => binding_username, :password => binding_password },
                        :encryption =>  :simple_tls,
                        :cert_store => cert_store
                      }

Note: Net::LDAP now accepts an additional argument :cert_store

Though, I have verfied it in ldap authentication scenario only, Other cases like search should work fine

@hasan-chronus

This comment has been minimized.

Copy link

@hasan-chronus hasan-chronus commented Oct 8, 2014

Ideal Solution:
Maintain list of trusted root CAs on your server (have a cron job which will download (weekly maintained by curl) copy from http://curl.haxx.se/ca/cacert.pem)
Override Net::HTTP to always use this trusted certificate list

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment