merlimat closed pull request #1297: Add Configuration to set tlsClientAuth
URL: https://github.com/apache/incubator-pulsar/pull/1297
 
 
   

This is a PR merged from a forked repository.
As GitHub hides the original diff on merge, it is displayed below for
the sake of provenance:

As this is a foreign pull request (from a fork), the diff is supplied
below (as it won't show otherwise due to GitHub magic):

diff --git a/conf/broker.conf b/conf/broker.conf
index 59a19d7b8..cec3c0fc9 100644
--- a/conf/broker.conf
+++ b/conf/broker.conf
@@ -207,6 +207,9 @@ tlsTrustCertsFilePath=
 # Accept untrusted TLS certificate from client
 tlsAllowInsecureConnection=false
 
+# Specify whether Client certificates are required for TLS
+# Reject the Connection if the Client Certificate is not trusted.
+tlsRequireTrustedClientCertOnConnect=false
 ### --- Authentication --- ###
 
 # Enable authentication
diff --git a/conf/discovery.conf b/conf/discovery.conf
index 49f499a08..87f887f0f 100644
--- a/conf/discovery.conf
+++ b/conf/discovery.conf
@@ -73,3 +73,7 @@ tlsCertificateFilePath=
 
 # Path for the TLS private key file
 tlsKeyFilePath=
+
+# Specify whether Client certificates are required for TLS
+# Reject the Connection if the Client Certificate is not trusted.
+tlsRequireTrustedClientCertOnConnect=false
diff --git a/conf/proxy.conf b/conf/proxy.conf
index 384cca06b..5d0647d30 100644
--- a/conf/proxy.conf
+++ b/conf/proxy.conf
@@ -85,3 +85,7 @@ tlsKeyFilePath=
 
 # Validates hostname when proxy creates tls connection with broker
 tlsHostnameVerificationEnabled=false
+
+# Specify whether Client certificates are required for TLS
+# Reject the Connection if the Client Certificate is not trusted.
+tlsRequireTrustedClientCertOnConnect=false
diff --git a/conf/websocket.conf b/conf/websocket.conf
index 0ceda6273..87accac7a 100644
--- a/conf/websocket.conf
+++ b/conf/websocket.conf
@@ -99,3 +99,7 @@ tlsKeyFilePath=
 
 # Path for the trusted TLS certificate file
 tlsTrustCertsFilePath=
+
+# Specify whether Client certificates are required for TLS
+# Reject the Connection if the Client Certificate is not trusted.
+tlsRequireTrustedClientCertOnConnect=false
diff --git 
a/pulsar-broker-common/src/main/java/org/apache/pulsar/broker/ServiceConfiguration.java
 
b/pulsar-broker-common/src/main/java/org/apache/pulsar/broker/ServiceConfiguration.java
index f851f7dd9..40ac189af 100644
--- 
a/pulsar-broker-common/src/main/java/org/apache/pulsar/broker/ServiceConfiguration.java
+++ 
b/pulsar-broker-common/src/main/java/org/apache/pulsar/broker/ServiceConfiguration.java
@@ -202,6 +202,9 @@
     // Specify the tls cipher the broker will use to negotiate during TLS 
Handshake.
     // Example:- [TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA256]
     private Set<String> tlsCiphers = Sets.newTreeSet();
+    // Specify whether Client certificates are required for TLS
+    // Reject the Connection if the Client Certificate is not trusted.
+    private boolean tlsRequireTrustedClientCertOnConnect = false;
 
     /***** --- Authentication --- ****/
     // Enable authentication
@@ -1497,7 +1500,14 @@ public void setTlsProtocols(Set<String> tlsProtocols) {
     public void setTlsCiphers(Set<String> tlsCiphers) {
         this.tlsCiphers = tlsCiphers;
     }
+    
+    public boolean getTlsRequireTrustedClientCertOnConnect() {
+        return tlsRequireTrustedClientCertOnConnect;
+    }
 
+    public void setTlsRequireTrustedClientCertOnConnect(boolean 
tlsRequireTrustedClientCertOnConnect) {
+        this.tlsRequireTrustedClientCertOnConnect = 
tlsRequireTrustedClientCertOnConnect;
+    }
     /**** --- Function ---- ****/
 
     public void setFunctionsWorkerEnabled(boolean enabled) {
diff --git 
a/pulsar-broker/src/main/java/org/apache/pulsar/broker/service/PulsarChannelInitializer.java
 
b/pulsar-broker/src/main/java/org/apache/pulsar/broker/service/PulsarChannelInitializer.java
index f77c6e6a6..8c16a5546 100644
--- 
a/pulsar-broker/src/main/java/org/apache/pulsar/broker/service/PulsarChannelInitializer.java
+++ 
b/pulsar-broker/src/main/java/org/apache/pulsar/broker/service/PulsarChannelInitializer.java
@@ -53,7 +53,8 @@ protected void initChannel(SocketChannel ch) throws Exception 
{
             SslContext sslCtx = SecurityUtility.createNettySslContextForServer(
                     serviceConfig.isTlsAllowInsecureConnection(), 
serviceConfig.getTlsTrustCertsFilePath(),
                     serviceConfig.getTlsCertificateFilePath(), 
serviceConfig.getTlsKeyFilePath(),
-                    serviceConfig.getTlsCiphers(), 
serviceConfig.getTlsProtocols());
+                    serviceConfig.getTlsCiphers(), 
serviceConfig.getTlsProtocols(),
+                    serviceConfig.getTlsRequireTrustedClientCertOnConnect());
             ch.pipeline().addLast(TLS_HANDLER, sslCtx.newHandler(ch.alloc()));
         }
 
diff --git 
a/pulsar-broker/src/main/java/org/apache/pulsar/broker/web/WebService.java 
b/pulsar-broker/src/main/java/org/apache/pulsar/broker/web/WebService.java
index 02c8b1a87..099f1a08e 100644
--- a/pulsar-broker/src/main/java/org/apache/pulsar/broker/web/WebService.java
+++ b/pulsar-broker/src/main/java/org/apache/pulsar/broker/web/WebService.java
@@ -90,24 +90,20 @@ public WebService(PulsarService pulsar) throws 
PulsarServerException {
         connectors.add(connector);
 
         if (pulsar.getConfiguration().isTlsEnabled()) {
-            SslContextFactory sslCtxFactory = new SslContextFactory();
-
             try {
-                sslCtxFactory.setSslContext(
-                        SecurityUtility.createSslContext(
-                            
pulsar.getConfiguration().isTlsAllowInsecureConnection(),
-                            
pulsar.getConfiguration().getTlsTrustCertsFilePath(),
-                            
pulsar.getConfiguration().getTlsCertificateFilePath(),
-                            pulsar.getConfiguration().getTlsKeyFilePath()));
+                SslContextFactory sslCtxFactory = 
SecurityUtility.createSslContextFactory(
+                        
pulsar.getConfiguration().isTlsAllowInsecureConnection(),
+                        pulsar.getConfiguration().getTlsTrustCertsFilePath(),
+                        pulsar.getConfiguration().getTlsCertificateFilePath(),
+                        pulsar.getConfiguration().getTlsKeyFilePath(),
+                        
pulsar.getConfiguration().getTlsRequireTrustedClientCertOnConnect());
+                ServerConnector tlsConnector = new 
PulsarServerConnector(server, 1, 1, sslCtxFactory);
+                
tlsConnector.setPort(pulsar.getConfiguration().getWebServicePortTls());
+                tlsConnector.setHost(pulsar.getBindAddress());
+                connectors.add(tlsConnector);
             } catch (GeneralSecurityException e) {
                 throw new PulsarServerException(e);
             }
-
-            sslCtxFactory.setWantClientAuth(true);
-            ServerConnector tlsConnector = new PulsarServerConnector(server, 
1, 1, sslCtxFactory);
-            
tlsConnector.setPort(pulsar.getConfiguration().getWebServicePortTls());
-            tlsConnector.setHost(pulsar.getBindAddress());
-            connectors.add(tlsConnector);
         }
 
         // Limit number of concurrent HTTP connections to avoid getting out of 
file descriptors
diff --git 
a/pulsar-broker/src/test/java/org/apache/pulsar/client/api/TlsProducerConsumerBase.java
 
b/pulsar-broker/src/test/java/org/apache/pulsar/client/api/TlsProducerConsumerBase.java
index 66b2265f2..f1e130891 100644
--- 
a/pulsar-broker/src/test/java/org/apache/pulsar/client/api/TlsProducerConsumerBase.java
+++ 
b/pulsar-broker/src/test/java/org/apache/pulsar/client/api/TlsProducerConsumerBase.java
@@ -21,11 +21,14 @@
 import static org.mockito.Mockito.spy;
 
 import java.net.URI;
+import java.util.HashMap;
+import java.util.Map;
+import java.util.Set;
 
 import org.apache.pulsar.client.admin.PulsarAdmin;
+import org.apache.pulsar.client.impl.auth.AuthenticationTls;
 import org.apache.pulsar.common.policies.data.ClusterData;
 import org.apache.pulsar.common.policies.data.PropertyAdmin;
-
 import org.slf4j.Logger;
 import org.slf4j.LoggerFactory;
 import org.testng.annotations.AfterMethod;
@@ -34,8 +37,12 @@
 import com.google.common.collect.Lists;
 import com.google.common.collect.Sets;
 
+import io.netty.handler.ssl.ClientAuth;
+
 public class TlsProducerConsumerBase extends ProducerConsumerBase {
     protected final String TLS_TRUST_CERT_FILE_PATH = 
"./src/test/resources/authentication/tls/cacert.pem";
+    protected final String TLS_CLIENT_CERT_FILE_PATH = 
"./src/test/resources/authentication/tls/client-cert.pem";
+    protected final String TLS_CLIENT_KEY_FILE_PATH = 
"./src/test/resources/authentication/tls/client-key.pem";
     protected final String TLS_SERVER_CERT_FILE_PATH = 
"./src/test/resources/authentication/tls/broker-cert.pem";
     protected final String TLS_SERVER_KEY_FILE_PATH = 
"./src/test/resources/authentication/tls/broker-key.pem";
     private final String clusterName = "use";
@@ -43,7 +50,6 @@
     @BeforeMethod
     @Override
     protected void setup() throws Exception {
-
         // TLS configuration for Broker
         internalSetUpForBroker();
 
@@ -61,19 +67,37 @@ protected void internalSetUpForBroker() throws Exception {
         conf.setTlsEnabled(true);
         conf.setTlsCertificateFilePath(TLS_SERVER_CERT_FILE_PATH);
         conf.setTlsKeyFilePath(TLS_SERVER_KEY_FILE_PATH);
+        conf.setTlsTrustCertsFilePath(TLS_TRUST_CERT_FILE_PATH);
         conf.setClusterName(clusterName);
+        conf.setTlsRequireTrustedClientCertOnConnect(true);
+        Set<String> tlsProtocols = Sets.newConcurrentHashSet();
+        tlsProtocols.add("TLSv1.2");
+        conf.setTlsProtocols(tlsProtocols);
     }
 
-    protected void internalSetUpForClient() throws Exception {
-        String lookupUrl = new URI("pulsar+ssl://localhost:" + 
BROKER_PORT_TLS).toString();
-        pulsarClient = 
PulsarClient.builder().serviceUrl(lookupUrl).tlsTrustCertsFilePath(TLS_SERVER_CERT_FILE_PATH)
-                .enableTls(true).build();
+    protected void internalSetUpForClient(boolean addCertificates, String 
lookupUrl) throws Exception {
+        ClientConfiguration clientConf = new ClientConfiguration();
+        clientConf.setTlsTrustCertsFilePath(TLS_TRUST_CERT_FILE_PATH);
+        clientConf.setUseTls(true);
+        clientConf.setTlsAllowInsecureConnection(false);
+        if (addCertificates) {
+            Map<String, String> authParams = new HashMap<>();
+            authParams.put("tlsCertFile", TLS_CLIENT_CERT_FILE_PATH);
+            authParams.put("tlsKeyFile", TLS_CLIENT_KEY_FILE_PATH);
+            clientConf.setAuthentication(AuthenticationTls.class.getName(), 
authParams);
+        }
+        pulsarClient = PulsarClient.create(lookupUrl, clientConf);
     }
 
     protected void internalSetUpForNamespace() throws Exception {
         ClientConfiguration clientConf = new ClientConfiguration();
         clientConf.setTlsTrustCertsFilePath(TLS_TRUST_CERT_FILE_PATH);
         clientConf.setUseTls(true);
+        clientConf.setTlsAllowInsecureConnection(false);
+        Map<String, String> authParams = new HashMap<>();
+        authParams.put("tlsCertFile", TLS_CLIENT_CERT_FILE_PATH);
+        authParams.put("tlsKeyFile", TLS_CLIENT_KEY_FILE_PATH);
+        clientConf.setAuthentication(AuthenticationTls.class.getName(), 
authParams);
         admin = spy(new PulsarAdmin(brokerUrlTls, clientConf));
         admin.clusters().updateCluster(clusterName, new 
ClusterData(brokerUrl.toString(), brokerUrlTls.toString(),
                 "pulsar://localhost:" + BROKER_PORT, "pulsar+ssl://localhost:" 
+ BROKER_PORT_TLS));
@@ -81,4 +105,4 @@ protected void internalSetUpForNamespace() throws Exception {
                 new PropertyAdmin(Lists.newArrayList("appid1", "appid2"), 
Sets.newHashSet("use")));
         admin.namespaces().createNamespace("my-property/use/my-ns");
     }
-}
\ No newline at end of file
+}
diff --git 
a/pulsar-broker/src/test/java/org/apache/pulsar/client/api/TlsProducerConsumerTest.java
 
b/pulsar-broker/src/test/java/org/apache/pulsar/client/api/TlsProducerConsumerTest.java
index a0d4bc275..8641ac7d8 100644
--- 
a/pulsar-broker/src/test/java/org/apache/pulsar/client/api/TlsProducerConsumerTest.java
+++ 
b/pulsar-broker/src/test/java/org/apache/pulsar/client/api/TlsProducerConsumerTest.java
@@ -42,7 +42,7 @@ public void testTlsLargeSizeMessage() throws Exception {
         final int MESSAGE_SIZE = 16 * 1024 + 1;
         log.info("-- message size --", MESSAGE_SIZE);
 
-        internalSetUpForClient();
+        internalSetUpForClient(true, "pulsar+ssl://localhost:" + 
BROKER_PORT_TLS);
         internalSetUpForNamespace();
 
         Consumer<byte[]> consumer = 
pulsarClient.newConsumer().topic("persistent://my-property/use/my-ns/my-topic1")
@@ -68,4 +68,68 @@ public void testTlsLargeSizeMessage() throws Exception {
         consumer.close();
         log.info("-- Exiting {} test --", methodName);
     }
+
+    @Test(timeOut = 30000)
+    public void testTlsClientAuthOverBinaryProtocol() throws Exception {
+        log.info("-- Starting {} test --", methodName);
+
+        final int MESSAGE_SIZE = 16 * 1024 + 1;
+        log.info("-- message size --", MESSAGE_SIZE);
+        internalSetUpForNamespace();
+
+        // Test 1 - Using TLS on binary protocol without sending certs - 
expect failure
+        internalSetUpForClient(false, "pulsar+ssl://localhost:" + 
BROKER_PORT_TLS);
+        try {
+            ConsumerConfiguration conf = new ConsumerConfiguration();
+            conf.setSubscriptionType(SubscriptionType.Exclusive);
+            Consumer consumer = 
pulsarClient.subscribe("persistent://my-property/use/my-ns/my-topic1",
+                    "my-subscriber-name", conf);
+            Assert.fail("Server should have failed the TLS handshake since 
client didn't .");
+        } catch (Exception ex) {
+            // OK
+        }
+
+        // Test 2 - Using TLS on binary protocol - sending certs
+        internalSetUpForClient(true, "pulsar+ssl://localhost:" + 
BROKER_PORT_TLS);
+        try {
+            ConsumerConfiguration conf = new ConsumerConfiguration();
+            conf.setSubscriptionType(SubscriptionType.Exclusive);
+            Consumer consumer = 
pulsarClient.subscribe("persistent://my-property/use/my-ns/my-topic1",
+                    "my-subscriber-name", conf);
+        } catch (Exception ex) {
+            Assert.fail("Should not fail since certs are sent.");
+        }
+    }
+
+    @Test(timeOut = 30000)
+    public void testTlsClientAuthOverHTTPProtocol() throws Exception {
+        log.info("-- Starting {} test --", methodName);
+
+        final int MESSAGE_SIZE = 16 * 1024 + 1;
+        log.info("-- message size --", MESSAGE_SIZE);
+        internalSetUpForNamespace();
+
+        // Test 1 - Using TLS on https without sending certs - expect failure
+        internalSetUpForClient(false, "https://localhost:"; + 
BROKER_WEBSERVICE_PORT_TLS);
+        try {
+            ConsumerConfiguration conf = new ConsumerConfiguration();
+            conf.setSubscriptionType(SubscriptionType.Exclusive);
+            Consumer consumer = 
pulsarClient.subscribe("persistent://my-property/use/my-ns/my-topic1",
+                    "my-subscriber-name", conf);
+            Assert.fail("Server should have failed the TLS handshake since 
client didn't .");
+        } catch (Exception ex) {
+            // OK
+        }
+
+        // Test 2 - Using TLS on https - sending certs
+        internalSetUpForClient(true, "https://localhost:"; + 
BROKER_WEBSERVICE_PORT_TLS);
+        try {
+            ConsumerConfiguration conf = new ConsumerConfiguration();
+            conf.setSubscriptionType(SubscriptionType.Exclusive);
+            Consumer consumer = 
pulsarClient.subscribe("persistent://my-property/use/my-ns/my-topic1",
+                    "my-subscriber-name", conf);
+        } catch (Exception ex) {
+            Assert.fail("Should not fail since certs are sent.");
+        }
+    }
 }
diff --git 
a/pulsar-broker/src/test/java/org/apache/pulsar/websocket/proxy/ProxyPublishConsumeTlsTest.java
 
b/pulsar-broker/src/test/java/org/apache/pulsar/websocket/proxy/ProxyPublishConsumeTlsTest.java
index ac79c8a00..6d486c2f4 100644
--- 
a/pulsar-broker/src/test/java/org/apache/pulsar/websocket/proxy/ProxyPublishConsumeTlsTest.java
+++ 
b/pulsar-broker/src/test/java/org/apache/pulsar/websocket/proxy/ProxyPublishConsumeTlsTest.java
@@ -24,12 +24,15 @@
 
 import java.net.URI;
 import java.security.GeneralSecurityException;
+import java.util.HashMap;
+import java.util.Map;
 import java.util.concurrent.ExecutorService;
 import java.util.concurrent.Future;
 import java.util.concurrent.TimeUnit;
 
 import org.apache.bookkeeper.test.PortManager;
 import org.apache.pulsar.client.api.TlsProducerConsumerBase;
+import org.apache.pulsar.client.impl.auth.AuthenticationTls;
 import org.apache.pulsar.common.util.SecurityUtility;
 import org.apache.pulsar.websocket.WebSocketService;
 import org.apache.pulsar.websocket.service.ProxyServer;
@@ -71,6 +74,9 @@ public void setup() throws Exception {
         config.setBrokerClientTrustCertsFilePath(TLS_TRUST_CERT_FILE_PATH);
         config.setClusterName("use");
         config.setGlobalZookeeperServers("dummy-zk-servers");
+        config.setBrokerClientAuthenticationParameters("tlsCertFile:" + 
TLS_CLIENT_CERT_FILE_PATH + ",tlsKeyFile:" + TLS_CLIENT_KEY_FILE_PATH);
+        
config.setBrokerClientAuthenticationPlugin(AuthenticationTls.class.getName());
+        String lookupUrl = new URI("pulsar://localhost:" + 
BROKER_PORT_TLS).toString();
         service = spy(new WebSocketService(config));
         
doReturn(mockZooKeeperClientFactory).when(service).getZooKeeperClientFactory();
         proxyServer = new ProxyServer(config);
diff --git a/pulsar-common/pom.xml b/pulsar-common/pom.xml
index 68dd3222d..2ef8e6485 100644
--- a/pulsar-common/pom.xml
+++ b/pulsar-common/pom.xml
@@ -86,5 +86,11 @@
       <groupId>io.netty</groupId>
       <artifactId>netty-tcnative-boringssl-static</artifactId>
     </dependency>
+
+       <dependency>
+               <groupId>org.eclipse.jetty</groupId>
+               <artifactId>jetty-server</artifactId>
+       </dependency>
+    
   </dependencies>
 </project>
diff --git 
a/pulsar-common/src/main/java/org/apache/pulsar/common/util/SecurityUtility.java
 
b/pulsar-common/src/main/java/org/apache/pulsar/common/util/SecurityUtility.java
index 26f97bbcb..01816277c 100644
--- 
a/pulsar-common/src/main/java/org/apache/pulsar/common/util/SecurityUtility.java
+++ 
b/pulsar-common/src/main/java/org/apache/pulsar/common/util/SecurityUtility.java
@@ -49,6 +49,8 @@
 import javax.net.ssl.TrustManager;
 import javax.net.ssl.TrustManagerFactory;
 
+import org.eclipse.jetty.util.ssl.SslContextFactory;
+
 import io.netty.handler.ssl.ClientAuth;
 import io.netty.handler.ssl.SslContext;
 import io.netty.handler.ssl.SslContextBuilder;
@@ -93,7 +95,8 @@ public static SslContext 
createNettySslContextForClient(boolean allowInsecureCon
     }
 
     public static SslContext createNettySslContextForServer(boolean 
allowInsecureConnection, String trustCertsFilePath,
-            String certFilePath, String keyFilePath, Set<String> ciphers, 
Set<String> protocols)
+            String certFilePath, String keyFilePath, Set<String> ciphers, 
Set<String> protocols,
+            boolean requireTrustedClientCertOnConnect)
             throws GeneralSecurityException, SSLException, 
FileNotFoundException, IOException {
         X509Certificate[] certificates = 
loadCertificatesFromPemFile(certFilePath);
         PrivateKey privateKey = loadPrivateKeyFromPemFile(keyFilePath);
@@ -103,7 +106,7 @@ public static SslContext 
createNettySslContextForServer(boolean allowInsecureCon
         setupProtocols(builder, protocols);
         setupTrustCerts(builder, allowInsecureConnection, trustCertsFilePath);
         setupKeyManager(builder, privateKey, certificates);
-        setupClientAuthentication(builder);
+        setupClientAuthentication(builder, requireTrustedClientCertOnConnect);
         return builder.build();
     }
 
@@ -236,7 +239,27 @@ private static void setupProtocols(SslContextBuilder 
builder, Set<String> protoc
         }
     }
 
-    private static void setupClientAuthentication(SslContextBuilder builder) {
-        builder.clientAuth(ClientAuth.OPTIONAL);
+    private static void setupClientAuthentication(SslContextBuilder builder, 
boolean requireTrustedClientCertOnConnect) {
+        if (requireTrustedClientCertOnConnect) {
+            builder.clientAuth(ClientAuth.REQUIRE);
+        } else {
+            builder.clientAuth(ClientAuth.OPTIONAL);
+        }
+    }
+
+    public static SslContextFactory createSslContextFactory(boolean 
tlsAllowInsecureConnection,
+            String tlsTrustCertsFilePath, String tlsCertificateFilePath, 
String tlsKeyFilePath,
+            boolean tlsRequireTrustedClientCertOnConnect) throws 
GeneralSecurityException {
+        SslContextFactory sslCtxFactory = new SslContextFactory();
+        SSLContext sslCtx = createSslContext(tlsAllowInsecureConnection, 
tlsTrustCertsFilePath, tlsCertificateFilePath,
+                tlsKeyFilePath);
+        sslCtxFactory.setSslContext(sslCtx);
+        if (tlsRequireTrustedClientCertOnConnect) {
+            sslCtxFactory.setNeedClientAuth(true);
+        } else {
+            sslCtxFactory.setWantClientAuth(true);
+        }
+        sslCtxFactory.setTrustAll(true);
+        return sslCtxFactory;
     }
 }
diff --git 
a/pulsar-discovery-service/src/main/java/org/apache/pulsar/discovery/service/ServiceChannelInitializer.java
 
b/pulsar-discovery-service/src/main/java/org/apache/pulsar/discovery/service/ServiceChannelInitializer.java
index 2cfe128e3..3f230d410 100644
--- 
a/pulsar-discovery-service/src/main/java/org/apache/pulsar/discovery/service/ServiceChannelInitializer.java
+++ 
b/pulsar-discovery-service/src/main/java/org/apache/pulsar/discovery/service/ServiceChannelInitializer.java
@@ -52,7 +52,8 @@ protected void initChannel(SocketChannel ch) throws Exception 
{
             SslContext sslCtx = SecurityUtility.createNettySslContextForServer(
                     serviceConfig.isTlsAllowInsecureConnection(), 
serviceConfig.getTlsTrustCertsFilePath(),
                     serviceConfig.getTlsCertificateFilePath(), 
serviceConfig.getTlsKeyFilePath(),
-                    serviceConfig.getTlsCiphers(), 
serviceConfig.getTlsProtocols());
+                    serviceConfig.getTlsCiphers(), 
serviceConfig.getTlsProtocols(),
+                    serviceConfig.getTlsRequireTrustedClientCertOnConnect());
             ch.pipeline().addLast(TLS_HANDLER, sslCtx.newHandler(ch.alloc()));
         }
         ch.pipeline().addLast("frameDecoder", new 
LengthFieldBasedFrameDecoder(PulsarDecoder.MaxFrameSize, 0, 4, 0, 4));
diff --git 
a/pulsar-discovery-service/src/main/java/org/apache/pulsar/discovery/service/server/ServerManager.java
 
b/pulsar-discovery-service/src/main/java/org/apache/pulsar/discovery/service/server/ServerManager.java
index d8be50749..f0d911f6d 100644
--- 
a/pulsar-discovery-service/src/main/java/org/apache/pulsar/discovery/service/server/ServerManager.java
+++ 
b/pulsar-discovery-service/src/main/java/org/apache/pulsar/discovery/service/server/ServerManager.java
@@ -72,19 +72,19 @@ public ServerManager(ServiceConfig config) {
         connectors.add(connector);
 
         if (config.isTlsEnabled()) {
-            SslContextFactory sslCtxFactory = new SslContextFactory();
             try {
-                SSLContext sslCtx = 
SecurityUtility.createSslContext(config.isTlsAllowInsecureConnection(), 
config.getTlsTrustCertsFilePath(), config.getTlsCertificateFilePath(),
-                        config.getTlsKeyFilePath());
-                sslCtxFactory.setSslContext(sslCtx);
+                SslContextFactory sslCtxFactory = 
SecurityUtility.createSslContextFactory(
+                        config.isTlsAllowInsecureConnection(),
+                        config.getTlsTrustCertsFilePath(),
+                        config.getTlsCertificateFilePath(),
+                        config.getTlsKeyFilePath(), 
+                        config.getTlsRequireTrustedClientCertOnConnect());
+                ServerConnector tlsConnector = new ServerConnector(server, 1, 
1, sslCtxFactory);
+                tlsConnector.setPort(config.getWebServicePortTls());
+                connectors.add(tlsConnector);
             } catch (GeneralSecurityException e) {
                 throw new RestException(e);
-            }
-
-            sslCtxFactory.setWantClientAuth(true);
-            ServerConnector tlsConnector = new ServerConnector(server, 1, 1, 
sslCtxFactory);
-            tlsConnector.setPort(config.getWebServicePortTls());
-            connectors.add(tlsConnector);
+            }            
         }
 
         // Limit number of concurrent HTTP connections to avoid getting out of 
file descriptors
diff --git 
a/pulsar-discovery-service/src/main/java/org/apache/pulsar/discovery/service/server/ServiceConfig.java
 
b/pulsar-discovery-service/src/main/java/org/apache/pulsar/discovery/service/server/ServiceConfig.java
index 8cf56d11a..c1d59ee4b 100644
--- 
a/pulsar-discovery-service/src/main/java/org/apache/pulsar/discovery/service/server/ServiceConfig.java
+++ 
b/pulsar-discovery-service/src/main/java/org/apache/pulsar/discovery/service/server/ServiceConfig.java
@@ -88,6 +88,9 @@
     // Specify the tls cipher the broker will use to negotiate during TLS 
Handshake.
     // Example:- [TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA256]
     private Set<String> tlsCiphers = Sets.newTreeSet();
+    // Specify whether Client certificates are required for TLS
+    // Reject the Connection if the Client Certificate is not trusted.
+    private boolean tlsRequireTrustedClientCertOnConnect = false;
     
     private Properties properties = new Properties();
 
@@ -266,4 +269,12 @@ public void setTlsProtocols(Set<String> tlsProtocols) {
     public void setTlsCiphers(Set<String> tlsCiphers) {
         this.tlsCiphers = tlsCiphers;
     }
+    
+    public boolean getTlsRequireTrustedClientCertOnConnect() {
+        return tlsRequireTrustedClientCertOnConnect;
+    }
+
+    public void setTlsRequireTrustedClientCertOnConnect(boolean 
tlsRequireTrustedClientCertOnConnect) {
+        this.tlsRequireTrustedClientCertOnConnect = 
tlsRequireTrustedClientCertOnConnect;
+    }
 }
diff --git 
a/pulsar-proxy/src/main/java/org/apache/pulsar/proxy/server/ProxyConfiguration.java
 
b/pulsar-proxy/src/main/java/org/apache/pulsar/proxy/server/ProxyConfiguration.java
index 69329efc0..a8d3855cb 100644
--- 
a/pulsar-proxy/src/main/java/org/apache/pulsar/proxy/server/ProxyConfiguration.java
+++ 
b/pulsar-proxy/src/main/java/org/apache/pulsar/proxy/server/ProxyConfiguration.java
@@ -98,7 +98,10 @@
     // Specify the tls cipher the broker will use to negotiate during TLS 
Handshake.
     // Example:- [TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA256]
     private Set<String> tlsCiphers = Sets.newTreeSet();
-
+    // Specify whether Client certificates are required for TLS
+    // Reject the Connection if the Client Certificate is not trusted.
+    private boolean tlsRequireTrustedClientCertOnConnect = false;
+    
     private Properties properties = new Properties();
 
     public boolean forwardAuthorizationCredentials() {
@@ -332,4 +335,12 @@ public void setTlsProtocols(Set<String> tlsProtocols) {
     public void setTlsCiphers(Set<String> tlsCiphers) {
         this.tlsCiphers = tlsCiphers;
     }
+    
+    public boolean getTlsRequireTrustedClientCertOnConnect() {
+        return tlsRequireTrustedClientCertOnConnect;
+    }
+
+    public void setTlsRequireTrustedClientCertOnConnect(boolean 
tlsRequireTrustedClientCertOnConnect) {
+        this.tlsRequireTrustedClientCertOnConnect = 
tlsRequireTrustedClientCertOnConnect;
+    }
 }
diff --git 
a/pulsar-proxy/src/main/java/org/apache/pulsar/proxy/server/ServiceChannelInitializer.java
 
b/pulsar-proxy/src/main/java/org/apache/pulsar/proxy/server/ServiceChannelInitializer.java
index 19abe8301..b0055e1be 100644
--- 
a/pulsar-proxy/src/main/java/org/apache/pulsar/proxy/server/ServiceChannelInitializer.java
+++ 
b/pulsar-proxy/src/main/java/org/apache/pulsar/proxy/server/ServiceChannelInitializer.java
@@ -49,7 +49,8 @@ protected void initChannel(SocketChannel ch) throws Exception 
{
         if (enableTLS) {
             SslContext sslCtx = 
SecurityUtility.createNettySslContextForServer(true /* to allow 
InsecureConnection */,
                     serviceConfig.getTlsTrustCertsFilePath(), 
serviceConfig.getTlsCertificateFilePath(),
-                    serviceConfig.getTlsKeyFilePath(), 
serviceConfig.getTlsCiphers(), serviceConfig.getTlsProtocols());
+                    serviceConfig.getTlsKeyFilePath(), 
serviceConfig.getTlsCiphers(), serviceConfig.getTlsProtocols(),
+                    serviceConfig.getTlsRequireTrustedClientCertOnConnect());
             ch.pipeline().addLast(TLS_HANDLER, sslCtx.newHandler(ch.alloc()));
         }
 
diff --git 
a/pulsar-proxy/src/main/java/org/apache/pulsar/proxy/server/WebServer.java 
b/pulsar-proxy/src/main/java/org/apache/pulsar/proxy/server/WebServer.java
index edc718828..5a2bddaac 100644
--- a/pulsar-proxy/src/main/java/org/apache/pulsar/proxy/server/WebServer.java
+++ b/pulsar-proxy/src/main/java/org/apache/pulsar/proxy/server/WebServer.java
@@ -73,19 +73,19 @@ public WebServer(ProxyConfiguration config) {
         connectors.add(connector);
 
         if (config.isTlsEnabledInProxy()) {
-            SslContextFactory sslCtxFactory = new SslContextFactory();
             try {
-                SSLContext sslCtx = SecurityUtility.createSslContext(false, 
null, config.getTlsCertificateFilePath(),
-                        config.getTlsKeyFilePath());
-                sslCtxFactory.setSslContext(sslCtx);
+                SslContextFactory sslCtxFactory = 
SecurityUtility.createSslContextFactory(
+                        config.isTlsAllowInsecureConnection(),
+                        config.getTlsTrustCertsFilePath(),
+                        config.getTlsCertificateFilePath(),
+                        config.getTlsKeyFilePath(), 
+                        config.getTlsRequireTrustedClientCertOnConnect());
+                ServerConnector tlsConnector = new ServerConnector(server, 1, 
1, sslCtxFactory);
+                tlsConnector.setPort(config.getWebServicePortTls());
+                connectors.add(tlsConnector);
             } catch (GeneralSecurityException e) {
                 throw new RuntimeException(e);
             }
-
-            sslCtxFactory.setWantClientAuth(false);
-            ServerConnector tlsConnector = new ServerConnector(server, 1, 1, 
sslCtxFactory);
-            tlsConnector.setPort(config.getWebServicePortTls());
-            connectors.add(tlsConnector);
         }
 
         // Limit number of concurrent HTTP connections to avoid getting out of 
file descriptors
diff --git 
a/pulsar-websocket/src/main/java/org/apache/pulsar/websocket/service/ProxyServer.java
 
b/pulsar-websocket/src/main/java/org/apache/pulsar/websocket/service/ProxyServer.java
index 77b24c143..2829fdc2b 100644
--- 
a/pulsar-websocket/src/main/java/org/apache/pulsar/websocket/service/ProxyServer.java
+++ 
b/pulsar-websocket/src/main/java/org/apache/pulsar/websocket/service/ProxyServer.java
@@ -79,20 +79,20 @@ public ProxyServer(WebSocketProxyConfiguration config)
 
         // TLS enabled connector
         if (config.isTlsEnabled()) {
-            SslContextFactory sslCtxFactory = new SslContextFactory(true);
             try {
-                SSLContext sslCtx = SecurityUtility.createSslContext(false, 
config.getTlsTrustCertsFilePath(), config.getTlsCertificateFilePath(),
-                        config.getTlsKeyFilePath());
-                sslCtxFactory.setSslContext(sslCtx);
-
+                SslContextFactory sslCtxFactory = 
SecurityUtility.createSslContextFactory(
+                        config.isTlsAllowInsecureConnection(),
+                        config.getTlsTrustCertsFilePath(),
+                        config.getTlsCertificateFilePath(),
+                        config.getTlsKeyFilePath(),
+                        config.getTlsRequireTrustedClientCertOnConnect());
+                ServerConnector tlsConnector = new ServerConnector(server, -1, 
-1, sslCtxFactory);
+                tlsConnector.setPort(config.getWebServicePortTls());
+                connectors.add(tlsConnector);
             } catch (GeneralSecurityException e) {
                 throw new PulsarServerException(e);
             }
 
-            sslCtxFactory.setWantClientAuth(true);
-            ServerConnector tlsConnector = new ServerConnector(server, -1, -1, 
sslCtxFactory);
-            tlsConnector.setPort(config.getWebServicePortTls());
-            connectors.add(tlsConnector);
         }
 
         // Limit number of concurrent HTTP connections to avoid getting out of
diff --git 
a/pulsar-websocket/src/main/java/org/apache/pulsar/websocket/service/WebSocketProxyConfiguration.java
 
b/pulsar-websocket/src/main/java/org/apache/pulsar/websocket/service/WebSocketProxyConfiguration.java
index c3040df66..0126d49c6 100644
--- 
a/pulsar-websocket/src/main/java/org/apache/pulsar/websocket/service/WebSocketProxyConfiguration.java
+++ 
b/pulsar-websocket/src/main/java/org/apache/pulsar/websocket/service/WebSocketProxyConfiguration.java
@@ -105,7 +105,10 @@
     private String tlsTrustCertsFilePath = "";
     // Accept untrusted TLS certificate from client
     private boolean tlsAllowInsecureConnection = false;
-
+    // Specify whether Client certificates are required for TLS
+    // Reject the Connection if the Client Certificate is not trusted.
+    private boolean tlsRequireTrustedClientCertOnConnect = false;
+    
     private Properties properties = new Properties();
 
     public String getClusterName() {
@@ -340,4 +343,11 @@ public void setProperties(Properties properties) {
         this.properties = properties;
     }
 
+    public boolean getTlsRequireTrustedClientCertOnConnect() {
+        return tlsRequireTrustedClientCertOnConnect;
+    }
+
+    public void setTlsRequireTrustedClientCertOnConnect(boolean 
tlsRequireTrustedClientCertOnConnect) {
+        this.tlsRequireTrustedClientCertOnConnect = 
tlsRequireTrustedClientCertOnConnect;
+    }
 }


 

----------------------------------------------------------------
This is an automated message from the Apache Git Service.
To respond to the message, please log on GitHub and use the
URL above to go to the specific comment.
 
For queries about this service, please contact Infrastructure at:
us...@infra.apache.org


With regards,
Apache Git Services

Reply via email to