Make SslStoreBundle implementations immutable
Closes gh-37222
This commit is contained in:
@@ -16,6 +16,9 @@
|
|||||||
|
|
||||||
package org.springframework.boot.autoconfigure.ssl;
|
package org.springframework.boot.autoconfigure.ssl;
|
||||||
|
|
||||||
|
import java.security.Key;
|
||||||
|
import java.security.KeyStore;
|
||||||
|
import java.security.cert.Certificate;
|
||||||
import java.util.Set;
|
import java.util.Set;
|
||||||
|
|
||||||
import org.junit.jupiter.api.Test;
|
import org.junit.jupiter.api.Test;
|
||||||
@@ -28,36 +31,42 @@ import static org.assertj.core.api.Assertions.assertThat;
|
|||||||
* Tests for {@link PropertiesSslBundle}.
|
* Tests for {@link PropertiesSslBundle}.
|
||||||
*
|
*
|
||||||
* @author Scott Frederick
|
* @author Scott Frederick
|
||||||
|
* @author Moritz Halbritter
|
||||||
*/
|
*/
|
||||||
class PropertiesSslBundleTests {
|
class PropertiesSslBundleTests {
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
void pemPropertiesAreMappedToSslBundle() {
|
void pemPropertiesAreMappedToSslBundle() throws Exception {
|
||||||
PemSslBundleProperties properties = new PemSslBundleProperties();
|
PemSslBundleProperties properties = new PemSslBundleProperties();
|
||||||
properties.getKey().setAlias("alias");
|
properties.getKey().setAlias("alias");
|
||||||
properties.getKey().setPassword("secret");
|
properties.getKey().setPassword("secret");
|
||||||
properties.getOptions().setCiphers(Set.of("cipher1", "cipher2", "cipher3"));
|
properties.getOptions().setCiphers(Set.of("cipher1", "cipher2", "cipher3"));
|
||||||
properties.getOptions().setEnabledProtocols(Set.of("protocol1", "protocol2"));
|
properties.getOptions().setEnabledProtocols(Set.of("protocol1", "protocol2"));
|
||||||
properties.getKeystore().setCertificate("cert1.pem");
|
properties.getKeystore().setCertificate("classpath:org/springframework/boot/autoconfigure/ssl/rsa-cert.pem");
|
||||||
properties.getKeystore().setPrivateKey("key1.pem");
|
properties.getKeystore().setPrivateKey("classpath:org/springframework/boot/autoconfigure/ssl/rsa-key.pem");
|
||||||
properties.getKeystore().setPrivateKeyPassword("keysecret1");
|
properties.getKeystore().setPrivateKeyPassword(null);
|
||||||
properties.getKeystore().setType("PKCS12");
|
properties.getKeystore().setType("PKCS12");
|
||||||
properties.getTruststore().setCertificate("cert2.pem");
|
properties.getTruststore()
|
||||||
properties.getTruststore().setPrivateKey("key2.pem");
|
.setCertificate("classpath:org/springframework/boot/autoconfigure/ssl/ed25519-cert.pem");
|
||||||
properties.getTruststore().setPrivateKeyPassword("keysecret2");
|
properties.getTruststore()
|
||||||
properties.getTruststore().setType("JKS");
|
.setPrivateKey("classpath:org/springframework/boot/autoconfigure/ssl/ed25519-key.pem");
|
||||||
|
properties.getTruststore().setPrivateKeyPassword("secret");
|
||||||
|
properties.getTruststore().setType("PKCS12");
|
||||||
SslBundle sslBundle = PropertiesSslBundle.get(properties);
|
SslBundle sslBundle = PropertiesSslBundle.get(properties);
|
||||||
assertThat(sslBundle.getKey().getAlias()).isEqualTo("alias");
|
assertThat(sslBundle.getKey().getAlias()).isEqualTo("alias");
|
||||||
assertThat(sslBundle.getKey().getPassword()).isEqualTo("secret");
|
assertThat(sslBundle.getKey().getPassword()).isEqualTo("secret");
|
||||||
assertThat(sslBundle.getOptions().getCiphers()).containsExactlyInAnyOrder("cipher1", "cipher2", "cipher3");
|
assertThat(sslBundle.getOptions().getCiphers()).containsExactlyInAnyOrder("cipher1", "cipher2", "cipher3");
|
||||||
assertThat(sslBundle.getOptions().getEnabledProtocols()).containsExactlyInAnyOrder("protocol1", "protocol2");
|
assertThat(sslBundle.getOptions().getEnabledProtocols()).containsExactlyInAnyOrder("protocol1", "protocol2");
|
||||||
assertThat(sslBundle.getStores()).isNotNull();
|
assertThat(sslBundle.getStores()).isNotNull();
|
||||||
assertThat(sslBundle.getStores()).extracting("keyStoreDetails")
|
Certificate certificate = sslBundle.getStores().getKeyStore().getCertificate("alias");
|
||||||
.extracting("certificate", "privateKey", "privateKeyPassword", "type")
|
assertThat(certificate).isNotNull();
|
||||||
.containsExactly("cert1.pem", "key1.pem", "keysecret1", "PKCS12");
|
assertThat(certificate.getType()).isEqualTo("X.509");
|
||||||
assertThat(sslBundle.getStores()).extracting("trustStoreDetails")
|
Key key = sslBundle.getStores().getKeyStore().getKey("alias", null);
|
||||||
.extracting("certificate", "privateKey", "privateKeyPassword", "type")
|
assertThat(key).isNotNull();
|
||||||
.containsExactly("cert2.pem", "key2.pem", "keysecret2", "JKS");
|
assertThat(key.getAlgorithm()).isEqualTo("RSA");
|
||||||
|
certificate = sslBundle.getStores().getTrustStore().getCertificate("alias");
|
||||||
|
assertThat(certificate).isNotNull();
|
||||||
|
assertThat(certificate.getType()).isEqualTo("X.509");
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
@@ -67,14 +76,14 @@ class PropertiesSslBundleTests {
|
|||||||
properties.getKey().setPassword("secret");
|
properties.getKey().setPassword("secret");
|
||||||
properties.getOptions().setCiphers(Set.of("cipher1", "cipher2", "cipher3"));
|
properties.getOptions().setCiphers(Set.of("cipher1", "cipher2", "cipher3"));
|
||||||
properties.getOptions().setEnabledProtocols(Set.of("protocol1", "protocol2"));
|
properties.getOptions().setEnabledProtocols(Set.of("protocol1", "protocol2"));
|
||||||
properties.getKeystore().setLocation("cert1.p12");
|
properties.getKeystore().setPassword("secret");
|
||||||
properties.getKeystore().setPassword("secret1");
|
properties.getKeystore().setProvider("SUN");
|
||||||
properties.getKeystore().setProvider("provider1");
|
|
||||||
properties.getKeystore().setType("JKS");
|
properties.getKeystore().setType("JKS");
|
||||||
properties.getTruststore().setLocation("cert2.jks");
|
properties.getKeystore().setLocation("classpath:org/springframework/boot/autoconfigure/ssl/keystore.jks");
|
||||||
properties.getTruststore().setPassword("secret2");
|
properties.getTruststore().setPassword("secret");
|
||||||
properties.getTruststore().setProvider("provider2");
|
properties.getTruststore().setProvider("SUN");
|
||||||
properties.getTruststore().setType("PKCS12");
|
properties.getTruststore().setType("PKCS12");
|
||||||
|
properties.getTruststore().setLocation("classpath:org/springframework/boot/autoconfigure/ssl/keystore.pkcs12");
|
||||||
SslBundle sslBundle = PropertiesSslBundle.get(properties);
|
SslBundle sslBundle = PropertiesSslBundle.get(properties);
|
||||||
assertThat(sslBundle.getKey().getAlias()).isEqualTo("alias");
|
assertThat(sslBundle.getKey().getAlias()).isEqualTo("alias");
|
||||||
assertThat(sslBundle.getKey().getPassword()).isEqualTo("secret");
|
assertThat(sslBundle.getKey().getPassword()).isEqualTo("secret");
|
||||||
@@ -83,10 +92,11 @@ class PropertiesSslBundleTests {
|
|||||||
assertThat(sslBundle.getStores()).isNotNull();
|
assertThat(sslBundle.getStores()).isNotNull();
|
||||||
assertThat(sslBundle.getStores()).extracting("keyStoreDetails")
|
assertThat(sslBundle.getStores()).extracting("keyStoreDetails")
|
||||||
.extracting("location", "password", "provider", "type")
|
.extracting("location", "password", "provider", "type")
|
||||||
.containsExactly("cert1.p12", "secret1", "provider1", "JKS");
|
.containsExactly("classpath:org/springframework/boot/autoconfigure/ssl/keystore.jks", "secret", "SUN",
|
||||||
assertThat(sslBundle.getStores()).extracting("trustStoreDetails")
|
"JKS");
|
||||||
.extracting("location", "password", "provider", "type")
|
KeyStore trustStore = sslBundle.getStores().getTrustStore();
|
||||||
.containsExactly("cert2.jks", "secret2", "provider2", "PKCS12");
|
assertThat(trustStore.getType()).isEqualTo("PKCS12");
|
||||||
|
assertThat(trustStore.getProvider().getName()).isEqualTo("SUN");
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -38,6 +38,7 @@ import static org.assertj.core.api.Assertions.assertThat;
|
|||||||
*
|
*
|
||||||
* @author Scott Frederick
|
* @author Scott Frederick
|
||||||
* @author Phillip Webb
|
* @author Phillip Webb
|
||||||
|
* @author Moritz Halbritter
|
||||||
*/
|
*/
|
||||||
class SslAutoConfigurationTests {
|
class SslAutoConfigurationTests {
|
||||||
|
|
||||||
@@ -54,18 +55,28 @@ class SslAutoConfigurationTests {
|
|||||||
List<String> propertyValues = new ArrayList<>();
|
List<String> propertyValues = new ArrayList<>();
|
||||||
propertyValues.add("spring.ssl.bundle.pem.first.key.alias=alias1");
|
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.key.password=secret1");
|
||||||
propertyValues.add("spring.ssl.bundle.pem.first.keystore.certificate=cert1.pem");
|
propertyValues.add(
|
||||||
propertyValues.add("spring.ssl.bundle.pem.first.keystore.private-key=key1.pem");
|
"spring.ssl.bundle.pem.first.keystore.certificate=classpath:org/springframework/boot/autoconfigure/ssl/rsa-cert.pem");
|
||||||
propertyValues.add("spring.ssl.bundle.pem.first.keystore.type=JKS");
|
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.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.alias=alias2");
|
||||||
propertyValues.add("spring.ssl.bundle.pem.second.key.password=secret2");
|
propertyValues.add("spring.ssl.bundle.pem.second.key.password=secret2");
|
||||||
propertyValues.add("spring.ssl.bundle.pem.second.keystore.certificate=cert2.pem");
|
propertyValues.add(
|
||||||
propertyValues.add("spring.ssl.bundle.pem.second.keystore.private-key=key2.pem");
|
"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.keystore.type=PKCS12");
|
||||||
propertyValues.add("spring.ssl.bundle.pem.second.truststore.certificate=ca.pem");
|
propertyValues.add(
|
||||||
propertyValues.add("spring.ssl.bundle.pem.second.truststore.private-key=ca-key.pem");
|
"spring.ssl.bundle.pem.second.truststore.certificate=classpath:org/springframework/boot/autoconfigure/ssl/ed25519-cert.pem");
|
||||||
propertyValues.add("spring.ssl.bundle.pem.second.truststore.type=JKS");
|
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) -> {
|
this.contextRunner.withPropertyValues(propertyValues.toArray(String[]::new)).run((context) -> {
|
||||||
assertThat(context).hasSingleBean(SslBundles.class);
|
assertThat(context).hasSingleBean(SslBundles.class);
|
||||||
SslBundles bundles = context.getBean(SslBundles.class);
|
SslBundles bundles = context.getBean(SslBundles.class);
|
||||||
@@ -75,16 +86,16 @@ class SslAutoConfigurationTests {
|
|||||||
assertThat(first.getManagers()).isNotNull();
|
assertThat(first.getManagers()).isNotNull();
|
||||||
assertThat(first.getKey().getAlias()).isEqualTo("alias1");
|
assertThat(first.getKey().getAlias()).isEqualTo("alias1");
|
||||||
assertThat(first.getKey().getPassword()).isEqualTo("secret1");
|
assertThat(first.getKey().getPassword()).isEqualTo("secret1");
|
||||||
assertThat(first.getStores()).extracting("keyStoreDetails").extracting("type").isEqualTo("JKS");
|
assertThat(first.getStores().getKeyStore().getType()).isEqualTo("PKCS12");
|
||||||
assertThat(first.getStores()).extracting("trustStoreDetails").extracting("type").isEqualTo("PKCS12");
|
assertThat(first.getStores().getTrustStore().getType()).isEqualTo("PKCS12");
|
||||||
SslBundle second = bundles.getBundle("second");
|
SslBundle second = bundles.getBundle("second");
|
||||||
assertThat(second).isNotNull();
|
assertThat(second).isNotNull();
|
||||||
assertThat(second.getStores()).isNotNull();
|
assertThat(second.getStores()).isNotNull();
|
||||||
assertThat(second.getManagers()).isNotNull();
|
assertThat(second.getManagers()).isNotNull();
|
||||||
assertThat(second.getKey().getAlias()).isEqualTo("alias2");
|
assertThat(second.getKey().getAlias()).isEqualTo("alias2");
|
||||||
assertThat(second.getKey().getPassword()).isEqualTo("secret2");
|
assertThat(second.getKey().getPassword()).isEqualTo("secret2");
|
||||||
assertThat(second.getStores()).extracting("keyStoreDetails").extracting("type").isEqualTo("PKCS12");
|
assertThat(second.getStores().getKeyStore().getType()).isEqualTo("PKCS12");
|
||||||
assertThat(second.getStores()).extracting("trustStoreDetails").extracting("type").isEqualTo("JKS");
|
assertThat(second.getStores().getTrustStore().getType()).isEqualTo("PKCS12");
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -93,7 +104,13 @@ class SslAutoConfigurationTests {
|
|||||||
List<String> propertyValues = new ArrayList<>();
|
List<String> propertyValues = new ArrayList<>();
|
||||||
propertyValues.add("custom.ssl.key.alias=alias1");
|
propertyValues.add("custom.ssl.key.alias=alias1");
|
||||||
propertyValues.add("custom.ssl.key.password=secret1");
|
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");
|
propertyValues.add("custom.ssl.truststore.type=PKCS12");
|
||||||
this.contextRunner.withUserConfiguration(CustomSslBundleConfiguration.class)
|
this.contextRunner.withUserConfiguration(CustomSslBundleConfiguration.class)
|
||||||
.withPropertyValues(propertyValues.toArray(String[]::new))
|
.withPropertyValues(propertyValues.toArray(String[]::new))
|
||||||
@@ -106,8 +123,8 @@ class SslAutoConfigurationTests {
|
|||||||
assertThat(first.getManagers()).isNotNull();
|
assertThat(first.getManagers()).isNotNull();
|
||||||
assertThat(first.getKey().getAlias()).isEqualTo("alias1");
|
assertThat(first.getKey().getAlias()).isEqualTo("alias1");
|
||||||
assertThat(first.getKey().getPassword()).isEqualTo("secret1");
|
assertThat(first.getKey().getPassword()).isEqualTo("secret1");
|
||||||
assertThat(first.getStores()).extracting("keyStoreDetails").extracting("type").isEqualTo("JKS");
|
assertThat(first.getStores().getKeyStore().getType()).isEqualTo("PKCS12");
|
||||||
assertThat(first.getStores()).extracting("trustStoreDetails").extracting("type").isEqualTo("PKCS12");
|
assertThat(first.getStores().getTrustStore().getType()).isEqualTo("PKCS12");
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -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-----
|
||||||
@@ -0,0 +1,3 @@
|
|||||||
|
-----BEGIN PRIVATE KEY-----
|
||||||
|
MC4CAQAwBQYDK2VwBCIEIC29RnMVTcyqXEAIO1b/6p7RdbM6TiqvnztVQ4IxYxUh
|
||||||
|
-----END PRIVATE KEY-----
|
||||||
Binary file not shown.
Binary file not shown.
@@ -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-----
|
||||||
@@ -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-----
|
||||||
@@ -35,13 +35,16 @@ import org.springframework.util.StringUtils;
|
|||||||
*
|
*
|
||||||
* @author Scott Frederick
|
* @author Scott Frederick
|
||||||
* @author Phillip Webb
|
* @author Phillip Webb
|
||||||
|
* @author Moritz Halbritter
|
||||||
* @since 3.1.0
|
* @since 3.1.0
|
||||||
*/
|
*/
|
||||||
public class JksSslStoreBundle implements SslStoreBundle {
|
public class JksSslStoreBundle implements SslStoreBundle {
|
||||||
|
|
||||||
private final JksSslStoreDetails keyStoreDetails;
|
private final JksSslStoreDetails keyStoreDetails;
|
||||||
|
|
||||||
private final JksSslStoreDetails trustStoreDetails;
|
private final KeyStore keyStore;
|
||||||
|
|
||||||
|
private final KeyStore trustStore;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Create a new {@link JksSslStoreBundle} instance.
|
* Create a new {@link JksSslStoreBundle} instance.
|
||||||
@@ -50,12 +53,13 @@ public class JksSslStoreBundle implements SslStoreBundle {
|
|||||||
*/
|
*/
|
||||||
public JksSslStoreBundle(JksSslStoreDetails keyStoreDetails, JksSslStoreDetails trustStoreDetails) {
|
public JksSslStoreBundle(JksSslStoreDetails keyStoreDetails, JksSslStoreDetails trustStoreDetails) {
|
||||||
this.keyStoreDetails = keyStoreDetails;
|
this.keyStoreDetails = keyStoreDetails;
|
||||||
this.trustStoreDetails = trustStoreDetails;
|
this.keyStore = createKeyStore("key", this.keyStoreDetails);
|
||||||
|
this.trustStore = createKeyStore("trust", trustStoreDetails);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public KeyStore getKeyStore() {
|
public KeyStore getKeyStore() {
|
||||||
return createKeyStore("key", this.keyStoreDetails);
|
return this.keyStore;
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
@@ -65,7 +69,7 @@ public class JksSslStoreBundle implements SslStoreBundle {
|
|||||||
|
|
||||||
@Override
|
@Override
|
||||||
public KeyStore getTrustStore() {
|
public KeyStore getTrustStore() {
|
||||||
return createKeyStore("trust", this.trustStoreDetails);
|
return this.trustStore;
|
||||||
}
|
}
|
||||||
|
|
||||||
private KeyStore createKeyStore(String name, JksSslStoreDetails details) {
|
private KeyStore createKeyStore(String name, JksSslStoreDetails details) {
|
||||||
|
|||||||
@@ -30,17 +30,16 @@ import org.springframework.util.StringUtils;
|
|||||||
*
|
*
|
||||||
* @author Scott Frederick
|
* @author Scott Frederick
|
||||||
* @author Phillip Webb
|
* @author Phillip Webb
|
||||||
|
* @author Moritz Halbritter
|
||||||
* @since 3.1.0
|
* @since 3.1.0
|
||||||
*/
|
*/
|
||||||
public class PemSslStoreBundle implements SslStoreBundle {
|
public class PemSslStoreBundle implements SslStoreBundle {
|
||||||
|
|
||||||
private static final String DEFAULT_KEY_ALIAS = "ssl";
|
private static final String DEFAULT_KEY_ALIAS = "ssl";
|
||||||
|
|
||||||
private final PemSslStoreDetails keyStoreDetails;
|
private final KeyStore keyStore;
|
||||||
|
|
||||||
private final PemSslStoreDetails trustStoreDetails;
|
private final KeyStore trustStore;
|
||||||
|
|
||||||
private final String keyAlias;
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Create a new {@link PemSslStoreBundle} instance.
|
* Create a new {@link PemSslStoreBundle} instance.
|
||||||
@@ -59,14 +58,13 @@ public class PemSslStoreBundle implements SslStoreBundle {
|
|||||||
*/
|
*/
|
||||||
public PemSslStoreBundle(PemSslStoreDetails keyStoreDetails, PemSslStoreDetails trustStoreDetails,
|
public PemSslStoreBundle(PemSslStoreDetails keyStoreDetails, PemSslStoreDetails trustStoreDetails,
|
||||||
String keyAlias) {
|
String keyAlias) {
|
||||||
this.keyAlias = keyAlias;
|
this.keyStore = createKeyStore("key", keyStoreDetails, keyAlias);
|
||||||
this.keyStoreDetails = keyStoreDetails;
|
this.trustStore = createKeyStore("trust", trustStoreDetails, keyAlias);
|
||||||
this.trustStoreDetails = trustStoreDetails;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public KeyStore getKeyStore() {
|
public KeyStore getKeyStore() {
|
||||||
return createKeyStore("key", this.keyStoreDetails);
|
return this.keyStore;
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
@@ -76,10 +74,10 @@ public class PemSslStoreBundle implements SslStoreBundle {
|
|||||||
|
|
||||||
@Override
|
@Override
|
||||||
public KeyStore getTrustStore() {
|
public KeyStore getTrustStore() {
|
||||||
return createKeyStore("trust", this.trustStoreDetails);
|
return this.trustStore;
|
||||||
}
|
}
|
||||||
|
|
||||||
private KeyStore createKeyStore(String name, PemSslStoreDetails details) {
|
private KeyStore createKeyStore(String name, PemSslStoreDetails details, String alias) {
|
||||||
if (details == null || details.isEmpty()) {
|
if (details == null || details.isEmpty()) {
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
@@ -92,7 +90,7 @@ public class PemSslStoreBundle implements SslStoreBundle {
|
|||||||
String privateKeyContent = PemContent.load(details.privateKey());
|
String privateKeyContent = PemContent.load(details.privateKey());
|
||||||
X509Certificate[] certificates = PemCertificateParser.parse(certificateContent);
|
X509Certificate[] certificates = PemCertificateParser.parse(certificateContent);
|
||||||
PrivateKey privateKey = PemPrivateKeyParser.parse(privateKeyContent, details.privateKeyPassword());
|
PrivateKey privateKey = PemPrivateKeyParser.parse(privateKeyContent, details.privateKeyPassword());
|
||||||
addCertificates(store, certificates, privateKey);
|
addCertificates(store, certificates, privateKey, (alias != null) ? alias : DEFAULT_KEY_ALIAS);
|
||||||
return store;
|
return store;
|
||||||
}
|
}
|
||||||
catch (Exception ex) {
|
catch (Exception ex) {
|
||||||
@@ -100,9 +98,8 @@ public class PemSslStoreBundle implements SslStoreBundle {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private void addCertificates(KeyStore keyStore, X509Certificate[] certificates, PrivateKey privateKey)
|
private void addCertificates(KeyStore keyStore, X509Certificate[] certificates, PrivateKey privateKey, String alias)
|
||||||
throws KeyStoreException {
|
throws KeyStoreException {
|
||||||
String alias = (this.keyAlias != null) ? this.keyAlias : DEFAULT_KEY_ALIAS;
|
|
||||||
if (privateKey != null) {
|
if (privateKey != null) {
|
||||||
keyStore.setKeyEntry(alias, privateKey, null, certificates);
|
keyStore.setKeyEntry(alias, privateKey, null, certificates);
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -32,6 +32,7 @@ import static org.assertj.core.api.Assertions.assertThatIllegalStateException;
|
|||||||
*
|
*
|
||||||
* @author Scott Frederick
|
* @author Scott Frederick
|
||||||
* @author Phillip Webb
|
* @author Phillip Webb
|
||||||
|
* @author Moritz Halbritter
|
||||||
*/
|
*/
|
||||||
@MockPkcs11Security
|
@MockPkcs11Security
|
||||||
class JksSslStoreBundleTests {
|
class JksSslStoreBundleTests {
|
||||||
@@ -58,10 +59,11 @@ class JksSslStoreBundleTests {
|
|||||||
|
|
||||||
@Test
|
@Test
|
||||||
void whenTypePKCS11AndLocationThrowsException() {
|
void whenTypePKCS11AndLocationThrowsException() {
|
||||||
JksSslStoreDetails keyStoreDetails = new JksSslStoreDetails("PKCS11", null, "test.jks", null);
|
assertThatIllegalStateException().isThrownBy(() -> {
|
||||||
JksSslStoreDetails trustStoreDetails = null;
|
JksSslStoreDetails keyStoreDetails = new JksSslStoreDetails("PKCS11", null, "test.jks", null);
|
||||||
JksSslStoreBundle bundle = new JksSslStoreBundle(keyStoreDetails, trustStoreDetails);
|
JksSslStoreDetails trustStoreDetails = null;
|
||||||
assertThatIllegalStateException().isThrownBy(bundle::getKeyStore)
|
new JksSslStoreBundle(keyStoreDetails, trustStoreDetails);
|
||||||
|
})
|
||||||
.withMessageContaining(
|
.withMessageContaining(
|
||||||
"Unable to create key store: Location is 'test.jks', but must be empty or null for PKCS11 hardware key stores");
|
"Unable to create key store: Location is 'test.jks', but must be empty or null for PKCS11 hardware key stores");
|
||||||
}
|
}
|
||||||
@@ -102,22 +104,22 @@ class JksSslStoreBundleTests {
|
|||||||
|
|
||||||
@Test
|
@Test
|
||||||
void whenHasKeyStoreProvider() {
|
void whenHasKeyStoreProvider() {
|
||||||
JksSslStoreDetails keyStoreDetails = new JksSslStoreDetails(null, "com.example.KeyStoreProvider",
|
assertThatIllegalStateException().isThrownBy(() -> {
|
||||||
"classpath:test.jks", "secret");
|
JksSslStoreDetails keyStoreDetails = new JksSslStoreDetails(null, "com.example.KeyStoreProvider",
|
||||||
JksSslStoreDetails trustStoreDetails = null;
|
"classpath:test.jks", "secret");
|
||||||
JksSslStoreBundle bundle = new JksSslStoreBundle(keyStoreDetails, trustStoreDetails);
|
JksSslStoreDetails trustStoreDetails = null;
|
||||||
assertThatIllegalStateException().isThrownBy(bundle::getKeyStore)
|
new JksSslStoreBundle(keyStoreDetails, trustStoreDetails);
|
||||||
.withMessageContaining("com.example.KeyStoreProvider");
|
}).withMessageContaining("com.example.KeyStoreProvider");
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
void whenHasTrustStoreProvider() {
|
void whenHasTrustStoreProvider() {
|
||||||
JksSslStoreDetails keyStoreDetails = null;
|
assertThatIllegalStateException().isThrownBy(() -> {
|
||||||
JksSslStoreDetails trustStoreDetails = new JksSslStoreDetails(null, "com.example.KeyStoreProvider",
|
JksSslStoreDetails keyStoreDetails = null;
|
||||||
"classpath:test.jks", "secret");
|
JksSslStoreDetails trustStoreDetails = new JksSslStoreDetails(null, "com.example.KeyStoreProvider",
|
||||||
JksSslStoreBundle bundle = new JksSslStoreBundle(keyStoreDetails, trustStoreDetails);
|
"classpath:test.jks", "secret");
|
||||||
assertThatIllegalStateException().isThrownBy(bundle::getTrustStore)
|
new JksSslStoreBundle(keyStoreDetails, trustStoreDetails);
|
||||||
.withMessageContaining("com.example.KeyStoreProvider");
|
}).withMessageContaining("com.example.KeyStoreProvider");
|
||||||
}
|
}
|
||||||
|
|
||||||
private Consumer<KeyStore> storeContainingCertAndKey(String keyAlias, String keyPassword) {
|
private Consumer<KeyStore> storeContainingCertAndKey(String keyAlias, String keyPassword) {
|
||||||
|
|||||||
@@ -67,14 +67,12 @@ class SslConnectorCustomizerTests {
|
|||||||
|
|
||||||
private Tomcat tomcat;
|
private Tomcat tomcat;
|
||||||
|
|
||||||
private Connector connector;
|
|
||||||
|
|
||||||
@BeforeEach
|
@BeforeEach
|
||||||
void setup() {
|
void setup() {
|
||||||
this.tomcat = new Tomcat();
|
this.tomcat = new Tomcat();
|
||||||
this.connector = new Connector("org.apache.coyote.http11.Http11NioProtocol");
|
Connector connector = new Connector("org.apache.coyote.http11.Http11NioProtocol");
|
||||||
this.connector.setPort(0);
|
connector.setPort(0);
|
||||||
this.tomcat.setConnector(this.connector);
|
this.tomcat.setConnector(connector);
|
||||||
}
|
}
|
||||||
|
|
||||||
@AfterEach
|
@AfterEach
|
||||||
@@ -207,10 +205,11 @@ class SslConnectorCustomizerTests {
|
|||||||
ssl.setKeyStoreProvider(MockPkcs11SecurityProvider.NAME);
|
ssl.setKeyStoreProvider(MockPkcs11SecurityProvider.NAME);
|
||||||
ssl.setKeyStore("src/test/resources/test.jks");
|
ssl.setKeyStore("src/test/resources/test.jks");
|
||||||
ssl.setKeyPassword("password");
|
ssl.setKeyPassword("password");
|
||||||
SslConnectorCustomizer customizer = new SslConnectorCustomizer(ssl.getClientAuth(),
|
assertThatIllegalStateException().isThrownBy(() -> {
|
||||||
WebServerSslBundle.get(ssl));
|
SslConnectorCustomizer customizer = new SslConnectorCustomizer(ssl.getClientAuth(),
|
||||||
assertThatIllegalStateException().isThrownBy(() -> customizer.customize(this.tomcat.getConnector()))
|
WebServerSslBundle.get(ssl));
|
||||||
.withMessageContaining("must be empty or null for PKCS11 hardware key stores");
|
customizer.customize(this.tomcat.getConnector());
|
||||||
|
}).withMessageContaining("must be empty or null for PKCS11 hardware key stores");
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
|
|||||||
@@ -25,6 +25,8 @@ import org.springframework.boot.ssl.SslBundle;
|
|||||||
import org.springframework.boot.ssl.SslBundleKey;
|
import org.springframework.boot.ssl.SslBundleKey;
|
||||||
import org.springframework.boot.ssl.SslOptions;
|
import org.springframework.boot.ssl.SslOptions;
|
||||||
import org.springframework.boot.ssl.SslStoreBundle;
|
import org.springframework.boot.ssl.SslStoreBundle;
|
||||||
|
import org.springframework.boot.web.embedded.test.MockPkcs11Security;
|
||||||
|
import org.springframework.boot.web.embedded.test.MockPkcs11SecurityProvider;
|
||||||
import org.springframework.core.io.ClassPathResource;
|
import org.springframework.core.io.ClassPathResource;
|
||||||
import org.springframework.core.io.Resource;
|
import org.springframework.core.io.Resource;
|
||||||
|
|
||||||
@@ -38,7 +40,9 @@ import static org.mockito.Mockito.mock;
|
|||||||
*
|
*
|
||||||
* @author Scott Frederick
|
* @author Scott Frederick
|
||||||
* @author Phillip Webb
|
* @author Phillip Webb
|
||||||
|
* @author Moritz Halbritter
|
||||||
*/
|
*/
|
||||||
|
@MockPkcs11Security
|
||||||
class WebServerSslBundleTests {
|
class WebServerSslBundleTests {
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
@@ -82,14 +86,13 @@ class WebServerSslBundleTests {
|
|||||||
@Test
|
@Test
|
||||||
void whenFromJksPropertiesWithPkcs11StoreType() {
|
void whenFromJksPropertiesWithPkcs11StoreType() {
|
||||||
Ssl ssl = new Ssl();
|
Ssl ssl = new Ssl();
|
||||||
ssl.setKeyStorePassword("secret");
|
|
||||||
ssl.setKeyStoreType("PKCS11");
|
ssl.setKeyStoreType("PKCS11");
|
||||||
|
ssl.setKeyStoreProvider(MockPkcs11SecurityProvider.NAME);
|
||||||
|
ssl.setKeyStore("src/test/resources/test.jks");
|
||||||
ssl.setKeyPassword("password");
|
ssl.setKeyPassword("password");
|
||||||
ssl.setClientAuth(Ssl.ClientAuth.NONE);
|
ssl.setClientAuth(Ssl.ClientAuth.NONE);
|
||||||
SslBundle bundle = WebServerSslBundle.get(ssl);
|
assertThatIllegalStateException().isThrownBy(() -> WebServerSslBundle.get(ssl))
|
||||||
assertThat(bundle).isNotNull();
|
.withMessageContaining("must be empty or null for PKCS11 hardware key stores");
|
||||||
assertThat(bundle.getStores().getKeyStorePassword()).isEqualTo("secret");
|
|
||||||
assertThat(bundle.getKey().getPassword()).isEqualTo("password");
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
|
|||||||
Reference in New Issue
Block a user