2017-05-24 104 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中的文件夾,不得不重新安裝證書下載。之後所有工作都很好。