Как заставить tomcat перезагрузить доверенные сертификаты? - PullRequest
3 голосов
/ 28 апреля 2011

My 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, который перезагружает сертификаты из хранилища ключей. Ну, здесь я пропускаю часть регистрации этого SSLContext с tomcat (так что tomcat будет использовать его в соединителе для новых входящих соединений)

Есть много сообщений по этому вопросу, но нет реального решения:

http://www.delphifaq.com/faq/f5003.shtml

http://jcalcote.wordpress.com/tag/truststore
(В этой статье описывается только как воссоздать SSLcontext со стороны клиента (без серверной стороны))

Есть идеи?

Есть еще один связанный вопрос:

Как заставить веб-приложение tomcat перезагрузить хранилище доверия после его обновления

но ответа там недостаточно, поскольку я не хочу создавать новый ClassLoader.

Спасибо.

Ответы [ 4 ]

0 голосов
/ 27 июля 2018

Теперь есть решение этой проблемы, начиная с Tomcat v8.5.24.

Они представили 2 метода с именем: reloadSslHostConfig (String hostName) - перезагрузить определенный хост reloadSslHostConfigs () - перезагрузить все

Их можно вызывать по-разному:

  1. Использование jmx
  2. Использование службы менеджера
  3. Создавая собственный протокол - я нашел этот путь во время исследования

Подробная информация о способе 1 и способе 2 легко доступна онлайн.

Подробная информация о том, как использовать способ 3:

  1. Создайте класс, расширяющий выбранный вами протокол, например. Http11NioProtocol
  2. Переопределите необходимые методы и просто вызовите в них super, чтобы сохранить поведение по умолчанию
  3. Создать поток в этом классе, чтобы время от времени вызывать метод reloadSslHostConfigs
  4. Упакуйте этот класс в банку и поместите эту банку в папку lib tomcat
  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"
 ..........

Надеюсь, это поможет.

0 голосов
/ 02 апреля 2015

http://my.oschina.net/u/157514/blog/395238

для справки. Вы можете самостоятельно реализовать trustManagerClassName, а затем загружать KeyStore при каждом ssl-сеансе

0 голосов
/ 01 декабря 2015

Если для вашего соединителя свойство 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;
    }
}

Затем вы можете остановить и запустить соединитель через JMX после обновления ваших ключей и доверенных хранилищ.

0 голосов
/ 28 апреля 2011

Вы не можете. Почему ты хочешь? Добавление материалов доверия является автономной операцией. Если вы делаете это онлайн, вы обязательно ставите под угрозу безопасность.

...