Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Fix #682: Allow to define if dev-server is HTTPS / TLS #684

Merged
merged 3 commits into from
Jun 13, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -79,6 +79,8 @@ public ForwardedDevServerBuildItem prepareDevService(
final DevServerConfig devServerConfig = resolvedConfig.devServer();
liveReload.setContextObject(QuinoaConfig.class, resolvedConfig);
final String configuredDevServerHost = devServerConfig.host();
final boolean configuredTls = devServerConfig.tls();
final boolean configuredTlsAllowInsecure = devServerConfig.tlsAllowInsecure();
final PackageManagerRunner packageManagerRunner = installedPackageManager.getPackageManager();
final String checkPath = resolvedConfig.devServer().checkPath().orElse(null);
if (devService != null) {
Expand All @@ -92,7 +94,9 @@ public ForwardedDevServerBuildItem prepareDevService(
}
LOG.debug("Quinoa config did not change; no need to restart.");
devServices.produce(devService.toBuildItem());
final String resolvedDevServerHost = PackageManagerRunner.isDevServerUp(devServerConfig.host(),
final String resolvedDevServerHost = PackageManagerRunner.isDevServerUp(devServerConfig.tls(),
devServerConfig.tlsAllowInsecure(),
devServerConfig.host(),
devServerConfig.port().get(),
checkPath);
return new ForwardedDevServerBuildItem(resolvedDevServerHost, devServerConfig.port().get());
Expand All @@ -118,7 +122,8 @@ public ForwardedDevServerBuildItem prepareDevService(
if (!devServerConfig.managed()) {
// No need to start the dev-service it is not managed by Quinoa
// We just check that it is up
final String resolvedHostIPAddress = PackageManagerRunner.isDevServerUp(configuredDevServerHost, port, checkPath);
final String resolvedHostIPAddress = PackageManagerRunner.isDevServerUp(configuredTls, configuredTlsAllowInsecure,
configuredDevServerHost, port, checkPath);
if (resolvedHostIPAddress != null) {
return new ForwardedDevServerBuildItem(resolvedHostIPAddress, port);
} else {
Expand All @@ -135,7 +140,8 @@ public ForwardedDevServerBuildItem prepareDevService(
final AtomicReference<Process> dev = new AtomicReference<>();
PackageManagerRunner.DevServer devServer = null;
try {
devServer = packageManagerRunner.dev(consoleInstalled, loggingSetup, configuredDevServerHost,
devServer = packageManagerRunner.dev(consoleInstalled, loggingSetup, configuredTls, configuredTlsAllowInsecure,
configuredDevServerHost,
port,
checkPath,
checkTimeout);
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,55 @@
package io.quarkiverse.quinoa.deployment;

import javax.net.ssl.*;
import java.io.IOException;
import java.net.InetAddress;
import java.net.Socket;
import java.net.UnknownHostException;
import java.security.KeyManagementException;
import java.security.NoSuchAlgorithmException;
import java.security.SecureRandom;
import java.security.cert.CertificateException;
import java.security.cert.X509Certificate;

public class SslUtil {
private final static X509ExtendedTrustManager NON_VALIDATING_TRUST_MANAGER = new X509ExtendedTrustManager() {
@Override
public void checkClientTrusted(X509Certificate[] chain, String authType, Socket socket) throws CertificateException {
}

@Override
public void checkServerTrusted(X509Certificate[] chain, String authType, Socket socket) throws CertificateException {
}

@Override
public void checkClientTrusted(X509Certificate[] chain, String authType, SSLEngine engine) throws CertificateException {
}

@Override
public void checkServerTrusted(X509Certificate[] chain, String authType, SSLEngine engine) throws CertificateException {
}

@Override
public void checkClientTrusted(X509Certificate[] chain, String authType) throws CertificateException {
}

@Override
public void checkServerTrusted(X509Certificate[] chain, String authType) throws CertificateException {
}

@Override
public X509Certificate[] getAcceptedIssuers() {
return new X509Certificate[0];
}
};

public static SSLContext createNonValidatingSslContext() {
try {
SSLContext sslContext = SSLContext.getInstance("TLS");
sslContext.init(null, new TrustManager[] { NON_VALIDATING_TRUST_MANAGER }, new SecureRandom());
return sslContext;
} catch (NoSuchAlgorithmException | KeyManagementException e) {
throw new RuntimeException(e);
}
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -40,6 +40,18 @@ public interface DevServerConfig {
@WithDefault("localhost")
String host();

/**
* Protocol of the server to forward requests to.
*/
@WithDefault("false")
boolean tls();

/**
* Protocol of the server to forward requests to.
*/
@WithDefault("false")
boolean tlsAllowInsecure();

/**
* After start, Quinoa wait for the external dev server.
* by sending GET requests to this path waiting for a 200 status.
Expand Down Expand Up @@ -100,6 +112,12 @@ static boolean isEqual(DevServerConfig d1, DevServerConfig d2) {
if (!Objects.equals(d1.host(), d2.host())) {
return false;
}
if (!Objects.equals(d1.tls(), d2.tls())) {
return false;
}
if (!Objects.equals(d1.tlsAllowInsecure(), d2.tlsAllowInsecure())) {
return false;
}
if (!Objects.equals(d1.checkPath(), d2.checkPath())) {
return false;
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -31,6 +31,16 @@ public String host() {
return delegate.host();
}

@Override
public boolean tls() {
return delegate.tls();
}

@Override
public boolean tlsAllowInsecure() {
return delegate.tlsAllowInsecure();
}

@Override
public Optional<String> checkPath() {
return delegate.checkPath();
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,7 @@
import java.util.concurrent.TimeUnit;
import java.util.function.Predicate;

import io.quarkiverse.quinoa.deployment.SslUtil;
import org.jboss.logging.Logger;

import io.quarkiverse.quinoa.deployment.config.PackageManagerCommandConfig;
Expand All @@ -33,6 +34,10 @@
import io.quarkus.dev.console.QuarkusConsole;
import io.quarkus.runtime.LaunchMode;

import javax.net.ssl.HostnameVerifier;
import javax.net.ssl.HttpsURLConnection;
import javax.net.ssl.SSLSession;

public class PackageManagerRunner {
private static final Logger LOG = Logger.getLogger(PackageManagerRunner.class);
public static final Predicate<Thread> DEV_PROCESS_THREAD_PREDICATE = thread -> thread.getName()
Expand Down Expand Up @@ -134,7 +139,8 @@ private static void killDescendants(ProcessHandle process, boolean force) {
}

public DevServer dev(Optional<ConsoleInstalledBuildItem> consoleInstalled, LoggingSetupBuildItem loggingSetup,
String devServerHost, int devServerPort, String checkPath, int checkTimeout) {
boolean tls, boolean tlsAllowInsecure, String devServerHost, int devServerPort, String checkPath,
int checkTimeout) {
final PackageManager.Command dev = packageManager.dev();
LOG.infof("Running Quinoa package manager live coding as a dev service: %s", dev.commandWithArguments);
StartupLogCompressor logCompressor = new StartupLogCompressor(
Expand All @@ -155,7 +161,7 @@ public void run() {
String ipAddress = null;
try {
int i = 0;
while ((ipAddress = isDevServerUp(devServerHost, devServerPort, checkPath)) == null) {
while ((ipAddress = isDevServerUp(tls, tlsAllowInsecure, devServerHost, devServerPort, checkPath)) == null) {
if (++i >= checkTimeout / 500) {
stopDev(p);
throw new RuntimeException(
Expand Down Expand Up @@ -269,7 +275,7 @@ public void run() {
}
}

public static String isDevServerUp(String host, int port, String path) {
public static String isDevServerUp(boolean tls, boolean tlsAllowInsecure, String host, int port, String path) {
if (path == null) {
return host;
}
Expand All @@ -280,8 +286,24 @@ public static String isDevServerUp(String host, int port, String path) {
try {
final String hostAddress = address.getHostAddress();
final String ipAddress = address instanceof Inet6Address ? "[" + hostAddress + "]" : hostAddress;
URL url = new URL(String.format("http://%s:%d%s", ipAddress, port, normalizedPath));
HttpURLConnection connection = (HttpURLConnection) url.openConnection();
URL url = new URL(String.format("%s://%s:%d%s", tls ? "https" : "http", ipAddress, port, normalizedPath));
HttpURLConnection connection;
if (tls) {
HttpsURLConnection httpsConnection = (HttpsURLConnection) url.openConnection();
if (tlsAllowInsecure) {
httpsConnection.setSSLSocketFactory(SslUtil.createNonValidatingSslContext().getSocketFactory());
httpsConnection.setHostnameVerifier(new HostnameVerifier() {
@Override
public boolean verify(String hostname, SSLSession session) {
return true;
}
});
}
connection = httpsConnection;
} else {
connection = (HttpURLConnection) url.openConnection();
}

connection.setRequestMethod("GET");
connection.setConnectTimeout(2000);
connection.setReadTimeout(2000);
Expand Down