我的 WebApp 使用 2-Way SSL 连接器(又名“客户端身份验证”):
<Connector port="8084" SSLEnabled="true" maxThreads="10" minSpareThreads="3" maxSpareThreads="5"
enableLookups="false" disableUploadTimeout="true" acceptCount="100" scheme="https" secure="true"
clientAuth="true" truststoreFile="conf/keystore.kst" truststoreType="JCEKS" sslProtocol="TLS" URIEncoding="UTF-8"
keystoreFile="conf/keystore.kst" keystoreType="JCEKS" keyAlias="myAlias"
ciphers="TLS_RSA_WITH_AES_128_CBC_SHA,TLS_RSA_WITH_3DES_EDE_CBC_SHA,SSL_RSA_WITH_3DES_EDE_CBC_SHA"/>
我的问题是,当 Tomcat 服务器正在运行并且我用新的可信证书更新 keystore ,甚至从中删除可信证书时,连接器没有注意到这些变化。
到目前为止我尝试了什么:
1) 停止、重新初始化(反射)和启动连接器 - 无效。
2) 实现我自己的 SSLContext,从 keystore 重新加载证书。 好吧,这里我遗漏了向 tomcat 注册此 SSLContext 的部分(以便 tomcat 将在连接器中使用它来进行新的传入连接)
关于这个问题有很多帖子,但没有真正的解决方案:
http://www.delphifaq.com/faq/f5003.shtml
http://jcalcote.wordpress.com/tag/truststore
(本文仅介绍如何从客户端(缺少服务器端)重新创建 SSLcontext)
有什么想法吗?
还有一个相关的问题:
How do I force a tomcat web application reload the trust store after I update it
但那里的答案还不够,因为我不想构建一个新的 ClassLoader。
谢谢。
最佳答案
现在有一个从 Tomcat v8.5.24 开始的解决方案。
他们引入了 2 个方法,命名为: reloadSslHostConfig(String hostName) - 重新加载特定主机 reloadSslHostConfigs() - 重新加载所有
可以通过多种方式调用它们:
- 使用jmx
- 使用经理服务
- 通过制定自定义协议(protocol) - 我在研究过程中发现了这种方式
方式 1 和方式 2 的详细信息很容易在线获得。
关于如何使用方式 3 的详细信息:
- 创建一个类来扩展您选择的协议(protocol),例如。 Http11Nio协议(protocol)
- 覆盖所需的方法并在其中调用 super 以保持默认行为
- 在该类中创建一个线程,定时调用reloadSslHostConfigs方法
- 把这个类打包成一个jar,然后把那个jar放到tomcat的lib文件夹中
- 在 server.xml 的连接器中编辑协议(protocol)以使用此自定义协议(protocol)
在下面找到示例代码:
主要协议(protocol)类:
package com.myown.connector;
import java.io.File;
import java.io.InputStream;
import java.lang.reflect.Field;
import java.net.URL;
import java.net.URLConnection;
import java.nio.file.StandardCopyOption;
import java.util.ArrayList;
import java.util.List;
import java.util.concurrent.ConcurrentMap;
import javax.management.MalformedObjectNameException;
import javax.management.ObjectName;
import javax.net.ssl.SSLSessionContext;
import org.apache.coyote.http11.Http11NioProtocol;
import org.apache.juli.logging.Log;
import org.apache.juli.logging.LogFactory;
import org.apache.tomcat.util.modeler.Registry;
import org.apache.tomcat.util.net.AbstractEndpoint;
import org.apache.tomcat.util.net.AbstractJsseEndpoint;
import org.apache.tomcat.util.net.GetSslConfig;
import org.apache.tomcat.util.net.SSLContext;
import org.apache.tomcat.util.net.SSLHostConfig;
import org.apache.tomcat.util.net.SSLHostConfigCertificate;
import org.apache.tomcat.util.net.SSLImplementation;
import org.apache.tomcat.util.net.SSLUtil;
public class ReloadProtocol extends Http11NioProtocol {
private static final Log log = LogFactory.getLog(Http12ProtocolSSL.class);
public ReloadProtocol() {
super();
RefreshSslConfigThread refresher = new
RefreshSslConfigThread(this.getEndpoint(), this);
refresher.start();
}
@Override
public void setKeystorePass(String s) {
super.setKeystorePass(s);
}
@Override
public void setKeyPass(String s) {
super.setKeyPass(s);
}
@Override
public void setTruststorePass(String p) {
super.setTruststorePass(p);
}
class RefreshSslConfigThread extends Thread {
AbstractJsseEndpoint<?> abstractJsseEndpoint = null;
Http11NioProtocol protocol = null;
public RefreshSslConfigThread(AbstractJsseEndpoint<?> abstractJsseEndpoint, Http11NioProtocol protocol) {
this.abstractJsseEndpoint = abstractJsseEndpoint;
this.protocol = protocol;
}
public void run() {
int timeBetweenRefreshesInt = 1000000; // time in milli-seconds
while (true) {
try {
abstractJsseEndpoint.reloadSslHostConfigs();
System.out.println("Config Updated");
} catch (Exception e) {
System.out.println("Problem while reloading.");
}
try {
Thread.sleep(timeBetweenRefreshesInt);
} catch (InterruptedException e) {
System.out.println("Error while sleeping");
}
}
}
}
}
server.xml 中的连接器应该将此作为协议(protocol)提及:
<Connector protocol="com.myown.connector.ReloadProtocol"
..........
希望这对您有所帮助。
关于java - 如何强制 tomcat 重新加载受信任的证书?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/5816239/