I need to connect to an LDAP directory over SSL.
In non-production environments, we use self-signed certificates which, of course, fails to validate with:
javax.naming.CommunicationException: simple bind failed: ldapserver:636 [Root exception is 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]
at com.sun.jndi.ldap.LdapClient.authenticate(LdapClient.java:197)
at com.sun.jndi.ldap.LdapCtx.connect(LdapCtx.java:2694)
at com.sun.jndi.ldap.LdapCtx.<init>(LdapCtx.java:293)
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:288)
at javax.naming.InitialContext.init(InitialContext.java:223)
at javax.naming.ldap.InitialLdapContext.<init>(InitialLdapContext.java:134)
I am aware of how to use a custom trust manager for SSL-enabled connections, but don't know how to use one in connection with the JNDI API where I don't manage the actual connection. That is, where is the following standard setup will I be able to plug the trust manager?
Thanks in advance.
Hashtable env = new Hashtable();
env.put(Context.INITIAL_CONTEXT_FACTORY, "com.sun.jndi.ldap.LdapCtxFactory");
env.put(Context.PROVIDER_URL, "ldaps://ldapserver:636");
env.put(Context.SECURITY_PROTOCOL, "ssl");
env.put(Context.SECURITY_AUTHENTICATION, "simple");
env.put(Context.SECURITY_PRINCIPAL, "myUser");
env.put(Context.SECURITY_CREDENTIALS, "myPassword");
LdapContext ctx = new InitialLdapContext(env, null);
ctx.search (...)
You could accept any certificate when you override the Trustmanager:
DummyTrustmanager.java
MySSLSocketFactory.java
Main.java
Its been about 5 years since I last did this so my answer will be a bit vague I'm afraid; but I think if you impliment a trusted provider in the java.security which you should be able to find under /usr/java/jre/lib/security/; it will then accept the certificate as trusted.
I dont have access to my notes at the moment, but I'll have a dig through them later
Setting aside JNDI entirely, some frameworks will refer to the LOCAL SYSTEM LDAP configuration (this is typically /etc/ldap.conf or something like that). When I say LOCAL, I mean the system(s) on which your JNDI operation is running.
At least in the case of most LDAP-enabled Linux OSs, inside of such an LDAP config file is (usually) a line that reads:
This is the default TLS/SSL criticality setting (and the most strict), as it will fail the connection if ANYTHING WHATSOEVER is wrong with the certificate (this includes being self-signed).
You can experiment with different settings instead of 'demand' (play with 'allow' or 'never'). Once this is done, try your operation again and see if your issue subsides. Again, not all things like this will read or even detect your local system settings. Some do, some don't. Worth a look.
I hope this helps...
Max
@Jcs answer is correct, but if you don't want to use a custom TrustManager, and if you're willing for that particular self-signed certificate to be a trusted CA for other uses within the VM, you can either:
cacerts
under the JRE security directory) orcacerts
) which would contain that particular certificate, and use this as your default truststore, but setting thejavax.net.ssl.trustStore*
system properties.According to the JNDI documentation it seems possible to set a custom
SSLSocketFactory
http://download.oracle.com/javase/1.5.0/docs/guide/jndi/jndi-ldap-gl.html#socket
Configure the environment to use this socket factory
No code required. Just add the certificate to the test client truststores.
Don't write extra code for this. It is insecure, and you run a major risk of the code leaking into production. You really don't want that.