mirror of
https://github.com/spring-projects/spring-boot.git
synced 2026-09-17 12:09:16 +00:00
Merge branch '4.0.x' into 4.1.x
Closes gh-51457
This commit is contained in:
+31
-7
@@ -17,8 +17,10 @@
|
||||
package org.springframework.boot.tomcat;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.Arrays;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.Set;
|
||||
|
||||
import org.apache.catalina.connector.Connector;
|
||||
import org.apache.commons.logging.Log;
|
||||
@@ -64,9 +66,15 @@ public class SslConnectorCustomizer {
|
||||
|
||||
public void update(@Nullable String serverName, SslBundle updatedSslBundle) {
|
||||
AbstractHttp11Protocol<?> protocol = (AbstractHttp11Protocol<?>) this.connector.getProtocolHandler();
|
||||
String host = (serverName != null) ? serverName : protocol.getDefaultSSLHostConfigName();
|
||||
this.logger.debug("SSL Bundle for host " + host + " has been updated, reloading SSL configuration");
|
||||
addSslHostConfig(protocol, host, updatedSslBundle);
|
||||
String hostName = (serverName != null) ? serverName : protocol.getDefaultSSLHostConfigName();
|
||||
this.logger.debug("SSL Bundle for host " + hostName + " has been updated, reloading SSL configuration");
|
||||
SSLHostConfig sslHostConfig = findSslHostConfig(protocol, hostName);
|
||||
if (sslHostConfig == null) {
|
||||
addSslHostConfig(protocol, hostName, updatedSslBundle);
|
||||
return;
|
||||
}
|
||||
applySslBundle(protocol, sslHostConfig, updatedSslBundle);
|
||||
protocol.addSslHostConfig(sslHostConfig, true);
|
||||
}
|
||||
|
||||
public void customize(SslBundle sslBundle, Map<String, SslBundle> serverNameSslBundles) {
|
||||
@@ -93,20 +101,27 @@ public class SslConnectorCustomizer {
|
||||
serverNameSslBundles.forEach((serverName, bundle) -> addSslHostConfig(protocol, serverName, bundle));
|
||||
}
|
||||
|
||||
private void addSslHostConfig(AbstractHttp11Protocol<?> protocol, String serverName, SslBundle sslBundle) {
|
||||
private void addSslHostConfig(AbstractHttp11Protocol<?> protocol, String hostName, SslBundle sslBundle) {
|
||||
SSLHostConfig sslHostConfig = new SSLHostConfig();
|
||||
sslHostConfig.setHostName(serverName);
|
||||
sslHostConfig.setHostName(hostName);
|
||||
configureSslClientAuth(sslHostConfig);
|
||||
applySslBundle(protocol, sslHostConfig, sslBundle);
|
||||
protocol.addSslHostConfig(sslHostConfig, true);
|
||||
}
|
||||
|
||||
private @Nullable SSLHostConfig findSslHostConfig(AbstractHttp11Protocol<?> protocol, String hostName) {
|
||||
return Arrays.stream(protocol.findSslHostConfigs())
|
||||
.filter((candidate) -> hostName.equalsIgnoreCase(candidate.getHostName()))
|
||||
.findFirst()
|
||||
.orElse(null);
|
||||
}
|
||||
|
||||
private void applySslBundle(AbstractHttp11Protocol<?> protocol, SSLHostConfig sslHostConfig, SslBundle sslBundle) {
|
||||
SslBundleKey key = sslBundle.getKey();
|
||||
SslStoreBundle stores = sslBundle.getStores();
|
||||
SslOptions options = sslBundle.getOptions();
|
||||
sslHostConfig.setSslProtocol(sslBundle.getProtocol());
|
||||
SSLHostConfigCertificate certificate = new SSLHostConfigCertificate(sslHostConfig, Type.UNDEFINED);
|
||||
SSLHostConfigCertificate certificate = getCertificate(sslHostConfig);
|
||||
String keystorePassword = (stores.getKeyStorePassword() != null) ? stores.getKeyStorePassword() : "";
|
||||
certificate.setCertificateKeystorePassword(keystorePassword);
|
||||
if (key.getPassword() != null) {
|
||||
@@ -115,12 +130,21 @@ public class SslConnectorCustomizer {
|
||||
if (key.getAlias() != null) {
|
||||
certificate.setCertificateKeyAlias(key.getAlias());
|
||||
}
|
||||
sslHostConfig.addCertificate(certificate);
|
||||
configureCiphers(options, sslHostConfig);
|
||||
configureSslStores(sslHostConfig, certificate, stores);
|
||||
configureEnabledProtocols(sslHostConfig, options);
|
||||
}
|
||||
|
||||
private SSLHostConfigCertificate getCertificate(SSLHostConfig sslHostConfig) {
|
||||
Set<SSLHostConfigCertificate> certificates = sslHostConfig.getCertificates();
|
||||
if (certificates.size() == 1) {
|
||||
return certificates.iterator().next();
|
||||
}
|
||||
SSLHostConfigCertificate certificate = new SSLHostConfigCertificate(sslHostConfig, Type.UNDEFINED);
|
||||
sslHostConfig.addCertificate(certificate);
|
||||
return certificate;
|
||||
}
|
||||
|
||||
private void configureCiphers(SslOptions options, SSLHostConfig sslHostConfig) {
|
||||
CipherConfiguration cipherConfiguration = CipherConfiguration.from(options);
|
||||
if (cipherConfiguration != null) {
|
||||
|
||||
+42
@@ -22,6 +22,7 @@ import org.apache.catalina.connector.Connector;
|
||||
import org.apache.catalina.startup.Tomcat;
|
||||
import org.apache.commons.logging.Log;
|
||||
import org.apache.commons.logging.LogFactory;
|
||||
import org.apache.coyote.http11.AbstractHttp11Protocol;
|
||||
import org.apache.tomcat.util.net.SSLHostConfig;
|
||||
import org.apache.tomcat.util.net.openssl.ciphers.Cipher;
|
||||
import org.junit.jupiter.api.AfterEach;
|
||||
@@ -157,6 +158,47 @@ class SslConnectorCustomizerTests {
|
||||
assertThat(sslHostConfig.getEnabledProtocols()).containsExactly("TLSv1.2");
|
||||
}
|
||||
|
||||
@Test
|
||||
@WithPackageResources("test.jks")
|
||||
void updateRetainsCustomizationsAppliedToSslHostConfig() {
|
||||
Ssl ssl = new Ssl();
|
||||
ssl.setKeyPassword("password");
|
||||
ssl.setKeyStore("classpath:test.jks");
|
||||
Connector connector = this.tomcat.getConnector();
|
||||
AbstractHttp11Protocol<?> protocol = (AbstractHttp11Protocol<?>) connector.getProtocolHandler();
|
||||
SslConnectorCustomizer customizer = new SslConnectorCustomizer(this.logger, connector, ssl.getClientAuth());
|
||||
customizer.customize(WebServerSslBundle.get(ssl), Collections.emptyMap());
|
||||
SSLHostConfig sslHostConfig = protocol.findSslHostConfigs()[0];
|
||||
sslHostConfig.setTruststoreProvider(MockPkcs11SecurityProvider.NAME);
|
||||
customizer.update(null, WebServerSslBundle.get(ssl));
|
||||
assertThat(protocol.findSslHostConfigs()).hasSize(1);
|
||||
SSLHostConfig updated = protocol.findSslHostConfigs()[0];
|
||||
assertThat(updated.getTruststoreProvider()).isEqualTo(MockPkcs11SecurityProvider.NAME);
|
||||
assertThat(updated.getCertificates()).hasSize(1);
|
||||
}
|
||||
|
||||
@Test
|
||||
@WithPackageResources("test.jks")
|
||||
void updateAppliesUpdatedBundleToExistingSslHostConfig() throws Exception {
|
||||
Ssl ssl = new Ssl();
|
||||
ssl.setKeyPassword("password");
|
||||
ssl.setKeyStore("classpath:test.jks");
|
||||
ssl.setEnabledProtocols(new String[] { "TLSv1.2" });
|
||||
Connector connector = this.tomcat.getConnector();
|
||||
AbstractHttp11Protocol<?> protocol = (AbstractHttp11Protocol<?>) connector.getProtocolHandler();
|
||||
SslConnectorCustomizer customizer = new SslConnectorCustomizer(this.logger, connector, ssl.getClientAuth());
|
||||
customizer.customize(WebServerSslBundle.get(ssl), Collections.emptyMap());
|
||||
this.tomcat.start();
|
||||
assertThat(protocol.findSslHostConfigs()[0].getEnabledProtocols()).containsExactly("TLSv1.2");
|
||||
Ssl updatedSsl = new Ssl();
|
||||
updatedSsl.setKeyPassword("password");
|
||||
updatedSsl.setKeyStore("classpath:test.jks");
|
||||
updatedSsl.setEnabledProtocols(new String[] { "TLSv1.3" });
|
||||
customizer.update(null, WebServerSslBundle.get(updatedSsl));
|
||||
SSLHostConfig sslHostConfig = protocol.findSslHostConfigs()[0];
|
||||
assertThat(sslHostConfig.getEnabledProtocols()).containsExactly("TLSv1.3");
|
||||
}
|
||||
|
||||
@Test
|
||||
void customizeWhenSslIsEnabledWithNoKeyStoreAndNotPkcs11ThrowsException() {
|
||||
assertThatIllegalStateException().isThrownBy(() -> {
|
||||
|
||||
+28
@@ -72,6 +72,7 @@ import org.apache.hc.core5.ssl.SSLContextBuilder;
|
||||
import org.apache.jasper.servlet.JspServlet;
|
||||
import org.apache.tomcat.JarScanFilter;
|
||||
import org.apache.tomcat.JarScanType;
|
||||
import org.apache.tomcat.util.net.SSLHostConfig;
|
||||
import org.apache.tomcat.util.scan.StandardJarScanFilter;
|
||||
import org.assertj.core.api.ThrowableAssert.ThrowingCallable;
|
||||
import org.awaitility.Awaitility;
|
||||
@@ -700,6 +701,33 @@ class TomcatServletWebServerFactoryTests extends AbstractServletWebServerFactory
|
||||
assertThat(verifier.getLastPrincipal()).isEqualTo("CN=2");
|
||||
}
|
||||
|
||||
@Test
|
||||
@WithPackageResources({ "1.crt", "1.key", "2.crt", "2.key" })
|
||||
void shouldRetainSslHostConfigCustomizationsWhenReloadingSslBundles() throws Exception {
|
||||
TomcatServletWebServerFactory factory = getFactory();
|
||||
addTestTxtFile(factory);
|
||||
DefaultSslBundleRegistry bundles = new DefaultSslBundleRegistry("test",
|
||||
createPemSslBundle("classpath:1.crt", "classpath:1.key"));
|
||||
factory.setSslBundles(bundles);
|
||||
factory.setSsl(Ssl.forBundle("test"));
|
||||
factory.addConnectorCustomizers((connector) -> {
|
||||
if (connector.getProtocolHandler() instanceof AbstractHttp11Protocol<?> protocol) {
|
||||
for (SSLHostConfig sslHostConfig : protocol.findSslHostConfigs()) {
|
||||
sslHostConfig.setSessionTimeout(12345);
|
||||
}
|
||||
}
|
||||
});
|
||||
this.webServer = factory.getWebServer();
|
||||
this.webServer.start();
|
||||
bundles.updateBundle("test", createPemSslBundle("classpath:2.crt", "classpath:2.key"));
|
||||
Connector connector = ((TomcatWebServer) this.webServer).getTomcat().getConnector();
|
||||
AbstractHttp11Protocol<?> protocol = (AbstractHttp11Protocol<?>) connector.getProtocolHandler();
|
||||
assertThat(protocol.findSslHostConfigs()).hasSize(1);
|
||||
SSLHostConfig sslHostConfig = protocol.findSslHostConfigs()[0];
|
||||
assertThat(sslHostConfig.getSessionTimeout()).isEqualTo(12345);
|
||||
assertThat(sslHostConfig.getCertificates()).hasSize(1);
|
||||
}
|
||||
|
||||
@Test
|
||||
@WithPackageResources("test.jks")
|
||||
void sslWithHttp11Nio2Protocol() throws Exception {
|
||||
|
||||
Reference in New Issue
Block a user