如何强制tomcat重新加载可信证书?

时间:2011-04-28 09:09:21

标签: java security tomcat ssl keystore

我的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,所以答案还不够。

感谢。

5 个答案:

答案 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. 使用jmx
  2. 使用经理服务
  3. 通过制定自定义协议-我在研究期间发现了这种方式

方法1和方法2的详细信息可轻松在线获得。

有关使用方法3的详细信息:

  1. 创建一个类,扩展您选择的协议,例如。 Http11NioProtocol
  2. 覆盖必需的方法,仅在其中调用super即可保持默认行为
  3. 在此类中创建一个线程以不时调用reloadSslHostConfigs方法
  4. 将此类包装在一个jar中,然后将该jar放入tomcat的lib文件夹中
  5. 在server.xml中的连接器中编辑协议以使用此自定义协议

在下面找到示例代码:

主协议类:

    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)

你做不到。你为什么想要?添加信任材料是一种脱机操作。如果你在网上做,你必然会危及安全。