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

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


The following commit(s) were added to refs/heads/master by this push:
     new fb6851788 KNOX-2864 - TLS cipher suites and protocols are configured 
for CM service discovery (#717)
fb6851788 is described below

commit fb685178890a5db337e7e69392ab4efc04ecf770
Author: Sandor Molnar <[email protected]>
AuthorDate: Wed Jan 25 17:37:17 2023 +0100

    KNOX-2864 - TLS cipher suites and protocols are configured for CM service 
discovery (#717)
    
    In addition to the CM extension, we now have the ability to indicate TLS 
protocols we'd like to include (not only the ones to exclude).
---
 .../topology/discovery/ambari/RESTInvoker.java     | 16 ++++--
 .../cm/ClouderaManagerServiceDiscovery.java        | 22 ++++++--
 .../topology/discovery/cm/DiscoveryApiClient.java  | 59 +++++++++++++++-------
 ...ClouderaManagerClusterConfigurationMonitor.java |  2 +-
 .../cm/monitor/PollingConfigurationAnalyzer.java   | 31 +++++++++---
 .../cm/ClouderaManagerServiceDiscoveryTest.java    | 15 +++---
 .../monitor/PollingConfigurationAnalyzerTest.java  | 23 ++++++---
 .../gateway/config/impl/GatewayConfigImpl.java     |  7 +++
 .../services/security/impl/JettySSLService.java    |  7 +++
 .../security/impl/JettySSLServiceTest.java         |  1 +
 .../org/apache/knox/gateway/GatewayTestConfig.java |  5 ++
 .../apache/knox/gateway/config/GatewayConfig.java  |  2 +
 .../gateway/util/TruststoreSSLContextUtils.java    | 32 +++++-------
 13 files changed, 156 insertions(+), 66 deletions(-)

diff --git 
a/gateway-discovery-ambari/src/main/java/org/apache/knox/gateway/topology/discovery/ambari/RESTInvoker.java
 
b/gateway-discovery-ambari/src/main/java/org/apache/knox/gateway/topology/discovery/ambari/RESTInvoker.java
index 776b5f5e7..8d817a880 100644
--- 
a/gateway-discovery-ambari/src/main/java/org/apache/knox/gateway/topology/discovery/ambari/RESTInvoker.java
+++ 
b/gateway-discovery-ambari/src/main/java/org/apache/knox/gateway/topology/discovery/ambari/RESTInvoker.java
@@ -30,14 +30,17 @@ import org.apache.http.message.BasicHeader;
 import org.apache.http.util.EntityUtils;
 import org.apache.knox.gateway.config.ConfigurationException;
 import org.apache.knox.gateway.config.GatewayConfig;
+import org.apache.knox.gateway.i18n.GatewaySpiMessages;
 import org.apache.knox.gateway.i18n.messages.MessagesFactory;
 import org.apache.knox.gateway.services.security.AliasService;
 import org.apache.knox.gateway.services.security.AliasServiceException;
 import org.apache.knox.gateway.services.security.KeystoreService;
+import org.apache.knox.gateway.services.security.KeystoreServiceException;
 import org.apache.knox.gateway.util.TruststoreSSLContextUtils;
 
 import java.io.IOException;
 import java.nio.charset.StandardCharsets;
+import java.security.KeyStore;
 import java.util.Base64;
 
 class RESTInvoker {
@@ -46,12 +49,13 @@ class RESTInvoker {
     private static final String DEFAULT_PWD_ALIAS  = 
"ambari.discovery.password";
 
     private static final AmbariServiceDiscoveryMessages log = 
MessagesFactory.get(AmbariServiceDiscoveryMessages.class);
+    private static final GatewaySpiMessages LOGGER = 
MessagesFactory.get(GatewaySpiMessages.class);
 
     private static final int DEFAULT_TIMEOUT = 10000;
 
     private AliasService aliasService;
 
-    private KeystoreService keystoreService;
+    private KeyStore truststore;
 
     private CloseableHttpClient httpClient;
 
@@ -61,7 +65,13 @@ class RESTInvoker {
 
     RESTInvoker(GatewayConfig config, AliasService aliasService, 
KeystoreService keystoreService) {
         this.aliasService = aliasService;
-        this.keystoreService = keystoreService;
+        if (keystoreService != null) {
+          try {
+            truststore = keystoreService.getTruststoreForHttpClient();
+          } catch (KeystoreServiceException e) {
+            LOGGER.failedToLoadTruststore(e.getMessage(), e);
+          }
+        }
 
         // Initialize the HTTP client
         this.httpClient = getHttpClient(config);
@@ -69,7 +79,7 @@ class RESTInvoker {
 
     private CloseableHttpClient getHttpClient(GatewayConfig config) {
       return HttpClientBuilder.create()
-                 
.setSSLContext(TruststoreSSLContextUtils.getTruststoreSSLContext(keystoreService))
+                 
.setSSLContext(TruststoreSSLContextUtils.getTruststoreSSLContext(truststore))
                  .setDefaultRequestConfig(getRequestConfig(config))
                  .build();
     }
diff --git 
a/gateway-discovery-cm/src/main/java/org/apache/knox/gateway/topology/discovery/cm/ClouderaManagerServiceDiscovery.java
 
b/gateway-discovery-cm/src/main/java/org/apache/knox/gateway/topology/discovery/cm/ClouderaManagerServiceDiscovery.java
index dcf2c41fc..4bca3fd0a 100644
--- 
a/gateway-discovery-cm/src/main/java/org/apache/knox/gateway/topology/discovery/cm/ClouderaManagerServiceDiscovery.java
+++ 
b/gateway-discovery-cm/src/main/java/org/apache/knox/gateway/topology/discovery/cm/ClouderaManagerServiceDiscovery.java
@@ -27,11 +27,13 @@ import com.cloudera.api.swagger.model.ApiServiceConfig;
 import com.cloudera.api.swagger.model.ApiServiceList;
 import org.apache.knox.gateway.GatewayServer;
 import org.apache.knox.gateway.config.GatewayConfig;
+import org.apache.knox.gateway.i18n.GatewaySpiMessages;
 import org.apache.knox.gateway.i18n.messages.MessagesFactory;
 import org.apache.knox.gateway.services.GatewayServices;
 import org.apache.knox.gateway.services.ServiceType;
 import org.apache.knox.gateway.services.security.AliasService;
 import org.apache.knox.gateway.services.security.KeystoreService;
+import org.apache.knox.gateway.services.security.KeystoreServiceException;
 import org.apache.knox.gateway.topology.ClusterConfigurationMonitorService;
 import org.apache.knox.gateway.topology.discovery.ClusterConfigurationMonitor;
 import org.apache.knox.gateway.topology.discovery.ServiceDiscovery;
@@ -39,6 +41,7 @@ import 
org.apache.knox.gateway.topology.discovery.ServiceDiscoveryConfig;
 import 
org.apache.knox.gateway.topology.discovery.cm.monitor.ClouderaManagerClusterConfigurationMonitor;
 
 import java.net.ConnectException;
+import java.security.KeyStore;
 import java.util.ArrayList;
 import java.util.Collection;
 import java.util.Collections;
@@ -62,6 +65,8 @@ public class ClouderaManagerServiceDiscovery implements 
ServiceDiscovery, Cluste
   private static final ClouderaManagerServiceDiscoveryMessages log =
                                         
MessagesFactory.get(ClouderaManagerServiceDiscoveryMessages.class);
 
+  private static final GatewaySpiMessages LOGGER = 
MessagesFactory.get(GatewaySpiMessages.class);
+
   static final String API_PATH = "api/v32";
 
   private static final String VIEW_SUMMARY     = "summary";
@@ -86,7 +91,7 @@ public class ClouderaManagerServiceDiscovery implements 
ServiceDiscovery, Cluste
   private boolean debug;
 
   private AliasService aliasService;
-  private KeystoreService keystoreService;
+  private KeyStore truststore;
 
   private ClouderaManagerClusterConfigurationMonitor configChangeMonitor;
 
@@ -104,7 +109,14 @@ public class ClouderaManagerServiceDiscovery implements 
ServiceDiscovery, Cluste
     GatewayServices gwServices = GatewayServer.getGatewayServices();
     if (gwServices != null) {
       this.aliasService = gwServices.getService(ServiceType.ALIAS_SERVICE);
-      this.keystoreService = 
gwServices.getService(ServiceType.KEYSTORE_SERVICE);
+      KeystoreService keystoreService = 
gwServices.getService(ServiceType.KEYSTORE_SERVICE);
+      if (keystoreService != null) {
+        try {
+          truststore = keystoreService.getTruststoreForHttpClient();
+        } catch (KeystoreServiceException e) {
+          LOGGER.failedToLoadTruststore(e.getMessage(), e);
+        }
+      }
     }
     this.debug = debug;
     this.configChangeMonitor = getConfigurationChangeMonitor();
@@ -135,14 +147,14 @@ public class ClouderaManagerServiceDiscovery implements 
ServiceDiscovery, Cluste
     return TYPE;
   }
 
-  private DiscoveryApiClient getClient(ServiceDiscoveryConfig discoveryConfig) 
{
+  private DiscoveryApiClient getClient(GatewayConfig gatewayConfig, 
ServiceDiscoveryConfig discoveryConfig) {
     String discoveryAddress = discoveryConfig.getAddress();
     if (discoveryAddress == null || discoveryAddress.isEmpty()) {
       log.missingDiscoveryAddress();
       throw new IllegalArgumentException("Missing or invalid discovery 
address.");
     }
 
-    DiscoveryApiClient client = new DiscoveryApiClient(discoveryConfig, 
aliasService, keystoreService);
+    DiscoveryApiClient client = new DiscoveryApiClient(gatewayConfig, 
discoveryConfig, aliasService, truststore);
     client.setDebugging(debug);
     return client;
   }
@@ -183,7 +195,7 @@ public class ClouderaManagerServiceDiscovery implements 
ServiceDiscovery, Cluste
                                          ServiceDiscoveryConfig 
discoveryConfig,
                                          String                 clusterName,
                                          Collection<String>     
includedServices) {
-    return discover(gatewayConfig, discoveryConfig, clusterName, 
includedServices, getClient(discoveryConfig));
+    return discover(gatewayConfig, discoveryConfig, clusterName, 
includedServices, getClient(gatewayConfig, discoveryConfig));
   }
 
   protected ClouderaManagerCluster discover(GatewayConfig          
gatewayConfig,
diff --git 
a/gateway-discovery-cm/src/main/java/org/apache/knox/gateway/topology/discovery/cm/DiscoveryApiClient.java
 
b/gateway-discovery-cm/src/main/java/org/apache/knox/gateway/topology/discovery/cm/DiscoveryApiClient.java
index 1f69a5c76..b1c9eacf1 100644
--- 
a/gateway-discovery-cm/src/main/java/org/apache/knox/gateway/topology/discovery/cm/DiscoveryApiClient.java
+++ 
b/gateway-discovery-cm/src/main/java/org/apache/knox/gateway/topology/discovery/cm/DiscoveryApiClient.java
@@ -16,28 +16,33 @@
  */
 package org.apache.knox.gateway.topology.discovery.cm;
 
-import com.cloudera.api.swagger.client.ApiClient;
-import com.cloudera.api.swagger.client.Pair;
-import com.cloudera.api.swagger.client.auth.Authentication;
-import com.cloudera.api.swagger.client.auth.HttpBasicAuth;
+import static 
org.apache.knox.gateway.topology.discovery.cm.ClouderaManagerServiceDiscovery.API_PATH;
+import static 
org.apache.knox.gateway.topology.discovery.cm.ClouderaManagerServiceDiscovery.DEFAULT_PWD_ALIAS;
+import static 
org.apache.knox.gateway.topology.discovery.cm.ClouderaManagerServiceDiscovery.DEFAULT_USER_ALIAS;
+
+import java.security.KeyStore;
+import java.util.Arrays;
+import java.util.List;
+import java.util.Set;
+
+import javax.net.ssl.SSLContext;
+import javax.security.auth.Subject;
+
 import org.apache.knox.gateway.config.ConfigurationException;
 import org.apache.knox.gateway.config.GatewayConfig;
 import org.apache.knox.gateway.i18n.messages.MessagesFactory;
 import org.apache.knox.gateway.services.security.AliasService;
 import org.apache.knox.gateway.services.security.AliasServiceException;
-import org.apache.knox.gateway.services.security.KeystoreService;
 import org.apache.knox.gateway.topology.discovery.ServiceDiscoveryConfig;
 import org.apache.knox.gateway.topology.discovery.cm.auth.AuthUtils;
 import 
org.apache.knox.gateway.topology.discovery.cm.auth.SpnegoAuthInterceptor;
 import org.apache.knox.gateway.util.TruststoreSSLContextUtils;
 
-import javax.net.ssl.SSLContext;
-import javax.security.auth.Subject;
-import java.util.List;
-
-import static 
org.apache.knox.gateway.topology.discovery.cm.ClouderaManagerServiceDiscovery.API_PATH;
-import static 
org.apache.knox.gateway.topology.discovery.cm.ClouderaManagerServiceDiscovery.DEFAULT_USER_ALIAS;
-import static 
org.apache.knox.gateway.topology.discovery.cm.ClouderaManagerServiceDiscovery.DEFAULT_PWD_ALIAS;
+import com.cloudera.api.swagger.client.ApiClient;
+import com.cloudera.api.swagger.client.Pair;
+import com.cloudera.api.swagger.client.auth.Authentication;
+import com.cloudera.api.swagger.client.auth.HttpBasicAuth;
+import com.squareup.okhttp.ConnectionSpec;
 
 /**
  * Cloudera Manager ApiClient extension for service discovery.
@@ -51,10 +56,10 @@ public class DiscoveryApiClient extends ApiClient {
 
   private ServiceDiscoveryConfig config;
 
-  public DiscoveryApiClient(ServiceDiscoveryConfig discoveryConfig, 
AliasService aliasService,
-                            KeystoreService keystoreService) {
+  public DiscoveryApiClient(GatewayConfig gatewayConfig, 
ServiceDiscoveryConfig discoveryConfig, AliasService aliasService,
+      KeyStore trustStore) {
     this.config = discoveryConfig;
-    configure(aliasService, keystoreService);
+    configure(gatewayConfig, aliasService, trustStore);
   }
 
   ServiceDiscoveryConfig getConfig() {
@@ -65,7 +70,7 @@ public class DiscoveryApiClient extends ApiClient {
     return isKerberos;
   }
 
-  private void configure(AliasService aliasService, KeystoreService 
keystoreService) {
+  private void configure(GatewayConfig gatewayConfig, AliasService 
aliasService, KeyStore trustStore) {
     String apiAddress = config.getAddress();
     apiAddress += (apiAddress.endsWith("/") ? API_PATH : "/" + API_PATH);
 
@@ -130,7 +135,7 @@ public class DiscoveryApiClient extends ApiClient {
       }
     }
 
-    configureTruststore(keystoreService);
+    configureSsl(gatewayConfig, trustStore);
   }
 
   @Override
@@ -157,12 +162,28 @@ public class DiscoveryApiClient extends ApiClient {
     return username;
   }
 
-  private void configureTruststore(KeystoreService keystoreService) {
-    SSLContext truststoreSSLContext = 
TruststoreSSLContextUtils.getTruststoreSSLContext(keystoreService);
+  private void configureSsl(GatewayConfig gatewayConfig, KeyStore trustStore) {
+    final SSLContext truststoreSSLContext = 
TruststoreSSLContextUtils.getTruststoreSSLContext(trustStore);
+
     if (truststoreSSLContext != null) {
+      final ConnectionSpec.Builder connectionSpecBuilder = new 
ConnectionSpec.Builder(ConnectionSpec.MODERN_TLS);
+      final List<String> includedSslCiphers = 
gatewayConfig.getIncludedSSLCiphers();
+      if (includedSslCiphers == null || includedSslCiphers.isEmpty()) {
+        
connectionSpecBuilder.cipherSuites(truststoreSSLContext.getSupportedSSLParameters().getCipherSuites());
+      } else {
+        connectionSpecBuilder.cipherSuites(includedSslCiphers.toArray(new 
String[0]));
+      }
+      final Set<String> includedSslProtocols = 
gatewayConfig.getIncludedSSLProtocols();
+      if (includedSslProtocols.isEmpty()) {
+        
connectionSpecBuilder.tlsVersions(truststoreSSLContext.getSupportedSSLParameters().getProtocols());
+      } else {
+        connectionSpecBuilder.tlsVersions(includedSslProtocols.toArray(new 
String[0]));
+      }
+      
getHttpClient().setConnectionSpecs(Arrays.asList(connectionSpecBuilder.build()));
       
getHttpClient().setSslSocketFactory(truststoreSSLContext.getSocketFactory());
     } else {
       log.failedToConfigureTruststore();
     }
   }
+
 }
diff --git 
a/gateway-discovery-cm/src/main/java/org/apache/knox/gateway/topology/discovery/cm/monitor/ClouderaManagerClusterConfigurationMonitor.java
 
b/gateway-discovery-cm/src/main/java/org/apache/knox/gateway/topology/discovery/cm/monitor/ClouderaManagerClusterConfigurationMonitor.java
index 0d2175193..99aa23066 100644
--- 
a/gateway-discovery-cm/src/main/java/org/apache/knox/gateway/topology/discovery/cm/monitor/ClouderaManagerClusterConfigurationMonitor.java
+++ 
b/gateway-discovery-cm/src/main/java/org/apache/knox/gateway/topology/discovery/cm/monitor/ClouderaManagerClusterConfigurationMonitor.java
@@ -87,7 +87,7 @@ public class ClouderaManagerClusterConfigurationMonitor 
implements ClusterConfig
     this.executorService = Executors.newSingleThreadExecutor(tf);
 
     // Initialize the internal monitor
-    internalMonitor = new PollingConfigurationAnalyzer(configCache, 
aliasService, keystoreService, this);
+    internalMonitor = new PollingConfigurationAnalyzer(config, configCache, 
aliasService, keystoreService, this);
 
     // Override the default polling interval if it has been configured
     // (org.apache.knox.gateway.topology.discovery.cm.monitor.interval)
diff --git 
a/gateway-discovery-cm/src/main/java/org/apache/knox/gateway/topology/discovery/cm/monitor/PollingConfigurationAnalyzer.java
 
b/gateway-discovery-cm/src/main/java/org/apache/knox/gateway/topology/discovery/cm/monitor/PollingConfigurationAnalyzer.java
index 212fde6ef..7460ea6e9 100644
--- 
a/gateway-discovery-cm/src/main/java/org/apache/knox/gateway/topology/discovery/cm/monitor/PollingConfigurationAnalyzer.java
+++ 
b/gateway-discovery-cm/src/main/java/org/apache/knox/gateway/topology/discovery/cm/monitor/PollingConfigurationAnalyzer.java
@@ -33,11 +33,14 @@ import com.github.benmanes.caffeine.cache.Cache;
 import com.github.benmanes.caffeine.cache.Caffeine;
 
 import org.apache.knox.gateway.GatewayServer;
+import org.apache.knox.gateway.config.GatewayConfig;
+import org.apache.knox.gateway.i18n.GatewaySpiMessages;
 import org.apache.knox.gateway.i18n.messages.MessagesFactory;
 import org.apache.knox.gateway.services.GatewayServices;
 import org.apache.knox.gateway.services.ServiceType;
 import org.apache.knox.gateway.services.security.AliasService;
 import org.apache.knox.gateway.services.security.KeystoreService;
+import org.apache.knox.gateway.services.security.KeystoreServiceException;
 import org.apache.knox.gateway.services.topology.TopologyService;
 import org.apache.knox.gateway.topology.ClusterConfigurationMonitorService;
 import org.apache.knox.gateway.topology.discovery.ServiceDiscoveryConfig;
@@ -49,6 +52,7 @@ import 
org.apache.knox.gateway.topology.simple.SimpleDescriptorFactory;
 import java.io.File;
 import java.io.IOException;
 import java.math.BigDecimal;
+import java.security.KeyStore;
 import java.time.Instant;
 import java.time.temporal.ChronoUnit;
 import java.util.ArrayList;
@@ -105,6 +109,8 @@ public class PollingConfigurationAnalyzer implements 
Runnable {
 
   private static final ClouderaManagerServiceDiscoveryMessages log = 
MessagesFactory.get(ClouderaManagerServiceDiscoveryMessages.class);
 
+  private static final GatewaySpiMessages LOGGER = 
MessagesFactory.get(GatewaySpiMessages.class);
+
   // Fully-qualified cluster name delimiter
   private static final String FQCN_DELIM = "::";
 
@@ -115,7 +121,7 @@ public class PollingConfigurationAnalyzer implements 
Runnable {
 
   private AliasService aliasService;
 
-  private KeystoreService keystoreService;
+  private KeyStore truststore;
 
   private TopologyService topologyService;
 
@@ -137,21 +143,34 @@ public class PollingConfigurationAnalyzer implements 
Runnable {
 
   private boolean isActive;
 
-  PollingConfigurationAnalyzer(final ClusterConfigurationCache   configCache,
+  private final GatewayConfig gatewayConfig;
+
+  PollingConfigurationAnalyzer(final GatewayConfig gatewayConfig,
+                               final ClusterConfigurationCache   configCache,
                                final AliasService                aliasService,
                                final KeystoreService             
keystoreService,
                                final ConfigurationChangeListener 
changeListener) {
-    this(configCache, aliasService, keystoreService, changeListener, 
DEFAULT_POLLING_INTERVAL);
+    this(gatewayConfig, configCache, aliasService, keystoreService, 
changeListener, DEFAULT_POLLING_INTERVAL);
   }
 
-  PollingConfigurationAnalyzer(final ClusterConfigurationCache   configCache,
+  PollingConfigurationAnalyzer(final GatewayConfig gatewayConfig,
+                               final ClusterConfigurationCache   configCache,
                                final AliasService                aliasService,
                                final KeystoreService             
keystoreService,
                                final ConfigurationChangeListener 
changeListener,
                                int                               interval) {
+    this.gatewayConfig = gatewayConfig;
     this.configCache     = configCache;
     this.aliasService    = aliasService;
-    this.keystoreService = keystoreService;
+
+    if (keystoreService != null) {
+      try {
+        truststore = keystoreService.getTruststoreForHttpClient();
+      } catch (KeystoreServiceException e) {
+        LOGGER.failedToLoadTruststore(e.getMessage(), e);
+      }
+    }
+
     this.changeListener  = changeListener;
     this.interval        = interval;
     this.processedEvents = Caffeine.newBuilder().expireAfterAccess(interval * 
3, TimeUnit.SECONDS).maximumSize(1000).build();
@@ -383,7 +402,7 @@ public class PollingConfigurationAnalyzer implements 
Runnable {
    */
   private DiscoveryApiClient getApiClient(final ServiceDiscoveryConfig 
discoveryConfig) {
     return clients.computeIfAbsent(discoveryConfig.getAddress(),
-                                   c -> new 
DiscoveryApiClient(discoveryConfig, aliasService, keystoreService));
+                                   c -> new DiscoveryApiClient(gatewayConfig, 
discoveryConfig, aliasService, truststore));
   }
 
   /**
diff --git 
a/gateway-discovery-cm/src/test/java/org/apache/knox/gateway/topology/discovery/cm/ClouderaManagerServiceDiscoveryTest.java
 
b/gateway-discovery-cm/src/test/java/org/apache/knox/gateway/topology/discovery/cm/ClouderaManagerServiceDiscoveryTest.java
index 3be2e264e..3495b84d6 100644
--- 
a/gateway-discovery-cm/src/test/java/org/apache/knox/gateway/topology/discovery/cm/ClouderaManagerServiceDiscoveryTest.java
+++ 
b/gateway-discovery-cm/src/test/java/org/apache/knox/gateway/topology/discovery/cm/ClouderaManagerServiceDiscoveryTest.java
@@ -33,7 +33,6 @@ import com.cloudera.api.swagger.model.ApiServiceList;
 import com.squareup.okhttp.Call;
 import org.apache.knox.gateway.config.GatewayConfig;
 import org.apache.knox.gateway.services.security.AliasService;
-import org.apache.knox.gateway.services.security.KeystoreService;
 import org.apache.knox.gateway.topology.discovery.ServiceDiscovery;
 import org.apache.knox.gateway.topology.discovery.ServiceDiscoveryConfig;
 import 
org.apache.knox.gateway.topology.discovery.cm.model.atlas.AtlasAPIServiceModelGenerator;
@@ -1184,12 +1183,14 @@ public class ClouderaManagerServiceDiscoveryTest {
       
EasyMock.expect(gwConf.getClouderaManagerServiceDiscoveryMaximumRetryAttempts()).andReturn(GatewayConfig.DEFAULT_CM_SERVICE_DISCOVERY_MAX_RETRY_ATTEMPTS).anyTimes();
       
EasyMock.expect(gwConf.getClusterMonitorPollingInterval(ClouderaManagerClusterConfigurationMonitor.getType())).andReturn(10).anyTimes();
     }
+    
EasyMock.expect(gwConf.getIncludedSSLCiphers()).andReturn(Collections.emptyList()).anyTimes();
+    
EasyMock.expect(gwConf.getIncludedSSLProtocols()).andReturn(Collections.emptySet()).anyTimes();
     EasyMock.replay(gwConf);
 
     ServiceDiscoveryConfig sdConfig = createMockDiscoveryConfig(clusterName);
 
     // Create the test client for providing test response content
-    TestDiscoveryApiClient mockClient = testRetry ? new 
TestFaultyDiscoveryApiClient(sdConfig, null, null) : new 
TestDiscoveryApiClient(sdConfig, null, null);
+    TestDiscoveryApiClient mockClient = testRetry ? new 
TestFaultyDiscoveryApiClient(gwConf, sdConfig, null) : new 
TestDiscoveryApiClient(gwConf, sdConfig, null);
 
     // Prepare the service list response for the cluster
     ApiServiceList serviceList = EasyMock.createNiceMock(ApiServiceList.class);
@@ -1318,9 +1319,8 @@ public class ClouderaManagerServiceDiscoveryTest {
 
     protected AtomicInteger executeCount = new AtomicInteger(0);
 
-    TestDiscoveryApiClient(ServiceDiscoveryConfig sdConfig, AliasService 
aliasService,
-                           KeystoreService keystoreService) {
-      super(sdConfig, aliasService, keystoreService);
+    TestDiscoveryApiClient(GatewayConfig gatewayConfig, ServiceDiscoveryConfig 
sdConfig, AliasService aliasService) {
+      super(gatewayConfig, sdConfig, aliasService, null);
     }
 
     void addResponse(Type type, ApiResponse<?> response) {
@@ -1345,9 +1345,8 @@ public class ClouderaManagerServiceDiscoveryTest {
 
   private static class TestFaultyDiscoveryApiClient extends 
TestDiscoveryApiClient {
 
-    TestFaultyDiscoveryApiClient(ServiceDiscoveryConfig sdConfig, AliasService 
aliasService,
-                           KeystoreService keystoreService) {
-      super(sdConfig, aliasService, keystoreService);
+    TestFaultyDiscoveryApiClient(GatewayConfig gatewayConfig, 
ServiceDiscoveryConfig sdConfig, AliasService aliasService) {
+      super(gatewayConfig, sdConfig, aliasService);
     }
 
     @Override
diff --git 
a/gateway-discovery-cm/src/test/java/org/apache/knox/gateway/topology/discovery/cm/monitor/PollingConfigurationAnalyzerTest.java
 
b/gateway-discovery-cm/src/test/java/org/apache/knox/gateway/topology/discovery/cm/monitor/PollingConfigurationAnalyzerTest.java
index 7e74ee6ee..f2df7224d 100644
--- 
a/gateway-discovery-cm/src/test/java/org/apache/knox/gateway/topology/discovery/cm/monitor/PollingConfigurationAnalyzerTest.java
+++ 
b/gateway-discovery-cm/src/test/java/org/apache/knox/gateway/topology/discovery/cm/monitor/PollingConfigurationAnalyzerTest.java
@@ -23,6 +23,7 @@ import com.cloudera.api.swagger.model.ApiEventCategory;
 import org.apache.commons.io.FileUtils;
 import org.apache.commons.lang3.RandomStringUtils;
 import org.apache.knox.gateway.GatewayServer;
+import org.apache.knox.gateway.config.GatewayConfig;
 import org.apache.knox.gateway.services.GatewayServices;
 import org.apache.knox.gateway.services.ServiceType;
 import org.apache.knox.gateway.services.topology.TopologyService;
@@ -297,6 +298,11 @@ public class PollingConfigurationAnalyzerTest {
       e.printStackTrace();
     }
 
+    final GatewayConfig gatewayConfig = 
EasyMock.createNiceMock(GatewayConfig.class);
+    
EasyMock.expect(gatewayConfig.getIncludedSSLCiphers()).andReturn(Collections.emptyList()).anyTimes();
+    
EasyMock.expect(gatewayConfig.getIncludedSSLProtocols()).andReturn(Collections.emptySet()).anyTimes();
+    EasyMock.replay(gatewayConfig);
+
     // Mock the service discovery details
     ServiceDiscoveryConfig sdc = 
EasyMock.createNiceMock(ServiceDiscoveryConfig.class);
     EasyMock.expect(sdc.getCluster()).andReturn(clusterName).anyTimes();
@@ -345,7 +351,7 @@ public class PollingConfigurationAnalyzerTest {
       setGatewayServices(gws);
 
       // Create the monitor
-      TestablePollingConfigAnalyzer pca = new 
TestablePollingConfigAnalyzer(configCache);
+      TestablePollingConfigAnalyzer pca = new 
TestablePollingConfigAnalyzer(gatewayConfig, configCache);
       pca.setInterval(5);
 
       // Start the polling thread
@@ -434,6 +440,11 @@ public class PollingConfigurationAnalyzerTest {
 
   private TestablePollingConfigAnalyzer buildPollingConfigAnalyzer(final 
String address, final String clusterName,
       final Map<String, ServiceConfigurationModel> serviceConfigurationModels, 
ChangeListener listener) {
+    final GatewayConfig gatewayConfig = 
EasyMock.createNiceMock(GatewayConfig.class);
+    
EasyMock.expect(gatewayConfig.getIncludedSSLCiphers()).andReturn(Collections.emptyList()).anyTimes();
+    
EasyMock.expect(gatewayConfig.getIncludedSSLProtocols()).andReturn(Collections.emptySet()).anyTimes();
+    EasyMock.replay(gatewayConfig);
+
     // Mock the service discovery details
     ServiceDiscoveryConfig sdc = 
EasyMock.createNiceMock(ServiceDiscoveryConfig.class);
     EasyMock.expect(sdc.getCluster()).andReturn(clusterName).anyTimes();
@@ -452,7 +463,7 @@ public class PollingConfigurationAnalyzerTest {
     EasyMock.expect(configCache.getClusterServiceConfigurations(address, 
clusterName)).andReturn(serviceConfigurationModels).anyTimes();
     EasyMock.replay(configCache);
 
-    return new TestablePollingConfigAnalyzer(configCache, listener);
+    return new TestablePollingConfigAnalyzer(gatewayConfig, configCache, 
listener);
   }
 
   private void doTestEventWithConfigChange(final ApiEvent event, final String 
clusterName) {
@@ -617,13 +628,13 @@ public class PollingConfigurationAnalyzerTest {
     private final Map<String, List<ApiEvent>> restartEvents = new HashMap<>();
     private final Map<String, ServiceConfigurationModel> serviceConfigModels = 
new HashMap<>();
 
-    TestablePollingConfigAnalyzer(ClusterConfigurationCache cache) {
-      this(cache, null);
+    TestablePollingConfigAnalyzer(GatewayConfig gatewayConfig, 
ClusterConfigurationCache cache) {
+      this(gatewayConfig, cache, null);
     }
 
-    TestablePollingConfigAnalyzer(ClusterConfigurationCache   cache,
+    TestablePollingConfigAnalyzer(GatewayConfig gatewayConfig, 
ClusterConfigurationCache   cache,
                                   ConfigurationChangeListener listener) {
-      super(cache, null, null, listener, 20);
+      super(gatewayConfig, cache, null, null, listener, 20);
     }
 
     void addRestartEvent(final String service, final ApiEvent restartEvent) {
diff --git 
a/gateway-server/src/main/java/org/apache/knox/gateway/config/impl/GatewayConfigImpl.java
 
b/gateway-server/src/main/java/org/apache/knox/gateway/config/impl/GatewayConfigImpl.java
index fce819a34..b76b48c22 100644
--- 
a/gateway-server/src/main/java/org/apache/knox/gateway/config/impl/GatewayConfigImpl.java
+++ 
b/gateway-server/src/main/java/org/apache/knox/gateway/config/impl/GatewayConfigImpl.java
@@ -181,6 +181,7 @@ public class GatewayConfigImpl extends Configuration 
implements GatewayConfig {
   // backward compatibility.
   // LET'S NOT CONTINUE THIS PATTERN BUT LEAVE THEM FOR NOW.
   private static final String SSL_ENABLED = "ssl.enabled";
+  private static final String SSL_INCLUDE_PROTOCOLS = "ssl.include.protocols";
   private static final String SSL_EXCLUDE_PROTOCOLS = "ssl.exclude.protocols";
   private static final String SSL_INCLUDE_CIPHERS = "ssl.include.ciphers";
   private static final String SSL_EXCLUDE_CIPHERS = "ssl.exclude.ciphers";
@@ -616,6 +617,12 @@ public class GatewayConfigImpl extends Configuration 
implements GatewayConfig {
     return get( FRONTEND_URL, null );
   }
 
+  @Override
+  public Set<String> getIncludedSSLProtocols() {
+    final Collection<String> includedSslProtocols = 
getTrimmedStringCollection(SSL_INCLUDE_PROTOCOLS);
+    return includedSslProtocols == null ? Collections.emptySet() : new 
HashSet<>(includedSslProtocols);
+  }
+
   @Override
   public List<String> getExcludedSSLProtocols() {
     List<String> protocols = null;
diff --git 
a/gateway-server/src/main/java/org/apache/knox/gateway/services/security/impl/JettySSLService.java
 
b/gateway-server/src/main/java/org/apache/knox/gateway/services/security/impl/JettySSLService.java
index 55f297ecf..002914053 100644
--- 
a/gateway-server/src/main/java/org/apache/knox/gateway/services/security/impl/JettySSLService.java
+++ 
b/gateway-server/src/main/java/org/apache/knox/gateway/services/security/impl/JettySSLService.java
@@ -24,6 +24,8 @@ import java.security.cert.X509Certificate;
 import java.util.Date;
 import java.util.List;
 import java.util.Map;
+import java.util.Set;
+
 import javax.security.auth.x500.X500Principal;
 
 import org.apache.knox.gateway.GatewayMessages;
@@ -225,6 +227,11 @@ public class JettySSLService implements SSLService {
       sslContextFactory.setExcludeProtocols( sslExcludeProtocols.toArray(new 
String[0]) );
     }
 
+    final Set<String> sslIncludeProtocols = config.getIncludedSSLProtocols();
+    if (sslIncludeProtocols != null && sslIncludeProtocols.isEmpty()) {
+      sslContextFactory.setIncludeProtocols(sslIncludeProtocols.toArray(new 
String[0]));
+    }
+
     
sslContextFactory.setRenegotiationAllowed(config.isSSLRenegotiationAllowed());
     return sslContextFactory;
   }
diff --git 
a/gateway-server/src/test/java/org/apache/knox/gateway/services/security/impl/JettySSLServiceTest.java
 
b/gateway-server/src/test/java/org/apache/knox/gateway/services/security/impl/JettySSLServiceTest.java
index 51cdf0508..ec67c77b7 100644
--- 
a/gateway-server/src/test/java/org/apache/knox/gateway/services/security/impl/JettySSLServiceTest.java
+++ 
b/gateway-server/src/test/java/org/apache/knox/gateway/services/security/impl/JettySSLServiceTest.java
@@ -480,6 +480,7 @@ public class JettySSLServiceTest {
     expect(config.getTrustAllCerts()).andReturn(false).atLeastOnce();
     expect(config.getIncludedSSLCiphers()).andReturn(null).atLeastOnce();
     expect(config.getExcludedSSLCiphers()).andReturn(null).atLeastOnce();
+    expect(config.getIncludedSSLProtocols()).andReturn(null).atLeastOnce();
     expect(config.getExcludedSSLProtocols()).andReturn(null).atLeastOnce();
     expect(config.isSSLRenegotiationAllowed()).andReturn(true).atLeastOnce();
     return config;
diff --git 
a/gateway-spi-common/src/main/java/org/apache/knox/gateway/GatewayTestConfig.java
 
b/gateway-spi-common/src/main/java/org/apache/knox/gateway/GatewayTestConfig.java
index 2974ac15c..801cfca85 100644
--- 
a/gateway-spi-common/src/main/java/org/apache/knox/gateway/GatewayTestConfig.java
+++ 
b/gateway-spi-common/src/main/java/org/apache/knox/gateway/GatewayTestConfig.java
@@ -303,6 +303,11 @@ public class GatewayTestConfig extends Configuration 
implements GatewayConfig {
     this.frontendUrl = frontendUrl;
   }
 
+  @Override
+  public Set<String> getIncludedSSLProtocols() {
+    return Collections.singleton("TLSv1.2");
+  }
+
   @Override
   public List<String> getExcludedSSLProtocols() {
     List<String> protocols = new ArrayList<>();
diff --git 
a/gateway-spi/src/main/java/org/apache/knox/gateway/config/GatewayConfig.java 
b/gateway-spi/src/main/java/org/apache/knox/gateway/config/GatewayConfig.java
index 2030180fd..c07411206 100644
--- 
a/gateway-spi/src/main/java/org/apache/knox/gateway/config/GatewayConfig.java
+++ 
b/gateway-spi/src/main/java/org/apache/knox/gateway/config/GatewayConfig.java
@@ -177,6 +177,8 @@ public interface GatewayConfig {
 
   boolean isSSLEnabled();
 
+  Set<String> getIncludedSSLProtocols();
+
   List<String> getExcludedSSLProtocols();
 
   List<String> getIncludedSSLCiphers();
diff --git 
a/gateway-spi/src/main/java/org/apache/knox/gateway/util/TruststoreSSLContextUtils.java
 
b/gateway-spi/src/main/java/org/apache/knox/gateway/util/TruststoreSSLContextUtils.java
index 322494408..7fadf5ed2 100644
--- 
a/gateway-spi/src/main/java/org/apache/knox/gateway/util/TruststoreSSLContextUtils.java
+++ 
b/gateway-spi/src/main/java/org/apache/knox/gateway/util/TruststoreSSLContextUtils.java
@@ -16,40 +16,36 @@
  */
 package org.apache.knox.gateway.util;
 
-import org.apache.http.ssl.SSLContextBuilder;
-import org.apache.http.ssl.SSLContexts;
-import org.apache.knox.gateway.i18n.GatewaySpiMessages;
-import org.apache.knox.gateway.i18n.messages.MessagesFactory;
-import org.apache.knox.gateway.services.security.KeystoreService;
-import org.apache.knox.gateway.services.security.KeystoreServiceException;
-
-import javax.net.ssl.SSLContext;
 import java.security.KeyManagementException;
 import java.security.KeyStore;
 import java.security.KeyStoreException;
 import java.security.NoSuchAlgorithmException;
 
+import javax.net.ssl.SSLContext;
+
+import org.apache.http.ssl.SSLContextBuilder;
+import org.apache.http.ssl.SSLContexts;
+import org.apache.knox.gateway.i18n.GatewaySpiMessages;
+import org.apache.knox.gateway.i18n.messages.MessagesFactory;
+
 public class TruststoreSSLContextUtils {
   private static final GatewaySpiMessages LOGGER = 
MessagesFactory.get(GatewaySpiMessages.class);
 
   private TruststoreSSLContextUtils() {
   }
 
-  public static SSLContext getTruststoreSSLContext(KeystoreService 
keystoreService) {
+  public static SSLContext getTruststoreSSLContext(KeyStore truststore) {
     SSLContext sslContext = null;
     try {
-      if(keystoreService != null) {
-        KeyStore truststore = keystoreService.getTruststoreForHttpClient();
-        if (truststore != null) {
-          SSLContextBuilder sslContextBuilder = SSLContexts.custom();
-          sslContextBuilder.loadTrustMaterial(truststore, null);
-          sslContext = sslContextBuilder.build();
-        }
+      if (truststore != null) {
+        SSLContextBuilder sslContextBuilder = SSLContexts.custom();
+        sslContextBuilder.loadTrustMaterial(truststore, null);
+        sslContext = sslContextBuilder.build();
       }
-    } catch (KeystoreServiceException | NoSuchAlgorithmException | 
KeyStoreException
-                 | KeyManagementException e) {
+    } catch (NoSuchAlgorithmException | KeyStoreException | 
KeyManagementException e) {
       LOGGER.failedToLoadTruststore(e.getMessage(), e);
     }
     return sslContext;
   }
+
 }


Reply via email to