1

We are using LDAP(Active Directory) to authenticate users. The ldap server is a secured one so we have generated the certificate and added to our keystore. To generate and import the cert we followed:

1.  Retrieve the public CA certificate from the server
echo | openssl s_client -connect <host>:<port> 2>&1 | sed -ne '/-BEGIN CERTIFICATE-/,/-END CERTIFICATE-/p' > ca-cert.cer

2.  Import the certificate into the keystore.
sudo keytool -keystore <path-tojre>/jre/lib/security/cacerts -import -alias <name> -file ca-cert.crt

We tried to authenticate user with below Java prog, it fails with SSL Handshake exception. If we try to authenticate our LDAP serviceAccount/master user, it works fine. Below is the code we are using.

import java.util.Hashtable;

import javax.naming.AuthenticationException;
import javax.naming.Context;
import javax.naming.NamingException;
import javax.naming.directory.DirContext;
import javax.naming.directory.InitialDirContext;

public class LdapAuthenticationTest {

private final static String mstrUsersearchBase = ",OU=ServiceAccounts,DC=org,DC=com";
private final static String userSearchBase = ",ou=Staff,DC=org,DC=com";
private static final String MASTER_USER = "MASTER_ID"+mstrUsersearchBase;
private static final String MASTER_PASSWORD = "MASTER_PASSWORD";
private final static String ldapUrl = "ldaps://server:636";

static String appUser = "userId";
static String appUserpassword = "password";

public static void main(String[] args) {
    String keystorePath = "/usr/lib/jvm/java-1.8.0-openjdk-1.8/jre/lib/security/cacerts";
    System.setProperty("javax.net.ssl.trustStore", keystorePath);
    // Password of your java keystore. Default value is : changeit
    System.setProperty("javax.net.ssl.trustStorePassword", "changeit");

    DirContext ctx = null;
    try {
//          1. Authenticate using master user.
        ctx = authenticate();
        System.out.println("-------->>>  FOUND MASTER ACCOUNT!    <<<--------- ");


//          2. Authenticate using app user.
        ctx = authenticate(appUser, appUserpassword);
        System.out.println("-------->>>  FOUND USER ACCOUNT!    <<<--------");
        ctx.close();
    } catch (AuthenticationException ae) {
        System.out.println(" Authentication failed - exception: " + ae);
    } catch (Exception ie) {
        System.err.println("Unable to get LDAP connection ----->>>>> " + ie);
    }
}

private static DirContext authenticate() throws NamingException {
    return authenticate(null, null);
}

private static DirContext authenticate(String username, String password) throws NamingException {
    String userType = username != null ? "App user" : "Master user";
    System.out.println("INSIDE Authenticate method:  authenticating-> "+ userType);

    String user = username != null ? username+userSearchBase : MASTER_USER;
    String initialContextFactory = "com.sun.jndi.ldap.LdapCtxFactory"; 
    String securityAuthentication = "simple";

    Hashtable<String, String> env = new Hashtable<>();
    env.put(Context.INITIAL_CONTEXT_FACTORY, initialContextFactory);
    env.put(Context.SECURITY_AUTHENTICATION, securityAuthentication);
    env.put(Context.PROVIDER_URL, ldapUrl);
    String principal = "CN=" + user;
    System.out.println("principal-> "+principal);
    env.put(Context.SECURITY_PRINCIPAL, principal);
    env.put(Context.SECURITY_CREDENTIALS, password != null ? password : MASTER_PASSWORD);
    // Specify SSL
    env.put(Context.SECURITY_PROTOCOL, "ssl");
    DirContext ctx = new InitialDirContext(env);

    return ctx;
}

}

I get the log in console as:

-------->>>  FOUND MASTER ACCOUNT!    <<<---------

followed by below Exception:

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

The Java application and LDAP server are both in different machines (Linux Environment)

pranav
  • 421
  • 1
  • 11
  • 27
  • Check if your Java app has access to root CA that issued the LDAPS cert. – Vesper May 24 '17 at 12:34
  • You mean writing a program using TrustManager and reading all certs? I will see a sample code as am not aware how to use that. Meanwhile i ran the application with Debug=ALL option. I see invalidated written for a certificate with a reason like (unknown certificate) followed by a closeSocket() call. After this SSLHandshake exception is there. I doubt like its reading the keystore and on finding one of the certificate invalid its closing the socket. – pranav May 24 '17 at 13:02
  • No, I mean checking whether the root CA cert from the CA that issued LDAPS cert (or the cert itself if it's self-signed) is present in Java's certificate storage that's in turn present to the app that's verifying the cert. If not, make it be present. This stuff should be accessible via Java control panel on the PC that's running your app. – Vesper May 24 '17 at 14:17
  • Got it working now. Updated above. – pranav May 24 '17 at 15:42
  • Better post the update as solution, this way the question would be listed as "answered" and might not get filtered out by someone who's searching for the same issue for having zero answers. – Vesper May 25 '17 at 09:36
  • Just saw i can answer my own question. Done below. Thanks!! – pranav May 25 '17 at 13:24

1 Answers1

1

[Solved]

Was able to solve the issue. Actually just before the SSLHandshake error and closeSocket() call i had this:

%% Invalidated:  [Session-2, TLS_ECDHE_RSA_WITH_AES_256_CBC_SHA384]
main, SEND TLSv1.2 ALERT:  fatal, description = certificate_unknown

Came to know that TLS_ECDHE_RSA_WITH_AES_256_CBC_SHA384 is a Cipher which is expected by the server. Java-8 has limited Ciphers due to some countries restrictions. Details here

Oracle seperately gives UnlimitedPolicy jars for extra Cipherswhich can be downloaded from PolicyJars

I had to replace the jars in jre/lib/security folder and had to reinstall the certificate again. All worked fine after that.

Lonzak
  • 9,334
  • 5
  • 57
  • 88
pranav
  • 421
  • 1
  • 11
  • 27