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;
}
+
}