0

I have an application java on tomcat with ldap and I can authenticate without problem. Now, my company would to insert ssl layer on ldap, so I need to use ldaps. Any suggestion to ignore certificate and trust certificate from ldaps server?

This is my code that works for ldap

final String ldapAdServer = "ldap://my_ldap_url:3268";
final String ldapSearchBase = "Ldap_search_base";

//need a default user to be able to do query on AD
final String ldapUsername = "username_path_AD";
final String ldapPassword = "password_path_AD";


Hashtable<String, Object> env = new Hashtable<String, Object>();
env.put(Context.SECURITY_AUTHENTICATION, "simple");
if(ldapUsername != null) {
    env.put(Context.SECURITY_PRINCIPAL, ldapUsername);
}
if(ldapPassword != null) {
    env.put(Context.SECURITY_CREDENTIALS, ldapPassword);
}
env.put(Context.INITIAL_CONTEXT_FACTORY, "com.sun.jndi.ldap.LdapCtxFactory");
env.put(Context.PROVIDER_URL, ldapAdServer);

//ensures that objectSID attribute values
//will be returned as a byte[] instead of a String
env.put("java.naming.ldap.attributes.binary", "objectSID");

LdapContext ctx = new InitialLdapContext(env,null);

return ctx;

now, I tried to create this class to trust all certificates :

import java.security.KeyManagementException;
import java.security.NoSuchAlgorithmException;
import java.security.cert.CertificateException;
import java.security.cert.X509Certificate;
import javax.net.ssl.HostnameVerifier;
import javax.net.ssl.HttpsURLConnection;
import javax.net.ssl.SSLContext;
import javax.net.ssl.SSLSession;
import javax.net.ssl.TrustManager;
import javax.net.ssl.X509TrustManager;


public class SSLFix {
 
 public static void execute(){
  TrustManager[] trustAllCerts = new TrustManager[] {
        new X509TrustManager() {
          public java.security.cert.X509Certificate[] getAcceptedIssuers() {
           return null;
          }
          @Override
          public void checkClientTrusted(X509Certificate[] arg0, String arg1)
           throws CertificateException {}
 
          @Override
          public void checkServerTrusted(X509Certificate[] arg0, String arg1)
            throws CertificateException {}

          }
     };

  SSLContext sc=null;
  try {
   sc = SSLContext.getInstance("SSL");
  } catch (NoSuchAlgorithmException e) {
   e.printStackTrace();
  }
  try {
   sc.init(null, trustAllCerts, new java.security.SecureRandom());
  } catch (KeyManagementException e) {
   e.printStackTrace();
  }
  HttpsURLConnection.setDefaultSSLSocketFactory(sc.getSocketFactory());

  // Create all-trusting host name verifier
  HostnameVerifier validHosts = new HostnameVerifier() {
  @Override
  public boolean verify(String arg0, SSLSession arg1) {
   return true;
  }
  };
  // All hosts will be valid
  HttpsURLConnection.setDefaultHostnameVerifier(validHosts);
 }

}

and so I decided to change my previous ldap code with this:

public LdapContext getLDAPContext() throws NamingException
{
    SSLFix.execute();
    
    
    final String ldapAdServer = "ldaps://my_ldap_url:3269";
    final String ldapSearchBase = "ldap_search_base";
    
//need a default user to be able to do query on AD
    final String ldapUsername = "username_path_AD";
    final String ldapPassword = "password_path_AD";
    
    
    Hashtable<String, Object> env = new Hashtable<String, Object>();
    env.put(Context.SECURITY_AUTHENTICATION, "simple");
    if(ldapUsername != null) {
        env.put(Context.SECURITY_PRINCIPAL, ldapUsername);
    }
    if(ldapPassword != null) {
        env.put(Context.SECURITY_CREDENTIALS, ldapPassword);
    }
    env.put(Context.INITIAL_CONTEXT_FACTORY, "com.sun.jndi.ldap.LdapCtxFactory");
    env.put(Context.PROVIDER_URL, ldapAdServer);

    //ensures that objectSID attribute values
    //will be returned as a byte[] instead of a String
    env.put("java.naming.ldap.attributes.binary", "objectSID");
    
    LdapContext ctx = new InitialLdapContext(env,null);
    
    return ctx;
}

but when I execute the control for ldaps, I obtain this error:

javax.naming.CommunicationException: simple bind failed: [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]

Nimantha
  • 6,405
  • 6
  • 28
  • 69
  • 1
    If your company wants SSL presumably they want it to be secure, and what you're asking for would destroy that. If the LDAP server has a CA-signed certificate you don't have a problem to solve, and if you do have a problem to solve the CA-signed certificate is the solution. – user207421 Sep 11 '20 at 09:37
  • It is a duplicated question. Please see: https://stackoverflow.com/questions/60571012/sslsocketfactory-in-java-ldap-network-connection – Diego Feb 01 '22 at 18:58
  • This cuase another javax.net.ssl.SSLHandshakeException: Received fatal alert: handshake_failure at sun.security.ssl.Alerts.getSSLException(Alerts.java:192) can any one solve it ? – MrSalesi Apr 15 '23 at 09:47

4 Answers4

4

You must import the "LDAP-CA certificate" into your Java virtual machine.
To do this, you can run:
keytool -import -trustcacerts -keystore $JAVA_HOME/jre/lib/security/cacerts -storepass changeit -alias ldap-CA -import -file ldap-ca-crt.pem

If your certificate is good. All your clients (web browsers or mobile SO) will have no problem using your application.

Don't forget to import your intermediate certificates or chained certificates.(these certificates usually come together with LDAP-CA certificate)

  • 1
    Well you only need to import the topmost certificate in the chain, not the whole chain. – user207421 Sep 13 '20 at 07:44
  • 1
    Funny thing that this is the most accepted answer when the poster wanted to "ignore certificates in java?" which this does not do. – jwilleke Aug 05 '22 at 09:21
0

You can create a custom X509TrustManager or SSLSocketFactory.

Found examples of both at https://stackoverflow.com/a/4615497/88122

jwilleke
  • 10,467
  • 1
  • 30
  • 51
0

I don't know your environment, but can you add the CA certificate that has released the LDAP certificate to your system's trusted CAs?

In this way, you enhance the app security, otherwise is almost useless to use LDAPs.

I suppose that the Domain Controller has a CA server installed and the LDAP's certificate is released by it. Download this certificate and add it to you environment.

If the app is installed on domain's computers, you can share the CA certificate throw a group policy rule. You can see the Microsoft documentation. Each certificate in a domain must be released by a trusted CA.

If you can't accept this certificate use the option 2 from this answer.

Daniele Licitra
  • 1,520
  • 21
  • 45
0

thanks all for your response. I decided to create X509TrustManager and SSLSocketFactory, and so allow all certificates. I solved my issue in this way