Remove spring-boot-smoke-test-webflux-ssl
Remove `spring-boot-smoke-test-webflux-ssl` since it's more of an integration test than a smoke test. We could consider relocating it to `spring-boot-integration-tests` but since we have unit tests with a mock PCKCS11 security it's probably best to see if we can get away without it. See gh-32179pull/33648/head
parent
bc6fc33498
commit
e8e56dbb11
@ -1,52 +0,0 @@
|
|||||||
plugins {
|
|
||||||
id "java"
|
|
||||||
id "org.springframework.boot.conventions"
|
|
||||||
id "org.springframework.boot.integration-test"
|
|
||||||
}
|
|
||||||
|
|
||||||
description = "Spring Boot WebFlux SSL smoke test"
|
|
||||||
|
|
||||||
|
|
||||||
configurations {
|
|
||||||
app
|
|
||||||
}
|
|
||||||
|
|
||||||
dependencies {
|
|
||||||
app project(path: ":spring-boot-project:spring-boot-dependencies", configuration: "mavenRepository")
|
|
||||||
app project(path: ":spring-boot-project:spring-boot-parent", configuration: "mavenRepository")
|
|
||||||
app project(path: ":spring-boot-project:spring-boot-tools:spring-boot-gradle-plugin", configuration: "mavenRepository")
|
|
||||||
app project(path: ":spring-boot-project:spring-boot-starters:spring-boot-starter-webflux", configuration: "mavenRepository")
|
|
||||||
|
|
||||||
testImplementation(enforcedPlatform(project(":spring-boot-project:spring-boot-parent")))
|
|
||||||
testImplementation(project(":spring-boot-project:spring-boot-tools:spring-boot-test-support"))
|
|
||||||
testImplementation(project(":spring-boot-project:spring-boot-starters:spring-boot-starter-test"))
|
|
||||||
testImplementation("org.testcontainers:junit-jupiter")
|
|
||||||
// For the WebClient in tests
|
|
||||||
testImplementation(project(":spring-boot-project:spring-boot-starters:spring-boot-starter-webflux"))
|
|
||||||
}
|
|
||||||
|
|
||||||
task syncMavenRepository(type: Sync) {
|
|
||||||
from configurations.app
|
|
||||||
into "${buildDir}/int-test-maven-repository"
|
|
||||||
}
|
|
||||||
|
|
||||||
task syncAppGradleFiles(type: org.springframework.boot.build.SyncAppSource) {
|
|
||||||
sourceDirectory = file("spring-boot-starter-webflux-tests-app")
|
|
||||||
destinationDirectory = file("${buildDir}/spring-boot-starter-webflux-tests-app")
|
|
||||||
}
|
|
||||||
|
|
||||||
task syncAppSource(type: org.springframework.boot.build.SyncAppSource) {
|
|
||||||
sourceDirectory = file("../spring-boot-smoke-test-webflux/src/main")
|
|
||||||
destinationDirectory = file("${buildDir}/spring-boot-starter-webflux-tests-app/src/main")
|
|
||||||
}
|
|
||||||
|
|
||||||
task buildApp(type: GradleBuild) {
|
|
||||||
dependsOn syncAppGradleFiles, syncAppSource, syncMavenRepository
|
|
||||||
dir = "${buildDir}/spring-boot-starter-webflux-tests-app"
|
|
||||||
startParameter.buildCacheEnabled = false
|
|
||||||
tasks = ["build"]
|
|
||||||
}
|
|
||||||
|
|
||||||
test {
|
|
||||||
dependsOn buildApp
|
|
||||||
}
|
|
@ -1,31 +0,0 @@
|
|||||||
plugins {
|
|
||||||
id "java"
|
|
||||||
id "org.springframework.boot"
|
|
||||||
}
|
|
||||||
|
|
||||||
apply plugin: "io.spring.dependency-management"
|
|
||||||
|
|
||||||
repositories {
|
|
||||||
maven { url "file:${rootDir}/../int-test-maven-repository"}
|
|
||||||
mavenCentral()
|
|
||||||
maven {
|
|
||||||
url "https://repo.spring.io/milestone"
|
|
||||||
content {
|
|
||||||
excludeGroup "org.springframework.boot"
|
|
||||||
}
|
|
||||||
}
|
|
||||||
maven {
|
|
||||||
url "https://repo.spring.io/snapshot"
|
|
||||||
content {
|
|
||||||
excludeGroup "org.springframework.boot"
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
dependencies {
|
|
||||||
implementation("org.springframework.boot:spring-boot-starter-webflux")
|
|
||||||
}
|
|
||||||
|
|
||||||
bootJar {
|
|
||||||
launchScript()
|
|
||||||
}
|
|
@ -1,15 +0,0 @@
|
|||||||
pluginManagement {
|
|
||||||
repositories {
|
|
||||||
maven { url "file:${rootDir}/../int-test-maven-repository"}
|
|
||||||
mavenCentral()
|
|
||||||
maven { url "https://repo.spring.io/snapshot" }
|
|
||||||
maven { url "https://repo.spring.io/milestone" }
|
|
||||||
}
|
|
||||||
resolutionStrategy {
|
|
||||||
eachPlugin {
|
|
||||||
if (requested.id.id == "org.springframework.boot") {
|
|
||||||
useModule "org.springframework.boot:spring-boot-gradle-plugin:${requested.version}"
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
@ -1,122 +0,0 @@
|
|||||||
/*
|
|
||||||
* Copyright 2012-2022 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.webflux.ssl;
|
|
||||||
|
|
||||||
import java.io.File;
|
|
||||||
import java.io.FileInputStream;
|
|
||||||
import java.security.KeyStore;
|
|
||||||
import java.security.cert.Certificate;
|
|
||||||
import java.security.cert.CertificateFactory;
|
|
||||||
|
|
||||||
import javax.net.ssl.TrustManagerFactory;
|
|
||||||
|
|
||||||
import io.netty.handler.ssl.SslContext;
|
|
||||||
import io.netty.handler.ssl.SslContextBuilder;
|
|
||||||
import org.junit.jupiter.api.Test;
|
|
||||||
import org.testcontainers.containers.GenericContainer;
|
|
||||||
import org.testcontainers.containers.output.ToStringConsumer;
|
|
||||||
import org.testcontainers.containers.wait.strategy.Wait;
|
|
||||||
import org.testcontainers.images.builder.ImageFromDockerfile;
|
|
||||||
import org.testcontainers.junit.jupiter.Testcontainers;
|
|
||||||
import org.testcontainers.utility.MountableFile;
|
|
||||||
import reactor.netty.http.client.HttpClient;
|
|
||||||
|
|
||||||
import org.springframework.http.client.reactive.ReactorClientHttpConnector;
|
|
||||||
import org.springframework.web.reactive.function.client.WebClient;
|
|
||||||
|
|
||||||
import static org.assertj.core.api.Assertions.assertThat;
|
|
||||||
import static org.assertj.core.api.Assertions.assertThatNoException;
|
|
||||||
import static org.assertj.core.api.Assertions.fail;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Integration tests of Spring Boot's SSL server configured to use a PKCS#11 keystore
|
|
||||||
* (HSM).
|
|
||||||
*
|
|
||||||
* @author Cyril Dangerville
|
|
||||||
*/
|
|
||||||
@Testcontainers(disabledWithoutDocker = true)
|
|
||||||
class EmbeddedNettySslServerWithPkcs11KeystoreTests {
|
|
||||||
|
|
||||||
@Test
|
|
||||||
void launchWithPkcs11KeystoreProvider() {
|
|
||||||
/*
|
|
||||||
* We are going to use the server certificate of the keypair generated in the
|
|
||||||
* PKCS#11 HSM inside the container, as trusted certificate for the SSL
|
|
||||||
* connection, to make sure that the Netty SSL server is actually using this
|
|
||||||
* certificate and the associated keypair in the HSM. The certificate is extracted
|
|
||||||
* to /server-cert.pem by the keytool command run inside the container at startup
|
|
||||||
* (see src/test/resources/docker-entrypoint.sh).
|
|
||||||
*/
|
|
||||||
final File serverCertDestinationFile = new File("build/tmp/test/server-cert.pem");
|
|
||||||
final ToStringConsumer consumer = new ToStringConsumer().withRemoveAnsiCodes(false);
|
|
||||||
try (SpringBootJarTestContainer container = new SpringBootJarTestContainer()) {
|
|
||||||
container.withLogConsumer(consumer);
|
|
||||||
container.start();
|
|
||||||
assertThat(consumer.toUtf8String().contains("Netty started"));
|
|
||||||
|
|
||||||
// HTTPS connection test
|
|
||||||
container.copyFileFromContainer("/server-cert.pem", serverCertDestinationFile.getAbsolutePath());
|
|
||||||
final KeyStore truststore = KeyStore.getInstance(KeyStore.getDefaultType());
|
|
||||||
truststore.load(null, null);
|
|
||||||
final CertificateFactory certFactory = CertificateFactory.getInstance("X.509");
|
|
||||||
final Certificate cert;
|
|
||||||
try (FileInputStream input = new FileInputStream(serverCertDestinationFile)) {
|
|
||||||
cert = certFactory.generateCertificate(input);
|
|
||||||
}
|
|
||||||
truststore.setCertificateEntry("server", cert);
|
|
||||||
TrustManagerFactory trustManagerFactory = TrustManagerFactory
|
|
||||||
.getInstance(TrustManagerFactory.getDefaultAlgorithm());
|
|
||||||
trustManagerFactory.init(truststore);
|
|
||||||
final SslContext sslContext = SslContextBuilder.forClient().trustManager(trustManagerFactory).build();
|
|
||||||
final HttpClient httpClient = HttpClient.create().secure((sslSpec) -> sslSpec.sslContext(sslContext));
|
|
||||||
final WebClient httpsClient = WebClient.builder()
|
|
||||||
.clientConnector(new ReactorClientHttpConnector(httpClient)).build();
|
|
||||||
assertThatNoException()
|
|
||||||
.isThrownBy(() -> httpsClient.get().uri("https://localhost:" + container.getFirstMappedPort() + "/")
|
|
||||||
.retrieve().toEntity(String.class).block());
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
catch (Throwable ex) {
|
|
||||||
ex.printStackTrace();
|
|
||||||
}
|
|
||||||
|
|
||||||
fail("Container failed to start or SSL test failed. Startup logs: " + consumer.toUtf8String());
|
|
||||||
}
|
|
||||||
|
|
||||||
private static final class SpringBootJarTestContainer extends GenericContainer<SpringBootJarTestContainer> {
|
|
||||||
|
|
||||||
private SpringBootJarTestContainer() {
|
|
||||||
super(new ImageFromDockerfile("spring-boot-smoke-test-webflux-ssl/ssl-server-with-pkcs11-keystore")
|
|
||||||
.withFileFromFile("Dockerfile",
|
|
||||||
new File("src/test/resources/ssl-server-with-pkcs11-keystore/Dockerfile")));
|
|
||||||
withCopyFileToContainer(MountableFile.forHostPath(new File(
|
|
||||||
"build/spring-boot-starter-webflux-tests-app/build/libs/spring-boot-starter-webflux-tests-app.jar")
|
|
||||||
.getAbsolutePath()),
|
|
||||||
"/app.jar");
|
|
||||||
final String startupScript = "docker-entrypoint.sh";
|
|
||||||
withCopyFileToContainer(
|
|
||||||
MountableFile.forHostPath("src/test/resources/ssl-server-with-pkcs11-keystore/" + startupScript),
|
|
||||||
"/" + startupScript);
|
|
||||||
withCommand("/bin/bash", "-c", "chown root:root *.sh && chown root:root *.jar && chmod +x " + startupScript
|
|
||||||
+ " && ./" + startupScript);
|
|
||||||
withExposedPorts(8443);
|
|
||||||
waitingFor(Wait.forListeningPort());
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
@ -1,14 +0,0 @@
|
|||||||
<configuration>
|
|
||||||
<appender name="STDOUT" class="ch.qos.logback.core.ConsoleAppender">
|
|
||||||
<encoder>
|
|
||||||
<pattern>%d{HH:mm:ss.SSS} [%thread] %-5level %logger - %msg%n</pattern>
|
|
||||||
</encoder>
|
|
||||||
</appender>
|
|
||||||
|
|
||||||
<root level="info">
|
|
||||||
<appender-ref ref="STDOUT"/>
|
|
||||||
</root>
|
|
||||||
|
|
||||||
<logger name="org.testcontainers" level="INFO"/>
|
|
||||||
<logger name="com.github.dockerjava" level="WARN"/>
|
|
||||||
</configuration>
|
|
@ -1,14 +0,0 @@
|
|||||||
FROM ubuntu:jammy
|
|
||||||
RUN apt-get update && \
|
|
||||||
apt-get install -y software-properties-common curl softhsm2 && \
|
|
||||||
mkdir -p /opt/openjdk && \
|
|
||||||
cd /opt/openjdk && \
|
|
||||||
curl -L https://github.com/adoptium/temurin17-binaries/releases/download/jdk-17.0.1%2B12/OpenJDK17U-jdk_x64_linux_hotspot_17.0.1_12.tar.gz | tar zx --strip-components=1 && \
|
|
||||||
# this mkdir fixes old SoftHSMv2 install issue in older Ubuntus: https://github.com/opendnssec/SoftHSMv2/issues/283
|
|
||||||
# mkdir -p /var/lib/softhsm/tokens && \
|
|
||||||
echo "name = SoftHSM\nlibrary = /usr/lib/softhsm/libsofthsm2.so\nslotListIndex = 0" > /pkcs11.cfg && \
|
|
||||||
echo "security.provider.12=SunPKCS11 /pkcs11.cfg" > /java.security.override
|
|
||||||
|
|
||||||
ENV JAVA_HOME /opt/openjdk
|
|
||||||
ENV PATH $JAVA_HOME/bin:$PATH
|
|
||||||
ENV JAVA_OPTS "-Djava.security.properties=/java.security.override -Djava.security.debug=sunpkcs11 -Djava.security.debug=pkcs11keystore"
|
|
@ -1,3 +0,0 @@
|
|||||||
# Initialize a SoftHSM token only if not done already, e.g. at first start
|
|
||||||
softhsm2-util --show-slots | grep "token-0" || { softhsm2-util --init-token --free --label "token-0" --pin 1234 --so-pin 0000; keytool -genkeypair -alias server -dname CN=localhost -ext san=dns:localhost -keyalg RSA -keysize 2048 -keystore NONE -storetype PKCS11 -providerclass sun.security.pkcs11.SunPKCS11 -providerarg /pkcs11.cfg -storepass 1234; keytool -exportcert -rfc -alias server -keystore NONE -storetype PKCS11 -providerclass sun.security.pkcs11.SunPKCS11 -providerarg /pkcs11.cfg -storepass 1234 > /server-cert.pem; }
|
|
||||||
java ${JAVA_OPTS} -jar /app.jar --server.port=8443 --server.ssl.enabled=true --server.ssl.key-alias=server --server.ssl.key-store-provider=SunPKCS11-SoftHSM --server.ssl.key-store-type=PKCS11 --server.ssl.key-store-password=1234
|
|
Loading…
Reference in New Issue