Platinum Solutions Corporate Website


Disable Cert Validation for LDAP and HTTP over SSL

The answer you entered to the math problem is incorrect.

Have you ever been developing something requiring a connection to a development server over SSL?  Was the server not under your control?  And you had either an invalid, corrupt or possibly no cert at all to add to your trustStore?

We won't go into why this scenario may occur... but I know there are quite a few people out there asking how to bypass the cert validation for HTTPS and LDAP over SSL (LDAPS) connections.

The place to start is the SSLSocketFactory and more specifically the TrustManager you use. 

In the sample reference file "BlindSSLSocketFactoryTest.java" we establish connections to HTTPS and Active Directory via SSL (LDAPS) servers without valid certs by using our own SSLSocketFactory.  We need to come up with a SSLSocketFactory that will use a TrustManager list we specify as an alternative to the SSLSocketFactory that will be used by the JVM.

Our socket factory will create a real SSLSocketFactory using an X509TrustManager created as an anonymous inner class with methods designed to simply fall down on the job when asked to validate certificates.  All of our implementations of the SocketFactory's methods will in turn call the created SSLSocketFactory's methods.  To use this class when connecting to an Active Directory server over SSL, we simply have to specify the "java.naming.ldap.factory.socket" property in our ldap context environment. 

The example below is taken from the main method of the BlindSSLSocketFactoryTest class:

boolean validateCert = false;

... clipped ...

// our environment
Hashtable env = new Hashtable();
// complete URL of Active Directory/LDAP server running SSL with invalid cert
String url = "ldaps://<URL TO YOUR AD SERVER>:636";
// domain is the Active Directory domain i.e. "yourdomain.com"
String domain = "<YOUR AD DOMAIN>";
// the sAMAccountName (i.e. jsmith)
String login = "<LOGIN>";
String password = "<PASSWORD>";
       
env.put(Context.INITIAL_CONTEXT_FACTORY, "com.sun.jndi.ldap.LdapCtxFactory");
env.put(Context.PROVIDER_URL, url);
env.put(Context.SECURITY_AUTHENTICATION, "simple");
env.put(Context.SECURITY_PRINCIPAL, login + "@" + domain);
env.put(Context.SECURITY_CREDENTIALS, password);

if (url.startsWith("ldaps") && !validateCert) {
    env.put("java.naming.ldap.factory.socket", BlindSSLSocketFactoryTest.class.getName());
}

try {
    LdapContext ctx = new InitialLdapContext(env, null);
    System.out.println("Successfull bind to " + url + "!");
} catch (AuthenticationException e) {
    System.out.println("The credentials could not be validated!");
} catch (NamingException e) {
    e.printStackTrace();

By using our "blind" SSLSocketFactory, we will be bypassing the cert validation when connecting to the Active Directory server.

Another use for our handy little class is to bypass cert validation when connecting to an HTTPS server.  Another example from main method:

// host name of server running SSL with invalid cert
String host = "<SSL WEB HOST>";
int port = 443;// modify this if other than default port.
       
try {
    SocketFactory sslFactory;
    if (validateCert) {
        sslFactory = SSLSocketFactory.getDefault();
    } else {
        sslFactory = BlindSSLSocketFactoryTest.getDefault();
    }
           
    SSLSocket s = (SSLSocket) sslFactory.createSocket(host, port);
    OutputStream out = s.getOutputStream();
           
    out.write("GET / HTTP/1.0\n\r\n\r".getBytes());
    out.flush();
    System.out.println("Successfull connection to " + host + ":" + port + "!");
} catch (IOException e) {
    e.printStackTrace();
}

As the security zealots will tell you, the best practice is to get a valid certificate and install it in your trustStore using the keytool and I agree with this.  But that being said, some of the scenarios described above still may occur during development and if you have a tight deadline to get a prototype out the door, this class/code may help.  Corrupt certs from servers you don't manage can be painful when trying to get the other party to move on something that is not deamed mission critical in development.

So take this code, create your own BlindSSLSocketFactory class (don't be lazy and just plug this in!!!) and let me know if it works for you.

Comments welcome...

AttachmentSize
BlindSSLSocketFactoryTest.java.txt5.55 KB

Comments

ajuehanim (not verified) Wed, 1969-12-31 20:00

Hi, i got this error when trying the above code against openLDAP. Can you please help me ? thanks.

javax.naming.CommunicationException: simple bind failed: 172.16.0.7:636 [Root exception is javax.net.ssl.SSLHandshakeException: Received fatal alert: handshake_failure]
at com.sun.jndi.ldap.LdapClient.authenticate(LdapClient.java:197)
at com.sun.jndi.ldap.LdapCtx.connect(LdapCtx.java:2637)
at com.sun.jndi.ldap.LdapCtx.(LdapCtx.java:283)
at com.sun.jndi.ldap.LdapCtxFactory.getUsingURL(LdapCtxFactory.java:175)
at com.sun.jndi.ldap.LdapCtxFactory.getUsingURLs(LdapCtxFactory.java:193)
at com.sun.jndi.ldap.LdapCtxFactory.getLdapCtxInstance(LdapCtxFactory.java:136)
at com.sun.jndi.ldap.LdapCtxFactory.getInitialContext(LdapCtxFactory.java:66)
at javax.naming.spi.NamingManager.getInitialContext(NamingManager.java:667)
at javax.naming.InitialContext.getDefaultInitCtx(InitialContext.java:247)
at javax.naming.InitialContext.init(InitialContext.java:223)
at javax.naming.ldap.InitialLdapContext.(InitialLdapContext.java:134)
at TestAD.authenticate(TestAD.java:51)
at TestAD.main(TestAD.java:22)
Caused by: javax.net.ssl.SSLHandshakeException: Received fatal alert: handshake_failure
at com.sun.net.ssl.internal.ssl.Alerts.getSSLException(Alerts.java:150)
at com.sun.net.ssl.internal.ssl.Alerts.getSSLException(Alerts.java:117)
at com.sun.net.ssl.internal.ssl.SSLSocketImpl.recvAlert(SSLSocketImpl.java:1542)
at com.sun.net.ssl.internal.ssl.SSLSocketImpl.readRecord(SSLSocketImpl.java:863)
at com.sun.net.ssl.internal.ssl.SSLSocketImpl.waitForClose(SSLSocketImpl.java:1345)
at com.sun.net.ssl.internal.ssl.HandshakeOutStream.flush(HandshakeOutStream.java:103)
at com.sun.net.ssl.internal.ssl.Handshaker.sendChangeCipherSpec(Handshaker.java:590)
at com.sun.net.ssl.internal.ssl.ClientHandshaker.sendChangeCipherAndFinish(ClientHandshaker.java:697)
at com.sun.net.ssl.internal.ssl.ClientHandshaker.serverHelloDone(ClientHandshaker.java:623)
at com.sun.net.ssl.internal.ssl.ClientHandshaker.processMessage(ClientHandshaker.java:160)
at com.sun.net.ssl.internal.ssl.Handshaker.processLoop(Handshaker.java:495)
at com.sun.net.ssl.internal.ssl.Handshaker.process_record(Handshaker.java:433)
at com.sun.net.ssl.internal.ssl.SSLSocketImpl.readRecord(SSLSocketImpl.java:815)
at com.sun.net.ssl.internal.ssl.SSLSocketImpl.performInitialHandshake(SSLSocketImpl.java:1025)
at com.sun.net.ssl.internal.ssl.SSLSocketImpl.readDataRecord(SSLSocketImpl.java:675)
at com.sun.net.ssl.internal.ssl.AppInputStream.read(AppInputStream.java:75)
at java.io.BufferedInputStream.fill(BufferedInputStream.java:218)
at java.io.BufferedInputStream.read1(BufferedInputStream.java:256)
at java.io.BufferedInputStream.read(BufferedInputStream.java:313)
at com.sun.jndi.ldap.Connection.run(Connection.java:784)
at java.lang.Thread.run(Thread.java:595)
false

Anonymous (not verified) Wed, 1969-12-31 20:00

Cool Mike ..It is gr8 piece of code..in development it comes handy...

Anonymous (not verified) Wed, 1969-12-31 20:00

Thank you!!! Solved another AD / LDAP nightmare.

The_OX (not verified) Wed, 1969-12-31 20:00

This has been of great help. I was able to connect to LDAP SSL as such but some of our servers had SubjectAltName set to Critical and due to that the validation was getting rejected. With this code, we can bypass the cert validations.

Thanks!!

Vijay (not verified) Wed, 1969-12-31 20:00

Thankq very much Mike for your help, I used u'r code in application and it worked. I am new to LDAP and JSSE , I struggled  with this problem for two days but couldn't find solution. Keep posting such stuff,it helps freshers like us to learn and understand concepts in a better way.

Thank you very much.

Regards,

Vijay B.

Vijay (not verified) Wed, 1969-12-31 20:00

Hi Mike,

            Thanks because of your code I was able to gain some knowledge about SSL. But when I tried implementing custom socket factory as you mentioned I received an error which says "The error is 10.233.8.21:636". Could you help me out in figuring out whats wrong over here.

            I am pasting the code of my method below and custom socket factory class which is just copy of your BlindSSLSocketFactoryTest.java

==========================authenticate method==================

public DirContext authenticate(String principle, String password) throws Exception
{
  // connect to , authenticate and return directory context
     Debug.out("principle: "+principle);
     Debug.out("password: "+password);

     Hashtable env = new Hashtable();
     env.put(Context.INITIAL_CONTEXT_FACTORY,"com.sun.jndi.ldap.LdapCtxFactory");
     env.put(Context.PROVIDER_URL, "ldaps://10.241.14.122:636");
     env.put("java.naming.ldap.factory.socket", SecureSSLSocketFactory.class.getName());
     env.put(Context.SECURITY_AUTHENTICATION,"simple");
     env.put(Context.SECURITY_PRINCIPAL,principle);
     env.put(Context.SECURITY_CREDENTIALS,password);    
     DirContext ctx = new InitialDirContext(env);
     return ctx

 

===========================================================

 

===================SecureSSLSocketFactory=====================

public class SecureSSLSocketFactory extends SocketFactory
{
    private static SocketFactory blindFactory = null;
   
    static
    {
     TrustManager[] blindTrustMan = new TrustManager[]
                                    {
              new X509TrustManager()
              {
               public X509Certificate[] getAcceptedIssuers() { return null; }
               public void checkClientTrusted(X509Certificate[] c, String a) { }
               public void checkServerTrusted(X509Certificate[] c, String a) { }
              }
                                    };
    }
   
    public static SocketFactory getDefault()
    {
  return new SecureSSLSocketFactory();
 }
   
    public Socket createSocket(String arg0, int arg1) throws IOException,UnknownHostException
    {
        return blindFactory.createSocket(arg0, arg1);
    }
   
    public Socket createSocket(InetAddress arg0, int arg1) throws IOException
    {
  return blindFactory.createSocket(arg0, arg1);
 }

    public Socket createSocket(String arg0, int arg1, InetAddress arg2, int arg3) throws IOException, UnknownHostException
    {
     return blindFactory.createSocket(arg0, arg1, arg2, arg3);
    }
   
    public Socket createSocket(InetAddress arg0, int arg1, InetAddress arg2,int arg3) throws IOException
    {
  return blindFactory.createSocket(arg0, arg1, arg2, arg3);
 }
      
}

===========================================================

Mike McKinney Wed, 1969-12-31 20:00

What was the exception that occurred?

Anonymous (not verified) Wed, 1969-12-31 20:00

Thanks a lot for this code ....

Mike McKinney Wed, 1969-12-31 20:00

Thanks "Anonymous"!!!  The attachment is fixed now.

Anonymous (not verified) Wed, 1969-12-31 20:00

Your attachment link is wrong.  It is:

/tmp/files/BlindSSLSocketFactoryTest.java.txt

But it should be:

files/BlindSSLSocketFactoryTest.java.txt

Post new comment

Please solve the math problem above and type in the result. e.g. for 1+1, type 2.
The content of this field is kept private and will not be shown publicly.
  • Lines and paragraphs break automatically.

More information about formatting options