Merge branch '3.4.x'

Closes gh-43891
This commit is contained in:
Andy Wilkinson
2025-01-21 12:10:35 +00:00
7 changed files with 195 additions and 11 deletions

View File

@@ -0,0 +1,21 @@
plugins {
id "java"
}
description = "Spring Boot Tomcat 11 SSL smoke test"
configurations.all {
resolutionStrategy.eachDependency {
if (it.requested.group == 'org.apache.tomcat' || it.requested.group == 'org.apache.tomcat.embed') {
it.useVersion '11.0.0'
}
}
}
dependencies {
implementation(project(":spring-boot-project:spring-boot-starters:spring-boot-starter-web"))
implementation(project(":spring-boot-project:spring-boot-starters:spring-boot-starter-actuator"))
testImplementation(project(":spring-boot-project:spring-boot-starters:spring-boot-starter-test"))
testImplementation("org.apache.httpcomponents.client5:httpclient5")
}

View File

@@ -0,0 +1,29 @@
/*
* Copyright 2012-2025 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
*
* https://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 smoketest.tomcat.ssl;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
@SpringBootApplication
public class SampleTomcat11SslApplication {
public static void main(String[] args) {
SpringApplication.run(SampleTomcat11SslApplication.class, args);
}
}

View File

@@ -0,0 +1,30 @@
/*
* Copyright 2012-2025 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
*
* https://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 smoketest.tomcat.ssl.web;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RestController;
@RestController
public class SampleController {
@GetMapping("/")
public String helloWorld() {
return "Hello, world";
}
}

View File

@@ -0,0 +1,13 @@
server.port=8443
management.endpoints.web.exposure.include=*
management.endpoint.health.show-details=always
management.health.ssl.certificate-validity-warning-threshold=7d
management.health.ssl.enabled=true
management.info.ssl.enabled=true
server.ssl.bundle=ssldemo
spring.ssl.bundle.jks.ssldemo.keystore.location=classpath:sample.jks
spring.ssl.bundle.jks.ssldemo.keystore.password=secret
spring.ssl.bundle.jks.ssldemo.keystore.type=JKS
spring.ssl.bundle.jks.ssldemo.key.password=password

View File

@@ -0,0 +1,92 @@
/*
* Copyright 2012-2025 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
*
* https://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 smoketest.tomcat.ssl;
import org.junit.jupiter.api.Test;
import org.springframework.beans.factory.annotation.Autowired;
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.web.server.AbstractConfigurableWebServerFactory;
import org.springframework.http.HttpStatus;
import org.springframework.http.ResponseEntity;
import org.springframework.test.json.JsonContent;
import static org.assertj.core.api.Assertions.assertThat;
@SpringBootTest(webEnvironment = WebEnvironment.RANDOM_PORT)
class SampleTomcat11SslApplicationTests {
@Autowired
private TestRestTemplate restTemplate;
@Autowired
private AbstractConfigurableWebServerFactory webServerFactory;
@Test
void testSsl() {
assertThat(this.webServerFactory.getSsl().isEnabled()).isTrue();
}
@Test
void testHome() {
ResponseEntity<String> entity = this.restTemplate.getForEntity("/", String.class);
assertThat(entity.getStatusCode()).isEqualTo(HttpStatus.OK);
assertThat(entity.getBody()).isEqualTo("Hello, world");
}
@Test
void testSslInfo() {
ResponseEntity<String> entity = this.restTemplate.getForEntity("/actuator/info", String.class);
assertThat(entity.getStatusCode()).isEqualTo(HttpStatus.OK);
JsonContent body = new JsonContent(entity.getBody());
assertThat(body).extractingPath("ssl.bundles[0].name").isEqualTo("ssldemo");
assertThat(body).extractingPath("ssl.bundles[0].certificateChains[0].alias")
.isEqualTo("spring-boot-ssl-sample");
assertThat(body).extractingPath("ssl.bundles[0].certificateChains[0].certificates[0].issuer")
.isEqualTo("CN=localhost,OU=Unknown,O=Unknown,L=Unknown,ST=Unknown,C=Unknown");
assertThat(body).extractingPath("ssl.bundles[0].certificateChains[0].certificates[0].subject")
.isEqualTo("CN=localhost,OU=Unknown,O=Unknown,L=Unknown,ST=Unknown,C=Unknown");
assertThat(body).extractingPath("ssl.bundles[0].certificateChains[0].certificates[0].validity.status")
.isEqualTo("EXPIRED");
assertThat(body).extractingPath("ssl.bundles[0].certificateChains[0].certificates[0].validity.message")
.asString()
.startsWith("Not valid after ");
}
@Test
void testSslHealth() {
ResponseEntity<String> entity = this.restTemplate.getForEntity("/actuator/health", String.class);
assertThat(entity.getStatusCode()).isEqualTo(HttpStatus.SERVICE_UNAVAILABLE);
JsonContent body = new JsonContent(entity.getBody());
assertThat(body).extractingPath("status").isEqualTo("OUT_OF_SERVICE");
assertThat(body).extractingPath("components.ssl.status").isEqualTo("OUT_OF_SERVICE");
assertThat(body).extractingPath("components.ssl.details.invalidChains[0].alias")
.isEqualTo("spring-boot-ssl-sample");
assertThat(body).extractingPath("components.ssl.details.invalidChains[0].certificates[0].issuer")
.isEqualTo("CN=localhost,OU=Unknown,O=Unknown,L=Unknown,ST=Unknown,C=Unknown");
assertThat(body).extractingPath("components.ssl.details.invalidChains[0].certificates[0].subject")
.isEqualTo("CN=localhost,OU=Unknown,O=Unknown,L=Unknown,ST=Unknown,C=Unknown");
assertThat(body).extractingPath("components.ssl.details.invalidChains[0].certificates[0].validity.status")
.isEqualTo("EXPIRED");
assertThat(body).extractingPath("components.ssl.details.invalidChains[0].certificates[0].validity.message")
.asString()
.startsWith("Not valid after ");
}
}