All Downloads are FREE. Search and download functionalities are using the official Maven repository.

org.apache.zookeeper.common.X509Util Maven / Gradle / Ivy

/*
 * Licensed to the Apache Software Foundation (ASF) under one
 * or more contributor license agreements.  See the NOTICE file
 * distributed with this work for additional information
 * regarding copyright ownership.  The ASF licenses this file
 * to you under the Apache License, Version 2.0 (the
 * "License"); you may not use this file except in compliance
 * with the License.  You may obtain a copy of the License at
 *
 *     http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

package org.apache.zookeeper.common;

import java.io.Closeable;
import java.io.IOException;
import java.lang.reflect.InvocationTargetException;
import java.net.Socket;
import java.nio.file.Path;
import java.nio.file.Paths;
import java.nio.file.StandardWatchEventKinds;
import java.nio.file.WatchEvent;
import java.security.GeneralSecurityException;
import java.security.KeyManagementException;
import java.security.KeyStore;
import java.security.NoSuchAlgorithmException;
import java.security.Security;
import java.security.cert.PKIXBuilderParameters;
import java.security.cert.X509CertSelector;
import java.util.Objects;
import java.util.concurrent.atomic.AtomicReference;
import java.util.function.Supplier;
import javax.net.ssl.CertPathTrustManagerParameters;
import javax.net.ssl.KeyManager;
import javax.net.ssl.KeyManagerFactory;
import javax.net.ssl.SSLContext;
import javax.net.ssl.SSLServerSocket;
import javax.net.ssl.SSLSocket;
import javax.net.ssl.TrustManager;
import javax.net.ssl.TrustManagerFactory;
import javax.net.ssl.X509ExtendedTrustManager;
import javax.net.ssl.X509KeyManager;
import javax.net.ssl.X509TrustManager;
import org.apache.zookeeper.common.X509Exception.KeyManagerException;
import org.apache.zookeeper.common.X509Exception.SSLContextException;
import org.apache.zookeeper.common.X509Exception.TrustManagerException;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

/**
 * Utility code for X509 handling
 *
 * Default cipher suites:
 *
 *   Performance testing done by Facebook engineers shows that on Intel x86_64 machines, Java9 performs better with
 *   GCM and Java8 performs better with CBC, so these seem like reasonable defaults.
 */
public abstract class X509Util implements Closeable, AutoCloseable {

    private static final Logger LOG = LoggerFactory.getLogger(X509Util.class);

    private static final String REJECT_CLIENT_RENEGOTIATION_PROPERTY = "jdk.tls.rejectClientInitiatedRenegotiation";

    static {
        // Client-initiated renegotiation in TLS is unsafe and
        // allows MITM attacks, so we should disable it unless
        // it was explicitly enabled by the user.
        // A brief summary of the issue can be found at
        // https://www.ietf.org/proceedings/76/slides/tls-7.pdf
        if (System.getProperty(REJECT_CLIENT_RENEGOTIATION_PROPERTY) == null) {
            LOG.info("Setting -D {}=true to disable client-initiated TLS renegotiation", REJECT_CLIENT_RENEGOTIATION_PROPERTY);
            System.setProperty(REJECT_CLIENT_RENEGOTIATION_PROPERTY, Boolean.TRUE.toString());
        }
    }

    public static final String DEFAULT_PROTOCOL = "TLSv1.2";
    private static String[] getGCMCiphers() {
        return new String[]{"TLS_ECDHE_ECDSA_WITH_AES_128_GCM_SHA256", "TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA256", "TLS_ECDHE_ECDSA_WITH_AES_256_GCM_SHA384", "TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384"};
    }

    private static String[] getCBCCiphers() {
        return new String[]{"TLS_ECDHE_ECDSA_WITH_AES_128_CBC_SHA256", "TLS_ECDHE_RSA_WITH_AES_128_CBC_SHA256", "TLS_ECDHE_ECDSA_WITH_AES_128_CBC_SHA", "TLS_ECDHE_RSA_WITH_AES_128_CBC_SHA", "TLS_ECDHE_ECDSA_WITH_AES_256_CBC_SHA384", "TLS_ECDHE_RSA_WITH_AES_256_CBC_SHA384", "TLS_ECDHE_ECDSA_WITH_AES_256_CBC_SHA", "TLS_ECDHE_RSA_WITH_AES_256_CBC_SHA"};
    }

    private static String[] concatArrays(String[] left, String[] right) {
        String[] result = new String[left.length + right.length];
        System.arraycopy(left, 0, result, 0, left.length);
        System.arraycopy(right, 0, result, left.length, right.length);
        return result;
    }

    // On Java 8, prefer CBC ciphers since AES-NI support is lacking and GCM is slower than CBC.
    private static final String[] DEFAULT_CIPHERS_JAVA8 = concatArrays(getCBCCiphers(), getGCMCiphers());
    // On Java 9 and later, prefer GCM ciphers due to improved AES-NI support.
    // Note that this performance assumption might not hold true for architectures other than x86_64.
    private static final String[] DEFAULT_CIPHERS_JAVA9 = concatArrays(getGCMCiphers(), getCBCCiphers());

    public static final int DEFAULT_HANDSHAKE_DETECTION_TIMEOUT_MILLIS = 5000;

    /**
     * Enum specifying the client auth requirement of server-side TLS sockets created by this X509Util.
     * 
    *
  • NONE - do not request a client certificate.
  • *
  • WANT - request a client certificate, but allow anonymous clients to connect.
  • *
  • NEED - require a client certificate, disconnect anonymous clients.
  • *
* * If the config property is not set, the default value is NEED. */ public enum ClientAuth { NONE(io.netty.handler.ssl.ClientAuth.NONE), WANT(io.netty.handler.ssl.ClientAuth.OPTIONAL), NEED(io.netty.handler.ssl.ClientAuth.REQUIRE); private final io.netty.handler.ssl.ClientAuth nettyAuth; ClientAuth(io.netty.handler.ssl.ClientAuth nettyAuth) { this.nettyAuth = nettyAuth; } /** * Converts a property value to a ClientAuth enum. If the input string is empty or null, returns * ClientAuth.NEED. * @param prop the property string. * @return the ClientAuth. * @throws IllegalArgumentException if the property value is not "NONE", "WANT", "NEED", or empty/null. */ public static ClientAuth fromPropertyValue(String prop) { if (prop == null || prop.length() == 0) { return NEED; } return ClientAuth.valueOf(prop.toUpperCase()); } public io.netty.handler.ssl.ClientAuth toNettyClientAuth() { return nettyAuth; } } private String sslProtocolProperty = getConfigPrefix() + "protocol"; private String sslEnabledProtocolsProperty = getConfigPrefix() + "enabledProtocols"; private String cipherSuitesProperty = getConfigPrefix() + "ciphersuites"; private String sslKeystoreLocationProperty = getConfigPrefix() + "keyStore.location"; private String sslKeystorePasswdProperty = getConfigPrefix() + "keyStore.password"; private String sslKeystoreTypeProperty = getConfigPrefix() + "keyStore.type"; private String sslTruststoreLocationProperty = getConfigPrefix() + "trustStore.location"; private String sslTruststorePasswdProperty = getConfigPrefix() + "trustStore.password"; private String sslTruststoreTypeProperty = getConfigPrefix() + "trustStore.type"; private String sslContextSupplierClassProperty = getConfigPrefix() + "context.supplier.class"; private String sslHostnameVerificationEnabledProperty = getConfigPrefix() + "hostnameVerification"; private String sslCrlEnabledProperty = getConfigPrefix() + "crl"; private String sslOcspEnabledProperty = getConfigPrefix() + "ocsp"; private String sslClientAuthProperty = getConfigPrefix() + "clientAuth"; private String sslHandshakeDetectionTimeoutMillisProperty = getConfigPrefix() + "handshakeDetectionTimeoutMillis"; private ZKConfig zkConfig; private AtomicReference defaultSSLContextAndOptions = new AtomicReference<>(null); private FileChangeWatcher keyStoreFileWatcher; private FileChangeWatcher trustStoreFileWatcher; public X509Util() { this(null); } public X509Util(ZKConfig zkConfig) { this.zkConfig = zkConfig; keyStoreFileWatcher = trustStoreFileWatcher = null; } protected abstract String getConfigPrefix(); protected abstract boolean shouldVerifyClientHostname(); public String getSslProtocolProperty() { return sslProtocolProperty; } public String getSslEnabledProtocolsProperty() { return sslEnabledProtocolsProperty; } public String getCipherSuitesProperty() { return cipherSuitesProperty; } public String getSslKeystoreLocationProperty() { return sslKeystoreLocationProperty; } public String getSslCipherSuitesProperty() { return cipherSuitesProperty; } public String getSslKeystorePasswdProperty() { return sslKeystorePasswdProperty; } public String getSslKeystoreTypeProperty() { return sslKeystoreTypeProperty; } public String getSslTruststoreLocationProperty() { return sslTruststoreLocationProperty; } public String getSslTruststorePasswdProperty() { return sslTruststorePasswdProperty; } public String getSslTruststoreTypeProperty() { return sslTruststoreTypeProperty; } public String getSslContextSupplierClassProperty() { return sslContextSupplierClassProperty; } public String getSslHostnameVerificationEnabledProperty() { return sslHostnameVerificationEnabledProperty; } public String getSslCrlEnabledProperty() { return sslCrlEnabledProperty; } public String getSslOcspEnabledProperty() { return sslOcspEnabledProperty; } public String getSslClientAuthProperty() { return sslClientAuthProperty; } /** * Returns the config property key that controls the amount of time, in milliseconds, that the first * UnifiedServerSocket read operation will block for when trying to detect the client mode (TLS or PLAINTEXT). * * @return the config property key. */ public String getSslHandshakeDetectionTimeoutMillisProperty() { return sslHandshakeDetectionTimeoutMillisProperty; } public SSLContext getDefaultSSLContext() throws X509Exception.SSLContextException { return getDefaultSSLContextAndOptions().getSSLContext(); } public SSLContext createSSLContext(ZKConfig config) throws SSLContextException { return createSSLContextAndOptions(config).getSSLContext(); } public SSLContextAndOptions getDefaultSSLContextAndOptions() throws X509Exception.SSLContextException { SSLContextAndOptions result = defaultSSLContextAndOptions.get(); if (result == null) { result = createSSLContextAndOptions(); if (!defaultSSLContextAndOptions.compareAndSet(null, result)) { // lost the race, another thread already set the value result = defaultSSLContextAndOptions.get(); } } return result; } private void resetDefaultSSLContextAndOptions() throws X509Exception.SSLContextException { SSLContextAndOptions newContext = createSSLContextAndOptions(); defaultSSLContextAndOptions.set(newContext); } private SSLContextAndOptions createSSLContextAndOptions() throws SSLContextException { /* * Since Configuration initializes the key store and trust store related * configuration from system property. Reading property from * configuration will be same reading from system property */ return createSSLContextAndOptions(zkConfig == null ? new ZKConfig() : zkConfig); } /** * Returns the max amount of time, in milliseconds, that the first UnifiedServerSocket read() operation should * block for when trying to detect the client mode (TLS or PLAINTEXT). * Defaults to {@link X509Util#DEFAULT_HANDSHAKE_DETECTION_TIMEOUT_MILLIS}. * * @return the handshake detection timeout, in milliseconds. */ public int getSslHandshakeTimeoutMillis() { try { SSLContextAndOptions ctx = getDefaultSSLContextAndOptions(); return ctx.getHandshakeDetectionTimeoutMillis(); } catch (SSLContextException e) { LOG.error("Error creating SSL context and options", e); return DEFAULT_HANDSHAKE_DETECTION_TIMEOUT_MILLIS; } catch (Exception e) { LOG.error("Error parsing config property {}", getSslHandshakeDetectionTimeoutMillisProperty(), e); return DEFAULT_HANDSHAKE_DETECTION_TIMEOUT_MILLIS; } } @SuppressWarnings("unchecked") public SSLContextAndOptions createSSLContextAndOptions(ZKConfig config) throws SSLContextException { final String supplierContextClassName = config.getProperty(sslContextSupplierClassProperty); if (supplierContextClassName != null) { LOG.debug("Loading SSLContext supplier from property '{}'", sslContextSupplierClassProperty); try { Class sslContextClass = Class.forName(supplierContextClassName); Supplier sslContextSupplier = (Supplier) sslContextClass.getConstructor().newInstance(); return new SSLContextAndOptions(this, config, sslContextSupplier.get()); } catch (ClassNotFoundException | ClassCastException | NoSuchMethodException | InvocationTargetException | InstantiationException | IllegalAccessException e) { throw new SSLContextException("Could not retrieve the SSLContext from supplier source '" + supplierContextClassName + "' provided in the property '" + sslContextSupplierClassProperty + "'", e); } } else { return createSSLContextAndOptionsFromConfig(config); } } public SSLContextAndOptions createSSLContextAndOptionsFromConfig(ZKConfig config) throws SSLContextException { KeyManager[] keyManagers = null; TrustManager[] trustManagers = null; String keyStoreLocationProp = config.getProperty(sslKeystoreLocationProperty, ""); String keyStorePasswordProp = config.getProperty(sslKeystorePasswdProperty, ""); String keyStoreTypeProp = config.getProperty(sslKeystoreTypeProperty); // There are legal states in some use cases for null KeyManager or TrustManager. // But if a user wanna specify one, location is required. Password defaults to empty string if it is not // specified by the user. if (keyStoreLocationProp.isEmpty()) { LOG.warn("{} not specified", getSslKeystoreLocationProperty()); } else { try { keyManagers = new KeyManager[]{createKeyManager(keyStoreLocationProp, keyStorePasswordProp, keyStoreTypeProp)}; } catch (KeyManagerException keyManagerException) { throw new SSLContextException("Failed to create KeyManager", keyManagerException); } catch (IllegalArgumentException e) { throw new SSLContextException("Bad value for " + sslKeystoreTypeProperty + ": " + keyStoreTypeProp, e); } } String trustStoreLocationProp = config.getProperty(sslTruststoreLocationProperty, ""); String trustStorePasswordProp = config.getProperty(sslTruststorePasswdProperty, ""); String trustStoreTypeProp = config.getProperty(sslTruststoreTypeProperty); boolean sslCrlEnabled = config.getBoolean(this.sslCrlEnabledProperty); boolean sslOcspEnabled = config.getBoolean(this.sslOcspEnabledProperty); boolean sslServerHostnameVerificationEnabled = config.getBoolean(this.getSslHostnameVerificationEnabledProperty(), true); boolean sslClientHostnameVerificationEnabled = sslServerHostnameVerificationEnabled && shouldVerifyClientHostname(); if (trustStoreLocationProp.isEmpty()) { LOG.warn("{} not specified", getSslTruststoreLocationProperty()); } else { try { trustManagers = new TrustManager[]{createTrustManager(trustStoreLocationProp, trustStorePasswordProp, trustStoreTypeProp, sslCrlEnabled, sslOcspEnabled, sslServerHostnameVerificationEnabled, sslClientHostnameVerificationEnabled)}; } catch (TrustManagerException trustManagerException) { throw new SSLContextException("Failed to create TrustManager", trustManagerException); } catch (IllegalArgumentException e) { throw new SSLContextException("Bad value for " + sslTruststoreTypeProperty + ": " + trustStoreTypeProp, e); } } String protocol = config.getProperty(sslProtocolProperty, DEFAULT_PROTOCOL); try { SSLContext sslContext = SSLContext.getInstance(protocol); sslContext.init(keyManagers, trustManagers, null); return new SSLContextAndOptions(this, config, sslContext); } catch (NoSuchAlgorithmException | KeyManagementException sslContextInitException) { throw new SSLContextException(sslContextInitException); } } public static KeyStore loadKeyStore( String keyStoreLocation, String keyStorePassword, String keyStoreTypeProp) throws IOException, GeneralSecurityException { KeyStoreFileType storeFileType = KeyStoreFileType.fromPropertyValueOrFileName(keyStoreTypeProp, keyStoreLocation); return FileKeyStoreLoaderBuilderProvider .getBuilderForKeyStoreFileType(storeFileType) .setKeyStorePath(keyStoreLocation) .setKeyStorePassword(keyStorePassword) .build() .loadKeyStore(); } public static KeyStore loadTrustStore( String trustStoreLocation, String trustStorePassword, String trustStoreTypeProp) throws IOException, GeneralSecurityException { KeyStoreFileType storeFileType = KeyStoreFileType.fromPropertyValueOrFileName(trustStoreTypeProp, trustStoreLocation); return FileKeyStoreLoaderBuilderProvider .getBuilderForKeyStoreFileType(storeFileType) .setTrustStorePath(trustStoreLocation) .setTrustStorePassword(trustStorePassword) .build() .loadTrustStore(); } /** * Creates a key manager by loading the key store from the given file of * the given type, optionally decrypting it using the given password. * @param keyStoreLocation the location of the key store file. * @param keyStorePassword optional password to decrypt the key store. If * empty, assumes the key store is not encrypted. * @param keyStoreTypeProp must be JKS, PEM, or null. If null, attempts to * autodetect the key store type from the file * extension (.jks / .pem). * @return the key manager. * @throws KeyManagerException if something goes wrong. */ public static X509KeyManager createKeyManager( String keyStoreLocation, String keyStorePassword, String keyStoreTypeProp) throws KeyManagerException { if (keyStorePassword == null) { keyStorePassword = ""; } try { KeyStore ks = loadKeyStore(keyStoreLocation, keyStorePassword, keyStoreTypeProp); KeyManagerFactory kmf = KeyManagerFactory.getInstance("PKIX"); kmf.init(ks, keyStorePassword.toCharArray()); for (KeyManager km : kmf.getKeyManagers()) { if (km instanceof X509KeyManager) { return (X509KeyManager) km; } } throw new KeyManagerException("Couldn't find X509KeyManager"); } catch (IOException | GeneralSecurityException | IllegalArgumentException e) { throw new KeyManagerException(e); } } /** * Creates a trust manager by loading the trust store from the given file * of the given type, optionally decrypting it using the given password. * @param trustStoreLocation the location of the trust store file. * @param trustStorePassword optional password to decrypt the trust store * (only applies to JKS trust stores). If empty, * assumes the trust store is not encrypted. * @param trustStoreTypeProp must be JKS, PEM, or null. If null, attempts * to autodetect the trust store type from the * file extension (.jks / .pem). * @param crlEnabled enable CRL (certificate revocation list) checks. * @param ocspEnabled enable OCSP (online certificate status protocol) * checks. * @param serverHostnameVerificationEnabled if true, verify hostnames of * remote servers that client * sockets created by this * X509Util connect to. * @param clientHostnameVerificationEnabled if true, verify hostnames of * remote clients that server * sockets created by this * X509Util accept connections * from. * @return the trust manager. * @throws TrustManagerException if something goes wrong. */ public static X509TrustManager createTrustManager( String trustStoreLocation, String trustStorePassword, String trustStoreTypeProp, boolean crlEnabled, boolean ocspEnabled, final boolean serverHostnameVerificationEnabled, final boolean clientHostnameVerificationEnabled) throws TrustManagerException { if (trustStorePassword == null) { trustStorePassword = ""; } try { KeyStore ts = loadTrustStore(trustStoreLocation, trustStorePassword, trustStoreTypeProp); PKIXBuilderParameters pbParams = new PKIXBuilderParameters(ts, new X509CertSelector()); if (crlEnabled || ocspEnabled) { pbParams.setRevocationEnabled(true); System.setProperty("com.sun.net.ssl.checkRevocation", "true"); System.setProperty("com.sun.security.enableCRLDP", "true"); if (ocspEnabled) { Security.setProperty("ocsp.enable", "true"); } } else { pbParams.setRevocationEnabled(false); } // Revocation checking is only supported with the PKIX algorithm TrustManagerFactory tmf = TrustManagerFactory.getInstance("PKIX"); tmf.init(new CertPathTrustManagerParameters(pbParams)); for (final TrustManager tm : tmf.getTrustManagers()) { if (tm instanceof X509ExtendedTrustManager) { return new ZKTrustManager((X509ExtendedTrustManager) tm, serverHostnameVerificationEnabled, clientHostnameVerificationEnabled); } } throw new TrustManagerException("Couldn't find X509TrustManager"); } catch (IOException | GeneralSecurityException | IllegalArgumentException e) { throw new TrustManagerException(e); } } public SSLSocket createSSLSocket() throws X509Exception, IOException { return getDefaultSSLContextAndOptions().createSSLSocket(); } public SSLSocket createSSLSocket(Socket socket, byte[] pushbackBytes) throws X509Exception, IOException { return getDefaultSSLContextAndOptions().createSSLSocket(socket, pushbackBytes); } public SSLServerSocket createSSLServerSocket() throws X509Exception, IOException { return getDefaultSSLContextAndOptions().createSSLServerSocket(); } public SSLServerSocket createSSLServerSocket(int port) throws X509Exception, IOException { return getDefaultSSLContextAndOptions().createSSLServerSocket(port); } static String[] getDefaultCipherSuites() { return getDefaultCipherSuitesForJavaVersion(System.getProperty("java.specification.version")); } static String[] getDefaultCipherSuitesForJavaVersion(String javaVersion) { Objects.requireNonNull(javaVersion); if (javaVersion.matches("\\d+")) { // Must be Java 9 or later LOG.debug("Using Java9+ optimized cipher suites for Java version {}", javaVersion); return DEFAULT_CIPHERS_JAVA9; } else if (javaVersion.startsWith("1.")) { // Must be Java 1.8 or earlier LOG.debug("Using Java8 optimized cipher suites for Java version {}", javaVersion); return DEFAULT_CIPHERS_JAVA8; } else { LOG.debug("Could not parse java version {}, using Java8 optimized cipher suites", javaVersion); return DEFAULT_CIPHERS_JAVA8; } } private FileChangeWatcher newFileChangeWatcher(String fileLocation) throws IOException { if (fileLocation == null || fileLocation.isEmpty()) { return null; } final Path filePath = Paths.get(fileLocation).toAbsolutePath(); Path parentPath = filePath.getParent(); if (parentPath == null) { throw new IOException("Key/trust store path does not have a parent: " + filePath); } return new FileChangeWatcher(parentPath, watchEvent -> { handleWatchEvent(filePath, watchEvent); }); } /** * Enables automatic reloading of the trust store and key store files when they change on disk. * * @throws IOException if creating the FileChangeWatcher objects fails. */ public void enableCertFileReloading() throws IOException { LOG.info("enabling cert file reloading"); ZKConfig config = zkConfig == null ? new ZKConfig() : zkConfig; FileChangeWatcher newKeyStoreFileWatcher = newFileChangeWatcher(config.getProperty(sslKeystoreLocationProperty)); if (newKeyStoreFileWatcher != null) { // stop old watcher if there is one if (keyStoreFileWatcher != null) { keyStoreFileWatcher.stop(); } keyStoreFileWatcher = newKeyStoreFileWatcher; keyStoreFileWatcher.start(); } FileChangeWatcher newTrustStoreFileWatcher = newFileChangeWatcher(config.getProperty(sslTruststoreLocationProperty)); if (newTrustStoreFileWatcher != null) { // stop old watcher if there is one if (trustStoreFileWatcher != null) { trustStoreFileWatcher.stop(); } trustStoreFileWatcher = newTrustStoreFileWatcher; trustStoreFileWatcher.start(); } } /** * Disables automatic reloading of the trust store and key store files when they change on disk. * Stops background threads and closes WatchService instances. */ @Override public void close() { if (keyStoreFileWatcher != null) { keyStoreFileWatcher.stop(); keyStoreFileWatcher = null; } if (trustStoreFileWatcher != null) { trustStoreFileWatcher.stop(); trustStoreFileWatcher = null; } } /** * Handler for watch events that let us know a file we may care about has changed on disk. * * @param filePath the path to the file we are watching for changes. * @param event the WatchEvent. */ private void handleWatchEvent(Path filePath, WatchEvent event) { boolean shouldResetContext = false; Path dirPath = filePath.getParent(); if (event.kind().equals(StandardWatchEventKinds.OVERFLOW)) { // If we get notified about possibly missed events, reload the key store / trust store just to be sure. shouldResetContext = true; } else if (event.kind().equals(StandardWatchEventKinds.ENTRY_MODIFY) || event.kind().equals(StandardWatchEventKinds.ENTRY_CREATE)) { Path eventFilePath = dirPath.resolve((Path) event.context()); if (filePath.equals(eventFilePath)) { shouldResetContext = true; } } // Note: we don't care about delete events if (shouldResetContext) { LOG.debug( "Attempting to reset default SSL context after receiving watch event: {} with context: {}", event.kind(), event.context()); try { this.resetDefaultSSLContextAndOptions(); } catch (SSLContextException e) { throw new RuntimeException(e); } } else { LOG.debug( "Ignoring watch event and keeping previous default SSL context. Event kind: {} with context: {}", event.kind(), event.context()); } } }




© 2015 - 2025 Weber Informatics LLC | Privacy Policy