diff --git a/src/test/java/redis/clients/jedis/SSLACLJedisTest.java b/src/test/java/redis/clients/jedis/SSLACLJedisTest.java deleted file mode 100644 index 296ff552d5..0000000000 --- a/src/test/java/redis/clients/jedis/SSLACLJedisTest.java +++ /dev/null @@ -1,102 +0,0 @@ -package redis.clients.jedis; - -import io.redis.test.annotations.ConditionalOnEnv; -import io.redis.test.annotations.SinceRedisVersion; -import java.nio.file.Path; -import java.util.Arrays; -import java.util.List; - -import org.junit.jupiter.api.AfterAll; -import org.junit.jupiter.api.BeforeAll; -import org.junit.jupiter.api.Tag; -import org.junit.jupiter.api.Test; -import org.junit.jupiter.api.extension.RegisterExtension; -import redis.clients.jedis.util.EnvCondition; -import redis.clients.jedis.util.RedisVersionCondition; -import redis.clients.jedis.util.TestEnvUtil; -import redis.clients.jedis.util.TlsUtil; - -import static org.junit.jupiter.api.Assertions.assertEquals; - -/** - * This test class is a copy of {@link SSLJedisTest}. - *

- * This test is only executed when the server/cluster is Redis 6. or more. - */ -@SinceRedisVersion(value = "6.0.0", message = "Not running ACL test on this version of Redis") -@Tag("integration") -@ConditionalOnEnv(value = TestEnvUtil.ENV_OSS_SOURCE, enabled = false) -public class SSLACLJedisTest { - - protected static EndpointConfig endpoint; - - protected static EndpointConfig endpointWithDefaultUser; - - @RegisterExtension - public static EnvCondition envCondition = new EnvCondition(); - - @RegisterExtension - public static RedisVersionCondition versionCondition = new RedisVersionCondition( - () -> Endpoints.getRedisEndpoint("standalone0-acl-tls")); - - private static final String trustStoreName = SSLACLJedisTest.class.getSimpleName(); - - @BeforeAll - public static void prepare() { - endpoint = Endpoints.getRedisEndpoint("standalone0-acl-tls"); - endpointWithDefaultUser = Endpoints.getRedisEndpoint("standalone0-tls"); - List trustedCertLocation = Arrays.asList(endpoint.getCertificatesLocation(), - endpointWithDefaultUser.getCertificatesLocation()); - Path trustStorePath = TlsUtil.createAndSaveTestTruststore(trustStoreName, trustedCertLocation, - "changeit"); - - TlsUtil.setCustomTrustStore(trustStorePath, "changeit"); - } - - @AfterAll - public static void teardownTrustStore() { - TlsUtil.restoreOriginalTrustStore(); - } - - @Test - public void connectWithSsl() { - try (Jedis jedis = new Jedis(endpoint.getHost(), endpoint.getPort(), true)) { - jedis.auth(endpoint.getUsername(), endpoint.getPassword()); - assertEquals("PONG", jedis.ping()); - } - } - - @Test - public void connectWithConfig() { - try (Jedis jedis = new Jedis(endpoint.getHostAndPort(), - DefaultJedisClientConfig.builder().ssl(true).build())) { - jedis.auth(endpoint.getUsername(), endpoint.getPassword()); - assertEquals("PONG", jedis.ping()); - } - } - - @Test - public void connectWithUrl() { - // The "rediss" scheme instructs jedis to open a SSL/TLS connection. - try (Jedis jedis = new Jedis( - endpointWithDefaultUser.getURIBuilder().defaultCredentials().build().toString())) { - assertEquals("PONG", jedis.ping()); - } - try (Jedis jedis = new Jedis( - endpoint.getURIBuilder().defaultCredentials().build().toString())) { - assertEquals("PONG", jedis.ping()); - } - } - - @Test - public void connectWithUri() { - // The "rediss" scheme instructs jedis to open a SSL/TLS connection. - try (Jedis jedis = new Jedis( - endpointWithDefaultUser.getURIBuilder().defaultCredentials().build())) { - assertEquals("PONG", jedis.ping()); - } - try (Jedis jedis = new Jedis(endpoint.getURIBuilder().defaultCredentials().build())) { - assertEquals("PONG", jedis.ping()); - } - } -} diff --git a/src/test/java/redis/clients/jedis/SSLACLRedisClusterClientTest.java b/src/test/java/redis/clients/jedis/SSLACLRedisClusterClientTest.java deleted file mode 100644 index 3d2e4d2c64..0000000000 --- a/src/test/java/redis/clients/jedis/SSLACLRedisClusterClientTest.java +++ /dev/null @@ -1,328 +0,0 @@ -package redis.clients.jedis; - - -import static org.hamcrest.MatcherAssert.assertThat; -import static org.hamcrest.Matchers.anyOf; -import static org.hamcrest.Matchers.containsString; -import static org.junit.jupiter.api.Assertions.assertEquals; -import static org.junit.jupiter.api.Assertions.assertTrue; -import static org.junit.jupiter.api.Assertions.fail; -import static redis.clients.jedis.util.TlsUtil.*; - -import java.nio.file.Path; -import java.util.Collections; -import java.util.List; -import java.util.Map; -import javax.net.ssl.HostnameVerifier; -import javax.net.ssl.SSLParameters; - -import io.redis.test.annotations.SinceRedisVersion; -import io.redis.test.utils.RedisVersion; - -import org.junit.jupiter.api.AfterAll; -import org.junit.jupiter.api.BeforeAll; -import org.junit.jupiter.api.Test; -import org.junit.jupiter.api.Tag; -import redis.clients.jedis.util.RedisVersionUtil; -import redis.clients.jedis.util.TlsUtil; -import redis.clients.jedis.exceptions.JedisClusterOperationException; - -@SinceRedisVersion(value = "7.0.0", message = "Redis 6.2.x returns non-tls port in CLUSTER SLOTS command. Enable for 6.2.x after tests are fixed.") -@Tag("integration") -public class SSLACLRedisClusterClientTest extends RedisClusterClientTestBase { - - private static final int DEFAULT_REDIRECTIONS = 5; - private static final ConnectionPoolConfig DEFAULT_POOL_CONFIG = new ConnectionPoolConfig(); - - protected static EndpointConfig tlsEndpoint; - - // legacy test env bootstrap uses stunnel causing redis server to report non-tls port instead tls one containerised - // test env enables tls directly on Redis nodes and in this case tls_port is correctly reported - // TODO : remove stunnel from legacy env - // static int tlsPortOffset = 0; - private final HostAndPortMapper hostAndPortMap = (hostAndPort) -> { - String host = hostAndPort.getHost(); - int port = hostAndPort.getPort(); - - if ("127.0.0.1".equals(host)) { - host = "localhost"; - } - return new HostAndPort(host, port); - }; - - // don't map IP addresses so that we try to connect with host 127.0.0.1 - private final HostAndPortMapper portMap = (hostAndPort) -> { - if ("localhost".equals(hostAndPort.getHost())) { - return hostAndPort; - } - return new HostAndPort(hostAndPort.getHost(), hostAndPort.getPort() /* + tlsPortOffset */); - }; - - private static final String trustStoreName = SSLACLRedisClusterClientTest.class.getSimpleName(); - - @BeforeAll - public static void prepare() { - tlsEndpoint = Endpoints.getRedisEndpoint("cluster-unbound-tls"); - List trustedCertLocation = Collections.singletonList(tlsEndpoint.getCertificatesLocation()); - Path trustStorePath = TlsUtil.createAndSaveTestTruststore(trustStoreName, trustedCertLocation,"changeit"); - - TlsUtil.setCustomTrustStore(trustStorePath, "changeit"); - } - - @AfterAll - public static void teardownTrustStore() { - TlsUtil.restoreOriginalTrustStore(); - } - - @Test - public void testSSLDiscoverNodesAutomatically() { - DefaultJedisClientConfig config = DefaultJedisClientConfig.builder() - .user("default").password(tlsEndpoint.getPassword()).ssl(true) - .hostAndPortMapper(hostAndPortMap).build(); - - try (RedisClusterClient jc = RedisClusterClient.builder() - .nodes(Collections.singleton(tlsEndpoint.getHostAndPort())) - .clientConfig(config) - .maxAttempts(DEFAULT_REDIRECTIONS) - .poolConfig(DEFAULT_POOL_CONFIG) - .build()) { - Map clusterNodes = jc.getClusterNodes(); - assertEquals(3, clusterNodes.size()); - - /** - * In versions prior to Redis 7.x, Redis does not natively support automatic port switching between TLS and - * non-TLS ports for CLUSTER SLOTS. When using Redis 6.2.16 in a cluster mode with TLS, CLUSTER command returns - * the regular (non-TLS) port rather than the TLS port. - */ - if (RedisVersionUtil.getRedisVersion(jc.getConnectionFromSlot(0)).isLessThanOrEqualTo(RedisVersion.V7_0_0)) { - assertTrue(clusterNodes.containsKey(nodeInfo1.toString())); - assertTrue(clusterNodes.containsKey(nodeInfo2.toString())); - assertTrue(clusterNodes.containsKey(nodeInfo3.toString())); - } else { - assertTrue(clusterNodes.containsKey(tlsEndpoint.getHostAndPort(0).toString())); - assertTrue(clusterNodes.containsKey(tlsEndpoint.getHostAndPort(1).toString())); - assertTrue(clusterNodes.containsKey(tlsEndpoint.getHostAndPort(2).toString())); - } - jc.get("foo"); - } - - try (RedisClusterClient jc2 = RedisClusterClient.builder() - .nodes(Collections.singleton(tlsEndpoint.getHostAndPort())) - .clientConfig(config) - .maxAttempts(DEFAULT_REDIRECTIONS) - .poolConfig(DEFAULT_POOL_CONFIG) - .build()) { - Map clusterNodes = jc2.getClusterNodes(); - assertEquals(3, clusterNodes.size()); - assertTrue(clusterNodes.containsKey(tlsEndpoint.getHostAndPort(0).toString())); - assertTrue(clusterNodes.containsKey(tlsEndpoint.getHostAndPort(1).toString())); - assertTrue(clusterNodes.containsKey(tlsEndpoint.getHostAndPort(2).toString())); - jc2.get("foo"); - } - } - - @Test - public void testSSLWithoutPortMap() { - try (RedisClusterClient jc = RedisClusterClient.builder() - .nodes(Collections.singleton(tlsEndpoint.getHostAndPort())) - .clientConfig(DefaultJedisClientConfig.builder().user("default").password(tlsEndpoint.getPassword()).ssl(true).build()) - .maxAttempts(DEFAULT_REDIRECTIONS) - .poolConfig(DEFAULT_POOL_CONFIG) - .build()) { - Map clusterNodes = jc.getClusterNodes(); - assertEquals(3, clusterNodes.size()); - /** - * In versions prior to Redis 7.x, Redis does not natively support automatic port switching between TLS and - * non-TLS ports for CLUSTER SLOTS. When using Redis 6.2.16 in a cluster mode with TLS, CLUSTER command returns - * the regular (non-TLS) port rather than the TLS port. - */ - if (RedisVersionUtil.getRedisVersion(jc.getConnectionFromSlot(0)).isLessThanOrEqualTo(RedisVersion.V7_0_0)) { - assertTrue(clusterNodes.containsKey(nodeInfo1.toString())); - assertTrue(clusterNodes.containsKey(nodeInfo2.toString())); - assertTrue(clusterNodes.containsKey(nodeInfo3.toString())); - } else { - assertTrue(clusterNodes.containsKey(tlsEndpoint.getHostAndPort(0).toString())); - assertTrue(clusterNodes.containsKey(tlsEndpoint.getHostAndPort(1).toString())); - assertTrue(clusterNodes.containsKey(tlsEndpoint.getHostAndPort(2).toString())); - } - } - } - - @Test - public void connectByIpAddress() { - try (RedisClusterClient jc = RedisClusterClient.builder() - .nodes(Collections.singleton(tlsEndpoint.getHostAndPort())) - .clientConfig(DefaultJedisClientConfig.builder().user("default").password(tlsEndpoint.getPassword()).ssl(true) - .hostAndPortMapper(hostAndPortMap).build()) - .maxAttempts(DEFAULT_REDIRECTIONS) - .poolConfig(DEFAULT_POOL_CONFIG) - .build()) { - jc.get("foo"); - } - } - - @Test - public void connectToNodesFailsWithSSLParametersAndNoHostMapping() { - final SSLParameters sslParameters = new SSLParameters(); - sslParameters.setEndpointIdentificationAlgorithm("HTTPS"); - - try (RedisClusterClient jc = RedisClusterClient.builder() - .nodes(Collections.singleton(new HostAndPort("localhost", tlsEndpoint.getPort()))) - .clientConfig(DefaultJedisClientConfig.builder().user("default").password(tlsEndpoint.getPassword()).ssl(true) - .sslParameters(sslParameters).hostAndPortMapper(portMap).build()) - .maxAttempts(DEFAULT_REDIRECTIONS) - .poolConfig(DEFAULT_POOL_CONFIG) - .build()) { - jc.get("foo"); - fail("It should fail after all cluster attempts."); -// } catch (JedisClusterMaxAttemptsException e) { - } catch (JedisClusterOperationException e) { - // initial connection to localhost works, but subsequent connections to nodes use 127.0.0.1 - // and fail hostname verification - assertThat(e.getMessage(), anyOf( - containsString("No more cluster attempts left."), - containsString("Cluster retry deadline exceeded.") - )); - } - } - - @Test - public void connectToNodesSucceedsWithSSLParametersAndHostMapping() { - final SSLParameters sslParameters = new SSLParameters(); - sslParameters.setEndpointIdentificationAlgorithm("HTTPS"); - - try (RedisClusterClient jc = RedisClusterClient.builder() - .nodes(Collections.singleton(tlsEndpoint.getHostAndPort())) - .clientConfig(DefaultJedisClientConfig.builder().user("default").password(tlsEndpoint.getPassword()).ssl(true) - .sslParameters(sslParameters).hostAndPortMapper(hostAndPortMap).build()) - .maxAttempts(DEFAULT_REDIRECTIONS) - .poolConfig(DEFAULT_POOL_CONFIG) - .build()) { - jc.get("foo"); - } - } - - @Test - public void connectByIpAddressFailsWithSSLParameters() { - final SSLParameters sslParameters = new SSLParameters(); - sslParameters.setEndpointIdentificationAlgorithm("HTTPS"); - - try (RedisClusterClient jc = RedisClusterClient.builder() - .nodes(Collections.singleton(tlsEndpoint.getHostAndPort())) - .clientConfig(DefaultJedisClientConfig.builder().user("default").password(tlsEndpoint.getPassword()).ssl(true) - .sslParameters(sslParameters).hostAndPortMapper(hostAndPortMap).build()) - .maxAttempts(DEFAULT_REDIRECTIONS) - .poolConfig(DEFAULT_POOL_CONFIG) - .build()) { -// jc.get("key"); -// Assert.fail("There should be no reachable node in cluster."); -//// } catch (JedisNoReachableClusterNodeException e) { - } catch (JedisClusterOperationException e) { -// assertEquals("No reachable node in cluster.", e.getMessage()); - assertEquals("Could not initialize cluster slots cache.", e.getMessage()); - } - } - - @Test - public void connectWithCustomHostNameVerifier() { - HostnameVerifier hostnameVerifier = new TlsUtil.BasicHostnameVerifier(); - HostnameVerifier localhostVerifier = new TlsUtil.LocalhostVerifier(); - - try (RedisClusterClient jc = RedisClusterClient.builder() - .nodes(Collections.singleton(new HostAndPort("localhost", tlsEndpoint.getPort()))) - .clientConfig(DefaultJedisClientConfig.builder().user("default").password(tlsEndpoint.getPassword()).ssl(true) - .hostnameVerifier(hostnameVerifier).hostAndPortMapper(portMap).build()) - .maxAttempts(DEFAULT_REDIRECTIONS) - .poolConfig(DEFAULT_POOL_CONFIG) - .build()) { - jc.get("foo"); - fail("It should fail after all cluster attempts."); -// } catch (JedisClusterMaxAttemptsException e) { - } catch (JedisClusterOperationException e) { - // initial connection made with 'localhost' but subsequent connections to nodes use 127.0.0.1 - // which causes custom hostname verification to fail - assertThat(e.getMessage(), anyOf( - containsString("No more cluster attempts left."), - containsString("Cluster retry deadline exceeded.") - )); - } - - try (RedisClusterClient jc2 = RedisClusterClient.builder() - .nodes(Collections.singleton(new HostAndPort("127.0.0.1", tlsEndpoint.getPort()))) - .clientConfig(DefaultJedisClientConfig.builder().user("default").password(tlsEndpoint.getPassword()).ssl(true) - .hostnameVerifier(hostnameVerifier).hostAndPortMapper(portMap).build()) - .maxAttempts(DEFAULT_REDIRECTIONS) - .poolConfig(DEFAULT_POOL_CONFIG) - .build()) { -// jc2.get("key"); -// Assert.fail("There should be no reachable node in cluster."); -//// } catch (JedisNoReachableClusterNodeException e) { - } catch (JedisClusterOperationException e) { - // JedisNoReachableClusterNodeException exception occurs from not being able to connect since - // the socket factory fails the hostname verification -// assertEquals("No reachable node in cluster.", e.getMessage()); - assertEquals("Could not initialize cluster slots cache.", e.getMessage()); - } - - try (RedisClusterClient jc3 = RedisClusterClient.builder() - .nodes(Collections.singleton(tlsEndpoint.getHostAndPort())) - .clientConfig(DefaultJedisClientConfig.builder().user("default").password(tlsEndpoint.getPassword()).ssl(true) - .hostnameVerifier(localhostVerifier).hostAndPortMapper(portMap).build()) - .maxAttempts(DEFAULT_REDIRECTIONS) - .poolConfig(DEFAULT_POOL_CONFIG) - .build()) { - jc3.get("foo"); - } - } - - @Test - public void connectWithCustomSocketFactory() { - try (RedisClusterClient jc = RedisClusterClient.builder() - .nodes(Collections.singleton(tlsEndpoint.getHostAndPort())) - .clientConfig(DefaultJedisClientConfig.builder().user("default").password(tlsEndpoint.getPassword()).ssl(true) - .sslSocketFactory(sslSocketFactoryForEnv(tlsEndpoint.getCertificatesLocation())) - .hostAndPortMapper(portMap).build()) - .maxAttempts(DEFAULT_REDIRECTIONS) - .poolConfig(DEFAULT_POOL_CONFIG) - .build()) { - assertEquals(3, jc.getClusterNodes().size()); - } - } - - @Test - public void connectWithEmptyTrustStore() throws Exception { - try (RedisClusterClient jc = RedisClusterClient.builder() - .nodes(Collections.singleton(tlsEndpoint.getHostAndPort())) - .clientConfig(DefaultJedisClientConfig.builder().user("default").password(tlsEndpoint.getPassword()).ssl(true) - .sslSocketFactory(createTrustNoOneSslSocketFactory()).build()) - .maxAttempts(DEFAULT_REDIRECTIONS) - .poolConfig(DEFAULT_POOL_CONFIG) - .build()) { -// jc.get("key"); -// Assert.fail("There should be no reachable node in cluster."); -//// } catch (JedisNoReachableClusterNodeException e) { - } catch (JedisClusterOperationException e) { -// assertEquals("No reachable node in cluster.", e.getMessage()); - assertEquals("Could not initialize cluster slots cache.", e.getMessage()); - } - } - - @Test - public void defaultHostAndPortUsedIfMapReturnsNull() { - HostAndPortMapper nullHostAndPortMap = (HostAndPort hostAndPort) -> null; - - try (RedisClusterClient jc = RedisClusterClient.builder() - .nodes(Collections.singleton(new HostAndPort("localhost", nodeInfo1.getPort()))) - .clientConfig(DefaultJedisClientConfig.builder().user("default").password(endpoint.getPassword()).ssl(false) - .hostAndPortMapper(nullHostAndPortMap).build()) - .maxAttempts(DEFAULT_REDIRECTIONS) - .poolConfig(DEFAULT_POOL_CONFIG) - .build()) { - Map clusterNodes = jc.getClusterNodes(); - assertEquals(3, clusterNodes.size()); - assertTrue(clusterNodes.containsKey(nodeInfo1.toString())); - assertTrue(clusterNodes.containsKey(nodeInfo2.toString())); - assertTrue(clusterNodes.containsKey(nodeInfo3.toString())); - } - } -} diff --git a/src/test/java/redis/clients/jedis/SSLJedisSentinelPoolTest.java b/src/test/java/redis/clients/jedis/SSLJedisSentinelPoolTest.java deleted file mode 100644 index 060b5df797..0000000000 --- a/src/test/java/redis/clients/jedis/SSLJedisSentinelPoolTest.java +++ /dev/null @@ -1,112 +0,0 @@ -package redis.clients.jedis; - -import java.nio.file.Path; -import java.nio.file.Paths; -import java.util.Collections; -import java.util.HashSet; -import java.util.List; -import java.util.Set; - -import org.apache.commons.pool2.impl.GenericObjectPoolConfig; -import org.junit.jupiter.api.AfterAll; -import org.junit.jupiter.api.BeforeAll; -import org.junit.jupiter.api.Tag; -import org.junit.jupiter.api.Test; -import redis.clients.jedis.util.TlsUtil; - -@Tag("integration") -public class SSLJedisSentinelPoolTest { - - private static EndpointConfig sentinel; - - private static final String MASTER_NAME = "aclmaster"; - - private static Set sentinels = new HashSet<>(); - - private static final HostAndPortMapper SSL_PORT_MAPPER = (HostAndPort hap) - -> new HostAndPort(hap.getHost(), hap.getPort() + 10000); - - private static final HostAndPortMapper SSL_PORT_MAPPER_PRIMARY = (HostAndPort hap) - -> new HostAndPort(hap.getHost(), hap.getPort() + 11); - - private static final GenericObjectPoolConfig POOL_CONFIG = new GenericObjectPoolConfig<>(); - private static final String trustStoreName = SSLJedisSentinelPoolTest.class.getSimpleName(); - - @BeforeAll - public static void prepare() { - sentinel = Endpoints.getRedisEndpoint("sentinel-standalone0"); - List trustedCertLocation = Collections.singletonList(Paths.get("redis1-2-5-8-sentinel/work/tls")); - Path trustStorePath = TlsUtil.createAndSaveTestTruststore(trustStoreName, trustedCertLocation,"changeit"); - TlsUtil.setCustomTrustStore(trustStorePath, "changeit"); - - sentinels.add(sentinel.getHostAndPort()); - } - - @AfterAll - public static void teardownTrustStore() { - TlsUtil.restoreOriginalTrustStore(); - } - - @Test - public void sentinelWithoutSslConnectsToRedisWithSsl() { - - DefaultJedisClientConfig masterConfig = Endpoints.getRedisEndpoint("standalone0-acl-tls") - .getClientConfigBuilder().clientName("master-client").hostAndPortMapper(SSL_PORT_MAPPER_PRIMARY) - .build(); - - DefaultJedisClientConfig sentinelConfig = sentinel.getClientConfigBuilder() - .clientName("sentinel-client").build(); - - try (JedisSentinelPool pool = new JedisSentinelPool(MASTER_NAME, sentinels, masterConfig, - sentinelConfig)) { - pool.getResource().close(); - } - - try (JedisSentinelPool pool = new JedisSentinelPool(MASTER_NAME, sentinels, POOL_CONFIG, - masterConfig, sentinelConfig)) { - pool.getResource().close(); - } - } - - @Test - public void sentinelWithSslConnectsToRedisWithoutSsl() { - - DefaultJedisClientConfig masterConfig = Endpoints.getRedisEndpoint("standalone0-acl") - .getClientConfigBuilder().clientName("master-client").build(); - - DefaultJedisClientConfig sentinelConfig = Endpoints.getRedisEndpoint( - "sentinel-standalone0-tls").getClientConfigBuilder().clientName("sentinel-client") - .hostAndPortMapper(SSL_PORT_MAPPER).build(); - - try (JedisSentinelPool pool = new JedisSentinelPool(MASTER_NAME, sentinels, masterConfig, sentinelConfig)) { - pool.getResource().close(); - } - - try (JedisSentinelPool pool = new JedisSentinelPool(MASTER_NAME, sentinels, POOL_CONFIG, - masterConfig, sentinelConfig)) { - pool.getResource().close(); - } - } - - @Test - public void sentinelWithSslConnectsToRedisWithSsl() { - - DefaultJedisClientConfig masterConfig = Endpoints.getRedisEndpoint("standalone0-acl-tls") - .getClientConfigBuilder().clientName("master-client").hostAndPortMapper(SSL_PORT_MAPPER_PRIMARY) - .build(); - - DefaultJedisClientConfig sentinelConfig = Endpoints.getRedisEndpoint( - "sentinel-standalone0-tls").getClientConfigBuilder().clientName("sentinel-client") - .hostAndPortMapper(SSL_PORT_MAPPER).build(); - - try (JedisSentinelPool pool = new JedisSentinelPool(MASTER_NAME, sentinels, masterConfig, sentinelConfig)) { - pool.getResource().close(); - } - - try (JedisSentinelPool pool = new JedisSentinelPool(MASTER_NAME, sentinels, POOL_CONFIG, - masterConfig, sentinelConfig)) { - pool.getResource().close(); - } - } - -} diff --git a/src/test/java/redis/clients/jedis/SSLOptionsJedisSentinelPoolTest.java b/src/test/java/redis/clients/jedis/SSLOptionsJedisSentinelPoolTest.java deleted file mode 100644 index 5c5bbae4ab..0000000000 --- a/src/test/java/redis/clients/jedis/SSLOptionsJedisSentinelPoolTest.java +++ /dev/null @@ -1,111 +0,0 @@ -package redis.clients.jedis; - -import java.nio.file.Path; -import java.nio.file.Paths; -import java.util.Collections; -import java.util.HashSet; -import java.util.List; -import java.util.Set; - -import org.apache.commons.pool2.impl.GenericObjectPoolConfig; -import org.junit.jupiter.api.BeforeAll; -import org.junit.jupiter.api.Tag; -import org.junit.jupiter.api.Test; -import redis.clients.jedis.util.TlsUtil; - -@Tag("integration") -public class SSLOptionsJedisSentinelPoolTest { - - private static EndpointConfig sentinel; - - private static final String MASTER_NAME = "aclmaster"; - - private static Set sentinels = new HashSet<>(); - - private static final HostAndPortMapper SSL_PORT_MAPPER = (HostAndPort hap) - -> new HostAndPort(hap.getHost(), hap.getPort() + 10000); - - private static final HostAndPortMapper SSL_PORT_MAPPER_PRIMARY = (HostAndPort hap) - -> new HostAndPort(hap.getHost(), hap.getPort() + 11); - - private static final GenericObjectPoolConfig POOL_CONFIG = new GenericObjectPoolConfig<>(); - - private static final String trustStoreName = SSLOptionsJedisSentinelPoolTest.class.getSimpleName(); - private static Path trustStorePath; - private static SslOptions sslOptions; - - @BeforeAll - public static void prepare() { - sentinel = Endpoints.getRedisEndpoint("sentinel-standalone0"); - List trustedCertLocation = Collections.singletonList(Paths.get("redis1-2-5-8-sentinel/work/tls")); - trustStorePath = TlsUtil.createAndSaveTestTruststore(trustStoreName, trustedCertLocation,"changeit"); - sslOptions = SslOptions.builder() - .truststore(trustStorePath.toFile()) - .trustStoreType("jceks") - .sslVerifyMode(SslVerifyMode.CA).build(); - - sentinels.add(sentinel.getHostAndPort()); - } - - @Test - public void sentinelWithoutSslConnectsToRedisWithSsl() { - - DefaultJedisClientConfig masterConfig = Endpoints.getRedisEndpoint("standalone0-acl-tls") - .getClientConfigBuilder().clientName("master-client").sslOptions(sslOptions) - .hostAndPortMapper(SSL_PORT_MAPPER_PRIMARY).build(); - - DefaultJedisClientConfig sentinelConfig = sentinel.getClientConfigBuilder() - .clientName("sentinel-client").build(); - - try (JedisSentinelPool pool = new JedisSentinelPool(MASTER_NAME, sentinels, masterConfig, sentinelConfig)) { - pool.getResource().close(); - } - - try (JedisSentinelPool pool = new JedisSentinelPool(MASTER_NAME, sentinels, POOL_CONFIG, - masterConfig, sentinelConfig)) { - pool.getResource().close(); - } - } - - @Test - public void sentinelWithSslConnectsToRedisWithoutSsl() { - - DefaultJedisClientConfig masterConfig = Endpoints.getRedisEndpoint("standalone0-acl") - .getClientConfigBuilder().clientName("master-client").build(); - - DefaultJedisClientConfig sentinelConfig = Endpoints.getRedisEndpoint( - "sentinel-standalone0-tls").getClientConfigBuilder().sslOptions(sslOptions) - .hostAndPortMapper(SSL_PORT_MAPPER).build(); - - try (JedisSentinelPool pool = new JedisSentinelPool(MASTER_NAME, sentinels, masterConfig, sentinelConfig)) { - pool.getResource().close(); - } - - try (JedisSentinelPool pool = new JedisSentinelPool(MASTER_NAME, sentinels, POOL_CONFIG, - masterConfig, sentinelConfig)) { - pool.getResource().close(); - } - } - - @Test - public void sentinelWithSslConnectsToRedisWithSsl() { - - DefaultJedisClientConfig masterConfig = Endpoints.getRedisEndpoint("standalone0-acl-tls") - .getClientConfigBuilder().clientName("master-client").sslOptions(sslOptions) - .hostAndPortMapper(SSL_PORT_MAPPER_PRIMARY).build(); - - DefaultJedisClientConfig sentinelConfig = Endpoints.getRedisEndpoint( - "sentinel-standalone0-tls").getClientConfigBuilder().clientName("sentinel-client") - .sslOptions(sslOptions).hostAndPortMapper(SSL_PORT_MAPPER).build(); - - try (JedisSentinelPool pool = new JedisSentinelPool(MASTER_NAME, sentinels, masterConfig, sentinelConfig)) { - pool.getResource().close(); - } - - try (JedisSentinelPool pool = new JedisSentinelPool(MASTER_NAME, sentinels, POOL_CONFIG, - masterConfig, sentinelConfig)) { - pool.getResource().close(); - } - } - -} diff --git a/src/test/java/redis/clients/jedis/SSLOptionsJedisTest.java b/src/test/java/redis/clients/jedis/SSLOptionsJedisTest.java deleted file mode 100644 index bd1c012e10..0000000000 --- a/src/test/java/redis/clients/jedis/SSLOptionsJedisTest.java +++ /dev/null @@ -1,91 +0,0 @@ -package redis.clients.jedis; - -import org.junit.jupiter.api.BeforeAll; -import org.junit.jupiter.api.Test; -import org.junit.jupiter.api.Tag; -import redis.clients.jedis.util.TlsUtil; - -import java.nio.file.Path; -import java.util.Arrays; -import java.util.List; - -import static org.junit.jupiter.api.Assertions.assertEquals; - -@Tag("integration") -public class SSLOptionsJedisTest { - - protected static EndpointConfig endpoint; - - protected static EndpointConfig aclEndpoint; - - private static final String trustStoreName = SSLOptionsJedisTest.class.getSimpleName(); - private static Path trustStorePath; - @BeforeAll - public static void prepare() { - endpoint = Endpoints.getRedisEndpoint("standalone0-tls"); - aclEndpoint = Endpoints.getRedisEndpoint("standalone0-acl-tls"); - List trustedCertLocation = Arrays.asList(endpoint.getCertificatesLocation(),aclEndpoint.getCertificatesLocation()); - trustStorePath = TlsUtil.createAndSaveTestTruststore(trustStoreName, trustedCertLocation,"changeit"); - } - - @Test - public void connectWithSsl() { - try (Jedis jedis = new Jedis(endpoint.getHostAndPort(), - DefaultJedisClientConfig.builder() - .sslOptions(SslOptions.builder() - .truststore(trustStorePath.toFile()) - .trustStoreType("jceks") - .build()).build())) { - jedis.auth(endpoint.getPassword()); - assertEquals("PONG", jedis.ping()); - } - } - - @Test - public void connectWithClientConfig() { - try (Jedis jedis = new Jedis(endpoint.getHostAndPort(), - endpoint.getClientConfigBuilder() - .sslOptions(SslOptions.builder() - .truststore(trustStorePath.toFile()) - .trustStoreType("jceks") - .build()).build())) { - assertEquals("PONG", jedis.ping()); - } - } - - @Test - public void connectWithSslInsecure() { - try (Jedis jedis = new Jedis(endpoint.getHostAndPort(), - endpoint.getClientConfigBuilder() - .sslOptions(SslOptions.builder() - .sslVerifyMode(SslVerifyMode.INSECURE) - .build()).build())) { - assertEquals("PONG", jedis.ping()); - } - } - - @Test - public void connectWithSslContextProtocol() { - try (Jedis jedis = new Jedis(endpoint.getHostAndPort(), - endpoint.getClientConfigBuilder() - .sslOptions(SslOptions.builder() - .sslProtocol("SSL") - .truststore(trustStorePath.toFile()) - .trustStoreType("jceks") - .build()).build())) { - assertEquals("PONG", jedis.ping()); - } - } - - @Test - public void connectWithAcl() { - try (Jedis jedis = new Jedis(aclEndpoint.getHostAndPort(), - aclEndpoint.getClientConfigBuilder() - .sslOptions(SslOptions.builder() - .truststore(trustStorePath.toFile()) - .trustStoreType("jceks") - .build()).build())) { - assertEquals("PONG", jedis.ping()); - } - } -} diff --git a/src/test/java/redis/clients/jedis/SSLOptionsRedisClientTest.java b/src/test/java/redis/clients/jedis/SSLOptionsRedisClientTest.java deleted file mode 100644 index 2522b0f7c6..0000000000 --- a/src/test/java/redis/clients/jedis/SSLOptionsRedisClientTest.java +++ /dev/null @@ -1,89 +0,0 @@ -package redis.clients.jedis; - -import org.junit.jupiter.api.BeforeAll; -import org.junit.jupiter.api.Test; -import org.junit.jupiter.api.Tag; -import redis.clients.jedis.util.TlsUtil; - -import java.nio.file.Path; -import java.util.Arrays; -import java.util.List; - -import static org.junit.jupiter.api.Assertions.assertEquals; - -@Tag("integration") -public class SSLOptionsRedisClientTest { - - protected static EndpointConfig endpoint; - - protected static EndpointConfig aclEndpoint; - - private static final String trustStoreName = SSLACLJedisTest.class.getSimpleName(); - private static Path trustStorePath; - - @BeforeAll - public static void prepare() { - endpoint = Endpoints.getRedisEndpoint("standalone0-tls"); - aclEndpoint = Endpoints.getRedisEndpoint("standalone0-acl-tls"); - List trustedCertLocation = Arrays.asList(endpoint.getCertificatesLocation(), - aclEndpoint.getCertificatesLocation()); - trustStorePath = TlsUtil.createAndSaveTestTruststore(trustStoreName, trustedCertLocation, - "changeit"); - } - - @Test - public void connectWithClientConfig() { - try (RedisClient jedis = RedisClient.builder() - .hostAndPort(endpoint.getHostAndPort()) - .clientConfig(endpoint.getClientConfigBuilder() - .sslOptions(SslOptions.builder() - .truststore(trustStorePath.toFile()) - .trustStoreType("jceks") - .build()).build()) - .build()) { - assertEquals("PONG", jedis.ping()); - } - } - - @Test - public void connectWithSslInsecure() { - try (RedisClient jedis = RedisClient.builder() - .hostAndPort(endpoint.getHostAndPort()) - .clientConfig(endpoint.getClientConfigBuilder() - .sslOptions(SslOptions.builder() - .sslVerifyMode(SslVerifyMode.INSECURE) - .build()).build()) - .build()) { - assertEquals("PONG", jedis.ping()); - } - } - - @Test - public void connectWithSslContextProtocol() { - try (RedisClient jedis = RedisClient.builder() - .hostAndPort(endpoint.getHostAndPort()) - .clientConfig(endpoint.getClientConfigBuilder() - .sslOptions(SslOptions.builder() - .sslProtocol("SSL") - .truststore(trustStorePath.toFile()) - .trustStoreType("jceks") - .build()).build()) - .build()) { - assertEquals("PONG", jedis.ping()); - } - } - - @Test - public void connectWithAcl() { - try (RedisClient jedis = RedisClient.builder() - .hostAndPort(aclEndpoint.getHostAndPort()) - .clientConfig(aclEndpoint.getClientConfigBuilder() - .sslOptions(SslOptions.builder() - .truststore(trustStorePath.toFile()) - .trustStoreType("jceks") - .build()).build()) - .build()) { - assertEquals("PONG", jedis.ping()); - } - } -} diff --git a/src/test/java/redis/clients/jedis/SSLOptionsRedisClusterClientTest.java b/src/test/java/redis/clients/jedis/SSLOptionsRedisClusterClientTest.java deleted file mode 100644 index 79ef4238cf..0000000000 --- a/src/test/java/redis/clients/jedis/SSLOptionsRedisClusterClientTest.java +++ /dev/null @@ -1,260 +0,0 @@ -package redis.clients.jedis; - -import java.nio.file.Path; -import java.util.Collections; -import java.util.List; -import java.util.Map; -import javax.net.ssl.HostnameVerifier; -import javax.net.ssl.SSLParameters; - -import io.redis.test.annotations.SinceRedisVersion; -import io.redis.test.utils.RedisVersion; - -import org.junit.jupiter.api.BeforeAll; -import org.junit.jupiter.api.Test; -import org.junit.jupiter.api.Tag; -import redis.clients.jedis.exceptions.JedisClusterOperationException; -import redis.clients.jedis.util.RedisVersionUtil; -import redis.clients.jedis.util.TlsUtil; - -import static org.hamcrest.MatcherAssert.assertThat; -import static org.hamcrest.Matchers.anyOf; -import static org.hamcrest.Matchers.containsString; -import static org.junit.jupiter.api.Assertions.assertEquals; -import static org.junit.jupiter.api.Assertions.assertTrue; -import static org.junit.jupiter.api.Assertions.fail; - -@SinceRedisVersion(value = "7.0.0", message = "Redis 6.2.x returns non-tls port in CLUSTER SLOTS command. Enable for 6.2.x after test is fixed.") -@Tag("integration") -public class SSLOptionsRedisClusterClientTest extends RedisClusterClientTestBase { - - private static final int DEFAULT_REDIRECTIONS = 5; - private static final ConnectionPoolConfig DEFAULT_POOL_CONFIG = new ConnectionPoolConfig(); - - protected static EndpointConfig tlsEndpoint; - - private final HostAndPortMapper hostAndPortMap = (HostAndPort hostAndPort) -> { - String host = hostAndPort.getHost(); - int port = hostAndPort.getPort(); - if (host.equals("127.0.0.1")) { - host = "localhost"; - } - return new HostAndPort(host, port); - }; - - // don't map IP addresses so that we try to connect with host 127.0.0.1 - private final HostAndPortMapper portMap = (HostAndPort hostAndPort) -> { - if ("localhost".equals(hostAndPort.getHost())) { - return hostAndPort; - } - return new HostAndPort(hostAndPort.getHost(), hostAndPort.getPort()); - }; - - private static final String trustStoreName = SSLOptionsRedisClusterClientTest.class.getSimpleName(); - private static Path trustStorePath; - - @BeforeAll - public static void prepare() { - tlsEndpoint = Endpoints.getRedisEndpoint("cluster-unbound-tls"); - List trustedCertLocation = Collections.singletonList(tlsEndpoint.getCertificatesLocation()); - trustStorePath = TlsUtil.createAndSaveTestTruststore(trustStoreName, trustedCertLocation,"changeit"); - } - - @Test - public void testSSLDiscoverNodesAutomatically() { - try (RedisClusterClient jc2 = RedisClusterClient.builder() - .nodes(Collections.singleton(tlsEndpoint.getHostAndPort())) - .clientConfig(DefaultJedisClientConfig.builder().password(tlsEndpoint.getPassword()) - .sslOptions(SslOptions.builder() - .truststore(trustStorePath.toFile()) - .trustStoreType("jceks").build()) - .hostAndPortMapper(hostAndPortMap).build()) - .maxAttempts(DEFAULT_REDIRECTIONS) - .poolConfig(DEFAULT_POOL_CONFIG) - .build()) { - Map clusterNodes = jc2.getClusterNodes(); - assertEquals(3, clusterNodes.size()); - /* - * In versions prior to Redis 7.x, Redis does not natively support automatic port switching between TLS and non-TLS ports for CLUSTER SLOTS. - * When using Redis 6.2.16 in a cluster mode with TLS, CLUSTER command returns the regular (non-TLS) port rather than the TLS port. - */ - if (RedisVersionUtil.getRedisVersion(jc2.getConnectionFromSlot(0)).isLessThanOrEqualTo(RedisVersion.V7_0_0)) { - assertTrue(clusterNodes.containsKey(nodeInfo1.toString())); - assertTrue(clusterNodes.containsKey(nodeInfo2.toString())); - assertTrue(clusterNodes.containsKey(nodeInfo3.toString())); - } else { - assertTrue(clusterNodes.containsKey(tlsEndpoint.getHostAndPort(0).toString())); - assertTrue(clusterNodes.containsKey(tlsEndpoint.getHostAndPort(1).toString())); - assertTrue(clusterNodes.containsKey(tlsEndpoint.getHostAndPort(2).toString())); - } - jc2.get("foo"); - } - } - - @Test - public void testSSLWithoutPortMap() { - try (RedisClusterClient jc = RedisClusterClient.builder() - .nodes(Collections.singleton(tlsEndpoint.getHostAndPort())) - .clientConfig(DefaultJedisClientConfig.builder().password(tlsEndpoint.getPassword()) - .sslOptions(SslOptions.builder() - .truststore(trustStorePath.toFile()) - .trustStoreType("jceks") - .sslVerifyMode(SslVerifyMode.CA).build()) - .build()) - .maxAttempts(DEFAULT_REDIRECTIONS) - .poolConfig(DEFAULT_POOL_CONFIG) - .build()) { - Map clusterNodes = jc.getClusterNodes(); - assertEquals(3, clusterNodes.size()); - /** - * In versions prior to Redis 7.x, Redis does not natively support automatic port switching between TLS and non-TLS ports for CLUSTER SLOTS. - * When using Redis 6.2.16 in a cluster mode with TLS, CLUSTER command returns the regular (non-TLS) port rather than the TLS port. - */ - if (RedisVersionUtil.getRedisVersion(jc.getConnectionFromSlot(0)).isLessThanOrEqualTo(RedisVersion.V7_0_0)) { - assertTrue(clusterNodes.containsKey(nodeInfo1.toString())); - assertTrue(clusterNodes.containsKey(nodeInfo2.toString())); - assertTrue(clusterNodes.containsKey(nodeInfo3.toString())); - } else { - assertTrue(clusterNodes.containsKey(tlsEndpoint.getHostAndPort(0).toString())); - assertTrue(clusterNodes.containsKey(tlsEndpoint.getHostAndPort(1).toString())); - assertTrue(clusterNodes.containsKey(tlsEndpoint.getHostAndPort(2).toString())); - } - } - } - - @Test - public void connectByIpAddress() { - try (RedisClusterClient jc = RedisClusterClient.builder() - .nodes(Collections.singleton(tlsEndpoint.getHostAndPort())) - .clientConfig(DefaultJedisClientConfig.builder().password(tlsEndpoint.getPassword()) - .sslOptions(SslOptions.builder() - .truststore(trustStorePath.toFile()) - .trustStoreType("jceks").build()) - .hostAndPortMapper(hostAndPortMap).build()) - .maxAttempts(DEFAULT_REDIRECTIONS) - .poolConfig(DEFAULT_POOL_CONFIG) - .build()) { - jc.get("foo"); - } - } - - @Test - public void connectToNodesFailsWithSSLParametersAndNoHostMapping() { - final SSLParameters sslParameters = new SSLParameters(); - sslParameters.setEndpointIdentificationAlgorithm("HTTPS"); - - try (RedisClusterClient jc = RedisClusterClient.builder() - .nodes(Collections.singleton(new HostAndPort("localhost", tlsEndpoint.getPort()))) - .clientConfig(DefaultJedisClientConfig.builder().password(tlsEndpoint.getPassword()) - .sslOptions(SslOptions.builder() - .sslParameters(sslParameters) - .truststore(trustStorePath.toFile()) - .trustStoreType("jceks").build()) - .hostAndPortMapper(portMap).build()) - .maxAttempts(DEFAULT_REDIRECTIONS) - .poolConfig(DEFAULT_POOL_CONFIG) - .build()) { - jc.get("foo"); - fail("It should fail after all cluster attempts."); - } catch (JedisClusterOperationException e) { - // initial connection to localhost works, but subsequent connections to nodes use 127.0.0.1 - // and fail hostname verification - assertThat(e.getMessage(), anyOf( - containsString("No more cluster attempts left."), - containsString("Cluster retry deadline exceeded.") - )); - } - } - - @Test - public void connectToNodesSucceedsWithSSLParametersAndHostMapping() { - final SSLParameters sslParameters = new SSLParameters(); - sslParameters.setEndpointIdentificationAlgorithm("HTTPS"); - - try (RedisClusterClient jc = RedisClusterClient.builder() - .nodes(Collections.singleton(tlsEndpoint.getHostAndPort())) - .clientConfig(DefaultJedisClientConfig.builder().password(tlsEndpoint.getPassword()) - .sslOptions(SslOptions.builder() - .sslParameters(sslParameters) - .truststore(trustStorePath.toFile()) - .trustStoreType("jceks").build()) - .hostAndPortMapper(hostAndPortMap).build()) - .maxAttempts(DEFAULT_REDIRECTIONS) - .poolConfig(DEFAULT_POOL_CONFIG) - .build()) { - jc.get("foo"); - } - } - - @Test - public void connectByIpAddressFailsWithSSLParameters() { - final SSLParameters sslParameters = new SSLParameters(); - sslParameters.setEndpointIdentificationAlgorithm("HTTPS"); - - try (RedisClusterClient jc = RedisClusterClient.builder() - .nodes(Collections.singleton(tlsEndpoint.getHostAndPort())) - .clientConfig(DefaultJedisClientConfig.builder().password(tlsEndpoint.getPassword()) - .sslOptions(SslOptions.builder() - .sslParameters(sslParameters) - .truststore(trustStorePath.toFile()) - .trustStoreType("jceks").build()) - .hostAndPortMapper(hostAndPortMap).build()) - .maxAttempts(DEFAULT_REDIRECTIONS) - .poolConfig(DEFAULT_POOL_CONFIG) - .build()) { - } catch (JedisClusterOperationException e) { - assertEquals("Could not initialize cluster slots cache.", e.getMessage()); - } - } - - @Test - public void connectWithCustomHostNameVerifier() { - HostnameVerifier hostnameVerifier = new TlsUtil.BasicHostnameVerifier(); - HostnameVerifier localhostVerifier = new TlsUtil.LocalhostVerifier(); - - SslOptions sslOptions = SslOptions.builder() - .truststore(trustStorePath.toFile()) - .trustStoreType("jceks") - .sslVerifyMode(SslVerifyMode.CA).build(); - - try (RedisClusterClient jc = RedisClusterClient.builder() - .nodes(Collections.singleton(new HostAndPort("localhost", tlsEndpoint.getPort()))) - .clientConfig(DefaultJedisClientConfig.builder().password(tlsEndpoint.getPassword()).sslOptions(sslOptions) - .hostnameVerifier(hostnameVerifier).hostAndPortMapper(portMap).build()) - .maxAttempts(DEFAULT_REDIRECTIONS) - .poolConfig(DEFAULT_POOL_CONFIG) - .build()) { - jc.get("foo"); - fail("It should fail after all cluster attempts."); - } catch (JedisClusterOperationException e) { - // initial connection made with 'localhost' but subsequent connections to nodes use 127.0.0.1 - // which causes custom hostname verification to fail - assertThat(e.getMessage(), anyOf( - containsString("No more cluster attempts left."), - containsString("Cluster retry deadline exceeded.") - )); - } - - try (RedisClusterClient jc2 = RedisClusterClient.builder() - .nodes(Collections.singleton(new HostAndPort("127.0.0.1", tlsEndpoint.getPort()))) - .clientConfig(DefaultJedisClientConfig.builder().password(tlsEndpoint.getPassword()).sslOptions(sslOptions) - .hostnameVerifier(hostnameVerifier).hostAndPortMapper(portMap).build()) - .maxAttempts(DEFAULT_REDIRECTIONS) - .poolConfig(DEFAULT_POOL_CONFIG) - .build()) { - } catch (JedisClusterOperationException e) { - assertEquals("Could not initialize cluster slots cache.", e.getMessage()); - } - - try (RedisClusterClient jc3 = RedisClusterClient.builder() - .nodes(Collections.singleton(tlsEndpoint.getHostAndPort())) - .clientConfig(DefaultJedisClientConfig.builder().password(tlsEndpoint.getPassword()).sslOptions(sslOptions) - .hostnameVerifier(localhostVerifier).hostAndPortMapper(portMap).build()) - .maxAttempts(DEFAULT_REDIRECTIONS) - .poolConfig(DEFAULT_POOL_CONFIG) - .build()) { - jc3.get("foo"); - } - } - -} diff --git a/src/test/java/redis/clients/jedis/SSLRedisClusterClientTest.java b/src/test/java/redis/clients/jedis/SSLRedisClusterClientTest.java deleted file mode 100644 index 213d5389b0..0000000000 --- a/src/test/java/redis/clients/jedis/SSLRedisClusterClientTest.java +++ /dev/null @@ -1,317 +0,0 @@ -package redis.clients.jedis; - -import static org.hamcrest.MatcherAssert.assertThat; -import static org.hamcrest.Matchers.anyOf; -import static org.hamcrest.Matchers.containsString; -import static org.junit.jupiter.api.Assertions.assertEquals; -import static org.junit.jupiter.api.Assertions.assertTrue; -import static org.junit.jupiter.api.Assertions.fail; -import static redis.clients.jedis.util.TlsUtil.*; - -import java.nio.file.Path; -import java.util.Collections; -import java.util.List; -import java.util.Map; -import javax.net.ssl.HostnameVerifier; -import javax.net.ssl.SSLParameters; - -import io.redis.test.annotations.SinceRedisVersion; -import io.redis.test.utils.RedisVersion; -import org.junit.jupiter.api.AfterAll; -import org.junit.jupiter.api.BeforeAll; -import org.junit.jupiter.api.Test; -import org.junit.jupiter.api.Tag; -import redis.clients.jedis.util.RedisVersionUtil; -import redis.clients.jedis.util.TlsUtil; - -import redis.clients.jedis.exceptions.JedisClusterOperationException; - -@SinceRedisVersion(value = "7.0.0", message = "Redis 6.2.x returns non-tls port in CLUSTER SLOTS command. Enable for 6.2.x after test is fixed.") -@Tag("integration") -public class SSLRedisClusterClientTest extends RedisClusterClientTestBase { - - private static final int DEFAULT_REDIRECTIONS = 5; - private static final ConnectionPoolConfig DEFAULT_POOL_CONFIG = new ConnectionPoolConfig(); - - protected static EndpointConfig tlsEndpoint; - - private final HostAndPortMapper hostAndPortMap = (HostAndPort hostAndPort) -> { - String host = hostAndPort.getHost(); - int port = hostAndPort.getPort(); - if (host.equals("127.0.0.1")) { - host = "localhost"; - } - return new HostAndPort(host, port); - }; - - // don't map IP addresses so that we try to connect with host 127.0.0.1 - private final HostAndPortMapper portMap = (HostAndPort hostAndPort) -> { - if ("localhost".equals(hostAndPort.getHost())) { - return hostAndPort; - } - return new HostAndPort(hostAndPort.getHost(), hostAndPort.getPort()); - }; - - private static final String trustStoreName = SSLRedisClusterClientTest.class.getSimpleName(); - - @BeforeAll - public static void prepare() { - tlsEndpoint = Endpoints.getRedisEndpoint("cluster-unbound-tls"); - List trustedCertLocation = Collections.singletonList(tlsEndpoint.getCertificatesLocation()); - Path trustStorePath = TlsUtil.createAndSaveTestTruststore(trustStoreName, trustedCertLocation,"changeit"); - - TlsUtil.setCustomTrustStore(trustStorePath, "changeit"); - } - - @AfterAll - public static void teardownTrustStore() { - TlsUtil.restoreOriginalTrustStore(); - } - - @Test - public void testSSLDiscoverNodesAutomatically() { - try (RedisClusterClient jc = RedisClusterClient.builder() - .nodes(Collections.singleton(tlsEndpoint.getHostAndPort())) - .clientConfig(DefaultJedisClientConfig.builder().password(tlsEndpoint.getPassword()).ssl(true) - .hostAndPortMapper(hostAndPortMap).build()) - .maxAttempts(DEFAULT_REDIRECTIONS) - .poolConfig(DEFAULT_POOL_CONFIG) - .build()) { - Map clusterNodes = jc.getClusterNodes(); - assertEquals(3, clusterNodes.size()); - /** - * In versions prior to Redis 7.x, Redis does not natively support automatic port switching between TLS and - * non-TLS ports for CLUSTER SLOTS. When using Redis 6.2.16 in a cluster mode with TLS, CLUSTER command returns - * the regular (non-TLS) port rather than the TLS port. - */ - if (RedisVersionUtil.getRedisVersion(jc.getConnectionFromSlot(0)).isLessThanOrEqualTo(RedisVersion.V7_0_0)) { - assertTrue(clusterNodes.containsKey(nodeInfo1.toString())); - assertTrue(clusterNodes.containsKey(nodeInfo2.toString())); - assertTrue(clusterNodes.containsKey(nodeInfo3.toString())); - } else { - assertTrue(clusterNodes.containsKey(tlsEndpoint.getHostAndPort(0).toString())); - assertTrue(clusterNodes.containsKey(tlsEndpoint.getHostAndPort(1).toString())); - assertTrue(clusterNodes.containsKey(tlsEndpoint.getHostAndPort(2).toString())); - } - - jc.get("foo"); - } - - try (RedisClusterClient jc2 = RedisClusterClient.builder() - .nodes(Collections.singleton(tlsEndpoint.getHostAndPort())) - .clientConfig(DefaultJedisClientConfig.builder().password(tlsEndpoint.getPassword()).ssl(true) - .hostAndPortMapper(hostAndPortMap).build()) - .maxAttempts(DEFAULT_REDIRECTIONS) - .poolConfig(DEFAULT_POOL_CONFIG) - .build()) { - Map clusterNodes = jc2.getClusterNodes(); - assertEquals(3, clusterNodes.size()); - assertTrue(clusterNodes.containsKey(tlsEndpoint.getHostAndPort(0).toString())); - assertTrue(clusterNodes.containsKey(tlsEndpoint.getHostAndPort(1).toString())); - assertTrue(clusterNodes.containsKey(tlsEndpoint.getHostAndPort(2).toString())); - jc2.get("foo"); - } - } - - @Test - public void testSSLWithoutPortMap() { - try (RedisClusterClient jc = RedisClusterClient.builder() - .nodes(Collections.singleton(tlsEndpoint.getHostAndPort())) - .clientConfig(DefaultJedisClientConfig.builder().password(tlsEndpoint.getPassword()).ssl(true).build()) - .maxAttempts(DEFAULT_REDIRECTIONS) - .poolConfig(DEFAULT_POOL_CONFIG) - .build()) { - Map clusterNodes = jc.getClusterNodes(); - assertEquals(3, clusterNodes.size()); - /** - * In versions prior to Redis 7.x, Redis does not natively support automatic port switching between TLS and - * non-TLS ports for CLUSTER SLOTS. When using Redis 6.2.16 in a cluster mode with TLS, CLUSTER command returns - * the regular (non-TLS) port rather than the TLS port. - */ - if (RedisVersionUtil.getRedisVersion(jc.getConnectionFromSlot(0)).isLessThanOrEqualTo(RedisVersion.V7_0_0)) { - assertTrue(clusterNodes.containsKey(nodeInfo1.toString())); - assertTrue(clusterNodes.containsKey(nodeInfo2.toString())); - assertTrue(clusterNodes.containsKey(nodeInfo3.toString())); - } else { - assertTrue(clusterNodes.containsKey(tlsEndpoint.getHostAndPort(0).toString())); - assertTrue(clusterNodes.containsKey(tlsEndpoint.getHostAndPort(1).toString())); - assertTrue(clusterNodes.containsKey(tlsEndpoint.getHostAndPort(2).toString())); - } - } - } - - @Test - public void connectByIpAddress() { - try (RedisClusterClient jc = RedisClusterClient.builder() - .nodes(Collections.singleton(tlsEndpoint.getHostAndPort())) - .clientConfig(DefaultJedisClientConfig.builder().password(tlsEndpoint.getPassword()).ssl(true) - .hostAndPortMapper(hostAndPortMap).build()) - .maxAttempts(DEFAULT_REDIRECTIONS) - .poolConfig(DEFAULT_POOL_CONFIG) - .build()) { - jc.get("foo"); - } - } - - @Test - public void connectToNodesFailsWithSSLParametersAndNoHostMapping() { - final SSLParameters sslParameters = new SSLParameters(); - sslParameters.setEndpointIdentificationAlgorithm("HTTPS"); - - try (RedisClusterClient jc = RedisClusterClient.builder() - .nodes(Collections.singleton(new HostAndPort("localhost", tlsEndpoint.getPort()))) - .clientConfig(DefaultJedisClientConfig.builder().password(tlsEndpoint.getPassword()).ssl(true) - .sslParameters(sslParameters).hostAndPortMapper(portMap).build()) - .maxAttempts(DEFAULT_REDIRECTIONS) - .poolConfig(DEFAULT_POOL_CONFIG) - .build()) { - jc.get("foo"); - fail("It should fail after all cluster attempts."); - } catch (JedisClusterOperationException e) { - // initial connection to localhost works, but subsequent connections to nodes use 127.0.0.1 - // and fail hostname verification - assertThat(e.getMessage(), anyOf( - containsString("No more cluster attempts left."), - containsString("Cluster retry deadline exceeded.") - )); - } - } - - @Test - @SinceRedisVersion(value = "7.0.0", message = "Redis 6.2.x returns non-tls port in CLUSTER SLOTS command. Enable for 6.2.x after test is fixed.") - public void connectToNodesSucceedsWithSSLParametersAndHostMapping() { - final SSLParameters sslParameters = new SSLParameters(); - sslParameters.setEndpointIdentificationAlgorithm("HTTPS"); - - try (RedisClusterClient jc = RedisClusterClient.builder() - .nodes(Collections.singleton(tlsEndpoint.getHostAndPort())) - .clientConfig(DefaultJedisClientConfig.builder().password(tlsEndpoint.getPassword()).ssl(true) - .sslParameters(sslParameters).hostAndPortMapper(hostAndPortMap).build()) - .maxAttempts(DEFAULT_REDIRECTIONS) - .poolConfig(DEFAULT_POOL_CONFIG) - .build()) { - jc.get("foo"); - } - } - - @Test - public void connectByIpAddressFailsWithSSLParameters() { - final SSLParameters sslParameters = new SSLParameters(); - sslParameters.setEndpointIdentificationAlgorithm("HTTPS"); - - try (RedisClusterClient jc = RedisClusterClient.builder() - .nodes(Collections.singleton(tlsEndpoint.getHostAndPort())) - .clientConfig(DefaultJedisClientConfig.builder().password(tlsEndpoint.getPassword()).ssl(true) - .sslParameters(sslParameters).hostAndPortMapper(hostAndPortMap).build()) - .maxAttempts(DEFAULT_REDIRECTIONS) - .poolConfig(DEFAULT_POOL_CONFIG) - .build()) { -// jc.get("key"); -// Assert.fail("There should be no reachable node in cluster."); -//// } catch (JedisNoReachableClusterNodeException e) { - } catch (JedisClusterOperationException e) { -// assertEquals("No reachable node in cluster.", e.getMessage()); - assertEquals("Could not initialize cluster slots cache.", e.getMessage()); - } - } - - @Test - public void connectWithCustomHostNameVerifier() { - HostnameVerifier hostnameVerifier = new TlsUtil.BasicHostnameVerifier(); - HostnameVerifier localhostVerifier = new TlsUtil.LocalhostVerifier(); - - try (RedisClusterClient jc = RedisClusterClient.builder() - .nodes(Collections.singleton(new HostAndPort("localhost", tlsEndpoint.getPort()))) - .clientConfig(DefaultJedisClientConfig.builder().password(tlsEndpoint.getPassword()).ssl(true) - .hostnameVerifier(hostnameVerifier).hostAndPortMapper(portMap).build()) - .maxAttempts(DEFAULT_REDIRECTIONS) - .poolConfig(DEFAULT_POOL_CONFIG) - .build()) { - jc.get("foo"); - fail("It should fail after all cluster attempts."); -// } catch (JedisClusterMaxAttemptsException e) { - } catch (JedisClusterOperationException e) { - // initial connection made with 'localhost' but subsequent connections to nodes use 127.0.0.1 - // which causes custom hostname verification to fail - assertThat(e.getMessage(), anyOf( - containsString("No more cluster attempts left."), - containsString("Cluster retry deadline exceeded.") - )); - } - - try (RedisClusterClient jc2 = RedisClusterClient.builder() - .nodes(Collections.singleton(new HostAndPort("127.0.0.1", tlsEndpoint.getPort()))) - .clientConfig(DefaultJedisClientConfig.builder().password(tlsEndpoint.getPassword()).ssl(true) - .hostnameVerifier(hostnameVerifier).hostAndPortMapper(portMap).build()) - .maxAttempts(DEFAULT_REDIRECTIONS) - .poolConfig(DEFAULT_POOL_CONFIG) - .build()) { -// jc2.get("foo"); -// Assert.fail("There should be no reachable node in cluster."); -//// } catch (JedisNoReachableClusterNodeException e) { - } catch (JedisClusterOperationException e) { - // JedisNoReachableClusterNodeException exception occurs from not being able to connect - // since the socket factory fails the hostname verification -// assertEquals("No reachable node in cluster.", e.getMessage()); - assertEquals("Could not initialize cluster slots cache.", e.getMessage()); - } - - try (RedisClusterClient jc3 = RedisClusterClient.builder() - .nodes(Collections.singleton(tlsEndpoint.getHostAndPort())) - .clientConfig(DefaultJedisClientConfig.builder().password(tlsEndpoint.getPassword()).ssl(true) - .hostnameVerifier(localhostVerifier).hostAndPortMapper(portMap).build()) - .maxAttempts(DEFAULT_REDIRECTIONS) - .poolConfig(DEFAULT_POOL_CONFIG) - .build()) { - jc3.get("foo"); - } - } - - @Test - public void connectWithCustomSocketFactory() throws Exception { - try (RedisClusterClient jc = RedisClusterClient.builder() - .nodes(Collections.singleton(tlsEndpoint.getHostAndPort())) - .clientConfig(DefaultJedisClientConfig.builder().password(tlsEndpoint.getPassword()).ssl(true) - .sslSocketFactory(sslSocketFactoryForEnv(tlsEndpoint.getCertificatesLocation())) - .hostAndPortMapper(portMap).build()) - .maxAttempts(DEFAULT_REDIRECTIONS) - .poolConfig(DEFAULT_POOL_CONFIG) - .build()) { - assertEquals(3, jc.getClusterNodes().size()); - } - } - - @Test - public void connectWithEmptyTrustStore() throws Exception { - try (RedisClusterClient jc = RedisClusterClient.builder() - .nodes(Collections.singleton(tlsEndpoint.getHostAndPort())) - .clientConfig(DefaultJedisClientConfig.builder().password(tlsEndpoint.getPassword()).ssl(true) - .sslSocketFactory(createTrustNoOneSslSocketFactory()).build()) - .maxAttempts(DEFAULT_REDIRECTIONS) - .poolConfig(DEFAULT_POOL_CONFIG) - .build()) { - } catch (JedisClusterOperationException e) { - assertEquals("Could not initialize cluster slots cache.", e.getMessage()); - } - } - - @Test - public void defaultHostAndPortUsedIfMapReturnsNull() { - HostAndPortMapper nullHostAndPortMap = (HostAndPort hostAndPort) -> null; - - try (RedisClusterClient jc = RedisClusterClient.builder() - .nodes(Collections.singleton(new HostAndPort("localhost", nodeInfo1.getPort()))) - .clientConfig(DefaultJedisClientConfig.builder().password(endpoint.getPassword()).ssl(false) - .hostAndPortMapper(nullHostAndPortMap).build()) - .maxAttempts(DEFAULT_REDIRECTIONS) - .poolConfig(DEFAULT_POOL_CONFIG) - .build()) { - - Map clusterNodes = jc.getClusterNodes(); - assertEquals(3, clusterNodes.size()); - assertTrue(clusterNodes.containsKey(nodeInfo1.toString())); - assertTrue(clusterNodes.containsKey(nodeInfo2.toString())); - assertTrue(clusterNodes.containsKey(nodeInfo3.toString())); - } - } -} diff --git a/src/test/java/redis/clients/jedis/RedisClusterClientTest.java b/src/test/java/redis/clients/jedis/UnboundRedisClusterClientTest.java similarity index 99% rename from src/test/java/redis/clients/jedis/RedisClusterClientTest.java rename to src/test/java/redis/clients/jedis/UnboundRedisClusterClientTest.java index 86a81de88b..3b46c25f42 100644 --- a/src/test/java/redis/clients/jedis/RedisClusterClientTest.java +++ b/src/test/java/redis/clients/jedis/UnboundRedisClusterClientTest.java @@ -42,7 +42,7 @@ import redis.clients.jedis.util.Pool; @Tag("integration") -public class RedisClusterClientTest extends RedisClusterClientTestBase { +public class UnboundRedisClusterClientTest extends UnboundRedisClusterClientTestBase { private static final int DEFAULT_TIMEOUT = 2000; //sec private static final int DEFAULT_REDIRECTIONS = 5; diff --git a/src/test/java/redis/clients/jedis/RedisClusterClientTestBase.java b/src/test/java/redis/clients/jedis/UnboundRedisClusterClientTestBase.java similarity index 98% rename from src/test/java/redis/clients/jedis/RedisClusterClientTestBase.java rename to src/test/java/redis/clients/jedis/UnboundRedisClusterClientTestBase.java index 5989c92155..8adc218c29 100644 --- a/src/test/java/redis/clients/jedis/RedisClusterClientTestBase.java +++ b/src/test/java/redis/clients/jedis/UnboundRedisClusterClientTestBase.java @@ -13,7 +13,7 @@ import redis.clients.jedis.util.JedisClusterTestUtil; @Tag("integration") -public abstract class RedisClusterClientTestBase { +public abstract class UnboundRedisClusterClientTestBase { protected static EndpointConfig endpoint; diff --git a/src/test/java/redis/clients/jedis/commands/jedis/ClusterCommandsTest.java b/src/test/java/redis/clients/jedis/commands/jedis/ClusterCommandsTest.java index 806259593d..78d4296d3d 100644 --- a/src/test/java/redis/clients/jedis/commands/jedis/ClusterCommandsTest.java +++ b/src/test/java/redis/clients/jedis/commands/jedis/ClusterCommandsTest.java @@ -252,7 +252,6 @@ public void clusterShards() { assertNotNull(nodeInfo.getIp()); assertNull(nodeInfo.getHostname()); assertNotNull(nodeInfo.getPort()); - assertNotNull(nodeInfo.getTlsPort()); // currently we are always starting Redis server with `tls-port` assertNotNull(nodeInfo.getRole()); assertNotNull(nodeInfo.getReplicationOffset()); assertNotNull(nodeInfo.getHealth()); diff --git a/src/test/java/redis/clients/jedis/tls/ACLJedisIT.java b/src/test/java/redis/clients/jedis/tls/ACLJedisIT.java new file mode 100644 index 0000000000..04cd6c74b9 --- /dev/null +++ b/src/test/java/redis/clients/jedis/tls/ACLJedisIT.java @@ -0,0 +1,74 @@ +package redis.clients.jedis.tls; + +import static org.junit.jupiter.api.Assertions.assertEquals; + +import org.junit.jupiter.api.Test; + +import redis.clients.jedis.DefaultJedisClientConfig; +import redis.clients.jedis.Jedis; + +/** + * SSL/TLS tests for {@link Jedis} with ACL authentication (username + password). + *

+ * This test class focuses on testing the ssl(true) flag approach (using system truststore) with ACL + * credentials. + */ + +public class ACLJedisIT extends JedisTlsTestBase { + /** + * Tests SSL connection with explicit ACL credentials (username + password). + */ + @Test + public void connectWithSsl() { + try (Jedis jedis = new Jedis(aclEndpoint.getHost(), aclEndpoint.getPort(), true)) { + jedis.auth(aclEndpoint.getUsername(), aclEndpoint.getPassword()); + assertEquals("PONG", jedis.ping()); + } + } + + /** + * Tests SSL connection using DefaultJedisClientConfig with ACL credentials. + */ + @Test + public void connectWithConfig() { + try (Jedis jedis = new Jedis(aclEndpoint.getHostAndPort(), + DefaultJedisClientConfig.builder().ssl(true).build())) { + jedis.auth(aclEndpoint.getUsername(), aclEndpoint.getPassword()); + assertEquals("PONG", jedis.ping()); + } + } + + /** + * Tests SSL connection using URL with credentials. + */ + @Test + public void connectWithUrl() { + // The "rediss" scheme instructs jedis to open a SSL/TLS connection. + // Test with default user endpoint + try ( + Jedis jedis = new Jedis(endpoint.getURIBuilder().defaultCredentials().build().toString())) { + assertEquals("PONG", jedis.ping()); + } + // Test with ACL user endpoint + try (Jedis jedis = new Jedis( + aclEndpoint.getURIBuilder().defaultCredentials().build().toString())) { + assertEquals("PONG", jedis.ping()); + } + } + + /** + * Tests SSL connection using URI with credentials. + */ + @Test + public void connectWithUri() { + // The "rediss" scheme instructs jedis to open a SSL/TLS connection. + // Test with default user endpoint + try (Jedis jedis = new Jedis(endpoint.getURIBuilder().defaultCredentials().build())) { + assertEquals("PONG", jedis.ping()); + } + // Test with ACL user endpoint + try (Jedis jedis = new Jedis(aclEndpoint.getURIBuilder().defaultCredentials().build())) { + assertEquals("PONG", jedis.ping()); + } + } +} diff --git a/src/test/java/redis/clients/jedis/tls/ACLRedisClientIT.java b/src/test/java/redis/clients/jedis/tls/ACLRedisClientIT.java new file mode 100644 index 0000000000..67b0a7027c --- /dev/null +++ b/src/test/java/redis/clients/jedis/tls/ACLRedisClientIT.java @@ -0,0 +1,82 @@ +package redis.clients.jedis.tls; + +import static org.junit.jupiter.api.Assertions.assertEquals; + +import org.junit.jupiter.api.Test; + +import redis.clients.jedis.DefaultJedisClientConfig; +import redis.clients.jedis.RedisClient; + +/** + * SSL/TLS tests for {@link RedisClient} with ACL authentication (username + password). + *

+ * This test class focuses on testing the ssl(true) flag approach (using system truststore) with ACL + * credentials. + */ + +public class ACLRedisClientIT extends RedisClientTlsTestBase { + /** + * Tests SSL connection with explicit ACL credentials (username + password). + */ + @Test + public void connectWithSsl() { + try ( + RedisClient client = RedisClient.builder() + .hostAndPort(aclEndpoint.getHost(), aclEndpoint.getPort()) + .clientConfig(DefaultJedisClientConfig.builder().ssl(true) + .user(aclEndpoint.getUsername()).password(aclEndpoint.getPassword()).build()) + .build()) { + assertEquals("PONG", client.ping()); + } + } + + /** + * Tests SSL connection using endpoint's client config builder (credentials from endpoint). + */ + @Test + public void connectWithConfig() { + try ( + RedisClient client = RedisClient.builder().hostAndPort(aclEndpoint.getHostAndPort()) + .clientConfig(DefaultJedisClientConfig.builder().ssl(true) + .user(aclEndpoint.getUsername()).password(aclEndpoint.getPassword()).build()) + .build()) { + assertEquals("PONG", client.ping()); + } + } + + /** + * Tests SSL connection using URL with credentials. + */ + @Test + public void connectWithUrl() { + // The "rediss" scheme instructs jedis to open a SSL/TLS connection. + // Test with default user endpoint + try (RedisClient client = RedisClient + .create(endpoint.getURIBuilder().defaultCredentials().build().toString())) { + assertEquals("PONG", client.ping()); + } + // Test with ACL user endpoint + try (RedisClient client = RedisClient + .create(aclEndpoint.getURIBuilder().defaultCredentials().build().toString())) { + assertEquals("PONG", client.ping()); + } + } + + /** + * Tests SSL connection using URI with credentials. + */ + @Test + public void connectWithUri() { + // The "rediss" scheme instructs jedis to open a SSL/TLS connection. + // Test with default user endpoint + try (RedisClient client = RedisClient + .create(endpoint.getURIBuilder().defaultCredentials().build())) { + assertEquals("PONG", client.ping()); + } + // Test with ACL user endpoint + try (RedisClient client = RedisClient + .create(aclEndpoint.getURIBuilder().defaultCredentials().build())) { + assertEquals("PONG", client.ping()); + } + } +} diff --git a/src/test/java/redis/clients/jedis/tls/ACLRedisClusterClientIT.java b/src/test/java/redis/clients/jedis/tls/ACLRedisClusterClientIT.java new file mode 100644 index 0000000000..d67338de44 --- /dev/null +++ b/src/test/java/redis/clients/jedis/tls/ACLRedisClusterClientIT.java @@ -0,0 +1,196 @@ +package redis.clients.jedis.tls; + +import static org.hamcrest.MatcherAssert.assertThat; +import static org.hamcrest.Matchers.anyOf; +import static org.hamcrest.Matchers.containsString; +import static org.junit.jupiter.api.Assertions.assertEquals; +import static org.junit.jupiter.api.Assertions.assertTrue; +import static org.junit.jupiter.api.Assertions.fail; +import static redis.clients.jedis.util.TlsUtil.*; + +import java.util.Collections; +import java.util.Map; +import javax.net.ssl.HostnameVerifier; +import javax.net.ssl.SSLParameters; + +import org.junit.jupiter.api.Test; +import redis.clients.jedis.*; +import redis.clients.jedis.util.TlsUtil; +import redis.clients.jedis.exceptions.JedisClusterOperationException; + +/** + * SSL/TLS Redis Cluster tests with ACL authentication + */ +public class ACLRedisClusterClientIT extends RedisClusterTestBase { + + private static final int DEFAULT_REDIRECTIONS = 5; + private static final ConnectionPoolConfig DEFAULT_POOL_CONFIG = new ConnectionPoolConfig(); + + @Test + public void testSSLDiscoverNodesAutomatically() { + DefaultJedisClientConfig config = DefaultJedisClientConfig.builder().user("default") + .password(tlsEndpoint.getPassword()).ssl(true).hostAndPortMapper(hostAndPortMap).build(); + + try (RedisClusterClient jc = RedisClusterClient.builder() + .nodes(Collections.singleton(tlsEndpoint.getHostAndPort())).clientConfig(config) + .maxAttempts(DEFAULT_REDIRECTIONS).poolConfig(DEFAULT_POOL_CONFIG).build()) { + Map clusterNodes = jc.getClusterNodes(); + assertEquals(6, clusterNodes.size()); + assertTrue(clusterNodes.containsKey(tlsEndpoint.getHostAndPort(0).toString())); + assertTrue(clusterNodes.containsKey(tlsEndpoint.getHostAndPort(1).toString())); + assertTrue(clusterNodes.containsKey(tlsEndpoint.getHostAndPort(2).toString())); + jc.get("foo"); + } + } + + @Test + public void testSSLWithoutPortMap() { + try (RedisClusterClient jc = RedisClusterClient.builder() + .nodes(Collections.singleton(tlsEndpoint.getHostAndPort())) + .clientConfig(DefaultJedisClientConfig.builder().user("default") + .password(tlsEndpoint.getPassword()).ssl(true).build()) + .maxAttempts(DEFAULT_REDIRECTIONS).poolConfig(DEFAULT_POOL_CONFIG).build()) { + Map clusterNodes = jc.getClusterNodes(); + assertEquals(6, clusterNodes.size()); + assertTrue(clusterNodes.containsKey(tlsEndpoint.getHostAndPort(0).toString())); + assertTrue(clusterNodes.containsKey(tlsEndpoint.getHostAndPort(1).toString())); + assertTrue(clusterNodes.containsKey(tlsEndpoint.getHostAndPort(2).toString())); + jc.get("foo"); + } + } + + @Test + public void connectByIpAddress() { + try (RedisClusterClient jc = RedisClusterClient.builder() + .nodes(Collections.singleton(tlsEndpoint.getHostAndPort())) + .clientConfig( + DefaultJedisClientConfig.builder().user("default").password(tlsEndpoint.getPassword()) + .ssl(true).hostAndPortMapper(hostAndPortMap).build()) + .maxAttempts(DEFAULT_REDIRECTIONS).poolConfig(DEFAULT_POOL_CONFIG).build()) { + jc.get("foo"); + } + } + + @Test + public void connectToNodesFailsWithSSLParametersAndNoHostMapping() { + final SSLParameters sslParameters = new SSLParameters(); + sslParameters.setEndpointIdentificationAlgorithm("HTTPS"); + + try (RedisClusterClient jc = RedisClusterClient.builder() + .nodes(Collections.singleton(new HostAndPort("localhost", tlsEndpoint.getPort()))) + .clientConfig( + DefaultJedisClientConfig.builder().user("default").password(tlsEndpoint.getPassword()) + .ssl(true).sslParameters(sslParameters).hostAndPortMapper(portMap).build()) + .maxAttempts(DEFAULT_REDIRECTIONS).poolConfig(DEFAULT_POOL_CONFIG).build()) { + jc.get("foo"); + fail("It should fail after all cluster attempts."); + } catch (JedisClusterOperationException e) { + // initial connection to localhost works, but subsequent connections to nodes use 127.0.0.1 + // and fail hostname verification + assertThat(e.getMessage(), anyOf(containsString("No more cluster attempts left."), + containsString("Cluster retry deadline exceeded."))); + } + } + + @Test + public void connectToNodesSucceedsWithSSLParametersAndHostMapping() { + final SSLParameters sslParameters = new SSLParameters(); + sslParameters.setEndpointIdentificationAlgorithm("HTTPS"); + + try (RedisClusterClient jc = RedisClusterClient.builder() + .nodes(Collections.singleton(tlsEndpoint.getHostAndPort())) + .clientConfig( + DefaultJedisClientConfig.builder().user("default").password(tlsEndpoint.getPassword()) + .ssl(true).sslParameters(sslParameters).hostAndPortMapper(hostAndPortMap).build()) + .maxAttempts(DEFAULT_REDIRECTIONS).poolConfig(DEFAULT_POOL_CONFIG).build()) { + jc.get("foo"); + } + } + + @Test + public void connectByIpAddressFailsWithSSLParameters() { + final SSLParameters sslParameters = new SSLParameters(); + sslParameters.setEndpointIdentificationAlgorithm("HTTPS"); + + try (RedisClusterClient jc = RedisClusterClient.builder() + .nodes(Collections.singleton(tlsEndpoint.getHostAndPort())) + .clientConfig( + DefaultJedisClientConfig.builder().user("default").password(tlsEndpoint.getPassword()) + .ssl(true).sslParameters(sslParameters).hostAndPortMapper(hostAndPortMap).build()) + .maxAttempts(DEFAULT_REDIRECTIONS).poolConfig(DEFAULT_POOL_CONFIG).build()) { + } catch (JedisClusterOperationException e) { + assertEquals("Could not initialize cluster slots cache.", e.getMessage()); + } + } + + @Test + public void connectWithCustomHostNameVerifier() { + HostnameVerifier hostnameVerifier = new TlsUtil.BasicHostnameVerifier(); + HostnameVerifier localhostVerifier = new TlsUtil.LocalhostVerifier(); + + try (RedisClusterClient jc = RedisClusterClient.builder() + .nodes(Collections.singleton(new HostAndPort("localhost", tlsEndpoint.getPort()))) + .clientConfig( + DefaultJedisClientConfig.builder().user("default").password(tlsEndpoint.getPassword()) + .ssl(true).hostnameVerifier(hostnameVerifier).hostAndPortMapper(portMap).build()) + .maxAttempts(DEFAULT_REDIRECTIONS).poolConfig(DEFAULT_POOL_CONFIG).build()) { + jc.get("foo"); + fail("It should fail after all cluster attempts."); + } catch (JedisClusterOperationException e) { + // initial connection made with 'localhost' but subsequent connections to nodes use 127.0.0.1 + // which causes custom hostname verification to fail + assertThat(e.getMessage(), anyOf(containsString("No more cluster attempts left."), + containsString("Cluster retry deadline exceeded."))); + } + + try (RedisClusterClient jc2 = RedisClusterClient.builder() + .nodes(Collections.singleton(new HostAndPort("127.0.0.1", tlsEndpoint.getPort()))) + .clientConfig( + DefaultJedisClientConfig.builder().user("default").password(tlsEndpoint.getPassword()) + .ssl(true).hostnameVerifier(hostnameVerifier).hostAndPortMapper(portMap).build()) + .maxAttempts(DEFAULT_REDIRECTIONS).poolConfig(DEFAULT_POOL_CONFIG).build()) { + } catch (JedisClusterOperationException e) { + // JedisNoReachableClusterNodeException exception occurs from not being able to connect since + // the socket factory fails the hostname verification + assertEquals("Could not initialize cluster slots cache.", e.getMessage()); + } + + try (RedisClusterClient jc3 = RedisClusterClient.builder() + .nodes(Collections.singleton(tlsEndpoint.getHostAndPort())) + .clientConfig( + DefaultJedisClientConfig.builder().user("default").password(tlsEndpoint.getPassword()) + .ssl(true).hostnameVerifier(localhostVerifier).hostAndPortMapper(portMap).build()) + .maxAttempts(DEFAULT_REDIRECTIONS).poolConfig(DEFAULT_POOL_CONFIG).build()) { + jc3.get("foo"); + } + } + + @Test + public void connectWithCustomSocketFactory() { + try (RedisClusterClient jc = RedisClusterClient.builder() + .nodes(Collections.singleton(tlsEndpoint.getHostAndPort())) + .clientConfig(DefaultJedisClientConfig.builder().user("default") + .password(tlsEndpoint.getPassword()).ssl(true) + .sslSocketFactory(sslSocketFactoryForEnv(tlsEndpoint.getCertificatesLocation())) + .hostAndPortMapper(portMap).build()) + .maxAttempts(DEFAULT_REDIRECTIONS).poolConfig(DEFAULT_POOL_CONFIG).build()) { + assertEquals(6, jc.getClusterNodes().size()); + jc.get("foo"); + } + } + + @Test + public void connectWithEmptyTrustStore() throws Exception { + try (RedisClusterClient jc = RedisClusterClient.builder() + .nodes(Collections.singleton(tlsEndpoint.getHostAndPort())) + .clientConfig( + DefaultJedisClientConfig.builder().user("default").password(tlsEndpoint.getPassword()) + .ssl(true).sslSocketFactory(createTrustNoOneSslSocketFactory()).build()) + .maxAttempts(DEFAULT_REDIRECTIONS).poolConfig(DEFAULT_POOL_CONFIG).build()) { + jc.get("foo"); + } catch (JedisClusterOperationException e) { + assertEquals("Could not initialize cluster slots cache.", e.getMessage()); + } + } + +} diff --git a/src/test/java/redis/clients/jedis/tls/ACLRedisSentinelClientIT.java b/src/test/java/redis/clients/jedis/tls/ACLRedisSentinelClientIT.java new file mode 100644 index 0000000000..57dfe3f613 --- /dev/null +++ b/src/test/java/redis/clients/jedis/tls/ACLRedisSentinelClientIT.java @@ -0,0 +1,99 @@ +package redis.clients.jedis.tls; + +import static org.junit.jupiter.api.Assertions.assertEquals; + +import io.redis.test.annotations.ConditionalOnEnv; + +import org.junit.jupiter.api.BeforeAll; +import org.junit.jupiter.api.Test; +import org.junit.jupiter.api.extension.RegisterExtension; + +import redis.clients.jedis.DefaultJedisClientConfig; +import redis.clients.jedis.EndpointConfig; +import redis.clients.jedis.Endpoints; +import redis.clients.jedis.RedisSentinelClient; +import redis.clients.jedis.util.EnvCondition; +import redis.clients.jedis.util.RedisVersionCondition; +import redis.clients.jedis.util.TestEnvUtil; + +/** + * SSL/TLS tests for {@link RedisSentinelClient} with ACL authentication (username + password). + *

+ * This test class focuses on testing the ssl(true) flag approach (using system truststore) rather + * than explicit SslOptions configuration. + */ +@ConditionalOnEnv(value = TestEnvUtil.ENV_OSS_SOURCE, enabled = false) +public class ACLRedisSentinelClientIT extends RedisSentinelTlsTestBase { + + // Endpoint for master with ACL authentication + private static EndpointConfig aclEndpoint; + + @RegisterExtension + public static EnvCondition envCondition = new EnvCondition(); + + @RegisterExtension + public static RedisVersionCondition versionCondition = new RedisVersionCondition( + () -> Endpoints.getRedisEndpoint("standalone0-acl-tls")); + + @BeforeAll + public static void setUp() { + aclEndpoint = Endpoints.getRedisEndpoint("standalone0-acl-tls"); + } + + /** + * Tests SSL connection with explicit ACL credentials (username + password). + */ + @Test + public void connectWithSsl() { + DefaultJedisClientConfig masterConfig = DefaultJedisClientConfig.builder() + .clientName("master-client").ssl(true).user(aclEndpoint.getUsername()) + .password(aclEndpoint.getPassword()).hostAndPortMapper(PRIMARY_SSL_PORT_MAPPER).build(); + + DefaultJedisClientConfig sentinelConfig = Endpoints.getRedisEndpoint("sentinel-standalone0-tls") + .getClientConfigBuilder().clientName("sentinel-client").ssl(true) + .hostAndPortMapper(SENTINEL_SSL_PORT_MAPPER).build(); + + try (RedisSentinelClient client = RedisSentinelClient.builder().masterName(MASTER_NAME) + .sentinels(sentinels).clientConfig(masterConfig).sentinelClientConfig(sentinelConfig) + .build()) { + assertEquals("PONG", client.ping()); + } + } + + /** + * Tests SSL connection using endpoint's client config builder (credentials from endpoint). + */ + @Test + public void connectWithConfig() { + DefaultJedisClientConfig masterConfig = aclEndpoint.getClientConfigBuilder() + .clientName("master-client").ssl(true).hostAndPortMapper(PRIMARY_SSL_PORT_MAPPER).build(); + + DefaultJedisClientConfig sentinelConfig = Endpoints.getRedisEndpoint("sentinel-standalone0-tls") + .getClientConfigBuilder().clientName("sentinel-client").ssl(true) + .hostAndPortMapper(SENTINEL_SSL_PORT_MAPPER).build(); + + try (RedisSentinelClient client = RedisSentinelClient.builder().masterName(MASTER_NAME) + .sentinels(sentinels).clientConfig(masterConfig).sentinelClientConfig(sentinelConfig) + .build()) { + assertEquals("PONG", client.ping()); + } + } + + /** + * Tests SSL connection using SslOptions with truststore configuration. + */ + @Test + public void connectWithSslOptions() { + DefaultJedisClientConfig masterConfig = aclEndpoint.getClientConfigBuilder() + .clientName("master-client").sslOptions(sslOptions) + .hostAndPortMapper(PRIMARY_SSL_PORT_MAPPER).build(); + + DefaultJedisClientConfig sentinelConfig = createSentinelConfigWithSsl(sslOptions); + + try (RedisSentinelClient client = RedisSentinelClient.builder().masterName(MASTER_NAME) + .sentinels(sentinels).clientConfig(masterConfig).sentinelClientConfig(sentinelConfig) + .build()) { + assertEquals("PONG", client.ping()); + } + } +} diff --git a/src/test/java/redis/clients/jedis/SSLJedisTest.java b/src/test/java/redis/clients/jedis/tls/JedisIT.java similarity index 56% rename from src/test/java/redis/clients/jedis/SSLJedisTest.java rename to src/test/java/redis/clients/jedis/tls/JedisIT.java index d536709638..539aac0408 100644 --- a/src/test/java/redis/clients/jedis/SSLJedisTest.java +++ b/src/test/java/redis/clients/jedis/tls/JedisIT.java @@ -1,37 +1,19 @@ -package redis.clients.jedis; - -import java.nio.file.Path; -import java.util.Collections; -import java.util.List; - -import org.junit.jupiter.api.AfterAll; -import org.junit.jupiter.api.BeforeAll; -import org.junit.jupiter.api.Test; -import org.junit.jupiter.api.Tag; -import redis.clients.jedis.util.TlsUtil; +package redis.clients.jedis.tls; import static org.junit.jupiter.api.Assertions.assertEquals; -@Tag("integration") -public class SSLJedisTest { - - protected static EndpointConfig endpoint; - - private static final String trustStoreName = SSLJedisTest.class.getSimpleName(); - - @BeforeAll - public static void prepare() { - endpoint = Endpoints.getRedisEndpoint("standalone0-tls"); - List trustedCertLocation = Collections.singletonList(endpoint.getCertificatesLocation()); - Path trustStorePath = TlsUtil.createAndSaveTestTruststore(trustStoreName, trustedCertLocation,"changeit"); +import org.junit.jupiter.api.Test; - TlsUtil.setCustomTrustStore(trustStorePath, "changeit"); - } +import redis.clients.jedis.DefaultJedisClientConfig; +import redis.clients.jedis.Jedis; +import redis.clients.jedis.JedisClientConfig; - @AfterAll - public static void teardownTrustStore() { - TlsUtil.restoreOriginalTrustStore(); - } +/** + * SSL/TLS tests for {@link Jedis} with basic authentication (password-only, no ACL). + *

+ * Uses the system truststore (ssl=true flag) for SSL connections. + */ +public class JedisIT extends JedisTlsTestBase { @Test public void connectWithSsl() { @@ -52,13 +34,12 @@ public void connectWithConfig() { @Test public void connectWithConfigInterface() { - try (Jedis jedis = new Jedis(endpoint.getHostAndPort(), - new JedisClientConfig() { - @Override - public boolean isSsl() { - return true; - } - })) { + try (Jedis jedis = new Jedis(endpoint.getHostAndPort(), new JedisClientConfig() { + @Override + public boolean isSsl() { + return true; + } + })) { jedis.auth(endpoint.getPassword()); assertEquals("PONG", jedis.ping()); } @@ -87,5 +68,4 @@ public void connectWithUri() { assertEquals("PONG", jedis.ping()); } } - } diff --git a/src/test/java/redis/clients/jedis/tls/JedisSentinelPoolIT.java b/src/test/java/redis/clients/jedis/tls/JedisSentinelPoolIT.java new file mode 100644 index 0000000000..760ce91380 --- /dev/null +++ b/src/test/java/redis/clients/jedis/tls/JedisSentinelPoolIT.java @@ -0,0 +1,103 @@ +package redis.clients.jedis.tls; + +import org.apache.commons.pool2.impl.GenericObjectPoolConfig; +import org.junit.jupiter.api.BeforeAll; +import org.junit.jupiter.api.Test; + +import redis.clients.jedis.DefaultJedisClientConfig; +import redis.clients.jedis.EndpointConfig; +import redis.clients.jedis.Endpoints; +import redis.clients.jedis.Jedis; +import redis.clients.jedis.JedisSentinelPool; + +/** + * SSL/TLS tests for {@link JedisSentinelPool} using system truststore (ssl=true flag). + *

+ * Tests various combinations of SSL on master and sentinel connections: + *

+ */ +public class JedisSentinelPoolIT extends RedisSentinelTlsTestBase { + + private static final GenericObjectPoolConfig POOL_CONFIG = new GenericObjectPoolConfig<>(); + + // Endpoints for different SSL configurations + private static EndpointConfig aclTlsEndpoint; + private static EndpointConfig aclEndpoint; + private static EndpointConfig sentinelTlsEndpoint; + + @BeforeAll + public static void setUp() { + aclTlsEndpoint = Endpoints.getRedisEndpoint("standalone0-acl-tls"); + aclEndpoint = Endpoints.getRedisEndpoint("standalone0-acl"); + sentinelTlsEndpoint = Endpoints.getRedisEndpoint("sentinel-standalone0-tls"); + } + + /** + * Tests sentinel without SSL connecting to Redis master with SSL. + */ + @Test + public void sentinelWithoutSslConnectsToRedisWithSsl() { + DefaultJedisClientConfig masterConfig = aclTlsEndpoint.getClientConfigBuilder() + .clientName("master-client").hostAndPortMapper(PRIMARY_SSL_PORT_MAPPER).build(); + + DefaultJedisClientConfig sentinelConfig = createSentinelConfigWithoutSsl(); + + try (JedisSentinelPool pool = new JedisSentinelPool(MASTER_NAME, sentinels, masterConfig, + sentinelConfig)) { + pool.getResource().close(); + } + + try (JedisSentinelPool pool = new JedisSentinelPool(MASTER_NAME, sentinels, POOL_CONFIG, + masterConfig, sentinelConfig)) { + pool.getResource().close(); + } + } + + /** + * Tests sentinel with SSL connecting to Redis master without SSL. + */ + @Test + public void sentinelWithSslConnectsToRedisWithoutSsl() { + DefaultJedisClientConfig masterConfig = aclEndpoint.getClientConfigBuilder() + .clientName("master-client").build(); + + DefaultJedisClientConfig sentinelConfig = sentinelTlsEndpoint.getClientConfigBuilder() + .clientName("sentinel-client").hostAndPortMapper(SENTINEL_SSL_PORT_MAPPER).build(); + + try (JedisSentinelPool pool = new JedisSentinelPool(MASTER_NAME, sentinels, masterConfig, + sentinelConfig)) { + pool.getResource().close(); + } + + try (JedisSentinelPool pool = new JedisSentinelPool(MASTER_NAME, sentinels, POOL_CONFIG, + masterConfig, sentinelConfig)) { + pool.getResource().close(); + } + } + + /** + * Tests both sentinel and Redis master with SSL. + */ + @Test + public void sentinelWithSslConnectsToRedisWithSsl() { + DefaultJedisClientConfig masterConfig = aclTlsEndpoint.getClientConfigBuilder() + .clientName("master-client").hostAndPortMapper(PRIMARY_SSL_PORT_MAPPER).build(); + + DefaultJedisClientConfig sentinelConfig = sentinelTlsEndpoint.getClientConfigBuilder() + .clientName("sentinel-client").hostAndPortMapper(SENTINEL_SSL_PORT_MAPPER).build(); + + try (JedisSentinelPool pool = new JedisSentinelPool(MASTER_NAME, sentinels, masterConfig, + sentinelConfig)) { + pool.getResource().close(); + } + + try (JedisSentinelPool pool = new JedisSentinelPool(MASTER_NAME, sentinels, POOL_CONFIG, + masterConfig, sentinelConfig)) { + pool.getResource().close(); + } + } +} diff --git a/src/test/java/redis/clients/jedis/tls/JedisTlsTestBase.java b/src/test/java/redis/clients/jedis/tls/JedisTlsTestBase.java new file mode 100644 index 0000000000..6b8c3e5d99 --- /dev/null +++ b/src/test/java/redis/clients/jedis/tls/JedisTlsTestBase.java @@ -0,0 +1,61 @@ +package redis.clients.jedis.tls; + +import java.nio.file.Path; +import java.util.Arrays; +import java.util.List; +import java.util.stream.Stream; + +import org.junit.jupiter.api.AfterAll; +import org.junit.jupiter.api.BeforeAll; +import org.junit.jupiter.params.provider.Arguments; + +import redis.clients.jedis.EndpointConfig; +import redis.clients.jedis.Endpoints; +import redis.clients.jedis.SslOptions; +import redis.clients.jedis.SslVerifyMode; +import redis.clients.jedis.util.TlsUtil; + +/** + * Abstract base class for SSL/TLS tests for {@link redis.clients.jedis.Jedis}. + */ +public abstract class JedisTlsTestBase { + + private static final String TRUSTSTORE_PASSWORD = "changeit"; + + protected static EndpointConfig endpoint; + protected static EndpointConfig aclEndpoint; + protected static Path trustStorePath; + protected static SslOptions sslOptions; + + @BeforeAll + public static void setUpTrustStore() { + endpoint = Endpoints.getRedisEndpoint("standalone0-tls"); + aclEndpoint = Endpoints.getRedisEndpoint("standalone0-acl-tls"); + + List trustedCertLocation = Arrays.asList(endpoint.getCertificatesLocation(), + aclEndpoint.getCertificatesLocation()); + trustStorePath = TlsUtil.createAndSaveTestTruststore(JedisTlsTestBase.class.getSimpleName(), + trustedCertLocation, TRUSTSTORE_PASSWORD); + + TlsUtil.setCustomTrustStore(trustStorePath, TRUSTSTORE_PASSWORD); + sslOptions = createTruststoreSslOptions(); + } + + @AfterAll + public static void tearDownTrustStore() { + TlsUtil.restoreOriginalTrustStore(); + } + + protected static SslOptions createTruststoreSslOptions() { + return SslOptions.builder().truststore(trustStorePath.toFile()).trustStoreType("jceks") + .sslVerifyMode(SslVerifyMode.CA).build(); + } + + protected static Stream sslOptionsProvider() { + return Stream.of(Arguments.of("truststore", createTruststoreSslOptions()), + Arguments.of("insecure", SslOptions.builder().sslVerifyMode(SslVerifyMode.INSECURE).build()), + Arguments.of("ssl-protocol", + SslOptions.builder().sslProtocol("SSL").truststore(trustStorePath.toFile()) + .trustStoreType("jceks").sslVerifyMode(SslVerifyMode.CA).build())); + } +} diff --git a/src/test/java/redis/clients/jedis/tls/RedisClientIT.java b/src/test/java/redis/clients/jedis/tls/RedisClientIT.java new file mode 100644 index 0000000000..897737264d --- /dev/null +++ b/src/test/java/redis/clients/jedis/tls/RedisClientIT.java @@ -0,0 +1,63 @@ +package redis.clients.jedis.tls; + +import static org.junit.jupiter.api.Assertions.assertEquals; + +import org.junit.jupiter.api.Test; + +import redis.clients.jedis.DefaultJedisClientConfig; +import redis.clients.jedis.RedisClient; + +/** + * SSL/TLS tests for {@link RedisClient} with basic authentication (password-only, no ACL). + *

+ * Uses the system truststore (ssl=true flag) for SSL connections. + */ +public class RedisClientIT extends RedisClientTlsTestBase { + + @Test + public void connectWithSsl() { + try (RedisClient client = RedisClient.builder() + .hostAndPort(endpoint.getHost(), endpoint.getPort()) + .clientConfig( + DefaultJedisClientConfig.builder().ssl(true).password(endpoint.getPassword()).build()) + .build()) { + assertEquals("PONG", client.ping()); + } + } + + @Test + public void connectWithConfig() { + try (RedisClient client = RedisClient.builder().hostAndPort(endpoint.getHostAndPort()) + .clientConfig( + DefaultJedisClientConfig.builder().ssl(true).password(endpoint.getPassword()).build()) + .build()) { + assertEquals("PONG", client.ping()); + } + } + + /** + * Tests opening a default SSL/TLS connection to redis using "rediss://" scheme url. + */ + @Test + public void connectWithUrl() { + // The "rediss" scheme instructs jedis to open a SSL/TLS connection. + // URI includes credentials via defaultCredentials() + try (RedisClient client = RedisClient + .create(endpoint.getURIBuilder().defaultCredentials().build().toString())) { + assertEquals("PONG", client.ping()); + } + } + + /** + * Tests opening a default SSL/TLS connection to redis. + */ + @Test + public void connectWithUri() { + // The "rediss" scheme instructs jedis to open a SSL/TLS connection. + // URI includes credentials via defaultCredentials() + try (RedisClient client = RedisClient + .create(endpoint.getURIBuilder().defaultCredentials().build())) { + assertEquals("PONG", client.ping()); + } + } +} diff --git a/src/test/java/redis/clients/jedis/tls/RedisClientTlsTestBase.java b/src/test/java/redis/clients/jedis/tls/RedisClientTlsTestBase.java new file mode 100644 index 0000000000..c90eb80b8b --- /dev/null +++ b/src/test/java/redis/clients/jedis/tls/RedisClientTlsTestBase.java @@ -0,0 +1,61 @@ +package redis.clients.jedis.tls; + +import java.nio.file.Path; +import java.util.Arrays; +import java.util.List; +import java.util.stream.Stream; + +import org.junit.jupiter.api.AfterAll; +import org.junit.jupiter.api.BeforeAll; +import org.junit.jupiter.params.provider.Arguments; + +import redis.clients.jedis.EndpointConfig; +import redis.clients.jedis.Endpoints; +import redis.clients.jedis.SslOptions; +import redis.clients.jedis.SslVerifyMode; +import redis.clients.jedis.util.TlsUtil; + +/** + * Abstract base class for SSL/TLS tests for {@link redis.clients.jedis.RedisClient}. + */ +public abstract class RedisClientTlsTestBase { + + private static final String TRUSTSTORE_PASSWORD = "changeit"; + + protected static EndpointConfig endpoint; + protected static EndpointConfig aclEndpoint; + protected static Path trustStorePath; + protected static SslOptions sslOptions; + + @BeforeAll + public static void setUpTrustStore() { + endpoint = Endpoints.getRedisEndpoint("standalone0-tls"); + aclEndpoint = Endpoints.getRedisEndpoint("standalone0-acl-tls"); + + List trustedCertLocation = Arrays.asList(endpoint.getCertificatesLocation(), + aclEndpoint.getCertificatesLocation()); + trustStorePath = TlsUtil.createAndSaveTestTruststore( + RedisClientTlsTestBase.class.getSimpleName(), trustedCertLocation, TRUSTSTORE_PASSWORD); + + TlsUtil.setCustomTrustStore(trustStorePath, TRUSTSTORE_PASSWORD); + sslOptions = createTruststoreSslOptions(); + } + + @AfterAll + public static void tearDownTrustStore() { + TlsUtil.restoreOriginalTrustStore(); + } + + protected static SslOptions createTruststoreSslOptions() { + return SslOptions.builder().truststore(trustStorePath.toFile()).trustStoreType("jceks") + .sslVerifyMode(SslVerifyMode.CA).build(); + } + + protected static Stream sslOptionsProvider() { + return Stream.of(Arguments.of("truststore", createTruststoreSslOptions()), + Arguments.of("insecure", SslOptions.builder().sslVerifyMode(SslVerifyMode.INSECURE).build()), + Arguments.of("ssl-protocol", + SslOptions.builder().sslProtocol("SSL").truststore(trustStorePath.toFile()) + .trustStoreType("jceks").sslVerifyMode(SslVerifyMode.CA).build())); + } +} diff --git a/src/test/java/redis/clients/jedis/tls/RedisClusterClientIT.java b/src/test/java/redis/clients/jedis/tls/RedisClusterClientIT.java new file mode 100644 index 0000000000..23706be076 --- /dev/null +++ b/src/test/java/redis/clients/jedis/tls/RedisClusterClientIT.java @@ -0,0 +1,187 @@ +package redis.clients.jedis.tls; + +import static org.hamcrest.MatcherAssert.assertThat; +import static org.hamcrest.Matchers.anyOf; +import static org.hamcrest.Matchers.containsString; +import static org.junit.jupiter.api.Assertions.assertEquals; +import static org.junit.jupiter.api.Assertions.assertTrue; +import static org.junit.jupiter.api.Assertions.fail; +import static redis.clients.jedis.util.TlsUtil.*; + +import java.util.Collections; +import java.util.Map; +import javax.net.ssl.HostnameVerifier; +import javax.net.ssl.SSLParameters; + +import io.redis.test.annotations.SinceRedisVersion; +import org.junit.jupiter.api.Test; +import redis.clients.jedis.*; +import redis.clients.jedis.util.TlsUtil; +import redis.clients.jedis.exceptions.JedisClusterOperationException; + +public class RedisClusterClientIT extends RedisClusterTestBase { + + private static final int DEFAULT_REDIRECTIONS = 3; + private static final ConnectionPoolConfig DEFAULT_POOL_CONFIG = new ConnectionPoolConfig(); + + @Test + public void testSSLDiscoverNodesAutomatically() { + try (RedisClusterClient jc = RedisClusterClient.builder() + .nodes(Collections.singleton(tlsEndpoint.getHostAndPort())) + .clientConfig(DefaultJedisClientConfig.builder().password(tlsEndpoint.getPassword()) + .sslOptions(createSslOptions()).hostAndPortMapper(hostAndPortMap).build()) + .maxAttempts(DEFAULT_REDIRECTIONS).poolConfig(DEFAULT_POOL_CONFIG).build()) { + Map clusterNodes = jc.getClusterNodes(); + assertEquals(6, clusterNodes.size()); + assertTrue(clusterNodes.containsKey(tlsEndpoint.getHostAndPort(0).toString())); + assertTrue(clusterNodes.containsKey(tlsEndpoint.getHostAndPort(1).toString())); + assertTrue(clusterNodes.containsKey(tlsEndpoint.getHostAndPort(2).toString())); + jc.get("foo"); + } + } + + @Test + public void testSSLWithoutPortMap() { + try (RedisClusterClient jc = RedisClusterClient.builder() + .nodes(Collections.singleton(tlsEndpoint.getHostAndPort())) + .clientConfig( + DefaultJedisClientConfig.builder().password(tlsEndpoint.getPassword()).ssl(true).build()) + .maxAttempts(DEFAULT_REDIRECTIONS).poolConfig(DEFAULT_POOL_CONFIG).build()) { + Map clusterNodes = jc.getClusterNodes(); + assertEquals(6, clusterNodes.size()); + assertTrue(clusterNodes.containsKey(tlsEndpoint.getHostAndPort(0).toString())); + assertTrue(clusterNodes.containsKey(tlsEndpoint.getHostAndPort(1).toString())); + assertTrue(clusterNodes.containsKey(tlsEndpoint.getHostAndPort(2).toString())); + jc.get("foo"); + } + } + + @Test + public void connectByIpAddress() { + try (RedisClusterClient jc = RedisClusterClient.builder() + .nodes(Collections.singleton(tlsEndpoint.getHostAndPort())) + .clientConfig(DefaultJedisClientConfig.builder().password(tlsEndpoint.getPassword()) + .sslOptions(createSslOptions()).hostAndPortMapper(hostAndPortMap).build()) + .maxAttempts(DEFAULT_REDIRECTIONS).poolConfig(DEFAULT_POOL_CONFIG).build()) { + jc.get("foo"); + } + } + + @Test + public void connectToNodesFailsWithSSLParametersAndNoHostMapping() { + final SSLParameters sslParameters = new SSLParameters(); + sslParameters.setEndpointIdentificationAlgorithm("HTTPS"); + + try (RedisClusterClient jc = RedisClusterClient.builder() + .nodes(Collections.singleton(new HostAndPort("localhost", tlsEndpoint.getPort()))) + .clientConfig(DefaultJedisClientConfig.builder().password(tlsEndpoint.getPassword()) + .sslOptions(createSslOptions()).sslParameters(sslParameters).hostAndPortMapper(portMap) + .build()) + .maxAttempts(DEFAULT_REDIRECTIONS).poolConfig(DEFAULT_POOL_CONFIG).build()) { + jc.get("foo"); + fail("It should fail after all cluster attempts."); + } catch (JedisClusterOperationException e) { + // initial connection to localhost works, but subsequent connections to nodes use 127.0.0.1 + // and fail hostname verification + assertThat(e.getMessage(), anyOf(containsString("No more cluster attempts left."), + containsString("Cluster retry deadline exceeded."))); + } + } + + @Test + public void connectToNodesSucceedsWithSSLParametersAndHostMapping() { + final SSLParameters sslParameters = new SSLParameters(); + sslParameters.setEndpointIdentificationAlgorithm("HTTPS"); + + try (RedisClusterClient jc = RedisClusterClient.builder() + .nodes(Collections.singleton(tlsEndpoint.getHostAndPort())) + .clientConfig(DefaultJedisClientConfig.builder().password(tlsEndpoint.getPassword()) + .sslOptions(createSslOptions()).sslParameters(sslParameters) + .hostAndPortMapper(hostAndPortMap).build()) + .maxAttempts(DEFAULT_REDIRECTIONS).poolConfig(DEFAULT_POOL_CONFIG).build()) { + jc.get("foo"); + } + } + + @Test + public void connectByIpAddressFailsWithSSLParameters() { + final SSLParameters sslParameters = new SSLParameters(); + sslParameters.setEndpointIdentificationAlgorithm("HTTPS"); + + try (RedisClusterClient jc = RedisClusterClient.builder() + .nodes(Collections.singleton(tlsEndpoint.getHostAndPort())) + .clientConfig(DefaultJedisClientConfig.builder().password(tlsEndpoint.getPassword()) + .sslOptions(createSslOptions()).sslParameters(sslParameters) + .hostAndPortMapper(hostAndPortMap).build()) + .maxAttempts(DEFAULT_REDIRECTIONS).poolConfig(DEFAULT_POOL_CONFIG).build()) { + } catch (JedisClusterOperationException e) { + assertEquals("Could not initialize cluster slots cache.", e.getMessage()); + } + } + + @Test + public void connectWithCustomHostNameVerifier() { + HostnameVerifier hostnameVerifier = new TlsUtil.BasicHostnameVerifier(); + HostnameVerifier localhostVerifier = new TlsUtil.LocalhostVerifier(); + + try (RedisClusterClient jc = RedisClusterClient.builder() + .nodes(Collections.singleton(new HostAndPort("localhost", tlsEndpoint.getPort()))) + .clientConfig(DefaultJedisClientConfig.builder().password(tlsEndpoint.getPassword()) + .ssl(true).hostnameVerifier(hostnameVerifier).hostAndPortMapper(portMap).build()) + .maxAttempts(DEFAULT_REDIRECTIONS).poolConfig(DEFAULT_POOL_CONFIG).build()) { + jc.get("foo"); + fail("It should fail after all cluster attempts."); + } catch (JedisClusterOperationException e) { + // initial connection made with 'localhost' but subsequent connections to nodes use 127.0.0.1 + // which causes custom hostname verification to fail + assertThat(e.getMessage(), anyOf(containsString("No more cluster attempts left."), + containsString("Cluster retry deadline exceeded."))); + } + + try (RedisClusterClient jc2 = RedisClusterClient.builder() + .nodes(Collections.singleton(new HostAndPort("127.0.0.1", tlsEndpoint.getPort()))) + .clientConfig(DefaultJedisClientConfig.builder().password(tlsEndpoint.getPassword()) + .ssl(true).hostnameVerifier(hostnameVerifier).hostAndPortMapper(portMap).build()) + .maxAttempts(DEFAULT_REDIRECTIONS).poolConfig(DEFAULT_POOL_CONFIG).build()) { + } catch (JedisClusterOperationException e) { + // JedisNoReachableClusterNodeException exception occurs from not being able to connect + // since the socket factory fails the hostname verification + assertEquals("Could not initialize cluster slots cache.", e.getMessage()); + } + + try (RedisClusterClient jc3 = RedisClusterClient.builder() + .nodes(Collections.singleton(tlsEndpoint.getHostAndPort())) + .clientConfig(DefaultJedisClientConfig.builder().password(tlsEndpoint.getPassword()) + .ssl(true).hostnameVerifier(localhostVerifier).hostAndPortMapper(portMap).build()) + .maxAttempts(DEFAULT_REDIRECTIONS).poolConfig(DEFAULT_POOL_CONFIG).build()) { + jc3.get("foo"); + } + } + + @Test + public void connectWithCustomSocketFactory() throws Exception { + try (RedisClusterClient jc = RedisClusterClient.builder() + .nodes(Collections.singleton(tlsEndpoint.getHostAndPort())) + .clientConfig( + DefaultJedisClientConfig.builder().password(tlsEndpoint.getPassword()).ssl(true) + .sslSocketFactory(sslSocketFactoryForEnv(tlsEndpoint.getCertificatesLocation())) + .hostAndPortMapper(portMap).build()) + .maxAttempts(DEFAULT_REDIRECTIONS).poolConfig(DEFAULT_POOL_CONFIG).build()) { + assertEquals(6, jc.getClusterNodes().size()); + jc.get("foo"); + } + } + + @Test + public void connectWithEmptyTrustStore() throws Exception { + try (RedisClusterClient jc = RedisClusterClient.builder() + .nodes(Collections.singleton(tlsEndpoint.getHostAndPort())) + .clientConfig(DefaultJedisClientConfig.builder().password(tlsEndpoint.getPassword()) + .ssl(true).sslSocketFactory(createTrustNoOneSslSocketFactory()).build()) + .maxAttempts(DEFAULT_REDIRECTIONS).poolConfig(DEFAULT_POOL_CONFIG).build()) { + } catch (JedisClusterOperationException e) { + assertEquals("Could not initialize cluster slots cache.", e.getMessage()); + } + } + +} diff --git a/src/test/java/redis/clients/jedis/tls/RedisClusterTestBase.java b/src/test/java/redis/clients/jedis/tls/RedisClusterTestBase.java new file mode 100644 index 0000000000..1d7249275d --- /dev/null +++ b/src/test/java/redis/clients/jedis/tls/RedisClusterTestBase.java @@ -0,0 +1,120 @@ +package redis.clients.jedis.tls; + +import java.nio.file.Path; +import java.util.Collections; +import java.util.HashSet; +import java.util.List; + +import io.redis.test.annotations.ConditionalOnEnv; +import org.junit.jupiter.api.AfterAll; +import org.junit.jupiter.api.AfterEach; +import org.junit.jupiter.api.BeforeAll; +import org.junit.jupiter.api.BeforeEach; +import org.junit.jupiter.api.extension.RegisterExtension; + +import redis.clients.jedis.DefaultJedisClientConfig; +import redis.clients.jedis.EndpointConfig; +import redis.clients.jedis.Endpoints; +import redis.clients.jedis.HostAndPort; +import redis.clients.jedis.HostAndPortMapper; +import redis.clients.jedis.RedisClusterClient; +import redis.clients.jedis.SslOptions; +import redis.clients.jedis.util.*; + +/** + * Abstract base class for SSL/TLS Redis cluster tests. + *

+ * This class provides common setup and teardown for TLS-enabled Redis cluster tests, including + * truststore initialization and cluster client configuration. + *

+ * Uses the {@code cluster-stable-tls} endpoint for stable integration tests. + *

+ * Note: The {@link RedisVersionCondition} and {@link EnabledOnCommandCondition} extensions use the + * non-TLS {@code cluster-stable} endpoint for version/command checks because JUnit 5 extensions run + * before {@code @BeforeAll} methods where the truststore is configured. + */ +@ConditionalOnEnv(value = TestEnvUtil.ENV_OSS_SOURCE, enabled = false) +public abstract class RedisClusterTestBase { + + private static final String ENDPOINT_NAME = "cluster-stable-tls"; + /** + * Non-TLS endpoint used for version and command checks. Extensions run before @BeforeAll, so we + * can't use TLS endpoints for these checks since the truststore isn't configured yet. + */ + private static final String VERSION_CHECK_ENDPOINT_NAME = "cluster-stable"; + private static final String TRUSTSTORE_PASSWORD = "changeit"; + + @RegisterExtension + public static EnvCondition envCondition = new EnvCondition(); + + @RegisterExtension + public EnabledOnCommandCondition enabledOnCommandCondition = new EnabledOnCommandCondition( + () -> Endpoints.getRedisEndpoint(VERSION_CHECK_ENDPOINT_NAME)); + + protected static EndpointConfig tlsEndpoint; + protected static Path trustStorePath; + + protected RedisClusterClient cluster; + + /** + * HostAndPortMapper that maps IP addresses (127.0.0.1) to localhost for hostname verification. + */ + protected final HostAndPortMapper hostAndPortMap = (HostAndPort hostAndPort) -> { + String host = hostAndPort.getHost(); + int port = hostAndPort.getPort(); + if ("127.0.0.1".equals(host)) { + host = "localhost"; + } + return new HostAndPort(host, port); + }; + + /** + * HostAndPortMapper that only maps localhost, leaving IP addresses unchanged. Useful for testing + * hostname verification failures. + */ + protected final HostAndPortMapper portMap = (HostAndPort hostAndPort) -> { + if ("localhost".equals(hostAndPort.getHost())) { + return hostAndPort; + } + return new HostAndPort(hostAndPort.getHost(), hostAndPort.getPort()); + }; + + @BeforeAll + public static void prepareEndpointAndTrustStore() { + tlsEndpoint = Endpoints.getRedisEndpoint(ENDPOINT_NAME); + List trustedCertLocation = Collections + .singletonList(tlsEndpoint.getCertificatesLocation()); + trustStorePath = TlsUtil.createAndSaveTestTruststore(RedisClusterTestBase.class.getSimpleName(), + trustedCertLocation, TRUSTSTORE_PASSWORD); + TlsUtil.setCustomTrustStore(trustStorePath, TRUSTSTORE_PASSWORD); + } + + @AfterAll + public static void teardownTrustStore() { + TlsUtil.restoreOriginalTrustStore(); + } + + @BeforeEach + public void setUp() { + SslOptions sslOptions = SslOptions.builder().truststore(trustStorePath.toFile()) + .trustStoreType("jceks").build(); + + cluster = RedisClusterClient.builder().nodes(new HashSet<>(tlsEndpoint.getHostsAndPorts())) + .clientConfig(DefaultJedisClientConfig.builder().password(tlsEndpoint.getPassword()) + .sslOptions(sslOptions).hostAndPortMapper(hostAndPortMap).build()) + .build(); + cluster.flushAll(); + } + + @AfterEach + public void tearDown() { + if (cluster != null) { + cluster.flushAll(); + cluster.close(); + } + } + + protected static SslOptions createSslOptions() { + return SslOptions.builder().truststore(trustStorePath.toFile()).trustStoreType("jceks").build(); + } +} diff --git a/src/test/java/redis/clients/jedis/tls/RedisSentinelClientIT.java b/src/test/java/redis/clients/jedis/tls/RedisSentinelClientIT.java new file mode 100644 index 0000000000..8137e75c8f --- /dev/null +++ b/src/test/java/redis/clients/jedis/tls/RedisSentinelClientIT.java @@ -0,0 +1,55 @@ +package redis.clients.jedis.tls; + +import static org.junit.jupiter.api.Assertions.assertEquals; + +import org.junit.jupiter.api.BeforeAll; +import org.junit.jupiter.params.ParameterizedTest; +import org.junit.jupiter.params.provider.MethodSource; + +import redis.clients.jedis.DefaultJedisClientConfig; +import redis.clients.jedis.EndpointConfig; +import redis.clients.jedis.Endpoints; +import redis.clients.jedis.RedisSentinelClient; +import redis.clients.jedis.SslOptions; + +/** + * SSL/TLS tests for {@link RedisSentinelClient} with basic authentication (password-only, no ACL). + *

+ * Tests various SSL/TLS connection configurations including: + *

    + *
  • Basic SSL connection with truststore
  • + *
  • Insecure SSL mode (no certificate verification)
  • + *
  • Custom SSL protocol
  • + *
+ *

+ * This test class uses the default user with password authentication instead of ACL user. The + * sentinel connection does not use SSL, only the master connection uses SSL. + */ +public class RedisSentinelClientIT extends RedisSentinelTlsTestBase { + + // Endpoint for master with default user (password-only, no ACL) + private static EndpointConfig masterEndpoint; + + @BeforeAll + public static void setUp() { + masterEndpoint = Endpoints.getRedisEndpoint("standalone0-tls"); + } + + @ParameterizedTest(name = "connectWithSsl_{0}") + @MethodSource("sslOptionsProvider") + void connectWithSsl(String testName, SslOptions ssl) { + DefaultJedisClientConfig masterConfig = DefaultJedisClientConfig.builder() + .clientName("master-client").sslOptions(ssl).password(masterEndpoint.getPassword()) + .hostAndPortMapper(PRIMARY_SSL_PORT_MAPPER).build(); + + // Sentinel requires authentication but does not use SSL + DefaultJedisClientConfig sentinelConfig = createSentinelConfigWithoutSsl(); + + try (RedisSentinelClient client = RedisSentinelClient.builder().masterName(MASTER_NAME) + .sentinels(sentinels).clientConfig(masterConfig).sentinelClientConfig(sentinelConfig) + .build()) { + assertEquals("PONG", client.ping()); + } + } + +} diff --git a/src/test/java/redis/clients/jedis/tls/RedisSentinelTlsTestBase.java b/src/test/java/redis/clients/jedis/tls/RedisSentinelTlsTestBase.java new file mode 100644 index 0000000000..26dadb792f --- /dev/null +++ b/src/test/java/redis/clients/jedis/tls/RedisSentinelTlsTestBase.java @@ -0,0 +1,85 @@ +package redis.clients.jedis.tls; + +import java.nio.file.Path; +import java.nio.file.Paths; +import java.util.Collections; +import java.util.HashSet; +import java.util.List; +import java.util.Set; +import java.util.stream.Stream; + +import org.junit.jupiter.api.AfterAll; +import org.junit.jupiter.api.BeforeAll; +import org.junit.jupiter.params.provider.Arguments; + +import redis.clients.jedis.DefaultJedisClientConfig; +import redis.clients.jedis.EndpointConfig; +import redis.clients.jedis.Endpoints; +import redis.clients.jedis.HostAndPort; +import redis.clients.jedis.HostAndPortMapper; +import redis.clients.jedis.SslOptions; +import redis.clients.jedis.SslVerifyMode; +import redis.clients.jedis.util.TlsUtil; + +/** + * Abstract base class for Redis Sentinel TLS integration tests. + */ +public abstract class RedisSentinelTlsTestBase { + + protected static final String MASTER_NAME = "aclmaster"; + private static final String TRUSTSTORE_PASSWORD = "changeit"; + private static final String TRUSTSTORE_TYPE = "jceks"; + + protected static EndpointConfig sentinel; + protected static Set sentinels = new HashSet<>(); + protected static Path trustStorePath; + protected static SslOptions sslOptions; + + protected static final HostAndPortMapper SENTINEL_SSL_PORT_MAPPER = ( + HostAndPort hap) -> new HostAndPort(hap.getHost(), hap.getPort() + 10000); + + protected static final HostAndPortMapper PRIMARY_SSL_PORT_MAPPER = ( + HostAndPort hap) -> new HostAndPort(hap.getHost(), hap.getPort() + 11); + + @BeforeAll + public static void setupSentinelTls() { + sentinel = Endpoints.getRedisEndpoint("sentinel-standalone0"); + sentinels.add(sentinel.getHostAndPort()); + + List trustedCertLocation = Collections + .singletonList(Paths.get("redis1-2-5-8-sentinel/work/tls")); + trustStorePath = TlsUtil.createAndSaveTestTruststore( + RedisSentinelTlsTestBase.class.getSimpleName(), trustedCertLocation, TRUSTSTORE_PASSWORD); + sslOptions = createTruststoreSslOptions(); + + TlsUtil.setCustomTrustStore(trustStorePath, TRUSTSTORE_PASSWORD); + } + + @AfterAll + public static void teardownTrustStore() { + TlsUtil.restoreOriginalTrustStore(); + } + + protected static SslOptions createTruststoreSslOptions() { + return SslOptions.builder().truststore(trustStorePath.toFile()).trustStoreType(TRUSTSTORE_TYPE) + .sslVerifyMode(SslVerifyMode.CA).build(); + } + + protected static DefaultJedisClientConfig createSentinelConfigWithSsl(SslOptions ssl) { + return Endpoints.getRedisEndpoint("sentinel-standalone0-tls").getClientConfigBuilder() + .clientName("sentinel-client").sslOptions(ssl).hostAndPortMapper(SENTINEL_SSL_PORT_MAPPER) + .build(); + } + + protected static DefaultJedisClientConfig createSentinelConfigWithoutSsl() { + return sentinel.getClientConfigBuilder().clientName("sentinel-client").build(); + } + + protected static Stream sslOptionsProvider() { + return Stream.of(Arguments.of("truststore", createTruststoreSslOptions()), + Arguments.of("insecure", SslOptions.builder().sslVerifyMode(SslVerifyMode.INSECURE).build()), + Arguments.of("ssl-protocol", + SslOptions.builder().sslProtocol("SSL").truststore(trustStorePath.toFile()) + .trustStoreType(TRUSTSTORE_TYPE).sslVerifyMode(SslVerifyMode.CA).build())); + } +} diff --git a/src/test/java/redis/clients/jedis/tls/SSLOptionsJedisIT.java b/src/test/java/redis/clients/jedis/tls/SSLOptionsJedisIT.java new file mode 100644 index 0000000000..74eb13b378 --- /dev/null +++ b/src/test/java/redis/clients/jedis/tls/SSLOptionsJedisIT.java @@ -0,0 +1,61 @@ +package redis.clients.jedis.tls; + +import static org.junit.jupiter.api.Assertions.assertEquals; + +import org.junit.jupiter.api.Test; +import org.junit.jupiter.params.ParameterizedTest; +import org.junit.jupiter.params.provider.MethodSource; + +import redis.clients.jedis.DefaultJedisClientConfig; +import redis.clients.jedis.Jedis; +import redis.clients.jedis.SslOptions; + +/** + * SSL/TLS tests for {@link Jedis} using SslOptions builder pattern. + *

+ * Tests various SSL/TLS connection configurations including: + *

    + *
  • Basic SSL connection with truststore
  • + *
  • Insecure SSL mode (no certificate verification)
  • + *
  • Custom SSL protocol
  • + *
  • ACL authentication over SSL
  • + *
+ */ +public class SSLOptionsJedisIT extends JedisTlsTestBase { + + /** + * Tests connecting to Redis with various SSL configurations using DefaultJedisClientConfig. + */ + @ParameterizedTest(name = "connectWithSsl_{0}") + @MethodSource("sslOptionsProvider") + void connectWithSsl(String testName, SslOptions ssl) { + try (Jedis jedis = new Jedis(endpoint.getHostAndPort(), + DefaultJedisClientConfig.builder().sslOptions(ssl).build())) { + jedis.auth(endpoint.getPassword()); + assertEquals("PONG", jedis.ping()); + } + } + + /** + * Tests connecting to Redis with various SSL configurations using endpoint's client config. + */ + @ParameterizedTest(name = "connectWithClientConfig_{0}") + @MethodSource("sslOptionsProvider") + void connectWithClientConfig(String testName, SslOptions ssl) { + try (Jedis jedis = new Jedis(endpoint.getHostAndPort(), + endpoint.getClientConfigBuilder().sslOptions(ssl).build())) { + assertEquals("PONG", jedis.ping()); + } + } + + /** + * Tests ACL authentication over SSL. + */ + @Test + public void connectWithAcl() { + try (Jedis jedis = new Jedis(aclEndpoint.getHostAndPort(), + aclEndpoint.getClientConfigBuilder().sslOptions(sslOptions).build())) { + assertEquals("PONG", jedis.ping()); + } + } +} diff --git a/src/test/java/redis/clients/jedis/tls/SSLOptionsJedisSentinelPoolIT.java b/src/test/java/redis/clients/jedis/tls/SSLOptionsJedisSentinelPoolIT.java new file mode 100644 index 0000000000..b30dc9c867 --- /dev/null +++ b/src/test/java/redis/clients/jedis/tls/SSLOptionsJedisSentinelPoolIT.java @@ -0,0 +1,104 @@ +package redis.clients.jedis.tls; + +import org.apache.commons.pool2.impl.GenericObjectPoolConfig; +import org.junit.jupiter.api.BeforeAll; +import org.junit.jupiter.api.Test; + +import redis.clients.jedis.DefaultJedisClientConfig; +import redis.clients.jedis.EndpointConfig; +import redis.clients.jedis.Endpoints; +import redis.clients.jedis.Jedis; +import redis.clients.jedis.JedisSentinelPool; + +/** + * SSL/TLS tests for {@link JedisSentinelPool} using SslOptions builder pattern. + *

+ * Tests various combinations of SSL on master and sentinel connections: + *

    + *
  • Sentinel without SSL, Redis master with SSL (using SslOptions)
  • + *
  • Sentinel with SSL (using SslOptions), Redis master without SSL
  • + *
  • Both sentinel and Redis master with SSL (using SslOptions)
  • + *
+ */ +public class SSLOptionsJedisSentinelPoolIT extends RedisSentinelTlsTestBase { + + private static final GenericObjectPoolConfig POOL_CONFIG = new GenericObjectPoolConfig<>(); + + // Endpoints for different SSL configurations + private static EndpointConfig aclTlsEndpoint; + private static EndpointConfig aclEndpoint; + private static EndpointConfig sentinelTlsEndpoint; + + @BeforeAll + public static void setUp() { + aclTlsEndpoint = Endpoints.getRedisEndpoint("standalone0-acl-tls"); + aclEndpoint = Endpoints.getRedisEndpoint("standalone0-acl"); + sentinelTlsEndpoint = Endpoints.getRedisEndpoint("sentinel-standalone0-tls"); + } + + /** + * Tests sentinel without SSL connecting to Redis master with SSL using SslOptions. + */ + @Test + public void sentinelWithoutSslConnectsToRedisWithSsl() { + DefaultJedisClientConfig masterConfig = aclTlsEndpoint.getClientConfigBuilder() + .clientName("master-client").sslOptions(sslOptions) + .hostAndPortMapper(PRIMARY_SSL_PORT_MAPPER).build(); + + DefaultJedisClientConfig sentinelConfig = createSentinelConfigWithoutSsl(); + + try (JedisSentinelPool pool = new JedisSentinelPool(MASTER_NAME, sentinels, masterConfig, + sentinelConfig)) { + pool.getResource().close(); + } + + try (JedisSentinelPool pool = new JedisSentinelPool(MASTER_NAME, sentinels, POOL_CONFIG, + masterConfig, sentinelConfig)) { + pool.getResource().close(); + } + } + + /** + * Tests sentinel with SSL (using SslOptions) connecting to Redis master without SSL. + */ + @Test + public void sentinelWithSslConnectsToRedisWithoutSsl() { + DefaultJedisClientConfig masterConfig = aclEndpoint.getClientConfigBuilder() + .clientName("master-client").build(); + + DefaultJedisClientConfig sentinelConfig = sentinelTlsEndpoint.getClientConfigBuilder() + .sslOptions(sslOptions).hostAndPortMapper(SENTINEL_SSL_PORT_MAPPER).build(); + + try (JedisSentinelPool pool = new JedisSentinelPool(MASTER_NAME, sentinels, masterConfig, + sentinelConfig)) { + pool.getResource().close(); + } + + try (JedisSentinelPool pool = new JedisSentinelPool(MASTER_NAME, sentinels, POOL_CONFIG, + masterConfig, sentinelConfig)) { + pool.getResource().close(); + } + } + + /** + * Tests both sentinel and Redis master with SSL using SslOptions. + */ + @Test + public void sentinelWithSslConnectsToRedisWithSsl() { + DefaultJedisClientConfig masterConfig = aclTlsEndpoint.getClientConfigBuilder() + .clientName("master-client").sslOptions(sslOptions) + .hostAndPortMapper(PRIMARY_SSL_PORT_MAPPER).build(); + + DefaultJedisClientConfig sentinelConfig = createSentinelConfigWithSsl(sslOptions); + + try (JedisSentinelPool pool = new JedisSentinelPool(MASTER_NAME, sentinels, masterConfig, + sentinelConfig)) { + pool.getResource().close(); + } + + try (JedisSentinelPool pool = new JedisSentinelPool(MASTER_NAME, sentinels, POOL_CONFIG, + masterConfig, sentinelConfig)) { + pool.getResource().close(); + } + } +} diff --git a/src/test/java/redis/clients/jedis/tls/SSLOptionsRedisClientIT.java b/src/test/java/redis/clients/jedis/tls/SSLOptionsRedisClientIT.java new file mode 100644 index 0000000000..ae13a62710 --- /dev/null +++ b/src/test/java/redis/clients/jedis/tls/SSLOptionsRedisClientIT.java @@ -0,0 +1,45 @@ +package redis.clients.jedis.tls; + +import static org.junit.jupiter.api.Assertions.assertEquals; + +import org.junit.jupiter.api.Test; +import org.junit.jupiter.params.ParameterizedTest; +import org.junit.jupiter.params.provider.MethodSource; + +import redis.clients.jedis.RedisClient; +import redis.clients.jedis.SslOptions; + +/** + * SSL/TLS tests for {@link RedisClient} using SslOptions builder pattern. + *

+ * Tests various SSL/TLS connection configurations including: + *

    + *
  • Basic SSL connection with truststore
  • + *
  • Insecure SSL mode (no certificate verification)
  • + *
  • Custom SSL protocol
  • + *
  • ACL authentication over SSL
  • + *
+ */ +public class SSLOptionsRedisClientIT extends RedisClientTlsTestBase { + + @ParameterizedTest(name = "connectWithSsl_{0}") + @MethodSource("sslOptionsProvider") + void connectWithSsl(String testName, SslOptions ssl) { + try (RedisClient client = RedisClient.builder().hostAndPort(endpoint.getHostAndPort()) + .clientConfig(endpoint.getClientConfigBuilder().sslOptions(ssl).build()).build()) { + assertEquals("PONG", client.ping()); + } + } + + /** + * Tests ACL authentication over SSL. + */ + @Test + public void connectWithAcl() { + try (RedisClient client = RedisClient.builder().hostAndPort(aclEndpoint.getHostAndPort()) + .clientConfig(aclEndpoint.getClientConfigBuilder().sslOptions(sslOptions).build()) + .build()) { + assertEquals("PONG", client.ping()); + } + } +} diff --git a/src/test/java/redis/clients/jedis/tls/SSLOptionsRedisClusterClientIT.java b/src/test/java/redis/clients/jedis/tls/SSLOptionsRedisClusterClientIT.java new file mode 100644 index 0000000000..7ec79760b6 --- /dev/null +++ b/src/test/java/redis/clients/jedis/tls/SSLOptionsRedisClusterClientIT.java @@ -0,0 +1,175 @@ +package redis.clients.jedis.tls; + +import static org.hamcrest.MatcherAssert.assertThat; +import static org.hamcrest.Matchers.anyOf; +import static org.hamcrest.Matchers.containsString; +import static org.junit.jupiter.api.Assertions.assertEquals; +import static org.junit.jupiter.api.Assertions.assertTrue; +import static org.junit.jupiter.api.Assertions.fail; + +import java.util.Collections; +import java.util.Map; +import javax.net.ssl.HostnameVerifier; +import javax.net.ssl.SSLParameters; + +import org.junit.jupiter.api.Test; +import redis.clients.jedis.*; +import redis.clients.jedis.exceptions.JedisClusterOperationException; +import redis.clients.jedis.util.TlsUtil; + +/** + * SSL/TLS Redis Cluster tests using SslOptions builder pattern. + */ +public class SSLOptionsRedisClusterClientIT extends RedisClusterTestBase { + + private static final int DEFAULT_REDIRECTIONS = 5; + private static final ConnectionPoolConfig DEFAULT_POOL_CONFIG = new ConnectionPoolConfig(); + + @Test + public void testSSLDiscoverNodesAutomatically() { + try (RedisClusterClient jc2 = RedisClusterClient.builder() + .nodes(Collections.singleton(tlsEndpoint.getHostAndPort())) + .clientConfig(DefaultJedisClientConfig.builder().password(tlsEndpoint.getPassword()) + .sslOptions(SslOptions.builder().truststore(trustStorePath.toFile()) + .trustStoreType("jceks").build()) + .hostAndPortMapper(hostAndPortMap).build()) + .maxAttempts(DEFAULT_REDIRECTIONS).poolConfig(DEFAULT_POOL_CONFIG).build()) { + Map clusterNodes = jc2.getClusterNodes(); + assertEquals(6, clusterNodes.size()); + assertTrue(clusterNodes.containsKey(tlsEndpoint.getHostAndPort(0).toString())); + assertTrue(clusterNodes.containsKey(tlsEndpoint.getHostAndPort(1).toString())); + assertTrue(clusterNodes.containsKey(tlsEndpoint.getHostAndPort(2).toString())); + jc2.get("foo"); + } + } + + @Test + public void testSSLWithoutPortMap() { + try (RedisClusterClient jc = RedisClusterClient.builder() + .nodes(Collections.singleton(tlsEndpoint.getHostAndPort())) + .clientConfig(DefaultJedisClientConfig.builder().password(tlsEndpoint.getPassword()) + .sslOptions(SslOptions.builder().truststore(trustStorePath.toFile()) + .trustStoreType("jceks").sslVerifyMode(SslVerifyMode.CA).build()) + .build()) + .maxAttempts(DEFAULT_REDIRECTIONS).poolConfig(DEFAULT_POOL_CONFIG).build()) { + Map clusterNodes = jc.getClusterNodes(); + assertEquals(6, clusterNodes.size()); + assertTrue(clusterNodes.containsKey(tlsEndpoint.getHostAndPort(0).toString())); + assertTrue(clusterNodes.containsKey(tlsEndpoint.getHostAndPort(1).toString())); + assertTrue(clusterNodes.containsKey(tlsEndpoint.getHostAndPort(2).toString())); + jc.get("foo"); + } + } + + @Test + public void connectByIpAddress() { + try (RedisClusterClient jc = RedisClusterClient.builder() + .nodes(Collections.singleton(tlsEndpoint.getHostAndPort())) + .clientConfig(DefaultJedisClientConfig.builder().password(tlsEndpoint.getPassword()) + .sslOptions(SslOptions.builder().truststore(trustStorePath.toFile()) + .trustStoreType("jceks").build()) + .hostAndPortMapper(hostAndPortMap).build()) + .maxAttempts(DEFAULT_REDIRECTIONS).poolConfig(DEFAULT_POOL_CONFIG).build()) { + jc.get("foo"); + } + } + + @Test + public void connectToNodesFailsWithSSLParametersAndNoHostMapping() { + final SSLParameters sslParameters = new SSLParameters(); + sslParameters.setEndpointIdentificationAlgorithm("HTTPS"); + + try (RedisClusterClient jc = RedisClusterClient.builder() + .nodes(Collections.singleton(new HostAndPort("localhost", tlsEndpoint.getPort()))) + .clientConfig(DefaultJedisClientConfig.builder().password(tlsEndpoint.getPassword()) + .sslOptions(SslOptions.builder().sslParameters(sslParameters) + .truststore(trustStorePath.toFile()).trustStoreType("jceks").build()) + .hostAndPortMapper(portMap).build()) + .maxAttempts(DEFAULT_REDIRECTIONS).poolConfig(DEFAULT_POOL_CONFIG).build()) { + jc.get("foo"); + fail("It should fail after all cluster attempts."); + } catch (JedisClusterOperationException e) { + // initial connection to localhost works, but subsequent connections to nodes use 127.0.0.1 + // and fail hostname verification + assertThat(e.getMessage(), anyOf(containsString("No more cluster attempts left."), + containsString("Cluster retry deadline exceeded."))); + } + } + + @Test + public void connectToNodesSucceedsWithSSLParametersAndHostMapping() { + final SSLParameters sslParameters = new SSLParameters(); + sslParameters.setEndpointIdentificationAlgorithm("HTTPS"); + + try (RedisClusterClient jc = RedisClusterClient.builder() + .nodes(Collections.singleton(tlsEndpoint.getHostAndPort())) + .clientConfig(DefaultJedisClientConfig.builder().password(tlsEndpoint.getPassword()) + .sslOptions(SslOptions.builder().sslParameters(sslParameters) + .truststore(trustStorePath.toFile()).trustStoreType("jceks").build()) + .hostAndPortMapper(hostAndPortMap).build()) + .maxAttempts(DEFAULT_REDIRECTIONS).poolConfig(DEFAULT_POOL_CONFIG).build()) { + jc.get("foo"); + } + } + + @Test + public void connectByIpAddressFailsWithSSLParameters() { + final SSLParameters sslParameters = new SSLParameters(); + sslParameters.setEndpointIdentificationAlgorithm("HTTPS"); + + try (RedisClusterClient jc = RedisClusterClient.builder() + .nodes(Collections.singleton(tlsEndpoint.getHostAndPort())) + .clientConfig(DefaultJedisClientConfig.builder().password(tlsEndpoint.getPassword()) + .sslOptions(SslOptions.builder().sslParameters(sslParameters) + .truststore(trustStorePath.toFile()).trustStoreType("jceks").build()) + .hostAndPortMapper(hostAndPortMap).build()) + .maxAttempts(DEFAULT_REDIRECTIONS).poolConfig(DEFAULT_POOL_CONFIG).build()) { + } catch (JedisClusterOperationException e) { + assertEquals("Could not initialize cluster slots cache.", e.getMessage()); + } + } + + @Test + public void connectWithCustomHostNameVerifier() { + HostnameVerifier hostnameVerifier = new TlsUtil.BasicHostnameVerifier(); + HostnameVerifier localhostVerifier = new TlsUtil.LocalhostVerifier(); + + SslOptions sslOptions = SslOptions.builder().truststore(trustStorePath.toFile()) + .trustStoreType("jceks").sslVerifyMode(SslVerifyMode.CA).build(); + + try (RedisClusterClient jc = RedisClusterClient.builder() + .nodes(Collections.singleton(new HostAndPort("localhost", tlsEndpoint.getPort()))) + .clientConfig(DefaultJedisClientConfig.builder().password(tlsEndpoint.getPassword()) + .sslOptions(sslOptions).hostnameVerifier(hostnameVerifier).hostAndPortMapper(portMap) + .build()) + .maxAttempts(DEFAULT_REDIRECTIONS).poolConfig(DEFAULT_POOL_CONFIG).build()) { + jc.get("foo"); + fail("It should fail after all cluster attempts."); + } catch (JedisClusterOperationException e) { + // initial connection made with 'localhost' but subsequent connections to nodes use 127.0.0.1 + // which causes custom hostname verification to fail + assertThat(e.getMessage(), anyOf(containsString("No more cluster attempts left."), + containsString("Cluster retry deadline exceeded."))); + } + + try (RedisClusterClient jc2 = RedisClusterClient.builder() + .nodes(Collections.singleton(new HostAndPort("127.0.0.1", tlsEndpoint.getPort()))) + .clientConfig(DefaultJedisClientConfig.builder().password(tlsEndpoint.getPassword()) + .sslOptions(sslOptions).hostnameVerifier(hostnameVerifier).hostAndPortMapper(portMap) + .build()) + .maxAttempts(DEFAULT_REDIRECTIONS).poolConfig(DEFAULT_POOL_CONFIG).build()) { + } catch (JedisClusterOperationException e) { + assertEquals("Could not initialize cluster slots cache.", e.getMessage()); + } + + try (RedisClusterClient jc3 = RedisClusterClient.builder() + .nodes(Collections.singleton(tlsEndpoint.getHostAndPort())) + .clientConfig(DefaultJedisClientConfig.builder().password(tlsEndpoint.getPassword()) + .sslOptions(sslOptions).hostnameVerifier(localhostVerifier).hostAndPortMapper(portMap) + .build()) + .maxAttempts(DEFAULT_REDIRECTIONS).poolConfig(DEFAULT_POOL_CONFIG).build()) { + jc3.get("foo"); + } + } + +} diff --git a/src/test/java/redis/clients/jedis/tls/SSLOptionsRedisSentinelClientIT.java b/src/test/java/redis/clients/jedis/tls/SSLOptionsRedisSentinelClientIT.java new file mode 100644 index 0000000000..88c6fc36ef --- /dev/null +++ b/src/test/java/redis/clients/jedis/tls/SSLOptionsRedisSentinelClientIT.java @@ -0,0 +1,95 @@ +package redis.clients.jedis.tls; + +import static org.junit.jupiter.api.Assertions.assertEquals; + +import org.junit.jupiter.api.BeforeAll; +import org.junit.jupiter.api.Test; +import org.junit.jupiter.params.ParameterizedTest; +import org.junit.jupiter.params.provider.MethodSource; + +import redis.clients.jedis.DefaultJedisClientConfig; +import redis.clients.jedis.EndpointConfig; +import redis.clients.jedis.Endpoints; +import redis.clients.jedis.RedisSentinelClient; +import redis.clients.jedis.SslOptions; + +/** + * SSL/TLS tests for RedisSentinelClient using SslOptions builder pattern. + *

+ * Tests various SSL/TLS connection configurations including: + *

    + *
  • Basic SSL connection with truststore
  • + *
  • Insecure SSL mode (no certificate verification)
  • + *
  • Custom SSL protocol
  • + *
  • ACL authentication over SSL
  • + *
+ *

+ * Both master and sentinel connections use SSL in these tests. + */ +public class SSLOptionsRedisSentinelClientIT extends RedisSentinelTlsTestBase { + + // Endpoint for master with ACL authentication + private static EndpointConfig aclEndpoint; + + @BeforeAll + public static void setUp() { + aclEndpoint = Endpoints.getRedisEndpoint("standalone0-acl-tls"); + } + + /** + * Tests connecting to Redis master and sentinel with various SSL configurations. Both master and + * sentinel connections use SSL. + */ + @ParameterizedTest(name = "connectWithSsl_{0}") + @MethodSource("sslOptionsProvider") + void connectWithSsl(String testName, SslOptions ssl) { + DefaultJedisClientConfig masterConfig = aclEndpoint.getClientConfigBuilder() + .clientName("master-client").sslOptions(ssl).hostAndPortMapper(PRIMARY_SSL_PORT_MAPPER) + .build(); + + DefaultJedisClientConfig sentinelConfig = createSentinelConfigWithSsl(ssl); + + try (RedisSentinelClient client = RedisSentinelClient.builder().masterName(MASTER_NAME) + .sentinels(sentinels).clientConfig(masterConfig).sentinelClientConfig(sentinelConfig) + .build()) { + assertEquals("PONG", client.ping()); + } + } + + /** + * Tests ACL authentication over SSL (same as truststore test but explicitly named). + */ + @Test + public void connectWithAcl() { + DefaultJedisClientConfig masterConfig = aclEndpoint.getClientConfigBuilder() + .clientName("master-client").sslOptions(sslOptions) + .hostAndPortMapper(PRIMARY_SSL_PORT_MAPPER).build(); + + DefaultJedisClientConfig sentinelConfig = createSentinelConfigWithSsl(sslOptions); + + try (RedisSentinelClient client = RedisSentinelClient.builder().masterName(MASTER_NAME) + .sentinels(sentinels).clientConfig(masterConfig).sentinelClientConfig(sentinelConfig) + .build()) { + assertEquals("PONG", client.ping()); + } + } + + /** + * Tests that sentinel without SSL can connect to Redis master with SSL. + */ + @Test + public void sentinelWithoutSslConnectsToRedisWithSsl() { + DefaultJedisClientConfig masterConfig = aclEndpoint.getClientConfigBuilder() + .clientName("master-client").sslOptions(sslOptions) + .hostAndPortMapper(PRIMARY_SSL_PORT_MAPPER).build(); + + DefaultJedisClientConfig sentinelConfig = createSentinelConfigWithoutSsl(); + + try (RedisSentinelClient client = RedisSentinelClient.builder().masterName(MASTER_NAME) + .sentinels(sentinels).clientConfig(masterConfig).sentinelClientConfig(sentinelConfig) + .build()) { + assertEquals("PONG", client.ping()); + } + } + +} diff --git a/src/test/resources/endpoints.json b/src/test/resources/endpoints.json index 480af9cb2e..fa5605c00d 100644 --- a/src/test/resources/endpoints.json +++ b/src/test/resources/endpoints.json @@ -157,16 +157,6 @@ "redis://127.0.0.1:7481" ] }, - "cluster-unbound-tls": { - "password": "cluster", - "tls": true, - "certificates_location": "cluster-unbound/work/tls", - "endpoints": [ - "rediss://127.0.0.1:8379", - "rediss://127.0.0.1:8380", - "rediss://127.0.0.1:8381" - ] - }, "cluster-stable-tls": { "password": "cluster", "tls": true, diff --git a/src/test/resources/env/cluster-unbound/config/node-7379-8379/redis.conf b/src/test/resources/env/cluster-unbound/config/node-7379-8379/redis.conf index 35a794a99b..b285f173cd 100644 --- a/src/test/resources/env/cluster-unbound/config/node-7379-8379/redis.conf +++ b/src/test/resources/env/cluster-unbound/config/node-7379-8379/redis.conf @@ -1,8 +1,6 @@ bind 0.0.0.0 port 7379 -tls-port 8379 requirepass cluster -tls-auth-clients no cluster-node-timeout 150 save "" appendonly no diff --git a/src/test/resources/env/cluster-unbound/config/node-7380-8380/redis.conf b/src/test/resources/env/cluster-unbound/config/node-7380-8380/redis.conf index c6129ed906..9694a663df 100644 --- a/src/test/resources/env/cluster-unbound/config/node-7380-8380/redis.conf +++ b/src/test/resources/env/cluster-unbound/config/node-7380-8380/redis.conf @@ -1,8 +1,6 @@ bind 0.0.0.0 port 7380 -tls-port 8380 requirepass cluster -tls-auth-clients no cluster-node-timeout 150 save "" appendonly no diff --git a/src/test/resources/env/cluster-unbound/config/node-7381-8381/redis.conf b/src/test/resources/env/cluster-unbound/config/node-7381-8381/redis.conf index aed97aceba..9fae282cea 100644 --- a/src/test/resources/env/cluster-unbound/config/node-7381-8381/redis.conf +++ b/src/test/resources/env/cluster-unbound/config/node-7381-8381/redis.conf @@ -1,8 +1,6 @@ bind 0.0.0.0 port 7381 -tls-port 8381 requirepass cluster -tls-auth-clients no cluster-node-timeout 150 save "" appendonly no diff --git a/src/test/resources/env/cluster-unbound/config/node-7382-8382/redis.conf b/src/test/resources/env/cluster-unbound/config/node-7382-8382/redis.conf index 41e8cd15c9..5b85b4ba4f 100644 --- a/src/test/resources/env/cluster-unbound/config/node-7382-8382/redis.conf +++ b/src/test/resources/env/cluster-unbound/config/node-7382-8382/redis.conf @@ -1,8 +1,6 @@ bind 0.0.0.0 requirepass cluster port 7382 -tls-port 8382 -tls-auth-clients no cluster-node-timeout 150 save "" appendonly no diff --git a/src/test/resources/env/cluster-unbound/config/node-7383-8383/redis.conf b/src/test/resources/env/cluster-unbound/config/node-7383-8383/redis.conf index aa5669901f..5ec98c4027 100644 --- a/src/test/resources/env/cluster-unbound/config/node-7383-8383/redis.conf +++ b/src/test/resources/env/cluster-unbound/config/node-7383-8383/redis.conf @@ -1,8 +1,6 @@ bind 0.0.0.0 port 7383 -tls-port 8383 requirepass cluster -tls-auth-clients no cluster-node-timeout 150 save "" appendonly no diff --git a/src/test/resources/env/docker-compose.yml b/src/test/resources/env/docker-compose.yml index dfca32b43f..89de19cad1 100644 --- a/src/test/resources/env/docker-compose.yml +++ b/src/test/resources/env/docker-compose.yml @@ -123,30 +123,33 @@ services: <<: *client-libs-image container_name: cluster-unbound-1 environment: - - TLS_ENABLED=yes - REDIS_PASSWORD=cluster ports: - "7379-7383:7379-7383" - - "8379-8383:8379-8383" volumes: - ${REDIS_ENV_CONF_DIR}/cluster-unbound/config:/redis/config:r - ${REDIS_ENV_WORK_DIR}/cluster-unbound/work:/redis/work:rw + #TLS endpoints of Cluster stable are used for TLS tests that do not require client authentication cluster-stable: sysctls: - net.ipv6.conf.all.disable_ipv6=1 <<: *client-libs-image container_name: cluster-stable-1 #network_mode: host - command: --cluster-announce-ip 127.0.0.1 --cluster-node-timeout 150 --save "" + command: --cluster-announce-ip 127.0.0.1 --cluster-node-timeout 150 --tls-auth-clients no --save "" environment: - REDIS_CLUSTER=yes - REDIS_PASSWORD=cluster - PORT=7479 + - TLS_PORT=8479 - NODES=6 - REPLICAS=1 + - TLS_ENABLED=yes + - TLS_AUTH_CLIENTS_USER=off ports: - "7479-7484:7479-7484" + - "8479-8484:8479-8484" volumes: - ${REDIS_ENV_CONF_DIR}/cluster-stable/config:/redis/config:r - ${REDIS_ENV_WORK_DIR}/cluster-stable/work:/redis/work:rw