1
我们正在使用LDAP(Active Directory)来验证用户。 ldap服务器是一个安全的服务器,所以我们生成了证书并添加到我们的密钥库中。要生成并导入我们就跟着证书:SSLHandshakeException当连接到LDAPS(活动目录)
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
我们试着用下面的Java PROG验证用户时,出现SSL握手异常。如果我们尝试验证我们的LDAP服务帐户/主用户,它工作正常。以下是我们正在使用的代码。
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;
}
}
我得到的日志中控制台:
-------->>> FOUND MASTER ACCOUNT! <<<---------
跟随以下异常:
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]
的Java应用程序和LDAP服务器都在不同的机器上(Linux环境中)
检查您的Java应用程序是否有权访问颁发LDAPS证书的根CA. – Vesper
你的意思是使用TrustManager编写程序并阅读所有证书?我会看到一个示例代码,因为我不知道如何使用它。同时我用Debug = ALL选项运行应用程序。我发现无效的书面证书的原因类似于(未知证书),然后是closeSocket()调用。在此SSLHandshake异常之后。我怀疑它的阅读密钥库,并找到其中一个证书无效关闭套接字。 – pranav
不,我的意思是检查颁发LDAPS证书的CA根CA证书(或证书本身是否自签名)存在于Java的证书存储中,证书存储又反过来呈现给验证证书的应用程序。如果没有,让它存在。这些东西应该可以通过运行你的应用的PC上的Java控制面板来访问。 – Vesper