Consolidate web server SSL configuration
This commit is contained in:
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright 2012-2022 the original author or authors.
|
||||
* Copyright 2012-2023 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.
|
||||
@@ -39,9 +39,9 @@ import org.springframework.boot.rsocket.server.ConfigurableRSocketServerFactory;
|
||||
import org.springframework.boot.rsocket.server.RSocketServer;
|
||||
import org.springframework.boot.rsocket.server.RSocketServerCustomizer;
|
||||
import org.springframework.boot.rsocket.server.RSocketServerFactory;
|
||||
import org.springframework.boot.web.server.CertificateFileSslStoreProvider;
|
||||
import org.springframework.boot.web.server.Ssl;
|
||||
import org.springframework.boot.web.server.SslStoreProvider;
|
||||
import org.springframework.boot.web.server.SslStoreProviderFactory;
|
||||
import org.springframework.http.client.reactive.ReactorResourceFactory;
|
||||
import org.springframework.util.Assert;
|
||||
import org.springframework.util.unit.DataSize;
|
||||
@@ -202,7 +202,7 @@ public class NettyRSocketServerFactory implements RSocketServerFactory, Configur
|
||||
if (this.sslStoreProvider != null) {
|
||||
return this.sslStoreProvider;
|
||||
}
|
||||
return CertificateFileSslStoreProvider.from(this.ssl);
|
||||
return SslStoreProviderFactory.from(this.ssl);
|
||||
}
|
||||
|
||||
private InetSocketAddress getListenAddress() {
|
||||
|
||||
@@ -16,9 +16,7 @@
|
||||
|
||||
package org.springframework.boot.web.embedded.jetty;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.net.InetSocketAddress;
|
||||
import java.net.URL;
|
||||
|
||||
import org.eclipse.jetty.alpn.server.ALPNServerConnectionFactory;
|
||||
import org.eclipse.jetty.http.HttpVersion;
|
||||
@@ -32,19 +30,15 @@ import org.eclipse.jetty.server.SecureRequestCustomizer;
|
||||
import org.eclipse.jetty.server.Server;
|
||||
import org.eclipse.jetty.server.ServerConnector;
|
||||
import org.eclipse.jetty.server.SslConnectionFactory;
|
||||
import org.eclipse.jetty.util.resource.Resource;
|
||||
import org.eclipse.jetty.util.ssl.SslContextFactory;
|
||||
|
||||
import org.springframework.boot.web.server.Http2;
|
||||
import org.springframework.boot.web.server.Ssl;
|
||||
import org.springframework.boot.web.server.SslConfigurationValidator;
|
||||
import org.springframework.boot.web.server.SslStoreProvider;
|
||||
import org.springframework.boot.web.server.WebServerException;
|
||||
import org.springframework.util.Assert;
|
||||
import org.springframework.util.ClassUtils;
|
||||
import org.springframework.util.ObjectUtils;
|
||||
import org.springframework.util.ResourceUtils;
|
||||
import org.springframework.util.StringUtils;
|
||||
|
||||
/**
|
||||
* {@link JettyServerCustomizer} that configures SSL on the given Jetty server instance.
|
||||
@@ -53,6 +47,7 @@ import org.springframework.util.StringUtils;
|
||||
* @author Olivier Lamy
|
||||
* @author Chris Bono
|
||||
* @author Cyril Dangerville
|
||||
* @author Scott Frederick
|
||||
*/
|
||||
class SslServerCustomizer implements JettyServerCustomizer {
|
||||
|
||||
@@ -193,13 +188,9 @@ class SslServerCustomizer implements JettyServerCustomizer {
|
||||
factory.setTrustStore(sslStoreProvider.getTrustStore());
|
||||
}
|
||||
catch (Exception ex) {
|
||||
throw new IllegalStateException("Unable to set SSL store", ex);
|
||||
throw new IllegalStateException("Unable to set SSL store: " + ex.getMessage(), ex);
|
||||
}
|
||||
}
|
||||
else {
|
||||
configureSslKeyStore(factory, ssl);
|
||||
configureSslTrustStore(factory, ssl);
|
||||
}
|
||||
}
|
||||
|
||||
private void configureSslClientAuth(SslContextFactory.Server factory, Ssl ssl) {
|
||||
@@ -221,49 +212,6 @@ class SslServerCustomizer implements JettyServerCustomizer {
|
||||
}
|
||||
}
|
||||
|
||||
private void configureSslKeyStore(SslContextFactory.Server factory, Ssl ssl) {
|
||||
String keystoreType = (ssl.getKeyStoreType() != null) ? ssl.getKeyStoreType() : "JKS";
|
||||
String keystoreLocation = ssl.getKeyStore();
|
||||
if (keystoreType.equalsIgnoreCase("PKCS11")) {
|
||||
Assert.state(!StringUtils.hasText(keystoreLocation),
|
||||
() -> "Keystore location '" + keystoreLocation + "' must be empty or null for PKCS11 key stores");
|
||||
}
|
||||
else {
|
||||
try {
|
||||
URL url = ResourceUtils.getURL(keystoreLocation);
|
||||
factory.setKeyStoreResource(Resource.newResource(url));
|
||||
}
|
||||
catch (Exception ex) {
|
||||
throw new WebServerException("Could not load key store '" + keystoreLocation + "'", ex);
|
||||
}
|
||||
}
|
||||
factory.setKeyStoreType(keystoreType);
|
||||
if (ssl.getKeyStoreProvider() != null) {
|
||||
factory.setKeyStoreProvider(this.ssl.getKeyStoreProvider());
|
||||
}
|
||||
}
|
||||
|
||||
private void configureSslTrustStore(SslContextFactory.Server factory, Ssl ssl) {
|
||||
if (ssl.getTrustStorePassword() != null) {
|
||||
factory.setTrustStorePassword(ssl.getTrustStorePassword());
|
||||
}
|
||||
if (ssl.getTrustStore() != null) {
|
||||
try {
|
||||
URL url = ResourceUtils.getURL(ssl.getTrustStore());
|
||||
factory.setTrustStoreResource(Resource.newResource(url));
|
||||
}
|
||||
catch (IOException ex) {
|
||||
throw new WebServerException("Could not find trust store '" + ssl.getTrustStore() + "'", ex);
|
||||
}
|
||||
}
|
||||
if (ssl.getTrustStoreType() != null) {
|
||||
factory.setTrustStoreType(ssl.getTrustStoreType());
|
||||
}
|
||||
if (ssl.getTrustStoreProvider() != null) {
|
||||
factory.setTrustStoreProvider(ssl.getTrustStoreProvider());
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* A {@link ServerConnector} that validates the ssl key alias on server startup.
|
||||
*/
|
||||
|
||||
@@ -16,9 +16,7 @@
|
||||
|
||||
package org.springframework.boot.web.embedded.netty;
|
||||
|
||||
import java.io.InputStream;
|
||||
import java.net.Socket;
|
||||
import java.net.URL;
|
||||
import java.security.InvalidAlgorithmParameterException;
|
||||
import java.security.KeyStore;
|
||||
import java.security.KeyStoreException;
|
||||
@@ -47,10 +45,6 @@ import org.springframework.boot.web.server.Http2;
|
||||
import org.springframework.boot.web.server.Ssl;
|
||||
import org.springframework.boot.web.server.SslConfigurationValidator;
|
||||
import org.springframework.boot.web.server.SslStoreProvider;
|
||||
import org.springframework.boot.web.server.WebServerException;
|
||||
import org.springframework.util.Assert;
|
||||
import org.springframework.util.ResourceUtils;
|
||||
import org.springframework.util.StringUtils;
|
||||
|
||||
/**
|
||||
* {@link NettyServerCustomizer} that configures SSL for the given Reactor Netty server
|
||||
@@ -60,6 +54,7 @@ import org.springframework.util.StringUtils;
|
||||
* @author Raheela Aslam
|
||||
* @author Chris Bono
|
||||
* @author Cyril Dangerville
|
||||
* @author Scott Frederick
|
||||
* @since 2.0.0
|
||||
* @deprecated this class is meant for Spring Boot internal use only.
|
||||
*/
|
||||
@@ -93,7 +88,7 @@ public class SslServerCustomizer implements NettyServerCustomizer {
|
||||
sslContextSpec = Http11SslContextSpec.forServer(getKeyManagerFactory(this.ssl, this.sslStoreProvider));
|
||||
}
|
||||
sslContextSpec.configure((builder) -> {
|
||||
builder.trustManager(getTrustManagerFactory(this.ssl, this.sslStoreProvider));
|
||||
builder.trustManager(getTrustManagerFactory(this.sslStoreProvider));
|
||||
if (this.ssl.getEnabledProtocols() != null) {
|
||||
builder.protocols(this.ssl.getEnabledProtocols());
|
||||
}
|
||||
@@ -112,13 +107,13 @@ public class SslServerCustomizer implements NettyServerCustomizer {
|
||||
|
||||
KeyManagerFactory getKeyManagerFactory(Ssl ssl, SslStoreProvider sslStoreProvider) {
|
||||
try {
|
||||
KeyStore keyStore = getKeyStore(ssl, sslStoreProvider);
|
||||
KeyStore keyStore = sslStoreProvider.getKeyStore();
|
||||
SslConfigurationValidator.validateKeyAlias(keyStore, ssl.getKeyAlias());
|
||||
KeyManagerFactory keyManagerFactory = (ssl.getKeyAlias() == null)
|
||||
? KeyManagerFactory.getInstance(KeyManagerFactory.getDefaultAlgorithm())
|
||||
: new ConfigurableAliasKeyManagerFactory(ssl.getKeyAlias(),
|
||||
KeyManagerFactory.getDefaultAlgorithm());
|
||||
String keyPassword = (sslStoreProvider != null) ? sslStoreProvider.getKeyPassword() : null;
|
||||
String keyPassword = sslStoreProvider.getKeyPassword();
|
||||
if (keyPassword == null) {
|
||||
keyPassword = (ssl.getKeyPassword() != null) ? ssl.getKeyPassword() : ssl.getKeyStorePassword();
|
||||
}
|
||||
@@ -126,76 +121,23 @@ public class SslServerCustomizer implements NettyServerCustomizer {
|
||||
return keyManagerFactory;
|
||||
}
|
||||
catch (Exception ex) {
|
||||
throw new IllegalStateException(ex);
|
||||
throw new IllegalStateException("Could not load key manager factory: " + ex.getMessage(), ex);
|
||||
}
|
||||
}
|
||||
|
||||
private KeyStore getKeyStore(Ssl ssl, SslStoreProvider sslStoreProvider) throws Exception {
|
||||
if (sslStoreProvider != null) {
|
||||
return sslStoreProvider.getKeyStore();
|
||||
}
|
||||
return loadKeyStore(ssl.getKeyStoreType(), ssl.getKeyStoreProvider(), ssl.getKeyStore(),
|
||||
ssl.getKeyStorePassword());
|
||||
}
|
||||
|
||||
TrustManagerFactory getTrustManagerFactory(Ssl ssl, SslStoreProvider sslStoreProvider) {
|
||||
TrustManagerFactory getTrustManagerFactory(SslStoreProvider sslStoreProvider) {
|
||||
try {
|
||||
KeyStore store = getTrustStore(ssl, sslStoreProvider);
|
||||
KeyStore store = sslStoreProvider.getTrustStore();
|
||||
TrustManagerFactory trustManagerFactory = TrustManagerFactory
|
||||
.getInstance(TrustManagerFactory.getDefaultAlgorithm());
|
||||
trustManagerFactory.init(store);
|
||||
return trustManagerFactory;
|
||||
}
|
||||
catch (Exception ex) {
|
||||
throw new IllegalStateException(ex);
|
||||
throw new IllegalStateException("Could not load trust manager factory: " + ex.getMessage(), ex);
|
||||
}
|
||||
}
|
||||
|
||||
private KeyStore getTrustStore(Ssl ssl, SslStoreProvider sslStoreProvider) throws Exception {
|
||||
if (sslStoreProvider != null) {
|
||||
return sslStoreProvider.getTrustStore();
|
||||
}
|
||||
return loadTrustStore(ssl.getTrustStoreType(), ssl.getTrustStoreProvider(), ssl.getTrustStore(),
|
||||
ssl.getTrustStorePassword());
|
||||
}
|
||||
|
||||
private KeyStore loadKeyStore(String type, String provider, String resource, String password) throws Exception {
|
||||
|
||||
return loadStore(type, provider, resource, password);
|
||||
}
|
||||
|
||||
private KeyStore loadTrustStore(String type, String provider, String resource, String password) throws Exception {
|
||||
if (resource == null) {
|
||||
return null;
|
||||
}
|
||||
return loadStore(type, provider, resource, password);
|
||||
}
|
||||
|
||||
private KeyStore loadStore(String keystoreType, String provider, String keystoreLocation, String password)
|
||||
throws Exception {
|
||||
keystoreType = (keystoreType != null) ? keystoreType : "JKS";
|
||||
char[] passwordChars = (password != null) ? password.toCharArray() : null;
|
||||
KeyStore store = (provider != null) ? KeyStore.getInstance(keystoreType, provider)
|
||||
: KeyStore.getInstance(keystoreType);
|
||||
if (keystoreType.equalsIgnoreCase("PKCS11")) {
|
||||
Assert.state(!StringUtils.hasText(keystoreLocation),
|
||||
() -> "Keystore location '" + keystoreLocation + "' must be empty or null for PKCS11 key stores");
|
||||
store.load(null, passwordChars);
|
||||
}
|
||||
else {
|
||||
try {
|
||||
URL url = ResourceUtils.getURL(keystoreLocation);
|
||||
try (InputStream stream = url.openStream()) {
|
||||
store.load(stream, passwordChars);
|
||||
}
|
||||
}
|
||||
catch (Exception ex) {
|
||||
throw new WebServerException("Could not load key store '" + keystoreLocation + "'", ex);
|
||||
}
|
||||
}
|
||||
return store;
|
||||
}
|
||||
|
||||
/**
|
||||
* A {@link KeyManagerFactory} that allows a configurable key alias to be used. Due to
|
||||
* the fact that the actual calls to retrieve the key by alias are done at request
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright 2012-2022 the original author or authors.
|
||||
* Copyright 2012-2023 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,8 +16,6 @@
|
||||
|
||||
package org.springframework.boot.web.embedded.tomcat;
|
||||
|
||||
import java.io.FileNotFoundException;
|
||||
|
||||
import org.apache.catalina.connector.Connector;
|
||||
import org.apache.coyote.ProtocolHandler;
|
||||
import org.apache.coyote.http11.AbstractHttp11JsseProtocol;
|
||||
@@ -28,9 +26,8 @@ import org.apache.tomcat.util.net.SSLHostConfigCertificate.Type;
|
||||
|
||||
import org.springframework.boot.web.server.Ssl;
|
||||
import org.springframework.boot.web.server.SslStoreProvider;
|
||||
import org.springframework.boot.web.server.WebServerException;
|
||||
import org.springframework.boot.web.server.SslStoreProviderFactory;
|
||||
import org.springframework.util.Assert;
|
||||
import org.springframework.util.ResourceUtils;
|
||||
import org.springframework.util.StringUtils;
|
||||
|
||||
/**
|
||||
@@ -47,6 +44,10 @@ class SslConnectorCustomizer implements TomcatConnectorCustomizer {
|
||||
|
||||
private final SslStoreProvider sslStoreProvider;
|
||||
|
||||
SslConnectorCustomizer(Ssl ssl) {
|
||||
this(ssl, SslStoreProviderFactory.from(ssl));
|
||||
}
|
||||
|
||||
SslConnectorCustomizer(Ssl ssl, SslStoreProvider sslStoreProvider) {
|
||||
Assert.notNull(ssl, "Ssl configuration should not be null");
|
||||
this.ssl = ssl;
|
||||
@@ -99,10 +100,6 @@ class SslConnectorCustomizer implements TomcatConnectorCustomizer {
|
||||
certificate.setCertificateKeyPassword(keyPassword);
|
||||
}
|
||||
}
|
||||
else {
|
||||
configureSslKeyStore(certificate, ssl);
|
||||
configureSslTrustStore(sslHostConfig, ssl);
|
||||
}
|
||||
}
|
||||
|
||||
private void configureEnabledProtocols(AbstractHttp11JsseProtocol<?> protocol, Ssl ssl) {
|
||||
@@ -135,48 +132,7 @@ class SslConnectorCustomizer implements TomcatConnectorCustomizer {
|
||||
}
|
||||
}
|
||||
catch (Exception ex) {
|
||||
throw new WebServerException("Could not load store: " + ex.getMessage(), ex);
|
||||
}
|
||||
}
|
||||
|
||||
private void configureSslKeyStore(SSLHostConfigCertificate certificate, Ssl ssl) {
|
||||
String keystoreType = (ssl.getKeyStoreType() != null) ? ssl.getKeyStoreType() : "JKS";
|
||||
String keystoreLocation = ssl.getKeyStore();
|
||||
if (keystoreType.equalsIgnoreCase("PKCS11")) {
|
||||
Assert.state(!StringUtils.hasText(keystoreLocation),
|
||||
() -> "Keystore location '" + keystoreLocation + "' must be empty or null for PKCS11 key stores");
|
||||
}
|
||||
else {
|
||||
try {
|
||||
certificate.setCertificateKeystoreFile(ResourceUtils.getURL(keystoreLocation).toString());
|
||||
}
|
||||
catch (Exception ex) {
|
||||
throw new WebServerException("Could not load key store '" + keystoreLocation + "'", ex);
|
||||
}
|
||||
}
|
||||
certificate.setCertificateKeystoreType(keystoreType);
|
||||
if (ssl.getKeyStoreProvider() != null) {
|
||||
certificate.setCertificateKeystoreProvider(ssl.getKeyStoreProvider());
|
||||
}
|
||||
}
|
||||
|
||||
private void configureSslTrustStore(SSLHostConfig sslHostConfig, Ssl ssl) {
|
||||
if (ssl.getTrustStore() != null) {
|
||||
try {
|
||||
sslHostConfig.setTruststoreFile(ResourceUtils.getURL(ssl.getTrustStore()).toString());
|
||||
}
|
||||
catch (FileNotFoundException ex) {
|
||||
throw new WebServerException("Could not load trust store: " + ex.getMessage(), ex);
|
||||
}
|
||||
}
|
||||
if (ssl.getTrustStorePassword() != null) {
|
||||
sslHostConfig.setTruststorePassword(ssl.getTrustStorePassword());
|
||||
}
|
||||
if (ssl.getTrustStoreType() != null) {
|
||||
sslHostConfig.setTruststoreType(ssl.getTrustStoreType());
|
||||
}
|
||||
if (ssl.getTrustStoreProvider() != null) {
|
||||
sslHostConfig.setTruststoreProvider(ssl.getTrustStoreProvider());
|
||||
throw new IllegalStateException("Could not load store: " + ex.getMessage(), ex);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -16,10 +16,8 @@
|
||||
|
||||
package org.springframework.boot.web.embedded.undertow;
|
||||
|
||||
import java.io.InputStream;
|
||||
import java.net.InetAddress;
|
||||
import java.net.Socket;
|
||||
import java.net.URL;
|
||||
import java.security.KeyManagementException;
|
||||
import java.security.KeyStore;
|
||||
import java.security.NoSuchAlgorithmException;
|
||||
@@ -43,8 +41,6 @@ import org.xnio.SslClientAuthMode;
|
||||
import org.springframework.boot.web.server.Ssl;
|
||||
import org.springframework.boot.web.server.SslConfigurationValidator;
|
||||
import org.springframework.boot.web.server.SslStoreProvider;
|
||||
import org.springframework.boot.web.server.WebServerException;
|
||||
import org.springframework.util.ResourceUtils;
|
||||
|
||||
/**
|
||||
* {@link UndertowBuilderCustomizer} that configures SSL on the given builder instance.
|
||||
@@ -52,6 +48,7 @@ import org.springframework.util.ResourceUtils;
|
||||
* @author Brian Clozel
|
||||
* @author Raheela Aslam
|
||||
* @author Cyril Dangerville
|
||||
* @author Scott Frederick
|
||||
*/
|
||||
class SslBuilderCustomizer implements UndertowBuilderCustomizer {
|
||||
|
||||
@@ -74,8 +71,8 @@ class SslBuilderCustomizer implements UndertowBuilderCustomizer {
|
||||
public void customize(Undertow.Builder builder) {
|
||||
try {
|
||||
SSLContext sslContext = SSLContext.getInstance(this.ssl.getProtocol());
|
||||
sslContext.init(getKeyManagers(this.ssl, this.sslStoreProvider),
|
||||
getTrustManagers(this.ssl, this.sslStoreProvider), null);
|
||||
sslContext.init(getKeyManagers(this.ssl, this.sslStoreProvider), getTrustManagers(this.sslStoreProvider),
|
||||
null);
|
||||
builder.addHttpsListener(this.port, getListenAddress(), sslContext);
|
||||
builder.setSocketOption(Options.SSL_CLIENT_AUTH_MODE, getSslClientAuthMode(this.ssl));
|
||||
if (this.ssl.getEnabledProtocols() != null) {
|
||||
@@ -107,13 +104,13 @@ class SslBuilderCustomizer implements UndertowBuilderCustomizer {
|
||||
return SslClientAuthMode.NOT_REQUESTED;
|
||||
}
|
||||
|
||||
private KeyManager[] getKeyManagers(Ssl ssl, SslStoreProvider sslStoreProvider) {
|
||||
KeyManager[] getKeyManagers(Ssl ssl, SslStoreProvider sslStoreProvider) {
|
||||
try {
|
||||
KeyStore keyStore = getKeyStore(ssl, sslStoreProvider);
|
||||
KeyStore keyStore = sslStoreProvider.getKeyStore();
|
||||
SslConfigurationValidator.validateKeyAlias(keyStore, ssl.getKeyAlias());
|
||||
KeyManagerFactory keyManagerFactory = KeyManagerFactory
|
||||
.getInstance(KeyManagerFactory.getDefaultAlgorithm());
|
||||
String keyPassword = (sslStoreProvider != null) ? sslStoreProvider.getKeyPassword() : null;
|
||||
String keyPassword = sslStoreProvider.getKeyPassword();
|
||||
if (keyPassword == null) {
|
||||
keyPassword = (ssl.getKeyPassword() != null) ? ssl.getKeyPassword() : ssl.getKeyStorePassword();
|
||||
}
|
||||
@@ -124,7 +121,7 @@ class SslBuilderCustomizer implements UndertowBuilderCustomizer {
|
||||
return keyManagerFactory.getKeyManagers();
|
||||
}
|
||||
catch (Exception ex) {
|
||||
throw new IllegalStateException(ex);
|
||||
throw new IllegalStateException("Could not load key managers: " + ex.getMessage(), ex);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -138,71 +135,19 @@ class SslBuilderCustomizer implements UndertowBuilderCustomizer {
|
||||
return keyManagers;
|
||||
}
|
||||
|
||||
private KeyStore getKeyStore(Ssl ssl, SslStoreProvider sslStoreProvider) throws Exception {
|
||||
if (sslStoreProvider != null) {
|
||||
return sslStoreProvider.getKeyStore();
|
||||
}
|
||||
return loadKeyStore(ssl.getKeyStoreType(), ssl.getKeyStoreProvider(), ssl.getKeyStore(),
|
||||
ssl.getKeyStorePassword());
|
||||
}
|
||||
|
||||
private TrustManager[] getTrustManagers(Ssl ssl, SslStoreProvider sslStoreProvider) {
|
||||
TrustManager[] getTrustManagers(SslStoreProvider sslStoreProvider) {
|
||||
try {
|
||||
KeyStore store = getTrustStore(ssl, sslStoreProvider);
|
||||
KeyStore store = sslStoreProvider.getTrustStore();
|
||||
TrustManagerFactory trustManagerFactory = TrustManagerFactory
|
||||
.getInstance(TrustManagerFactory.getDefaultAlgorithm());
|
||||
trustManagerFactory.init(store);
|
||||
return trustManagerFactory.getTrustManagers();
|
||||
}
|
||||
catch (Exception ex) {
|
||||
throw new IllegalStateException(ex);
|
||||
throw new IllegalStateException("Could not load trust managers: " + ex.getMessage(), ex);
|
||||
}
|
||||
}
|
||||
|
||||
private KeyStore getTrustStore(Ssl ssl, SslStoreProvider sslStoreProvider) throws Exception {
|
||||
if (sslStoreProvider != null) {
|
||||
return sslStoreProvider.getTrustStore();
|
||||
}
|
||||
return loadTrustStore(ssl.getTrustStoreType(), ssl.getTrustStoreProvider(), ssl.getTrustStore(),
|
||||
ssl.getTrustStorePassword());
|
||||
}
|
||||
|
||||
private KeyStore loadKeyStore(String type, String provider, String resource, String password) throws Exception {
|
||||
return loadStore(type, provider, resource, password);
|
||||
}
|
||||
|
||||
private KeyStore loadTrustStore(String type, String provider, String resource, String password) throws Exception {
|
||||
if (resource == null) {
|
||||
return null;
|
||||
}
|
||||
return loadStore(type, provider, resource, password);
|
||||
}
|
||||
|
||||
private KeyStore loadStore(String type, String provider, String resource, String password) throws Exception {
|
||||
type = (type != null) ? type : "JKS";
|
||||
KeyStore store = (provider != null) ? KeyStore.getInstance(type, provider) : KeyStore.getInstance(type);
|
||||
if (type.equalsIgnoreCase("PKCS11")) {
|
||||
if (resource != null && !resource.isEmpty()) {
|
||||
throw new IllegalArgumentException("Input keystore location is not valid for keystore type 'PKCS11': '"
|
||||
+ resource + "'. Must be undefined / null.");
|
||||
}
|
||||
store.load(null, (password != null) ? password.toCharArray() : null);
|
||||
}
|
||||
else {
|
||||
try {
|
||||
URL url = ResourceUtils.getURL(resource);
|
||||
try (InputStream stream = url.openStream()) {
|
||||
store.load(stream, (password != null) ? password.toCharArray() : null);
|
||||
}
|
||||
}
|
||||
catch (Exception ex) {
|
||||
throw new WebServerException("Could not load key store '" + resource + "'", ex);
|
||||
}
|
||||
}
|
||||
|
||||
return store;
|
||||
}
|
||||
|
||||
/**
|
||||
* {@link X509ExtendedKeyManager} that supports custom alias configuration.
|
||||
*/
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright 2012-2022 the original author or authors.
|
||||
* Copyright 2012-2023 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.
|
||||
@@ -189,7 +189,7 @@ public abstract class AbstractConfigurableWebServerFactory implements Configurab
|
||||
if (this.sslStoreProvider != null) {
|
||||
return this.sslStoreProvider;
|
||||
}
|
||||
return CertificateFileSslStoreProvider.from(this.ssl);
|
||||
return SslStoreProviderFactory.from(this.ssl);
|
||||
}
|
||||
|
||||
/**
|
||||
|
||||
@@ -0,0 +1,97 @@
|
||||
/*
|
||||
* Copyright 2012-2023 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.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* https://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package org.springframework.boot.web.server;
|
||||
|
||||
import java.io.InputStream;
|
||||
import java.net.URL;
|
||||
import java.security.KeyStore;
|
||||
|
||||
import org.springframework.util.Assert;
|
||||
import org.springframework.util.ResourceUtils;
|
||||
import org.springframework.util.StringUtils;
|
||||
|
||||
/**
|
||||
* An {@link SslStoreProvider} that creates key and trust stores from Java keystore files.
|
||||
*
|
||||
* @author Scott Frederick
|
||||
*/
|
||||
final class JavaKeyStoreSslStoreProvider implements SslStoreProvider {
|
||||
|
||||
private final Ssl ssl;
|
||||
|
||||
private JavaKeyStoreSslStoreProvider(Ssl ssl) {
|
||||
this.ssl = ssl;
|
||||
}
|
||||
|
||||
@Override
|
||||
public KeyStore getKeyStore() throws Exception {
|
||||
return createKeyStore(this.ssl.getKeyStoreType(), this.ssl.getKeyStoreProvider(), this.ssl.getKeyStore(),
|
||||
this.ssl.getKeyStorePassword());
|
||||
}
|
||||
|
||||
@Override
|
||||
public KeyStore getTrustStore() throws Exception {
|
||||
if (this.ssl.getTrustStore() == null) {
|
||||
return null;
|
||||
}
|
||||
return createKeyStore(this.ssl.getTrustStoreType(), this.ssl.getTrustStoreProvider(), this.ssl.getTrustStore(),
|
||||
this.ssl.getTrustStorePassword());
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getKeyPassword() {
|
||||
return this.ssl.getKeyPassword();
|
||||
}
|
||||
|
||||
private KeyStore createKeyStore(String type, String provider, String location, String password) throws Exception {
|
||||
type = (type != null) ? type : "JKS";
|
||||
char[] passwordChars = (password != null) ? password.toCharArray() : null;
|
||||
KeyStore store = (provider != null) ? KeyStore.getInstance(type, provider) : KeyStore.getInstance(type);
|
||||
if (type.equalsIgnoreCase("PKCS11")) {
|
||||
Assert.state(!StringUtils.hasText(location),
|
||||
() -> "KeyStore location is '" + location + "', but must be empty or null for PKCS11 key stores");
|
||||
store.load(null, passwordChars);
|
||||
}
|
||||
else {
|
||||
Assert.state(StringUtils.hasText(location), () -> "KeyStore location must not be empty or null");
|
||||
try {
|
||||
URL url = ResourceUtils.getURL(location);
|
||||
try (InputStream stream = url.openStream()) {
|
||||
store.load(stream, passwordChars);
|
||||
}
|
||||
}
|
||||
catch (Exception ex) {
|
||||
throw new IllegalStateException("Could not load key store '" + location + "'", ex);
|
||||
}
|
||||
}
|
||||
return store;
|
||||
}
|
||||
|
||||
/**
|
||||
* Create an {@link SslStoreProvider} if the appropriate SSL properties are
|
||||
* configured.
|
||||
* @param ssl the SSL properties
|
||||
* @return an {@code SslStoreProvider} or {@code null}
|
||||
*/
|
||||
static SslStoreProvider from(Ssl ssl) {
|
||||
if (ssl != null && ssl.isEnabled()) {
|
||||
return new JavaKeyStoreSslStoreProvider(ssl);
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,41 @@
|
||||
/*
|
||||
* Copyright 2012-2023 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.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* https://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package org.springframework.boot.web.server;
|
||||
|
||||
/**
|
||||
* Creates an {@link SslStoreProvider} based on SSL configuration properties.
|
||||
*
|
||||
* @author Scott Frederick
|
||||
* @since 3.1.0
|
||||
*/
|
||||
public final class SslStoreProviderFactory {
|
||||
|
||||
private SslStoreProviderFactory() {
|
||||
}
|
||||
|
||||
/**
|
||||
* Create an {@link SslStoreProvider} if the appropriate SSL properties are
|
||||
* configured.
|
||||
* @param ssl the SSL properties
|
||||
* @return an {@code SslStoreProvider} or {@code null}
|
||||
*/
|
||||
public static SslStoreProvider from(Ssl ssl) {
|
||||
SslStoreProvider sslStoreProvider = CertificateFileSslStoreProvider.from(ssl);
|
||||
return ((sslStoreProvider != null) ? sslStoreProvider : JavaKeyStoreSslStoreProvider.from(ssl));
|
||||
}
|
||||
|
||||
}
|
||||
@@ -35,10 +35,9 @@ import org.springframework.boot.web.embedded.test.MockPkcs11Security;
|
||||
import org.springframework.boot.web.embedded.test.MockPkcs11SecurityProvider;
|
||||
import org.springframework.boot.web.server.Http2;
|
||||
import org.springframework.boot.web.server.Ssl;
|
||||
import org.springframework.boot.web.server.WebServerException;
|
||||
import org.springframework.boot.web.server.SslStoreProviderFactory;
|
||||
|
||||
import static org.assertj.core.api.Assertions.assertThat;
|
||||
import static org.assertj.core.api.Assertions.assertThatExceptionOfType;
|
||||
import static org.assertj.core.api.Assertions.assertThatIllegalStateException;
|
||||
import static org.assertj.core.api.Assertions.assertThatNoException;
|
||||
|
||||
@@ -47,6 +46,7 @@ import static org.assertj.core.api.Assertions.assertThatNoException;
|
||||
*
|
||||
* @author Andy Wilkinson
|
||||
* @author Cyril Dangerville
|
||||
* @author Scott Frederick
|
||||
*/
|
||||
@MockPkcs11Security
|
||||
class SslServerCustomizerTests {
|
||||
@@ -92,12 +92,9 @@ class SslServerCustomizerTests {
|
||||
void configureSslWhenSslIsEnabledWithNoKeyStoreAndNotPkcs11ThrowsException() {
|
||||
Ssl ssl = new Ssl();
|
||||
SslServerCustomizer customizer = new SslServerCustomizer(null, ssl, null, null);
|
||||
assertThatExceptionOfType(Exception.class)
|
||||
.isThrownBy(() -> customizer.configureSsl(new SslContextFactory.Server(), ssl, null))
|
||||
.satisfies((ex) -> {
|
||||
assertThat(ex).isInstanceOf(WebServerException.class);
|
||||
assertThat(ex).hasMessageContaining("Could not load key store 'null'");
|
||||
});
|
||||
assertThatIllegalStateException().isThrownBy(
|
||||
() -> customizer.configureSsl(new SslContextFactory.Server(), ssl, SslStoreProviderFactory.from(ssl)))
|
||||
.withMessageContaining("KeyStore location must not be empty or null");
|
||||
}
|
||||
|
||||
@Test
|
||||
@@ -108,8 +105,8 @@ class SslServerCustomizerTests {
|
||||
ssl.setKeyStore("src/test/resources/test.jks");
|
||||
ssl.setKeyPassword("password");
|
||||
SslServerCustomizer customizer = new SslServerCustomizer(null, ssl, null, null);
|
||||
assertThatIllegalStateException()
|
||||
.isThrownBy(() -> customizer.configureSsl(new SslContextFactory.Server(), ssl, null))
|
||||
assertThatIllegalStateException().isThrownBy(
|
||||
() -> customizer.configureSsl(new SslContextFactory.Server(), ssl, SslStoreProviderFactory.from(ssl)))
|
||||
.withMessageContaining("must be empty or null for PKCS11 key stores");
|
||||
}
|
||||
|
||||
|
||||
@@ -23,7 +23,7 @@ import org.junit.jupiter.api.Test;
|
||||
import org.springframework.boot.web.embedded.test.MockPkcs11Security;
|
||||
import org.springframework.boot.web.embedded.test.MockPkcs11SecurityProvider;
|
||||
import org.springframework.boot.web.server.Ssl;
|
||||
import org.springframework.boot.web.server.WebServerException;
|
||||
import org.springframework.boot.web.server.SslStoreProviderFactory;
|
||||
|
||||
import static org.assertj.core.api.Assertions.assertThatIllegalStateException;
|
||||
import static org.assertj.core.api.Assertions.assertThatNoException;
|
||||
@@ -34,6 +34,7 @@ import static org.assertj.core.api.Assertions.assertThatNoException;
|
||||
* @author Andy Wilkinson
|
||||
* @author Raheela Aslam
|
||||
* @author Cyril Dangerville
|
||||
* @author Scott Frederick
|
||||
*/
|
||||
@SuppressWarnings("deprecation")
|
||||
@MockPkcs11Security
|
||||
@@ -46,7 +47,8 @@ class SslServerCustomizerTests {
|
||||
ssl.setKeyStore("src/test/resources/test.jks");
|
||||
ssl.setKeyStoreProvider("com.example.KeyStoreProvider");
|
||||
SslServerCustomizer customizer = new SslServerCustomizer(ssl, null, null);
|
||||
assertThatIllegalStateException().isThrownBy(() -> customizer.getKeyManagerFactory(ssl, null))
|
||||
assertThatIllegalStateException()
|
||||
.isThrownBy(() -> customizer.getKeyManagerFactory(ssl, SslStoreProviderFactory.from(ssl)))
|
||||
.withCauseInstanceOf(NoSuchProviderException.class)
|
||||
.withMessageContaining("com.example.KeyStoreProvider");
|
||||
}
|
||||
@@ -58,7 +60,8 @@ class SslServerCustomizerTests {
|
||||
ssl.setTrustStore("src/test/resources/test.jks");
|
||||
ssl.setTrustStoreProvider("com.example.TrustStoreProvider");
|
||||
SslServerCustomizer customizer = new SslServerCustomizer(ssl, null, null);
|
||||
assertThatIllegalStateException().isThrownBy(() -> customizer.getTrustManagerFactory(ssl, null))
|
||||
assertThatIllegalStateException()
|
||||
.isThrownBy(() -> customizer.getTrustManagerFactory(SslStoreProviderFactory.from(ssl)))
|
||||
.withCauseInstanceOf(NoSuchProviderException.class)
|
||||
.withMessageContaining("com.example.TrustStoreProvider");
|
||||
}
|
||||
@@ -67,9 +70,10 @@ class SslServerCustomizerTests {
|
||||
void getKeyManagerFactoryWhenSslIsEnabledWithNoKeyStoreAndNotPkcs11ThrowsException() {
|
||||
Ssl ssl = new Ssl();
|
||||
SslServerCustomizer customizer = new SslServerCustomizer(ssl, null, null);
|
||||
assertThatIllegalStateException().isThrownBy(() -> customizer.getKeyManagerFactory(ssl, null))
|
||||
.withCauseInstanceOf(WebServerException.class)
|
||||
.withMessageContaining("Could not load key store 'null'");
|
||||
assertThatIllegalStateException()
|
||||
.isThrownBy(() -> customizer.getKeyManagerFactory(ssl, SslStoreProviderFactory.from(ssl)))
|
||||
.withCauseInstanceOf(IllegalStateException.class)
|
||||
.withMessageContaining("KeyStore location must not be empty or null");
|
||||
}
|
||||
|
||||
@Test
|
||||
@@ -80,7 +84,8 @@ class SslServerCustomizerTests {
|
||||
ssl.setKeyStore("src/test/resources/test.jks");
|
||||
ssl.setKeyPassword("password");
|
||||
SslServerCustomizer customizer = new SslServerCustomizer(ssl, null, null);
|
||||
assertThatIllegalStateException().isThrownBy(() -> customizer.getKeyManagerFactory(ssl, null))
|
||||
assertThatIllegalStateException()
|
||||
.isThrownBy(() -> customizer.getKeyManagerFactory(ssl, SslStoreProviderFactory.from(ssl)))
|
||||
.withCauseInstanceOf(IllegalStateException.class)
|
||||
.withMessageContaining("must be empty or null for PKCS11 key stores");
|
||||
}
|
||||
@@ -92,7 +97,8 @@ class SslServerCustomizerTests {
|
||||
ssl.setKeyStoreProvider(MockPkcs11SecurityProvider.NAME);
|
||||
ssl.setKeyStorePassword("1234");
|
||||
SslServerCustomizer customizer = new SslServerCustomizer(ssl, null, null);
|
||||
assertThatNoException().isThrownBy(() -> customizer.getKeyManagerFactory(ssl, null));
|
||||
assertThatNoException()
|
||||
.isThrownBy(() -> customizer.getKeyManagerFactory(ssl, SslStoreProviderFactory.from(ssl)));
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -41,12 +41,10 @@ import org.springframework.boot.web.embedded.test.MockPkcs11Security;
|
||||
import org.springframework.boot.web.embedded.test.MockPkcs11SecurityProvider;
|
||||
import org.springframework.boot.web.server.Ssl;
|
||||
import org.springframework.boot.web.server.SslStoreProvider;
|
||||
import org.springframework.boot.web.server.WebServerException;
|
||||
import org.springframework.core.io.ClassPathResource;
|
||||
import org.springframework.core.io.Resource;
|
||||
|
||||
import static org.assertj.core.api.Assertions.assertThat;
|
||||
import static org.assertj.core.api.Assertions.assertThatExceptionOfType;
|
||||
import static org.assertj.core.api.Assertions.assertThatIllegalStateException;
|
||||
import static org.assertj.core.api.Assertions.assertThatNoException;
|
||||
import static org.mockito.BDDMockito.given;
|
||||
@@ -184,9 +182,9 @@ class SslConnectorCustomizerTests {
|
||||
|
||||
@Test
|
||||
void customizeWhenSslIsEnabledWithNoKeyStoreAndNotPkcs11ThrowsException() {
|
||||
assertThatExceptionOfType(WebServerException.class)
|
||||
.isThrownBy(() -> new SslConnectorCustomizer(new Ssl(), null).customize(this.tomcat.getConnector()))
|
||||
.withMessageContaining("Could not load key store 'null'");
|
||||
assertThatIllegalStateException()
|
||||
.isThrownBy(() -> new SslConnectorCustomizer(new Ssl()).customize(this.tomcat.getConnector()))
|
||||
.withMessageContaining("KeyStore location must not be empty or null");
|
||||
}
|
||||
|
||||
@Test
|
||||
@@ -196,7 +194,7 @@ class SslConnectorCustomizerTests {
|
||||
ssl.setKeyStoreProvider(MockPkcs11SecurityProvider.NAME);
|
||||
ssl.setKeyStore("src/test/resources/test.jks");
|
||||
ssl.setKeyPassword("password");
|
||||
SslConnectorCustomizer customizer = new SslConnectorCustomizer(ssl, null);
|
||||
SslConnectorCustomizer customizer = new SslConnectorCustomizer(ssl);
|
||||
assertThatIllegalStateException().isThrownBy(() -> customizer.customize(this.tomcat.getConnector()))
|
||||
.withMessageContaining("must be empty or null for PKCS11 key stores");
|
||||
}
|
||||
|
||||
@@ -26,8 +26,7 @@ import org.junit.jupiter.api.Test;
|
||||
import org.springframework.boot.web.embedded.test.MockPkcs11Security;
|
||||
import org.springframework.boot.web.embedded.test.MockPkcs11SecurityProvider;
|
||||
import org.springframework.boot.web.server.Ssl;
|
||||
import org.springframework.boot.web.server.WebServerException;
|
||||
import org.springframework.test.util.ReflectionTestUtils;
|
||||
import org.springframework.boot.web.server.SslStoreProviderFactory;
|
||||
|
||||
import static org.assertj.core.api.Assertions.assertThat;
|
||||
import static org.assertj.core.api.Assertions.assertThatIllegalStateException;
|
||||
@@ -49,7 +48,7 @@ class SslBuilderCustomizerTests {
|
||||
ssl.setKeyPassword("password");
|
||||
ssl.setKeyStore("src/test/resources/test.jks");
|
||||
SslBuilderCustomizer customizer = new SslBuilderCustomizer(8080, InetAddress.getLocalHost(), ssl, null);
|
||||
KeyManager[] keyManagers = ReflectionTestUtils.invokeMethod(customizer, "getKeyManagers", ssl, null);
|
||||
KeyManager[] keyManagers = customizer.getKeyManagers(ssl, SslStoreProviderFactory.from(ssl));
|
||||
Class<?> name = Class
|
||||
.forName("org.springframework.boot.web.embedded.undertow.SslBuilderCustomizer$ConfigurableAliasKeyManager");
|
||||
assertThat(keyManagers[0]).isNotInstanceOf(name);
|
||||
@@ -63,7 +62,7 @@ class SslBuilderCustomizerTests {
|
||||
ssl.setKeyStoreProvider("com.example.KeyStoreProvider");
|
||||
SslBuilderCustomizer customizer = new SslBuilderCustomizer(8080, InetAddress.getLocalHost(), ssl, null);
|
||||
assertThatIllegalStateException()
|
||||
.isThrownBy(() -> ReflectionTestUtils.invokeMethod(customizer, "getKeyManagers", ssl, null))
|
||||
.isThrownBy(() -> customizer.getKeyManagers(ssl, SslStoreProviderFactory.from(ssl)))
|
||||
.withCauseInstanceOf(NoSuchProviderException.class)
|
||||
.withMessageContaining("com.example.KeyStoreProvider");
|
||||
}
|
||||
@@ -76,8 +75,7 @@ class SslBuilderCustomizerTests {
|
||||
ssl.setTrustStoreProvider("com.example.TrustStoreProvider");
|
||||
SslBuilderCustomizer customizer = new SslBuilderCustomizer(8080, InetAddress.getLocalHost(), ssl, null);
|
||||
assertThatIllegalStateException()
|
||||
.isThrownBy(() -> ReflectionTestUtils.invokeMethod(customizer, "getTrustManagers", ssl, null))
|
||||
.withCauseInstanceOf(NoSuchProviderException.class)
|
||||
.isThrownBy(() -> customizer.getTrustManagers(SslStoreProviderFactory.from(ssl)))
|
||||
.withMessageContaining("com.example.TrustStoreProvider");
|
||||
}
|
||||
|
||||
@@ -86,9 +84,9 @@ class SslBuilderCustomizerTests {
|
||||
Ssl ssl = new Ssl();
|
||||
SslBuilderCustomizer customizer = new SslBuilderCustomizer(8080, InetAddress.getLocalHost(), ssl, null);
|
||||
assertThatIllegalStateException()
|
||||
.isThrownBy(() -> ReflectionTestUtils.invokeMethod(customizer, "getKeyManagers", ssl, null))
|
||||
.withCauseInstanceOf(WebServerException.class)
|
||||
.withMessageContaining("Could not load key store 'null'");
|
||||
.isThrownBy(() -> customizer.getKeyManagers(ssl, SslStoreProviderFactory.from(ssl)))
|
||||
.withCauseInstanceOf(IllegalStateException.class)
|
||||
.withMessageContaining("KeyStore location must not be empty or null");
|
||||
}
|
||||
|
||||
@Test
|
||||
@@ -100,9 +98,9 @@ class SslBuilderCustomizerTests {
|
||||
ssl.setKeyPassword("password");
|
||||
SslBuilderCustomizer customizer = new SslBuilderCustomizer(8080, InetAddress.getLocalHost(), ssl, null);
|
||||
assertThatIllegalStateException()
|
||||
.isThrownBy(() -> ReflectionTestUtils.invokeMethod(customizer, "getKeyManagers", ssl, null))
|
||||
.withCauseInstanceOf(IllegalArgumentException.class)
|
||||
.withMessageContaining("Input keystore location is not valid for keystore type 'PKCS11'");
|
||||
.isThrownBy(() -> customizer.getKeyManagers(ssl, SslStoreProviderFactory.from(ssl)))
|
||||
.withCauseInstanceOf(IllegalStateException.class)
|
||||
.withMessageContaining("must be empty or null for PKCS11 key stores");
|
||||
}
|
||||
|
||||
@Test
|
||||
@@ -112,8 +110,7 @@ class SslBuilderCustomizerTests {
|
||||
ssl.setKeyStoreProvider(MockPkcs11SecurityProvider.NAME);
|
||||
ssl.setKeyStorePassword("1234");
|
||||
SslBuilderCustomizer customizer = new SslBuilderCustomizer(8080, InetAddress.getLocalHost(), ssl, null);
|
||||
assertThatNoException()
|
||||
.isThrownBy(() -> ReflectionTestUtils.invokeMethod(customizer, "getKeyManagers", ssl, null));
|
||||
assertThatNoException().isThrownBy(() -> customizer.getKeyManagers(ssl, SslStoreProviderFactory.from(ssl)));
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -77,6 +77,7 @@ import org.springframework.web.reactive.function.client.WebClient;
|
||||
import org.springframework.web.reactive.function.client.WebClientRequestException;
|
||||
|
||||
import static org.assertj.core.api.Assertions.assertThat;
|
||||
import static org.assertj.core.api.Assertions.assertThatIllegalStateException;
|
||||
import static org.assertj.core.api.Assertions.assertThatThrownBy;
|
||||
|
||||
/**
|
||||
@@ -400,8 +401,8 @@ public abstract class AbstractReactiveWebServerFactoryTests {
|
||||
|
||||
@Test
|
||||
void whenSslIsEnabledAndNoKeyStoreIsConfiguredThenServerFailsToStart() {
|
||||
assertThatThrownBy(() -> testBasicSslWithKeyStore(null, null))
|
||||
.hasMessageContaining("Could not load key store 'null'");
|
||||
assertThatIllegalStateException().isThrownBy(() -> testBasicSslWithKeyStore(null, null))
|
||||
.withMessageContaining("KeyStore location must not be empty or null");
|
||||
}
|
||||
|
||||
@Test
|
||||
|
||||
@@ -0,0 +1,142 @@
|
||||
/*
|
||||
* Copyright 2012-2023 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.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* https://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package org.springframework.boot.web.server;
|
||||
|
||||
import java.security.KeyStore;
|
||||
import java.security.KeyStoreException;
|
||||
import java.security.NoSuchAlgorithmException;
|
||||
import java.security.NoSuchProviderException;
|
||||
import java.security.UnrecoverableKeyException;
|
||||
|
||||
import org.junit.jupiter.api.Test;
|
||||
|
||||
import org.springframework.boot.web.embedded.test.MockPkcs11Security;
|
||||
|
||||
import static org.assertj.core.api.Assertions.assertThat;
|
||||
import static org.assertj.core.api.Assertions.assertThatExceptionOfType;
|
||||
import static org.assertj.core.api.Assertions.assertThatIllegalStateException;
|
||||
|
||||
/**
|
||||
* Tests for {@link JavaKeyStoreSslStoreProvider}.
|
||||
*
|
||||
* @author Scott Frederick
|
||||
*/
|
||||
@MockPkcs11Security
|
||||
class JavaKeyStoreSslStoreProviderTests {
|
||||
|
||||
@Test
|
||||
void fromSslWhenNullReturnsNull() {
|
||||
assertThat(JavaKeyStoreSslStoreProvider.from(null)).isNull();
|
||||
}
|
||||
|
||||
@Test
|
||||
void fromSslWhenDisabledReturnsNull() {
|
||||
Ssl ssl = new Ssl();
|
||||
ssl.setEnabled(false);
|
||||
assertThat(JavaKeyStoreSslStoreProvider.from(ssl)).isNull();
|
||||
}
|
||||
|
||||
@Test
|
||||
void getKeyStoreWithNoLocationThrowsException() {
|
||||
Ssl ssl = new Ssl();
|
||||
SslStoreProvider storeProvider = JavaKeyStoreSslStoreProvider.from(ssl);
|
||||
assertThatIllegalStateException().isThrownBy(storeProvider::getKeyStore)
|
||||
.withMessageContaining("KeyStore location must not be empty or null");
|
||||
}
|
||||
|
||||
@Test
|
||||
void getKeyStoreWithTypePKCS11AndLocationThrowsException() {
|
||||
Ssl ssl = new Ssl();
|
||||
ssl.setKeyStore("test.jks");
|
||||
ssl.setKeyStoreType("PKCS11");
|
||||
SslStoreProvider storeProvider = JavaKeyStoreSslStoreProvider.from(ssl);
|
||||
assertThatIllegalStateException().isThrownBy(storeProvider::getKeyStore)
|
||||
.withMessageContaining("KeyStore location is 'test.jks', but must be empty or null for PKCS11 key stores");
|
||||
}
|
||||
|
||||
@Test
|
||||
void getKeyStoreWithLocationReturnsKeyStore() throws Exception {
|
||||
Ssl ssl = new Ssl();
|
||||
ssl.setKeyStore("classpath:test.jks");
|
||||
ssl.setKeyStorePassword("secret");
|
||||
SslStoreProvider storeProvider = JavaKeyStoreSslStoreProvider.from(ssl);
|
||||
assertThat(storeProvider).isNotNull();
|
||||
assertStoreContainsCertAndKey(storeProvider.getKeyStore(), "JKS", "test-alias", "password");
|
||||
}
|
||||
|
||||
@Test
|
||||
void getTrustStoreWithLocationsReturnsTrustStore() throws Exception {
|
||||
Ssl ssl = new Ssl();
|
||||
ssl.setTrustStore("classpath:test.jks");
|
||||
ssl.setKeyStorePassword("secret");
|
||||
SslStoreProvider storeProvider = JavaKeyStoreSslStoreProvider.from(ssl);
|
||||
assertThat(storeProvider).isNotNull();
|
||||
assertStoreContainsCertAndKey(storeProvider.getTrustStore(), "JKS", "test-alias", "password");
|
||||
}
|
||||
|
||||
@Test
|
||||
void getKeyStoreWithTypeUsesType() throws Exception {
|
||||
Ssl ssl = new Ssl();
|
||||
ssl.setKeyStore("classpath:test.jks");
|
||||
ssl.setKeyStorePassword("secret");
|
||||
ssl.setKeyStoreType("PKCS12");
|
||||
SslStoreProvider storeProvider = JavaKeyStoreSslStoreProvider.from(ssl);
|
||||
assertThat(storeProvider).isNotNull();
|
||||
assertStoreContainsCertAndKey(storeProvider.getKeyStore(), "PKCS12", "test-alias", "password");
|
||||
}
|
||||
|
||||
@Test
|
||||
void getTrustStoreWithTypeUsesType() throws Exception {
|
||||
Ssl ssl = new Ssl();
|
||||
ssl.setTrustStore("classpath:test.jks");
|
||||
ssl.setKeyStorePassword("secret");
|
||||
ssl.setTrustStoreType("PKCS12");
|
||||
SslStoreProvider storeProvider = JavaKeyStoreSslStoreProvider.from(ssl);
|
||||
assertThat(storeProvider).isNotNull();
|
||||
assertStoreContainsCertAndKey(storeProvider.getTrustStore(), "PKCS12", "test-alias", "password");
|
||||
}
|
||||
|
||||
@Test
|
||||
void getKeyStoreWithProviderUsesProvider() {
|
||||
Ssl ssl = new Ssl();
|
||||
ssl.setKeyStore("classpath:test.jks");
|
||||
ssl.setKeyStoreProvider("com.example.KeyStoreProvider");
|
||||
SslStoreProvider storeProvider = JavaKeyStoreSslStoreProvider.from(ssl);
|
||||
assertThatExceptionOfType(NoSuchProviderException.class).isThrownBy(storeProvider::getKeyStore)
|
||||
.withMessageContaining("com.example.KeyStoreProvider");
|
||||
}
|
||||
|
||||
@Test
|
||||
void getTrustStoreWithProviderUsesProvider() {
|
||||
Ssl ssl = new Ssl();
|
||||
ssl.setTrustStore("classpath:test.jks");
|
||||
ssl.setTrustStoreProvider("com.example.TrustStoreProvider");
|
||||
SslStoreProvider storeProvider = JavaKeyStoreSslStoreProvider.from(ssl);
|
||||
assertThatExceptionOfType(NoSuchProviderException.class).isThrownBy(storeProvider::getTrustStore)
|
||||
.withMessageContaining("com.example.TrustStoreProvider");
|
||||
}
|
||||
|
||||
private void assertStoreContainsCertAndKey(KeyStore keyStore, String keyStoreType, String keyAlias,
|
||||
String keyPassword) throws KeyStoreException, NoSuchAlgorithmException, UnrecoverableKeyException {
|
||||
assertThat(keyStore).isNotNull();
|
||||
assertThat(keyStore.getType()).isEqualTo(keyStoreType);
|
||||
assertThat(keyStore.containsAlias(keyAlias)).isTrue();
|
||||
assertThat(keyStore.getCertificate(keyAlias)).isNotNull();
|
||||
assertThat(keyStore.getKey(keyAlias, keyPassword.toCharArray())).isNotNull();
|
||||
}
|
||||
|
||||
}
|
||||
Reference in New Issue
Block a user