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 045833b  ZOOKEEPER-3160: Custom User SSLContext
045833b is described below

commit 045833b795a7041607337b192fa3dbcf2cc3f291
Author: Alex Rankin <[email protected]>
AuthorDate: Fri Jan 25 14:32:24 2019 +0100

    ZOOKEEPER-3160: Custom User SSLContext
    
    This is a master branch version of: 
https://github.com/apache/zookeeper/pull/654
    
    The previous PR was for branch 3.5, and couldn't be merged as that branch 
is closed for new features.
    
    The Zookeeper libraries currently allow you to set up your SSL Context via 
system properties such as "zookeeper.ssl.keyStore.location" in the X509Util. 
This covers most simple use cases, where users have software keystores on their 
harddrive.
    
    There are, however, a few additional scenarios that this doesn't cover. Two 
possible ones would be:
    
    1. The user has a hardware keystore, loaded in using PKCS11 or something 
similar.
    2. The user has no access to the software keystore, but can retrieve an 
already-constructed SSLContext from their container.
    
    For this, I would propose that the X509Util be extended to allow a user to 
set a property "zookeeper.ssl.client.context" to provide a class which supplies 
a custom SSL context. This gives a lot more flexibility to the ZK client, and 
allows the user to construct the SSLContext in whatever way they please (which 
also future proofs the implementation somewhat).
    
    I added a few simple tests to this class around setting the SSLContext, and 
setting an invalid one. I'm not testing the actual functionality of the 
SSLContext, etc.
    
    Author: Alex Rankin <[email protected]>
    Author: Alex Rankin <[email protected]>
    
    Reviewers: [email protected]
    
    Closes #728 from arankin-irl/ZOOKEEPER-3160 and squashes the following 
commits:
    
    a20c62feb [Alex Rankin] Merge branch 'master' into ZOOKEEPER-3160
    5a9b8fcb4 [Alex Rankin] Merge pull request #7 from apache/master
    3c3dfdd70 [Alex Rankin] Re-ordering imports.
    69e0b6c93 [Alex Rankin] Updating custom SSLContext supplier with review 
comments
    874529ba0 [Alex Rankin] Using supplier interface instead of custom 
interface, and renaming property
    ec272607d [Alex Rankin] Merge branch 'master' into ZOOKEEPER-3160
    75a010e34 [Alex Rankin] Merge pull request #6 from apache/master
    838f61c1a [Alex Rankin] Merge branch 'master' into ZOOKEEPER-3160
    f85d7e5cb [Alex Rankin] Merge pull request #5 from apache/master
    31d8dd5a4 [Alex Rankin] Extracting SSLContext creation from config to new 
method.
    400839a60 [Alex Rankin] Adding ability to specify custom SSLContext for 
client
    7ae74851b [Alex Rankin] Merge pull request #4 from apache/master
---
 .../java/org/apache/zookeeper/common/X509Util.java | 32 ++++++++++++++++++---
 .../java/org/apache/zookeeper/common/ZKConfig.java |  2 ++
 .../org/apache/zookeeper/common/X509UtilTest.java  | 33 ++++++++++++++++++++++
 3 files changed, 63 insertions(+), 4 deletions(-)

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 3ca787f..f8b275a 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
@@ -17,10 +17,9 @@
  */
 package org.apache.zookeeper.common;
 
-
-import java.io.ByteArrayInputStream;
 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;
@@ -33,15 +32,14 @@ import java.security.NoSuchAlgorithmException;
 import java.security.Security;
 import java.security.cert.PKIXBuilderParameters;
 import java.security.cert.X509CertSelector;
-import java.util.Arrays;
 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.SSLParameters;
 import javax.net.ssl.SSLServerSocket;
 import javax.net.ssl.SSLSocket;
 import javax.net.ssl.TrustManager;
@@ -137,6 +135,7 @@ public abstract class X509Util implements Closeable, 
AutoCloseable {
     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";
@@ -202,6 +201,10 @@ public abstract class X509Util implements Closeable, 
AutoCloseable {
         return sslTruststoreTypeProperty;
     }
 
+    public String getSslContextSupplierClassProperty() {
+        return sslContextSupplierClassProperty;
+    }
+
     public String getSslHostnameVerificationEnabledProperty() {
         return sslHostnameVerificationEnabledProperty;
     }
@@ -282,7 +285,28 @@ public abstract class X509Util implements Closeable, 
AutoCloseable {
         }
     }
 
+    @SuppressWarnings("unchecked")
     public SSLContextAndOptions createSSLContextAndOptions(ZKConfig config) 
throws SSLContextException {
+        final String supplierContextClassName = 
config.getProperty(sslContextSupplierClassProperty);
+        if (supplierContextClassName != null) {
+            if (LOG.isDebugEnabled()) {
+                LOG.debug("Loading SSLContext supplier from property '{}'", 
sslContextSupplierClassProperty);
+            }
+            try {
+                Class<?> sslContextClass = 
Class.forName(supplierContextClassName);
+                Supplier<SSLContext> sslContextSupplier = 
(Supplier<SSLContext>) 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;
 
diff --git 
a/zookeeper-server/src/main/java/org/apache/zookeeper/common/ZKConfig.java 
b/zookeeper-server/src/main/java/org/apache/zookeeper/common/ZKConfig.java
index 43bc2d8..76bdd2e 100644
--- a/zookeeper-server/src/main/java/org/apache/zookeeper/common/ZKConfig.java
+++ b/zookeeper-server/src/main/java/org/apache/zookeeper/common/ZKConfig.java
@@ -133,6 +133,8 @@ public class ZKConfig {
                 System.getProperty(x509Util.getSslTruststorePasswdProperty()));
         properties.put(x509Util.getSslTruststoreTypeProperty(),
                 System.getProperty(x509Util.getSslTruststoreTypeProperty()));
+        properties.put(x509Util.getSslContextSupplierClassProperty(),
+                
System.getProperty(x509Util.getSslContextSupplierClassProperty()));
         properties.put(x509Util.getSslHostnameVerificationEnabledProperty(),
                 
System.getProperty(x509Util.getSslHostnameVerificationEnabledProperty()));
         properties.put(x509Util.getSslCrlEnabledProperty(),
diff --git 
a/zookeeper-server/src/test/java/org/apache/zookeeper/common/X509UtilTest.java 
b/zookeeper-server/src/test/java/org/apache/zookeeper/common/X509UtilTest.java
index 2a6bb32..1fecd80 100644
--- 
a/zookeeper-server/src/test/java/org/apache/zookeeper/common/X509UtilTest.java
+++ 
b/zookeeper-server/src/test/java/org/apache/zookeeper/common/X509UtilTest.java
@@ -22,6 +22,7 @@ import java.net.InetAddress;
 import java.net.InetSocketAddress;
 import java.net.ServerSocket;
 import java.net.Socket;
+import java.security.NoSuchAlgorithmException;
 import java.security.Security;
 import java.util.Collection;
 import java.util.concurrent.Callable;
@@ -30,6 +31,7 @@ import java.util.concurrent.ExecutorService;
 import java.util.concurrent.Executors;
 import java.util.concurrent.Future;
 import java.util.concurrent.atomic.AtomicInteger;
+import java.util.function.Supplier;
 
 import javax.net.ssl.HandshakeCompletedEvent;
 import javax.net.ssl.HandshakeCompletedListener;
@@ -403,6 +405,23 @@ public class X509UtilTest extends 
BaseX509ParameterizedTestCase {
         }
     }
 
+    @Test(expected = X509Exception.SSLContextException.class)
+    public void testCreateSSLContext_invalidCustomSSLContextClass() throws 
Exception {
+        ZKConfig zkConfig = new ZKConfig();
+        ClientX509Util clientX509Util = new ClientX509Util();
+        
zkConfig.setProperty(clientX509Util.getSslContextSupplierClassProperty(), 
String.class.getCanonicalName());
+        clientX509Util.createSSLContext(zkConfig);
+    }
+
+    @Test
+    public void testCreateSSLContext_validCustomSSLContextClass() throws 
Exception {
+        ZKConfig zkConfig = new ZKConfig();
+        ClientX509Util clientX509Util = new ClientX509Util();
+        
zkConfig.setProperty(clientX509Util.getSslContextSupplierClassProperty(), 
SslContextSupplier.class.getName());
+        final SSLContext sslContext = 
clientX509Util.createSSLContext(zkConfig);
+        Assert.assertEquals(SSLContext.getDefault(), sslContext);
+    }
+
     private static void forceClose(Socket s) {
         if (s == null || s.isClosed()) {
             return;
@@ -528,4 +547,18 @@ public class X509UtilTest extends 
BaseX509ParameterizedTestCase {
         x509Util.close(); // remember to close old instance before replacing it
         x509Util = new ClientX509Util();
     }
+
+    public static class SslContextSupplier implements Supplier<SSLContext> {
+
+        @Override
+        public SSLContext get() {
+            try {
+                return SSLContext.getDefault();
+            } catch (NoSuchAlgorithmException e) {
+                throw new RuntimeException(e);
+            }
+        }
+
+    }
+
 }

Reply via email to