Monday, May 8, 2006

Disable Cert Validation for LDAP and HTTP over SSL

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:

[sourcecode language="java"]
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://:636";
// domain is the Active Directory domain i.e. "yourdomain.com"
String domain = "";
// the sAMAccountName (i.e. jsmith)
String login = "";
String 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();
}[/sourcecode]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:

[sourcecode language="java"]
// host name of server running SSL with invalid cert
String 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();
}[/sourcecode]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. (click here to download)

Comments welcome...