我正在尝试使用java Web应用程序动态更改信任库路径。
正在开发struts应用程序,登录基于ldap通过安全套接字层(ssl)连接。
要与ssl连接,我使用java keytool选项创建了.cer文件。
现在我能够连接ldap,我可以从ldap中恢复用户信息。
当我动态更改ssl证书(测试的无效证书)时,它无法提供任何异常。但是当我重新启动tomcat时它会起作用 服务器
以下是我正在尝试的代码
try{
java.io.InputStream in = new java.io.FileInputStream("C:\\test.cer");
java.security.cert.Certificate c = java.security.cert.CertificateFactory.getInstance("X.509").generateCertificate(in);
java.security.KeyStore ks = java.security.KeyStore.getInstance("JKS");
ks.load(null);
if (!ks.containsAlias("alias ldap")) {
ks.setCertificateEntry("alias ldap", c);
}
java.io.OutputStream out = new java.io.FileOutputStream("C:\\ldap.jks");
char[] kspass = "changeit".toCharArray();
ks.store(out, kspass);
out.close();
System.setProperty("javax.net.ssl.trustStore", "C:\\ldap.jks");
System.setProperty("javax.net.ssl.trustStorePassword", "changeit");
}catch(Exception e){
e.printStackTrace();
}
我用代码做错了吗? 我需要动态连接的任何新代码吗?
注意: 而不是c:\ ldap.jks文件我动态地给出了无效文件。它没有任何例外。
已编辑(使用自定义TrustManager检查):
我还实现了TrustManager,并使用自定义信任管理器初始化了ssl上下文。 但我无法得到预期的行为
你可以帮助我吗?我试过的代码是import java.io.DataInputStream;
import java.io.File;
import java.io.FileInputStream;
import java.io.IOException;
import java.io.InputStream;
import java.security.KeyStore;
import java.security.NoSuchAlgorithmException;
import java.security.cert.Certificate;
import java.security.cert.CertificateException;
import java.security.cert.X509Certificate;
import java.util.ArrayList;
import java.util.Hashtable;
import java.util.List;
import java.util.UUID;
import javax.naming.Context;
import javax.naming.NamingEnumeration;
import javax.naming.NamingException;
import javax.naming.directory.DirContext;
import javax.naming.directory.InitialDirContext;
import javax.net.ssl.TrustManager;
import javax.net.ssl.TrustManagerFactory;
import javax.net.ssl.X509TrustManager;
public class TestDynamicSSLCert {
public static void main(String[] args)throws NamingException,IOException {
DataInputStream din = new DataInputStream (System.in);
String yes = "yes";
String certpath = "C:\\cert.cer";
String ldappath1 = "C:\\ldap.jks";
String ldappath2 = "C:\\ldap.jks"; // setting valid key store path
while("yes".equalsIgnoreCase(yes.trim())){
System.out.println(" ldappath2 : "+ldappath2);
Hashtable env = new Hashtable();
env.put(Context.SECURITY_AUTHENTICATION, "simple");
env.put(Context.SECURITY_PRINCIPAL,"uid=admin,ou=system");
env.put(Context.SECURITY_CREDENTIALS, "secret");
env.put(Context.INITIAL_CONTEXT_FACTORY,"com.sun.jndi.ldap.LdapCtxFactory");
env.put(Context.PROVIDER_URL, "ldaps://172.16.12.4:636/ou=system");
try {
java.io.InputStream in = new java.io.FileInputStream(certpath);
java.security.cert.Certificate c = java.security.cert.CertificateFactory.getInstance("X.509").generateCertificate(in);
java.security.KeyStore ks = java.security.KeyStore.getInstance("JKS");
ks.load(null);
if (!ks.containsAlias("alias ldap")) {
ks.setCertificateEntry("alias ldap", c);
}
java.io.OutputStream out = new java.io.FileOutputStream(ldappath1);
char[] kspass = "changeit".toCharArray();
ks.store(out, kspass);
out.close();
System.setProperty("javax.net.ssl.trustStore", ldappath2);
System.setProperty("javax.net.ssl.trustStorePassword", "changeit");
// Custorm trust manager
MyX509TrustManager reload = new MyX509TrustManager(ldappath2,c);
TrustManager[] tms = new TrustManager[] { reload };
javax.net.ssl.SSLContext sslCtx = javax.net.ssl.SSLContext.getInstance("SSL");
sslCtx.init(null, tms, null);
// Custom trust manager
} catch (Exception e) {
e.printStackTrace();
}
DirContext ctx = new InitialDirContext(env);
NamingEnumeration enm = ctx.list("");
while (enm.hasMore()) {
System.out.println(enm.next());
}
ctx.close();
System.out.println(" Go again by yes/no :");
yes = din.readLine();
ldappath2 = "C:\\invalidldap.jks"; // setting invalid keystore path
}
}
}
class MyX509TrustManager implements X509TrustManager {
private final String trustStorePath;
private X509TrustManager trustManager;
private List<Certificate> tempCertList = new ArrayList<Certificate>();
public MyX509TrustManager(String tspath,Certificate cert)throws Exception{
this.trustStorePath = tspath;
tempCertList.add(cert);
reloadTrustManager();
}
public MyX509TrustManager(String tspath)
throws Exception {
this.trustStorePath = tspath;
reloadTrustManager();
}
@Override
public void checkClientTrusted(X509Certificate[] chain,
String authType) throws CertificateException {
trustManager.checkClientTrusted(chain, authType);
}
@Override
public void checkServerTrusted(X509Certificate[] chain,
String authType) throws CertificateException {
try {
trustManager.checkServerTrusted(chain, authType);
} catch (CertificateException cx) {
addServerCertAndReload(chain[0], true);
trustManager.checkServerTrusted(chain, authType);
}
}
@Override
public X509Certificate[] getAcceptedIssuers() {
X509Certificate[] issuers = trustManager.getAcceptedIssuers();
return issuers;
}
private void reloadTrustManager() throws Exception {
// load keystore from specified cert store (or default)
KeyStore ts = KeyStore.getInstance(KeyStore.getDefaultType());
InputStream in = new FileInputStream(trustStorePath);
try {
ts.load(in, null);
} finally {
in.close();
}
// add all temporary certs to KeyStore (ts)
for (Certificate cert : tempCertList) {
ts.setCertificateEntry(UUID.randomUUID().toString(), cert);
}
// initialize a new TMF with the ts we just loaded
TrustManagerFactory tmf = TrustManagerFactory.getInstance(TrustManagerFactory.getDefaultAlgorithm());
tmf.init(ts);
// acquire X509 trust manager from factory
TrustManager tms[] = tmf.getTrustManagers();
for (int i = 0; i < tms.length; i++) {
if (tms[i] instanceof X509TrustManager) {
trustManager = (X509TrustManager) tms[i];
return;
}
}
throw new NoSuchAlgorithmException("No X509TrustManager in TrustManagerFactory");
}
private void addServerCertAndReload(Certificate cert,
boolean permanent) {
try {
if (permanent) {
// import the cert into file trust store
// Google "java keytool source" or just ...
Runtime.getRuntime().exec("keytool -importcert ...");
} else {
tempCertList.add(cert);
}
reloadTrustManager();
} catch (Exception ex) { /* ... */ }
}
}
预期行为:
ldap连接应该成功使用有效的密钥库文件(在第一次循环期间)。 如果用户给出是,则分配无效密钥库,并且需要产生异常,不应连接到ldap
实际行为:
对于有效的密钥库文件,我能够从ldap中检索信息。
注意:
如果我设置字符串ldappath2 =&#34; C:\ invalidldap.jks&#34 ;;在开始时,它给出例外。
为什么要这样做?
@EJP,因为,我需要安全地开发基于ldap身份验证的模块。模块应该支持多个ldap服务器。 ldap设置可以从UI(具有ui的网页)中插入,以获取ldaphost,port,basedn和ssl证书等详细信息,这些详细信息应该转到数据库。同时证书也存在于数据库中。 work for module只是从ldap中检索用户并将其存储到另一个表中。因此,如果我们使用新证书方式更改新的ldap服务器设置,则System.setProperty(&#34; javax.net.ssl.trustStore&#34;,&#34; truststorepath&#34;)将失败。你对我的解释没问题吗?
答案 0 :(得分:3)
你是对的。更改密钥库或信任库时,必须重新启动Tomcat。您不需要编写代码来加载客户端证书,您只需要确保您正在处理其证书由您信任的CA签名的服务器。在运行时添加新证书是非常不安全的。
答案 1 :(得分:0)
有没有其他方法可以安全地连接ldap而不使用上面的方法 步骤是什么?
是的,但为什么你认为你需要知道?
是否应该重新启动应用程序(tomcat或单个java文件) 每当trustStore属性更新?
是