我的WebApp使用双向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服务器正在运行并且我使用新的受信任证书更新密钥库,甚至从中删除可信证书时,连接器不会注意到更改。
到目前为止我尝试过:
1)停止,重新初始化(反射)和启动连接器 - 不起作用。
2)实现我自己的SSLContext,从密钥库重新加载证书。 好吧,这里我错过了用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,所以答案还不够。
感谢。
答案 0 :(得分:0)
http://my.oschina.net/u/157514/blog/395238
供参考。您可以实现自己的trustManagerClassName,然后在每个ssl-session上加载KeyStore
答案 1 :(得分:0)
如果您的连接器将 bindOnInit 属性设置为 false (存在于Tomcat 6.x中),则执行以下操作:
控制连接器使用的套接字何时绑定。默认情况下 当连接器启动时绑定并在绑定时解除绑定 连接器被破坏。如果设置为false,则套接字将被绑定 连接器在停止时启动和解除绑定。
来自 org.apache.tomcat.util.net.AbstractEndpoint Tomcat 8.0.29的代码段:
public final void start() throws Exception {
if (bindState == BindState.UNBOUND) {
bind();
bindState = BindState.BOUND_ON_START;
}
startInternal();
}
public final void stop() throws Exception {
stopInternal();
if (bindState == BindState.BOUND_ON_START) {
unbind();
bindState = BindState.UNBOUND;
}
}
然后你可以停下来&amp;更新密钥和信任存储后,通过JMX启动连接器。
答案 2 :(得分:0)
现在从Tomcat v8.5.24开始有一个解决方案。
他们介绍了两种名为: reloadSslHostConfig(String hostName)-重新加载特定的主机 reloadSslHostConfigs()-重新加载所有
可以通过多种方式调用它们:
方法1和方法2的详细信息可轻松在线获得。
有关使用方法3的详细信息:
在下面找到示例代码:
主协议类:
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中的连接器应将此作为协议提及:
<Connector protocol="com.myown.connector.ReloadProtocol"
..........
希望这会有所帮助。
答案 3 :(得分:0)
Tomcat HTTP / 1.1协议处理程序可以重新加载密钥库。
如果您正在使用嵌入式Tomcat或可以通过某种方式访问Tomcat连接器,则您可以要求协议处理程序按需重新加载密钥库和信任库,而无需重新启动连接器。
void addConnector(TomcatEmbedded tomcatEmbedded) {
// Create a connector using the HTTP/1.1 protocol handler
Connector connector = new Connector("HTTP/1.1");
connector.setPort(8080);
tomcatEmbedded.addConnector(connector);
}
void reload(Connector connector) {
ProtocolHandler protocolHandler = connector.getProtocolHandler();
if (protocolHandler instanceof Http11NioProtocol) {
Http11NioProtocol http11NioProtocol = (Http11NioProtocol)protocolHandler;
// reload the key and trust stores
http11NioProtocol.reloadSslHostConfigs();
}
}
答案 4 :(得分:-3)
你做不到。你为什么想要?添加信任材料是一种脱机操作。如果你在网上做,你必然会危及安全。