Tomcat có thể tải lại chứng chỉ SSL mà không cần khởi động lại không?


11

Tôi có một quy trình nền có thể cập nhật kho khóa mà Tomcat sử dụng cho thông tin SSL của nó. Tôi muốn có thể tải Tomcat tự động mà không cần khởi động lại thủ công.

Có thể để Tomcat tải lại cái này mà không cần khởi động lại, hoặc có một cách lập trình mà nó có thể được thực hiện thay thế?

Câu trả lời:


6

Tôi không tin có một cách để làm điều đó tự động mặc dù quá trình nền của bạn có thể tự động khởi động lại tomcat. Kho khóa chỉ được đọc một lần khi jvm được khởi tạo. Có thể có một giải pháp nếu bạn viết trình xử lý của riêng bạn, định kỳ kiểm tra lại kho khóa nhưng cá nhân tôi không tìm thấy bất kỳ ví dụ nào về điều này trên Internet.


8

Bạn có thể khởi động lại trình kết nối Tomcat riêng lẻ, tức là khởi động lại cổng như 8443 sau khi bạn thay đổi tệp jssecacert.

Đây là mã / phương thức hoàn chỉnh mà tôi đang sử dụng để khởi động lại trình kết nối tomcat sau khi tôi thêm / xóa chứng chỉ.

// Stop and restart the SSL connection so that the tomcat server will
// re-read the certificates from the truststore file.
public void refreshTrustStore() throws Exception 
{
    try 
    {
        //following line should be replaced based on where you get your port number. You may pass in as argument to this method
        String httpsPort = configurationManager.getHttpsPort();
        String objectString = "*:type=Connector,port=" + httpsPort + ",*";

        final ObjectName objectNameQuery = new ObjectName(objectString); 

        for (final MBeanServer server: MBeanServerFactory.findMBeanServer(null))
        {
            if (!server.queryNames(objectNameQuery, null).isEmpty())
            {
                MBeanServer mbeanServer = server;
                ObjectName objectName = (ObjectName) server.queryNames(objectNameQuery, null).toArray()[0];

                mbeanServer.invoke(objectName, "stop", null, null);

                // Polling sleep to reduce delay to safe minimum.
                // Use currentTimeMillis() over nanoTime() to avoid issues
                // with migrating threads across sleep() calls.
                long start = System.currentTimeMillis();
                // Maximum of 6 seconds, 3x time required on an idle system.
                long max_duration = 6000L;
                long duration = 0L;
                do
                {
                    try
                    {
                        Thread.sleep(100);
                    }
                    catch (InterruptedException e)
                    {
                        Thread.currentThread().interrupt();
                    }

                    duration = (System.currentTimeMillis() - start);
                } while (duration < max_duration &&
                        server.queryNames(objectNameQuery, null).size() > 0);

                // Use below to get more accurate metrics.
                String message = "TrustStoreManager TrustStore Stop: took " + duration + "milliseconds";
                logger.information(message);

                mbeanServer.invoke(objectName, "start", null, null);

                break;
            }
        }
    } 
    catch (Exception exception) 
    {
        // Log and throw exception
            throw exception
    }
}

1
Điều này sẽ chỉ hoạt động nếu kết nối được cấu hình với bindOnInit="false"tùy chọn.
anilech

4

Bây giờ có một cách để làm điều này bắt đầu với tomcat v8.5.24.

Họ giới thiệu 2 phương pháp có tên:

  1. reloadSslhostConfig (String hostName) - để tải lại một máy chủ cụ thể
  2. tải lạiSslhostConfigs () - tải lại tất cả

Chúng có thể được gọi theo nhiều cách khác nhau:

  1. Sử dụng jmx
  2. Sử dụng dịch vụ quản lý (trong tomcat v9.xx)
  3. Bằng cách thực hiện giao thức tùy chỉnh - tôi đã tìm thấy cách này trong quá trình nghiên cứu của mình

Chi tiết về cách 1 và cách 2 dễ dàng có sẵn trong tài liệu tomcat.

Chi tiết về cách sử dụng cách 3:

  1. Tạo một lớp mở rộng giao thức bạn chọn, vd. Http11NioProtocol
  2. Ghi đè các phương thức cần thiết và chỉ cần gọi siêu trong chúng để giữ hành vi mặc định
  3. Tạo một chủ đề trong lớp này để thỉnh thoảng gọi phương thức reloadSslhostConfigs
  4. Gói lớp này trong một cái lọ và đặt cái lọ đó vào thư mục lib của tomcat
  5. Chỉnh sửa giao thức trong trình kết nối trong server.xml để sử dụng giao thức được xác định tùy chỉnh này

Tìm mã mẫu dưới đây:

Lớp giao thức chính:

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");
                }
            }
        }
   }
}

Trình kết nối trong server.xml nên đề cập đến điều này như giao thức:

<Connector protocol="com.myown.connector.ReloadProtocol"
 ..........

Hi vọng điêu nay co ich.

Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookieChính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.