DATAREDIS-1060 - Redis password should not automatically be applied to Sentinel.

We now expose two separate properties in RedisSentinelConfiguration to configure the data password individually from the sentinel password.

Original pull request: #495.
This commit is contained in:
Christoph Strobl
2019-11-11 15:40:29 +01:00
committed by Mark Paluch
parent df9c57ad98
commit 1955074eb7
7 changed files with 292 additions and 31 deletions

View File

@@ -22,7 +22,6 @@ import java.util.Collections;
import java.util.HashSet;
import org.junit.Test;
import org.springframework.core.env.PropertySource;
import org.springframework.mock.env.MockPropertySource;
import org.springframework.util.StringUtils;
@@ -51,8 +50,7 @@ public class RedisSentinelConfigurationUnitTests {
public void shouldCreateRedisSentinelConfigurationCorrectlyGivenMasterAndMultipleHostAndPortStrings() {
RedisSentinelConfiguration config = new RedisSentinelConfiguration("mymaster",
new HashSet<>(Arrays.asList(
HOST_AND_PORT_1, HOST_AND_PORT_2, HOST_AND_PORT_3)));
new HashSet<>(Arrays.asList(HOST_AND_PORT_1, HOST_AND_PORT_2, HOST_AND_PORT_3)));
assertThat(config.getSentinels().size()).isEqualTo(3);
assertThat(config.getSentinels()).contains(new RedisNode("127.0.0.1", 123), new RedisNode("localhost", 456),
@@ -121,4 +119,65 @@ public class RedisSentinelConfigurationUnitTests {
assertThat(config.getSentinels()).contains(new RedisNode("127.0.0.1", 123), new RedisNode("localhost", 456),
new RedisNode("localhost", 789));
}
@Test // DATAREDIS-1060
public void throwsExceptionOnSentinelPasswordAlreadySetWhenTryingToReuseDataNodePassword() {
RedisSentinelConfiguration configuration = new RedisSentinelConfiguration("myMaster",
Collections.singleton(HOST_AND_PORT_1));
configuration.setSentinelPassword(RedisPassword.of("so-secret-you'll-never-guess-123"));
assertThatExceptionOfType(IllegalStateException.class)
.isThrownBy(() -> configuration.useDataNodeAuthenticationForSentinel(true));
}
@Test // DATAREDIS-1060
public void throwsExceptionOnSettingSentinelPasswordWhenAlreadyReusingDataNodePassword() {
RedisSentinelConfiguration configuration = new RedisSentinelConfiguration("myMaster",
Collections.singleton(HOST_AND_PORT_1));
configuration.setPassword(RedisPassword.of("qwerty"));
configuration.useDataNodeAuthenticationForSentinel(true);
assertThatExceptionOfType(IllegalStateException.class)
.isThrownBy(() -> configuration.setSentinelPassword(RedisPassword.of("who-needs-security-anyway")));
}
@Test // DATAREDIS-1060
public void settingSentinelPasswordReturnsDataNodePasswordIfUseDataNodeAuthIsTrue() {
RedisPassword password = RedisPassword.of("monkey-dragon->yeah-getting-better-combining-trivial-ones");
RedisSentinelConfiguration configuration = new RedisSentinelConfiguration("myMaster",
Collections.singleton(HOST_AND_PORT_1));
configuration.setPassword(password);
configuration.useDataNodeAuthenticationForSentinel(true);
assertThat(configuration.getSentinelPassword()).isEqualTo(password);
}
@Test // DATAREDIS-1060
public void dataNodePasswordDoesNotAffectSentinelPassword() {
RedisPassword password = RedisPassword.of("88888888-8x8-getting-creative-now");
RedisSentinelConfiguration configuration = new RedisSentinelConfiguration("myMaster",
Collections.singleton(HOST_AND_PORT_1));
configuration.setPassword(password);
assertThat(configuration.getSentinelPassword()).isEqualTo(RedisPassword.none());
}
@Test // DATAREDIS-1060
public void readSentinelPasswordFromConfigProperty() {
MockPropertySource propertySource = new MockPropertySource();
propertySource.setProperty("spring.redis.sentinel.master", "myMaster");
propertySource.setProperty("spring.redis.sentinel.nodes", HOST_AND_PORT_1);
propertySource.setProperty("spring.redis.sentinel.password", "computer-says-no");
RedisSentinelConfiguration config = new RedisSentinelConfiguration(propertySource);
assertThat(config.getSentinelPassword()).isEqualTo(RedisPassword.of("computer-says-no"));
assertThat(config.getSentinels().size()).isEqualTo(1);
assertThat(config.getSentinels()).contains(new RedisNode("127.0.0.1", 123));
}
}

View File

@@ -46,7 +46,6 @@ import org.junit.After;
import org.junit.Before;
import org.junit.Test;
import org.mockito.ArgumentMatchers;
import org.springframework.beans.DirectFieldAccessor;
import org.springframework.beans.factory.DisposableBean;
import org.springframework.data.redis.ConnectionFactoryTracker;
@@ -179,8 +178,8 @@ public class LettuceConnectionFactoryUnitTests {
}
}
@Test // DATAREDIS-524, DATAREDIS-1045
public void passwordShouldBeSetCorrectlyOnSentinelClient() {
@Test // DATAREDIS-524, DATAREDIS-1045, DATAREDIS-1060
public void passwordShouldNotBeSetOnSentinelClient() {
LettuceConnectionFactory connectionFactory = new LettuceConnectionFactory(
new RedisSentinelConfiguration("mymaster", Collections.singleton("host:1234")));
@@ -197,8 +196,78 @@ public class LettuceConnectionFactoryUnitTests {
assertThat(redisUri.getPassword()).isEqualTo(connectionFactory.getPassword().toCharArray());
for (RedisURI sentinel : redisUri.getSentinels()) {
assertThat(sentinel.getPassword())
.isEqualTo(connectionFactory.getPassword().toCharArray());
assertThat(sentinel.getPassword()).isNull();
}
}
@Test // DATAREDIS-1060
public void sentinelPasswordShouldBeSetOnSentinelClient() {
RedisSentinelConfiguration config = new RedisSentinelConfiguration("mymaster", Collections.singleton("host:1234"));
config.setSentinelPassword("sentinel-pwd");
LettuceConnectionFactory connectionFactory = new LettuceConnectionFactory(config);
connectionFactory.setClientResources(getSharedClientResources());
connectionFactory.setPassword("o_O");
connectionFactory.afterPropertiesSet();
ConnectionFactoryTracker.add(connectionFactory);
AbstractRedisClient client = (AbstractRedisClient) getField(connectionFactory, "client");
assertThat(client).isInstanceOf(RedisClient.class);
RedisURI redisUri = (RedisURI) getField(client, "redisURI");
assertThat(redisUri.getPassword()).isEqualTo(connectionFactory.getPassword().toCharArray());
for (RedisURI sentinel : redisUri.getSentinels()) {
assertThat(sentinel.getPassword()).isEqualTo("sentinel-pwd".toCharArray());
}
}
@Test // DATAREDIS-1060
public void redisPasswordShouldBeSetOnSentinelClientIfItShouldBeReused() {
RedisSentinelConfiguration config = new RedisSentinelConfiguration("mymaster", Collections.singleton("host:1234"));
config.useDataNodeAuthenticationForSentinel(true);
LettuceConnectionFactory connectionFactory = new LettuceConnectionFactory(config);
connectionFactory.setClientResources(getSharedClientResources());
connectionFactory.setPassword("o_O");
connectionFactory.afterPropertiesSet();
ConnectionFactoryTracker.add(connectionFactory);
AbstractRedisClient client = (AbstractRedisClient) getField(connectionFactory, "client");
assertThat(client).isInstanceOf(RedisClient.class);
RedisURI redisUri = (RedisURI) getField(client, "redisURI");
assertThat(redisUri.getPassword()).isEqualTo(connectionFactory.getPassword().toCharArray());
for (RedisURI sentinel : redisUri.getSentinels()) {
assertThat(sentinel.getPassword()).isEqualTo("o_O".toCharArray());
}
}
@Test // DATAREDIS-1060
public void sentinelPasswordShouldNotLeakIntoDataNodeClient() {
RedisSentinelConfiguration config = new RedisSentinelConfiguration("mymaster", Collections.singleton("host:1234"));
config.setSentinelPassword("sentinel-pwd");
LettuceConnectionFactory connectionFactory = new LettuceConnectionFactory(config);
connectionFactory.setClientResources(getSharedClientResources());
connectionFactory.afterPropertiesSet();
ConnectionFactoryTracker.add(connectionFactory);
AbstractRedisClient client = (AbstractRedisClient) getField(connectionFactory, "client");
assertThat(client).isInstanceOf(RedisClient.class);
RedisURI redisUri = (RedisURI) getField(client, "redisURI");
assertThat(redisUri.getPassword()).isNull();
for (RedisURI sentinel : redisUri.getSentinels()) {
assertThat(sentinel.getPassword()).isEqualTo("sentinel-pwd".toCharArray());
}
}