From 86fa0cb72f13930e18ab1a8c0c53f71d1c2704c0 Mon Sep 17 00:00:00 2001 From: Jorge Ferreira Date: Mon, 29 Jun 2026 13:50:33 +0100 Subject: [PATCH] feat: expose sslSocketFactory, sslParameters, and hostnameVerifier on RedisStoreBuilder --- .../integrations/RedisStoreBuilder.java | 56 ++++++++++++++++++- .../integrations/RedisStoreImplBase.java | 7 ++- .../RedisDataStoreBuilderTest.java | 29 ++++++++++ 3 files changed, 87 insertions(+), 5 deletions(-) diff --git a/lib/java-server-sdk-redis-store/src/main/java/com/launchdarkly/sdk/server/integrations/RedisStoreBuilder.java b/lib/java-server-sdk-redis-store/src/main/java/com/launchdarkly/sdk/server/integrations/RedisStoreBuilder.java index 1a7dbff9..8da1e451 100644 --- a/lib/java-server-sdk-redis-store/src/main/java/com/launchdarkly/sdk/server/integrations/RedisStoreBuilder.java +++ b/lib/java-server-sdk-redis-store/src/main/java/com/launchdarkly/sdk/server/integrations/RedisStoreBuilder.java @@ -11,6 +11,10 @@ import java.net.URI; import java.time.Duration; +import javax.net.ssl.HostnameVerifier; +import javax.net.ssl.SSLParameters; +import javax.net.ssl.SSLSocketFactory; + import redis.clients.jedis.JedisPoolConfig; import redis.clients.jedis.Protocol; @@ -56,7 +60,7 @@ * .build(); * * - * @param the component type that this builder is being used for + * @param the component type that this builder is being used for * * @since 5.0.0 */ @@ -80,6 +84,9 @@ public abstract class RedisStoreBuilder implements ComponentConfigurer, Di String password = null; boolean tls = false; JedisPoolConfig poolConfig = null; + SSLSocketFactory sslSocketFactory = null; + SSLParameters sslParameters = null; + HostnameVerifier hostnameVerifier = null; // These constructors are called only from Implementations RedisStoreBuilder() { @@ -146,7 +153,52 @@ public RedisStoreBuilder tls(boolean tls) { this.tls = tls; return this; } - + + /** + * Optionally specifies a custom {@link SSLSocketFactory} for TLS connections. + *

+ * This is only used when TLS is enabled (either via {@link #tls(boolean)} or by using a + * {@code rediss:} URI). If TLS is not enabled this value is silently ignored. If not set, + * the JVM default SSL socket factory is used. + * + * @param sslSocketFactory the SSL socket factory, or null to use the default + * @return the builder + */ + public RedisStoreBuilder sslSocketFactory(SSLSocketFactory sslSocketFactory) { + this.sslSocketFactory = sslSocketFactory; + return this; + } + + /** + * Optionally specifies {@link SSLParameters} for TLS connections. + *

+ * This is only used when TLS is enabled (either via {@link #tls(boolean)} or by using a + * {@code rediss:} URI). If TLS is not enabled this value is silently ignored. If not set, + * the JVM default SSL parameters are used. + * + * @param sslParameters the SSL parameters, or null to use the default + * @return the builder + */ + public RedisStoreBuilder sslParameters(SSLParameters sslParameters) { + this.sslParameters = sslParameters; + return this; + } + + /** + * Optionally specifies a {@link HostnameVerifier} for TLS connections. + *

+ * This is only used when TLS is enabled (either via {@link #tls(boolean)} or by using a + * {@code rediss:} URI). If TLS is not enabled this value is silently ignored. If not set, + * the JVM default hostname verifier is used. + * + * @param hostnameVerifier the hostname verifier, or null to use the default + * @return the builder + */ + public RedisStoreBuilder hostnameVerifier(HostnameVerifier hostnameVerifier) { + this.hostnameVerifier = hostnameVerifier; + return this; + } + /** * Specifies a Redis host URI other than {@link #DEFAULT_URI}. * diff --git a/lib/java-server-sdk-redis-store/src/main/java/com/launchdarkly/sdk/server/integrations/RedisStoreImplBase.java b/lib/java-server-sdk-redis-store/src/main/java/com/launchdarkly/sdk/server/integrations/RedisStoreImplBase.java index 2241675d..47587c28 100644 --- a/lib/java-server-sdk-redis-store/src/main/java/com/launchdarkly/sdk/server/integrations/RedisStoreImplBase.java +++ b/lib/java-server-sdk-redis-store/src/main/java/com/launchdarkly/sdk/server/integrations/RedisStoreImplBase.java @@ -40,6 +40,7 @@ protected RedisStoreImplBase(RedisStoreBuilder builder, LDLogger logger) { this.prefix = (builder.prefix == null || builder.prefix.isEmpty()) ? RedisStoreBuilder.DEFAULT_PREFIX : builder.prefix; + this.pool = new JedisPool(poolConfig, host, port, @@ -50,9 +51,9 @@ protected RedisStoreImplBase(RedisStoreBuilder builder, LDLogger logger) { database, null, // clientName tls, - null, // sslSocketFactory - null, // sslParameters - null // hostnameVerifier + builder.sslSocketFactory, + builder.sslParameters, + builder.hostnameVerifier ); } diff --git a/lib/java-server-sdk-redis-store/src/test/java/com/launchdarkly/sdk/server/integrations/RedisDataStoreBuilderTest.java b/lib/java-server-sdk-redis-store/src/test/java/com/launchdarkly/sdk/server/integrations/RedisDataStoreBuilderTest.java index 45b840ab..128ccee1 100644 --- a/lib/java-server-sdk-redis-store/src/test/java/com/launchdarkly/sdk/server/integrations/RedisDataStoreBuilderTest.java +++ b/lib/java-server-sdk-redis-store/src/test/java/com/launchdarkly/sdk/server/integrations/RedisDataStoreBuilderTest.java @@ -11,6 +11,11 @@ import static org.junit.Assert.assertNull; import static org.junit.Assert.assertTrue; +import javax.net.ssl.HostnameVerifier; +import javax.net.ssl.HttpsURLConnection; +import javax.net.ssl.SSLParameters; +import javax.net.ssl.SSLSocketFactory; + import redis.clients.jedis.JedisPoolConfig; import redis.clients.jedis.Protocol; @@ -23,6 +28,9 @@ public void testDefaultValues() { assertNull(conf.database); assertNull(conf.password); assertFalse(conf.tls); + assertNull(conf.sslSocketFactory); + assertNull(conf.sslParameters); + assertNull(conf.hostnameVerifier); assertEquals(Duration.ofMillis(Protocol.DEFAULT_TIMEOUT), conf.connectTimeout); assertEquals(Duration.ofMillis(Protocol.DEFAULT_TIMEOUT), conf.socketTimeout); assertEquals(RedisStoreBuilder.DEFAULT_PREFIX, conf.prefix); @@ -53,6 +61,27 @@ public void testTlsConfigured() { RedisStoreBuilder conf = Redis.dataStore().tls(true); assertTrue(conf.tls); } + + @Test + public void testSslSocketFactoryConfigured() { + SSLSocketFactory factory = (SSLSocketFactory) SSLSocketFactory.getDefault(); + RedisStoreBuilder conf = Redis.dataStore().sslSocketFactory(factory); + assertEquals(factory, conf.sslSocketFactory); + } + + @Test + public void testSslParametersConfigured() { + SSLParameters params = new SSLParameters(); + RedisStoreBuilder conf = Redis.dataStore().sslParameters(params); + assertEquals(params, conf.sslParameters); + } + + @Test + public void testHostnameVerifierConfigured() { + HostnameVerifier verifier = HttpsURLConnection.getDefaultHostnameVerifier(); + RedisStoreBuilder conf = Redis.dataStore().hostnameVerifier(verifier); + assertEquals(verifier, conf.hostnameVerifier); + } @Test public void testPrefixConfigured() throws URISyntaxException {