This is an automated email from the ASF dual-hosted git repository.

andor pushed a commit to branch master
in repository https://gitbox.apache.org/repos/asf/zookeeper.git


The following commit(s) were added to refs/heads/master by this push:
     new c91f6111d ZOOKEEPER-4997: Unify construction of TrustManager to 
dedicated method
c91f6111d is described below

commit c91f6111d2f4d115217ba1dc4c28fa5bd26e2c91
Author: Kezhu Wang <[email protected]>
AuthorDate: Wed Dec 17 06:24:33 2025 +0800

    ZOOKEEPER-4997: Unify construction of TrustManager to dedicated method
    
    Reviewers: anmolnar
    Author: kezhuw
    Closes #2340 from kezhuw/ZOOKEEPER-4997-refactor-x509-createTrustManager
---
 .../apache/zookeeper/common/ClientX509Util.java    |  50 ++------
 .../java/org/apache/zookeeper/common/X509Util.java | 131 ++++++++++++++-------
 .../server/auth/X509AuthenticationProvider.java    |  55 ++-------
 .../zookeeper/common/X509UtilCrlPropertyTest.java  | 104 ++++++++++++++++
 4 files changed, 209 insertions(+), 131 deletions(-)

diff --git 
a/zookeeper-server/src/main/java/org/apache/zookeeper/common/ClientX509Util.java
 
b/zookeeper-server/src/main/java/org/apache/zookeeper/common/ClientX509Util.java
index b035bbfe0..1e50b8425 100644
--- 
a/zookeeper-server/src/main/java/org/apache/zookeeper/common/ClientX509Util.java
+++ 
b/zookeeper-server/src/main/java/org/apache/zookeeper/common/ClientX509Util.java
@@ -63,20 +63,14 @@ public String getSslProviderProperty() {
 
     public SslContext createNettySslContextForClient(ZKConfig config)
         throws X509Exception.KeyManagerException, 
X509Exception.TrustManagerException, SSLException {
-        String keyStoreLocation = 
config.getProperty(getSslKeystoreLocationProperty(), "");
-        String keyStorePassword = getPasswordFromConfigPropertyOrFile(config, 
getSslKeystorePasswdProperty(),
-            getSslKeystorePasswdPathProperty());
-        String keyStoreType = config.getProperty(getSslKeystoreTypeProperty());
-
         SslContextBuilder sslContextBuilder = SslContextBuilder.forClient();
 
-        if (keyStoreLocation.isEmpty()) {
-            LOG.warn("{} not specified", getSslKeystoreLocationProperty());
-        } else {
-            sslContextBuilder.keyManager(createKeyManager(keyStoreLocation, 
keyStorePassword, keyStoreType));
+        KeyManager km = buildKeyManager(config);
+        if (km != null) {
+            sslContextBuilder.keyManager(km);
         }
 
-        TrustManager tm = getTrustManager(config);
+        TrustManager tm = buildTrustManager(config);
         if (tm != null) {
             sslContextBuilder.trustManager(tm);
         }
@@ -103,19 +97,12 @@ public SslContext createNettySslContextForClient(ZKConfig 
config)
 
     public SslContext createNettySslContextForServer(ZKConfig config)
         throws X509Exception.SSLContextException, 
X509Exception.KeyManagerException, X509Exception.TrustManagerException, 
SSLException {
-        String keyStoreLocation = 
config.getProperty(getSslKeystoreLocationProperty(), "");
-        String keyStorePassword = getPasswordFromConfigPropertyOrFile(config, 
getSslKeystorePasswdProperty(),
-            getSslKeystorePasswdPathProperty());
-        String keyStoreType = config.getProperty(getSslKeystoreTypeProperty());
-
-        if (keyStoreLocation.isEmpty()) {
+        KeyManager km = buildKeyManager(config);
+        if (km == null) {
             throw new X509Exception.SSLContextException(
                 "Keystore is required for SSL server: " + 
getSslKeystoreLocationProperty());
         }
-
-        KeyManager km = createKeyManager(keyStoreLocation, keyStorePassword, 
keyStoreType);
-
-        return createNettySslContextForServer(config, km, 
getTrustManager(config));
+        return createNettySslContextForServer(config, km, 
buildTrustManager(config));
     }
 
     public SslContext createNettySslContextForServer(ZKConfig config, 
KeyManager keyManager, TrustManager trustManager) throws SSLException {
@@ -195,27 +182,4 @@ private Iterable<String> getCipherSuites(final ZKConfig 
config) {
     public SslProvider getSslProvider(ZKConfig config) {
         return 
SslProvider.valueOf(config.getProperty(getSslProviderProperty(), "JDK"));
     }
-
-    private TrustManager getTrustManager(ZKConfig config) throws 
X509Exception.TrustManagerException {
-        String trustStoreLocation = 
config.getProperty(getSslTruststoreLocationProperty(), "");
-        String trustStorePassword = 
getPasswordFromConfigPropertyOrFile(config, getSslTruststorePasswdProperty(),
-            getSslTruststorePasswdPathProperty());
-        String trustStoreType = 
config.getProperty(getSslTruststoreTypeProperty());
-
-        boolean sslCrlEnabled = config.getBoolean(getSslCrlEnabledProperty(), 
Boolean.getBoolean("com.sun.net.ssl.checkRevocation"));
-        boolean sslOcspEnabled = 
config.getBoolean(getSslOcspEnabledProperty(), 
Boolean.parseBoolean(Security.getProperty("ocsp.enable")));
-        boolean sslServerHostnameVerificationEnabled = 
isServerHostnameVerificationEnabled(config);
-        boolean sslClientHostnameVerificationEnabled = 
isClientHostnameVerificationEnabled(config);
-        boolean allowReverseDnsLookup = allowReverseDnsLookup(config);
-
-        if (trustStoreLocation.isEmpty()) {
-            LOG.warn("{} not specified", getSslTruststoreLocationProperty());
-            return null;
-        } else {
-            return createTrustManager(trustStoreLocation, trustStorePassword, 
trustStoreType,
-                sslCrlEnabled, sslOcspEnabled, 
sslServerHostnameVerificationEnabled,
-                sslClientHostnameVerificationEnabled, allowReverseDnsLookup,
-                getFipsMode(config));
-        }
-    }
 }
diff --git 
a/zookeeper-server/src/main/java/org/apache/zookeeper/common/X509Util.java 
b/zookeeper-server/src/main/java/org/apache/zookeeper/common/X509Util.java
index 2ac1ad9ee..fee410cf0 100644
--- a/zookeeper-server/src/main/java/org/apache/zookeeper/common/X509Util.java
+++ b/zookeeper-server/src/main/java/org/apache/zookeeper/common/X509Util.java
@@ -378,57 +378,37 @@ public SSLContextAndOptions 
createSSLContextAndOptions(ZKConfig config) throws S
     }
 
     public SSLContextAndOptions createSSLContextAndOptionsFromConfig(ZKConfig 
config) throws SSLContextException {
-        KeyManager[] keyManagers = null;
-        TrustManager[] trustManagers = null;
-
-        String keyStoreLocationProp = 
config.getProperty(sslKeystoreLocationProperty, "");
-        String keyStorePasswordProp = 
getPasswordFromConfigPropertyOrFile(config, sslKeystorePasswdProperty, 
sslKeystorePasswdPathProperty);
-        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.
+        KeyManager[] keyManagers = null;
+        TrustManager[] trustManagers = null;
 
-        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);
+        try {
+            KeyManager km = buildKeyManager(config);
+            if (km != null) {
+                keyManagers = new KeyManager[]{km};
             }
+        } catch (KeyManagerException keyManagerException) {
+            throw new SSLContextException("Failed to create KeyManager", 
keyManagerException);
+        } catch (IllegalArgumentException e) {
+            String keyStoreTypeProp = 
config.getProperty(sslKeystoreTypeProperty);
+            throw new SSLContextException("Bad value for " + 
sslKeystoreTypeProperty + ": " + keyStoreTypeProp, e);
         }
 
-        String trustStoreLocationProp = 
config.getProperty(sslTruststoreLocationProperty, "");
-        String trustStorePasswordProp = 
getPasswordFromConfigPropertyOrFile(config, sslTruststorePasswdProperty, 
sslTruststorePasswdPathProperty);
-        String trustStoreTypeProp = 
config.getProperty(sslTruststoreTypeProperty);
-
-        boolean sslCrlEnabled = config.getBoolean(this.sslCrlEnabledProperty, 
Boolean.getBoolean("com.sun.net.ssl.checkRevocation"));
-        boolean sslOcspEnabled = 
config.getBoolean(this.sslOcspEnabledProperty, 
Boolean.parseBoolean(Security.getProperty("ocsp.enable")));
-
-        boolean sslServerHostnameVerificationEnabled = 
isServerHostnameVerificationEnabled(config);
-        boolean sslClientHostnameVerificationEnabled = 
isClientHostnameVerificationEnabled(config);
-        boolean allowReverseDnsLookup = allowReverseDnsLookup(config);
-        boolean fipsMode = getFipsMode(config);
-
-        if (trustStoreLocationProp.isEmpty()) {
-            LOG.warn("{} not specified", getSslTruststoreLocationProperty());
-        } else {
-            try {
-                trustManagers = new TrustManager[]{
-                    createTrustManager(trustStoreLocationProp, 
trustStorePasswordProp, trustStoreTypeProp, sslCrlEnabled,
-                        sslOcspEnabled, sslServerHostnameVerificationEnabled, 
sslClientHostnameVerificationEnabled,
-                        allowReverseDnsLookup, fipsMode)};
-            } catch (TrustManagerException trustManagerException) {
-                throw new SSLContextException("Failed to create TrustManager", 
trustManagerException);
-            } catch (IllegalArgumentException e) {
-                throw new SSLContextException("Bad value for "
-                                              + sslTruststoreTypeProperty
-                                              + ": "
-                                              + trustStoreTypeProp, e);
+        try {
+            TrustManager tm = buildTrustManager(config);
+            if (tm != null) {
+                trustManagers = new TrustManager[]{tm};
             }
+        } catch (TrustManagerException trustManagerException) {
+            throw new SSLContextException("Failed to create TrustManager", 
trustManagerException);
+        } catch (IllegalArgumentException e) {
+            String trustStoreTypeProp = 
config.getProperty(sslTruststoreTypeProperty);
+            throw new SSLContextException("Bad value for "
+                    + sslTruststoreTypeProperty
+                    + ": "
+                    + trustStoreTypeProp, e);
         }
 
         String protocol = config.getProperty(sslProtocolProperty, 
DEFAULT_PROTOCOL);
@@ -487,6 +467,18 @@ public String getPasswordFromConfigPropertyOrFile(final 
ZKConfig config,
         return value;
     }
 
+    public X509KeyManager buildKeyManager(ZKConfig config) throws 
KeyManagerException {
+        String keyStoreLocation = 
config.getProperty(getSslKeystoreLocationProperty(), "");
+        if (keyStoreLocation.isEmpty()) {
+            LOG.warn("{} not specified for X509KeyManager", 
getSslKeystoreLocationProperty());
+            return null;
+        }
+        String keyStorePassword = getPasswordFromConfigPropertyOrFile(config, 
getSslKeystorePasswdProperty(),
+                getSslKeystorePasswdPathProperty());
+        String keyStoreType = config.getProperty(getSslKeystoreTypeProperty());
+        return createKeyManager(keyStoreLocation, keyStorePassword, 
keyStoreType);
+    }
+
     /**
      * Creates a key manager by loading the key store from the given file of
      * the given type, optionally decrypting it using the given password.
@@ -522,6 +514,59 @@ public static X509KeyManager createKeyManager(
         }
     }
 
+    public X509TrustManager buildTrustManager(ZKConfig config) throws 
TrustManagerException {
+        String trustStoreLocationProp = 
config.getProperty(sslTruststoreLocationProperty, "");
+        if (trustStoreLocationProp.isEmpty()) {
+            LOG.warn("{} not specified for X509TrustManager", 
sslTruststoreLocationProperty);
+            return null;
+        }
+
+        String trustStorePasswordProp = 
getPasswordFromConfigPropertyOrFile(config, sslTruststorePasswdProperty, 
sslTruststorePasswdPathProperty);
+        String trustStoreTypeProp = 
config.getProperty(sslTruststoreTypeProperty);
+
+        boolean sslCrlEnabled = config.getBoolean(this.sslCrlEnabledProperty, 
Boolean.getBoolean("com.sun.net.ssl.checkRevocation"));
+        boolean sslOcspEnabled = 
config.getBoolean(this.sslOcspEnabledProperty, 
Boolean.parseBoolean(Security.getProperty("ocsp.enable")));
+
+        boolean sslServerHostnameVerificationEnabled = 
isServerHostnameVerificationEnabled(config);
+        boolean sslClientHostnameVerificationEnabled = 
isClientHostnameVerificationEnabled(config);
+        boolean allowReverseDnsLookup = allowReverseDnsLookup(config);
+        boolean fipsMode = getFipsMode(config);
+
+        return createTrustManagerInternal(
+                trustStoreLocationProp,
+                trustStorePasswordProp,
+                trustStoreTypeProp,
+                sslCrlEnabled,
+                sslOcspEnabled,
+                sslServerHostnameVerificationEnabled,
+                sslClientHostnameVerificationEnabled,
+                allowReverseDnsLookup,
+                fipsMode);
+    }
+
+    // @VisibleForTesting
+    protected X509TrustManager createTrustManagerInternal(
+            String trustStoreLocation,
+            String trustStorePassword,
+            String trustStoreTypeProp,
+            boolean crlEnabled,
+            boolean ocspEnabled,
+            final boolean serverHostnameVerificationEnabled,
+            final boolean clientHostnameVerificationEnabled,
+            final boolean allowReverseDnsLookup,
+            final boolean fipsMode) throws TrustManagerException {
+        return createTrustManager(
+                trustStoreLocation,
+                trustStorePassword,
+                trustStoreTypeProp,
+                crlEnabled,
+                ocspEnabled,
+                serverHostnameVerificationEnabled,
+                clientHostnameVerificationEnabled,
+                allowReverseDnsLookup,
+                fipsMode);
+    }
+
     /**
      * Creates a trust manager by loading the trust store from the given file
      * of the given type, optionally decrypting it using the given password.
diff --git 
a/zookeeper-server/src/main/java/org/apache/zookeeper/server/auth/X509AuthenticationProvider.java
 
b/zookeeper-server/src/main/java/org/apache/zookeeper/server/auth/X509AuthenticationProvider.java
index 8392db6bc..3bc430468 100644
--- 
a/zookeeper-server/src/main/java/org/apache/zookeeper/server/auth/X509AuthenticationProvider.java
+++ 
b/zookeeper-server/src/main/java/org/apache/zookeeper/server/auth/X509AuthenticationProvider.java
@@ -18,7 +18,6 @@
 
 package org.apache.zookeeper.server.auth;
 
-import java.security.Security;
 import java.security.cert.Certificate;
 import java.security.cert.CertificateException;
 import java.security.cert.X509Certificate;
@@ -80,55 +79,21 @@ public class X509AuthenticationProvider implements 
AuthenticationProvider {
     public X509AuthenticationProvider() throws X509Exception {
         ZKConfig config = new ZKConfig();
         try (X509Util x509Util = new ClientX509Util()) {
-            String keyStoreLocation = 
config.getProperty(x509Util.getSslKeystoreLocationProperty(), "");
-            String keyStorePassword = 
x509Util.getPasswordFromConfigPropertyOrFile(config,
-                    x509Util.getSslKeystorePasswdProperty(),
-                    x509Util.getSslKeystorePasswdPathProperty());
-            String keyStoreTypeProp = 
config.getProperty(x509Util.getSslKeystoreTypeProperty());
-
-            boolean crlEnabled = 
config.getBoolean(x509Util.getSslCrlEnabledProperty(), 
Boolean.getBoolean("com.sun.net.ssl.checkRevocation"));
-            boolean ocspEnabled = 
config.getBoolean(x509Util.getSslOcspEnabledProperty(), 
Boolean.parseBoolean(Security.getProperty("ocsp.enable")));
-            boolean hostnameVerificationEnabled = 
Boolean.parseBoolean(config.getProperty(x509Util.getSslHostnameVerificationEnabledProperty()));
-            boolean clientHostnameVerificationEnabled = 
x509Util.isClientHostnameVerificationEnabled(config);
-            boolean allowReverseDnsLookup = 
Boolean.parseBoolean(config.getProperty(x509Util.getSslAllowReverseDnsLookupProperty()));
-
             X509KeyManager km = null;
             X509TrustManager tm = null;
-            if (keyStoreLocation.isEmpty()) {
-                LOG.warn("keystore not specified for client connection");
-            } else {
-                try {
-                    km = X509Util.createKeyManager(keyStoreLocation, 
keyStorePassword, keyStoreTypeProp);
-                } catch (KeyManagerException e) {
-                    LOG.error("Failed to create key manager", e);
-                }
-            }
 
-            String trustStoreLocation = 
config.getProperty(x509Util.getSslTruststoreLocationProperty(), "");
-            String trustStorePassword = 
x509Util.getPasswordFromConfigPropertyOrFile(config,
-                    x509Util.getSslTruststorePasswdProperty(),
-                    x509Util.getSslTruststorePasswdPathProperty());
-            String trustStoreTypeProp = 
config.getProperty(x509Util.getSslTruststoreTypeProperty());
-            boolean fipsMode = X509Util.getFipsMode(config);
+            try {
+                km = x509Util.buildKeyManager(config);
+            } catch (KeyManagerException e) {
+                LOG.error("Failed to create key manager", e);
+            }
 
-            if (trustStoreLocation.isEmpty()) {
-                LOG.warn("Truststore not specified for client connection");
-            } else {
-                try {
-                    tm = X509Util.createTrustManager(
-                        trustStoreLocation,
-                        trustStorePassword,
-                        trustStoreTypeProp,
-                        crlEnabled,
-                        ocspEnabled,
-                        hostnameVerificationEnabled,
-                        clientHostnameVerificationEnabled,
-                        allowReverseDnsLookup,
-                        fipsMode);
-                } catch (TrustManagerException e) {
-                    LOG.error("Failed to create trust manager", e);
-                }
+            try {
+                tm = x509Util.buildTrustManager(config);
+            } catch (TrustManagerException e) {
+                LOG.error("Failed to create trust manager", e);
             }
+
             this.keyManager = km;
             this.trustManager = tm;
         }
diff --git 
a/zookeeper-server/src/test/java/org/apache/zookeeper/common/X509UtilCrlPropertyTest.java
 
b/zookeeper-server/src/test/java/org/apache/zookeeper/common/X509UtilCrlPropertyTest.java
new file mode 100644
index 000000000..154e738ce
--- /dev/null
+++ 
b/zookeeper-server/src/test/java/org/apache/zookeeper/common/X509UtilCrlPropertyTest.java
@@ -0,0 +1,104 @@
+/*
+ * 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 static org.junit.jupiter.api.Assertions.assertFalse;
+import static org.junit.jupiter.api.Assertions.assertTrue;
+import static org.mockito.Mockito.any;
+import static org.mockito.Mockito.anyBoolean;
+import static org.mockito.Mockito.doAnswer;
+import static org.mockito.Mockito.spy;
+import java.security.Security;
+import java.security.cert.CertificateException;
+import java.security.cert.X509Certificate;
+import javax.net.ssl.X509TrustManager;
+import org.junit.jupiter.params.ParameterizedTest;
+import org.junit.jupiter.params.provider.ValueSource;
+
+public class X509UtilCrlPropertyTest {
+    private static class TrustManagerCrlProperties implements X509TrustManager 
{
+        private final boolean crlEnabled;
+        private final boolean ocspEnabled;
+
+        public TrustManagerCrlProperties(boolean crlEnabled, boolean 
ocspEnabled) {
+            this.crlEnabled = crlEnabled;
+            this.ocspEnabled = ocspEnabled;
+        }
+
+        @Override
+        public X509Certificate[] getAcceptedIssuers() {
+            return new X509Certificate[0];
+        }
+
+        @Override
+        public void checkClientTrusted(X509Certificate[] chain, String 
authType) throws CertificateException {
+        }
+
+        @Override
+        public void checkServerTrusted(X509Certificate[] chain, String 
authType) throws CertificateException {
+        }
+    }
+
+    @ParameterizedTest
+    @ValueSource(classes = {ClientX509Util.class, QuorumX509Util.class})
+    public void testCrlProperties(Class<? extends X509Util> clazz) throws 
Exception {
+        try {
+            X509Util util = spy(clazz.getDeclaredConstructor().newInstance());
+
+            doAnswer(mock -> new TrustManagerCrlProperties(mock.getArgument(3, 
Boolean.class), mock.getArgument(4, Boolean.class)))
+                .when(util)
+                .createTrustManagerInternal(any(), any(), any(), anyBoolean(), 
anyBoolean(), anyBoolean(), anyBoolean(), anyBoolean(), anyBoolean());
+
+            ZKConfig config = new ZKConfig();
+            config.setProperty(util.getSslTruststoreLocationProperty(), 
"no-empty");
+
+            TrustManagerCrlProperties properties = (TrustManagerCrlProperties) 
util.buildTrustManager(config);
+
+            assertFalse(properties.crlEnabled);
+            assertFalse(properties.ocspEnabled);
+
+            // given: "com.sun.net.ssl.checkRevocation"
+            System.setProperty("com.sun.net.ssl.checkRevocation", "true");
+            properties = (TrustManagerCrlProperties) 
util.buildTrustManager(config);
+            // then: default to "com.sun.net.ssl.checkRevocation"
+            assertTrue(properties.crlEnabled);
+
+            // given: security property "ocsp.enable"
+            Security.setProperty("ocsp.enable", "true");
+            properties = (TrustManagerCrlProperties) 
util.buildTrustManager(config);
+            // then: default to "ocsp.enable"
+            assertTrue(properties.ocspEnabled);
+
+            // given: both "zookeeper.ssl.crl" and 
"com.sun.net.ssl.checkRevocation"
+            config.setProperty(util.getSslCrlEnabledProperty(), "false");
+            properties = (TrustManagerCrlProperties) 
util.buildTrustManager(config);
+            // then: "zookeeper.ssl.crl" take precedence
+            assertFalse(properties.crlEnabled);
+
+            // given: both "zookeeper.ssl.ocsp" and "ocsp.enable"
+            config.setProperty(util.getSslOcspEnabledProperty(), "false");
+            properties = (TrustManagerCrlProperties) 
util.buildTrustManager(config);
+            // then: "zookeeper.ssl.ocsp" take precedence
+            assertFalse(properties.ocspEnabled);
+        } finally {
+            System.clearProperty("com.sun.net.ssl.checkRevocation");
+            Security.setProperty("ocsp.enable", "false");
+        }
+    }
+}

Reply via email to