Add support for Lettuce's 6.2 RedisCredentialsProvider.
We now support construction of RedisCredentialsProvider through LettuceClientConfiguration and RedisCredentialsProviderFactory. The default implementation adapts credentials configured in RedisConfiguration objects. Closes: #2376 Original Pull Request: #2387
This commit is contained in:
committed by
Christoph Strobl
parent
c3ee0d8b3c
commit
8f37abe950
@@ -41,13 +41,15 @@ class DefaultLettuceClientConfiguration implements LettuceClientConfiguration {
|
|||||||
private final Optional<ClientOptions> clientOptions;
|
private final Optional<ClientOptions> clientOptions;
|
||||||
private final Optional<String> clientName;
|
private final Optional<String> clientName;
|
||||||
private final Optional<ReadFrom> readFrom;
|
private final Optional<ReadFrom> readFrom;
|
||||||
|
private final Optional<RedisCredentialsProviderFactory> redisCredentialsProviderFactory;
|
||||||
private final Duration timeout;
|
private final Duration timeout;
|
||||||
private final Duration shutdownTimeout;
|
private final Duration shutdownTimeout;
|
||||||
private final Duration shutdownQuietPeriod;
|
private final Duration shutdownQuietPeriod;
|
||||||
|
|
||||||
DefaultLettuceClientConfiguration(boolean useSsl, boolean verifyPeer, boolean startTls,
|
DefaultLettuceClientConfiguration(boolean useSsl, boolean verifyPeer, boolean startTls,
|
||||||
@Nullable ClientResources clientResources, @Nullable ClientOptions clientOptions, @Nullable String clientName,
|
@Nullable ClientResources clientResources, @Nullable ClientOptions clientOptions, @Nullable String clientName,
|
||||||
@Nullable ReadFrom readFrom, Duration timeout, Duration shutdownTimeout, @Nullable Duration shutdownQuietPeriod) {
|
@Nullable ReadFrom readFrom, @Nullable RedisCredentialsProviderFactory redisCredentialsProviderFactory,
|
||||||
|
Duration timeout, Duration shutdownTimeout, @Nullable Duration shutdownQuietPeriod) {
|
||||||
|
|
||||||
this.useSsl = useSsl;
|
this.useSsl = useSsl;
|
||||||
this.verifyPeer = verifyPeer;
|
this.verifyPeer = verifyPeer;
|
||||||
@@ -56,6 +58,7 @@ class DefaultLettuceClientConfiguration implements LettuceClientConfiguration {
|
|||||||
this.clientOptions = Optional.ofNullable(clientOptions);
|
this.clientOptions = Optional.ofNullable(clientOptions);
|
||||||
this.clientName = Optional.ofNullable(clientName);
|
this.clientName = Optional.ofNullable(clientName);
|
||||||
this.readFrom = Optional.ofNullable(readFrom);
|
this.readFrom = Optional.ofNullable(readFrom);
|
||||||
|
this.redisCredentialsProviderFactory = Optional.ofNullable(redisCredentialsProviderFactory);
|
||||||
this.timeout = timeout;
|
this.timeout = timeout;
|
||||||
this.shutdownTimeout = shutdownTimeout;
|
this.shutdownTimeout = shutdownTimeout;
|
||||||
this.shutdownQuietPeriod = shutdownQuietPeriod != null ? shutdownQuietPeriod : shutdownTimeout;
|
this.shutdownQuietPeriod = shutdownQuietPeriod != null ? shutdownQuietPeriod : shutdownTimeout;
|
||||||
@@ -96,6 +99,11 @@ class DefaultLettuceClientConfiguration implements LettuceClientConfiguration {
|
|||||||
return readFrom;
|
return readFrom;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public Optional<RedisCredentialsProviderFactory> getRedisCredentialsProviderFactory() {
|
||||||
|
return redisCredentialsProviderFactory;
|
||||||
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public Duration getCommandTimeout() {
|
public Duration getCommandTimeout() {
|
||||||
return timeout;
|
return timeout;
|
||||||
|
|||||||
@@ -79,6 +79,11 @@ class DefaultLettucePoolingClientConfiguration implements LettucePoolingClientCo
|
|||||||
return clientConfiguration.getReadFrom();
|
return clientConfiguration.getReadFrom();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public Optional<RedisCredentialsProviderFactory> getRedisCredentialsProviderFactory() {
|
||||||
|
return clientConfiguration.getRedisCredentialsProviderFactory();
|
||||||
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public Duration getCommandTimeout() {
|
public Duration getCommandTimeout() {
|
||||||
return clientConfiguration.getCommandTimeout();
|
return clientConfiguration.getCommandTimeout();
|
||||||
|
|||||||
@@ -94,6 +94,12 @@ public interface LettuceClientConfiguration {
|
|||||||
*/
|
*/
|
||||||
Optional<ReadFrom> getReadFrom();
|
Optional<ReadFrom> getReadFrom();
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @return the optional {@link RedisCredentialsProviderFactory}.
|
||||||
|
* @since 3.0
|
||||||
|
*/
|
||||||
|
Optional<RedisCredentialsProviderFactory> getRedisCredentialsProviderFactory();
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @return the timeout.
|
* @return the timeout.
|
||||||
*/
|
*/
|
||||||
@@ -166,6 +172,7 @@ public interface LettuceClientConfiguration {
|
|||||||
ClientOptions clientOptions = ClientOptions.builder().timeoutOptions(TimeoutOptions.enabled()).build();
|
ClientOptions clientOptions = ClientOptions.builder().timeoutOptions(TimeoutOptions.enabled()).build();
|
||||||
@Nullable String clientName;
|
@Nullable String clientName;
|
||||||
@Nullable ReadFrom readFrom;
|
@Nullable ReadFrom readFrom;
|
||||||
|
@Nullable RedisCredentialsProviderFactory redisCredentialsProviderFactory;
|
||||||
Duration timeout = Duration.ofSeconds(RedisURI.DEFAULT_TIMEOUT);
|
Duration timeout = Duration.ofSeconds(RedisURI.DEFAULT_TIMEOUT);
|
||||||
Duration shutdownTimeout = Duration.ofMillis(100);
|
Duration shutdownTimeout = Duration.ofMillis(100);
|
||||||
@Nullable Duration shutdownQuietPeriod;
|
@Nullable Duration shutdownQuietPeriod;
|
||||||
@@ -242,7 +249,7 @@ public interface LettuceClientConfiguration {
|
|||||||
*
|
*
|
||||||
* @param readFrom must not be {@literal null}.
|
* @param readFrom must not be {@literal null}.
|
||||||
* @return {@literal this} builder.
|
* @return {@literal this} builder.
|
||||||
* @throws IllegalArgumentException if clientOptions is {@literal null}.
|
* @throws IllegalArgumentException if readFrom is {@literal null}.
|
||||||
* @since 2.1
|
* @since 2.1
|
||||||
*/
|
*/
|
||||||
public LettuceClientConfigurationBuilder readFrom(ReadFrom readFrom) {
|
public LettuceClientConfigurationBuilder readFrom(ReadFrom readFrom) {
|
||||||
@@ -253,6 +260,24 @@ public interface LettuceClientConfiguration {
|
|||||||
return this;
|
return this;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Configure a {@link RedisCredentialsProviderFactory} to obtain {@link io.lettuce.core.RedisCredentialsProvider}
|
||||||
|
* instances to support credential rotation.
|
||||||
|
*
|
||||||
|
* @param redisCredentialsProviderFactory must not be {@literal null}.
|
||||||
|
* @return {@literal this} builder.
|
||||||
|
* @throws IllegalArgumentException if redisCredentialsProviderFactory is {@literal null}.
|
||||||
|
* @since 3.0
|
||||||
|
*/
|
||||||
|
public LettuceClientConfigurationBuilder redisCredentialsProviderFactory(
|
||||||
|
RedisCredentialsProviderFactory redisCredentialsProviderFactory) {
|
||||||
|
|
||||||
|
Assert.notNull(redisCredentialsProviderFactory, "RedisCredentialsProviderFactory must not be null");
|
||||||
|
|
||||||
|
this.redisCredentialsProviderFactory = redisCredentialsProviderFactory;
|
||||||
|
return this;
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Configure a {@code clientName} to be set with {@code CLIENT SETNAME}.
|
* Configure a {@code clientName} to be set with {@code CLIENT SETNAME}.
|
||||||
*
|
*
|
||||||
@@ -323,7 +348,7 @@ public interface LettuceClientConfiguration {
|
|||||||
public LettuceClientConfiguration build() {
|
public LettuceClientConfiguration build() {
|
||||||
|
|
||||||
return new DefaultLettuceClientConfiguration(useSsl, verifyPeer, startTls, clientResources, clientOptions,
|
return new DefaultLettuceClientConfiguration(useSsl, verifyPeer, startTls, clientResources, clientOptions,
|
||||||
clientName, readFrom, timeout, shutdownTimeout, shutdownQuietPeriod);
|
clientName, readFrom, redisCredentialsProviderFactory, timeout, shutdownTimeout, shutdownQuietPeriod);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -22,6 +22,7 @@ import io.lettuce.core.ClientOptions;
|
|||||||
import io.lettuce.core.ReadFrom;
|
import io.lettuce.core.ReadFrom;
|
||||||
import io.lettuce.core.RedisClient;
|
import io.lettuce.core.RedisClient;
|
||||||
import io.lettuce.core.RedisConnectionException;
|
import io.lettuce.core.RedisConnectionException;
|
||||||
|
import io.lettuce.core.RedisCredentialsProvider;
|
||||||
import io.lettuce.core.RedisURI;
|
import io.lettuce.core.RedisURI;
|
||||||
import io.lettuce.core.api.StatefulConnection;
|
import io.lettuce.core.api.StatefulConnection;
|
||||||
import io.lettuce.core.api.StatefulRedisConnection;
|
import io.lettuce.core.api.StatefulRedisConnection;
|
||||||
@@ -1216,6 +1217,15 @@ public class LettuceConnectionFactory
|
|||||||
|
|
||||||
redisUri.setDatabase(getDatabase());
|
redisUri.setDatabase(getDatabase());
|
||||||
|
|
||||||
|
clientConfiguration.getRedisCredentialsProviderFactory().ifPresent(factory -> {
|
||||||
|
|
||||||
|
redisUri.setCredentialsProvider(factory.createCredentialsProvider(configuration));
|
||||||
|
|
||||||
|
RedisCredentialsProvider sentinelCredentials = factory
|
||||||
|
.createSentinelCredentialsProvider((RedisSentinelConfiguration) configuration);
|
||||||
|
redisUri.getSentinels().forEach(it -> it.setCredentialsProvider(sentinelCredentials));
|
||||||
|
});
|
||||||
|
|
||||||
return redisUri;
|
return redisUri;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -1267,6 +1277,10 @@ public class LettuceConnectionFactory
|
|||||||
} else {
|
} else {
|
||||||
getRedisPassword().toOptional().ifPresent(builder::withPassword);
|
getRedisPassword().toOptional().ifPresent(builder::withPassword);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
clientConfiguration.getRedisCredentialsProviderFactory().ifPresent(factory -> {
|
||||||
|
builder.withAuthentication(factory.createCredentialsProvider(configuration));
|
||||||
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
@@ -1456,6 +1470,11 @@ public class LettuceConnectionFactory
|
|||||||
return Optional.empty();
|
return Optional.empty();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public Optional<RedisCredentialsProviderFactory> getRedisCredentialsProviderFactory() {
|
||||||
|
return Optional.empty();
|
||||||
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public Optional<String> getClientName() {
|
public Optional<String> getClientName() {
|
||||||
return Optional.ofNullable(clientName);
|
return Optional.ofNullable(clientName);
|
||||||
|
|||||||
@@ -145,6 +145,13 @@ public interface LettucePoolingClientConfiguration extends LettuceClientConfigur
|
|||||||
return this;
|
return this;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public LettucePoolingClientConfigurationBuilder redisCredentialsProviderFactory(
|
||||||
|
RedisCredentialsProviderFactory redisCredentialsProviderFactory) {
|
||||||
|
super.redisCredentialsProviderFactory(redisCredentialsProviderFactory);
|
||||||
|
return this;
|
||||||
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public LettucePoolingClientConfigurationBuilder clientName(String clientName) {
|
public LettucePoolingClientConfigurationBuilder clientName(String clientName) {
|
||||||
super.clientName(clientName);
|
super.clientName(clientName);
|
||||||
|
|||||||
@@ -0,0 +1,111 @@
|
|||||||
|
/*
|
||||||
|
* Copyright 2022 the original author or authors.
|
||||||
|
*
|
||||||
|
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
|
* you may not use this file except in compliance with the License.
|
||||||
|
* You may obtain a copy of the License at
|
||||||
|
*
|
||||||
|
* https://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
*
|
||||||
|
* Unless required by applicable law or agreed to in writing, software
|
||||||
|
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
|
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
|
* See the License for the specific language governing permissions and
|
||||||
|
* limitations under the License.
|
||||||
|
*/
|
||||||
|
package org.springframework.data.redis.connection.lettuce;
|
||||||
|
|
||||||
|
import io.lettuce.core.RedisCredentials;
|
||||||
|
import io.lettuce.core.RedisCredentialsProvider;
|
||||||
|
import reactor.core.publisher.Mono;
|
||||||
|
|
||||||
|
import org.springframework.data.redis.connection.RedisConfiguration;
|
||||||
|
import org.springframework.data.redis.connection.RedisSentinelConfiguration;
|
||||||
|
import org.springframework.lang.Nullable;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Factory interface to create {@link RedisCredentialsProvider} from a {@link RedisConfiguration}. Credentials can be
|
||||||
|
* associated with {@link RedisCredentials#hasUsername() username} and/or {@link RedisCredentials#hasPassword()
|
||||||
|
* password}.
|
||||||
|
* <p>
|
||||||
|
* Credentials are based off the given {@link RedisConfiguration} objects. Changing the credentials in the actual object
|
||||||
|
* affects the constructed {@link RedisCredentials} object. Credentials are requested by the Lettuce client after
|
||||||
|
* connecting to the host. Therefore, credential retrieval is subject to complete within the configured connection
|
||||||
|
* creation timeout to avoid connection failures.
|
||||||
|
*
|
||||||
|
* @author Mark Paluch
|
||||||
|
* @since 3.0
|
||||||
|
*/
|
||||||
|
public interface RedisCredentialsProviderFactory {
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Create a {@link RedisCredentialsProvider} for data node authentication given {@link RedisConfiguration}.
|
||||||
|
*
|
||||||
|
* @param redisConfiguration the {@link RedisConfiguration} object.
|
||||||
|
* @return a {@link RedisCredentialsProvider} that emits {@link RedisCredentials} for data node authentication.
|
||||||
|
*/
|
||||||
|
@Nullable
|
||||||
|
default RedisCredentialsProvider createCredentialsProvider(RedisConfiguration redisConfiguration) {
|
||||||
|
|
||||||
|
if (redisConfiguration instanceof RedisConfiguration.WithAuthentication
|
||||||
|
&& ((RedisConfiguration.WithAuthentication) redisConfiguration).getPassword().isPresent()) {
|
||||||
|
|
||||||
|
return RedisCredentialsProvider.from(() -> {
|
||||||
|
|
||||||
|
RedisConfiguration.WithAuthentication withAuthentication = (RedisConfiguration.WithAuthentication) redisConfiguration;
|
||||||
|
|
||||||
|
return RedisCredentials.just(withAuthentication.getUsername(), withAuthentication.getPassword().get());
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
return () -> Mono.just(AbsentRedisCredentials.ANONYMOUS);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Create a {@link RedisCredentialsProvider} for Sentinel node authentication given
|
||||||
|
* {@link RedisSentinelConfiguration}.
|
||||||
|
*
|
||||||
|
* @param redisConfiguration the {@link RedisSentinelConfiguration} object.
|
||||||
|
* @return a {@link RedisCredentialsProvider} that emits {@link RedisCredentials} for sentinel authentication.
|
||||||
|
*/
|
||||||
|
default RedisCredentialsProvider createSentinelCredentialsProvider(RedisSentinelConfiguration redisConfiguration) {
|
||||||
|
|
||||||
|
if (redisConfiguration.getSentinelPassword().isPresent()) {
|
||||||
|
|
||||||
|
return RedisCredentialsProvider.from(() -> RedisCredentials.just(redisConfiguration.getSentinelUsername(),
|
||||||
|
redisConfiguration.getSentinelPassword().get()));
|
||||||
|
}
|
||||||
|
|
||||||
|
return () -> Mono.just(AbsentRedisCredentials.ANONYMOUS);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Default anonymous {@link RedisCredentials} without username/password.
|
||||||
|
*/
|
||||||
|
enum AbsentRedisCredentials implements RedisCredentials {
|
||||||
|
|
||||||
|
ANONYMOUS;
|
||||||
|
|
||||||
|
@Override
|
||||||
|
@Nullable
|
||||||
|
public String getUsername() {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public boolean hasUsername() {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
@Nullable
|
||||||
|
public char[] getPassword() {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public boolean hasPassword() {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -37,6 +37,7 @@ import io.lettuce.core.codec.RedisCodec;
|
|||||||
import io.lettuce.core.resource.ClientResources;
|
import io.lettuce.core.resource.ClientResources;
|
||||||
import lombok.AllArgsConstructor;
|
import lombok.AllArgsConstructor;
|
||||||
import lombok.Data;
|
import lombok.Data;
|
||||||
|
import reactor.test.StepVerifier;
|
||||||
|
|
||||||
import java.time.Duration;
|
import java.time.Duration;
|
||||||
import java.util.Collections;
|
import java.util.Collections;
|
||||||
@@ -187,6 +188,59 @@ class LettuceConnectionFactoryUnitTests {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Test // GH-2376
|
||||||
|
@SuppressWarnings("unchecked")
|
||||||
|
void credentialsProviderShouldBeSetCorrectlyOnClusterClient() {
|
||||||
|
|
||||||
|
clusterConfig.setUsername("foo");
|
||||||
|
clusterConfig.setPassword("bar");
|
||||||
|
|
||||||
|
LettuceClientConfiguration clientConfiguration = LettuceClientConfiguration.builder()
|
||||||
|
.clientResources(getSharedClientResources())
|
||||||
|
.redisCredentialsProviderFactory(new RedisCredentialsProviderFactory() {}).build();
|
||||||
|
LettuceConnectionFactory connectionFactory = new LettuceConnectionFactory(clusterConfig, clientConfiguration);
|
||||||
|
connectionFactory.afterPropertiesSet();
|
||||||
|
ConnectionFactoryTracker.add(connectionFactory);
|
||||||
|
|
||||||
|
AbstractRedisClient client = (AbstractRedisClient) getField(connectionFactory, "client");
|
||||||
|
assertThat(client).isInstanceOf(RedisClusterClient.class);
|
||||||
|
|
||||||
|
Iterable<RedisURI> initialUris = (Iterable<RedisURI>) getField(client, "initialUris");
|
||||||
|
|
||||||
|
for (RedisURI uri : initialUris) {
|
||||||
|
|
||||||
|
uri.getCredentialsProvider().resolveCredentials().as(StepVerifier::create).consumeNextWith(actual -> {
|
||||||
|
assertThat(actual.getUsername()).isEqualTo("foo");
|
||||||
|
assertThat(new String(actual.getPassword())).isEqualTo("bar");
|
||||||
|
}).verifyComplete();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test // GH-2376
|
||||||
|
void credentialsProviderShouldBeSetCorrectlyOnStandaloneClient() {
|
||||||
|
|
||||||
|
RedisStandaloneConfiguration config = new RedisStandaloneConfiguration("localhost");
|
||||||
|
config.setUsername("foo");
|
||||||
|
config.setPassword("bar");
|
||||||
|
|
||||||
|
LettuceClientConfiguration clientConfiguration = LettuceClientConfiguration.builder()
|
||||||
|
.clientResources(getSharedClientResources())
|
||||||
|
.redisCredentialsProviderFactory(new RedisCredentialsProviderFactory() {}).build();
|
||||||
|
LettuceConnectionFactory connectionFactory = new LettuceConnectionFactory(config, clientConfiguration);
|
||||||
|
connectionFactory.afterPropertiesSet();
|
||||||
|
ConnectionFactoryTracker.add(connectionFactory);
|
||||||
|
|
||||||
|
AbstractRedisClient client = (AbstractRedisClient) getField(connectionFactory, "client");
|
||||||
|
assertThat(client).isInstanceOf(RedisClient.class);
|
||||||
|
|
||||||
|
RedisURI uri = (RedisURI) getField(client, "redisURI");
|
||||||
|
|
||||||
|
uri.getCredentialsProvider().resolveCredentials().as(StepVerifier::create).consumeNextWith(actual -> {
|
||||||
|
assertThat(actual.getUsername()).isEqualTo("foo");
|
||||||
|
assertThat(new String(actual.getPassword())).isEqualTo("bar");
|
||||||
|
}).verifyComplete();
|
||||||
|
}
|
||||||
|
|
||||||
@Test // DATAREDIS-524, DATAREDIS-1045, DATAREDIS-1060
|
@Test // DATAREDIS-524, DATAREDIS-1045, DATAREDIS-1060
|
||||||
void passwordShouldNotBeSetOnSentinelClient() {
|
void passwordShouldNotBeSetOnSentinelClient() {
|
||||||
|
|
||||||
@@ -233,6 +287,41 @@ class LettuceConnectionFactoryUnitTests {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Test // GH-2376
|
||||||
|
void sentinelCredentialsProviderShouldBeSetOnSentinelClient() {
|
||||||
|
|
||||||
|
RedisSentinelConfiguration config = new RedisSentinelConfiguration("mymaster", Collections.singleton("host:1234"));
|
||||||
|
config.setUsername("data-user");
|
||||||
|
config.setPassword("data-pwd");
|
||||||
|
config.setSentinelPassword("sentinel-pwd");
|
||||||
|
|
||||||
|
LettuceClientConfiguration clientConfiguration = LettuceClientConfiguration.builder()
|
||||||
|
.clientResources(getSharedClientResources())
|
||||||
|
.redisCredentialsProviderFactory(new RedisCredentialsProviderFactory() {}).build();
|
||||||
|
|
||||||
|
LettuceConnectionFactory connectionFactory = new LettuceConnectionFactory(config, clientConfiguration);
|
||||||
|
connectionFactory.afterPropertiesSet();
|
||||||
|
ConnectionFactoryTracker.add(connectionFactory);
|
||||||
|
|
||||||
|
AbstractRedisClient client = (AbstractRedisClient) getField(connectionFactory, "client");
|
||||||
|
assertThat(client).isInstanceOf(RedisClient.class);
|
||||||
|
|
||||||
|
RedisURI redisUri = (RedisURI) getField(client, "redisURI");
|
||||||
|
|
||||||
|
redisUri.getCredentialsProvider().resolveCredentials().as(StepVerifier::create).consumeNextWith(actual -> {
|
||||||
|
assertThat(actual.getUsername()).isEqualTo("data-user");
|
||||||
|
assertThat(new String(actual.getPassword())).isEqualTo("data-pwd");
|
||||||
|
}).verifyComplete();
|
||||||
|
|
||||||
|
for (RedisURI sentinelUri : redisUri.getSentinels()) {
|
||||||
|
|
||||||
|
sentinelUri.getCredentialsProvider().resolveCredentials().as(StepVerifier::create).consumeNextWith(actual -> {
|
||||||
|
assertThat(actual.getUsername()).isNull();
|
||||||
|
assertThat(new String(actual.getPassword())).isEqualTo("sentinel-pwd");
|
||||||
|
}).verifyComplete();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
@Test // DATAREDIS-1060
|
@Test // DATAREDIS-1060
|
||||||
void sentinelPasswordShouldNotLeakIntoDataNodeClient() {
|
void sentinelPasswordShouldNotLeakIntoDataNodeClient() {
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user