Make SslStoreBundle implementations immutable

Closes gh-37222
This commit is contained in:
Moritz Halbritter
2023-09-11 12:01:18 +02:00
parent c298091e34
commit e2d84fa462
13 changed files with 185 additions and 86 deletions

View File

@@ -16,6 +16,9 @@
package org.springframework.boot.autoconfigure.ssl;
import java.security.Key;
import java.security.KeyStore;
import java.security.cert.Certificate;
import java.util.Set;
import org.junit.jupiter.api.Test;
@@ -28,36 +31,42 @@ import static org.assertj.core.api.Assertions.assertThat;
* Tests for {@link PropertiesSslBundle}.
*
* @author Scott Frederick
* @author Moritz Halbritter
*/
class PropertiesSslBundleTests {
@Test
void pemPropertiesAreMappedToSslBundle() {
void pemPropertiesAreMappedToSslBundle() throws Exception {
PemSslBundleProperties properties = new PemSslBundleProperties();
properties.getKey().setAlias("alias");
properties.getKey().setPassword("secret");
properties.getOptions().setCiphers(Set.of("cipher1", "cipher2", "cipher3"));
properties.getOptions().setEnabledProtocols(Set.of("protocol1", "protocol2"));
properties.getKeystore().setCertificate("cert1.pem");
properties.getKeystore().setPrivateKey("key1.pem");
properties.getKeystore().setPrivateKeyPassword("keysecret1");
properties.getKeystore().setCertificate("classpath:org/springframework/boot/autoconfigure/ssl/rsa-cert.pem");
properties.getKeystore().setPrivateKey("classpath:org/springframework/boot/autoconfigure/ssl/rsa-key.pem");
properties.getKeystore().setPrivateKeyPassword(null);
properties.getKeystore().setType("PKCS12");
properties.getTruststore().setCertificate("cert2.pem");
properties.getTruststore().setPrivateKey("key2.pem");
properties.getTruststore().setPrivateKeyPassword("keysecret2");
properties.getTruststore().setType("JKS");
properties.getTruststore()
.setCertificate("classpath:org/springframework/boot/autoconfigure/ssl/ed25519-cert.pem");
properties.getTruststore()
.setPrivateKey("classpath:org/springframework/boot/autoconfigure/ssl/ed25519-key.pem");
properties.getTruststore().setPrivateKeyPassword("secret");
properties.getTruststore().setType("PKCS12");
SslBundle sslBundle = PropertiesSslBundle.get(properties);
assertThat(sslBundle.getKey().getAlias()).isEqualTo("alias");
assertThat(sslBundle.getKey().getPassword()).isEqualTo("secret");
assertThat(sslBundle.getOptions().getCiphers()).containsExactlyInAnyOrder("cipher1", "cipher2", "cipher3");
assertThat(sslBundle.getOptions().getEnabledProtocols()).containsExactlyInAnyOrder("protocol1", "protocol2");
assertThat(sslBundle.getStores()).isNotNull();
assertThat(sslBundle.getStores()).extracting("keyStoreDetails")
.extracting("certificate", "privateKey", "privateKeyPassword", "type")
.containsExactly("cert1.pem", "key1.pem", "keysecret1", "PKCS12");
assertThat(sslBundle.getStores()).extracting("trustStoreDetails")
.extracting("certificate", "privateKey", "privateKeyPassword", "type")
.containsExactly("cert2.pem", "key2.pem", "keysecret2", "JKS");
Certificate certificate = sslBundle.getStores().getKeyStore().getCertificate("alias");
assertThat(certificate).isNotNull();
assertThat(certificate.getType()).isEqualTo("X.509");
Key key = sslBundle.getStores().getKeyStore().getKey("alias", null);
assertThat(key).isNotNull();
assertThat(key.getAlgorithm()).isEqualTo("RSA");
certificate = sslBundle.getStores().getTrustStore().getCertificate("alias");
assertThat(certificate).isNotNull();
assertThat(certificate.getType()).isEqualTo("X.509");
}
@Test
@@ -67,14 +76,14 @@ class PropertiesSslBundleTests {
properties.getKey().setPassword("secret");
properties.getOptions().setCiphers(Set.of("cipher1", "cipher2", "cipher3"));
properties.getOptions().setEnabledProtocols(Set.of("protocol1", "protocol2"));
properties.getKeystore().setLocation("cert1.p12");
properties.getKeystore().setPassword("secret1");
properties.getKeystore().setProvider("provider1");
properties.getKeystore().setPassword("secret");
properties.getKeystore().setProvider("SUN");
properties.getKeystore().setType("JKS");
properties.getTruststore().setLocation("cert2.jks");
properties.getTruststore().setPassword("secret2");
properties.getTruststore().setProvider("provider2");
properties.getKeystore().setLocation("classpath:org/springframework/boot/autoconfigure/ssl/keystore.jks");
properties.getTruststore().setPassword("secret");
properties.getTruststore().setProvider("SUN");
properties.getTruststore().setType("PKCS12");
properties.getTruststore().setLocation("classpath:org/springframework/boot/autoconfigure/ssl/keystore.pkcs12");
SslBundle sslBundle = PropertiesSslBundle.get(properties);
assertThat(sslBundle.getKey().getAlias()).isEqualTo("alias");
assertThat(sslBundle.getKey().getPassword()).isEqualTo("secret");
@@ -83,10 +92,11 @@ class PropertiesSslBundleTests {
assertThat(sslBundle.getStores()).isNotNull();
assertThat(sslBundle.getStores()).extracting("keyStoreDetails")
.extracting("location", "password", "provider", "type")
.containsExactly("cert1.p12", "secret1", "provider1", "JKS");
assertThat(sslBundle.getStores()).extracting("trustStoreDetails")
.extracting("location", "password", "provider", "type")
.containsExactly("cert2.jks", "secret2", "provider2", "PKCS12");
.containsExactly("classpath:org/springframework/boot/autoconfigure/ssl/keystore.jks", "secret", "SUN",
"JKS");
KeyStore trustStore = sslBundle.getStores().getTrustStore();
assertThat(trustStore.getType()).isEqualTo("PKCS12");
assertThat(trustStore.getProvider().getName()).isEqualTo("SUN");
}
}

View File

@@ -38,6 +38,7 @@ import static org.assertj.core.api.Assertions.assertThat;
*
* @author Scott Frederick
* @author Phillip Webb
* @author Moritz Halbritter
*/
class SslAutoConfigurationTests {
@@ -54,18 +55,28 @@ class SslAutoConfigurationTests {
List<String> propertyValues = new ArrayList<>();
propertyValues.add("spring.ssl.bundle.pem.first.key.alias=alias1");
propertyValues.add("spring.ssl.bundle.pem.first.key.password=secret1");
propertyValues.add("spring.ssl.bundle.pem.first.keystore.certificate=cert1.pem");
propertyValues.add("spring.ssl.bundle.pem.first.keystore.private-key=key1.pem");
propertyValues.add("spring.ssl.bundle.pem.first.keystore.type=JKS");
propertyValues.add(
"spring.ssl.bundle.pem.first.keystore.certificate=classpath:org/springframework/boot/autoconfigure/ssl/rsa-cert.pem");
propertyValues.add(
"spring.ssl.bundle.pem.first.keystore.private-key=classpath:org/springframework/boot/autoconfigure/ssl/rsa-key.pem");
propertyValues.add("spring.ssl.bundle.pem.first.keystore.type=PKCS12");
propertyValues.add("spring.ssl.bundle.pem.first.truststore.type=PKCS12");
propertyValues.add(
"spring.ssl.bundle.pem.first.truststore.certificate=classpath:org/springframework/boot/autoconfigure/ssl/rsa-cert.pem");
propertyValues.add(
"spring.ssl.bundle.pem.first.truststore.private-key=classpath:org/springframework/boot/autoconfigure/ssl/rsa-key.pem");
propertyValues.add("spring.ssl.bundle.pem.second.key.alias=alias2");
propertyValues.add("spring.ssl.bundle.pem.second.key.password=secret2");
propertyValues.add("spring.ssl.bundle.pem.second.keystore.certificate=cert2.pem");
propertyValues.add("spring.ssl.bundle.pem.second.keystore.private-key=key2.pem");
propertyValues.add(
"spring.ssl.bundle.pem.second.keystore.certificate=classpath:org/springframework/boot/autoconfigure/ssl/ed25519-cert.pem");
propertyValues.add(
"spring.ssl.bundle.pem.second.keystore.private-key=classpath:org/springframework/boot/autoconfigure/ssl/ed25519-key.pem");
propertyValues.add("spring.ssl.bundle.pem.second.keystore.type=PKCS12");
propertyValues.add("spring.ssl.bundle.pem.second.truststore.certificate=ca.pem");
propertyValues.add("spring.ssl.bundle.pem.second.truststore.private-key=ca-key.pem");
propertyValues.add("spring.ssl.bundle.pem.second.truststore.type=JKS");
propertyValues.add(
"spring.ssl.bundle.pem.second.truststore.certificate=classpath:org/springframework/boot/autoconfigure/ssl/ed25519-cert.pem");
propertyValues.add(
"spring.ssl.bundle.pem.second.truststore.private-key=classpath:org/springframework/boot/autoconfigure/ssl/ed25519-key.pem");
propertyValues.add("spring.ssl.bundle.pem.second.truststore.type=PKCS12");
this.contextRunner.withPropertyValues(propertyValues.toArray(String[]::new)).run((context) -> {
assertThat(context).hasSingleBean(SslBundles.class);
SslBundles bundles = context.getBean(SslBundles.class);
@@ -75,16 +86,16 @@ class SslAutoConfigurationTests {
assertThat(first.getManagers()).isNotNull();
assertThat(first.getKey().getAlias()).isEqualTo("alias1");
assertThat(first.getKey().getPassword()).isEqualTo("secret1");
assertThat(first.getStores()).extracting("keyStoreDetails").extracting("type").isEqualTo("JKS");
assertThat(first.getStores()).extracting("trustStoreDetails").extracting("type").isEqualTo("PKCS12");
assertThat(first.getStores().getKeyStore().getType()).isEqualTo("PKCS12");
assertThat(first.getStores().getTrustStore().getType()).isEqualTo("PKCS12");
SslBundle second = bundles.getBundle("second");
assertThat(second).isNotNull();
assertThat(second.getStores()).isNotNull();
assertThat(second.getManagers()).isNotNull();
assertThat(second.getKey().getAlias()).isEqualTo("alias2");
assertThat(second.getKey().getPassword()).isEqualTo("secret2");
assertThat(second.getStores()).extracting("keyStoreDetails").extracting("type").isEqualTo("PKCS12");
assertThat(second.getStores()).extracting("trustStoreDetails").extracting("type").isEqualTo("JKS");
assertThat(second.getStores().getKeyStore().getType()).isEqualTo("PKCS12");
assertThat(second.getStores().getTrustStore().getType()).isEqualTo("PKCS12");
});
}
@@ -93,7 +104,13 @@ class SslAutoConfigurationTests {
List<String> propertyValues = new ArrayList<>();
propertyValues.add("custom.ssl.key.alias=alias1");
propertyValues.add("custom.ssl.key.password=secret1");
propertyValues.add("custom.ssl.keystore.type=JKS");
propertyValues
.add("custom.ssl.keystore.certificate=classpath:org/springframework/boot/autoconfigure/ssl/rsa-cert.pem");
propertyValues.add(
"custom.ssl.keystore.keystore.private-key=classpath:org/springframework/boot/autoconfigure/ssl/rsa-key.pem");
propertyValues
.add("custom.ssl.truststore.certificate=classpath:org/springframework/boot/autoconfigure/ssl/rsa-cert.pem");
propertyValues.add("custom.ssl.keystore.type=PKCS12");
propertyValues.add("custom.ssl.truststore.type=PKCS12");
this.contextRunner.withUserConfiguration(CustomSslBundleConfiguration.class)
.withPropertyValues(propertyValues.toArray(String[]::new))
@@ -106,8 +123,8 @@ class SslAutoConfigurationTests {
assertThat(first.getManagers()).isNotNull();
assertThat(first.getKey().getAlias()).isEqualTo("alias1");
assertThat(first.getKey().getPassword()).isEqualTo("secret1");
assertThat(first.getStores()).extracting("keyStoreDetails").extracting("type").isEqualTo("JKS");
assertThat(first.getStores()).extracting("trustStoreDetails").extracting("type").isEqualTo("PKCS12");
assertThat(first.getStores().getKeyStore().getType()).isEqualTo("PKCS12");
assertThat(first.getStores().getTrustStore().getType()).isEqualTo("PKCS12");
});
}

View File

@@ -0,0 +1,13 @@
-----BEGIN CERTIFICATE-----
MIICCzCCAb2gAwIBAgIUZbDi7G5czH+Yi0k2EMWxdf00XagwBQYDK2VwMHsxCzAJ
BgNVBAYTAlhYMRIwEAYDVQQIDAlTdGF0ZU5hbWUxETAPBgNVBAcMCENpdHlOYW1l
MRQwEgYDVQQKDAtDb21wYW55TmFtZTEbMBkGA1UECwwSQ29tcGFueVNlY3Rpb25O
YW1lMRIwEAYDVQQDDAlsb2NhbGhvc3QwHhcNMjMwOTExMTIxNDMwWhcNMzMwOTA4
MTIxNDMwWjB7MQswCQYDVQQGEwJYWDESMBAGA1UECAwJU3RhdGVOYW1lMREwDwYD
VQQHDAhDaXR5TmFtZTEUMBIGA1UECgwLQ29tcGFueU5hbWUxGzAZBgNVBAsMEkNv
bXBhbnlTZWN0aW9uTmFtZTESMBAGA1UEAwwJbG9jYWxob3N0MCowBQYDK2VwAyEA
Q/DDA4BSgZ+Hx0DUxtIRjVjN+OcxXVURwAWc3Gt9GUyjUzBRMB0GA1UdDgQWBBSv
EdpoaBMBoxgO96GFbf03k07DSTAfBgNVHSMEGDAWgBSvEdpoaBMBoxgO96GFbf03
k07DSTAPBgNVHRMBAf8EBTADAQH/MAUGAytlcANBAHMXDkGd57d4F4cRk/8UjhxD
7OtRBZfdfznSvlhJIMNfH5q0zbC2eO3hWCB3Hrn/vIeswGP8Ov4AJ6eXeX44BQM=
-----END CERTIFICATE-----

View File

@@ -0,0 +1,3 @@
-----BEGIN PRIVATE KEY-----
MC4CAQAwBQYDK2VwBCIEIC29RnMVTcyqXEAIO1b/6p7RdbM6TiqvnztVQ4IxYxUh
-----END PRIVATE KEY-----

View File

@@ -0,0 +1,23 @@
-----BEGIN CERTIFICATE-----
MIID1zCCAr+gAwIBAgIUNM5QQv8IzVQsgSmmdPQNaqyzWs4wDQYJKoZIhvcNAQEL
BQAwezELMAkGA1UEBhMCWFgxEjAQBgNVBAgMCVN0YXRlTmFtZTERMA8GA1UEBwwI
Q2l0eU5hbWUxFDASBgNVBAoMC0NvbXBhbnlOYW1lMRswGQYDVQQLDBJDb21wYW55
U2VjdGlvbk5hbWUxEjAQBgNVBAMMCWxvY2FsaG9zdDAeFw0yMzA5MTExMjExNTha
Fw0zMzA5MDgxMjExNThaMHsxCzAJBgNVBAYTAlhYMRIwEAYDVQQIDAlTdGF0ZU5h
bWUxETAPBgNVBAcMCENpdHlOYW1lMRQwEgYDVQQKDAtDb21wYW55TmFtZTEbMBkG
A1UECwwSQ29tcGFueVNlY3Rpb25OYW1lMRIwEAYDVQQDDAlsb2NhbGhvc3QwggEi
MA0GCSqGSIb3DQEBAQUAA4IBDwAwggEKAoIBAQCfdkeEiCk+5mpXUhJ1FLmOCx6/
jAHHaDxZ8hIpyp/c4ZAqFX5uamP08jL056kRKL4RRoUamNWdt0dgpHqds/84pb+3
OlCVjnFvzGVrvRwdrrQA2mda0BDm2Qnb0r9IhZr7tBpursbDsIC1U6zk1iwrbiO3
hu0/9uXlMWt49nccTDOpTtuhYUPEA3+NQFqUCwHrd8H9j+BQD5lf4RhoE6krDdV1
JD8qOns+uD6IKn0xfyPHmy8LD0mM5Rch6J13TZnH1yeFT8Y0ZnAPuwXHO5BNw504
3Kt/das3NvV+4Qq0qQ08NFK+vmoooP11uIcZb8gUaMgmRINL4P3TOhyA1ueXAgMB
AAGjUzBRMB0GA1UdDgQWBBRHYz8OjqU/4JZMegJaN/jQbdj4MjAfBgNVHSMEGDAW
gBRHYz8OjqU/4JZMegJaN/jQbdj4MjAPBgNVHRMBAf8EBTADAQH/MA0GCSqGSIb3
DQEBCwUAA4IBAQBr9zqlNx7Mr1ordGfhk+xFrDtyBnk1vXbwVdnog66REqpPLH+K
MfCKdj6wFoPa8ZjPb4VYFp2DvMxVXtFMzqGfLjYJPqefEzQCleOcA5aiE/ENIaaD
ybYh99V5CsFAqyKuHLBFEzeYJ028SR3QsCISom0k/Fh6y2IwHJJEHykjqJKvL4bb
V0IJjcmYjEZbTvpjFKznvaFiOUv+8L7jHQ1/Yf+9c3C8gSjdUfv88m17pqYXd+Ds
HEmfmNNjht130UyjNCITmLVXyy5p35vWmdf95U3uEbJSnNVtXH8qRmN9oK9mUpDb
ngX6JBJI7fw7tXoqWSLHNiBODM88fUlQSho8
-----END CERTIFICATE-----

View File

@@ -0,0 +1,28 @@
-----BEGIN PRIVATE KEY-----
MIIEvAIBADANBgkqhkiG9w0BAQEFAASCBKYwggSiAgEAAoIBAQCfdkeEiCk+5mpX
UhJ1FLmOCx6/jAHHaDxZ8hIpyp/c4ZAqFX5uamP08jL056kRKL4RRoUamNWdt0dg
pHqds/84pb+3OlCVjnFvzGVrvRwdrrQA2mda0BDm2Qnb0r9IhZr7tBpursbDsIC1
U6zk1iwrbiO3hu0/9uXlMWt49nccTDOpTtuhYUPEA3+NQFqUCwHrd8H9j+BQD5lf
4RhoE6krDdV1JD8qOns+uD6IKn0xfyPHmy8LD0mM5Rch6J13TZnH1yeFT8Y0ZnAP
uwXHO5BNw5043Kt/das3NvV+4Qq0qQ08NFK+vmoooP11uIcZb8gUaMgmRINL4P3T
OhyA1ueXAgMBAAECggEAPK1LqmULWMlhdoeeyVlQ//lAQn+6X4/MwycG/UsCSJC2
BCV4nfgyv853UFRkM0jPBhDQ7h1wz1ohuWbs11xaBcqgKE7ywe3ZQULD5tqnO64y
BU8V2+rnO4gjpbdMHQLlxdgy5KHxtR3Q4+6Kj+rlFMOMqLWZSmke8na7H+SczzGf
+dZO4LRTbjGmFdUidehovm2icSM8OdU2w3FHlFRu2NBsTHGeAhRw86Yw24KfJp4R
GSDQIBdwp1wCs5w7w4zPjxS7Zi+Uwspyq31KDJwyfK2O1WLI05bQ6FLqVRD/xy+Y
b4WCse1O08SYWze2No915LB07sokgmomr3//bOwuEQKBgQDPBrPQXokn0BoTlgsa
JohgWzQ5P9u/2WY+u2SG/xgNEx0s+lk/AmAH80wsBJ68FV6z5Non7TzD7xCsf2HJ
3cP/EHl2ngTctz/eqpCcS5UPZBHmay60q6WKIkH/3ml7c0UhlqSqS3EDVyEe05hk
msWAN+fV4ajVlhWgiUZRVdxMpwKBgQDFLyPBOEn6zLOHfkQWcibVf8s2LTe76R/S
8Gk3jbk5mimR3vNm0L/rHqGwl75rOuFiFOHVkfuY9Dawaht0QnagjayT5hDqr6aD
s5Chyoy9qpXnfnqOgk6rQZqj+/ODkjqEkBdRCKWvCVnDIi3Au2kS3QIc4iTsGrBW
ygZdbxM7kQKBgEuzS7T5nHVuZtqaltytElkJgIMekqAIQpbVtuCWDplZT+XOdSvR
FoRRtpyx48kql0J4gDzxRrLui85Hld5WtQBjacax6V07tKMbA13jVVIXaWQz9RQj
X5ivBisljLSTZcfuaa/LfjuWdIntHWBMJ8PGrYNLzIytIKNfDtNW7gMpAoGAIRZQ
5JpCZ7Azq9e3KyEKfSbNfZDG2mQ679Vhgm3ol87TjOOhai47FgP008IStMGTkja4
0nKFilvoVV/orXB9oWFEhSjEy+yff1gBO/TV+vmF3+tsOz+IXdpLTZr4eKpv4VCg
aPuPebiS9Fhm3wFTl1O4iAo2cdvknRuXR9RcoNECgYADksGk1lJGW5kMIMJ+6os+
CJdGnJiX7XsnM0VzkagswnqDe03SqkJuFOmIp96eitxLT4EfB+585pYQRSy2fyJX
WR2AAnC7oqUcQFkgDt9WBZAazI6aLXYO+trRoGKuWynGM8mjetr5C75g0auj4lsN
rGiie2UnjshJ67FrG4kZoA==
-----END PRIVATE KEY-----