Skip to content

Commit 66db13b

Browse files
scottfrederickphilwebb
authored andcommitted
Refactor web server support to use SslBundles
Update Tomcat, Jetty, Undertow and Netty servers so that an SslBundle is used to apply SSL configuration. Existing `Ssl` properties are internally adapted to an `SslBundle` using the `WebServerSslBundle` class. Additionally, if `Ssl.getBundle()` returns a non-null value the the `SslBundles` bean will be used to find a registered bundle by name. See gh-34814
1 parent 8e1f24f commit 66db13b

File tree

48 files changed

+1025
-1759
lines changed

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

48 files changed

+1025
-1759
lines changed

spring-boot-project/spring-boot-actuator-autoconfigure/src/main/resources/META-INF/additional-spring-configuration-metadata.json

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2064,6 +2064,10 @@
20642064
"level": "error"
20652065
}
20662066
},
2067+
{
2068+
"name": "management.server.ssl.bundle",
2069+
"description": "The name of a configured SSL bundle."
2070+
},
20672071
{
20682072
"name": "management.server.ssl.certificate",
20692073
"description": "Path to a PEM-encoded SSL certificate file."

spring-boot-project/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/rsocket/RSocketServerAutoConfiguration.java

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -37,6 +37,7 @@
3737
import org.springframework.boot.rsocket.netty.NettyRSocketServerFactory;
3838
import org.springframework.boot.rsocket.server.RSocketServerCustomizer;
3939
import org.springframework.boot.rsocket.server.RSocketServerFactory;
40+
import org.springframework.boot.ssl.SslBundles;
4041
import org.springframework.context.annotation.Bean;
4142
import org.springframework.context.annotation.Conditional;
4243
import org.springframework.context.annotation.Configuration;
@@ -54,6 +55,7 @@
5455
* server port is configured, a new standalone RSocket server is created.
5556
*
5657
* @author Brian Clozel
58+
* @author Scott Frederick
5759
* @since 2.2.0
5860
*/
5961
@AutoConfiguration(after = RSocketStrategiesAutoConfiguration.class)
@@ -85,7 +87,7 @@ static class EmbeddedServerConfiguration {
8587
@Bean
8688
@ConditionalOnMissingBean
8789
RSocketServerFactory rSocketServerFactory(RSocketProperties properties, ReactorResourceFactory resourceFactory,
88-
ObjectProvider<RSocketServerCustomizer> customizers) {
90+
ObjectProvider<RSocketServerCustomizer> customizers, ObjectProvider<SslBundles> sslBundles) {
8991
NettyRSocketServerFactory factory = new NettyRSocketServerFactory();
9092
factory.setResourceFactory(resourceFactory);
9193
factory.setTransport(properties.getServer().getTransport());
@@ -94,6 +96,7 @@ RSocketServerFactory rSocketServerFactory(RSocketProperties properties, ReactorR
9496
map.from(properties.getServer().getPort()).to(factory::setPort);
9597
map.from(properties.getServer().getFragmentSize()).to(factory::setFragmentSize);
9698
map.from(properties.getServer().getSsl()).to(factory::setSsl);
99+
factory.setSslBundles(sslBundles.getIfAvailable());
97100
factory.setRSocketServerCustomizers(customizers.orderedStream().toList());
98101
return factory;
99102
}

spring-boot-project/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/web/reactive/ReactiveWebServerFactoryAutoConfiguration.java

Lines changed: 6 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -19,6 +19,7 @@
1919
import org.springframework.beans.BeansException;
2020
import org.springframework.beans.factory.BeanFactory;
2121
import org.springframework.beans.factory.BeanFactoryAware;
22+
import org.springframework.beans.factory.ObjectProvider;
2223
import org.springframework.beans.factory.config.ConfigurableListableBeanFactory;
2324
import org.springframework.beans.factory.support.BeanDefinitionRegistry;
2425
import org.springframework.beans.factory.support.RootBeanDefinition;
@@ -31,6 +32,7 @@
3132
import org.springframework.boot.autoconfigure.condition.ConditionalOnWebApplication;
3233
import org.springframework.boot.autoconfigure.web.ServerProperties;
3334
import org.springframework.boot.context.properties.EnableConfigurationProperties;
35+
import org.springframework.boot.ssl.SslBundles;
3436
import org.springframework.boot.web.server.WebServerFactoryCustomizerBeanPostProcessor;
3537
import org.springframework.context.annotation.Bean;
3638
import org.springframework.context.annotation.Import;
@@ -45,6 +47,7 @@
4547
* {@link EnableAutoConfiguration Auto-configuration} for a reactive web server.
4648
*
4749
* @author Brian Clozel
50+
* @author Scott Frederick
4851
* @since 2.0.0
4952
*/
5053
@AutoConfigureOrder(Ordered.HIGHEST_PRECEDENCE)
@@ -60,8 +63,9 @@
6063
public class ReactiveWebServerFactoryAutoConfiguration {
6164

6265
@Bean
63-
public ReactiveWebServerFactoryCustomizer reactiveWebServerFactoryCustomizer(ServerProperties serverProperties) {
64-
return new ReactiveWebServerFactoryCustomizer(serverProperties);
66+
public ReactiveWebServerFactoryCustomizer reactiveWebServerFactoryCustomizer(ServerProperties serverProperties,
67+
ObjectProvider<SslBundles> sslBundles) {
68+
return new ReactiveWebServerFactoryCustomizer(serverProperties, sslBundles.getIfAvailable());
6569
}
6670

6771
@Bean

spring-boot-project/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/web/reactive/ReactiveWebServerFactoryCustomizer.java

Lines changed: 21 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
/*
2-
* Copyright 2012-2020 the original author or authors.
2+
* Copyright 2012-2023 the original author or authors.
33
*
44
* Licensed under the Apache License, Version 2.0 (the "License");
55
* you may not use this file except in compliance with the License.
@@ -18,6 +18,7 @@
1818

1919
import org.springframework.boot.autoconfigure.web.ServerProperties;
2020
import org.springframework.boot.context.properties.PropertyMapper;
21+
import org.springframework.boot.ssl.SslBundles;
2122
import org.springframework.boot.web.reactive.server.ConfigurableReactiveWebServerFactory;
2223
import org.springframework.boot.web.server.WebServerFactoryCustomizer;
2324
import org.springframework.core.Ordered;
@@ -28,15 +29,33 @@
2829
*
2930
* @author Brian Clozel
3031
* @author Yunkun Huang
32+
* @author Scott Frederick
3133
* @since 2.0.0
3234
*/
3335
public class ReactiveWebServerFactoryCustomizer
3436
implements WebServerFactoryCustomizer<ConfigurableReactiveWebServerFactory>, Ordered {
3537

3638
private final ServerProperties serverProperties;
3739

40+
private final SslBundles sslBundles;
41+
42+
/**
43+
* Create a new {@link ReactiveWebServerFactoryCustomizer} instance.
44+
* @param serverProperties the server properties
45+
*/
3846
public ReactiveWebServerFactoryCustomizer(ServerProperties serverProperties) {
47+
this(serverProperties, null);
48+
}
49+
50+
/**
51+
* Create a new {@link ReactiveWebServerFactoryCustomizer} instance.
52+
* @param serverProperties the server properties
53+
* @param sslBundles the SSL bundles
54+
* @since 3.1.0
55+
*/
56+
public ReactiveWebServerFactoryCustomizer(ServerProperties serverProperties, SslBundles sslBundles) {
3957
this.serverProperties = serverProperties;
58+
this.sslBundles = sslBundles;
4059
}
4160

4261
@Override
@@ -53,6 +72,7 @@ public void customize(ConfigurableReactiveWebServerFactory factory) {
5372
map.from(this.serverProperties::getCompression).to(factory::setCompression);
5473
map.from(this.serverProperties::getHttp2).to(factory::setHttp2);
5574
map.from(this.serverProperties.getShutdown()).to(factory::setShutdown);
75+
map.from(() -> this.sslBundles).to(factory::setSslBundles);
5676
}
5777

5878
}

spring-boot-project/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/web/servlet/ServletWebServerFactoryAutoConfiguration.java

Lines changed: 6 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -33,8 +33,10 @@
3333
import org.springframework.boot.autoconfigure.condition.ConditionalOnProperty;
3434
import org.springframework.boot.autoconfigure.condition.ConditionalOnWebApplication;
3535
import org.springframework.boot.autoconfigure.condition.ConditionalOnWebApplication.Type;
36+
import org.springframework.boot.autoconfigure.ssl.SslAutoConfiguration;
3637
import org.springframework.boot.autoconfigure.web.ServerProperties;
3738
import org.springframework.boot.context.properties.EnableConfigurationProperties;
39+
import org.springframework.boot.ssl.SslBundles;
3840
import org.springframework.boot.web.server.ErrorPageRegistrarBeanPostProcessor;
3941
import org.springframework.boot.web.server.WebServerFactoryCustomizerBeanPostProcessor;
4042
import org.springframework.boot.web.servlet.FilterRegistrationBean;
@@ -57,9 +59,10 @@
5759
* @author Ivan Sopov
5860
* @author Brian Clozel
5961
* @author Stephane Nicoll
62+
* @author Scott Frederick
6063
* @since 2.0.0
6164
*/
62-
@AutoConfiguration
65+
@AutoConfiguration(after = SslAutoConfiguration.class)
6366
@AutoConfigureOrder(Ordered.HIGHEST_PRECEDENCE)
6467
@ConditionalOnClass(ServletRequest.class)
6568
@ConditionalOnWebApplication(type = Type.SERVLET)
@@ -73,9 +76,9 @@ public class ServletWebServerFactoryAutoConfiguration {
7376
@Bean
7477
public ServletWebServerFactoryCustomizer servletWebServerFactoryCustomizer(ServerProperties serverProperties,
7578
ObjectProvider<WebListenerRegistrar> webListenerRegistrars,
76-
ObjectProvider<CookieSameSiteSupplier> cookieSameSiteSuppliers) {
79+
ObjectProvider<CookieSameSiteSupplier> cookieSameSiteSuppliers, ObjectProvider<SslBundles> sslBundles) {
7780
return new ServletWebServerFactoryCustomizer(serverProperties, webListenerRegistrars.orderedStream().toList(),
78-
cookieSameSiteSuppliers.orderedStream().toList());
81+
cookieSameSiteSuppliers.orderedStream().toList(), sslBundles.getIfAvailable());
7982
}
8083

8184
@Bean

spring-boot-project/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/web/servlet/ServletWebServerFactoryCustomizer.java

Lines changed: 14 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
/*
2-
* Copyright 2012-2021 the original author or authors.
2+
* Copyright 2012-2023 the original author or authors.
33
*
44
* Licensed under the Apache License, Version 2.0 (the "License");
55
* you may not use this file except in compliance with the License.
@@ -21,6 +21,7 @@
2121

2222
import org.springframework.boot.autoconfigure.web.ServerProperties;
2323
import org.springframework.boot.context.properties.PropertyMapper;
24+
import org.springframework.boot.ssl.SslBundles;
2425
import org.springframework.boot.web.server.WebServerFactoryCustomizer;
2526
import org.springframework.boot.web.servlet.WebListenerRegistrar;
2627
import org.springframework.boot.web.servlet.server.ConfigurableServletWebServerFactory;
@@ -36,6 +37,7 @@
3637
* @author Stephane Nicoll
3738
* @author Olivier Lamy
3839
* @author Yunkun Huang
40+
* @author Scott Frederick
3941
* @since 2.0.0
4042
*/
4143
public class ServletWebServerFactoryCustomizer
@@ -47,20 +49,24 @@ public class ServletWebServerFactoryCustomizer
4749

4850
private final List<CookieSameSiteSupplier> cookieSameSiteSuppliers;
4951

52+
private final SslBundles sslBundles;
53+
5054
public ServletWebServerFactoryCustomizer(ServerProperties serverProperties) {
5155
this(serverProperties, Collections.emptyList());
5256
}
5357

5458
public ServletWebServerFactoryCustomizer(ServerProperties serverProperties,
5559
List<WebListenerRegistrar> webListenerRegistrars) {
56-
this(serverProperties, webListenerRegistrars, null);
60+
this(serverProperties, webListenerRegistrars, null, null);
5761
}
5862

5963
ServletWebServerFactoryCustomizer(ServerProperties serverProperties,
60-
List<WebListenerRegistrar> webListenerRegistrars, List<CookieSameSiteSupplier> cookieSameSiteSuppliers) {
64+
List<WebListenerRegistrar> webListenerRegistrars, List<CookieSameSiteSupplier> cookieSameSiteSuppliers,
65+
SslBundles sslBundles) {
6166
this.serverProperties = serverProperties;
6267
this.webListenerRegistrars = webListenerRegistrars;
6368
this.cookieSameSiteSuppliers = cookieSameSiteSuppliers;
69+
this.sslBundles = sslBundles;
6470
}
6571

6672
@Override
@@ -84,12 +90,11 @@ public void customize(ConfigurableServletWebServerFactory factory) {
8490
map.from(this.serverProperties::getServerHeader).to(factory::setServerHeader);
8591
map.from(this.serverProperties.getServlet()::getContextParameters).to(factory::setInitParameters);
8692
map.from(this.serverProperties.getShutdown()).to(factory::setShutdown);
87-
for (WebListenerRegistrar registrar : this.webListenerRegistrars) {
88-
registrar.register(factory);
89-
}
90-
if (!CollectionUtils.isEmpty(this.cookieSameSiteSuppliers)) {
91-
factory.setCookieSameSiteSuppliers(this.cookieSameSiteSuppliers);
92-
}
93+
map.from(() -> this.sslBundles).to(factory::setSslBundles);
94+
map.from(() -> this.cookieSameSiteSuppliers)
95+
.whenNot(CollectionUtils::isEmpty)
96+
.to(factory::setCookieSameSiteSuppliers);
97+
this.webListenerRegistrars.forEach((registrar) -> registrar.register(factory));
9398
}
9499

95100
}

spring-boot-project/spring-boot-autoconfigure/src/main/resources/META-INF/additional-spring-configuration-metadata.json

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2639,6 +2639,10 @@
26392639
"level": "error"
26402640
}
26412641
},
2642+
{
2643+
"name": "spring.rsocket.server.ssl.bundle",
2644+
"description": "The name of a configured SSL bundle."
2645+
},
26422646
{
26432647
"name": "spring.rsocket.server.ssl.certificate",
26442648
"description": "Path to a PEM-encoded SSL certificate file."

spring-boot-project/spring-boot-autoconfigure/src/test/java/org/springframework/boot/autoconfigure/rsocket/RSocketServerAutoConfigurationTests.java

Lines changed: 31 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -16,13 +16,16 @@
1616

1717
package org.springframework.boot.autoconfigure.rsocket;
1818

19+
import org.junit.jupiter.api.Disabled;
1920
import org.junit.jupiter.api.Test;
2021

2122
import org.springframework.boot.autoconfigure.AutoConfigurations;
23+
import org.springframework.boot.autoconfigure.ssl.SslAutoConfiguration;
2224
import org.springframework.boot.rsocket.context.RSocketPortInfoApplicationContextInitializer;
2325
import org.springframework.boot.rsocket.context.RSocketServerBootstrap;
2426
import org.springframework.boot.rsocket.server.RSocketServerCustomizer;
2527
import org.springframework.boot.rsocket.server.RSocketServerFactory;
28+
import org.springframework.boot.ssl.NoSuchSslBundleException;
2629
import org.springframework.boot.test.context.FilteredClassLoader;
2730
import org.springframework.boot.test.context.runner.ApplicationContextRunner;
2831
import org.springframework.boot.test.context.runner.ReactiveWebApplicationContextRunner;
@@ -44,6 +47,7 @@
4447
*
4548
* @author Brian Clozel
4649
* @author Verónica Vásquez
50+
* @author Scott Frederick
4751
*/
4852
class RSocketServerAutoConfigurationTests {
4953

@@ -134,6 +138,32 @@ void shouldUseSslWhenRocketServerSslIsConfigured() {
134138
.hasFieldOrPropertyWithValue("ssl.keyPassword", "password"));
135139
}
136140

141+
@Test
142+
@Disabled
143+
void shouldUseSslWhenRocketServerSslIsConfiguredWithSslBundle() {
144+
reactiveWebContextRunner()
145+
.withPropertyValues("spring.rsocket.server.port=0", "spring.rsocket.server.ssl.bundle=test-bundle",
146+
"spring.ssl.bundle.jks.test-bundle.keystore.location=classpath:rsocket/test.jks",
147+
"spring.ssl.bundle.jks.test-bundle.key.password=password")
148+
.run((context) -> assertThat(context).hasSingleBean(RSocketServerFactory.class)
149+
.hasSingleBean(RSocketServerBootstrap.class)
150+
.hasSingleBean(RSocketServerCustomizer.class)
151+
.getBean(RSocketServerFactory.class)
152+
.hasFieldOrPropertyWithValue("sslBundle.details.keyStore", "classpath:rsocket/test.jks")
153+
.hasFieldOrPropertyWithValue("sslBundle.details.keyPassword", "password"));
154+
}
155+
156+
@Test
157+
void shouldFailWhenSslIsConfiguredWithMissingBundle() {
158+
reactiveWebContextRunner()
159+
.withPropertyValues("spring.rsocket.server.port=0", "spring.rsocket.server.ssl.bundle=test-bundle")
160+
.run((context) -> {
161+
assertThat(context).hasFailed();
162+
assertThat(context.getStartupFailure()).hasRootCauseInstanceOf(NoSuchSslBundleException.class)
163+
.withFailMessage("SSL bundle name 'test-bundle' is not valid");
164+
});
165+
}
166+
137167
@Test
138168
void shouldUseCustomServerBootstrap() {
139169
contextRunner().withUserConfiguration(CustomServerBootstrapConfig.class)
@@ -164,7 +194,7 @@ private ApplicationContextRunner contextRunner() {
164194

165195
private ReactiveWebApplicationContextRunner reactiveWebContextRunner() {
166196
return new ReactiveWebApplicationContextRunner().withUserConfiguration(BaseConfiguration.class)
167-
.withConfiguration(AutoConfigurations.of(RSocketServerAutoConfiguration.class));
197+
.withConfiguration(AutoConfigurations.of(RSocketServerAutoConfiguration.class, SslAutoConfiguration.class));
168198
}
169199

170200
@Configuration(proxyBeanMethods = false)

spring-boot-project/spring-boot-autoconfigure/src/test/java/org/springframework/boot/autoconfigure/web/reactive/ReactiveWebServerFactoryAutoConfigurationTests.java

Lines changed: 16 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -26,6 +26,8 @@
2626
import reactor.netty.http.server.HttpServer;
2727

2828
import org.springframework.boot.autoconfigure.AutoConfigurations;
29+
import org.springframework.boot.autoconfigure.ssl.SslAutoConfiguration;
30+
import org.springframework.boot.ssl.NoSuchSslBundleException;
2931
import org.springframework.boot.test.context.FilteredClassLoader;
3032
import org.springframework.boot.test.context.runner.ReactiveWebApplicationContextRunner;
3133
import org.springframework.boot.testsupport.web.servlet.DirtiesUrlFactories;
@@ -64,13 +66,15 @@
6466
* @author Brian Clozel
6567
* @author Raheela Aslam
6668
* @author Madhura Bhave
69+
* @author Scott Frederick
6770
*/
6871
@DirtiesUrlFactories
6972
class ReactiveWebServerFactoryAutoConfigurationTests {
7073

7174
private final ReactiveWebApplicationContextRunner contextRunner = new ReactiveWebApplicationContextRunner(
7275
AnnotationConfigReactiveWebServerApplicationContext::new)
73-
.withConfiguration(AutoConfigurations.of(ReactiveWebServerFactoryAutoConfiguration.class));
76+
.withConfiguration(
77+
AutoConfigurations.of(ReactiveWebServerFactoryAutoConfiguration.class, SslAutoConfiguration.class));
7478

7579
@Test
7680
void createFromConfigClass() {
@@ -118,6 +122,17 @@ void defaultWebServerIsTomcat() {
118122
.isInstanceOf(TomcatReactiveWebServerFactory.class));
119123
}
120124

125+
@Test
126+
void webServerFailsWithInvalidSslBundle() {
127+
this.contextRunner.withUserConfiguration(HttpHandlerConfiguration.class)
128+
.withPropertyValues("server.port=0", "server.ssl.bundle=test-bundle")
129+
.run((context) -> {
130+
assertThat(context).hasFailed();
131+
assertThat(context.getStartupFailure().getCause()).isInstanceOf(NoSuchSslBundleException.class)
132+
.withFailMessage("test");
133+
});
134+
}
135+
121136
@Test
122137
void tomcatConnectorCustomizerBeanIsAddedToFactory() {
123138
ReactiveWebApplicationContextRunner runner = new ReactiveWebApplicationContextRunner(

0 commit comments

Comments
 (0)