2017-05-24 82 views
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环境中)

+0

检查您的Java应用程序是否有权访问颁发LDAPS证书的根CA. – Vesper

+0

你的意思是使用TrustManager编写程序并阅读所有证书?我会看到一个示例代码,因为我不知道如何使用它。同时我用Debug = ALL选项运行应用程序。我发现无效的书面证书的原因类似于(未知证书),然后是closeSocket()调用。在此SSLHandshake异常之后。我怀疑它的阅读密钥库,并找到其中一个证书无效关闭套接字。 – pranav

+0

不,我的意思是检查颁发LDAPS证书的CA根CA证书(或证书本身是否自签名)存在于Java的证书存储中,证书存储又反过来呈现给验证证书的应用程序。如果没有,让它存在。这些东西应该可以通过运行你的应用的PC上的Java控制面板来访问。 – Vesper

回答

1

[已解决]

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 

才知道,TLS_ECDHE_RSA_WITH_AES_256_CBC_SHA384是由服务器预期密码。 Java-8由于某些国家的限制而具有有限的密码。详细 here

甲骨文seperately给出了额外的Cipherswhich UnlimitedPolicy罐可以从PolicyJars

我不得不更换的罐子中的jre/lib/security中的文件夹,不得不重新安装证书下载。之后所有工作都很好。