Skip to content

Commit d56bd91

Browse files
fix some of the ssl tests
1 parent 54ba159 commit d56bd91

File tree

5 files changed

+151
-17
lines changed

5 files changed

+151
-17
lines changed

src/test/java/io/lettuce/core/SslIntegrationTests.java

Lines changed: 21 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -42,6 +42,8 @@
4242
import java.io.File;
4343
import java.net.MalformedURLException;
4444
import java.net.URL;
45+
import java.nio.file.Path;
46+
import java.nio.file.Paths;
4547
import java.time.Duration;
4648
import java.util.List;
4749
import java.util.function.Function;
@@ -50,6 +52,7 @@
5052

5153
import static io.lettuce.TestTags.INTEGRATION_TEST;
5254
import static io.lettuce.test.settings.TestSettings.sslPort;
55+
import static io.lettuce.test.settings.TlsSettings.*;
5356
import static org.assertj.core.api.Assertions.assertThat;
5457
import static org.assertj.core.api.Assertions.assertThatThrownBy;
5558
import static org.junit.jupiter.api.Assumptions.assumeTrue;
@@ -66,11 +69,9 @@ class SslIntegrationTests extends TestSupport {
6669

6770
private static final String KEYSTORE = "work/keystore.jks";
6871

69-
private static final String TRUSTSTORE = "work/truststore.jks";
72+
private static File truststoreFile;
7073

71-
private static final File TRUSTSTORE_FILE = new File(TRUSTSTORE);
72-
73-
private static final File CA_CERT_FILE = new File("work/ca/certs/ca.cert.pem");
74+
private static File cacertFile;
7475

7576
private static final int MASTER_SLAVE_BASE_PORT_OFFSET = 2000;
7677

@@ -111,9 +112,12 @@ class SslIntegrationTests extends TestSupport {
111112

112113
@BeforeAll
113114
static void beforeClass() {
114-
115+
Path path = createAndSaveTestTruststore("redis-standalone-1", Paths.get("work/tls"), "changeit");
116+
truststoreFile = path.toFile();
117+
cacertFile = envCa(Paths.get("redis-standalone-1/work/tls")).toFile();
118+
// do for 6444 and 8444
115119
assumeTrue(CanConnect.to(TestSettings.host(), sslPort()), "Assume that stunnel runs on port 6443");
116-
assertThat(TRUSTSTORE_FILE).exists();
120+
assertThat(truststoreFile).exists();
117121
}
118122

119123
@Test
@@ -130,7 +134,7 @@ void standaloneWithJdkSsl() {
130134

131135
SslOptions sslOptions = SslOptions.builder() //
132136
.jdkSslProvider() //
133-
.truststore(TRUSTSTORE_FILE) //
137+
.truststore(truststoreFile, "changeit") //
134138
.build();
135139
setOptions(sslOptions);
136140

@@ -142,7 +146,7 @@ void standaloneWithVerifyCaOnly() {
142146

143147
SslOptions sslOptions = SslOptions.builder() //
144148
.jdkSslProvider() //
145-
.truststore(TRUSTSTORE_FILE) //
149+
.truststore(truststoreFile, "changeit") //
146150
.build();
147151
setOptions(sslOptions);
148152

@@ -153,7 +157,7 @@ void standaloneWithVerifyCaOnly() {
153157
void standaloneWithPemCert() {
154158

155159
SslOptions sslOptions = SslOptions.builder() //
156-
.trustManager(CA_CERT_FILE) //
160+
.trustManager(cacertFile) //
157161
.build();
158162
setOptions(sslOptions);
159163
verifyConnection(URI_VERIFY);
@@ -164,7 +168,7 @@ void standaloneWithPemCertAndImpossibleTimeout() {
164168

165169
Assertions.setMaxStackTraceElementsDisplayed(30);
166170
SslOptions sslOptions = SslOptions.builder() //
167-
.trustManager(CA_CERT_FILE) //
171+
.trustManager(cacertFile) //
168172
.build();
169173
setOptions(sslOptions);
170174
redisClient.setOptions(ClientOptions.builder().protocolVersion(ProtocolVersion.RESP3).sslOptions(sslOptions).build());
@@ -196,7 +200,7 @@ void standaloneWithClientCertificates() {
196200
SslOptions sslOptions = SslOptions.builder() //
197201
.jdkSslProvider() //
198202
.keystore(new File(KEYSTORE), "changeit".toCharArray()) //
199-
.truststore(TRUSTSTORE_FILE) //
203+
.truststore(truststoreFile, "changeit") //
200204
.build();
201205
setOptions(sslOptions);
202206

@@ -208,7 +212,7 @@ void standaloneWithClientCertificatesWithoutKeystore() {
208212

209213
SslOptions sslOptions = SslOptions.builder() //
210214
.jdkSslProvider() //
211-
.truststore(TRUSTSTORE_FILE) //
215+
.truststore(truststoreFile, "changeit") //
212216
.build();
213217
setOptions(sslOptions);
214218

@@ -245,7 +249,7 @@ void standaloneWithOpenSsl() {
245249

246250
SslOptions sslOptions = SslOptions.builder() //
247251
.openSslProvider() //
248-
.truststore(TRUSTSTORE_FILE) //
252+
.truststore(truststoreFile, "changeit") //
249253
.build();
250254
setOptions(sslOptions);
251255

@@ -298,7 +302,7 @@ void masterSlaveWithJdkSsl() {
298302

299303
SslOptions sslOptions = SslOptions.builder() //
300304
.jdkSslProvider() //
301-
.truststore(TRUSTSTORE_FILE) //
305+
.truststore(truststoreFile, "changeit") //
302306
.build();
303307
setOptions(sslOptions);
304308

@@ -363,7 +367,7 @@ void masterSlaveSslWithOneInvalidHostWillSucceed() {
363367

364368
SslOptions sslOptions = SslOptions.builder() //
365369
.jdkSslProvider() //
366-
.truststore(TRUSTSTORE_FILE) //
370+
.truststore(truststoreFile, "changeit") //
367371
.build();
368372
setOptions(sslOptions);
369373

@@ -375,7 +379,7 @@ void masterSlaveSslWithAllInvalidHostsWillFail() {
375379

376380
SslOptions sslOptions = SslOptions.builder() //
377381
.jdkSslProvider() //
378-
.truststore(TRUSTSTORE_FILE) //
382+
.truststore(truststoreFile, "changeit") //
379383
.build();
380384
setOptions(sslOptions);
381385

@@ -416,7 +420,7 @@ private static List<RedisURI> sslUris(IntStream masterSlaveOffsets,
416420
}
417421

418422
private URL truststoreURL() throws MalformedURLException {
419-
return TRUSTSTORE_FILE.toURI().toURL();
423+
return truststoreFile.toURI().toURL();
420424
}
421425

422426
private void setOptions(SslOptions sslOptions) {
Lines changed: 124 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,124 @@
1+
package io.lettuce.test.settings;
2+
3+
import java.io.FileInputStream;
4+
import java.io.FileOutputStream;
5+
import java.io.IOException;
6+
import java.nio.file.Path;
7+
import java.nio.file.Paths;
8+
import java.security.KeyStore;
9+
import java.security.KeyStoreException;
10+
import java.security.NoSuchAlgorithmException;
11+
import java.security.cert.CertificateException;
12+
import java.security.cert.CertificateFactory;
13+
import java.security.cert.X509Certificate;
14+
import java.util.ArrayList;
15+
import java.util.List;
16+
import java.util.UUID;
17+
18+
public class TlsSettings {
19+
20+
private static final String TRUST_STORE_TYPE = "PKCS12";
21+
22+
private static final String TEST_WORK_FOLDER = System.getenv().getOrDefault("TEST_WORK_FOLDER", "/tmp/redis-env-work");
23+
24+
private static final String TEST_SERVER_CERT = "redis.crt";
25+
26+
private static final String TEST_CA_CERT = "ca.crt";
27+
28+
private static final String TEST_TRUSTSTORE = "truststore.jks";
29+
30+
public static Path envServerCert(Path certLocation) {
31+
return Paths.get(TEST_WORK_FOLDER, certLocation.toString(), TEST_SERVER_CERT);
32+
}
33+
34+
public static Path envCa(Path certLocation) {
35+
return Paths.get(TEST_WORK_FOLDER, certLocation.toString(), TEST_CA_CERT);
36+
}
37+
38+
public static Path testTruststorePath(String name) {
39+
return Paths.get(TEST_WORK_FOLDER, name + '-' + TEST_TRUSTSTORE);
40+
}
41+
42+
/**
43+
* Creates an empty truststore.
44+
*
45+
* @return An empty KeyStore object.
46+
* @throws KeyStoreException If there's an error initializing the truststore.
47+
* @throws IOException If there's an error loading the truststore.
48+
* @throws NoSuchAlgorithmException If the algorithm used to check the integrity of the truststore cannot be found.
49+
* @throws CertificateException If any of the certificates in the truststore could not be loaded.
50+
*/
51+
private static KeyStore createTruststore()
52+
throws KeyStoreException, IOException, NoSuchAlgorithmException, CertificateException {
53+
KeyStore trustStore = KeyStore.getInstance(TRUST_STORE_TYPE);
54+
trustStore.load(null, null);
55+
return trustStore;
56+
}
57+
58+
/**
59+
* Loads an X.509 certificate from the given file path.
60+
*
61+
* @param certPath Path to the certificate file.
62+
* @return An X509Certificate object.
63+
* @throws Exception If there's an error loading the certificate.
64+
*/
65+
private static X509Certificate loadCertificate(Path certPath) throws Exception {
66+
try (FileInputStream fis = new FileInputStream(certPath.toFile())) {
67+
CertificateFactory certFactory = CertificateFactory.getInstance("X.509");
68+
return (X509Certificate) certFactory.generateCertificate(fis);
69+
}
70+
}
71+
72+
/**
73+
* Adds a trusted certificate to the given truststore.
74+
*
75+
* @param trustStore The KeyStore object.
76+
* @param alias Alias for the certificate.
77+
* @param certPath Path to the certificate file.
78+
* @throws Exception If there's an error adding the certificate.
79+
*/
80+
private static void addTrustedCertificate(KeyStore trustStore, String alias, Path certPath) throws Exception {
81+
X509Certificate cert = loadCertificate(certPath);
82+
trustStore.setCertificateEntry(alias, cert);
83+
}
84+
85+
/**
86+
* Creates a truststore, adds multiple trusted certificates, and saves it to the specified path.
87+
*
88+
* @param trustedCertPaths List of certificate file paths to add to the truststore.
89+
* @param truststorePath Path to save the generated truststore.
90+
* @param truststorePassword Password for the truststore.
91+
* @return Path to the saved truststore file.
92+
*/
93+
public static Path createAndSaveTruststore(List<Path> trustedCertPaths, Path truststorePath, String truststorePassword) {
94+
try {
95+
KeyStore trustStore = createTruststore();
96+
97+
for (Path certPath : trustedCertPaths) {
98+
addTrustedCertificate(trustStore, "trusted-cert-" + UUID.randomUUID(), certPath);
99+
}
100+
101+
try (FileOutputStream fos = new FileOutputStream(truststorePath.toFile())) {
102+
trustStore.store(fos, truststorePassword.toCharArray());
103+
} catch (IOException e) {
104+
throw new RuntimeException("Failed to save truststore to " + truststorePath + ": " + e.getMessage(), e);
105+
}
106+
} catch (Exception e) {
107+
throw new RuntimeException("Failed to create and save truststore: " + e.getMessage(), e);
108+
}
109+
110+
return truststorePath;
111+
}
112+
113+
public static Path createAndSaveTestTruststore(String trustStoreName, Path certificateLocations,
114+
String truststorePassword) {
115+
List<Path> trustedCertPaths = new ArrayList<>();
116+
trustedCertPaths.add(envCa(certificateLocations).toAbsolutePath());
117+
trustedCertPaths.add(envServerCert(certificateLocations).toAbsolutePath());
118+
119+
Path trustStorePath = testTruststorePath(trustStoreName).toAbsolutePath();
120+
121+
return createAndSaveTruststore(trustedCertPaths, trustStorePath, truststorePassword);
122+
}
123+
124+
}

src/test/resources/docker-env/.env

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
REDIS_ENV_WORK_DIR=/tmp/redis-env-work

src/test/resources/docker-env/docker-compose.yml

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,7 @@ services:
77
- TLS_ENABLED=yes
88
volumes:
99
- ./redis-standalone-1/config:/redis/config:r
10+
- ${REDIS_ENV_WORK_DIR}/redis-standalone-1/work:/redis/work:rw
1011
ports:
1112
- "6479:6479"
1213
- "6443:6443" # TLS Port
@@ -52,10 +53,12 @@ services:
5253
container_name: redis-standalone-sentinel-controlled
5354
environment:
5455
- REDIS_CLUSTER=no
56+
- TLS_ENABLED=yes
5557
volumes:
5658
- ./redis-standalone-sentinel-controlled/config:/redis/config:r
5759
ports:
5860
- "26380:26380"
61+
- "26822:26822" # sentinel tls port
5962
- "26379:26379"
6063
- "6482:6482"
6164
- "6483:6483"

src/test/resources/docker-env/redis-standalone-sentinel-controlled/config/node-sentinel-26379/redis.conf

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,6 @@
11
port 26379
2+
tls-port 26822
3+
tls-auth-clients no
24
sentinel monitor mymaster localhost 6482 1
35
sentinel announce-hostnames yes
46
sentinel resolve-hostnames yes

0 commit comments

Comments
 (0)