Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

how to accept self-signed certificates for JNDI/LDAP connections?

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 (...)
like image 393
wishihadabettername Avatar asked Jan 06 '11 13:01

wishihadabettername


People also ask

Can you use a self-signed certificate for LDAPS?

Can I use a self-signed certificate for LDAPS with the Duo Authentication Proxy? Yes. Please note that if you use a self-signed certificate to secure LDAPS communications to your directory server, the certificate's key usage should include "Certificate Signing."

Does JNDI use LDAP?

So where does JNDI fit into this LDAP jargon? JNDI does for LDAP what JDBC does for Oracle -- it provides a standard API for interacting with naming and directory services using a service provider interface (SPI), which is analogous to an JDBC driver. LDAP is a standard way to provide access to directory information.

How does JNDI LDAP work?

Both the JNDI and LDAP models define a hierarchical namespace in which you name objects. Each object in the namespace may have attributes that can be used to search for the object. At this high level, the two models are similar, so it is not surprising that the JNDI maps well to the LDAP.


1 Answers

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

public class MySSLSocketFactory extends SocketFactory {
    private static final AtomicReference<MySSLSocketFactory> defaultFactory = new AtomicReference<>();

    private SSLSocketFactory sf;

    public MySSLSocketFactory() {
        KeyStore keyStore = ... /* Get a keystore containing the self-signed certificate) */
        TrustManagerFactory tmf = TrustManagerFactory.getInstance();
        tmf.init(keyStore);
        SSLContext ctx = SSLContext.getInstance("TLS");
        ctx.init(null, tmf.getTrustManagers(), null);
        sf = ctx.getSocketFactory();
    }

    public static SocketFactory getDefault() {
        final MySSLSocketFactory value = defaultFactory.get();
        if (value == null) {
            defaultFactory.compareAndSet(null, new MySSLSocketFactory());
            return defaultFactory.get();
        }
        return value;
    }

    @Override
    public Socket createSocket(final String s, final int i) throws IOException {
        return sf.createSocket(s, i);
    }

    @Override
    public Socket createSocket(final String s, final int i, final InetAddress inetAddress, final int i1) throws IOException {
        return sf.createSocket(s, i, inetAddress, i1);
    }

    @Override
    public Socket createSocket(final InetAddress inetAddress, final int i) throws IOException {
        return sf.createSocket(inetAddress, i);
    }

    @Override
    public Socket createSocket(final InetAddress inetAddress, final int i, final InetAddress inetAddress1, final int i1) throws IOException {
        return sf.createSocket(inetAddress, i, inetAddress1, i1);
    }
}

Configure the environment to use this socket factory

env.put("java.naming.ldap.factory.socket", "com.example.MySSLSocketFactory");
like image 157
Jcs Avatar answered Oct 11 '22 15:10

Jcs