Skip to content

Commit 7f58db7

Browse files
committed
Apply TLS configuration to reactive web servers
This commit applies the SSL configuration to the following reactive web servers: Jetty, Tomcat, Undertow, Reactor Netty. Closes gh-9431
1 parent 5f57578 commit 7f58db7

17 files changed

+1009
-532
lines changed

spring-boot-project/spring-boot/src/main/java/org/springframework/boot/web/embedded/jetty/JettyReactiveWebServerFactory.java

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -97,11 +97,13 @@ protected Server createJettyServer(JettyHttpHandlerAdapter servlet) {
9797
ServletContextHandler contextHandler = new ServletContextHandler(server, "",
9898
false, false);
9999
contextHandler.addServlet(servletHolder, "/");
100+
this.logger.info("Server initialized with port: " + port);
101+
SslServerCustomizer sslServerCustomizer = new SslServerCustomizer(port,
102+
getSsl(), getSslStoreProvider());
103+
sslServerCustomizer.customize(server);
100104
for (JettyServerCustomizer customizer : getServerCustomizers()) {
101105
customizer.customize(server);
102106
}
103-
JettyReactiveWebServerFactory.logger
104-
.info("Server initialized with port: " + port);
105107
return server;
106108
}
107109

spring-boot-project/spring-boot/src/main/java/org/springframework/boot/web/embedded/jetty/JettyServletWebServerFactory.java

Lines changed: 5 additions & 123 deletions
Original file line numberDiff line numberDiff line change
@@ -36,20 +36,16 @@
3636
import javax.servlet.http.HttpServletResponse;
3737

3838
import org.eclipse.jetty.http.HttpMethod;
39-
import org.eclipse.jetty.http.HttpVersion;
4039
import org.eclipse.jetty.http.MimeTypes;
4140
import org.eclipse.jetty.server.AbstractConnector;
4241
import org.eclipse.jetty.server.ConnectionFactory;
4342
import org.eclipse.jetty.server.Connector;
4443
import org.eclipse.jetty.server.ForwardedRequestCustomizer;
4544
import org.eclipse.jetty.server.Handler;
4645
import org.eclipse.jetty.server.HttpConfiguration;
47-
import org.eclipse.jetty.server.HttpConnectionFactory;
4846
import org.eclipse.jetty.server.Request;
49-
import org.eclipse.jetty.server.SecureRequestCustomizer;
5047
import org.eclipse.jetty.server.Server;
5148
import org.eclipse.jetty.server.ServerConnector;
52-
import org.eclipse.jetty.server.SslConnectionFactory;
5349
import org.eclipse.jetty.server.handler.ErrorHandler;
5450
import org.eclipse.jetty.server.handler.HandlerWrapper;
5551
import org.eclipse.jetty.server.handler.gzip.GzipHandler;
@@ -62,7 +58,6 @@
6258
import org.eclipse.jetty.util.resource.JarResource;
6359
import org.eclipse.jetty.util.resource.Resource;
6460
import org.eclipse.jetty.util.resource.ResourceCollection;
65-
import org.eclipse.jetty.util.ssl.SslContextFactory;
6661
import org.eclipse.jetty.util.thread.ThreadPool;
6762
import org.eclipse.jetty.webapp.AbstractConfiguration;
6863
import org.eclipse.jetty.webapp.Configuration;
@@ -71,18 +66,13 @@
7166
import org.springframework.boot.web.server.Compression;
7267
import org.springframework.boot.web.server.ErrorPage;
7368
import org.springframework.boot.web.server.MimeMappings;
74-
import org.springframework.boot.web.server.Ssl;
75-
import org.springframework.boot.web.server.Ssl.ClientAuth;
7669
import org.springframework.boot.web.server.WebServer;
77-
import org.springframework.boot.web.server.WebServerException;
7870
import org.springframework.boot.web.servlet.ServletContextInitializer;
7971
import org.springframework.boot.web.servlet.server.AbstractServletWebServerFactory;
8072
import org.springframework.boot.web.servlet.server.ServletWebServerFactory;
8173
import org.springframework.context.ResourceLoaderAware;
8274
import org.springframework.core.io.ResourceLoader;
8375
import org.springframework.util.Assert;
84-
import org.springframework.util.ObjectUtils;
85-
import org.springframework.util.ResourceUtils;
8676
import org.springframework.util.StringUtils;
8777

8878
/**
@@ -163,13 +153,9 @@ public WebServer getWebServer(ServletContextInitializer... initializers) {
163153
configureWebAppContext(context, initializers);
164154
server.setHandler(addHandlerWrappers(context));
165155
this.logger.info("Server initialized with port: " + port);
166-
if (getSsl() != null && getSsl().isEnabled()) {
167-
SslContextFactory sslContextFactory = new SslContextFactory();
168-
configureSsl(sslContextFactory, getSsl());
169-
AbstractConnector connector = createSslConnector(server, sslContextFactory,
170-
port);
171-
server.setConnectors(new Connector[] { connector });
172-
}
156+
SslServerCustomizer sslServerCustomizer = new SslServerCustomizer(port,
157+
getSsl(), getSslStoreProvider());
158+
sslServerCustomizer.customize(server);
173159
for (JettyServerCustomizer customizer : getServerCustomizers()) {
174160
customizer.customize(server);
175161
}
@@ -181,7 +167,7 @@ public WebServer getWebServer(ServletContextInitializer... initializers) {
181167

182168
private Server createServer(InetSocketAddress address) {
183169
Server server = new Server(getThreadPool());
184-
server.setConnectors(new Connector[] { createConnector(address, server) });
170+
server.setConnectors(new Connector[] {createConnector(address, server)});
185171
return server;
186172
}
187173

@@ -199,20 +185,6 @@ private AbstractConnector createConnector(InetSocketAddress address, Server serv
199185
return connector;
200186
}
201187

202-
private AbstractConnector createSslConnector(Server server,
203-
SslContextFactory sslContextFactory, int port) {
204-
HttpConfiguration config = new HttpConfiguration();
205-
config.setSendServerVersion(false);
206-
config.addCustomizer(new SecureRequestCustomizer());
207-
HttpConnectionFactory connectionFactory = new HttpConnectionFactory(config);
208-
SslConnectionFactory sslConnectionFactory = new SslConnectionFactory(
209-
sslContextFactory, HttpVersion.HTTP_1_1.asString());
210-
ServerConnector serverConnector = new ServerConnector(server,
211-
sslConnectionFactory, connectionFactory);
212-
serverConnector.setPort(port);
213-
return serverConnector;
214-
}
215-
216188
private Handler addHandlerWrappers(Handler handler) {
217189
if (getCompression() != null && getCompression().getEnabled()) {
218190
handler = applyWrapper(handler, createGzipHandler());
@@ -242,96 +214,6 @@ private HandlerWrapper createGzipHandler() {
242214
return handler;
243215
}
244216

245-
/**
246-
* Configure the SSL connection.
247-
* @param factory the Jetty {@link SslContextFactory}.
248-
* @param ssl the ssl details.
249-
*/
250-
protected void configureSsl(SslContextFactory factory, Ssl ssl) {
251-
factory.setProtocol(ssl.getProtocol());
252-
configureSslClientAuth(factory, ssl);
253-
configureSslPasswords(factory, ssl);
254-
factory.setCertAlias(ssl.getKeyAlias());
255-
if (!ObjectUtils.isEmpty(ssl.getCiphers())) {
256-
factory.setIncludeCipherSuites(ssl.getCiphers());
257-
factory.setExcludeCipherSuites();
258-
}
259-
if (ssl.getEnabledProtocols() != null) {
260-
factory.setIncludeProtocols(ssl.getEnabledProtocols());
261-
}
262-
if (getSslStoreProvider() != null) {
263-
try {
264-
factory.setKeyStore(getSslStoreProvider().getKeyStore());
265-
factory.setTrustStore(getSslStoreProvider().getTrustStore());
266-
}
267-
catch (Exception ex) {
268-
throw new IllegalStateException("Unable to set SSL store", ex);
269-
}
270-
}
271-
else {
272-
configureSslKeyStore(factory, ssl);
273-
configureSslTrustStore(factory, ssl);
274-
}
275-
}
276-
277-
private void configureSslClientAuth(SslContextFactory factory, Ssl ssl) {
278-
if (ssl.getClientAuth() == ClientAuth.NEED) {
279-
factory.setNeedClientAuth(true);
280-
factory.setWantClientAuth(true);
281-
}
282-
else if (ssl.getClientAuth() == ClientAuth.WANT) {
283-
factory.setWantClientAuth(true);
284-
}
285-
}
286-
287-
private void configureSslPasswords(SslContextFactory factory, Ssl ssl) {
288-
if (ssl.getKeyStorePassword() != null) {
289-
factory.setKeyStorePassword(ssl.getKeyStorePassword());
290-
}
291-
if (ssl.getKeyPassword() != null) {
292-
factory.setKeyManagerPassword(ssl.getKeyPassword());
293-
}
294-
}
295-
296-
private void configureSslKeyStore(SslContextFactory factory, Ssl ssl) {
297-
try {
298-
URL url = ResourceUtils.getURL(ssl.getKeyStore());
299-
factory.setKeyStoreResource(Resource.newResource(url));
300-
}
301-
catch (IOException ex) {
302-
throw new WebServerException(
303-
"Could not find key store '" + ssl.getKeyStore() + "'", ex);
304-
}
305-
if (ssl.getKeyStoreType() != null) {
306-
factory.setKeyStoreType(ssl.getKeyStoreType());
307-
}
308-
if (ssl.getKeyStoreProvider() != null) {
309-
factory.setKeyStoreProvider(ssl.getKeyStoreProvider());
310-
}
311-
}
312-
313-
private void configureSslTrustStore(SslContextFactory factory, Ssl ssl) {
314-
if (ssl.getTrustStorePassword() != null) {
315-
factory.setTrustStorePassword(ssl.getTrustStorePassword());
316-
}
317-
if (ssl.getTrustStore() != null) {
318-
try {
319-
URL url = ResourceUtils.getURL(ssl.getTrustStore());
320-
factory.setTrustStoreResource(Resource.newResource(url));
321-
}
322-
catch (IOException ex) {
323-
throw new WebServerException(
324-
"Could not find trust store '" + ssl.getTrustStore() + "'", ex);
325-
}
326-
}
327-
if (ssl.getTrustStoreType() != null) {
328-
factory.setTrustStoreType(ssl.getTrustStoreType());
329-
}
330-
if (ssl.getTrustStoreProvider() != null) {
331-
factory.setTrustStoreProvider(ssl.getTrustStoreProvider());
332-
}
333-
}
334-
335217
/**
336218
* Configure the given Jetty {@link WebAppContext} for use.
337219
* @param context the context to configure
@@ -456,7 +338,7 @@ protected final void addJspServlet(WebAppContext context) {
456338
context.getServletHandler().addServlet(holder);
457339
ServletMapping mapping = new ServletMapping();
458340
mapping.setServletName("jsp");
459-
mapping.setPathSpecs(new String[] { "*.jsp", "*.jspx" });
341+
mapping.setPathSpecs(new String[] {"*.jsp", "*.jspx"});
460342
context.getServletHandler().addServletMapping(mapping);
461343
}
462344

Original file line numberDiff line numberDiff line change
@@ -0,0 +1,175 @@
1+
/*
2+
* Copyright 2012-2017 the original author or authors.
3+
*
4+
* Licensed under the Apache License, Version 2.0 (the "License");
5+
* you may not use this file except in compliance with the License.
6+
* You may obtain a copy of the License at
7+
*
8+
* http://www.apache.org/licenses/LICENSE-2.0
9+
*
10+
* Unless required by applicable law or agreed to in writing, software
11+
* distributed under the License is distributed on an "AS IS" BASIS,
12+
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13+
* See the License for the specific language governing permissions and
14+
* limitations under the License.
15+
*/
16+
17+
package org.springframework.boot.web.embedded.jetty;
18+
19+
import java.io.IOException;
20+
import java.net.URL;
21+
22+
import org.eclipse.jetty.http.HttpVersion;
23+
import org.eclipse.jetty.server.AbstractConnector;
24+
import org.eclipse.jetty.server.Connector;
25+
import org.eclipse.jetty.server.HttpConfiguration;
26+
import org.eclipse.jetty.server.HttpConnectionFactory;
27+
import org.eclipse.jetty.server.SecureRequestCustomizer;
28+
import org.eclipse.jetty.server.Server;
29+
import org.eclipse.jetty.server.ServerConnector;
30+
import org.eclipse.jetty.server.SslConnectionFactory;
31+
import org.eclipse.jetty.util.resource.Resource;
32+
import org.eclipse.jetty.util.ssl.SslContextFactory;
33+
34+
import org.springframework.boot.web.server.Ssl;
35+
import org.springframework.boot.web.server.SslStoreProvider;
36+
import org.springframework.boot.web.server.WebServerException;
37+
import org.springframework.util.ObjectUtils;
38+
import org.springframework.util.ResourceUtils;
39+
40+
/**
41+
* {@link JettyServerCustomizer} that configures SSL on the
42+
* given Jetty server instance.
43+
*
44+
* @author Brian Clozel
45+
*/
46+
class SslServerCustomizer implements JettyServerCustomizer {
47+
48+
private final int port;
49+
50+
private final Ssl ssl;
51+
52+
private final SslStoreProvider sslStoreProvider;
53+
54+
SslServerCustomizer(int port, Ssl ssl, SslStoreProvider sslStoreProvider) {
55+
this.port = port;
56+
this.ssl = ssl;
57+
this.sslStoreProvider = sslStoreProvider;
58+
}
59+
60+
@Override
61+
public void customize(Server server) {
62+
if (this.ssl != null && this.ssl.isEnabled()) {
63+
SslContextFactory sslContextFactory = new SslContextFactory();
64+
configureSsl(sslContextFactory, this.ssl, this.sslStoreProvider);
65+
AbstractConnector connector = createSslConnector(server, sslContextFactory,
66+
this.port);
67+
server.setConnectors(new Connector[] { connector });
68+
}
69+
}
70+
71+
private AbstractConnector createSslConnector(Server server,
72+
SslContextFactory sslContextFactory, int port) {
73+
HttpConfiguration config = new HttpConfiguration();
74+
config.setSendServerVersion(false);
75+
config.addCustomizer(new SecureRequestCustomizer());
76+
HttpConnectionFactory connectionFactory = new HttpConnectionFactory(config);
77+
SslConnectionFactory sslConnectionFactory = new SslConnectionFactory(
78+
sslContextFactory, HttpVersion.HTTP_1_1.asString());
79+
ServerConnector serverConnector = new ServerConnector(server,
80+
sslConnectionFactory, connectionFactory);
81+
serverConnector.setPort(port);
82+
return serverConnector;
83+
}
84+
85+
/**
86+
* Configure the SSL connection.
87+
* @param factory the Jetty {@link SslContextFactory}.
88+
* @param ssl the ssl details.
89+
* @param sslStoreProvider the ssl store provider
90+
*/
91+
protected void configureSsl(SslContextFactory factory, Ssl ssl, SslStoreProvider sslStoreProvider) {
92+
factory.setProtocol(ssl.getProtocol());
93+
configureSslClientAuth(factory, ssl);
94+
configureSslPasswords(factory, ssl);
95+
factory.setCertAlias(ssl.getKeyAlias());
96+
if (!ObjectUtils.isEmpty(ssl.getCiphers())) {
97+
factory.setIncludeCipherSuites(ssl.getCiphers());
98+
factory.setExcludeCipherSuites();
99+
}
100+
if (ssl.getEnabledProtocols() != null) {
101+
factory.setIncludeProtocols(ssl.getEnabledProtocols());
102+
}
103+
if (sslStoreProvider != null) {
104+
try {
105+
factory.setKeyStore(sslStoreProvider.getKeyStore());
106+
factory.setTrustStore(sslStoreProvider.getTrustStore());
107+
}
108+
catch (Exception ex) {
109+
throw new IllegalStateException("Unable to set SSL store", ex);
110+
}
111+
}
112+
else {
113+
configureSslKeyStore(factory, ssl);
114+
configureSslTrustStore(factory, ssl);
115+
}
116+
}
117+
118+
private void configureSslClientAuth(SslContextFactory factory, Ssl ssl) {
119+
if (ssl.getClientAuth() == Ssl.ClientAuth.NEED) {
120+
factory.setNeedClientAuth(true);
121+
factory.setWantClientAuth(true);
122+
}
123+
else if (ssl.getClientAuth() == Ssl.ClientAuth.WANT) {
124+
factory.setWantClientAuth(true);
125+
}
126+
}
127+
128+
private void configureSslPasswords(SslContextFactory factory, Ssl ssl) {
129+
if (ssl.getKeyStorePassword() != null) {
130+
factory.setKeyStorePassword(ssl.getKeyStorePassword());
131+
}
132+
if (ssl.getKeyPassword() != null) {
133+
factory.setKeyManagerPassword(ssl.getKeyPassword());
134+
}
135+
}
136+
137+
private void configureSslKeyStore(SslContextFactory factory, Ssl ssl) {
138+
try {
139+
URL url = ResourceUtils.getURL(ssl.getKeyStore());
140+
factory.setKeyStoreResource(Resource.newResource(url));
141+
}
142+
catch (IOException ex) {
143+
throw new WebServerException(
144+
"Could not find key store '" + ssl.getKeyStore() + "'", ex);
145+
}
146+
if (ssl.getKeyStoreType() != null) {
147+
factory.setKeyStoreType(ssl.getKeyStoreType());
148+
}
149+
if (ssl.getKeyStoreProvider() != null) {
150+
factory.setKeyStoreProvider(ssl.getKeyStoreProvider());
151+
}
152+
}
153+
154+
private void configureSslTrustStore(SslContextFactory factory, Ssl ssl) {
155+
if (ssl.getTrustStorePassword() != null) {
156+
factory.setTrustStorePassword(ssl.getTrustStorePassword());
157+
}
158+
if (ssl.getTrustStore() != null) {
159+
try {
160+
URL url = ResourceUtils.getURL(ssl.getTrustStore());
161+
factory.setTrustStoreResource(Resource.newResource(url));
162+
}
163+
catch (IOException ex) {
164+
throw new WebServerException(
165+
"Could not find trust store '" + ssl.getTrustStore() + "'", ex);
166+
}
167+
}
168+
if (ssl.getTrustStoreType() != null) {
169+
factory.setTrustStoreType(ssl.getTrustStoreType());
170+
}
171+
if (ssl.getTrustStoreProvider() != null) {
172+
factory.setTrustStoreProvider(ssl.getTrustStoreProvider());
173+
}
174+
}
175+
}

0 commit comments

Comments
 (0)