以编程方式更新tomcat 8中的证书而无需重新启动服务器

时间:2017-04-23 13:08:48

标签: java tomcat ssl certificate mbeans

为了更新我用于服务器的SSL证书,我有一个代码可以执行我需要的import \ export和验证。

效果很好,但为了让更改生效,我必须重新启动tomcat 我希望避免重启,并在不使用外部工具(例如keytool)的情况下更新它 我查找了一些类似的问题,并找到了解决方案 - 重新启动443连接器。我能够这样做,连接器正在停止并启动,但证书没有更新。只有服务器重启才会实际更新它

我是否缺少一些连接器初始化程序? 一些系统缓存或我应该清除的对象?

这是我用来重新启动连接器的代码:

MBeanServer mbeanServer = null;
ObjectName objectName = null;
final ObjectName objectNameQuery = new ObjectName("*:type=Connector,port=443,*");
for (final MBeanServer server : (ArrayList<MBeanServer>) MBeanServerFactory.findMBeanServer(null)) {
    if (server.queryNames(objectNameQuery, null).size() > 0) {
        mbeanServer = server;
        objectName = (ObjectName) server.queryNames(objectNameQuery,null).toArray()[0];
        break;
    }
}

mbeanServer.invoke(objectName, "stop", null, null);
Thread.sleep(1000);
mbeanServer.invoke(objectName, "start", null, null);  

我在tomcat日志中看到连接器重启的以下痕迹:
    23-Apr-2017 15:42:00.292 INFO [BG-Task RestartTomcatConnector] org.apache.coyote.AbstractProtocol.stop Stopping ProtocolHandler ["http-nio-443"]
    23-Apr-2017 15:42:01.349 INFO [BG-Task RestartTomcatConnector] org.apache.coyote.AbstractProtocol.start Starting ProtocolHandler ["http-nio-443"]

1 个答案:

答案 0 :(得分:0)

问题解决了,这些是组件:

  1. server.xml必须包含bindOnInit =“false”。这是我使用的配置

    <Connector protocol="org.apache.coyote.http11.Http11NioProtocol" port="443" SSLEnabled="true" maxThreads="150" acceptCount="2000" scheme="https" secure="true" ciphers="TLS_ECDHE_RSA_WITH_AES_128_CBC_SHA256, TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA256, TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384, TLS_DHE_RSA_WITH_AES_128_GCM_SHA256, TLS_ECDHE_RSA_WITH_AES_256_CBC_SHA384, TLS_DHE_RSA_WITH_AES_128_CBC_SHA256, TLS_DHE_RSA_WITH_AES_256_CBC_SHA256, TLS_DHE_RSA_WITH_AES_256_CBC_SHA" keystoreFile="webapps/ServerKeyStore" keystorePass="***" clientAuth="false" sslProtocol="TLS" sslEnabledProtocols="TLSv1.1,TLSv1.2" compression="on" compressableMimeType="text/html,text/xml,application/xml,application/json,application/javascript,text/css,text/plain" server="Portal" useSendfile="false" compressionMinSize="1024" bindOnInit="false"/>

  2. 连接器重启的Java代码:

  3. public class TomcatConnectorRestarter implements Callable {

        private final int waitSeconds = 3;
        private final static ReentrantLock rl = new ReentrantLock();
    
        @Override
        public Boolean call() throws Exception {
            restartConnector();
            return true;
        }
    
        protected void restartConnector() throws Exception {
            try {
                if (tryLock()){
                    mLogger.info("Acquired lock");
                    try {
                        HTTPSConnectorMBean httpsConnector = null;
                        MBeanServer mbeanServer = null;
                        ObjectName objectName = null;
                        final ObjectName objectNameQuery = new ObjectName("*:type=Connector,port=443,*");
    
                        for (final MBeanServer server : (ArrayList<MBeanServer>) MBeanServerFactory.findMBeanServer(null)) {
                            if (server.queryNames(objectNameQuery, null).size() > 0) {
                                mbeanServer = server;
                                objectName = (ObjectName) server.queryNames(objectNameQuery, null).toArray()[0];
                                httpsConnector = new HTTPSConnectorMBean(objectName, mbeanServer);
                                break;
                            }
                        }
    
                        if (Objects.nonNull(httpsConnector)) {
                            mLogger.info("Stopping connector");
                            httpsConnector.stop();
                            mLogger.info("Waiting "+waitSeconds+" seconds after "+"stop"+" ...");
                            Thread.sleep(waitSeconds*1000);
                            mLogger.info("Starting connector");
                            httpsConnector.start();
                        }
                        else {
                            mLogger.error("Could not find connector object");
                        }
                    }
                    catch (Exception e) {
                        mLogger.error("Failed restarting connector",e);
                    }
                }
                else {
                    mLogger.warn("Operation is in process");
                }
            }
            finally {
                unlock();
            }
        }
    
        private void unlock() {
            if (rl.isHeldByCurrentThread()) {
                mLogger.debug("Releasing lock");
                rl.unlock();
            }
        }
    
        private boolean tryLock() {
            return !rl.isHeldByCurrentThread() && rl.tryLock();
        }
    
        private enum MBeanConnectorAction {
            start,stop,getState;
        }
    
        private abstract class MBeansObjectAction {
            private final ObjectName on;
            private final MBeanServer server;
    
            public MBeansObjectAction(ObjectName on, MBeanServer server) {
                this.on = on;
                this.server = server;
            }
    
            protected Object invoke(MBeanConnectorAction cmd) throws InstanceNotFoundException, ReflectionException, MBeanException {
                return server.invoke(on, cmd.toString(), null, null);
            }
        }
    
        private class HTTPSConnectorMBean extends MBeansObjectAction {
    
            public HTTPSConnectorMBean(ObjectName on, MBeanServer server) {
                super(on, server);
            }
    
            public void start() throws InstanceNotFoundException, ReflectionException, MBeanException {
                invoke(MBeanConnectorAction.start);
            }
            public void stop() throws InstanceNotFoundException, ReflectionException, MBeanException {
                invoke(MBeanConnectorAction.stop);
            }
            public Object status() throws InstanceNotFoundException, ReflectionException, MBeanException {
                return invoke(MBeanConnectorAction.getState);
            }
        }
    }