diff --git a/spring-boot-actuator/pom.xml b/spring-boot-actuator/pom.xml
index 1b23af54ca..f7641cacbe 100644
--- a/spring-boot-actuator/pom.xml
+++ b/spring-boot-actuator/pom.xml
@@ -308,8 +308,8 @@
test
- org.apache.tomcat.embed
- tomcat-embed-logging-juli
+ org.apache.tomcat
+ tomcat-juli
test
diff --git a/spring-boot-dependencies/pom.xml b/spring-boot-dependencies/pom.xml
index 56d1ff334a..c277fc0af2 100644
--- a/spring-boot-dependencies/pom.xml
+++ b/spring-boot-dependencies/pom.xml
@@ -173,7 +173,7 @@
1.4.0
1.3
2.1.0.RELEASE
- 8.0.33
+ 8.5.3
1.3.22.Final
1.7
2.0
@@ -1314,11 +1314,6 @@
tomcat-embed-jasper
${tomcat.version}
-
- org.apache.tomcat.embed
- tomcat-embed-logging-juli
- ${tomcat.version}
-
org.apache.tomcat.embed
tomcat-embed-websocket
@@ -1334,6 +1329,11 @@
tomcat-jsp-api
${tomcat.version}
+
+ org.apache.tomcat
+ tomcat-juli
+ ${tomcat.version}
+
org.apache.velocity
velocity
diff --git a/spring-boot-devtools/pom.xml b/spring-boot-devtools/pom.xml
index 69468f6515..72c68b82cf 100644
--- a/spring-boot-devtools/pom.xml
+++ b/spring-boot-devtools/pom.xml
@@ -118,8 +118,8 @@
test
- org.apache.tomcat.embed
- tomcat-embed-logging-juli
+ org.apache.tomcat
+ tomcat-juli
test
diff --git a/spring-boot-docs/pom.xml b/spring-boot-docs/pom.xml
index 440ff6b884..d0fc03f938 100644
--- a/spring-boot-docs/pom.xml
+++ b/spring-boot-docs/pom.xml
@@ -300,8 +300,8 @@
true
- org.apache.tomcat.embed
- tomcat-embed-logging-juli
+ org.apache.tomcat
+ tomcat-juli
true
diff --git a/spring-boot-samples/README.adoc b/spring-boot-samples/README.adoc
index 79cb240275..590a0c437f 100644
--- a/spring-boot-samples/README.adoc
+++ b/spring-boot-samples/README.adoc
@@ -193,7 +193,7 @@ The following sample applications are provided:
| Embedded Tomcat
| link:spring-boot-sample-tomcat-jsp[spring-boot-sample-tomcat-jsp]
-| Web application that uses JSP templates with Tomcat 8
+| Web application that uses JSP templates with Tomcat
| link:spring-boot-sample-tomcat-multi-connectors[spring-boot-sample-tomcat-multi-connectors]
| Web application that uses Tomcat configured with multiple connectors
@@ -204,6 +204,12 @@ The following sample applications are provided:
| link:spring-boot-sample-tomcat7-jsp[spring-boot-sample-tomcat7-jsp]
| Web application that uses JSP templates with Tomcat 7
+| link:spring-boot-sample-tomcat7-ssl[spring-boot-sample-tomcat7-ssl]
+| Web application that uses Tomcat 7 configured with SSL
+
+| link:spring-boot-sample-tomcat80-ssl[spring-boot-sample-tomcat80-ssl]
+| Web application that uses Tomcat 8.0 configured with SSL
+
| link:spring-boot-sample-traditional[spring-boot-sample-traditional]
| Traditional WAR packaging (but also executable using `java -jar`)
diff --git a/spring-boot-samples/pom.xml b/spring-boot-samples/pom.xml
index fbe02fd085..95984aceb6 100644
--- a/spring-boot-samples/pom.xml
+++ b/spring-boot-samples/pom.xml
@@ -87,6 +87,8 @@
spring-boot-sample-tomcat-ssl
spring-boot-sample-tomcat-multi-connectors
spring-boot-sample-tomcat7-jsp
+ spring-boot-sample-tomcat7-ssl
+ spring-boot-sample-tomcat80-ssl
spring-boot-sample-traditional
spring-boot-sample-undertow
spring-boot-sample-undertow-ssl
diff --git a/spring-boot-samples/spring-boot-sample-tomcat-jsp/pom.xml b/spring-boot-samples/spring-boot-sample-tomcat-jsp/pom.xml
index c09885658b..0fe62952f9 100644
--- a/spring-boot-samples/spring-boot-sample-tomcat-jsp/pom.xml
+++ b/spring-boot-samples/spring-boot-sample-tomcat-jsp/pom.xml
@@ -19,6 +19,7 @@
${basedir}/../..
/
+ 7.0.69
diff --git a/spring-boot-samples/spring-boot-sample-tomcat-ssl/pom.xml b/spring-boot-samples/spring-boot-sample-tomcat-ssl/pom.xml
index c583d31868..ad94327532 100644
--- a/spring-boot-samples/spring-boot-sample-tomcat-ssl/pom.xml
+++ b/spring-boot-samples/spring-boot-sample-tomcat-ssl/pom.xml
@@ -8,7 +8,7 @@
1.4.0.BUILD-SNAPSHOT
spring-boot-sample-tomcat-ssl
- Spring Boot Tomcat Sample
+ Spring Boot Tomcat SSL Sample
Spring Boot Tomcat SSL Sample
http://projects.spring.io/spring-boot/
diff --git a/spring-boot-samples/spring-boot-sample-tomcat7-ssl/pom.xml b/spring-boot-samples/spring-boot-sample-tomcat7-ssl/pom.xml
new file mode 100644
index 0000000000..8796da6189
--- /dev/null
+++ b/spring-boot-samples/spring-boot-sample-tomcat7-ssl/pom.xml
@@ -0,0 +1,57 @@
+
+
+ 4.0.0
+
+
+ org.springframework.boot
+ spring-boot-samples
+ 1.4.0.BUILD-SNAPSHOT
+
+ spring-boot-sample-tomcat7-ssl
+ Spring Boot Tomcat 7 SSL Sample
+ Spring Boot Tomcat 7 SSL Sample
+ http://projects.spring.io/spring-boot/
+
+ Pivotal Software, Inc.
+ http://www.spring.io
+
+
+ ${basedir}/../..
+ 7.0.69
+
+
+
+ org.springframework.boot
+ spring-boot-starter
+
+
+ org.springframework.boot
+ spring-boot-starter-tomcat
+
+
+ org.springframework
+ spring-webmvc
+
+
+ org.apache.httpcomponents
+ httpclient
+
+
+ org.springframework.boot
+ spring-boot-starter-test
+ test
+
+
+ org.yaml
+ snakeyaml
+
+
+
+
+
+ org.springframework.boot
+ spring-boot-maven-plugin
+
+
+
+
diff --git a/spring-boot-samples/spring-boot-sample-tomcat7-ssl/src/main/java/sample/tomcat/ssl/SampleTomcatSslApplication.java b/spring-boot-samples/spring-boot-sample-tomcat7-ssl/src/main/java/sample/tomcat/ssl/SampleTomcatSslApplication.java
new file mode 100644
index 0000000000..32d2e6ed77
--- /dev/null
+++ b/spring-boot-samples/spring-boot-sample-tomcat7-ssl/src/main/java/sample/tomcat/ssl/SampleTomcatSslApplication.java
@@ -0,0 +1,29 @@
+/*
+ * Copyright 2012-2015 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
+ *
+ * http://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 sample.tomcat.ssl;
+
+import org.springframework.boot.SpringApplication;
+import org.springframework.boot.autoconfigure.SpringBootApplication;
+
+@SpringBootApplication
+public class SampleTomcatSslApplication {
+
+ public static void main(String[] args) throws Exception {
+ SpringApplication.run(SampleTomcatSslApplication.class, args);
+ }
+
+}
diff --git a/spring-boot-samples/spring-boot-sample-tomcat7-ssl/src/main/java/sample/tomcat/ssl/web/SampleController.java b/spring-boot-samples/spring-boot-sample-tomcat7-ssl/src/main/java/sample/tomcat/ssl/web/SampleController.java
new file mode 100644
index 0000000000..7ca0d5ed01
--- /dev/null
+++ b/spring-boot-samples/spring-boot-sample-tomcat7-ssl/src/main/java/sample/tomcat/ssl/web/SampleController.java
@@ -0,0 +1,32 @@
+/*
+ * Copyright 2012-2016 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
+ *
+ * http://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 sample.tomcat.ssl.web;
+
+import org.springframework.stereotype.Controller;
+import org.springframework.web.bind.annotation.GetMapping;
+import org.springframework.web.bind.annotation.ResponseBody;
+
+@Controller
+public class SampleController {
+
+ @GetMapping("/")
+ @ResponseBody
+ public String helloWorld() {
+ return "Hello, world";
+ }
+
+}
diff --git a/spring-boot-samples/spring-boot-sample-tomcat7-ssl/src/main/resources/application.properties b/spring-boot-samples/spring-boot-sample-tomcat7-ssl/src/main/resources/application.properties
new file mode 100644
index 0000000000..37199bfd25
--- /dev/null
+++ b/spring-boot-samples/spring-boot-sample-tomcat7-ssl/src/main/resources/application.properties
@@ -0,0 +1,4 @@
+server.port = 8443
+server.ssl.key-store = classpath:sample.jks
+server.ssl.key-store-password = secret
+server.ssl.key-password = password
diff --git a/spring-boot-samples/spring-boot-sample-tomcat7-ssl/src/main/resources/sample.jks b/spring-boot-samples/spring-boot-sample-tomcat7-ssl/src/main/resources/sample.jks
new file mode 100644
index 0000000000..6aa9a28053
Binary files /dev/null and b/spring-boot-samples/spring-boot-sample-tomcat7-ssl/src/main/resources/sample.jks differ
diff --git a/spring-boot-samples/spring-boot-sample-tomcat7-ssl/src/test/java/sample/tomcat/ssl/SampleTomcatSslApplicationTests.java b/spring-boot-samples/spring-boot-sample-tomcat7-ssl/src/test/java/sample/tomcat/ssl/SampleTomcatSslApplicationTests.java
new file mode 100644
index 0000000000..f7b42c68a6
--- /dev/null
+++ b/spring-boot-samples/spring-boot-sample-tomcat7-ssl/src/test/java/sample/tomcat/ssl/SampleTomcatSslApplicationTests.java
@@ -0,0 +1,51 @@
+/*
+ * Copyright 2012-2016 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
+ *
+ * http://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 sample.tomcat.ssl;
+
+import org.junit.Test;
+import org.junit.runner.RunWith;
+
+import org.springframework.boot.context.embedded.LocalServerPort;
+import org.springframework.boot.test.context.SpringBootTest;
+import org.springframework.boot.test.context.SpringBootTest.WebEnvironment;
+import org.springframework.boot.test.web.client.TestRestTemplate;
+import org.springframework.boot.test.web.client.TestRestTemplate.HttpClientOption;
+import org.springframework.http.HttpStatus;
+import org.springframework.http.ResponseEntity;
+import org.springframework.test.annotation.DirtiesContext;
+import org.springframework.test.context.junit4.SpringRunner;
+
+import static org.assertj.core.api.Assertions.assertThat;
+
+@RunWith(SpringRunner.class)
+@SpringBootTest(webEnvironment = WebEnvironment.RANDOM_PORT)
+@DirtiesContext
+public class SampleTomcatSslApplicationTests {
+
+ @LocalServerPort
+ private int port;
+
+ @Test
+ public void testHome() throws Exception {
+ TestRestTemplate testRestTemplate = new TestRestTemplate(HttpClientOption.SSL);
+ ResponseEntity entity = testRestTemplate
+ .getForEntity("https://localhost:" + this.port, String.class);
+ assertThat(entity.getStatusCode()).isEqualTo(HttpStatus.OK);
+ assertThat(entity.getBody()).isEqualTo("Hello, world");
+ }
+
+}
diff --git a/spring-boot-samples/spring-boot-sample-tomcat80-ssl/pom.xml b/spring-boot-samples/spring-boot-sample-tomcat80-ssl/pom.xml
new file mode 100644
index 0000000000..4da6d54d88
--- /dev/null
+++ b/spring-boot-samples/spring-boot-sample-tomcat80-ssl/pom.xml
@@ -0,0 +1,57 @@
+
+
+ 4.0.0
+
+
+ org.springframework.boot
+ spring-boot-samples
+ 1.4.0.BUILD-SNAPSHOT
+
+ spring-boot-sample-tomcat-ssl
+ Spring Boot Tomcat 8.0 SSL Sample
+ Spring Boot Tomcat 8.0 SSL Sample
+ http://projects.spring.io/spring-boot/
+
+ Pivotal Software, Inc.
+ http://www.spring.io
+
+
+ ${basedir}/../..
+ 8.0.33
+
+
+
+ org.springframework.boot
+ spring-boot-starter
+
+
+ org.springframework.boot
+ spring-boot-starter-tomcat
+
+
+ org.springframework
+ spring-webmvc
+
+
+ org.apache.httpcomponents
+ httpclient
+
+
+ org.springframework.boot
+ spring-boot-starter-test
+ test
+
+
+ org.yaml
+ snakeyaml
+
+
+
+
+
+ org.springframework.boot
+ spring-boot-maven-plugin
+
+
+
+
diff --git a/spring-boot-samples/spring-boot-sample-tomcat80-ssl/src/main/java/sample/tomcat/ssl/SampleTomcatSslApplication.java b/spring-boot-samples/spring-boot-sample-tomcat80-ssl/src/main/java/sample/tomcat/ssl/SampleTomcatSslApplication.java
new file mode 100644
index 0000000000..32d2e6ed77
--- /dev/null
+++ b/spring-boot-samples/spring-boot-sample-tomcat80-ssl/src/main/java/sample/tomcat/ssl/SampleTomcatSslApplication.java
@@ -0,0 +1,29 @@
+/*
+ * Copyright 2012-2015 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
+ *
+ * http://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 sample.tomcat.ssl;
+
+import org.springframework.boot.SpringApplication;
+import org.springframework.boot.autoconfigure.SpringBootApplication;
+
+@SpringBootApplication
+public class SampleTomcatSslApplication {
+
+ public static void main(String[] args) throws Exception {
+ SpringApplication.run(SampleTomcatSslApplication.class, args);
+ }
+
+}
diff --git a/spring-boot-samples/spring-boot-sample-tomcat80-ssl/src/main/java/sample/tomcat/ssl/web/SampleController.java b/spring-boot-samples/spring-boot-sample-tomcat80-ssl/src/main/java/sample/tomcat/ssl/web/SampleController.java
new file mode 100644
index 0000000000..7ca0d5ed01
--- /dev/null
+++ b/spring-boot-samples/spring-boot-sample-tomcat80-ssl/src/main/java/sample/tomcat/ssl/web/SampleController.java
@@ -0,0 +1,32 @@
+/*
+ * Copyright 2012-2016 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
+ *
+ * http://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 sample.tomcat.ssl.web;
+
+import org.springframework.stereotype.Controller;
+import org.springframework.web.bind.annotation.GetMapping;
+import org.springframework.web.bind.annotation.ResponseBody;
+
+@Controller
+public class SampleController {
+
+ @GetMapping("/")
+ @ResponseBody
+ public String helloWorld() {
+ return "Hello, world";
+ }
+
+}
diff --git a/spring-boot-samples/spring-boot-sample-tomcat80-ssl/src/main/resources/application.properties b/spring-boot-samples/spring-boot-sample-tomcat80-ssl/src/main/resources/application.properties
new file mode 100644
index 0000000000..37199bfd25
--- /dev/null
+++ b/spring-boot-samples/spring-boot-sample-tomcat80-ssl/src/main/resources/application.properties
@@ -0,0 +1,4 @@
+server.port = 8443
+server.ssl.key-store = classpath:sample.jks
+server.ssl.key-store-password = secret
+server.ssl.key-password = password
diff --git a/spring-boot-samples/spring-boot-sample-tomcat80-ssl/src/main/resources/sample.jks b/spring-boot-samples/spring-boot-sample-tomcat80-ssl/src/main/resources/sample.jks
new file mode 100644
index 0000000000..6aa9a28053
Binary files /dev/null and b/spring-boot-samples/spring-boot-sample-tomcat80-ssl/src/main/resources/sample.jks differ
diff --git a/spring-boot-samples/spring-boot-sample-tomcat80-ssl/src/test/java/sample/tomcat/ssl/SampleTomcatSslApplicationTests.java b/spring-boot-samples/spring-boot-sample-tomcat80-ssl/src/test/java/sample/tomcat/ssl/SampleTomcatSslApplicationTests.java
new file mode 100644
index 0000000000..f7b42c68a6
--- /dev/null
+++ b/spring-boot-samples/spring-boot-sample-tomcat80-ssl/src/test/java/sample/tomcat/ssl/SampleTomcatSslApplicationTests.java
@@ -0,0 +1,51 @@
+/*
+ * Copyright 2012-2016 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
+ *
+ * http://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 sample.tomcat.ssl;
+
+import org.junit.Test;
+import org.junit.runner.RunWith;
+
+import org.springframework.boot.context.embedded.LocalServerPort;
+import org.springframework.boot.test.context.SpringBootTest;
+import org.springframework.boot.test.context.SpringBootTest.WebEnvironment;
+import org.springframework.boot.test.web.client.TestRestTemplate;
+import org.springframework.boot.test.web.client.TestRestTemplate.HttpClientOption;
+import org.springframework.http.HttpStatus;
+import org.springframework.http.ResponseEntity;
+import org.springframework.test.annotation.DirtiesContext;
+import org.springframework.test.context.junit4.SpringRunner;
+
+import static org.assertj.core.api.Assertions.assertThat;
+
+@RunWith(SpringRunner.class)
+@SpringBootTest(webEnvironment = WebEnvironment.RANDOM_PORT)
+@DirtiesContext
+public class SampleTomcatSslApplicationTests {
+
+ @LocalServerPort
+ private int port;
+
+ @Test
+ public void testHome() throws Exception {
+ TestRestTemplate testRestTemplate = new TestRestTemplate(HttpClientOption.SSL);
+ ResponseEntity entity = testRestTemplate
+ .getForEntity("https://localhost:" + this.port, String.class);
+ assertThat(entity.getStatusCode()).isEqualTo(HttpStatus.OK);
+ assertThat(entity.getBody()).isEqualTo("Hello, world");
+ }
+
+}
diff --git a/spring-boot-starters/spring-boot-starter-tomcat/pom.xml b/spring-boot-starters/spring-boot-starter-tomcat/pom.xml
index 50ccbc4d84..7f8388079e 100644
--- a/spring-boot-starters/spring-boot-starter-tomcat/pom.xml
+++ b/spring-boot-starters/spring-boot-starter-tomcat/pom.xml
@@ -28,8 +28,8 @@
tomcat-embed-el
- org.apache.tomcat.embed
- tomcat-embed-logging-juli
+ org.apache.tomcat
+ tomcat-juli
org.apache.tomcat.embed
diff --git a/spring-boot-test/pom.xml b/spring-boot-test/pom.xml
index ff648694f3..067563b234 100644
--- a/spring-boot-test/pom.xml
+++ b/spring-boot-test/pom.xml
@@ -112,8 +112,8 @@
test
- org.apache.tomcat.embed
- tomcat-embed-logging-juli
+ org.apache.tomcat
+ tomcat-juli
test
diff --git a/spring-boot/pom.xml b/spring-boot/pom.xml
index 25648b9977..c90fe9e397 100644
--- a/spring-boot/pom.xml
+++ b/spring-boot/pom.xml
@@ -110,8 +110,8 @@
true
- org.apache.tomcat.embed
- tomcat-embed-logging-juli
+ org.apache.tomcat
+ tomcat-juli
true
diff --git a/spring-boot/src/main/java/org/springframework/boot/context/embedded/tomcat/TomcatEmbeddedJSSEImplementation.java b/spring-boot/src/main/java/org/springframework/boot/context/embedded/tomcat/TomcatEmbeddedJSSEImplementation.java
deleted file mode 100644
index 6681da0c4e..0000000000
--- a/spring-boot/src/main/java/org/springframework/boot/context/embedded/tomcat/TomcatEmbeddedJSSEImplementation.java
+++ /dev/null
@@ -1,98 +0,0 @@
-/*
- * Copyright 2012-2016 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
- *
- * http://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.context.embedded.tomcat;
-
-import java.io.IOException;
-import java.security.KeyStore;
-
-import org.apache.tomcat.util.net.AbstractEndpoint;
-import org.apache.tomcat.util.net.SSLUtil;
-import org.apache.tomcat.util.net.ServerSocketFactory;
-import org.apache.tomcat.util.net.jsse.JSSEImplementation;
-import org.apache.tomcat.util.net.jsse.JSSESocketFactory;
-
-import org.springframework.boot.context.embedded.SslStoreProvider;
-
-/**
- * {@link JSSEImplementation} for embedded Tomcat that supports {@link SslStoreProvider}.
- *
- * @author Phillip Webb
- * @author Venil Noronha
- * @since 1.4.0
- */
-public class TomcatEmbeddedJSSEImplementation extends JSSEImplementation {
-
- @Override
- public ServerSocketFactory getServerSocketFactory(AbstractEndpoint> endpoint) {
- return new SocketFactory(endpoint);
- }
-
- @Override
- public SSLUtil getSSLUtil(AbstractEndpoint> endpoint) {
- return new SocketFactory(endpoint);
- }
-
- /**
- * {@link JSSESocketFactory} that supports {@link SslStoreProvider}.
- */
- static class SocketFactory extends JSSESocketFactory {
-
- private final SslStoreProvider sslStoreProvider;
-
- SocketFactory(AbstractEndpoint> endpoint) {
- super(endpoint);
- this.sslStoreProvider = (SslStoreProvider) endpoint
- .getAttribute("sslStoreProvider");
- }
-
- @Override
- protected KeyStore getKeystore(String type, String provider, String pass)
- throws IOException {
- if (this.sslStoreProvider != null) {
- try {
- KeyStore store = this.sslStoreProvider.getKeyStore();
- if (store != null) {
- return store;
- }
- }
- catch (Exception ex) {
- throw new IOException(ex);
- }
- }
- return super.getKeystore(type, provider, pass);
- }
-
- @Override
- protected KeyStore getTrustStore(String keystoreType, String keystoreProvider)
- throws IOException {
- if (this.sslStoreProvider != null) {
- try {
- KeyStore store = this.sslStoreProvider.getTrustStore();
- if (store != null) {
- return store;
- }
- }
- catch (Exception ex) {
- throw new IOException(ex);
- }
- }
- return super.getTrustStore(keystoreType, keystoreProvider);
- }
-
- }
-
-}
diff --git a/spring-boot/src/main/java/org/springframework/boot/context/embedded/tomcat/TomcatEmbeddedServletContainerFactory.java b/spring-boot/src/main/java/org/springframework/boot/context/embedded/tomcat/TomcatEmbeddedServletContainerFactory.java
index 96477db2e4..e3e40a7688 100644
--- a/spring-boot/src/main/java/org/springframework/boot/context/embedded/tomcat/TomcatEmbeddedServletContainerFactory.java
+++ b/spring-boot/src/main/java/org/springframework/boot/context/embedded/tomcat/TomcatEmbeddedServletContainerFactory.java
@@ -16,12 +16,19 @@
package org.springframework.boot.context.embedded.tomcat;
+import java.io.ByteArrayInputStream;
+import java.io.ByteArrayOutputStream;
import java.io.File;
import java.io.FileNotFoundException;
import java.io.IOException;
import java.io.InputStream;
import java.lang.reflect.Method;
+import java.net.URL;
+import java.net.URLConnection;
+import java.net.URLStreamHandler;
+import java.net.URLStreamHandlerFactory;
import java.nio.charset.Charset;
+import java.security.KeyStore;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collection;
@@ -48,11 +55,13 @@ import org.apache.catalina.session.ManagerBase;
import org.apache.catalina.session.StandardManager;
import org.apache.catalina.startup.Tomcat;
import org.apache.catalina.startup.Tomcat.FixContextListener;
+import org.apache.catalina.webresources.TomcatURLStreamHandlerFactory;
import org.apache.coyote.AbstractProtocol;
import org.apache.coyote.ProtocolHandler;
import org.apache.coyote.http11.AbstractHttp11JsseProtocol;
import org.apache.coyote.http11.AbstractHttp11Protocol;
import org.apache.coyote.http11.Http11NioProtocol;
+import org.apache.tomcat.util.net.SSLHostConfig;
import org.springframework.beans.BeanUtils;
import org.springframework.boot.context.embedded.AbstractEmbeddedServletContainerFactory;
@@ -301,7 +310,7 @@ public class TomcatEmbeddedServletContainerFactory
Compression compression = getCompression();
protocol.setCompression("on");
protocol.setCompressionMinSize(compression.getMinResponseSize());
- protocol.setCompressableMimeTypes(
+ protocol.setCompressableMimeType(
StringUtils.arrayToCommaDelimitedString(compression.getMimeTypes()));
if (getCompression().getExcludedUserAgents() != null) {
protocol.setNoCompressionUserAgents(
@@ -323,13 +332,33 @@ public class TomcatEmbeddedServletContainerFactory
protocol.setKeystorePass(ssl.getKeyStorePassword());
protocol.setKeyPass(ssl.getKeyPassword());
protocol.setKeyAlias(ssl.getKeyAlias());
- protocol.setCiphers(StringUtils.arrayToCommaDelimitedString(ssl.getCiphers()));
+ String ciphers = StringUtils.arrayToCommaDelimitedString(ssl.getCiphers());
+ protocol.setCiphers(StringUtils.hasText(ciphers) ? ciphers : null);
if (ssl.getEnabledProtocols() != null) {
- protocol.setProperty("sslEnabledProtocols",
- StringUtils.arrayToCommaDelimitedString(ssl.getEnabledProtocols()));
+ try {
+ for (SSLHostConfig sslHostConfig : protocol.findSslHostConfigs()) {
+ sslHostConfig.setProtocols(StringUtils
+ .arrayToCommaDelimitedString(ssl.getEnabledProtocols()));
+ }
+ }
+ catch (NoSuchMethodError ex) {
+ // Tomcat 8.0.x or earlier
+ Assert.isTrue(
+ protocol.setProperty("sslEnabledProtocols",
+ StringUtils.arrayToCommaDelimitedString(
+ ssl.getEnabledProtocols())),
+ "Failed to set sslEnabledProtocols");
+ }
}
if (getSslStoreProvider() != null) {
- configureSslStoreProvider(protocol, getSslStoreProvider());
+ TomcatURLStreamHandlerFactory instance = TomcatURLStreamHandlerFactory
+ .getInstance();
+ instance.addUserFactory(
+ new SslStoreProviderUrlStreamHandlerFactory(getSslStoreProvider()));
+ protocol.setKeystoreFile(
+ SslStoreProviderUrlStreamHandlerFactory.KEY_STORE_URL);
+ protocol.setTruststoreFile(
+ SslStoreProviderUrlStreamHandlerFactory.TRUST_STORE_URL);
}
else {
configureSslKeyStore(protocol, ssl);
@@ -350,10 +379,6 @@ public class TomcatEmbeddedServletContainerFactory
SslStoreProvider sslStoreProvider) {
Assert.isInstanceOf(Http11NioProtocol.class, protocol,
"SslStoreProvider can only be used with Http11NioProtocol");
- ((Http11NioProtocol) protocol).getEndpoint().setAttribute("sslStoreProvider",
- sslStoreProvider);
- protocol.setSslImplementationName(
- TomcatEmbeddedJSSEImplementation.class.getName());
}
private void configureSslKeyStore(AbstractHttp11JsseProtocol> protocol, Ssl ssl) {
@@ -677,6 +702,89 @@ public class TomcatEmbeddedServletContainerFactory
return this.uriEncoding;
}
+ /**
+ * A {@link URLStreamHandlerFactory} that provides a {@link URLStreamHandler} for
+ * accessing an {@link SslStoreProvider}'s key store and trust store from a URL.
+ */
+ private static final class SslStoreProviderUrlStreamHandlerFactory
+ implements URLStreamHandlerFactory {
+
+ private static final String PROTOCOL = "springbootssl";
+
+ private static final String KEY_STORE_PATH = "keyStore";
+
+ private static final String KEY_STORE_URL = PROTOCOL + ":" + KEY_STORE_PATH;
+
+ private static final String TRUST_STORE_PATH = "trustStore";
+
+ private static final String TRUST_STORE_URL = PROTOCOL + ":" + TRUST_STORE_PATH;
+
+ private final SslStoreProvider sslStoreProvider;
+
+ private SslStoreProviderUrlStreamHandlerFactory(
+ SslStoreProvider sslStoreProvider) {
+ this.sslStoreProvider = sslStoreProvider;
+ }
+
+ @Override
+ public URLStreamHandler createURLStreamHandler(String protocol) {
+ if (PROTOCOL.equals(protocol)) {
+ return new URLStreamHandler() {
+
+ @Override
+ protected URLConnection openConnection(URL url) throws IOException {
+ try {
+ if (KEY_STORE_PATH.equals(url.getPath())) {
+ return new KeyStoreUrlConnection(url,
+ SslStoreProviderUrlStreamHandlerFactory.this.sslStoreProvider
+ .getKeyStore());
+ }
+ if (TRUST_STORE_PATH.equals(url.getPath())) {
+ return new KeyStoreUrlConnection(url,
+ SslStoreProviderUrlStreamHandlerFactory.this.sslStoreProvider
+ .getTrustStore());
+ }
+ }
+ catch (Exception ex) {
+ throw new IOException(ex);
+ }
+ throw new IOException("Invalid path: " + url.getPath());
+ }
+ };
+ }
+ return null;
+ }
+
+ private static final class KeyStoreUrlConnection extends URLConnection {
+
+ private final KeyStore keyStore;
+
+ private KeyStoreUrlConnection(URL url, KeyStore keyStore) {
+ super(url);
+ this.keyStore = keyStore;
+ }
+
+ @Override
+ public void connect() throws IOException {
+
+ }
+
+ @Override
+ public InputStream getInputStream() throws IOException {
+
+ try {
+ ByteArrayOutputStream stream = new ByteArrayOutputStream();
+ this.keyStore.store(stream, new char[0]);
+ return new ByteArrayInputStream(stream.toByteArray());
+ }
+ catch (Exception ex) {
+ throw new IOException(ex);
+ }
+ }
+
+ }
+ }
+
private static class TomcatErrorPage {
private static final String ERROR_PAGE_CLASS = "org.apache.tomcat.util.descriptor.web.ErrorPage";
@@ -752,8 +860,7 @@ public class TomcatEmbeddedServletContainerFactory
*/
private static class StoreMergedWebXmlListener implements LifecycleListener {
- @SuppressWarnings("deprecation")
- private final String MERGED_WEB_XML = org.apache.tomcat.util.scan.Constants.MERGED_WEB_XML;
+ private static final String MERGED_WEB_XML = "org.apache.tomcat.util.scan.MergedWebXml";
@Override
public void lifecycleEvent(LifecycleEvent event) {
@@ -764,8 +871,10 @@ public class TomcatEmbeddedServletContainerFactory
private void onStart(Context context) {
ServletContext servletContext = context.getServletContext();
- if (servletContext.getAttribute(this.MERGED_WEB_XML) == null) {
- servletContext.setAttribute(this.MERGED_WEB_XML, getEmptyWebXml());
+ if (servletContext
+ .getAttribute(StoreMergedWebXmlListener.MERGED_WEB_XML) == null) {
+ servletContext.setAttribute(StoreMergedWebXmlListener.MERGED_WEB_XML,
+ getEmptyWebXml());
}
TomcatResources.get(context).addClasspathResources();
}
diff --git a/spring-boot/src/test/java/org/springframework/boot/SpringApplicationTests.java b/spring-boot/src/test/java/org/springframework/boot/SpringApplicationTests.java
index c80dc0c2a9..84608f01a8 100644
--- a/spring-boot/src/test/java/org/springframework/boot/SpringApplicationTests.java
+++ b/spring-boot/src/test/java/org/springframework/boot/SpringApplicationTests.java
@@ -40,7 +40,7 @@ import org.springframework.beans.factory.support.BeanDefinitionRegistry;
import org.springframework.beans.factory.support.BeanNameGenerator;
import org.springframework.beans.factory.support.DefaultBeanNameGenerator;
import org.springframework.boot.context.embedded.AnnotationConfigEmbeddedWebApplicationContext;
-import org.springframework.boot.context.embedded.jetty.JettyEmbeddedServletContainerFactory;
+import org.springframework.boot.context.embedded.tomcat.TomcatEmbeddedServletContainerFactory;
import org.springframework.boot.context.event.ApplicationEnvironmentPreparedEvent;
import org.springframework.boot.context.event.ApplicationPreparedEvent;
import org.springframework.boot.context.event.ApplicationReadyEvent;
@@ -971,8 +971,8 @@ public class SpringApplicationTests {
static class ExampleWebConfig {
@Bean
- public JettyEmbeddedServletContainerFactory container() {
- return new JettyEmbeddedServletContainerFactory(0);
+ public TomcatEmbeddedServletContainerFactory container() {
+ return new TomcatEmbeddedServletContainerFactory(0);
}
}
diff --git a/spring-boot/src/test/java/org/springframework/boot/context/embedded/AbstractEmbeddedServletContainerFactoryTests.java b/spring-boot/src/test/java/org/springframework/boot/context/embedded/AbstractEmbeddedServletContainerFactoryTests.java
index faede699dd..f9cd1df718 100644
--- a/spring-boot/src/test/java/org/springframework/boot/context/embedded/AbstractEmbeddedServletContainerFactoryTests.java
+++ b/spring-boot/src/test/java/org/springframework/boot/context/embedded/AbstractEmbeddedServletContainerFactoryTests.java
@@ -55,6 +55,7 @@ import javax.servlet.ServletResponse;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpSession;
+import org.apache.catalina.webresources.TomcatURLStreamHandlerFactory;
import org.apache.http.client.HttpClient;
import org.apache.http.client.entity.InputStreamFactory;
import org.apache.http.client.protocol.HttpClientContext;
@@ -124,6 +125,8 @@ public abstract class AbstractEmbeddedServletContainerFactoryTests {
@BeforeClass
@AfterClass
public static void uninstallUrlStreamHandlerFactory() {
+ ReflectionTestUtils.setField(TomcatURLStreamHandlerFactory.class, "instance",
+ null);
ReflectionTestUtils.setField(URL.class, "factory", null);
}
@@ -589,7 +592,7 @@ public abstract class AbstractEmbeddedServletContainerFactoryTests {
assertThat(response.getStatusCode()).isEqualTo(HttpStatus.NOT_FOUND);
}
- private Ssl getSsl(ClientAuth clientAuth, String keyPassword, String keyStore) {
+ protected Ssl getSsl(ClientAuth clientAuth, String keyPassword, String keyStore) {
return getSsl(clientAuth, keyPassword, keyStore, null, null, null);
}
diff --git a/spring-boot/src/test/java/org/springframework/boot/context/embedded/tomcat/TomcatEmbeddedServletContainerFactoryTests.java b/spring-boot/src/test/java/org/springframework/boot/context/embedded/tomcat/TomcatEmbeddedServletContainerFactoryTests.java
index 2b57c02b09..8695ef7099 100644
--- a/spring-boot/src/test/java/org/springframework/boot/context/embedded/tomcat/TomcatEmbeddedServletContainerFactoryTests.java
+++ b/spring-boot/src/test/java/org/springframework/boot/context/embedded/tomcat/TomcatEmbeddedServletContainerFactoryTests.java
@@ -38,7 +38,7 @@ import org.apache.catalina.Wrapper;
import org.apache.catalina.connector.Connector;
import org.apache.catalina.startup.Tomcat;
import org.apache.catalina.valves.RemoteIpValve;
-import org.apache.coyote.http11.AbstractHttp11JsseProtocol;
+import org.apache.tomcat.util.net.SSLHostConfig;
import org.junit.After;
import org.junit.Rule;
import org.junit.Test;
@@ -266,16 +266,14 @@ public class TomcatEmbeddedServletContainerFactoryTests
Tomcat tomcat = getTomcat(factory);
Connector connector = tomcat.getConnector();
- AbstractHttp11JsseProtocol> jsseProtocol = (AbstractHttp11JsseProtocol>) connector
- .getProtocolHandler();
- assertThat(jsseProtocol.getCiphers()).isEqualTo("ALPHA,BRAVO,CHARLIE");
+ SSLHostConfig[] sslHostConfigs = connector.getProtocolHandler()
+ .findSslHostConfigs();
+ assertThat(sslHostConfigs[0].getCiphers()).isEqualTo("ALPHA:BRAVO:CHARLIE");
}
@Test
public void sslEnabledMultipleProtocolsConfiguration() throws Exception {
- Ssl ssl = new Ssl();
- ssl.setKeyStore("test.jks");
- ssl.setKeyStorePassword("secret");
+ Ssl ssl = getSsl(null, "password", "src/test/resources/test.jks");
ssl.setEnabledProtocols(new String[] { "TLSv1.1", "TLSv1.2" });
ssl.setCiphers(new String[] { "TLS_ECDHE_RSA_WITH_AES_128_CBC_SHA256", "BRAVO" });
@@ -284,21 +282,20 @@ public class TomcatEmbeddedServletContainerFactoryTests
this.container = factory
.getEmbeddedServletContainer(sessionServletRegistration());
+ this.container.start();
Tomcat tomcat = ((TomcatEmbeddedServletContainer) this.container).getTomcat();
Connector connector = tomcat.getConnector();
- AbstractHttp11JsseProtocol> jsseProtocol = (AbstractHttp11JsseProtocol>) connector
- .getProtocolHandler();
- assertThat(jsseProtocol.getSslProtocol()).isEqualTo("TLS");
- assertThat(jsseProtocol.getProperty("sslEnabledProtocols"))
- .isEqualTo("TLSv1.1,TLSv1.2");
+ SSLHostConfig sslHostConfig = connector.getProtocolHandler()
+ .findSslHostConfigs()[0];
+ assertThat(sslHostConfig.getSslProtocol()).isEqualTo("TLS");
+ assertThat(sslHostConfig.getEnabledProtocols())
+ .containsExactlyInAnyOrder("TLSv1.1", "TLSv1.2");
}
@Test
public void sslEnabledProtocolsConfiguration() throws Exception {
- Ssl ssl = new Ssl();
- ssl.setKeyStore("test.jks");
- ssl.setKeyStorePassword("secret");
+ Ssl ssl = getSsl(null, "password", "src/test/resources/test.jks");
ssl.setEnabledProtocols(new String[] { "TLSv1.2" });
ssl.setCiphers(new String[] { "TLS_ECDHE_RSA_WITH_AES_128_CBC_SHA256", "BRAVO" });
@@ -310,10 +307,11 @@ public class TomcatEmbeddedServletContainerFactoryTests
Tomcat tomcat = ((TomcatEmbeddedServletContainer) this.container).getTomcat();
Connector connector = tomcat.getConnector();
- AbstractHttp11JsseProtocol> jsseProtocol = (AbstractHttp11JsseProtocol>) connector
- .getProtocolHandler();
- assertThat(jsseProtocol.getSslProtocol()).isEqualTo("TLS");
- assertThat(jsseProtocol.getProperty("sslEnabledProtocols")).isEqualTo("TLSv1.2");
+ this.container.start();
+ SSLHostConfig sslHostConfig = connector.getProtocolHandler()
+ .findSslHostConfigs()[0];
+ assertThat(sslHostConfig.getSslProtocol()).isEqualTo("TLS");
+ assertThat(sslHostConfig.getEnabledProtocols()).containsExactly("TLSv1.2");
}
@Test