From 864fe808ab7a539d99ec801774958b4bbb2ced55 Mon Sep 17 00:00:00 2001 From: Tim Carter Date: Fri, 18 Oct 2024 17:00:36 +1100 Subject: [PATCH 1/5] Make byte buffer size configurable. Add configurable whitelist of proxy targets. Factor out common IO code. Switch to using Vert.x server. Add support for HTTPS. Handle exceptions seen when connection dies between client and server. Refactored domain proxy in general for consistency. --- .../.dockerignore | 0 java-components/domain-proxy/Dockerfile | 4 + .../client/pom.xml | 8 +- .../domainproxy/client/DomainProxyClient.java | 57 ++++++++ .../src/main/resources/application.properties | 3 + java-components/domain-proxy/common/pom.xml | 18 +++ .../domainproxy/common/CommonIOUtil.java | 84 +++++++++++ .../{domainproxy => domain-proxy}/pom.xml | 13 +- .../server/pom.xml | 8 +- .../hacbs/domainproxy/DomainProxyServer.java | 70 +++++++++ .../domainproxy/ExternalProxyVerticle.java | 135 ++++++++++++++++++ .../hacbs/domainproxy/VerticleDeployer.java | 15 ++ .../src/main/resources/application.properties | 4 + .../ExternalProxyEndpointTest.disabled} | 0 java-components/domainproxy/Dockerfile | 4 - .../domainproxy/client/UnsharedProxy.java | 90 ------------ .../src/main/resources/application.properties | 1 - .../redhat/hacbs/domainproxy/Dependency.java | 14 -- .../hacbs/domainproxy/DomainProxyHack.java | 113 --------------- .../domainproxy/ExternalProxyEndpoint.java | 54 ------- .../src/main/resources/application.properties | 4 - java-components/pom.xml | 2 +- 22 files changed, 413 insertions(+), 288 deletions(-) rename java-components/{domainproxy => domain-proxy}/.dockerignore (100%) create mode 100644 java-components/domain-proxy/Dockerfile rename java-components/{domainproxy => domain-proxy}/client/pom.xml (88%) create mode 100644 java-components/domain-proxy/client/src/main/java/com/redhat/hacbs/domainproxy/client/DomainProxyClient.java create mode 100644 java-components/domain-proxy/client/src/main/resources/application.properties create mode 100644 java-components/domain-proxy/common/pom.xml create mode 100644 java-components/domain-proxy/common/src/main/java/com/redhat/hacbs/domainproxy/common/CommonIOUtil.java rename java-components/{domainproxy => domain-proxy}/pom.xml (72%) rename java-components/{domainproxy => domain-proxy}/server/pom.xml (92%) create mode 100644 java-components/domain-proxy/server/src/main/java/com/redhat/hacbs/domainproxy/DomainProxyServer.java create mode 100644 java-components/domain-proxy/server/src/main/java/com/redhat/hacbs/domainproxy/ExternalProxyVerticle.java create mode 100644 java-components/domain-proxy/server/src/main/java/com/redhat/hacbs/domainproxy/VerticleDeployer.java create mode 100644 java-components/domain-proxy/server/src/main/resources/application.properties rename java-components/{domainproxy/server/src/test/java/com/redhat/hacbs/domainproxy/ExternalProxyEndpointTest.java => domain-proxy/server/src/test/java/com/redhat/hacbs/domainproxy/ExternalProxyEndpointTest.disabled} (100%) delete mode 100644 java-components/domainproxy/Dockerfile delete mode 100644 java-components/domainproxy/client/src/main/java/com/redhat/hacbs/domainproxy/client/UnsharedProxy.java delete mode 100644 java-components/domainproxy/client/src/main/resources/application.properties delete mode 100644 java-components/domainproxy/server/src/main/java/com/redhat/hacbs/domainproxy/Dependency.java delete mode 100644 java-components/domainproxy/server/src/main/java/com/redhat/hacbs/domainproxy/DomainProxyHack.java delete mode 100644 java-components/domainproxy/server/src/main/java/com/redhat/hacbs/domainproxy/ExternalProxyEndpoint.java delete mode 100644 java-components/domainproxy/server/src/main/resources/application.properties diff --git a/java-components/domainproxy/.dockerignore b/java-components/domain-proxy/.dockerignore similarity index 100% rename from java-components/domainproxy/.dockerignore rename to java-components/domain-proxy/.dockerignore diff --git a/java-components/domain-proxy/Dockerfile b/java-components/domain-proxy/Dockerfile new file mode 100644 index 000000000..9f5659422 --- /dev/null +++ b/java-components/domain-proxy/Dockerfile @@ -0,0 +1,4 @@ +FROM quay.io/redhat-appstudio/buildah:v1.35.4@sha256:3d3575bb7d0df64abcf1f22f06e82101a945d03317db1f3caac12814f796d01c +RUN dnf install -y iproute +COPY client/target/domain-proxy-client-999-SNAPSHOT-runner /app/domain-proxy-client-runner +COPY server/target/domain-proxy-server-999-SNAPSHOT-runner /app/domain-proxy-server-runner diff --git a/java-components/domainproxy/client/pom.xml b/java-components/domain-proxy/client/pom.xml similarity index 88% rename from java-components/domainproxy/client/pom.xml rename to java-components/domain-proxy/client/pom.xml index 1cb8ade6e..94436ce6e 100644 --- a/java-components/domainproxy/client/pom.xml +++ b/java-components/domain-proxy/client/pom.xml @@ -4,10 +4,10 @@ 4.0.0 io.github.redhat-appstudio.jvmbuild - domainproxy-parent + domain-proxy-parent 999-SNAPSHOT - domainproxy-client + domain-proxy-client @@ -24,6 +24,10 @@ rest-assured test + + io.github.redhat-appstudio.jvmbuild + domain-proxy-common + diff --git a/java-components/domain-proxy/client/src/main/java/com/redhat/hacbs/domainproxy/client/DomainProxyClient.java b/java-components/domain-proxy/client/src/main/java/com/redhat/hacbs/domainproxy/client/DomainProxyClient.java new file mode 100644 index 000000000..19e05be64 --- /dev/null +++ b/java-components/domain-proxy/client/src/main/java/com/redhat/hacbs/domainproxy/client/DomainProxyClient.java @@ -0,0 +1,57 @@ +package com.redhat.hacbs.domainproxy.client; + +import java.io.IOException; +import java.net.ServerSocket; +import java.net.Socket; +import java.net.UnixDomainSocketAddress; +import java.nio.channels.SocketChannel; + +import jakarta.annotation.PostConstruct; +import jakarta.inject.Inject; +import jakarta.inject.Singleton; + +import org.eclipse.microprofile.config.inject.ConfigProperty; + +import com.redhat.hacbs.domainproxy.common.CommonIOUtil; + +import io.quarkus.logging.Log; +import io.quarkus.runtime.Quarkus; +import io.quarkus.runtime.Startup; + +@Startup +@Singleton +public class DomainProxyClient { + + @Inject + @ConfigProperty(name = "client-domain-socket") + String domainSocket; + + @Inject + @ConfigProperty(name = "client-http-port") + int clientHttpPort; + + @Inject + @ConfigProperty(name = "byte-buffer-size") + int byteBufferSize; + + @PostConstruct + public void start() { + Log.info("Starting domain proxy client..."); + new Thread(() -> { + try (final ServerSocket serverSocket = new ServerSocket(clientHttpPort)) { + while (true) { + final Socket socket = serverSocket.accept(); + final UnixDomainSocketAddress address = UnixDomainSocketAddress.of(domainSocket); + final SocketChannel channel = SocketChannel.open(address); + // write from socket to channel + CommonIOUtil.createSocketToChannelWriter(byteBufferSize, socket, channel).start(); + // write from channel to socket + CommonIOUtil.createChannelToSocketWriter(byteBufferSize, channel, socket).start(); + } + } catch (final IOException e) { + Log.errorf(e, "Error initialising domain proxy client"); + } + Quarkus.asyncExit(); + }).start(); + } +} diff --git a/java-components/domain-proxy/client/src/main/resources/application.properties b/java-components/domain-proxy/client/src/main/resources/application.properties new file mode 100644 index 000000000..b5617e7ce --- /dev/null +++ b/java-components/domain-proxy/client/src/main/resources/application.properties @@ -0,0 +1,3 @@ +client-domain-socket=${DOMAIN_SOCKET:/tmp/domainserver} +client-http-port=8080 +byte-buffer-size=${BYTE_BUFFER_SIZE:1024} diff --git a/java-components/domain-proxy/common/pom.xml b/java-components/domain-proxy/common/pom.xml new file mode 100644 index 000000000..2190f3a52 --- /dev/null +++ b/java-components/domain-proxy/common/pom.xml @@ -0,0 +1,18 @@ + + + 4.0.0 + + io.github.redhat-appstudio.jvmbuild + domain-proxy-parent + 999-SNAPSHOT + + domain-proxy-common + + + + org.jboss.logging + jboss-logging + + + diff --git a/java-components/domain-proxy/common/src/main/java/com/redhat/hacbs/domainproxy/common/CommonIOUtil.java b/java-components/domain-proxy/common/src/main/java/com/redhat/hacbs/domainproxy/common/CommonIOUtil.java new file mode 100644 index 000000000..98e5392eb --- /dev/null +++ b/java-components/domain-proxy/common/src/main/java/com/redhat/hacbs/domainproxy/common/CommonIOUtil.java @@ -0,0 +1,84 @@ +package com.redhat.hacbs.domainproxy.common; + +import java.io.IOException; +import java.net.Socket; +import java.net.SocketException; +import java.nio.ByteBuffer; +import java.nio.channels.AsynchronousCloseException; +import java.nio.channels.SocketChannel; + +import org.jboss.logging.Logger; + +public final class CommonIOUtil { + + private static final Logger LOG = Logger.getLogger(CommonIOUtil.class); + + public static Thread createSocketToChannelWriter(final int byteBufferSize, final Socket socket, + final SocketChannel channel) { + // write from socket to channel + return new Thread(() -> { + int r; + final byte[] buf = new byte[byteBufferSize]; + int bytesWritten = 0; + LOG.info("Writing from socket to channel"); + try { + while ((r = socket.getInputStream().read(buf)) > 0) { + channel.write(ByteBuffer.wrap(buf, 0, r)); + bytesWritten += r; + } + } catch (final SocketException ignore) { + LOG.info("Socket closed"); + } catch (final IOException e) { + LOG.errorf(e, "Error writing from socket to channel"); + } finally { + try { + channel.close(); + } catch (final Exception e) { + LOG.errorf(e, "Error closing channel"); + } + try { + socket.close(); + } catch (final IOException e) { + LOG.errorf(e, "Error closing socket"); + } + } + LOG.infof("Wrote %d bytes from socket to channel", bytesWritten); + }); + } + + public static Thread createChannelToSocketWriter(final int byteBufferSize, final SocketChannel channel, + final Socket socket) { + // write from channel to socket + return new Thread(() -> { + int r; + final ByteBuffer buf = ByteBuffer.allocate(byteBufferSize); + buf.clear(); + int bytesWritten = 0; + LOG.info("Writing from channel to socket"); + try { + while ((r = channel.read(buf)) > 0) { + buf.flip(); + socket.getOutputStream().write(buf.array(), buf.arrayOffset(), buf.remaining()); + buf.clear(); + bytesWritten += r; + } + } catch (final AsynchronousCloseException ignore) { + LOG.info("Channel closed"); + } catch (final Exception e) { + LOG.errorf(e, "Error writing from channel to socket"); + } finally { + try { + channel.close(); + } catch (final IOException e) { + LOG.errorf(e, "Error closing channel"); + } + try { + socket.close(); + } catch (final IOException e) { + LOG.errorf(e, "Error closing socket"); + } + } + LOG.infof("Wrote %d bytes from channel to socket", bytesWritten); + }); + } +} diff --git a/java-components/domainproxy/pom.xml b/java-components/domain-proxy/pom.xml similarity index 72% rename from java-components/domainproxy/pom.xml rename to java-components/domain-proxy/pom.xml index 9eb4484d6..8c158cbf2 100644 --- a/java-components/domainproxy/pom.xml +++ b/java-components/domain-proxy/pom.xml @@ -7,7 +7,7 @@ jvm-build-service-parent 999-SNAPSHOT - domainproxy-parent + domain-proxy-parent pom true @@ -16,8 +16,19 @@ server client + common + + + + io.github.redhat-appstudio.jvmbuild + domain-proxy-common + ${project.version} + + + + native diff --git a/java-components/domainproxy/server/pom.xml b/java-components/domain-proxy/server/pom.xml similarity index 92% rename from java-components/domainproxy/server/pom.xml rename to java-components/domain-proxy/server/pom.xml index 545324587..691704776 100644 --- a/java-components/domainproxy/server/pom.xml +++ b/java-components/domain-proxy/server/pom.xml @@ -4,15 +4,15 @@ 4.0.0 io.github.redhat-appstudio.jvmbuild - domainproxy-parent + domain-proxy-parent 999-SNAPSHOT - domainproxy-server + domain-proxy-server io.quarkus - quarkus-rest + quarkus-vertx io.quarkus @@ -30,7 +30,7 @@ io.github.redhat-appstudio.jvmbuild - common-maven + domain-proxy-common diff --git a/java-components/domain-proxy/server/src/main/java/com/redhat/hacbs/domainproxy/DomainProxyServer.java b/java-components/domain-proxy/server/src/main/java/com/redhat/hacbs/domainproxy/DomainProxyServer.java new file mode 100644 index 000000000..63fac1326 --- /dev/null +++ b/java-components/domain-proxy/server/src/main/java/com/redhat/hacbs/domainproxy/DomainProxyServer.java @@ -0,0 +1,70 @@ +package com.redhat.hacbs.domainproxy; + +import java.io.IOException; +import java.net.Socket; +import java.net.StandardProtocolFamily; +import java.net.UnixDomainSocketAddress; +import java.nio.channels.ServerSocketChannel; +import java.nio.channels.SocketChannel; +import java.nio.file.Files; +import java.nio.file.Path; + +import jakarta.annotation.PostConstruct; +import jakarta.inject.Inject; +import jakarta.inject.Singleton; + +import org.eclipse.microprofile.config.inject.ConfigProperty; + +import com.redhat.hacbs.domainproxy.common.CommonIOUtil; + +import io.quarkus.logging.Log; +import io.quarkus.runtime.Quarkus; +import io.quarkus.runtime.Startup; + +@Startup +@Singleton +public class DomainProxyServer { + + static final String HOST = "localhost"; + + @Inject + @ConfigProperty(name = "server-domain-socket") + String domainSocket; + + @Inject + @ConfigProperty(name = "server-http-port") + int serverHttpPort; + + @Inject + @ConfigProperty(name = "byte-buffer-size") + int byteBufferSize; + + @PostConstruct + public void start() { + Log.info("Starting domain proxy server..."); + new Thread(() -> { + Runtime.getRuntime().addShutdownHook(new Thread(() -> { + try { + Files.delete(Path.of(domainSocket)); + } catch (final IOException e) { + Log.errorf(e, "Error deleting domain socket"); + } + })); + try (final ServerSocketChannel serverChannel = ServerSocketChannel.open(StandardProtocolFamily.UNIX)) { + final UnixDomainSocketAddress address = UnixDomainSocketAddress.of(domainSocket); + serverChannel.bind(address); + while (true) { + final SocketChannel channel = serverChannel.accept(); + final Socket socket = new Socket(HOST, serverHttpPort); + // write from socket to channel + CommonIOUtil.createSocketToChannelWriter(byteBufferSize, socket, channel).start(); + // write from channel to socket + CommonIOUtil.createChannelToSocketWriter(byteBufferSize, channel, socket).start(); + } + } catch (final IOException e) { + Log.errorf(e, "Error initialising domain proxy server"); + } + Quarkus.asyncExit(); + }).start(); + } +} diff --git a/java-components/domain-proxy/server/src/main/java/com/redhat/hacbs/domainproxy/ExternalProxyVerticle.java b/java-components/domain-proxy/server/src/main/java/com/redhat/hacbs/domainproxy/ExternalProxyVerticle.java new file mode 100644 index 000000000..078215c6c --- /dev/null +++ b/java-components/domain-proxy/server/src/main/java/com/redhat/hacbs/domainproxy/ExternalProxyVerticle.java @@ -0,0 +1,135 @@ +package com.redhat.hacbs.domainproxy; + +import java.util.Set; + +import jakarta.enterprise.context.ApplicationScoped; +import jakarta.inject.Inject; + +import org.eclipse.microprofile.config.inject.ConfigProperty; + +import io.netty.handler.codec.http.HttpResponseStatus; +import io.quarkus.logging.Log; +import io.vertx.core.AbstractVerticle; +import io.vertx.core.Vertx; +import io.vertx.core.buffer.Buffer; +import io.vertx.core.http.HttpMethod; +import io.vertx.core.http.HttpServer; +import io.vertx.core.http.HttpServerRequest; +import io.vertx.core.net.NetClient; +import io.vertx.core.net.NetClientOptions; +import io.vertx.core.net.NetSocket; +import io.vertx.ext.web.client.HttpResponse; +import io.vertx.ext.web.client.WebClient; +import io.vertx.ext.web.client.WebClientOptions; + +@ApplicationScoped +public class ExternalProxyVerticle extends AbstractVerticle { + + static final int HTTPS_PORT = 443; + + @Inject + @ConfigProperty(name = "server-http-port") + int serverHttpPort; + + @Inject + @ConfigProperty(name = "proxy-target-whitelist") + Set proxyTargetWhitelist; + + private final WebClient webClient; + private final NetClient netClient; + + public ExternalProxyVerticle(final Vertx vertx) { + webClient = WebClient.create(vertx, new WebClientOptions()); + netClient = vertx.createNetClient(new NetClientOptions()); + } + + @Override + public void start() { + final HttpServer server = vertx.createHttpServer(); + server.requestHandler(request -> { + if (request.method() == HttpMethod.GET) { + handleGetRequest(request); + } else if (request.method() == HttpMethod.CONNECT) { + handleConnectRequest(request); + } + }); + server.listen(serverHttpPort, result -> { + if (result.succeeded()) { + Log.infof("Server is now listening on port %d", serverHttpPort); + } else { + Log.errorf(result.cause(), "Failed to bind server"); + } + }); + } + + private void handleGetRequest(final HttpServerRequest request) { + Log.info("Handling HTTP GET Request"); + if (isTargetWhitelisted(request.authority().host(), request)) { + webClient.getAbs(request.uri()).send(asyncResult -> { + if (asyncResult.succeeded()) { + final HttpResponse response = asyncResult.result(); + if (response.statusCode() != HttpResponseStatus.OK.code()) { + Log.errorf("Response code: %d, message: %s, body: %s", response.statusCode(), response.statusMessage(), + response.bodyAsString()); + } + request.response() + .setStatusCode(response.statusCode()) + .headers().addAll(response.headers()); + request.response().end(response.body()); + } else { + Log.errorf(asyncResult.cause(), "Failed to get response"); + request.response() + .setStatusCode(HttpResponseStatus.BAD_GATEWAY.code()) + .setStatusMessage(HttpResponseStatus.BAD_GATEWAY.reasonPhrase()) + .end("The server received an invalid response from the upstream server."); + } + }); + } + } + + private void handleConnectRequest(final HttpServerRequest request) { + Log.info("Handling HTTPS CONNECT request"); // + final String targetHost = request.authority().host(); + if (isTargetWhitelisted(targetHost, request)) { + int targetPort = request.authority().port(); + if (targetPort == -1) { + targetPort = HTTPS_PORT; + } + netClient.connect(targetPort, targetHost, targetConnect -> { + if (targetConnect.succeeded()) { + final NetSocket targetSocket = targetConnect.result(); + request.toNetSocket().onComplete(sourceConnect -> { + if (sourceConnect.succeeded()) { + final NetSocket sourceSocket = sourceConnect.result(); + sourceSocket.handler(targetSocket::write); + targetSocket.handler(sourceSocket::write); + sourceSocket.closeHandler(v -> targetSocket.close()); + targetSocket.closeHandler(v -> sourceSocket.close()); + } else { + Log.errorf(sourceConnect.cause(), "Failed to connect to source"); + } + }); + } else { + Log.errorf(targetConnect.cause(), "Failed to connect to target"); + request.response() + .setStatusCode(HttpResponseStatus.BAD_GATEWAY.code()) + .setStatusMessage(HttpResponseStatus.BAD_GATEWAY.reasonPhrase()) + .end("The server received an invalid response from the upstream server."); + } + }); + } + } + + private boolean isTargetWhitelisted(final String targetHost, final HttpServerRequest request) { + Log.infof("Target %s", targetHost); + if (!proxyTargetWhitelist.contains(targetHost)) { + Log.error("Target is not in whitelist"); + request.response() + .setStatusCode(HttpResponseStatus.NOT_FOUND.code()) + .setStatusMessage(HttpResponseStatus.NOT_FOUND.reasonPhrase()) + .end("The requested resource was not found."); + return false; + } + return true; + } +} diff --git a/java-components/domain-proxy/server/src/main/java/com/redhat/hacbs/domainproxy/VerticleDeployer.java b/java-components/domain-proxy/server/src/main/java/com/redhat/hacbs/domainproxy/VerticleDeployer.java new file mode 100644 index 000000000..ecd7e0b07 --- /dev/null +++ b/java-components/domain-proxy/server/src/main/java/com/redhat/hacbs/domainproxy/VerticleDeployer.java @@ -0,0 +1,15 @@ +package com.redhat.hacbs.domainproxy; + +import jakarta.enterprise.context.ApplicationScoped; +import jakarta.enterprise.event.Observes; + +import io.quarkus.runtime.StartupEvent; +import io.vertx.mutiny.core.Vertx; + +@ApplicationScoped +public class VerticleDeployer { + + public void init(final @Observes StartupEvent e, final Vertx vertx, final ExternalProxyVerticle verticle) { + vertx.deployVerticle(verticle).await().indefinitely(); + } +} diff --git a/java-components/domain-proxy/server/src/main/resources/application.properties b/java-components/domain-proxy/server/src/main/resources/application.properties new file mode 100644 index 000000000..a7465e5c8 --- /dev/null +++ b/java-components/domain-proxy/server/src/main/resources/application.properties @@ -0,0 +1,4 @@ +server-domain-socket=${DOMAIN_SOCKET:/tmp/domainserver} +server-http-port=2000 +byte-buffer-size=${BYTE_BUFFER_SIZE:1024} +proxy-target-whitelist=${PROXY_TARGET_WHITELIST:repo.maven.apache.org,repository.jboss.org,packages.confluent.io,jitpack.io,repo.gradle.org,plugins.gradle.org} diff --git a/java-components/domainproxy/server/src/test/java/com/redhat/hacbs/domainproxy/ExternalProxyEndpointTest.java b/java-components/domain-proxy/server/src/test/java/com/redhat/hacbs/domainproxy/ExternalProxyEndpointTest.disabled similarity index 100% rename from java-components/domainproxy/server/src/test/java/com/redhat/hacbs/domainproxy/ExternalProxyEndpointTest.java rename to java-components/domain-proxy/server/src/test/java/com/redhat/hacbs/domainproxy/ExternalProxyEndpointTest.disabled diff --git a/java-components/domainproxy/Dockerfile b/java-components/domainproxy/Dockerfile deleted file mode 100644 index 5884476ef..000000000 --- a/java-components/domainproxy/Dockerfile +++ /dev/null @@ -1,4 +0,0 @@ -FROM quay.io/redhat-appstudio/buildah:v1.35.4@sha256:3d3575bb7d0df64abcf1f22f06e82101a945d03317db1f3caac12814f796d01c -RUN dnf install -y iproute -COPY client/target/domainproxy-client-999-SNAPSHOT-runner /app/domainproxy-client-runner -COPY server/target/domainproxy-server-999-SNAPSHOT-runner /app/domainproxy-server-runner diff --git a/java-components/domainproxy/client/src/main/java/com/redhat/hacbs/domainproxy/client/UnsharedProxy.java b/java-components/domainproxy/client/src/main/java/com/redhat/hacbs/domainproxy/client/UnsharedProxy.java deleted file mode 100644 index 7f2558d6a..000000000 --- a/java-components/domainproxy/client/src/main/java/com/redhat/hacbs/domainproxy/client/UnsharedProxy.java +++ /dev/null @@ -1,90 +0,0 @@ -package com.redhat.hacbs.domainproxy.client; - -import java.io.IOException; -import java.net.ServerSocket; -import java.net.Socket; -import java.net.UnixDomainSocketAddress; -import java.nio.ByteBuffer; -import java.nio.channels.SocketChannel; - -import jakarta.annotation.PostConstruct; - -import io.quarkus.runtime.Quarkus; -import io.quarkus.runtime.Startup; - -@Startup -public class UnsharedProxy { - - @PostConstruct - public void start() { - new Thread(new Runnable() { - @Override - public void run() { - try (ServerSocket socket = new ServerSocket(8080)) { - while (true) { - Socket s = socket.accept(); - UnixDomainSocketAddress address = UnixDomainSocketAddress.of("/tmp/domainserver"); - SocketChannel channel = SocketChannel.open(address); - new Thread(new Runnable() { - @Override - public void run() { - int r; - byte[] buf = new byte[1024]; - try { - while ((r = s.getInputStream().read(buf)) > 0) { - channel.write(ByteBuffer.wrap(buf, 0, r)); - } - } catch (IOException e) { - e.printStackTrace(); - } finally { - try { - channel.close(); - } catch (Exception ex) { - ex.printStackTrace(); - } - try { - s.close(); - } catch (IOException ex) { - ex.printStackTrace(); - } - } - } - }).start(); - new Thread(new Runnable() { - @Override - public void run() { - ByteBuffer buf = ByteBuffer.allocate(1024); - buf.clear(); - try { - while (channel.read(buf) > 0) { - buf.flip(); - s.getOutputStream().write(buf.array(), buf.arrayOffset(), buf.remaining()); - buf.clear(); - } - } catch (Exception e) { - e.printStackTrace(); - } finally { - - try { - channel.close(); - } catch (IOException ex) { - ex.printStackTrace(); - } - try { - s.close(); - } catch (IOException ex) { - ex.printStackTrace(); - } - } - } - }).start(); - } - } catch (IOException e) { - e.printStackTrace(); - } - Quarkus.asyncExit(); - } - }).start(); - } - -} diff --git a/java-components/domainproxy/client/src/main/resources/application.properties b/java-components/domainproxy/client/src/main/resources/application.properties deleted file mode 100644 index f6ea4e4c4..000000000 --- a/java-components/domainproxy/client/src/main/resources/application.properties +++ /dev/null @@ -1 +0,0 @@ -client-domain-socket=${DOMAIN_SOCKET:/tmp/domainserver} diff --git a/java-components/domainproxy/server/src/main/java/com/redhat/hacbs/domainproxy/Dependency.java b/java-components/domainproxy/server/src/main/java/com/redhat/hacbs/domainproxy/Dependency.java deleted file mode 100644 index 64ba008ee..000000000 --- a/java-components/domainproxy/server/src/main/java/com/redhat/hacbs/domainproxy/Dependency.java +++ /dev/null @@ -1,14 +0,0 @@ -package com.redhat.hacbs.domainproxy; - -import java.util.Comparator; - -import com.redhat.hacbs.common.maven.GAV; - -public record Dependency(GAV GAV, String classifier) implements Comparable { - @Override - public int compareTo(Dependency o) { - return Comparator.comparing(Dependency::GAV) - .thenComparing(Dependency::classifier, Comparator.nullsFirst(Comparator.naturalOrder())) - .compare(this, o); - } -} diff --git a/java-components/domainproxy/server/src/main/java/com/redhat/hacbs/domainproxy/DomainProxyHack.java b/java-components/domainproxy/server/src/main/java/com/redhat/hacbs/domainproxy/DomainProxyHack.java deleted file mode 100644 index eca86feaa..000000000 --- a/java-components/domainproxy/server/src/main/java/com/redhat/hacbs/domainproxy/DomainProxyHack.java +++ /dev/null @@ -1,113 +0,0 @@ -package com.redhat.hacbs.domainproxy; - -import java.io.IOException; -import java.net.Socket; -import java.net.StandardProtocolFamily; -import java.net.UnixDomainSocketAddress; -import java.nio.ByteBuffer; -import java.nio.channels.ServerSocketChannel; -import java.nio.channels.SocketChannel; -import java.nio.file.Files; -import java.nio.file.Path; - -import jakarta.annotation.PostConstruct; -import jakarta.inject.Inject; -import jakarta.inject.Singleton; - -import org.eclipse.microprofile.config.inject.ConfigProperty; - -import io.quarkus.runtime.Quarkus; -import io.quarkus.runtime.Startup; - -@Startup -@Singleton -public class DomainProxyHack { - - @Inject - @ConfigProperty(name = "server-domain-socket") - String domainSocket; - - @PostConstruct - public void start() { - new Thread(new Runnable() { - @Override - public void run() { - Runtime.getRuntime().addShutdownHook(new Thread(new Runnable() { - @Override - public void run() { - try { - Files.delete(Path.of(domainSocket)); - } catch (IOException e) { - e.printStackTrace(); - } - } - })); - try { - UnixDomainSocketAddress address = UnixDomainSocketAddress.of(domainSocket); - var socket = ServerSocketChannel.open(StandardProtocolFamily.UNIX); - socket.bind(address); - while (true) { - SocketChannel channel = socket.accept(); - Socket s = new Socket("localhost", 2000); - new Thread(new Runnable() { - @Override - public void run() { - int r; - byte[] buf = new byte[1024]; - try { - while ((r = s.getInputStream().read(buf)) > 0) { - channel.write(ByteBuffer.wrap(buf, 0, r)); - } - } catch (IOException e) { - e.printStackTrace(); - } finally { - try { - channel.close(); - } catch (Exception ex) { - ex.printStackTrace(); - } - try { - s.close(); - } catch (IOException ex) { - ex.printStackTrace(); - } - } - } - }).start(); - new Thread(new Runnable() { - @Override - public void run() { - ByteBuffer buf = ByteBuffer.allocate(1024); - buf.clear(); - try { - while (channel.read(buf) > 0) { - buf.flip(); - s.getOutputStream().write(buf.array(), buf.arrayOffset(), buf.remaining()); - buf.clear(); - } - } catch (Exception e) { - e.printStackTrace(); - } finally { - - try { - channel.close(); - } catch (IOException ex) { - ex.printStackTrace(); - } - try { - s.close(); - } catch (IOException ex) { - ex.printStackTrace(); - } - } - } - }).start(); - } - } catch (IOException e) { - e.printStackTrace(); - } - Quarkus.asyncExit(); - } - }).start(); - } -} diff --git a/java-components/domainproxy/server/src/main/java/com/redhat/hacbs/domainproxy/ExternalProxyEndpoint.java b/java-components/domainproxy/server/src/main/java/com/redhat/hacbs/domainproxy/ExternalProxyEndpoint.java deleted file mode 100644 index cc6db521e..000000000 --- a/java-components/domainproxy/server/src/main/java/com/redhat/hacbs/domainproxy/ExternalProxyEndpoint.java +++ /dev/null @@ -1,54 +0,0 @@ -package com.redhat.hacbs.domainproxy; - -import java.io.InputStream; -import java.util.HashMap; -import java.util.List; -import java.util.Map; - -import jakarta.ws.rs.GET; -import jakarta.ws.rs.NotFoundException; -import jakarta.ws.rs.Path; -import jakarta.ws.rs.PathParam; -import jakarta.ws.rs.client.Client; -import jakarta.ws.rs.client.ClientBuilder; - -import org.eclipse.microprofile.config.Config; -import org.eclipse.microprofile.config.inject.ConfigProperty; - -import io.quarkus.logging.Log; -import io.vertx.core.Vertx; - -@Path("/") -public class ExternalProxyEndpoint { - - final Client client; - final Map proxyTargets; - - public ExternalProxyEndpoint(Config config, - @ConfigProperty(name = "proxy-paths") List endpoints, Vertx vertx) { - client = ClientBuilder.newBuilder() - .build(); - Map targets = new HashMap<>(); - for (var endpoint : endpoints) { - var proxyTarget = config.getConfigValue("proxy-path." + endpoint + ".target").getValue(); - targets.put(endpoint, proxyTarget); - } - this.proxyTargets = targets; - } - - @GET - @Path("{root}/{path:.*}") - public InputStream get(@PathParam("root") String root, @PathParam("path") String path) { - var target = proxyTargets.get(root); - if (target == null) { - throw new NotFoundException(); - } - var response = client.target(target + "/" + path).request().get(); - if (response.getStatus() != 200) { - Log.errorf("Response %d %s", response.getStatus(), response.readEntity(String.class)); - throw new NotFoundException(); - } - - return response.readEntity(InputStream.class); - } -} diff --git a/java-components/domainproxy/server/src/main/resources/application.properties b/java-components/domainproxy/server/src/main/resources/application.properties deleted file mode 100644 index a49b14694..000000000 --- a/java-components/domainproxy/server/src/main/resources/application.properties +++ /dev/null @@ -1,4 +0,0 @@ -server-domain-socket=${DOMAIN_SOCKET:/tmp/domainserver} -quarkus.http.port=2000 -proxy-paths=main -proxy-path.main.target=https://repo1.maven.org/maven2 diff --git a/java-components/pom.xml b/java-components/pom.xml index 92cebb16b..4d68e7931 100644 --- a/java-components/pom.xml +++ b/java-components/pom.xml @@ -85,7 +85,7 @@ common-tools common-images common-maven - domainproxy + domain-proxy From 10cac0a9d5dcff6d05413a7c68e7e0873fe0124f Mon Sep 17 00:00:00 2001 From: Tim Carter Date: Tue, 22 Oct 2024 16:08:28 +1100 Subject: [PATCH 2/5] Implement unit tests. Minor refactoring. Migrate to JDK 21 to support Virtual Threads. --- java-components/domain-proxy/client/pom.xml | 11 -- .../domainproxy/client/DomainProxyClient.java | 13 +- .../domainproxy/common/CommonIOUtil.java | 16 +-- java-components/domain-proxy/server/pom.xml | 5 + .../hacbs/domainproxy/DomainProxyServer.java | 20 ++-- .../domainproxy/ExternalProxyVerticle.java | 12 +- .../ExternalProxyEndpointTest.disabled | 50 -------- .../ExternalProxyVerticleTest.java | 113 ++++++++++++++++++ .../ExternalProxyVerticleTestProfile.java | 15 +++ .../server/src/test/resources/bar-1.0.pom | 9 ++ java-components/pom.xml | 2 +- 11 files changed, 175 insertions(+), 91 deletions(-) delete mode 100644 java-components/domain-proxy/server/src/test/java/com/redhat/hacbs/domainproxy/ExternalProxyEndpointTest.disabled create mode 100644 java-components/domain-proxy/server/src/test/java/com/redhat/hacbs/domainproxy/ExternalProxyVerticleTest.java create mode 100644 java-components/domain-proxy/server/src/test/java/com/redhat/hacbs/domainproxy/ExternalProxyVerticleTestProfile.java create mode 100644 java-components/domain-proxy/server/src/test/resources/bar-1.0.pom diff --git a/java-components/domain-proxy/client/pom.xml b/java-components/domain-proxy/client/pom.xml index 94436ce6e..cf1471c9a 100644 --- a/java-components/domain-proxy/client/pom.xml +++ b/java-components/domain-proxy/client/pom.xml @@ -14,16 +14,6 @@ io.quarkus quarkus-arc - - io.quarkus - quarkus-junit5 - test - - - io.rest-assured - rest-assured - test - io.github.redhat-appstudio.jvmbuild domain-proxy-common @@ -41,7 +31,6 @@ build generate-code - generate-code-tests diff --git a/java-components/domain-proxy/client/src/main/java/com/redhat/hacbs/domainproxy/client/DomainProxyClient.java b/java-components/domain-proxy/client/src/main/java/com/redhat/hacbs/domainproxy/client/DomainProxyClient.java index 19e05be64..196cf44ae 100644 --- a/java-components/domain-proxy/client/src/main/java/com/redhat/hacbs/domainproxy/client/DomainProxyClient.java +++ b/java-components/domain-proxy/client/src/main/java/com/redhat/hacbs/domainproxy/client/DomainProxyClient.java @@ -1,5 +1,8 @@ package com.redhat.hacbs.domainproxy.client; +import static com.redhat.hacbs.domainproxy.common.CommonIOUtil.createChannelToSocketWriter; +import static com.redhat.hacbs.domainproxy.common.CommonIOUtil.createSocketToChannelWriter; + import java.io.IOException; import java.net.ServerSocket; import java.net.Socket; @@ -12,8 +15,6 @@ import org.eclipse.microprofile.config.inject.ConfigProperty; -import com.redhat.hacbs.domainproxy.common.CommonIOUtil; - import io.quarkus.logging.Log; import io.quarkus.runtime.Quarkus; import io.quarkus.runtime.Startup; @@ -43,10 +44,10 @@ public void start() { final Socket socket = serverSocket.accept(); final UnixDomainSocketAddress address = UnixDomainSocketAddress.of(domainSocket); final SocketChannel channel = SocketChannel.open(address); - // write from socket to channel - CommonIOUtil.createSocketToChannelWriter(byteBufferSize, socket, channel).start(); - // write from channel to socket - CommonIOUtil.createChannelToSocketWriter(byteBufferSize, channel, socket).start(); + // Write from socket to channel + Thread.startVirtualThread(createSocketToChannelWriter(byteBufferSize, socket, channel)); + // Write from channel to socket + Thread.startVirtualThread(createChannelToSocketWriter(byteBufferSize, channel, socket)); } } catch (final IOException e) { Log.errorf(e, "Error initialising domain proxy client"); diff --git a/java-components/domain-proxy/common/src/main/java/com/redhat/hacbs/domainproxy/common/CommonIOUtil.java b/java-components/domain-proxy/common/src/main/java/com/redhat/hacbs/domainproxy/common/CommonIOUtil.java index 98e5392eb..2e03c7be0 100644 --- a/java-components/domain-proxy/common/src/main/java/com/redhat/hacbs/domainproxy/common/CommonIOUtil.java +++ b/java-components/domain-proxy/common/src/main/java/com/redhat/hacbs/domainproxy/common/CommonIOUtil.java @@ -13,10 +13,10 @@ public final class CommonIOUtil { private static final Logger LOG = Logger.getLogger(CommonIOUtil.class); - public static Thread createSocketToChannelWriter(final int byteBufferSize, final Socket socket, + public static Runnable createSocketToChannelWriter(final int byteBufferSize, final Socket socket, final SocketChannel channel) { - // write from socket to channel - return new Thread(() -> { + // Write from socket to channel + return () -> { int r; final byte[] buf = new byte[byteBufferSize]; int bytesWritten = 0; @@ -43,13 +43,13 @@ public static Thread createSocketToChannelWriter(final int byteBufferSize, final } } LOG.infof("Wrote %d bytes from socket to channel", bytesWritten); - }); + }; } - public static Thread createChannelToSocketWriter(final int byteBufferSize, final SocketChannel channel, + public static Runnable createChannelToSocketWriter(final int byteBufferSize, final SocketChannel channel, final Socket socket) { - // write from channel to socket - return new Thread(() -> { + // Write from channel to socket + return () -> { int r; final ByteBuffer buf = ByteBuffer.allocate(byteBufferSize); buf.clear(); @@ -79,6 +79,6 @@ public static Thread createChannelToSocketWriter(final int byteBufferSize, final } } LOG.infof("Wrote %d bytes from channel to socket", bytesWritten); - }); + }; } } diff --git a/java-components/domain-proxy/server/pom.xml b/java-components/domain-proxy/server/pom.xml index 691704776..955bd1ef9 100644 --- a/java-components/domain-proxy/server/pom.xml +++ b/java-components/domain-proxy/server/pom.xml @@ -28,6 +28,11 @@ rest-assured test + + org.wiremock + wiremock + test + io.github.redhat-appstudio.jvmbuild domain-proxy-common diff --git a/java-components/domain-proxy/server/src/main/java/com/redhat/hacbs/domainproxy/DomainProxyServer.java b/java-components/domain-proxy/server/src/main/java/com/redhat/hacbs/domainproxy/DomainProxyServer.java index 63fac1326..40ccbbad7 100644 --- a/java-components/domain-proxy/server/src/main/java/com/redhat/hacbs/domainproxy/DomainProxyServer.java +++ b/java-components/domain-proxy/server/src/main/java/com/redhat/hacbs/domainproxy/DomainProxyServer.java @@ -1,5 +1,8 @@ package com.redhat.hacbs.domainproxy; +import static com.redhat.hacbs.domainproxy.common.CommonIOUtil.createChannelToSocketWriter; +import static com.redhat.hacbs.domainproxy.common.CommonIOUtil.createSocketToChannelWriter; + import java.io.IOException; import java.net.Socket; import java.net.StandardProtocolFamily; @@ -15,8 +18,6 @@ import org.eclipse.microprofile.config.inject.ConfigProperty; -import com.redhat.hacbs.domainproxy.common.CommonIOUtil; - import io.quarkus.logging.Log; import io.quarkus.runtime.Quarkus; import io.quarkus.runtime.Startup; @@ -25,7 +26,7 @@ @Singleton public class DomainProxyServer { - static final String HOST = "localhost"; + static final String LOCALHOST = "localhost"; @Inject @ConfigProperty(name = "server-domain-socket") @@ -33,7 +34,7 @@ public class DomainProxyServer { @Inject @ConfigProperty(name = "server-http-port") - int serverHttpPort; + int httpServerPort; @Inject @ConfigProperty(name = "byte-buffer-size") @@ -41,7 +42,6 @@ public class DomainProxyServer { @PostConstruct public void start() { - Log.info("Starting domain proxy server..."); new Thread(() -> { Runtime.getRuntime().addShutdownHook(new Thread(() -> { try { @@ -55,11 +55,11 @@ public void start() { serverChannel.bind(address); while (true) { final SocketChannel channel = serverChannel.accept(); - final Socket socket = new Socket(HOST, serverHttpPort); - // write from socket to channel - CommonIOUtil.createSocketToChannelWriter(byteBufferSize, socket, channel).start(); - // write from channel to socket - CommonIOUtil.createChannelToSocketWriter(byteBufferSize, channel, socket).start(); + final Socket socket = new Socket(LOCALHOST, httpServerPort); + // Write from socket to channel + Thread.startVirtualThread(createSocketToChannelWriter(byteBufferSize, socket, channel)); + // Write from channel to socket + Thread.startVirtualThread(createChannelToSocketWriter(byteBufferSize, channel, socket)); } } catch (final IOException e) { Log.errorf(e, "Error initialising domain proxy server"); diff --git a/java-components/domain-proxy/server/src/main/java/com/redhat/hacbs/domainproxy/ExternalProxyVerticle.java b/java-components/domain-proxy/server/src/main/java/com/redhat/hacbs/domainproxy/ExternalProxyVerticle.java index 078215c6c..2e5cc43e9 100644 --- a/java-components/domain-proxy/server/src/main/java/com/redhat/hacbs/domainproxy/ExternalProxyVerticle.java +++ b/java-components/domain-proxy/server/src/main/java/com/redhat/hacbs/domainproxy/ExternalProxyVerticle.java @@ -29,7 +29,7 @@ public class ExternalProxyVerticle extends AbstractVerticle { @Inject @ConfigProperty(name = "server-http-port") - int serverHttpPort; + int httpServerPort; @Inject @ConfigProperty(name = "proxy-target-whitelist") @@ -37,25 +37,27 @@ public class ExternalProxyVerticle extends AbstractVerticle { private final WebClient webClient; private final NetClient netClient; + private final HttpServer httpServer; public ExternalProxyVerticle(final Vertx vertx) { webClient = WebClient.create(vertx, new WebClientOptions()); netClient = vertx.createNetClient(new NetClientOptions()); + httpServer = vertx.createHttpServer(); } @Override public void start() { - final HttpServer server = vertx.createHttpServer(); - server.requestHandler(request -> { + Log.info("Starting domain proxy server..."); + httpServer.requestHandler(request -> { if (request.method() == HttpMethod.GET) { handleGetRequest(request); } else if (request.method() == HttpMethod.CONNECT) { handleConnectRequest(request); } }); - server.listen(serverHttpPort, result -> { + httpServer.listen(httpServerPort, result -> { if (result.succeeded()) { - Log.infof("Server is now listening on port %d", serverHttpPort); + Log.infof("Server is now listening on port %d", httpServerPort); } else { Log.errorf(result.cause(), "Failed to bind server"); } diff --git a/java-components/domain-proxy/server/src/test/java/com/redhat/hacbs/domainproxy/ExternalProxyEndpointTest.disabled b/java-components/domain-proxy/server/src/test/java/com/redhat/hacbs/domainproxy/ExternalProxyEndpointTest.disabled deleted file mode 100644 index bd80096da..000000000 --- a/java-components/domain-proxy/server/src/test/java/com/redhat/hacbs/domainproxy/ExternalProxyEndpointTest.disabled +++ /dev/null @@ -1,50 +0,0 @@ -package com.redhat.hacbs.domainproxy; - -import static io.restassured.RestAssured.given; -import static org.junit.jupiter.api.Assertions.assertEquals; - -import org.apache.commons.codec.digest.DigestUtils; -import org.junit.jupiter.api.Test; - -import io.quarkus.test.common.http.TestHTTPEndpoint; -import io.quarkus.test.junit.QuarkusTest; - -@QuarkusTest -@TestHTTPEndpoint(ExternalProxyEndpoint.class) -class ExternalProxyEndpointTest { - - @Test - public void testDownloadDependency() { - byte[] jar = given() - .when() - .get("main/org/apache/maven/plugins/maven-jar-plugin/3.4.1/maven-jar-plugin-3.4.1.jar").asByteArray(); - assertEquals("27934a80a9fe932f50887f4c79cb539d", DigestUtils.md5Hex(jar)); - } - - @Test - public void testDownloadDependencyWithClassifier() { - byte[] jar = given() - .when() - .get("main/io/netty/netty-transport-native-epoll/4.1.111.Final/netty-transport-native-epoll-4.1.111.Final-linux-aarch_64.jar") - .asByteArray(); - assertEquals("ddacd8fbbc4e883e17c9b735cd9fc7b0", DigestUtils.md5Hex(jar)); - } - - @Test - public void testMissingDependency() { - given() - .when() - .get("main/org/apache/maven/plugins/maven-jar-plugin/3.4.1/maven-jar-plugin-3.4.1.jar1") - .then() - .statusCode(404); - } - - @Test - public void testInvalidRoot() { - given() - .when() - .get("foo/org/apache/maven/plugins/maven-jar-plugin/3.4.1/maven-jar-plugin-3.4.1.jar") - .then() - .statusCode(404); - } -} diff --git a/java-components/domain-proxy/server/src/test/java/com/redhat/hacbs/domainproxy/ExternalProxyVerticleTest.java b/java-components/domain-proxy/server/src/test/java/com/redhat/hacbs/domainproxy/ExternalProxyVerticleTest.java new file mode 100644 index 000000000..bef55d66c --- /dev/null +++ b/java-components/domain-proxy/server/src/test/java/com/redhat/hacbs/domainproxy/ExternalProxyVerticleTest.java @@ -0,0 +1,113 @@ +package com.redhat.hacbs.domainproxy; + +import static com.github.tomakehurst.wiremock.client.WireMock.aResponse; +import static com.github.tomakehurst.wiremock.client.WireMock.get; +import static com.github.tomakehurst.wiremock.client.WireMock.urlEqualTo; +import static com.github.tomakehurst.wiremock.core.WireMockConfiguration.wireMockConfig; +import static com.redhat.hacbs.domainproxy.DomainProxyServer.LOCALHOST; +import static io.restassured.RestAssured.given; +import static org.junit.jupiter.api.Assertions.assertEquals; + +import java.io.IOException; +import java.nio.charset.StandardCharsets; +import java.nio.file.Files; +import java.nio.file.Path; + +import jakarta.inject.Inject; + +import org.apache.commons.codec.digest.DigestUtils; +import org.eclipse.microprofile.config.inject.ConfigProperty; +import org.junit.jupiter.api.AfterAll; +import org.junit.jupiter.api.BeforeAll; +import org.junit.jupiter.api.Test; + +import com.github.tomakehurst.wiremock.WireMockServer; + +import io.netty.handler.codec.http.HttpResponseStatus; +import io.quarkus.test.junit.QuarkusTest; +import io.quarkus.test.junit.TestProfile; +import io.restassured.specification.RequestSpecification; + +@QuarkusTest +@TestProfile(ExternalProxyVerticleTestProfile.class) +class ExternalProxyVerticleTest { + + static final String MD5_HASH = "ea3ca57f8f99d1d210d1b438c9841440"; + + private static WireMockServer wireMockServer; + + @Inject + @ConfigProperty(name = "server-http-port") + int httpServerPort; + + @BeforeAll + public static void before() throws IOException { + wireMockServer = new WireMockServer(wireMockConfig().port(2002).httpsPort(2003)); + wireMockServer.start(); + wireMockServer.stubFor( + get(urlEqualTo("/com/foo/bar/1.0/bar-1.0.pom")) + .willReturn(aResponse() + .withHeader("Content-Type", "text/xml") + .withBody( + Files.readString(Path.of("src/test/resources/bar-1.0.pom"), StandardCharsets.UTF_8)))); + } + + @AfterAll + public static void after() { + if (wireMockServer != null) { + wireMockServer.stop(); + } + } + + private RequestSpecification httpRequest() { + return given().proxy(LOCALHOST, httpServerPort).port(wireMockServer.port()); + } + + private RequestSpecification httpsRequest() { + return given().proxy(LOCALHOST, httpServerPort).port(wireMockServer.httpsPort()).relaxedHTTPSValidation(); + } + + @Test + public void testDownloadDependencyHTTP() { + final byte[] jar = httpRequest().get("http://" + LOCALHOST + "/com/foo/bar/1.0/bar-1.0.pom") + .asByteArray(); + assertEquals(MD5_HASH, DigestUtils.md5Hex(jar)); + } + + @Test + public void testDownloadDependencyHTTPS() { + final byte[] jar = httpsRequest().get("https://" + LOCALHOST + "/com/foo/bar/1.0/bar-1.0.pom") + .asByteArray(); + assertEquals(MD5_HASH, DigestUtils.md5Hex(jar)); + } + + @Test + public void testMissingDependencyHTTP() { + httpRequest().get("http://" + LOCALHOST + "/com/foo/bar/2.0/bar-2.0.pom") + .then() + .statusCode(HttpResponseStatus.NOT_FOUND.code()); + } + + @Test + public void testMissingDependencyHTTPS() { + httpsRequest().get("https://" + LOCALHOST + "/com/foo/bar/2.0/bar-2.0.pom") + .then() + .statusCode(HttpResponseStatus.NOT_FOUND.code()); + } + + @Test + public void testNotWhitelistedHTTP() { + httpRequest().get( + "http://repo1.maven.org/maven2/org/apache/maven/plugins/maven-jar-plugin/3.4.1/maven-jar-plugin-3.4.1.jar") + .then() + .statusCode(HttpResponseStatus.NOT_FOUND.code()); + } + + @Test + public void testNotWhitelistedHTTPS() { + httpsRequest().get( + "https://repo1.maven.org/maven2/org/apache/maven/plugins/maven-jar-plugin/3.4.1/maven-jar-plugin-3.4.1.jar") + .then() + .statusCode(HttpResponseStatus.NOT_FOUND.code()); + } +} diff --git a/java-components/domain-proxy/server/src/test/java/com/redhat/hacbs/domainproxy/ExternalProxyVerticleTestProfile.java b/java-components/domain-proxy/server/src/test/java/com/redhat/hacbs/domainproxy/ExternalProxyVerticleTestProfile.java new file mode 100644 index 000000000..8a4ee86a0 --- /dev/null +++ b/java-components/domain-proxy/server/src/test/java/com/redhat/hacbs/domainproxy/ExternalProxyVerticleTestProfile.java @@ -0,0 +1,15 @@ +package com.redhat.hacbs.domainproxy; + +import static com.redhat.hacbs.domainproxy.DomainProxyServer.LOCALHOST; + +import java.util.Map; + +import io.quarkus.test.junit.QuarkusTestProfile; + +public class ExternalProxyVerticleTestProfile implements QuarkusTestProfile { + + @Override + public Map getConfigOverrides() { + return Map.of("server-http-port", "2001", "proxy-target-whitelist", LOCALHOST); + } +} diff --git a/java-components/domain-proxy/server/src/test/resources/bar-1.0.pom b/java-components/domain-proxy/server/src/test/resources/bar-1.0.pom new file mode 100644 index 000000000..45f65a9c9 --- /dev/null +++ b/java-components/domain-proxy/server/src/test/resources/bar-1.0.pom @@ -0,0 +1,9 @@ + + + 4.0.0 + com.foo + bar + 1.0 + diff --git a/java-components/pom.xml b/java-components/pom.xml index 463bfd803..2db1c4ae2 100644 --- a/java-components/pom.xml +++ b/java-components/pom.xml @@ -40,7 +40,7 @@ UTF-8 UTF-8 - 17 + 21 quarkus-bom io.quarkus.platform From d8dd3461fed907e38c7994853741095ff5323436 Mon Sep 17 00:00:00 2001 From: Tim Carter Date: Tue, 22 Oct 2024 16:17:46 +1100 Subject: [PATCH 3/5] Try upping build to JDK 21. --- .github/workflows/java-ci.yml | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/.github/workflows/java-ci.yml b/.github/workflows/java-ci.yml index 17c575dab..04ddbdbcb 100644 --- a/.github/workflows/java-ci.yml +++ b/.github/workflows/java-ci.yml @@ -17,11 +17,11 @@ jobs: key: ${{ runner.os }}-maven-${{ hashFiles('**/pom.xml') }} restore-keys: | ${{ runner.os }}-maven- - - name: Set up JDK 17 + - name: Set up JDK 21 uses: actions/setup-java@b36c23c0d998641eff861008f374ee103c25ac73 # v4 with: distribution: 'temurin' - java-version: 17 + java-version: 21 - name: Set up Maven uses: stCarolas/setup-maven@d6af6abeda15e98926a57b5aa970a96bb37f97d1 # v5 with: From f2c6db1803bf08f46915e93c39c60281662c060a Mon Sep 17 00:00:00 2001 From: Tim Carter Date: Wed, 23 Oct 2024 11:21:52 +1100 Subject: [PATCH 4/5] Correct test case condition after JDK 21 upgrade. --- .../hacbs/container/verifier/JarVerificationTestCase.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/java-components/build-request-processor/src/test/java/com/redhat/hacbs/container/verifier/JarVerificationTestCase.java b/java-components/build-request-processor/src/test/java/com/redhat/hacbs/container/verifier/JarVerificationTestCase.java index 2a81365b9..cbb593594 100644 --- a/java-components/build-request-processor/src/test/java/com/redhat/hacbs/container/verifier/JarVerificationTestCase.java +++ b/java-components/build-request-processor/src/test/java/com/redhat/hacbs/container/verifier/JarVerificationTestCase.java @@ -66,7 +66,7 @@ public void visit(int version, int access, String name, String signature, String super.visit(version - 1, access, name, signature, superName, interfaces); } - }, List.of(new ExpectedChange(ChangeType.MODIFY, "version:61.0>60.0"))); + }, List.of(new ExpectedChange(ChangeType.MODIFY, "version:65.0>64.0"))); } @Test From 9d4b620d31aaf1ab9714a0e1c12fe642c692557e Mon Sep 17 00:00:00 2001 From: Tim Carter Date: Wed, 23 Oct 2024 12:31:43 +1100 Subject: [PATCH 5/5] Upversion JDK builder and runtime images after JDK 21 upgrade. --- .../src/main/docker/Dockerfile.all-in-one | 4 ++-- java-components/cache/src/main/docker/Dockerfile.all-in-one | 4 ++-- java-components/cli/src/main/docker/Dockerfile.all-in-one | 4 ++-- .../management-console/src/main/docker/Dockerfile.all-in-one | 4 ++-- 4 files changed, 8 insertions(+), 8 deletions(-) diff --git a/java-components/build-request-processor/src/main/docker/Dockerfile.all-in-one b/java-components/build-request-processor/src/main/docker/Dockerfile.all-in-one index 94dc36893..5c16ee29e 100644 --- a/java-components/build-request-processor/src/main/docker/Dockerfile.all-in-one +++ b/java-components/build-request-processor/src/main/docker/Dockerfile.all-in-one @@ -1,11 +1,11 @@ -FROM registry.access.redhat.com/ubi8/openjdk-17@sha256:1e7c98337b27ca336c9f0c3734460c8fa621b35e99d5a45cf815bc8db9f1db98 AS builder +FROM registry.access.redhat.com/ubi8/openjdk-21@sha256:a10b277c0f16283bb45b0e6cfca3ae9ecf155178f7f731df4a1f744ebd35af70 AS builder USER 0 WORKDIR /work COPY ./ . RUN mvn -V -B package -pl build-request-processor -am -Dmaven.test.skip -FROM registry.access.redhat.com/ubi8/openjdk-17-runtime@sha256:e2f33a6c60db4f4e70882a4a557eec5890997f8a1be7e3eb8971a0ff8a45a1a8 +FROM registry.access.redhat.com/ubi8/openjdk-21-runtime@sha256:c1bf8370627eaed6711ea22915b476d4216517c35c8f8268c0d39ed983bceaff USER 0 WORKDIR /work/ diff --git a/java-components/cache/src/main/docker/Dockerfile.all-in-one b/java-components/cache/src/main/docker/Dockerfile.all-in-one index 740911b4a..b8ee4fdd2 100644 --- a/java-components/cache/src/main/docker/Dockerfile.all-in-one +++ b/java-components/cache/src/main/docker/Dockerfile.all-in-one @@ -1,4 +1,4 @@ -FROM registry.access.redhat.com/ubi8/openjdk-17@sha256:1e7c98337b27ca336c9f0c3734460c8fa621b35e99d5a45cf815bc8db9f1db98 AS builder +FROM registry.access.redhat.com/ubi8/openjdk-21@sha256:a10b277c0f16283bb45b0e6cfca3ae9ecf155178f7f731df4a1f744ebd35af70 AS builder USER 0 WORKDIR /work COPY ./ . @@ -7,7 +7,7 @@ RUN mkdir -p /work/cache/target/classes RUN mvn -V -B package -pl cache -am -Dmaven.test.skip -FROM registry.access.redhat.com/ubi8/openjdk-17-runtime@sha256:e2f33a6c60db4f4e70882a4a557eec5890997f8a1be7e3eb8971a0ff8a45a1a8 +FROM registry.access.redhat.com/ubi8/openjdk-21-runtime@sha256:c1bf8370627eaed6711ea22915b476d4216517c35c8f8268c0d39ed983bceaff USER 0 WORKDIR /work/ diff --git a/java-components/cli/src/main/docker/Dockerfile.all-in-one b/java-components/cli/src/main/docker/Dockerfile.all-in-one index c7f32ecf4..8db6767fe 100644 --- a/java-components/cli/src/main/docker/Dockerfile.all-in-one +++ b/java-components/cli/src/main/docker/Dockerfile.all-in-one @@ -1,11 +1,11 @@ -FROM registry.access.redhat.com/ubi8/openjdk-17@sha256:1e7c98337b27ca336c9f0c3734460c8fa621b35e99d5a45cf815bc8db9f1db98 AS builder +FROM registry.access.redhat.com/ubi8/openjdk-21@sha256:a10b277c0f16283bb45b0e6cfca3ae9ecf155178f7f731df4a1f744ebd35af70 AS builder WORKDIR /work COPY ./ . RUN mvn -V -B package -pl cli -am -DskipTests -FROM registry.access.redhat.com/ubi8/openjdk-17-runtime@sha256:e2f33a6c60db4f4e70882a4a557eec5890997f8a1be7e3eb8971a0ff8a45a1a8 +FROM registry.access.redhat.com/ubi8/openjdk-21-runtime@sha256:c1bf8370627eaed6711ea22915b476d4216517c35c8f8268c0d39ed983bceaff WORKDIR /work/ COPY --from=builder /work/cli/target/quarkus-app/lib/ /deployments/lib/ diff --git a/java-components/management-console/src/main/docker/Dockerfile.all-in-one b/java-components/management-console/src/main/docker/Dockerfile.all-in-one index 740911b4a..b8ee4fdd2 100644 --- a/java-components/management-console/src/main/docker/Dockerfile.all-in-one +++ b/java-components/management-console/src/main/docker/Dockerfile.all-in-one @@ -1,4 +1,4 @@ -FROM registry.access.redhat.com/ubi8/openjdk-17@sha256:1e7c98337b27ca336c9f0c3734460c8fa621b35e99d5a45cf815bc8db9f1db98 AS builder +FROM registry.access.redhat.com/ubi8/openjdk-21@sha256:a10b277c0f16283bb45b0e6cfca3ae9ecf155178f7f731df4a1f744ebd35af70 AS builder USER 0 WORKDIR /work COPY ./ . @@ -7,7 +7,7 @@ RUN mkdir -p /work/cache/target/classes RUN mvn -V -B package -pl cache -am -Dmaven.test.skip -FROM registry.access.redhat.com/ubi8/openjdk-17-runtime@sha256:e2f33a6c60db4f4e70882a4a557eec5890997f8a1be7e3eb8971a0ff8a45a1a8 +FROM registry.access.redhat.com/ubi8/openjdk-21-runtime@sha256:c1bf8370627eaed6711ea22915b476d4216517c35c8f8268c0d39ed983bceaff USER 0 WORKDIR /work/