Reputation: 431
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)
Upvotes: 1
Views: 6574
Reputation: 431
[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.
Upvotes: 1