This is an automated email from the ASF dual-hosted git repository.
hanicz 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 420b65b98 KNOX-3245: Add new separators for SSL ciphers and protocols
(#1142)
420b65b98 is described below
commit 420b65b981ce96d87e8eacab127f53f797b121ab
Author: hanicz <[email protected]>
AuthorDate: Thu Jan 29 16:41:21 2026 +0100
KNOX-3245: Add new separators for SSL ciphers and protocols (#1142)
* KNOX-3245: Add new separators for SSL ciphers and protocols
* KNOX-3245: Fixed a bug where the ssl.include.protocols config wasn't
applied to the internal Jetty server
---
.../gateway/config/impl/GatewayConfigImpl.java | 28 ++--
.../services/security/impl/JettySSLService.java | 2 +-
.../gateway/config/impl/GatewayConfigImplTest.java | 151 +++++++++++++++++++++
.../security/impl/JettySSLServiceTest.java | 71 +++++++++-
4 files changed, 231 insertions(+), 21 deletions(-)
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 495d82646..e2c099c4e 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
@@ -38,6 +38,7 @@ import java.util.Map;
import java.util.Set;
import java.util.concurrent.ConcurrentHashMap;
import java.util.concurrent.TimeUnit;
+import java.util.stream.Collectors;
import org.apache.commons.codec.digest.HmacAlgorithms;
import org.apache.commons.io.FilenameUtils;
@@ -668,36 +669,33 @@ public class GatewayConfigImpl extends Configuration
implements GatewayConfig {
@Override
public Set<String> getIncludedSSLProtocols() {
- final Collection<String> includedSslProtocols =
getTrimmedStringCollection(SSL_INCLUDE_PROTOCOLS);
+ final List<String> includedSslProtocols =
splitConfigValueToList(SSL_INCLUDE_PROTOCOLS);
return includedSslProtocols == null ? Collections.emptySet() : new
HashSet<>(includedSslProtocols);
}
@Override
public List<String> getExcludedSSLProtocols() {
- List<String> protocols = null;
- String value = get(SSL_EXCLUDE_PROTOCOLS);
- if (!"none".equals(value)) {
- protocols = Arrays.asList(value.split("\\s*,\\s*"));
- }
- return protocols;
+ return splitConfigValueToList(SSL_EXCLUDE_PROTOCOLS);
}
@Override
public List<String> getIncludedSSLCiphers() {
- List<String> list = null;
- String value = get(SSL_INCLUDE_CIPHERS);
- if (value != null && !value.isEmpty() &&
!"none".equalsIgnoreCase(value.trim())) {
- list = Arrays.asList(value.trim().split("\\s*,\\s*"));
- }
- return list;
+ return splitConfigValueToList(SSL_INCLUDE_CIPHERS);
}
@Override
public List<String> getExcludedSSLCiphers() {
+ return splitConfigValueToList(SSL_EXCLUDE_CIPHERS);
+ }
+
+ private List<String> splitConfigValueToList(String config) {
List<String> list = null;
- String value = get(SSL_EXCLUDE_CIPHERS);
+ String value = get(config);
if (value != null && !value.isEmpty() &&
!"none".equalsIgnoreCase(value.trim())) {
- list = Arrays.asList(value.trim().split("\\s*,\\s*"));
+ list = Arrays.stream(value.split("[,:\n]"))
+ .map(String::trim)
+ .filter(part -> !part.isEmpty())
+ .collect(Collectors.toList());
}
return list;
}
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 782d07902..c8e6841f9 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
@@ -228,7 +228,7 @@ public class JettySSLService implements SSLService {
}
final Set<String> sslIncludeProtocols = config.getIncludedSSLProtocols();
- if (sslIncludeProtocols != null && sslIncludeProtocols.isEmpty()) {
+ if (sslIncludeProtocols != null && !sslIncludeProtocols.isEmpty()) {
sslContextFactory.setIncludeProtocols(sslIncludeProtocols.toArray(new
String[0]));
}
diff --git
a/gateway-server/src/test/java/org/apache/knox/gateway/config/impl/GatewayConfigImplTest.java
b/gateway-server/src/test/java/org/apache/knox/gateway/config/impl/GatewayConfigImplTest.java
index 484386871..6555b7610 100644
---
a/gateway-server/src/test/java/org/apache/knox/gateway/config/impl/GatewayConfigImplTest.java
+++
b/gateway-server/src/test/java/org/apache/knox/gateway/config/impl/GatewayConfigImplTest.java
@@ -18,8 +18,10 @@ package org.apache.knox.gateway.config.impl;
import static
org.apache.knox.gateway.services.security.impl.RemoteAliasService.REMOTE_ALIAS_SERVICE_TYPE;
import static org.hamcrest.CoreMatchers.is;
+import static org.hamcrest.CoreMatchers.not;
import static org.hamcrest.CoreMatchers.notNullValue;
import static org.hamcrest.MatcherAssert.assertThat;
+import static org.hamcrest.Matchers.empty;
import static org.hamcrest.Matchers.hasItems;
import static org.hamcrest.Matchers.nullValue;
import static org.junit.Assert.assertEquals;
@@ -36,6 +38,7 @@ import java.util.Arrays;
import java.util.HashSet;
import java.util.List;
import java.util.Map;
+import java.util.Set;
import java.util.concurrent.TimeUnit;
import org.apache.knox.gateway.config.GatewayConfig;
@@ -143,6 +146,30 @@ public class GatewayConfigImplTest {
config.set( "ssl.include.ciphers", " ONE , TWO , THREE " );
assertThat( config.getIncludedSSLCiphers(),
is(hasItems("ONE","TWO","THREE")) );
+ config.set( "ssl.include.ciphers", " ONE:TWO:THREE " );
+ assertThat( config.getIncludedSSLCiphers(),
is(hasItems("ONE","TWO","THREE")) );
+
+ config.set( "ssl.include.ciphers", " ONE:TWO,THREE " );
+ assertThat( config.getIncludedSSLCiphers(),
is(hasItems("ONE","TWO","THREE")) );
+
+ config.set( "ssl.include.ciphers", " ONE : TWO,THREE " );
+ assertThat( config.getIncludedSSLCiphers(),
is(hasItems("ONE","TWO","THREE")) );
+
+ config.set( "ssl.include.ciphers", " ONE : TWO\nTHREE " );
+ assertThat( config.getIncludedSSLCiphers(),
is(hasItems("ONE","TWO","THREE")) );
+
+ config.set( "ssl.include.ciphers", " ONE,TWO \n THREE " );
+ assertThat( config.getIncludedSSLCiphers(),
is(hasItems("ONE","TWO","THREE")) );
+
+ config.set( "ssl.include.ciphers", " ONE,TWO \n THREE :FOUR" );
+ assertThat( config.getIncludedSSLCiphers(),
is(hasItems("ONE","TWO","THREE", "FOUR")) );
+
+ config.set( "ssl.include.ciphers", " ONE,TWO,,THREE" );
+ assertThat( config.getIncludedSSLCiphers(),
is(hasItems("ONE","TWO","THREE")) );
+
+ config.set( "ssl.include.ciphers", " ONE,TWO,,THREE" );
+ assertThat( config.getIncludedSSLCiphers(), not(hasItems("")) );
+
list = config.getExcludedSSLCiphers();
assertThat( list, is(nullValue()) );
@@ -166,6 +193,130 @@ public class GatewayConfigImplTest {
config.set( "ssl.exclude.ciphers", " ONE , TWO , THREE " );
assertThat( config.getExcludedSSLCiphers(),
is(hasItems("ONE","TWO","THREE")) );
+
+ config.set( "ssl.exclude.ciphers", " ONE:TWO:THREE " );
+ assertThat( config.getExcludedSSLCiphers(),
is(hasItems("ONE","TWO","THREE")) );
+
+ config.set( "ssl.exclude.ciphers", " ONE:TWO,THREE " );
+ assertThat( config.getExcludedSSLCiphers(),
is(hasItems("ONE","TWO","THREE")) );
+
+ config.set( "ssl.exclude.ciphers", " ONE : TWO,THREE " );
+ assertThat( config.getExcludedSSLCiphers(),
is(hasItems("ONE","TWO","THREE")) );
+
+ config.set( "ssl.exclude.ciphers", " ONE : TWO\nTHREE " );
+ assertThat( config.getExcludedSSLCiphers(),
is(hasItems("ONE","TWO","THREE")) );
+
+ config.set( "ssl.exclude.ciphers", " ONE,TWO \n THREE " );
+ assertThat( config.getExcludedSSLCiphers(),
is(hasItems("ONE","TWO","THREE")) );
+
+ config.set( "ssl.exclude.ciphers", " ONE,TWO \n THREE :FOUR" );
+ assertThat( config.getExcludedSSLCiphers(),
is(hasItems("ONE","TWO","THREE", "FOUR")) );
+
+
+ config.set( "ssl.exclude.ciphers", " ONE,TWO,,THREE" );
+ assertThat( config.getExcludedSSLCiphers(),
is(hasItems("ONE","TWO","THREE")) );
+
+ config.set( "ssl.exclude.ciphers", " ONE,TWO,,THREE" );
+ assertThat( config.getExcludedSSLCiphers(), not(hasItems("")) );
+ }
+
+ @Test
+ public void testSSLProtocols() {
+ GatewayConfigImpl config = new GatewayConfigImpl();
+ Set<String> list;
+
+ list = config.getIncludedSSLProtocols();
+ assertThat( list, is(empty()) );
+
+ config.set( "ssl.include.protocols", "none" );
+ assertThat( config.getIncludedSSLProtocols(), is(empty()) );
+
+ config.set( "ssl.include.protocols", "" );
+ assertThat( config.getIncludedSSLProtocols(), is(empty()) );
+
+ config.set( "ssl.include.protocols", "ONE" );
+ assertThat( config.getIncludedSSLProtocols(), is(hasItems("ONE")) );
+
+ config.set( "ssl.include.protocols", " ONE " );
+ assertThat( config.getIncludedSSLProtocols(), is(hasItems("ONE")) );
+
+ config.set( "ssl.include.protocols", "ONE,TWO" );
+ assertThat( config.getIncludedSSLProtocols(), is(hasItems("ONE","TWO")) );
+
+ config.set( "ssl.include.protocols", "ONE,TWO,THREE" );
+ assertThat( config.getIncludedSSLProtocols(),
is(hasItems("ONE","TWO","THREE")) );
+
+ config.set( "ssl.include.protocols", " ONE , TWO , THREE " );
+ assertThat( config.getIncludedSSLProtocols(),
is(hasItems("ONE","TWO","THREE")) );
+
+ config.set( "ssl.include.protocols", " ONE:TWO:THREE " );
+ assertThat( config.getIncludedSSLProtocols(),
is(hasItems("ONE","TWO","THREE")) );
+
+ config.set( "ssl.include.protocols", " ONE:TWO,THREE " );
+ assertThat( config.getIncludedSSLProtocols(),
is(hasItems("ONE","TWO","THREE")) );
+
+ config.set( "ssl.include.protocols", " ONE : TWO,THREE " );
+ assertThat( config.getIncludedSSLProtocols(),
is(hasItems("ONE","TWO","THREE")) );
+
+ config.set( "ssl.include.protocols", " ONE : TWO\nTHREE " );
+ assertThat( config.getIncludedSSLProtocols(),
is(hasItems("ONE","TWO","THREE")) );
+
+ config.set( "ssl.include.protocols", " ONE,TWO \n THREE " );
+ assertThat( config.getIncludedSSLProtocols(),
is(hasItems("ONE","TWO","THREE")) );
+
+ config.set( "ssl.include.protocols", " ONE,TWO \n THREE :FOUR" );
+ assertThat( config.getIncludedSSLProtocols(),
is(hasItems("ONE","TWO","THREE", "FOUR")) );
+
+ config.set( "ssl.include.protocols", " ONE,TWO,,THREE" );
+ assertThat( config.getIncludedSSLProtocols(),
is(hasItems("ONE","TWO","THREE")) );
+
+ config.set( "ssl.include.protocols", " ONE,TWO,,THREE" );
+ assertThat( config.getIncludedSSLProtocols(), not(hasItems("")) );
+
+ config.set( "ssl.exclude.protocols", "none" );
+ assertThat( config.getExcludedSSLProtocols(), is(nullValue()) );
+
+ config.set( "ssl.exclude.protocols", "" );
+ assertThat( config.getExcludedSSLProtocols(), is(nullValue()) );
+
+ config.set( "ssl.exclude.protocols", "ONE" );
+ assertThat( config.getExcludedSSLProtocols(), is(hasItems("ONE")) );
+
+ config.set( "ssl.exclude.protocols", " ONE " );
+ assertThat( config.getExcludedSSLProtocols(), is(hasItems("ONE")) );
+
+ config.set( "ssl.exclude.protocols", "ONE,TWO" );
+ assertThat( config.getExcludedSSLProtocols(), is(hasItems("ONE","TWO")) );
+
+ config.set( "ssl.exclude.protocols", "ONE,TWO,THREE" );
+ assertThat( config.getExcludedSSLProtocols(),
is(hasItems("ONE","TWO","THREE")) );
+
+ config.set( "ssl.exclude.protocols", " ONE , TWO , THREE " );
+ assertThat( config.getExcludedSSLProtocols(),
is(hasItems("ONE","TWO","THREE")) );
+
+ config.set( "ssl.exclude.protocols", " ONE:TWO:THREE " );
+ assertThat( config.getExcludedSSLProtocols(),
is(hasItems("ONE","TWO","THREE")) );
+
+ config.set( "ssl.exclude.protocols", " ONE:TWO,THREE " );
+ assertThat( config.getExcludedSSLProtocols(),
is(hasItems("ONE","TWO","THREE")) );
+
+ config.set( "ssl.exclude.protocols", " ONE : TWO,THREE " );
+ assertThat( config.getExcludedSSLProtocols(),
is(hasItems("ONE","TWO","THREE")) );
+
+ config.set( "ssl.exclude.protocols", " ONE : TWO\nTHREE " );
+ assertThat( config.getExcludedSSLProtocols(),
is(hasItems("ONE","TWO","THREE")) );
+
+ config.set( "ssl.exclude.protocols", " ONE,TWO \n THREE " );
+ assertThat( config.getExcludedSSLProtocols(),
is(hasItems("ONE","TWO","THREE")) );
+
+ config.set( "ssl.exclude.protocols", " ONE,TWO \n THREE :FOUR" );
+ assertThat( config.getExcludedSSLProtocols(),
is(hasItems("ONE","TWO","THREE", "FOUR")) );
+
+ config.set( "ssl.exclude.protocols", " ONE,TWO,,THREE" );
+ assertThat( config.getExcludedSSLProtocols(),
is(hasItems("ONE","TWO","THREE")) );
+
+ config.set( "ssl.exclude.protocols", " ONE,TWO,,THREE" );
+ assertThat( config.getExcludedSSLProtocols(), not(hasItems("")) );
}
// KNOX-2772
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 6491ddfea..f21a9a6e1 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
@@ -23,6 +23,7 @@ import static org.easymock.EasyMock.eq;
import static org.easymock.EasyMock.expect;
import static org.easymock.EasyMock.replay;
import static org.easymock.EasyMock.verify;
+import static org.junit.Assert.assertArrayEquals;
import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertFalse;
import static org.junit.Assert.assertNotNull;
@@ -30,6 +31,11 @@ import static org.junit.Assert.assertNull;
import static org.junit.Assert.assertTrue;
import static org.junit.Assert.fail;
+import java.util.Arrays;
+import java.util.HashSet;
+import java.util.List;
+import java.util.Set;
+
import org.apache.knox.gateway.config.GatewayConfig;
import org.apache.knox.gateway.services.security.AliasService;
import org.apache.knox.gateway.services.security.AliasServiceException;
@@ -498,10 +504,65 @@ public class JettySSLServiceTest {
assertFalse(sslContextFactory.getWantClientAuth());
}
+ @Test
+ public void testBuildSslContextFactoryCiphersAndProtocols() throws Exception
{
+ String basedir = System.getProperty("basedir");
+ if (basedir == null) {
+ basedir = new File(".").getCanonicalPath();
+ }
+
+ Path identityKeystorePath = Paths.get(basedir, "target", "test-classes",
"keystores", "server-keystore.jks");
+ String identityKeystoreType = "jks";
+ char[] identityKeystorePassword = "horton".toCharArray();
+ char[] identityKeyPassphrase = "horton".toCharArray();
+ String identityKeyAlias = "server";
+ Path truststorePath = Paths.get(basedir, "target", "test-classes",
"keystores", "server-truststore.jks");
+ String truststoreType = "jks";
+ String truststorePasswordAlias = "trust_store_password";
+
+ List<String> includedCiphers = Arrays.asList("SSL_RSA_WITH_RC4_128_MD5",
"SSL_RSA_WITH_RC4_128_SHA");
+ List<String> excludedCiphers =
List.of("SSL_DHE_RSA_WITH_3DES_EDE_CBC_SHA");
+ List<String> excludedProtocols = List.of("SSLv3");
+ Set<String> includedProtocols = new HashSet<>(Arrays.asList("TLSv1.2",
"TLSv1.3"));
+
+ GatewayConfig config = createGatewayConfig(false, false,
identityKeystorePath, identityKeystoreType, identityKeyAlias, truststorePath,
truststoreType, truststorePasswordAlias,
+ includedCiphers, excludedCiphers, includedProtocols,
excludedProtocols);
+
+ AliasService aliasService = createMock(AliasService.class);
+
expect(aliasService.getGatewayIdentityKeystorePassword()).andReturn(identityKeystorePassword).atLeastOnce();
+
expect(aliasService.getGatewayIdentityPassphrase()).andReturn(identityKeyPassphrase).atLeastOnce();
+
+ KeystoreService keystoreService = createMock(KeystoreService.class);
+
+ replay(config, aliasService, keystoreService);
+
+ JettySSLService sslService = new JettySSLService();
+ sslService.setAliasService(aliasService);
+ sslService.setKeystoreService(keystoreService);
+
+ SslContextFactory sslContextFactory = (SslContextFactory)
sslService.buildSslContextFactory(config);
+ assertArrayEquals(excludedCiphers.toArray(),
sslContextFactory.getExcludeCipherSuites());
+ assertArrayEquals(includedCiphers.toArray(),
sslContextFactory.getIncludeCipherSuites());
+ assertArrayEquals(excludedProtocols.toArray(),
sslContextFactory.getExcludeProtocols());
+ assertArrayEquals(includedProtocols.toArray(),
sslContextFactory.getIncludeProtocols());
+
+
+ verify(config, aliasService, keystoreService);
+ }
+
private GatewayConfig createGatewayConfig(boolean isClientAuthNeeded,
boolean isExplicitTruststore,
Path identityKeystorePath, String
identityKeystoreType,
String identityKeyAlias, Path
truststorePath,
String truststoreType, String
trustStorePasswordAlias) {
+ return createGatewayConfig(isClientAuthNeeded, isExplicitTruststore,
identityKeystorePath, identityKeystoreType, identityKeyAlias, truststorePath,
truststoreType, trustStorePasswordAlias, null, null, null, null);
+ }
+
+ private GatewayConfig createGatewayConfig(boolean isClientAuthNeeded,
boolean isExplicitTruststore,
+ Path identityKeystorePath, String
identityKeystoreType,
+ String identityKeyAlias, Path
truststorePath,
+ String truststoreType, String
trustStorePasswordAlias,
+ List<String> includedCiphers,
List<String> excludedCiphers,
+ Set<String> includedProtocols,
List<String> excludedProtocols) {
GatewayConfig config = createMock(GatewayConfig.class);
expect(config.getIdentityKeystorePath()).andReturn(identityKeystorePath.toString()).atLeastOnce();
expect(config.getIdentityKeystoreType()).andReturn(identityKeystoreType).atLeastOnce();
@@ -523,10 +584,10 @@ public class JettySSLServiceTest {
expect(config.isClientAuthWanted()).andReturn(false).atLeastOnce();
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.getIncludedSSLCiphers()).andReturn(includedCiphers).atLeastOnce();
+
expect(config.getExcludedSSLCiphers()).andReturn(excludedCiphers).atLeastOnce();
+
expect(config.getIncludedSSLProtocols()).andReturn(includedProtocols).atLeastOnce();
+
expect(config.getExcludedSSLProtocols()).andReturn(excludedProtocols).atLeastOnce();
expect(config.isSSLRenegotiationAllowed()).andReturn(true).atLeastOnce();
return config;
}
@@ -538,4 +599,4 @@ public class JettySSLServiceTest {
return config;
}
-}
\ No newline at end of file
+}