Skip to content

Commit 62a5ce5

Browse files
committed
Backport Jetty/Tomcat SSL support
Fixes gh-1570 Cherry-picked from 0960908 and 258c6f1
1 parent fae9ab4 commit 62a5ce5

File tree

20 files changed

+920
-80
lines changed

20 files changed

+920
-80
lines changed

spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/web/ServerProperties.java

Lines changed: 40 additions & 27 deletions
Original file line numberDiff line numberDiff line change
@@ -33,6 +33,7 @@
3333
import org.springframework.boot.context.embedded.EmbeddedServletContainerCustomizer;
3434
import org.springframework.boot.context.embedded.EmbeddedServletContainerCustomizerBeanPostProcessor;
3535
import org.springframework.boot.context.embedded.EmbeddedServletContainerFactory;
36+
import org.springframework.boot.context.embedded.Ssl;
3637
import org.springframework.boot.context.embedded.tomcat.TomcatConnectorCustomizer;
3738
import org.springframework.boot.context.embedded.tomcat.TomcatContextCustomizer;
3839
import org.springframework.boot.context.embedded.tomcat.TomcatEmbeddedServletContainerFactory;
@@ -59,6 +60,8 @@ public class ServerProperties implements EmbeddedServletContainerCustomizer {
5960

6061
private String contextPath;
6162

63+
private Ssl ssl;
64+
6265
@NotNull
6366
private String servletPath = "/";
6467

@@ -132,6 +135,14 @@ public void setSessionTimeout(Integer sessionTimeout) {
132135
this.sessionTimeout = sessionTimeout;
133136
}
134137

138+
public Ssl getSsl() {
139+
return this.ssl;
140+
}
141+
142+
public void setSsl(Ssl ssl) {
143+
this.ssl = ssl;
144+
}
145+
135146
public void setLoader(String value) {
136147
// no op to support Tomcat running as a traditional container (not embedded)
137148
}
@@ -150,12 +161,41 @@ public void customize(ConfigurableEmbeddedServletContainer container) {
150161
if (getSessionTimeout() != null) {
151162
container.setSessionTimeout(getSessionTimeout());
152163
}
164+
if (getSsl() != null) {
165+
container.setSsl(getSsl());
166+
}
153167
if (container instanceof TomcatEmbeddedServletContainerFactory) {
154168
getTomcat()
155169
.customizeTomcat((TomcatEmbeddedServletContainerFactory) container);
156170
}
157171
}
158172

173+
public String[] getPathsArray(Collection<String> paths) {
174+
String[] result = new String[paths.size()];
175+
int i = 0;
176+
for (String path : paths) {
177+
result[i++] = getPath(path);
178+
}
179+
return result;
180+
}
181+
182+
public String[] getPathsArray(String[] paths) {
183+
String[] result = new String[paths.length];
184+
int i = 0;
185+
for (String path : paths) {
186+
result[i++] = getPath(path);
187+
}
188+
return result;
189+
}
190+
191+
public String getPath(String path) {
192+
String prefix = getServletPrefix();
193+
if (!path.startsWith("/")) {
194+
path = "/" + path;
195+
}
196+
return prefix + path;
197+
}
198+
159199
public static class Tomcat {
160200

161201
private String accessLogPattern;
@@ -330,31 +370,4 @@ public void customize(Connector connector) {
330370
}
331371

332372
}
333-
334-
public String[] getPathsArray(Collection<String> paths) {
335-
String[] result = new String[paths.size()];
336-
int i = 0;
337-
for (String path : paths) {
338-
result[i++] = getPath(path);
339-
}
340-
return result;
341-
}
342-
343-
public String[] getPathsArray(String[] paths) {
344-
String[] result = new String[paths.length];
345-
int i = 0;
346-
for (String path : paths) {
347-
result[i++] = getPath(path);
348-
}
349-
return result;
350-
}
351-
352-
public String getPath(String path) {
353-
String prefix = getServletPrefix();
354-
if (!path.startsWith("/")) {
355-
path = "/" + path;
356-
}
357-
return prefix + path;
358-
}
359-
360373
}

spring-boot-docs/src/main/asciidoc/appendix-application-properties.adoc

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -56,6 +56,18 @@ content into your application; rather pick only the properties that you need.
5656
server.session-timeout= # session timeout in seconds
5757
server.context-path= # the context path, defaults to '/'
5858
server.servlet-path= # the servlet path, defaults to '/'
59+
server.ssl.client-auth= # want or need
60+
server.ssl.key-alias=
61+
server.ssl.key-password=
62+
server.ssl.key-store=
63+
server.ssl.key-store-password=
64+
server.ssl.key-store-provider=
65+
server.ssl.key-store-type=
66+
server.ssl.protocol=TLS
67+
server.ssl.trust-store=
68+
server.ssl.trust-store-password=
69+
server.ssl.trust-store-provider=
70+
server.ssl.trust-store-type=
5971
server.tomcat.access-log-pattern= # log pattern of the access log
6072
server.tomcat.access-log-enabled=false # is access logging enabled
6173
server.tomcat.internal-proxies=10\.\d{1,3}\.\d{1,3}\.\d{1,3}|\

spring-boot-docs/src/main/asciidoc/howto.adoc

Lines changed: 21 additions & 50 deletions
Original file line numberDiff line numberDiff line change
@@ -389,6 +389,27 @@ and then inject the actual (``local'') port as a `@Value`. For example:
389389

390390

391391

392+
[[howto-configure-ssl]]
393+
=== Configure SSL
394+
SSL can be configured declaratively by setting the various `server.ssl.*` properties,
395+
typically in `application.properties` or `application.yml`. For example:
396+
397+
[source,properties,indent=0,subs="verbatim,quotes,attributes"]
398+
----
399+
server.port = 8443
400+
server.ssl.key-store = classpath:keystore.jks
401+
server.ssl.key-store-password = secret
402+
server.ssl.key-password = another-secret
403+
----
404+
405+
See {sc-spring-boot}/context/embedded/Ssl.{sc-ext}[`Ssl`] for details of all of the
406+
supported properties.
407+
408+
NOTE: Tomcat requires the key store (and trust store if you're using one) to be directly
409+
accessible on the filesystem, i.e. it cannot be read from within a jar file.
410+
411+
412+
392413
[[howto-configure-tomcat]]
393414
=== Configure Tomcat
394415
Generally you can follow the advice from
@@ -401,56 +422,6 @@ nuclear option is to add your own `TomcatEmbeddedServletContainerFactory`.
401422

402423

403424

404-
[[howto-terminate-ssl-in-tomcat]]
405-
=== Terminate SSL in Tomcat
406-
Use an `EmbeddedServletContainerCustomizer` and in that add a `TomcatConnectorCustomizer`
407-
that sets up the connector to be secure:
408-
409-
[source,java,indent=0,subs="verbatim,quotes,attributes"]
410-
----
411-
@Bean
412-
public EmbeddedServletContainerCustomizer containerCustomizer(){
413-
return new MyCustomizer();
414-
}
415-
416-
// ...
417-
418-
private static class MyCustomizer implements EmbeddedServletContainerCustomizer {
419-
420-
@Override
421-
public void customize(ConfigurableEmbeddedServletContainer factory) {
422-
if(factory instanceof TomcatEmbeddedServletContainerFactory) {
423-
customizeTomcat((TomcatEmbeddedServletContainerFactory) factory);
424-
}
425-
}
426-
427-
public void customizeTomcat(TomcatEmbeddedServletContainerFactory factory) {
428-
factory.addConnectorCustomizers(new TomcatConnectorCustomizer() {
429-
@Override
430-
public void customize(Connector connector) {
431-
connector.setPort(serverPort);
432-
connector.setSecure(true);
433-
connector.setScheme("https");
434-
connector.setAttribute("keyAlias", "tomcat");
435-
connector.setAttribute("keystorePass", "password");
436-
try {
437-
connector.setAttribute("keystoreFile",
438-
ResourceUtils.getFile("src/ssl/tomcat.keystore").getAbsolutePath());
439-
} catch (FileNotFoundException e) {
440-
throw new IllegalStateException("Cannot load keystore", e);
441-
}
442-
connector.setAttribute("clientAuth", "false");
443-
connector.setAttribute("sslProtocol", "TLS");
444-
connector.setAttribute("SSLEnabled", true);
445-
}
446-
});
447-
}
448-
449-
}
450-
----
451-
452-
453-
454425
[[howto-enable-multiple-connectors-in-tomcat]]
455426
=== Enable Multiple Connectors Tomcat
456427
Add a `org.apache.catalina.connector.Connector` to the

spring-boot-samples/pom.xml

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -44,6 +44,7 @@
4444
<module>spring-boot-sample-secure</module>
4545
<module>spring-boot-sample-servlet</module>
4646
<module>spring-boot-sample-simple</module>
47+
<module>spring-boot-sample-tomcat-ssl</module>
4748
<module>spring-boot-sample-tomcat</module>
4849
<module>spring-boot-sample-tomcat-multi-connectors</module>
4950
<module>spring-boot-sample-tomcat8-jsp</module>
Lines changed: 56 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,56 @@
1+
<?xml version="1.0" encoding="UTF-8"?>
2+
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
3+
<modelVersion>4.0.0</modelVersion>
4+
<parent>
5+
<!-- Your own application should inherit from spring-boot-starter-parent -->
6+
<groupId>org.springframework.boot</groupId>
7+
<artifactId>spring-boot-samples</artifactId>
8+
<version>1.1.7.BUILD-SNAPSHOT</version>
9+
</parent>
10+
<artifactId>spring-boot-sample-tomcat-ssl</artifactId>
11+
<name>Spring Boot Tomcat Sample</name>
12+
<description>Spring Boot Tomcat SSL Sample</description>
13+
<url>http://projects.spring.io/spring-boot/</url>
14+
<organization>
15+
<name>Pivotal Software, Inc.</name>
16+
<url>http://www.spring.io</url>
17+
</organization>
18+
<properties>
19+
<main.basedir>${basedir}/../..</main.basedir>
20+
</properties>
21+
<dependencies>
22+
<dependency>
23+
<groupId>org.springframework.boot</groupId>
24+
<artifactId>spring-boot-starter</artifactId>
25+
</dependency>
26+
<dependency>
27+
<groupId>org.springframework.boot</groupId>
28+
<artifactId>spring-boot-starter-tomcat</artifactId>
29+
</dependency>
30+
<dependency>
31+
<groupId>org.springframework</groupId>
32+
<artifactId>spring-webmvc</artifactId>
33+
</dependency>
34+
<dependency>
35+
<groupId>org.apache.httpcomponents</groupId>
36+
<artifactId>httpclient</artifactId>
37+
</dependency>
38+
<dependency>
39+
<groupId>org.springframework.boot</groupId>
40+
<artifactId>spring-boot-starter-test</artifactId>
41+
<scope>test</scope>
42+
</dependency>
43+
<dependency>
44+
<groupId>org.yaml</groupId>
45+
<artifactId>snakeyaml</artifactId>
46+
</dependency>
47+
</dependencies>
48+
<build>
49+
<plugins>
50+
<plugin>
51+
<groupId>org.springframework.boot</groupId>
52+
<artifactId>spring-boot-maven-plugin</artifactId>
53+
</plugin>
54+
</plugins>
55+
</build>
56+
</project>
Binary file not shown.
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,35 @@
1+
/*
2+
* Copyright 2012-2014 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 sample.tomcat;
18+
19+
import org.springframework.boot.SpringApplication;
20+
import org.springframework.boot.autoconfigure.EnableAutoConfiguration;
21+
import org.springframework.boot.context.properties.EnableConfigurationProperties;
22+
import org.springframework.context.annotation.ComponentScan;
23+
import org.springframework.context.annotation.Configuration;
24+
25+
@ComponentScan
26+
@Configuration
27+
@EnableAutoConfiguration
28+
@EnableConfigurationProperties
29+
public class SampleTomcatSslApplication {
30+
31+
public static void main(String[] args) throws Exception {
32+
SpringApplication.run(SampleTomcatSslApplication.class, args);
33+
}
34+
35+
}
Lines changed: 32 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,32 @@
1+
/*
2+
* Copyright 2012-2014 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 sample.tomcat.web;
18+
19+
import org.springframework.stereotype.Controller;
20+
import org.springframework.web.bind.annotation.RequestMapping;
21+
import org.springframework.web.bind.annotation.ResponseBody;
22+
23+
@Controller
24+
public class SampleController {
25+
26+
@RequestMapping("/")
27+
@ResponseBody
28+
public String helloWorld() {
29+
return "Hello, world";
30+
}
31+
32+
}
Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,4 @@
1+
server.port = 8443
2+
server.ssl.key-store = sample.jks
3+
server.ssl.key-store-password = secret
4+
server.ssl.key-password = password

0 commit comments

Comments
 (0)