diff --git a/src/main/java/org/springframework/data/redis/connection/lettuce/DefaultLettuceClientConfiguration.java b/src/main/java/org/springframework/data/redis/connection/lettuce/DefaultLettuceClientConfiguration.java index c166000bc..976037e1a 100644 --- a/src/main/java/org/springframework/data/redis/connection/lettuce/DefaultLettuceClientConfiguration.java +++ b/src/main/java/org/springframework/data/redis/connection/lettuce/DefaultLettuceClientConfiguration.java @@ -17,6 +17,7 @@ package org.springframework.data.redis.connection.lettuce; import io.lettuce.core.ClientOptions; import io.lettuce.core.ReadFrom; +import io.lettuce.core.SslVerifyMode; import io.lettuce.core.resource.ClientResources; import java.time.Duration; @@ -30,12 +31,13 @@ import org.springframework.lang.Nullable; * @author Mark Paluch * @author Christoph Strobl * @author Yanming Zhou + * @author Zhian Chen * @since 2.0 */ class DefaultLettuceClientConfiguration implements LettuceClientConfiguration { private final boolean useSsl; - private final boolean verifyPeer; + private final SslVerifyMode verifyMode; private final boolean startTls; private final Optional clientResources; private final Optional clientOptions; @@ -52,7 +54,7 @@ class DefaultLettuceClientConfiguration implements LettuceClientConfiguration { Duration timeout, Duration shutdownTimeout, @Nullable Duration shutdownQuietPeriod) { this.useSsl = useSsl; - this.verifyPeer = verifyPeer; + this.verifyMode = verifyPeer ? SslVerifyMode.FULL : SslVerifyMode.NONE; this.startTls = startTls; this.clientResources = Optional.ofNullable(clientResources); this.clientOptions = Optional.ofNullable(clientOptions); @@ -71,7 +73,12 @@ class DefaultLettuceClientConfiguration implements LettuceClientConfiguration { @Override public boolean isVerifyPeer() { - return verifyPeer; + return verifyMode != SslVerifyMode.NONE; + } + + @Override + public SslVerifyMode getVerifyMode() { + return verifyMode; } @Override diff --git a/src/main/java/org/springframework/data/redis/connection/lettuce/DefaultLettucePoolingClientConfiguration.java b/src/main/java/org/springframework/data/redis/connection/lettuce/DefaultLettucePoolingClientConfiguration.java index fac5f8ec2..70043b16a 100644 --- a/src/main/java/org/springframework/data/redis/connection/lettuce/DefaultLettucePoolingClientConfiguration.java +++ b/src/main/java/org/springframework/data/redis/connection/lettuce/DefaultLettucePoolingClientConfiguration.java @@ -17,6 +17,7 @@ package org.springframework.data.redis.connection.lettuce; import io.lettuce.core.ClientOptions; import io.lettuce.core.ReadFrom; +import io.lettuce.core.SslVerifyMode; import io.lettuce.core.resource.ClientResources; import java.time.Duration; @@ -30,6 +31,7 @@ import org.apache.commons.pool2.impl.GenericObjectPoolConfig; * @author Mark Paluch * @author Christoph Strobl * @author Yanming Zhou + * @author Zhian Chen * @since 2.0 */ class DefaultLettucePoolingClientConfiguration implements LettucePoolingClientConfiguration { @@ -54,6 +56,11 @@ class DefaultLettucePoolingClientConfiguration implements LettucePoolingClientCo return clientConfiguration.isVerifyPeer(); } + @Override + public SslVerifyMode getVerifyMode() { + return clientConfiguration.getVerifyMode(); + } + @Override public boolean isStartTls() { return clientConfiguration.isStartTls(); diff --git a/src/main/java/org/springframework/data/redis/connection/lettuce/LettuceClientConfiguration.java b/src/main/java/org/springframework/data/redis/connection/lettuce/LettuceClientConfiguration.java index 637222684..77ac8c5d4 100644 --- a/src/main/java/org/springframework/data/redis/connection/lettuce/LettuceClientConfiguration.java +++ b/src/main/java/org/springframework/data/redis/connection/lettuce/LettuceClientConfiguration.java @@ -18,6 +18,7 @@ package org.springframework.data.redis.connection.lettuce; import io.lettuce.core.ClientOptions; import io.lettuce.core.ReadFrom; import io.lettuce.core.RedisURI; +import io.lettuce.core.SslVerifyMode; import io.lettuce.core.TimeoutOptions; import io.lettuce.core.resource.ClientResources; @@ -50,6 +51,7 @@ import org.springframework.util.ObjectUtils; * @author Mark Paluch * @author Christoph Strobl * @author Yanming Zhou + * @author Zhian Chen * @since 2.0 * @see org.springframework.data.redis.connection.RedisStandaloneConfiguration * @see org.springframework.data.redis.connection.RedisSentinelConfiguration @@ -67,6 +69,11 @@ public interface LettuceClientConfiguration { */ boolean isVerifyPeer(); + /** + * @return the {@link io.lettuce.core.SslVerifyMode}. + */ + SslVerifyMode getVerifyMode(); + /** * @return {@literal true} to use Start TLS ({@code true} if the first write request shouldn't be encrypted). */ @@ -166,7 +173,7 @@ public interface LettuceClientConfiguration { class LettuceClientConfigurationBuilder { boolean useSsl; - boolean verifyPeer = true; + SslVerifyMode verifyMode = SslVerifyMode.FULL; boolean startTls; @Nullable ClientResources clientResources; ClientOptions clientOptions = ClientOptions.builder().timeoutOptions(TimeoutOptions.enabled()).build(); @@ -189,7 +196,7 @@ public interface LettuceClientConfiguration { public LettuceClientConfigurationBuilder apply(RedisURI redisUri) { this.useSsl = redisUri.isSsl(); - this.verifyPeer = redisUri.isVerifyPeer(); + this.verifyMode = redisUri.getVerifyMode(); this.startTls = redisUri.isStartTls(); if (!redisUri.getTimeout().equals(RedisURI.DEFAULT_TIMEOUT_DURATION)) { @@ -347,7 +354,7 @@ public interface LettuceClientConfiguration { */ public LettuceClientConfiguration build() { - return new DefaultLettuceClientConfiguration(useSsl, verifyPeer, startTls, clientResources, clientOptions, + return new DefaultLettuceClientConfiguration(useSsl, verifyMode != SslVerifyMode.NONE, startTls, clientResources, clientOptions, clientName, readFrom, redisCredentialsProviderFactory, timeout, shutdownTimeout, shutdownQuietPeriod); } } @@ -372,7 +379,7 @@ public interface LettuceClientConfiguration { */ public LettuceSslClientConfigurationBuilder disablePeerVerification() { - delegate.verifyPeer = false; + delegate.verifyMode = SslVerifyMode.NONE; return this; } diff --git a/src/main/java/org/springframework/data/redis/connection/lettuce/LettuceConnectionFactory.java b/src/main/java/org/springframework/data/redis/connection/lettuce/LettuceConnectionFactory.java index c406faaa1..f37035f76 100644 --- a/src/main/java/org/springframework/data/redis/connection/lettuce/LettuceConnectionFactory.java +++ b/src/main/java/org/springframework/data/redis/connection/lettuce/LettuceConnectionFactory.java @@ -24,6 +24,7 @@ import io.lettuce.core.RedisClient; import io.lettuce.core.RedisConnectionException; import io.lettuce.core.RedisCredentialsProvider; import io.lettuce.core.RedisURI; +import io.lettuce.core.SslVerifyMode; import io.lettuce.core.api.StatefulConnection; import io.lettuce.core.api.StatefulRedisConnection; import io.lettuce.core.cluster.ClusterClientOptions; @@ -63,6 +64,7 @@ import org.springframework.data.redis.connection.*; import org.springframework.data.redis.connection.RedisConfiguration.ClusterConfiguration; import org.springframework.data.redis.connection.RedisConfiguration.WithDatabaseIndex; import org.springframework.data.redis.connection.RedisConfiguration.WithPassword; +import org.springframework.data.redis.connection.lettuce.LettuceConnection.PipeliningFlushPolicy; import org.springframework.data.redis.util.RedisAssertions; import org.springframework.data.util.Optionals; import org.springframework.lang.Nullable; @@ -115,6 +117,7 @@ import org.springframework.util.StringUtils; * @author Andrea Como * @author Chris Bono * @author John Blum + * @author Zhian Chen */ public class LettuceConnectionFactory implements RedisConnectionFactory, ReactiveRedisConnectionFactory, InitializingBean, DisposableBean, SmartLifecycle { @@ -490,6 +493,19 @@ public class LettuceConnectionFactory implements RedisConnectionFactory, Reactiv getMutableConfiguration().setVerifyPeer(verifyPeer); } + /** + * Returns the mode to verify peers when using SSL. + *

+ * FULL will enable a full certificate verification. + * CA means Lettuces only verify the certificate and skip verifying th hostname matches. NONE will disable + * verification and {@link #isVerifyPeer() isVerifyPeer} will return false with this mode. + * + * @return the verify mode of {@link io.lettuce.core.SslVerifyMode}. + */ + public SslVerifyMode getVerifyMode() { + return getMutableConfiguration().getVerifyMode(); + } + /** * Returns whether to issue a StartTLS. * @@ -1360,7 +1376,7 @@ public class LettuceConnectionFactory implements RedisConnectionFactory, Reactiv this.clientConfiguration.getClientName().ifPresent(it::setClientName); it.setSsl(this.clientConfiguration.isUseSsl()); - it.setVerifyPeer(this.clientConfiguration.isVerifyPeer()); + it.setVerifyPeer(this.clientConfiguration.getVerifyMode()); it.setStartTls(this.clientConfiguration.isStartTls()); it.setTimeout(this.clientConfiguration.getCommandTimeout()); }); @@ -1659,7 +1675,7 @@ public class LettuceConnectionFactory implements RedisConnectionFactory, Reactiv static class MutableLettuceClientConfiguration implements LettuceClientConfiguration { private boolean useSsl; - private boolean verifyPeer = true; + private SslVerifyMode verifyMode = SslVerifyMode.FULL; private boolean startTls; private @Nullable ClientResources clientResources; @@ -1680,11 +1696,20 @@ public class LettuceConnectionFactory implements RedisConnectionFactory, Reactiv @Override public boolean isVerifyPeer() { - return verifyPeer; + return verifyMode != SslVerifyMode.NONE; + } + + @Override + public SslVerifyMode getVerifyMode() { + return verifyMode; } void setVerifyPeer(boolean verifyPeer) { - this.verifyPeer = verifyPeer; + this.verifyMode = verifyPeer? SslVerifyMode.FULL: SslVerifyMode.NONE; + } + + void setVerifyPeer(SslVerifyMode verifyMode) { + this.verifyMode = verifyMode; } @Override diff --git a/src/test/java/org/springframework/data/redis/connection/lettuce/LettuceClientConfigurationUnitTests.java b/src/test/java/org/springframework/data/redis/connection/lettuce/LettuceClientConfigurationUnitTests.java index 35c818bb8..261e5ea96 100644 --- a/src/test/java/org/springframework/data/redis/connection/lettuce/LettuceClientConfigurationUnitTests.java +++ b/src/test/java/org/springframework/data/redis/connection/lettuce/LettuceClientConfigurationUnitTests.java @@ -19,6 +19,7 @@ import static org.assertj.core.api.Assertions.*; import io.lettuce.core.ClientOptions; import io.lettuce.core.RedisURI; +import io.lettuce.core.SslVerifyMode; import io.lettuce.core.TimeoutOptions; import io.lettuce.core.resource.ClientResources; @@ -34,6 +35,7 @@ import org.springframework.data.redis.test.extension.LettuceTestClientResources; * @author Mark Paluch * @author Christoph Strobl * @author Yanming Zhou + * @author Zhian Chen */ class LettuceClientConfigurationUnitTests { @@ -45,6 +47,7 @@ class LettuceClientConfigurationUnitTests { assertThat(configuration.isUseSsl()).isFalse(); assertThat(configuration.isVerifyPeer()).isTrue(); + assertThat(configuration.getVerifyMode().equals(SslVerifyMode.FULL)); assertThat(configuration.isStartTls()).isFalse(); assertThat(configuration.getClientOptions()).hasValueSatisfying(actual -> { @@ -78,6 +81,7 @@ class LettuceClientConfigurationUnitTests { assertThat(configuration.isUseSsl()).isTrue(); assertThat(configuration.isVerifyPeer()).isFalse(); + assertThat(configuration.getVerifyMode().equals(SslVerifyMode.NONE)); assertThat(configuration.isStartTls()).isTrue(); assertThat(configuration.getClientOptions()).contains(clientOptions); assertThat(configuration.getClientResources()).contains(sharedClientResources); @@ -115,6 +119,7 @@ class LettuceClientConfigurationUnitTests { assertThat(configuration.isUseSsl()).isTrue(); assertThat(configuration.isVerifyPeer()).isTrue(); + assertThat(configuration.getVerifyMode().equals(SslVerifyMode.FULL)); assertThat(configuration.isStartTls()).isFalse(); assertThat(configuration.getClientName()).contains("bar"); assertThat(configuration.getCommandTimeout()).isEqualTo(Duration.ofSeconds(10)); diff --git a/src/test/java/org/springframework/data/redis/connection/lettuce/LettuceConnectionFactoryUnitTests.java b/src/test/java/org/springframework/data/redis/connection/lettuce/LettuceConnectionFactoryUnitTests.java index b4dd713fb..952114585 100644 --- a/src/test/java/org/springframework/data/redis/connection/lettuce/LettuceConnectionFactoryUnitTests.java +++ b/src/test/java/org/springframework/data/redis/connection/lettuce/LettuceConnectionFactoryUnitTests.java @@ -26,6 +26,7 @@ import io.lettuce.core.AbstractRedisClient; import io.lettuce.core.ClientOptions; import io.lettuce.core.RedisClient; import io.lettuce.core.RedisURI; +import io.lettuce.core.SslVerifyMode; import io.lettuce.core.api.StatefulConnection; import io.lettuce.core.api.StatefulRedisConnection; import io.lettuce.core.cluster.ClusterClientOptions; @@ -76,6 +77,7 @@ import org.springframework.data.redis.test.extension.LettuceTestClientResources; * @author Andrea Como * @author Chris Bono * @author John Blum + * @author Zhian Chen */ class LettuceConnectionFactoryUnitTests { @@ -374,7 +376,9 @@ class LettuceConnectionFactoryUnitTests { assertThat(redisUri.isStartTls()).isFalse(); assertThat(connectionFactory.isStartTls()).isFalse(); assertThat(redisUri.isVerifyPeer()).isTrue(); + assertThat(redisUri.getVerifyMode().equals(SslVerifyMode.FULL)); assertThat(connectionFactory.isVerifyPeer()).isTrue(); + assertThat(connectionFactory.getVerifyMode().equals(SslVerifyMode.FULL)); } @Test // DATAREDIS-476 @@ -393,7 +397,9 @@ class LettuceConnectionFactoryUnitTests { assertThat(redisUri.isSsl()).isTrue(); assertThat(connectionFactory.isUseSsl()).isTrue(); assertThat(redisUri.isVerifyPeer()).isTrue(); + assertThat(redisUri.getVerifyMode().equals(SslVerifyMode.FULL)); assertThat(connectionFactory.isVerifyPeer()).isTrue(); + assertThat(connectionFactory.getVerifyMode().equals(SslVerifyMode.FULL)); } @Test // DATAREDIS-480 @@ -411,7 +417,9 @@ class LettuceConnectionFactoryUnitTests { RedisURI redisUri = (RedisURI) getField(client, "redisURI"); assertThat(redisUri.isVerifyPeer()).isFalse(); + assertThat(redisUri.getVerifyMode().equals(SslVerifyMode.NONE)); assertThat(connectionFactory.isVerifyPeer()).isFalse(); + assertThat(connectionFactory.getVerifyMode().equals(SslVerifyMode.NONE)); } @Test // DATAREDIS-480 @@ -450,7 +458,9 @@ class LettuceConnectionFactoryUnitTests { assertThat(redisUri.isSsl()).isTrue(); assertThat(connectionFactory.isUseSsl()).isTrue(); assertThat(redisUri.isVerifyPeer()).isTrue(); + assertThat(redisUri.getVerifyMode().equals(SslVerifyMode.FULL)); assertThat(connectionFactory.isVerifyPeer()).isTrue(); + assertThat(connectionFactory.getVerifyMode().equals(SslVerifyMode.FULL)); } @Test // DATAREDIS-990 @@ -470,6 +480,7 @@ class LettuceConnectionFactoryUnitTests { assertThat(redisUri.isVerifyPeer()).isFalse(); assertThat(connectionFactory.isVerifyPeer()).isFalse(); + assertThat(connectionFactory.getVerifyMode().equals(SslVerifyMode.NONE)); } @Test // DATAREDIS-990 @@ -545,6 +556,7 @@ class LettuceConnectionFactoryUnitTests { for (RedisURI uri : initialUris) { assertThat(uri.isVerifyPeer()).isTrue(); + assertThat(uri.getVerifyMode().equals(SslVerifyMode.FULL)); } } @@ -745,6 +757,7 @@ class LettuceConnectionFactoryUnitTests { assertThat(connectionFactory.isUseSsl()).isTrue(); assertThat(connectionFactory.isVerifyPeer()).isFalse(); + assertThat(connectionFactory.getVerifyMode().equals(SslVerifyMode.NONE)); assertThat(connectionFactory.isStartTls()).isTrue(); assertThat(connectionFactory.getClientResources()).isEqualTo(sharedClientResources); assertThat(connectionFactory.getTimeout()).isEqualTo(Duration.ofMinutes(5).toMillis()); diff --git a/src/test/java/org/springframework/data/redis/connection/lettuce/LettucePoolingClientConfigurationUnitTests.java b/src/test/java/org/springframework/data/redis/connection/lettuce/LettucePoolingClientConfigurationUnitTests.java index 85215098f..0cae2e9ed 100644 --- a/src/test/java/org/springframework/data/redis/connection/lettuce/LettucePoolingClientConfigurationUnitTests.java +++ b/src/test/java/org/springframework/data/redis/connection/lettuce/LettucePoolingClientConfigurationUnitTests.java @@ -19,6 +19,7 @@ import static org.assertj.core.api.Assertions.*; import io.lettuce.core.ClientOptions; import io.lettuce.core.ReadFrom; +import io.lettuce.core.SslVerifyMode; import io.lettuce.core.TimeoutOptions; import io.lettuce.core.resource.ClientResources; @@ -35,6 +36,7 @@ import org.springframework.data.redis.test.extension.LettuceTestClientResources; * @author Mark Paluch * @author Christoph Strobl * @author Longlong Zhao + * @author Zhian Chen */ class LettucePoolingClientConfigurationUnitTests { @@ -46,6 +48,7 @@ class LettucePoolingClientConfigurationUnitTests { assertThat(configuration.getPoolConfig()).isNotNull(); assertThat(configuration.isUseSsl()).isFalse(); assertThat(configuration.isVerifyPeer()).isTrue(); + assertThat(configuration.getVerifyMode().equals(SslVerifyMode.FULL)); assertThat(configuration.isStartTls()).isFalse(); assertThat(configuration.getClientOptions()).hasValueSatisfying(actual -> { @@ -80,6 +83,7 @@ class LettucePoolingClientConfigurationUnitTests { assertThat(configuration.getPoolConfig()).isEqualTo(poolConfig); assertThat(configuration.isUseSsl()).isTrue(); assertThat(configuration.isVerifyPeer()).isFalse(); + assertThat(configuration.getVerifyMode().equals(SslVerifyMode.NONE)); assertThat(configuration.isStartTls()).isTrue(); assertThat(configuration.getClientOptions()).contains(clientOptions); assertThat(configuration.getClientResources()).contains(sharedClientResources);