Browse Source
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
7 changed files with 0 additions and 251 deletions
@ -1,52 +0,0 @@
@@ -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 @@
@@ -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 @@
@@ -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 @@
@@ -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 @@
@@ -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 @@
@@ -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 @@
@@ -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