diff --git a/core/build.gradle b/core/build.gradle index 265bc378de9..b2f48647bef 100644 --- a/core/build.gradle +++ b/core/build.gradle @@ -71,4 +71,5 @@ dependencies { testImplementation "org.testcontainers:testcontainers:1.20.3" testImplementation "org.testcontainers:junit-jupiter:1.20.3" + testImplementation "org.bouncycastle:bcpkix-jdk18on:1.78.1" } diff --git a/core/src/main/java/io/kestra/core/http/client/HttpClient.java b/core/src/main/java/io/kestra/core/http/client/HttpClient.java index 8716849603c..3837fdca8d3 100644 --- a/core/src/main/java/io/kestra/core/http/client/HttpClient.java +++ b/core/src/main/java/io/kestra/core/http/client/HttpClient.java @@ -40,6 +40,7 @@ import java.util.List; import java.util.function.Consumer; import javax.net.ssl.SSLContext; +import javax.net.ssl.SSLHandshakeException; @Slf4j public class HttpClient implements Closeable { @@ -252,6 +253,10 @@ private HttpResponse request( } catch (SocketException e) { throw new HttpClientRequestException(e.getMessage(), request, e); } catch (IOException e) { + if (e instanceof SSLHandshakeException) { + throw new HttpClientRequestException(e.getMessage(), request, e); + } + if (e.getCause() instanceof HttpClientException httpClientException) { throw httpClientException; } diff --git a/core/src/test/java/io/kestra/plugin/core/http/RequestTest.java b/core/src/test/java/io/kestra/plugin/core/http/RequestTest.java index 60b53684952..22336e4b268 100644 --- a/core/src/test/java/io/kestra/plugin/core/http/RequestTest.java +++ b/core/src/test/java/io/kestra/plugin/core/http/RequestTest.java @@ -3,6 +3,7 @@ import com.devskiller.friendly_id.FriendlyId; import com.google.common.base.Charsets; import com.google.common.collect.ImmutableMap; +import io.kestra.core.http.client.HttpClientRequestException; import io.kestra.core.http.client.HttpClientResponseException; import io.kestra.core.http.client.configurations.*; import io.kestra.core.junit.annotations.KestraTest; @@ -13,6 +14,7 @@ import io.kestra.core.utils.IdUtils; import io.kestra.core.utils.TestsUtils; import io.micronaut.context.ApplicationContext; +import io.micronaut.context.env.Environment; import io.micronaut.http.*; import io.micronaut.http.annotation.*; import io.micronaut.http.multipart.StreamingFileUpload; @@ -187,28 +189,58 @@ void failed() throws Exception { @Test void selfSigned() throws Exception { - final String url = "https://self-signed.badssl.com/"; + try ( + ApplicationContext applicationContext = ApplicationContext.run(Environment.TEST, "testssl"); + EmbeddedServer server = applicationContext.getBean(EmbeddedServer.class).start(); - Request task = Request.builder() - .id(RequestTest.class.getSimpleName()) - .type(RequestTest.class.getName()) - .uri(url) - .headers(Map.of("bla", "sdfsdf")) - .options(HttpConfiguration.builder() - .allowFailed(true) - .timeout(TimeoutConfiguration.builder().readIdleTimeout(Duration.ofSeconds(30)).build()) - .ssl(SslOptions.builder().insecureTrustAllCertificates(true).build()) - .build() - ) - .build(); + ) { + Request task = Request.builder() + .id(RequestTest.class.getSimpleName()) + .type(RequestTest.class.getName()) + .uri(server.getURL().toString() + "/hello") + .options(HttpConfiguration.builder() + .timeout(TimeoutConfiguration.builder().readIdleTimeout(Duration.ofSeconds(30)).build()) + .ssl(SslOptions.builder().insecureTrustAllCertificates(true).build()) + .build() + ) + .build(); - RunContext runContext = TestsUtils.mockRunContext(this.runContextFactory, task, ImmutableMap.of()); + RunContext runContext = TestsUtils.mockRunContext(this.runContextFactory, task, ImmutableMap.of()); - Request.Output output = task.run(runContext); + Request.Output output = task.run(runContext); - assertThat(output.getUri(), is(URI.create(url))); - assertThat((String) output.getBody(), containsString("self-signed.
badssl.com")); - assertThat(output.getCode(), is(200)); + assertThat(output.getBody(), is("{ \"hello\": \"world\" }")); + assertThat(output.getCode(), is(200)); + } + } + + @Test + void selfSignedFailed() { + try ( + ApplicationContext applicationContext = ApplicationContext.run(Environment.TEST, "testssl"); + EmbeddedServer server = applicationContext.getBean(EmbeddedServer.class).start(); + + ) { + Request task = Request.builder() + .id(RequestTest.class.getSimpleName()) + .type(RequestTest.class.getName()) + .uri(server.getURL().toString() + "/hello") + .options(HttpConfiguration.builder() + .allowFailed(true) + .timeout(TimeoutConfiguration.builder().readIdleTimeout(Duration.ofSeconds(30)).build()) + .build() + ) + .build(); + + RunContext runContext = TestsUtils.mockRunContext(this.runContextFactory, task, ImmutableMap.of()); + + HttpClientRequestException exception = assertThrows( + HttpClientRequestException.class, + () -> task.run(runContext) + ); + + assertThat(exception.getMessage(), containsString("unable to find valid certification path")); + } } @Test diff --git a/core/src/test/resources/application-testssl.yml b/core/src/test/resources/application-testssl.yml new file mode 100644 index 00000000000..d9bddcea1b4 --- /dev/null +++ b/core/src/test/resources/application-testssl.yml @@ -0,0 +1,7 @@ +micronaut: + server: + ssl: + enabled: true + build-self-signed: true + port: "${random.port}" + dual-protocol : true