Add SSL service connection support for Redis
See gh-41137
This commit is contained in:
parent
b773dcd356
commit
7cf9cc74a2
@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright 2012-2023 the original author or authors.
|
||||
* Copyright 2012-2025 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.
|
||||
@ -92,21 +92,17 @@ class JedisConnectionConfiguration extends RedisConnectionConfiguration {
|
||||
private JedisConnectionFactory createJedisConnectionFactory(
|
||||
ObjectProvider<JedisClientConfigurationBuilderCustomizer> builderCustomizers) {
|
||||
JedisClientConfiguration clientConfiguration = getJedisClientConfiguration(builderCustomizers);
|
||||
if (getSentinelConfig() != null) {
|
||||
return new JedisConnectionFactory(getSentinelConfig(), clientConfiguration);
|
||||
}
|
||||
if (getClusterConfiguration() != null) {
|
||||
return new JedisConnectionFactory(getClusterConfiguration(), clientConfiguration);
|
||||
}
|
||||
return new JedisConnectionFactory(getStandaloneConfig(), clientConfiguration);
|
||||
return switch (this.mode) {
|
||||
case STANDALONE -> new JedisConnectionFactory(getStandaloneConfig(), clientConfiguration);
|
||||
case CLUSTER -> new JedisConnectionFactory(getClusterConfiguration(), clientConfiguration);
|
||||
case SENTINEL -> new JedisConnectionFactory(getSentinelConfig(), clientConfiguration);
|
||||
};
|
||||
}
|
||||
|
||||
private JedisClientConfiguration getJedisClientConfiguration(
|
||||
ObjectProvider<JedisClientConfigurationBuilderCustomizer> builderCustomizers) {
|
||||
JedisClientConfigurationBuilder builder = applyProperties(JedisClientConfiguration.builder());
|
||||
if (isSslEnabled()) {
|
||||
applySsl(builder);
|
||||
}
|
||||
applySslIfNeeded(builder);
|
||||
RedisProperties.Pool pool = getProperties().getJedis().getPool();
|
||||
if (isPoolEnabled(pool)) {
|
||||
applyPooling(pool, builder);
|
||||
@ -126,18 +122,19 @@ class JedisConnectionConfiguration extends RedisConnectionConfiguration {
|
||||
return builder;
|
||||
}
|
||||
|
||||
private void applySsl(JedisClientConfigurationBuilder builder) {
|
||||
JedisSslClientConfigurationBuilder sslBuilder = builder.useSsl();
|
||||
if (getProperties().getSsl().getBundle() != null) {
|
||||
SslBundle sslBundle = getSslBundles().getBundle(getProperties().getSsl().getBundle());
|
||||
sslBuilder.sslSocketFactory(sslBundle.createSslContext().getSocketFactory());
|
||||
SslOptions sslOptions = sslBundle.getOptions();
|
||||
SSLParameters sslParameters = new SSLParameters();
|
||||
PropertyMapper map = PropertyMapper.get().alwaysApplyingWhenNonNull();
|
||||
map.from(sslOptions.getCiphers()).to(sslParameters::setCipherSuites);
|
||||
map.from(sslOptions.getEnabledProtocols()).to(sslParameters::setProtocols);
|
||||
sslBuilder.sslParameters(sslParameters);
|
||||
private void applySslIfNeeded(JedisClientConfigurationBuilder builder) {
|
||||
SslBundle sslBundle = getSslBundle();
|
||||
if (sslBundle == null) {
|
||||
return;
|
||||
}
|
||||
JedisSslClientConfigurationBuilder sslBuilder = builder.useSsl();
|
||||
sslBuilder.sslSocketFactory(sslBundle.createSslContext().getSocketFactory());
|
||||
SslOptions sslOptions = sslBundle.getOptions();
|
||||
SSLParameters sslParameters = new SSLParameters();
|
||||
PropertyMapper map = PropertyMapper.get().alwaysApplyingWhenNonNull();
|
||||
map.from(sslOptions.getCiphers()).to(sslParameters::setCipherSuites);
|
||||
map.from(sslOptions.getEnabledProtocols()).to(sslParameters::setProtocols);
|
||||
sslBuilder.sslParameters(sslParameters);
|
||||
}
|
||||
|
||||
private void applyPooling(RedisProperties.Pool pool,
|
||||
|
@ -116,19 +116,14 @@ class LettuceConnectionConfiguration extends RedisConnectionConfiguration {
|
||||
ObjectProvider<LettuceClientConfigurationBuilderCustomizer> clientConfigurationBuilderCustomizers,
|
||||
ObjectProvider<LettuceClientOptionsBuilderCustomizer> clientOptionsBuilderCustomizers,
|
||||
ClientResources clientResources) {
|
||||
LettuceClientConfiguration clientConfig = getLettuceClientConfiguration(clientConfigurationBuilderCustomizers,
|
||||
clientOptionsBuilderCustomizers, clientResources, getProperties().getLettuce().getPool());
|
||||
return createLettuceConnectionFactory(clientConfig);
|
||||
}
|
||||
|
||||
private LettuceConnectionFactory createLettuceConnectionFactory(LettuceClientConfiguration clientConfiguration) {
|
||||
if (getSentinelConfig() != null) {
|
||||
return new LettuceConnectionFactory(getSentinelConfig(), clientConfiguration);
|
||||
}
|
||||
if (getClusterConfiguration() != null) {
|
||||
return new LettuceConnectionFactory(getClusterConfiguration(), clientConfiguration);
|
||||
}
|
||||
return new LettuceConnectionFactory(getStandaloneConfig(), clientConfiguration);
|
||||
LettuceClientConfiguration clientConfiguration = getLettuceClientConfiguration(
|
||||
clientConfigurationBuilderCustomizers, clientOptionsBuilderCustomizers, clientResources,
|
||||
getProperties().getLettuce().getPool());
|
||||
return switch (this.mode) {
|
||||
case STANDALONE -> new LettuceConnectionFactory(getStandaloneConfig(), clientConfiguration);
|
||||
case CLUSTER -> new LettuceConnectionFactory(getClusterConfiguration(), clientConfiguration);
|
||||
case SENTINEL -> new LettuceConnectionFactory(getSentinelConfig(), clientConfiguration);
|
||||
};
|
||||
}
|
||||
|
||||
private LettuceClientConfiguration getLettuceClientConfiguration(
|
||||
@ -136,11 +131,12 @@ class LettuceConnectionConfiguration extends RedisConnectionConfiguration {
|
||||
ObjectProvider<LettuceClientOptionsBuilderCustomizer> clientOptionsBuilderCustomizers,
|
||||
ClientResources clientResources, Pool pool) {
|
||||
LettuceClientConfigurationBuilder builder = createBuilder(pool);
|
||||
applyProperties(builder);
|
||||
SslBundle sslBundle = getSslBundle();
|
||||
applyProperties(builder, sslBundle);
|
||||
if (StringUtils.hasText(getProperties().getUrl())) {
|
||||
customizeConfigurationFromUrl(builder);
|
||||
}
|
||||
builder.clientOptions(createClientOptions(clientOptionsBuilderCustomizers));
|
||||
builder.clientOptions(createClientOptions(clientOptionsBuilderCustomizers, sslBundle));
|
||||
builder.clientResources(clientResources);
|
||||
clientConfigurationBuilderCustomizers.orderedStream().forEach((customizer) -> customizer.customize(builder));
|
||||
return builder.build();
|
||||
@ -153,8 +149,8 @@ class LettuceConnectionConfiguration extends RedisConnectionConfiguration {
|
||||
return LettuceClientConfiguration.builder();
|
||||
}
|
||||
|
||||
private void applyProperties(LettuceClientConfiguration.LettuceClientConfigurationBuilder builder) {
|
||||
if (isSslEnabled()) {
|
||||
private void applyProperties(LettuceClientConfigurationBuilder builder, SslBundle sslBundle) {
|
||||
if (sslBundle != null) {
|
||||
builder.useSsl();
|
||||
}
|
||||
if (getProperties().getTimeout() != null) {
|
||||
@ -195,14 +191,14 @@ class LettuceConnectionConfiguration extends RedisConnectionConfiguration {
|
||||
}
|
||||
|
||||
private ClientOptions createClientOptions(
|
||||
ObjectProvider<LettuceClientOptionsBuilderCustomizer> clientConfigurationBuilderCustomizers) {
|
||||
ObjectProvider<LettuceClientOptionsBuilderCustomizer> clientConfigurationBuilderCustomizers,
|
||||
SslBundle sslBundle) {
|
||||
ClientOptions.Builder builder = initializeClientOptionsBuilder();
|
||||
Duration connectTimeout = getProperties().getConnectTimeout();
|
||||
if (connectTimeout != null) {
|
||||
builder.socketOptions(SocketOptions.builder().connectTimeout(connectTimeout).build());
|
||||
}
|
||||
if (isSslEnabled() && getProperties().getSsl().getBundle() != null) {
|
||||
SslBundle sslBundle = getSslBundles().getBundle(getProperties().getSsl().getBundle());
|
||||
if (sslBundle != null) {
|
||||
io.lettuce.core.SslOptions.Builder sslOptionsBuilder = io.lettuce.core.SslOptions.builder();
|
||||
sslOptionsBuilder.keyManager(sslBundle.getManagers().getKeyManagerFactory());
|
||||
sslOptionsBuilder.trustManager(sslBundle.getManagers().getTrustManagerFactory());
|
||||
|
@ -18,6 +18,11 @@ package org.springframework.boot.autoconfigure.data.redis;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
import org.springframework.boot.ssl.SslBundle;
|
||||
import org.springframework.boot.ssl.SslBundles;
|
||||
import org.springframework.util.Assert;
|
||||
import org.springframework.util.StringUtils;
|
||||
|
||||
/**
|
||||
* Adapts {@link RedisProperties} to {@link RedisConnectionDetails}.
|
||||
*
|
||||
@ -32,8 +37,11 @@ class PropertiesRedisConnectionDetails implements RedisConnectionDetails {
|
||||
|
||||
private final RedisProperties properties;
|
||||
|
||||
PropertiesRedisConnectionDetails(RedisProperties properties) {
|
||||
private final SslBundles sslBundles;
|
||||
|
||||
PropertiesRedisConnectionDetails(RedisProperties properties, SslBundles sslBundles) {
|
||||
this.properties = properties;
|
||||
this.sslBundles = sslBundles;
|
||||
}
|
||||
|
||||
@Override
|
||||
@ -52,8 +60,21 @@ class PropertiesRedisConnectionDetails implements RedisConnectionDetails {
|
||||
public Standalone getStandalone() {
|
||||
RedisUrl redisUrl = getRedisUrl();
|
||||
return (redisUrl != null)
|
||||
? Standalone.of(redisUrl.uri().getHost(), redisUrl.uri().getPort(), redisUrl.database())
|
||||
: Standalone.of(this.properties.getHost(), this.properties.getPort(), this.properties.getDatabase());
|
||||
? Standalone.of(redisUrl.uri().getHost(), redisUrl.uri().getPort(), redisUrl.database(), getSslBundle())
|
||||
: Standalone.of(this.properties.getHost(), this.properties.getPort(), this.properties.getDatabase(),
|
||||
getSslBundle());
|
||||
}
|
||||
|
||||
private SslBundle getSslBundle() {
|
||||
if (!this.properties.getSsl().isEnabled()) {
|
||||
return null;
|
||||
}
|
||||
String bundleName = this.properties.getSsl().getBundle();
|
||||
if (StringUtils.hasLength(bundleName)) {
|
||||
Assert.notNull(this.sslBundles, "SSL bundle name has been set but no SSL bundles found in context");
|
||||
return this.sslBundles.getBundle(bundleName);
|
||||
}
|
||||
return SslBundle.systemDefault();
|
||||
}
|
||||
|
||||
@Override
|
||||
@ -65,8 +86,7 @@ class PropertiesRedisConnectionDetails implements RedisConnectionDetails {
|
||||
@Override
|
||||
public Cluster getCluster() {
|
||||
RedisProperties.Cluster cluster = this.properties.getCluster();
|
||||
List<Node> nodes = (cluster != null) ? asNodes(cluster.getNodes()) : null;
|
||||
return (nodes != null) ? () -> nodes : null;
|
||||
return (cluster != null) ? new PropertiesCluster(cluster) : null;
|
||||
}
|
||||
|
||||
private RedisUrl getRedisUrl() {
|
||||
@ -84,6 +104,29 @@ class PropertiesRedisConnectionDetails implements RedisConnectionDetails {
|
||||
return new Node(host, port);
|
||||
}
|
||||
|
||||
/**
|
||||
* {@link Cluster} implementation backed by properties.
|
||||
*/
|
||||
private class PropertiesCluster implements Cluster {
|
||||
|
||||
private final List<Node> nodes;
|
||||
|
||||
PropertiesCluster(RedisProperties.Cluster properties) {
|
||||
this.nodes = asNodes(properties.getNodes());
|
||||
}
|
||||
|
||||
@Override
|
||||
public List<Node> getNodes() {
|
||||
return this.nodes;
|
||||
}
|
||||
|
||||
@Override
|
||||
public SslBundle getSslBundle() {
|
||||
return PropertiesRedisConnectionDetails.this.getSslBundle();
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
* {@link Sentinel} implementation backed by properties.
|
||||
*/
|
||||
@ -123,6 +166,11 @@ class PropertiesRedisConnectionDetails implements RedisConnectionDetails {
|
||||
return this.properties.getPassword();
|
||||
}
|
||||
|
||||
@Override
|
||||
public SslBundle getSslBundle() {
|
||||
return PropertiesRedisConnectionDetails.this.getSslBundle();
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright 2012-2023 the original author or authors.
|
||||
* Copyright 2012-2025 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.
|
||||
@ -16,12 +16,14 @@
|
||||
|
||||
package org.springframework.boot.autoconfigure.data.redis;
|
||||
|
||||
import org.springframework.beans.factory.ObjectProvider;
|
||||
import org.springframework.boot.autoconfigure.AutoConfiguration;
|
||||
import org.springframework.boot.autoconfigure.EnableAutoConfiguration;
|
||||
import org.springframework.boot.autoconfigure.condition.ConditionalOnClass;
|
||||
import org.springframework.boot.autoconfigure.condition.ConditionalOnMissingBean;
|
||||
import org.springframework.boot.autoconfigure.condition.ConditionalOnSingleCandidate;
|
||||
import org.springframework.boot.context.properties.EnableConfigurationProperties;
|
||||
import org.springframework.boot.ssl.SslBundles;
|
||||
import org.springframework.context.annotation.Bean;
|
||||
import org.springframework.context.annotation.Import;
|
||||
import org.springframework.data.redis.connection.RedisConnectionFactory;
|
||||
@ -51,8 +53,9 @@ public class RedisAutoConfiguration {
|
||||
|
||||
@Bean
|
||||
@ConditionalOnMissingBean(RedisConnectionDetails.class)
|
||||
PropertiesRedisConnectionDetails redisConnectionDetails(RedisProperties properties) {
|
||||
return new PropertiesRedisConnectionDetails(properties);
|
||||
PropertiesRedisConnectionDetails redisConnectionDetails(RedisProperties properties,
|
||||
ObjectProvider<SslBundles> sslBundles) {
|
||||
return new PropertiesRedisConnectionDetails(properties, sslBundles.getIfAvailable());
|
||||
}
|
||||
|
||||
@Bean
|
||||
|
@ -24,6 +24,7 @@ import org.springframework.boot.autoconfigure.data.redis.RedisConnectionDetails.
|
||||
import org.springframework.boot.autoconfigure.data.redis.RedisConnectionDetails.Node;
|
||||
import org.springframework.boot.autoconfigure.data.redis.RedisConnectionDetails.Sentinel;
|
||||
import org.springframework.boot.autoconfigure.data.redis.RedisProperties.Pool;
|
||||
import org.springframework.boot.ssl.SslBundle;
|
||||
import org.springframework.boot.ssl.SslBundles;
|
||||
import org.springframework.data.redis.connection.RedisClusterConfiguration;
|
||||
import org.springframework.data.redis.connection.RedisNode;
|
||||
@ -62,6 +63,8 @@ abstract class RedisConnectionConfiguration {
|
||||
|
||||
private final SslBundles sslBundles;
|
||||
|
||||
protected final Mode mode;
|
||||
|
||||
protected RedisConnectionConfiguration(RedisProperties properties, RedisConnectionDetails connectionDetails,
|
||||
ObjectProvider<RedisStandaloneConfiguration> standaloneConfigurationProvider,
|
||||
ObjectProvider<RedisSentinelConfiguration> sentinelConfigurationProvider,
|
||||
@ -73,6 +76,7 @@ abstract class RedisConnectionConfiguration {
|
||||
this.clusterConfiguration = clusterConfigurationProvider.getIfAvailable();
|
||||
this.connectionDetails = connectionDetails;
|
||||
this.sslBundles = sslBundles.getIfAvailable();
|
||||
this.mode = determineMode();
|
||||
}
|
||||
|
||||
protected final RedisStandaloneConfiguration getStandaloneConfig() {
|
||||
@ -153,6 +157,17 @@ abstract class RedisConnectionConfiguration {
|
||||
return this.sslBundles;
|
||||
}
|
||||
|
||||
protected SslBundle getSslBundle() {
|
||||
return switch (this.mode) {
|
||||
case STANDALONE -> (this.connectionDetails.getStandalone() != null)
|
||||
? this.connectionDetails.getStandalone().getSslBundle() : null;
|
||||
case CLUSTER -> (this.connectionDetails.getCluster() != null)
|
||||
? this.connectionDetails.getCluster().getSslBundle() : null;
|
||||
case SENTINEL -> (this.connectionDetails.getSentinel() != null)
|
||||
? this.connectionDetails.getSentinel().getSslBundle() : null;
|
||||
};
|
||||
}
|
||||
|
||||
protected final boolean isSslEnabled() {
|
||||
return getProperties().getSsl().isEnabled();
|
||||
}
|
||||
@ -178,4 +193,20 @@ abstract class RedisConnectionConfiguration {
|
||||
return this.connectionDetails;
|
||||
}
|
||||
|
||||
private Mode determineMode() {
|
||||
if (getSentinelConfig() != null) {
|
||||
return Mode.SENTINEL;
|
||||
}
|
||||
if (getClusterConfiguration() != null) {
|
||||
return Mode.CLUSTER;
|
||||
}
|
||||
return Mode.STANDALONE;
|
||||
}
|
||||
|
||||
enum Mode {
|
||||
|
||||
STANDALONE, CLUSTER, SENTINEL
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
@ -19,6 +19,7 @@ package org.springframework.boot.autoconfigure.data.redis;
|
||||
import java.util.List;
|
||||
|
||||
import org.springframework.boot.autoconfigure.service.connection.ConnectionDetails;
|
||||
import org.springframework.boot.ssl.SslBundle;
|
||||
import org.springframework.util.Assert;
|
||||
|
||||
/**
|
||||
@ -98,11 +99,58 @@ public interface RedisConnectionDetails extends ConnectionDetails {
|
||||
return 0;
|
||||
}
|
||||
|
||||
static Standalone of(String host, int port) {
|
||||
return of(host, port, 0);
|
||||
/**
|
||||
* SSL bundle to use.
|
||||
* @return the SSL bundle to use
|
||||
* @since 3.5.0
|
||||
*/
|
||||
default SslBundle getSslBundle() {
|
||||
return null;
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates a new instance with the given host and port.
|
||||
* @param host the host
|
||||
* @param port the port
|
||||
* @return the new instance
|
||||
*/
|
||||
static Standalone of(String host, int port) {
|
||||
return of(host, port, 0, null);
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates a new instance with the given host, port and SSL bundle.
|
||||
* @param host the host
|
||||
* @param port the port
|
||||
* @param sslBundle the SSL bundle
|
||||
* @return the new instance
|
||||
* @since 3.5.0
|
||||
*/
|
||||
static Standalone of(String host, int port, SslBundle sslBundle) {
|
||||
return of(host, port, 0, sslBundle);
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates a new instance with the given host, port and database.
|
||||
* @param host the host
|
||||
* @param port the port
|
||||
* @param database the database
|
||||
* @return the new instance
|
||||
*/
|
||||
static Standalone of(String host, int port, int database) {
|
||||
return of(host, port, database, null);
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates a new instance with the given host, port, database and SSL bundle.
|
||||
* @param host the host
|
||||
* @param port the port
|
||||
* @param database the database
|
||||
* @param sslBundle the SSL bundle
|
||||
* @return the new instance
|
||||
* @since 3.5.0
|
||||
*/
|
||||
static Standalone of(String host, int port, int database, SslBundle sslBundle) {
|
||||
Assert.hasLength(host, "'host' must not be empty");
|
||||
return new Standalone() {
|
||||
|
||||
@ -121,6 +169,10 @@ public interface RedisConnectionDetails extends ConnectionDetails {
|
||||
return database;
|
||||
}
|
||||
|
||||
@Override
|
||||
public SslBundle getSslBundle() {
|
||||
return sslBundle;
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
@ -161,6 +213,15 @@ public interface RedisConnectionDetails extends ConnectionDetails {
|
||||
*/
|
||||
String getPassword();
|
||||
|
||||
/**
|
||||
* SSL bundle to use.
|
||||
* @return the SSL bundle to use
|
||||
* @since 3.5.0
|
||||
*/
|
||||
default SslBundle getSslBundle() {
|
||||
return null;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
@ -175,6 +236,15 @@ public interface RedisConnectionDetails extends ConnectionDetails {
|
||||
*/
|
||||
List<Node> getNodes();
|
||||
|
||||
/**
|
||||
* SSL bundle to use.
|
||||
* @return the SSL bundle to use
|
||||
* @since 3.5.0
|
||||
*/
|
||||
default SslBundle getSslBundle() {
|
||||
return null;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -18,40 +18,54 @@ package org.springframework.boot.autoconfigure.data.redis;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
import org.junit.jupiter.api.BeforeEach;
|
||||
import org.junit.jupiter.api.Test;
|
||||
|
||||
import org.springframework.boot.autoconfigure.data.redis.RedisConnectionDetails.Node;
|
||||
import org.springframework.boot.ssl.DefaultSslBundleRegistry;
|
||||
import org.springframework.boot.ssl.SslBundle;
|
||||
|
||||
import static org.assertj.core.api.Assertions.assertThat;
|
||||
import static org.mockito.Mockito.mock;
|
||||
|
||||
/**
|
||||
* Tests for {@link PropertiesRedisConnectionDetails}.
|
||||
*
|
||||
* @author Scott Frederick
|
||||
* @author Moritz Halbritter
|
||||
*/
|
||||
class PropertiesRedisConnectionDetailsTests {
|
||||
|
||||
private final RedisProperties properties = new RedisProperties();
|
||||
private RedisProperties properties;
|
||||
|
||||
private PropertiesRedisConnectionDetails connectionDetails;
|
||||
|
||||
private DefaultSslBundleRegistry sslBundleRegistry;
|
||||
|
||||
@BeforeEach
|
||||
void setUp() {
|
||||
this.properties = new RedisProperties();
|
||||
this.sslBundleRegistry = new DefaultSslBundleRegistry();
|
||||
this.connectionDetails = new PropertiesRedisConnectionDetails(this.properties, this.sslBundleRegistry);
|
||||
}
|
||||
|
||||
@Test
|
||||
void connectionIsConfiguredWithDefaults() {
|
||||
PropertiesRedisConnectionDetails connectionDetails = new PropertiesRedisConnectionDetails(this.properties);
|
||||
RedisConnectionDetails.Standalone standalone = connectionDetails.getStandalone();
|
||||
RedisConnectionDetails.Standalone standalone = this.connectionDetails.getStandalone();
|
||||
assertThat(standalone.getHost()).isEqualTo("localhost");
|
||||
assertThat(standalone.getPort()).isEqualTo(6379);
|
||||
assertThat(standalone.getDatabase()).isEqualTo(0);
|
||||
assertThat(connectionDetails.getSentinel()).isNull();
|
||||
assertThat(connectionDetails.getCluster()).isNull();
|
||||
assertThat(connectionDetails.getUsername()).isNull();
|
||||
assertThat(connectionDetails.getPassword()).isNull();
|
||||
assertThat(this.connectionDetails.getSentinel()).isNull();
|
||||
assertThat(this.connectionDetails.getCluster()).isNull();
|
||||
assertThat(this.connectionDetails.getUsername()).isNull();
|
||||
assertThat(this.connectionDetails.getPassword()).isNull();
|
||||
}
|
||||
|
||||
@Test
|
||||
void credentialsAreConfiguredFromUrlWithUsernameAndPassword() {
|
||||
this.properties.setUrl("redis://user:secret@example.com");
|
||||
PropertiesRedisConnectionDetails connectionDetails = new PropertiesRedisConnectionDetails(this.properties);
|
||||
assertThat(connectionDetails.getUsername()).isEqualTo("user");
|
||||
assertThat(connectionDetails.getPassword()).isEqualTo("secret");
|
||||
assertThat(this.connectionDetails.getUsername()).isEqualTo("user");
|
||||
assertThat(this.connectionDetails.getPassword()).isEqualTo("secret");
|
||||
}
|
||||
|
||||
@Test
|
||||
@ -59,9 +73,8 @@ class PropertiesRedisConnectionDetailsTests {
|
||||
this.properties.setUrl("redis://user:@example.com");
|
||||
this.properties.setUsername("notused");
|
||||
this.properties.setPassword("notused");
|
||||
PropertiesRedisConnectionDetails connectionDetails = new PropertiesRedisConnectionDetails(this.properties);
|
||||
assertThat(connectionDetails.getUsername()).isEqualTo("user");
|
||||
assertThat(connectionDetails.getPassword()).isEmpty();
|
||||
assertThat(this.connectionDetails.getUsername()).isEqualTo("user");
|
||||
assertThat(this.connectionDetails.getPassword()).isEmpty();
|
||||
}
|
||||
|
||||
@Test
|
||||
@ -69,9 +82,8 @@ class PropertiesRedisConnectionDetailsTests {
|
||||
this.properties.setUrl("redis://:secret@example.com");
|
||||
this.properties.setUsername("notused");
|
||||
this.properties.setPassword("notused");
|
||||
PropertiesRedisConnectionDetails connectionDetails = new PropertiesRedisConnectionDetails(this.properties);
|
||||
assertThat(connectionDetails.getUsername()).isEmpty();
|
||||
assertThat(connectionDetails.getPassword()).isEqualTo("secret");
|
||||
assertThat(this.connectionDetails.getUsername()).isEmpty();
|
||||
assertThat(this.connectionDetails.getPassword()).isEqualTo("secret");
|
||||
}
|
||||
|
||||
@Test
|
||||
@ -79,18 +91,16 @@ class PropertiesRedisConnectionDetailsTests {
|
||||
this.properties.setUrl("redis://secret@example.com");
|
||||
this.properties.setUsername("notused");
|
||||
this.properties.setPassword("notused");
|
||||
PropertiesRedisConnectionDetails connectionDetails = new PropertiesRedisConnectionDetails(this.properties);
|
||||
assertThat(connectionDetails.getUsername()).isNull();
|
||||
assertThat(connectionDetails.getPassword()).isEqualTo("secret");
|
||||
assertThat(this.connectionDetails.getUsername()).isNull();
|
||||
assertThat(this.connectionDetails.getPassword()).isEqualTo("secret");
|
||||
}
|
||||
|
||||
@Test
|
||||
void credentialsAreConfiguredFromProperties() {
|
||||
this.properties.setUsername("user");
|
||||
this.properties.setPassword("secret");
|
||||
PropertiesRedisConnectionDetails connectionDetails = new PropertiesRedisConnectionDetails(this.properties);
|
||||
assertThat(connectionDetails.getUsername()).isEqualTo("user");
|
||||
assertThat(connectionDetails.getPassword()).isEqualTo("secret");
|
||||
assertThat(this.connectionDetails.getUsername()).isEqualTo("user");
|
||||
assertThat(this.connectionDetails.getPassword()).isEqualTo("secret");
|
||||
}
|
||||
|
||||
@Test
|
||||
@ -99,8 +109,7 @@ class PropertiesRedisConnectionDetailsTests {
|
||||
this.properties.setHost("notused");
|
||||
this.properties.setPort(9999);
|
||||
this.properties.setDatabase(5);
|
||||
PropertiesRedisConnectionDetails connectionDetails = new PropertiesRedisConnectionDetails(this.properties);
|
||||
RedisConnectionDetails.Standalone standalone = connectionDetails.getStandalone();
|
||||
RedisConnectionDetails.Standalone standalone = this.connectionDetails.getStandalone();
|
||||
assertThat(standalone.getHost()).isEqualTo("example.com");
|
||||
assertThat(standalone.getPort()).isEqualTo(1234);
|
||||
assertThat(standalone.getDatabase()).isEqualTo(9999);
|
||||
@ -110,7 +119,8 @@ class PropertiesRedisConnectionDetailsTests {
|
||||
void standaloneIsConfiguredFromUrlWithoutDatabase() {
|
||||
this.properties.setUrl("redis://example.com:1234");
|
||||
this.properties.setDatabase(5);
|
||||
PropertiesRedisConnectionDetails connectionDetails = new PropertiesRedisConnectionDetails(this.properties);
|
||||
PropertiesRedisConnectionDetails connectionDetails = new PropertiesRedisConnectionDetails(this.properties,
|
||||
null);
|
||||
RedisConnectionDetails.Standalone standalone = connectionDetails.getStandalone();
|
||||
assertThat(standalone.getHost()).isEqualTo("example.com");
|
||||
assertThat(standalone.getPort()).isEqualTo(1234);
|
||||
@ -122,8 +132,7 @@ class PropertiesRedisConnectionDetailsTests {
|
||||
this.properties.setHost("example.com");
|
||||
this.properties.setPort(1234);
|
||||
this.properties.setDatabase(5);
|
||||
PropertiesRedisConnectionDetails connectionDetails = new PropertiesRedisConnectionDetails(this.properties);
|
||||
RedisConnectionDetails.Standalone standalone = connectionDetails.getStandalone();
|
||||
RedisConnectionDetails.Standalone standalone = this.connectionDetails.getStandalone();
|
||||
assertThat(standalone.getHost()).isEqualTo("example.com");
|
||||
assertThat(standalone.getPort()).isEqualTo(1234);
|
||||
assertThat(standalone.getDatabase()).isEqualTo(5);
|
||||
@ -134,8 +143,7 @@ class PropertiesRedisConnectionDetailsTests {
|
||||
RedisProperties.Cluster cluster = new RedisProperties.Cluster();
|
||||
cluster.setNodes(List.of("localhost:1111", "127.0.0.1:2222", "[::1]:3333"));
|
||||
this.properties.setCluster(cluster);
|
||||
PropertiesRedisConnectionDetails connectionDetails = new PropertiesRedisConnectionDetails(this.properties);
|
||||
assertThat(connectionDetails.getCluster().getNodes()).containsExactly(new Node("localhost", 1111),
|
||||
assertThat(this.connectionDetails.getCluster().getNodes()).containsExactly(new Node("localhost", 1111),
|
||||
new Node("127.0.0.1", 2222), new Node("[::1]", 3333));
|
||||
}
|
||||
|
||||
@ -145,7 +153,8 @@ class PropertiesRedisConnectionDetailsTests {
|
||||
sentinel.setNodes(List.of("localhost:1111", "127.0.0.1:2222", "[::1]:3333"));
|
||||
this.properties.setSentinel(sentinel);
|
||||
this.properties.setDatabase(5);
|
||||
PropertiesRedisConnectionDetails connectionDetails = new PropertiesRedisConnectionDetails(this.properties);
|
||||
PropertiesRedisConnectionDetails connectionDetails = new PropertiesRedisConnectionDetails(this.properties,
|
||||
null);
|
||||
assertThat(connectionDetails.getSentinel().getNodes()).containsExactly(new Node("localhost", 1111),
|
||||
new Node("127.0.0.1", 2222), new Node("[::1]", 3333));
|
||||
assertThat(connectionDetails.getSentinel().getDatabase()).isEqualTo(5);
|
||||
@ -158,8 +167,32 @@ class PropertiesRedisConnectionDetailsTests {
|
||||
this.properties.setSentinel(sentinel);
|
||||
this.properties.setUrl("redis://example.com:1234/9999");
|
||||
this.properties.setDatabase(5);
|
||||
PropertiesRedisConnectionDetails connectionDetails = new PropertiesRedisConnectionDetails(this.properties);
|
||||
PropertiesRedisConnectionDetails connectionDetails = new PropertiesRedisConnectionDetails(this.properties,
|
||||
null);
|
||||
assertThat(connectionDetails.getSentinel().getDatabase()).isEqualTo(9999);
|
||||
}
|
||||
|
||||
@Test
|
||||
void shouldReturnSslBundle() {
|
||||
SslBundle bundle1 = mock(SslBundle.class);
|
||||
this.sslBundleRegistry.registerBundle("bundle-1", bundle1);
|
||||
this.properties.getSsl().setBundle("bundle-1");
|
||||
SslBundle sslBundle = this.connectionDetails.getStandalone().getSslBundle();
|
||||
assertThat(sslBundle).isSameAs(bundle1);
|
||||
}
|
||||
|
||||
@Test
|
||||
void shouldReturnSystemBundleIfSslIsEnabledButBundleNotSet() {
|
||||
this.properties.getSsl().setEnabled(true);
|
||||
SslBundle sslBundle = this.connectionDetails.getStandalone().getSslBundle();
|
||||
assertThat(sslBundle).isNotNull();
|
||||
}
|
||||
|
||||
@Test
|
||||
void shouldReturnNullIfSslIsNotEnabled() {
|
||||
this.properties.getSsl().setEnabled(false);
|
||||
SslBundle sslBundle = this.connectionDetails.getStandalone().getSslBundle();
|
||||
assertThat(sslBundle).isNull();
|
||||
}
|
||||
|
||||
}
|
||||
|
@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright 2012-2024 the original author or authors.
|
||||
* Copyright 2012-2025 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.
|
||||
@ -16,9 +16,12 @@
|
||||
|
||||
package org.springframework.boot.docker.compose.service.connection.redis;
|
||||
|
||||
import javax.net.ssl.SSLContext;
|
||||
|
||||
import org.springframework.boot.autoconfigure.data.redis.RedisConnectionDetails;
|
||||
import org.springframework.boot.autoconfigure.data.redis.RedisConnectionDetails.Standalone;
|
||||
import org.springframework.boot.docker.compose.service.connection.test.DockerComposeTest;
|
||||
import org.springframework.boot.ssl.SslBundle;
|
||||
import org.springframework.boot.testsupport.container.TestImage;
|
||||
|
||||
import static org.assertj.core.api.Assertions.assertThat;
|
||||
@ -39,6 +42,17 @@ class RedisDockerComposeConnectionDetailsFactoryIntegrationTests {
|
||||
assertConnectionDetails(connectionDetails);
|
||||
}
|
||||
|
||||
@DockerComposeTest(composeFile = "redis-ssl-compose.yaml", image = TestImage.REDIS,
|
||||
additionalResources = { "ca.crt", "server.crt", "server.key", "client.crt", "client.key" })
|
||||
void runWithSslCreatesConnectionDetails(RedisConnectionDetails connectionDetails) {
|
||||
assertConnectionDetails(connectionDetails);
|
||||
Standalone standalone = connectionDetails.getStandalone();
|
||||
SslBundle sslBundle = standalone.getSslBundle();
|
||||
assertThat(sslBundle).isNotNull();
|
||||
SSLContext sslContext = sslBundle.createSslContext();
|
||||
assertThat(sslContext).isNotNull();
|
||||
}
|
||||
|
||||
@DockerComposeTest(composeFile = "redis-bitnami-compose.yaml", image = TestImage.BITNAMI_REDIS)
|
||||
void runWithBitnamiImageCreatesConnectionDetails(RedisConnectionDetails connectionDetails) {
|
||||
assertConnectionDetails(connectionDetails);
|
||||
|
@ -0,0 +1,32 @@
|
||||
-----BEGIN CERTIFICATE-----
|
||||
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
|
||||
Dyno/RVFR/rUL5091gjGRXhLsi1oUHKdEzU=
|
||||
-----END CERTIFICATE-----
|
@ -0,0 +1,26 @@
|
||||
-----BEGIN CERTIFICATE-----
|
||||
MIIEWjCCAkKgAwIBAgIURBZvq442tp+/K9TZII5Vy/LzVx0wDQYJKoZIhvcNAQEL
|
||||
BQAwOzEZMBcGA1UECgwQU3ByaW5nIEJvb3QgVGVzdDEeMBwGA1UEAwwVQ2VydGlm
|
||||
aWNhdGUgQXV0aG9yaXR5MB4XDTI0MDUwMTE2NTMyNVoXDTM0MDQyOTE2NTMyNVow
|
||||
LzEZMBcGA1UECgwQU3ByaW5nIEJvb3QgVGVzdDESMBAGA1UEAwwJbG9jYWxob3N0
|
||||
MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAvGb7tu0odSuOjeY1lHlh
|
||||
sRR4PayAvlryjfrrp49hjoVTiL3d/Jo6Po5HlqwJcYuclm0EWQR5Vur/zYJpfUE7
|
||||
b8+E9Qwe50+YzfQ2tVFEdq/VfqemrYRGee+pMelOCI90enOKCxfpo6EHbz+WnUP0
|
||||
mnD8OAF9QpolSdWAMOGJoPdWX65KQvyMXvQbj9VIHmsx7NCaIOYxjHXB/dI2FmXV
|
||||
+m4VT6mb8he9dXmgK/ozMq6XIPOAXe0n3dlfMTSEddeNeVwnBpr/n5e0cpwGFhdf
|
||||
NNu5CI4ecipBhXljJi/4/47M/6hd69HwE05C4zyH4ZDZ2JTfaSKOLV+jYdBUqJP5
|
||||
dwIDAQABo2IwYDALBgNVHQ8EBAMCBaAwEQYJYIZIAYb4QgEBBAQDAgeAMB0GA1Ud
|
||||
DgQWBBRWiWOo9cm2IF/ZlhWLVjifLzYa/DAfBgNVHSMEGDAWgBRVMLDVqPECWaH6
|
||||
GruL9E52VcTrPjANBgkqhkiG9w0BAQsFAAOCAgEAA5Wphtu2nBhY+QNOBOwXq4zF
|
||||
N5qt2IYTLfR7xqpKhhXx9VkIjdPWpcsGuCuMmfPVNvQWE6iK0/jMMqToTj4H6K7e
|
||||
MN74j0GwwcknT1P42tUzEpg8LKR8VMdhWhyqdniCDNWWuaz1iVSoF0S2i4jFSzH5
|
||||
1q3KMKMZ4niK5aJI0fAGa4fCjyuun1Mfg/qGBGwLnqDkIXjeAopZf4Jb64TtzjAs
|
||||
j9NT6mYbe3E0tw3fHT9ihYdbZDZgSjeCsuq9OiRMVb0DWWmRoLmmOrlN8IJlHV/3
|
||||
WyI/ta4Cw5EZ0oaOg0lIyOxXyvElth1xIvh+kdqZSBsU0gNBri6ZIzYbbTh2KTTO
|
||||
BJHQt9L5naWG27pDrIxBicWXS/MIYonktm3YgCLfuW3kWcVk8bIlNhfcoAYBBgfM
|
||||
IEYSYEq+bH2IQ+YoWQz3AxjJ8gEuuSUP6R6mYY65FfpjkKgcpGBvw4EIAmqKDtPS
|
||||
hlLY/F0XVj9KZzrMyH4/vonu+DAb/P7Zmt2fyk/dQO6bAc3ltRmJbJm4VJ2v/T8I
|
||||
LVu2FtcUYgtLNtkWUPfdb3GSUUgkKlUpWSty31TKSUszJjW1oRykQhEko6o5U3S8
|
||||
ptQzXdApsb1lGOqewkubE25tIu2RLiNkKcjFOjJ/lu0vP9k76wWwRVnFLFvfo4lW
|
||||
pgywiOifs5JbcCt0ZQ0=
|
||||
-----END CERTIFICATE-----
|
@ -0,0 +1,28 @@
|
||||
-----BEGIN PRIVATE KEY-----
|
||||
MIIEvgIBADANBgkqhkiG9w0BAQEFAASCBKgwggSkAgEAAoIBAQC8Zvu27Sh1K46N
|
||||
5jWUeWGxFHg9rIC+WvKN+uunj2GOhVOIvd38mjo+jkeWrAlxi5yWbQRZBHlW6v/N
|
||||
gml9QTtvz4T1DB7nT5jN9Da1UUR2r9V+p6athEZ576kx6U4Ij3R6c4oLF+mjoQdv
|
||||
P5adQ/SacPw4AX1CmiVJ1YAw4Ymg91ZfrkpC/Ixe9BuP1UgeazHs0Jog5jGMdcH9
|
||||
0jYWZdX6bhVPqZvyF711eaAr+jMyrpcg84Bd7Sfd2V8xNIR11415XCcGmv+fl7Ry
|
||||
nAYWF18027kIjh5yKkGFeWMmL/j/jsz/qF3r0fATTkLjPIfhkNnYlN9pIo4tX6Nh
|
||||
0FSok/l3AgMBAAECggEABXnBe3MwXAMQENzNypOiXK4VE3XMYkePfdsSK163byOD
|
||||
w3ZeTgQNfU4g8LJK8/homzO0SQIJAdz2+ZFbpsp4A2W2zJ+1jvN5RuX/8/UcVhmk
|
||||
tb1IL/LWCvx5/aoYBWkgIA70UfQJa2jDbdM0v5j/Gu9yE7GI14jh6DFC3xGMGV3b
|
||||
fOwManxf7sDibCI1nGjnFYNGxninRr+tpb+a1KNbVzhett68LrgPmtph6B3HCPAJ
|
||||
zBigk1Phgb8WHozTXxnLyw9/RdKJ0Ro4PFmtQv0EvCSlytptnF+0nXkqr3f851XS
|
||||
bUWwYFchIFWPMhPfD5B3niNWCV42/sU/bQlk+BMQAQKBgQD6NvMq8EdYy2Y7fXT5
|
||||
FgB4s+7EkLgI2d5LUaCXCFgc6iZtCTQKUXj1rIWeRfGrFVCCe8qV+XIMKt/G5eEi
|
||||
tn5ifHhktA2A8GK1scj026qHP3bVn0hMaUnkCF1UpDRKPiEO5G/apPtav8PbCNaX
|
||||
GAimLGw+WZNZuv7+T33bEBeUdwKBgQDAwiidayLXkRkz2deefdDKcXQsB7RHFGGy
|
||||
vfZPBCGqizxml+6ojJkkDsVUKL1IXFfyK9KpQAI6tezn4oktgu4jAQqkYY7QZobs
|
||||
RpQx1dR+KxEm7ISDBTq/B1Q9cFKUKVvQQy8N2pnIbCdzb6MTOKLmJqFGTjr+5T8q
|
||||
F32B5vkDAQKBgDCKfH42AwFc5EZiPlEcTZcdARMtKCa/bXqbKVZjjgR+AFpi0K+3
|
||||
womWoI1l8E5KYkYOEe0qaU+m+aaybgy37qjYkNqoe34qJFwvU1b9ToXScBFdRz9b
|
||||
pbQRU1naSTKl/u/OrUxzeTfPwAU8H7VMOlFSiOVHp2he+J0JetcGtixdAoGBAIJQ
|
||||
QMj7rxhxHcqyEVUy1b6nKNTDeJs9Kjd+uU/+CQyVCQaK3GvScY2w9rLIv/51f3dX
|
||||
LRoDDf7HExxJSFgeVgQQJjOvSK+XQMvngzSVzQxm7TeVWpiBJpAS0l6e2xUTSODp
|
||||
KpyBFsoqZBlkdaj+9xIFN66iILxGG4fHTbBOiDYBAoGBAOZMKjM5N/hGcCmik/6t
|
||||
p/zBA2pN9O6zwPndITTsdyVWSlVqCZhXlRX47CerAN+/WVCidlh7Vp5Tuy75Wa77
|
||||
v16IDLO01txgWNobcLaM4VgFsyLi5JuxK73S18Vb1cKWdHFRF0LH3cUIq20fjpv6
|
||||
Odl4vjNOncXMZCLPHQ+bKWaf
|
||||
-----END PRIVATE KEY-----
|
@ -0,0 +1,21 @@
|
||||
services:
|
||||
redis:
|
||||
image: '{imageName}'
|
||||
ports:
|
||||
- '6379'
|
||||
secrets:
|
||||
- ssl-ca
|
||||
- ssl-key
|
||||
- ssl-cert
|
||||
command: 'redis-server --tls-port 6379 --port 0 --tls-cert-file /run/secrets/ssl-cert --tls-key-file /run/secrets/ssl-key --tls-ca-cert-file /run/secrets/ssl-ca'
|
||||
labels:
|
||||
- 'org.springframework.boot.sslbundle.pem.keystore.certificate=client.crt'
|
||||
- 'org.springframework.boot.sslbundle.pem.keystore.private-key=client.key'
|
||||
- 'org.springframework.boot.sslbundle.pem.truststore.certificate=ca.crt'
|
||||
secrets:
|
||||
ssl-ca:
|
||||
file: 'ca.crt'
|
||||
ssl-key:
|
||||
file: 'server.key'
|
||||
ssl-cert:
|
||||
file: 'server.crt'
|
@ -0,0 +1,26 @@
|
||||
-----BEGIN CERTIFICATE-----
|
||||
MIIEWjCCAkKgAwIBAgIURBZvq442tp+/K9TZII5Vy/LzVxwwDQYJKoZIhvcNAQEL
|
||||
BQAwOzEZMBcGA1UECgwQU3ByaW5nIEJvb3QgVGVzdDEeMBwGA1UEAwwVQ2VydGlm
|
||||
aWNhdGUgQXV0aG9yaXR5MB4XDTI0MDUwMTE2NTMyNVoXDTM0MDQyOTE2NTMyNVow
|
||||
LzEZMBcGA1UECgwQU3ByaW5nIEJvb3QgVGVzdDESMBAGA1UEAwwJbG9jYWxob3N0
|
||||
MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAsllxsSQzTTJlNHMfXC2b
|
||||
CIXCPsfCgCBl7FbPz828jwJk+EYcXh0+WTFGks0WxSwb8NQza5UtyCUDEueZj9fV
|
||||
j5mWBY97WCu01Sl/3xClHmYisXfyyv27GKec7PaSOurCm2JDkyHRNumiJROa4jte
|
||||
N0GOHzw7FYsM3779TuNw14/gtW+eBrGnvgrpU7fbUvx42Di6ftGYQUwIi+3uIaqT
|
||||
//i7ktDMaAQJtkL6haTzZ5JN2qKO5a34/WRz/ApvPw3lpDV8c4qoTk3C0Bg9MP+a
|
||||
DnZtjtLBSN9CJWwr+n11QaMgHTotEKsOahGdi3J2zYxCvJP0LT+hjN2O9aRzSMIs
|
||||
MwIDAQABo2IwYDALBgNVHQ8EBAMCBaAwEQYJYIZIAYb4QgEBBAQDAgZAMB0GA1Ud
|
||||
DgQWBBS9XQHGwJZhG0olAGM1UMNuwZ65DzAfBgNVHSMEGDAWgBRVMLDVqPECWaH6
|
||||
GruL9E52VcTrPjANBgkqhkiG9w0BAQsFAAOCAgEAhBcqm5UQahn8iFMETXvfLMR6
|
||||
OOPijsHQ5lVfhig08s46a9O5eaJ9EYSYyiDnxYvZ4gYVH03f/kPwNLamvGR5KIBQ
|
||||
R0DltkPPX4a11/vjwlSq1cXAt9r59nY+sNcVXWgIWH7zNodL8lyTpYhqvB2wEQkx
|
||||
t2/JKZ8A0sGjed4S6I5HofYd7bnBxQZgfZShQ2SdDbzbcyg4SCEb8ghwnsH0KNZo
|
||||
jJF+20RpK2VMViE6lylLTEMd/PyAdST/NPoqVxyva3QjTrKt+tkkFTsmNVMXcmYC
|
||||
f1xo1/YFp73FFE63VYFI+Yw+Ajau8sYSo4+YvgFCy+Efhf3h3GFDtaiNod56uX9G
|
||||
9M/cu8XsFzFP2e/0YWY3XL+v7ESOdc3g7yS4FQZ7Z6YvfAed9hCB25cDECvZXqJG
|
||||
HSYDR38NHyAPROuCwlEwDyVmWRl9bpwZt+hr9kaTQScIDx+rV/EF3o0GKIwtR7AK
|
||||
jaPAta0f4/Uu+EuWAcccSRUMtfx5/Jse/6iliBvy7JXmA+Y0PrT7K4uHO7iktdI+
|
||||
x8WbfZKfnLVuqw5fneTjC1n48Ltjis/f8DgO7BuWTmLdZXddjqqxzBSukFTBn4Hg
|
||||
/oSg3XiMywOAVrRCNJehcdTG0u/BqZsrRjcYAJaf5qG/0tMLNsuF9Y53XQQAeezE
|
||||
etL+7y0mkeQhVF+Kmy4=
|
||||
-----END CERTIFICATE-----
|
@ -0,0 +1,28 @@
|
||||
-----BEGIN PRIVATE KEY-----
|
||||
MIIEugIBADANBgkqhkiG9w0BAQEFAASCBKQwggSgAgEAAoIBAQCyWXGxJDNNMmU0
|
||||
cx9cLZsIhcI+x8KAIGXsVs/PzbyPAmT4RhxeHT5ZMUaSzRbFLBvw1DNrlS3IJQMS
|
||||
55mP19WPmZYFj3tYK7TVKX/fEKUeZiKxd/LK/bsYp5zs9pI66sKbYkOTIdE26aIl
|
||||
E5riO143QY4fPDsViwzfvv1O43DXj+C1b54Gsae+CulTt9tS/HjYOLp+0ZhBTAiL
|
||||
7e4hqpP/+LuS0MxoBAm2QvqFpPNnkk3aoo7lrfj9ZHP8Cm8/DeWkNXxziqhOTcLQ
|
||||
GD0w/5oOdm2O0sFI30IlbCv6fXVBoyAdOi0Qqw5qEZ2LcnbNjEK8k/QtP6GM3Y71
|
||||
pHNIwiwzAgMBAAECgf9REZuCvy2Bi8SoTnjqQuHG5FuA6cPuisuFZr1k88IO+zJQ
|
||||
uY3WKNs29BV+LcxnoK29W8jQnjqPHXcMfrF5dVWmkrrJdu8JLaGWVHF+uBq8nRb0
|
||||
2LvREh5XhZTGzIESNdc/7GIxdouag/8FlzCUYQGuT3v9+wUCiim+4CuIuPvv7ncD
|
||||
8vANe3Ua5G0mHjVshOiMNpegg45zYlzYpMtUFPs+asLilW6A7UlgC+pLZ1cHUUlU
|
||||
ZB7KOGT9JdrZpilTidl6LLvDDQK30TSWz8A26SuEAE71DR2VEjLVpjTNS76vlx+c
|
||||
CrYr/WwpMb0xul+e/uHiNgo+51FiTiJ/IfuGeskCgYEA804CXQM6i5m4/Upps2yG
|
||||
aTae5xBaYUquZREp5Zb054U6lUAHI41iTMTIwTTvWn5ogNojgi+YjljkzRj2RQ5k
|
||||
NccBkjBBwwUNVWpBoGeZ73KAdejNB4C4ucGc2kkqEDo4MU5x3IE4JK1Yi1jl9mKb
|
||||
IR6m3pqb2PCQHjO8sqKNHYkCgYEAu6fH/qUd/XGmCZJWY5K6jg3dISXH16MTO5M+
|
||||
jetprkGMMybWKZQa1GedXurPexE48oRlRhkjdQkW6Wcj1Qh6OKp6N2Zx8sY4dLeQ
|
||||
yVChnMPFE2LK+UlRCKJUZi+rzX415ML6pZg+yW7O2cHpMKv7PlXISw2YDqtboCAi
|
||||
Y+doqNsCgYBE1yqmBJbZDuqfiCF2KduyA0lcmWzpIEdNw1h2ZIrwwup7dj1O2t8Y
|
||||
V4lx2TdsBF4vLwli+XKRvCcovMpZaaQC70bLhSnmMxS9uS3OY+HTNTORqQfx+oLJ
|
||||
1DU8Mf1b0A08LjTbLhijkASAkOuoFehMq66NR3OXIyGz2fGnHYUN+QKBgCC47SL2
|
||||
X/hl7PIWVoIef/FtcXXqRKLRiPUGhA3zUwZT38K7rvSpItSPDN4UTAHFywxfEdnb
|
||||
YFd0Mk6Y8aKgS8+9ynoGnzAaaJXRvKmeKdBQQvlSbNpzcnHy/IylG2xF6dfuOA7Q
|
||||
MYKmk+Nc8PDPzIveIYMU58MHFn8hm12YaKOpAoGAV1CE8hFkEK9sbRGoKNJkx9nm
|
||||
CZTv7PybaG/RN4ZrBSwVmnER0FEagA/Tzrlp1pi3sC8ZsC9onSOf6Btq8ZE0zbO1
|
||||
vsAm3gTBXcrCJxzw0Wjt8pzEbk3yELm4WE6VDEx4da2jWocdspslpIwdjHnPwsbH
|
||||
r5O3ZAgigZs/ZtKW/U4=
|
||||
-----END PRIVATE KEY-----
|
@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright 2012-2024 the original author or authors.
|
||||
* Copyright 2012-2025 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.
|
||||
@ -57,7 +57,7 @@ class RedisDockerComposeConnectionDetailsFactory extends DockerComposeConnection
|
||||
|
||||
RedisDockerComposeConnectionDetails(RunningService service) {
|
||||
super(service);
|
||||
this.standalone = Standalone.of(service.host(), service.ports().get(REDIS_PORT));
|
||||
this.standalone = Standalone.of(service.host(), service.ports().get(REDIS_PORT), getSslBundle(service));
|
||||
}
|
||||
|
||||
@Override
|
||||
|
@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright 2012-2024 the original author or authors.
|
||||
* Copyright 2012-2025 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.
|
||||
@ -75,7 +75,8 @@ class RedisContainerConnectionDetailsFactory
|
||||
|
||||
@Override
|
||||
public Standalone getStandalone() {
|
||||
return Standalone.of(getContainer().getHost(), getContainer().getMappedPort(REDIS_PORT));
|
||||
return Standalone.of(getContainer().getHost(), getContainer().getMappedPort(REDIS_PORT),
|
||||
super.getSslBundle());
|
||||
}
|
||||
|
||||
}
|
||||
|
@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright 2012-2024 the original author or authors.
|
||||
* Copyright 2012-2025 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.
|
||||
@ -26,6 +26,8 @@ import org.testcontainers.junit.jupiter.Testcontainers;
|
||||
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
import org.springframework.boot.test.autoconfigure.data.redis.DataRedisTest;
|
||||
import org.springframework.boot.testcontainers.service.connection.PemKeyStore;
|
||||
import org.springframework.boot.testcontainers.service.connection.PemTrustStore;
|
||||
import org.springframework.boot.testcontainers.service.connection.ServiceConnection;
|
||||
import org.springframework.boot.testsupport.classpath.ClassPathExclusions;
|
||||
import org.springframework.boot.testsupport.container.TestImage;
|
||||
@ -40,16 +42,15 @@ import static org.assertj.core.api.Assertions.assertThat;
|
||||
*/
|
||||
@Testcontainers(disabledWithoutDocker = true)
|
||||
@ClassPathExclusions("lettuce-core-*.jar")
|
||||
@DataRedisTest(properties = { "spring.data.redis.ssl.bundle=client",
|
||||
"spring.ssl.bundle.pem.client.keystore.certificate=classpath:ssl/test-client.crt",
|
||||
"spring.ssl.bundle.pem.client.keystore.private-key=classpath:ssl/test-client.key",
|
||||
"spring.ssl.bundle.pem.client.truststore.certificate=classpath:ssl/test-ca.crt" })
|
||||
@DataRedisTest
|
||||
class SampleRedisApplicationJedisSslTests {
|
||||
|
||||
private static final Charset CHARSET = StandardCharsets.UTF_8;
|
||||
|
||||
@Container
|
||||
@ServiceConnection
|
||||
@PemKeyStore(certificate = "classpath:ssl/test-client.crt", privateKey = "classpath:ssl/test-client.key")
|
||||
@PemTrustStore("classpath:ssl/test-ca.crt")
|
||||
static RedisContainer redis = TestImage.container(SecureRedisContainer.class);
|
||||
|
||||
@Autowired
|
||||
|
@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright 2012-2024 the original author or authors.
|
||||
* Copyright 2012-2025 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.
|
||||
@ -27,6 +27,8 @@ import reactor.test.StepVerifier;
|
||||
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
import org.springframework.boot.test.context.SpringBootTest;
|
||||
import org.springframework.boot.testcontainers.service.connection.PemKeyStore;
|
||||
import org.springframework.boot.testcontainers.service.connection.PemTrustStore;
|
||||
import org.springframework.boot.testcontainers.service.connection.ServiceConnection;
|
||||
import org.springframework.boot.testsupport.container.TestImage;
|
||||
import org.springframework.data.redis.core.ReactiveRedisOperations;
|
||||
@ -37,14 +39,13 @@ import org.springframework.data.redis.core.ReactiveRedisOperations;
|
||||
* @author Scott Frederick
|
||||
*/
|
||||
@Testcontainers(disabledWithoutDocker = true)
|
||||
@SpringBootTest(properties = { "spring.data.redis.ssl.bundle=client",
|
||||
"spring.ssl.bundle.pem.client.keystore.certificate=classpath:ssl/test-client.crt",
|
||||
"spring.ssl.bundle.pem.client.keystore.private-key=classpath:ssl/test-client.key",
|
||||
"spring.ssl.bundle.pem.client.truststore.certificate=classpath:ssl/test-ca.crt" })
|
||||
@SpringBootTest
|
||||
class SampleRedisApplicationReactiveSslTests {
|
||||
|
||||
@Container
|
||||
@ServiceConnection
|
||||
@PemKeyStore(certificate = "classpath:ssl/test-client.crt", privateKey = "classpath:ssl/test-client.key")
|
||||
@PemTrustStore("classpath:ssl/test-ca.crt")
|
||||
static RedisContainer redis = TestImage.container(SecureRedisContainer.class);
|
||||
|
||||
@Autowired
|
||||
|
@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright 2012-2024 the original author or authors.
|
||||
* Copyright 2012-2025 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.
|
||||
@ -26,6 +26,8 @@ import org.testcontainers.junit.jupiter.Testcontainers;
|
||||
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
import org.springframework.boot.test.context.SpringBootTest;
|
||||
import org.springframework.boot.testcontainers.service.connection.PemKeyStore;
|
||||
import org.springframework.boot.testcontainers.service.connection.PemTrustStore;
|
||||
import org.springframework.boot.testcontainers.service.connection.ServiceConnection;
|
||||
import org.springframework.boot.testsupport.container.TestImage;
|
||||
import org.springframework.data.redis.core.RedisOperations;
|
||||
@ -38,16 +40,15 @@ import static org.assertj.core.api.Assertions.assertThat;
|
||||
* @author Scott Frederick
|
||||
*/
|
||||
@Testcontainers(disabledWithoutDocker = true)
|
||||
@SpringBootTest(properties = { "spring.data.redis.ssl.bundle=client",
|
||||
"spring.ssl.bundle.pem.client.keystore.certificate=classpath:ssl/test-client.crt",
|
||||
"spring.ssl.bundle.pem.client.keystore.private-key=classpath:ssl/test-client.key",
|
||||
"spring.ssl.bundle.pem.client.truststore.certificate=classpath:ssl/test-ca.crt" })
|
||||
@SpringBootTest
|
||||
class SampleRedisApplicationSslTests {
|
||||
|
||||
private static final Charset CHARSET = StandardCharsets.UTF_8;
|
||||
|
||||
@Container
|
||||
@ServiceConnection
|
||||
@PemKeyStore(certificate = "classpath:ssl/test-client.crt", privateKey = "classpath:ssl/test-client.key")
|
||||
@PemTrustStore("classpath:ssl/test-ca.crt")
|
||||
static RedisContainer redis = TestImage.container(SecureRedisContainer.class);
|
||||
|
||||
@Autowired
|
||||
|
Loading…
x
Reference in New Issue
Block a user