Secure Java Authentication (SSL) to Active Directory

Following on from an old article I wrote, with regards to getting your java applications to authenticate against an LDAP compliant directory server, I thought I’d write another article explaining how to encrypt your communication. It’s all very well getting your users to authenticate against AD, but sending their username/password in cleartext isn’t ideal.

To begin, I have a default installation of Windows Server 2012 R2 onto which I have installed the Active Directory Domain Services role. I created a new user, setup a password and tested I could connect to AD via java using port 389 (unencrypted). It’s also useful to note you can test this with the Microsoft built in client ldp.exe (I’ll be using this later).

You might well have an AD server setup that already supports using port 636 with SSL, but for completeness I’ll explain what I did for testing, as it took a little while to find the correct information. I found various articles about creating a certificate authority, self signing a certificate, then importing into various places using mmc.exe. None of these seemed to work for me and I was unable to establish an SSL connection over port 636 using ldp.exe. In the end I added the role Active Directory Certificate Services (just the Certificate Authority part) and followed the configuration wizard to create an initial certificate. After rebooting the server, the certificate was up and running and a simple Connect using server, port, SSL checked in ldp.exe worked! See the acknowledgements section at the bottom for a guide on installing AD Certificate Services. It’s important you succeed in connecting before moving onto the java code as SSL can with fiddly enough without fighting against other configuration issues as well.

The alterations needed to the code from the original article are pretty small. To keep it short, I assume SSL is required if the default port 636 is used.

LDAPConnection conn = null;
if (port == 636) {
    conn = new LDAPConnection(new LDAPJSSESecureSocketFactory());
} else {
    conn = new LDAPConnection();
}
conn.connect(host, port);

If you have purchased an SSL certificate from a trusted certificate authority, you should be ready to go. If you are using a self signed SSL certificate you’ll see the following errors when trying to bind.

javax.net.ssl.SSLHandshakeException: sun.security.validator.ValidatorException: PKIX path building failed: sun.security.provider.certpath.SunCertPathBuilderException: unable to find valid certification path to requested target
Caused by: sun.security.validator.ValidatorException: PKIX path building failed: sun.security.provider.certpath.SunCertPathBuilderException: unable to find valid certification path to requested target
Caused by: sun.security.provider.certpath.SunCertPathBuilderException: unable to find valid certification path to requested target

To stop this, you need to export the certificate from the AD server and import it into a java keystore so you acknowledge you trust it. Using mmc.exe (add the Certificates snapon if it’s not already added), look in Certificates (Local Computer) – Personal – Certificates and find the AD certificate. Right click on it, All Tasks – Export, do NOT export the private key and export in DER format. I called mine ad-server.cer

The following command will create a new java keystore (called cacerts in the current directory) and import the certificate you just exported.

keytool -import -alias ad.tilion.org.uk -keystore cacerts -file ad-server.cer

You can double check the import with the following command.

keytool -list -keystore cacerts

To run your java code with the new keystore, you need to use javax.net.ssl.trustStore and javax.net.ssl.trustStorePassword if your keystore requires a password. Pay careful attention to the variable names as there are equivalent ending in keyStore, but it’s important we use trustStore in this case. For example;

java -Djavax.net.ssl.trustStore=PATH_TO/cacerts -jar app.jar

If your code is a webapp deployed in something like Apache Tomcat you need to make the addition to the Tomcat startup. For the windows service install, right click on the service monitor and from the menu, Configure…, then under the Java tab update the Java Options: by adding the extra variables. For other Apache Tomcat installs, you need to add to the JAVA_OPTS parameter in catalina.bat or catalina.sh depending if you’re using Windows or Linux.

As a final note, this article describes how to use SSL on port 636. The encrypted channel is setup before any LDAP related communication takes place. If you’re trying to setup TLS it might be working over the default 389 port as TLS is an option that can be enabled by supported clients over unencrypted ports. LDAP communication will take place before the client tries to enable TLS.

Acknowledgements

Leave a Reply

Your email address will not be published. Required fields are marked *

Security Question * Time limit is exhausted. Please reload the CAPTCHA.