Ldap Authentication using TLS in Java
by Mike
I was talking to Brophy about this a couple of weeks back and he told me that if I didn’t get it to work right away that I should give up and move on. I have to say, getting this authentication to work in Java is no fun, but I figure I would post some instructions up here and the pertinent code snippets as to give someone else a hand in the future.
First thing you have to know, is that you need a certificate for the TLS part. Get the certificate for the server from either the sys-admins of the system your doing this on, or grab it from its location on the server(I can’t really tell you this location because I went with option one).
Okay, so now you have your Certificate, the second thing you need on your server is Java’s keytool( see here ). The keytool manages a database of private keys and certificates and you need this to add your certificate to Java’s truststore so you can create a connection using your certificate.To use the keytool the command is:
keytool -import -file cert -keystore .truststore
(cert being your certificate) It will then prompt you for a password, so enter one, and don’t forget it.
Okay, so now that we’ve got this far, lets get to the code. You can grab it here .
(I just updated this and haven’t tested it, so if you have any problems leave a comment)
import javax.naming.*; import java.security.cert.*; import java.util.Hashtable; import javax.naming.ldap.*; import java.io.IOException; import java.io.PrintWriter; import java.security.Security; import java.io.UnsupportedEncodingException; public class LdapAuth{ private final String LDAPSERVER = "ldap://yourldapserver"; private final String TSLOCATION = "filesystemlocationofyourtruststore"; private final String TSPASSWORD = "passwordofyourtruststore"; public LdapAuth(){} public boolean authenticate(String user, String pass){ if((user == null) || (pass == null)){ return false; } try { //set up the system property for trustStore System.setProperty("javax.net.ssl.trustStore", TSLOCATION); System.setProperty("javax.net.ssl.trustStorePassword", TSPASSWORD); Hashtable env = new Hashtable(11); env.put(Context.INITIAL_CONTEXT_FACTORY, "com.sun.jndi.ldap.LdapCtxFactory"); env.put(Context.PROVIDER_URL, LDAPSERVER); //create initial LDAP context LdapContext ctx = new InitialLdapContext(env, null); //Use TLS to create a connection StartTlsResponse tls = (StartTlsResponse) ctx.extendedOperation(new StartTlsRequest()); tls.negotiate(); //authenticate as user, with pass String bind = "uid=" + user; //other ldap settings would go here too ctx.addToEnvironment(Context.SECURITY_AUTHENTICATION, "simple"); ctx.addToEnvironment(Context.SECURITY_PRINCIPAL, bind); ctx.addToEnvironment(Context.SECURITY_CREDENTIALS, pass); /** for it to actually do the authentication you have to do something with the connection so we are going to get attributes here if you are not authenticated this throws an exception so it is a good test */ ctx.getAttributes(bind); //stop TLS tls.close(); //close LDAP Context ctx.close(); //we got here so we are authenticated return true; } catch(AuthenticationException e){ //you probably want to log this (e.toString) return false; } catch(NamingException e){ //probably want to log this (e.toString) return false; } catch(IOException e){ //and you probably want to log this return false; } } }
So really there isn’t much else to it, but I do want to mention just one thing.
These lines of code:
System.setProperty("javax.net.ssl.trustStore",TSLOCATION); System.setProperty("javax.net.ssl.trustStorePassword",TSPASS);
can be removed if you like and as a substitute it by running LdapAuth.java with:
java -Djavax.net.ssl.trustStore=PATH_TO_CERTIFICATE/.truststore -Djavax.net.ssl.trustStorePassword=PASSWD_FROM_KEYTOOL_COMMAND LdapAuthAnd I guess thats about it, all your authentication problems solved(we hope!). In the big scheme of things Java doesn't handle Authenticating against Ldap too well, but in retrospect it was much easier than I was expecting.
If you see any errors in the code or have any suggestions/questions leave a comment and let me know.
Stay Good,
Mike
Comments
You are a hero. Well, my hero anyway. Seriously – that must’ve taken a load of effort.
geeze brophy, thanks
It did suck alot doing it, the main problem was trying to figure out what qualified as authenticated, basically Java doesn’t do a bind until you do something that requires authentication, so it was a pain trying to figure out what attributes I needed to try to get to get Java to actually authenticate. I would say its pretty similar for all Ldap servers, but there could be some that don’t require authentication to get the attributes that I got in my code, soooooo, if it doesn’t work on someone elses server that is why. I also have a jetty servlet wrote that does the authentication using post vars from a webpage.
Sadly, the code link
http://mikegrouchy.com/dev/ldapauth/LdapAuth.java
is unresolved.
Perhaps you’d like to help us (again) and fix the link?
Can you please update the code link?
Thanks,
Sree
I will do my best to dig up the code, I switched servers and I think I have a backup somewhere. Tonight or tomorrow I will look into it.
[...] Backup, or Things to not do like me. So I have been looking around for some old code I have written to criticize(or post on github) and it led me to go looking around this blog for code I had written since I started writing this. The first thing I realized is that I am terrible at backup, I actually have non of the code that I had originally linked, prime example: LDAP authentication using TLS in Java [...]