From 00d17e684f9ad7b993c09d4cd962d9809e8319fc Mon Sep 17 00:00:00 2001 From: Simon Rettberg Date: Thu, 6 Apr 2023 16:26:07 +0200 Subject: [client] Completely change proxy detection code Try to turn the old mess into a slightly less confusing new mess --- .../src/main/java/org/openslx/dozmod/App.java | 6 +- .../openslx/dozmod/gui/GraphicalCertHandler.java | 5 +- .../org/openslx/dozmod/util/ProxyConfigurator.java | 231 +++++++++++---------- 3 files changed, 124 insertions(+), 118 deletions(-) diff --git a/dozentenmodul/src/main/java/org/openslx/dozmod/App.java b/dozentenmodul/src/main/java/org/openslx/dozmod/App.java index 9ef3f7b9..e6e272da 100755 --- a/dozentenmodul/src/main/java/org/openslx/dozmod/App.java +++ b/dozentenmodul/src/main/java/org/openslx/dozmod/App.java @@ -15,7 +15,6 @@ import java.util.Set; import java.util.concurrent.CountDownLatch; import java.util.zip.Deflater; -import javax.net.ssl.SSLContext; import javax.swing.SwingUtilities; import javax.swing.UIDefaults; import javax.swing.UIManager; @@ -237,10 +236,9 @@ public class App { } // SSL if (useSsl) { + waitForInit(); try { - SSLContext ctx = SSLContext.getInstance("TLSv1.2"); - ctx.init(null, null, null); - ThriftManager.setMasterServerAddress(ctx, host, port, THRIFT_TIMEOUT_MS); + ThriftManager.setMasterServerAddress(ProxyConfigurator.getThriftSslContext(), host, port, THRIFT_TIMEOUT_MS); } catch (final Exception e1) { SwingUtilities.invokeAndWait(new Runnable() { @Override diff --git a/dozentenmodul/src/main/java/org/openslx/dozmod/gui/GraphicalCertHandler.java b/dozentenmodul/src/main/java/org/openslx/dozmod/gui/GraphicalCertHandler.java index 648a0403..34997133 100644 --- a/dozentenmodul/src/main/java/org/openslx/dozmod/gui/GraphicalCertHandler.java +++ b/dozentenmodul/src/main/java/org/openslx/dozmod/gui/GraphicalCertHandler.java @@ -18,6 +18,7 @@ import org.openslx.dozmod.authentication.FingerprintManager; import org.openslx.dozmod.gui.Gui.GuiCallable; import org.openslx.dozmod.gui.helper.I18n; import org.openslx.dozmod.gui.helper.MessageType; +import org.openslx.dozmod.util.ProxyConfigurator; public class GraphicalCertHandler { @@ -114,7 +115,9 @@ public class GraphicalCertHandler { private GraphicalCertHandler(String address) { SSLContext ctx = null; try { - ctx = SSLContext.getInstance("TLSv1.2"); + ctx = ProxyConfigurator.getThriftSslContext(); + // Make copy + ctx = SSLContext.getInstance(ctx.getProtocol(), ctx.getProvider()); } catch (NoSuchAlgorithmException e) { Gui.asyncMessageBox(I18n.GUI.getString("GraphicalCertHandler.Message.error.couldNotGetSSLContext"), MessageType.ERROR, LOGGER, e); diff --git a/dozentenmodul/src/main/java/org/openslx/dozmod/util/ProxyConfigurator.java b/dozentenmodul/src/main/java/org/openslx/dozmod/util/ProxyConfigurator.java index 035d310b..711915aa 100644 --- a/dozentenmodul/src/main/java/org/openslx/dozmod/util/ProxyConfigurator.java +++ b/dozentenmodul/src/main/java/org/openslx/dozmod/util/ProxyConfigurator.java @@ -1,33 +1,26 @@ package org.openslx.dozmod.util; -import java.io.IOException; -import java.net.Proxy; import java.net.ProxySelector; -import java.net.Socket; +import java.security.KeyManagementException; +import java.security.NoSuchAlgorithmException; import java.text.MessageFormat; +import java.util.ArrayList; +import java.util.Arrays; +import java.util.Collections; +import java.util.List; import java.util.concurrent.atomic.AtomicReference; import javax.net.ssl.SSLContext; -import org.apache.hc.client5.http.HttpRoute; import org.apache.hc.client5.http.classic.methods.HttpGet; import org.apache.hc.client5.http.config.ConnectionConfig; import org.apache.hc.client5.http.config.RequestConfig; import org.apache.hc.client5.http.config.TlsConfig; import org.apache.hc.client5.http.impl.classic.CloseableHttpClient; import org.apache.hc.client5.http.impl.classic.HttpClientBuilder; -import org.apache.hc.client5.http.impl.io.PoolingHttpClientConnectionManager; import org.apache.hc.client5.http.impl.io.PoolingHttpClientConnectionManagerBuilder; -import org.apache.hc.client5.http.impl.routing.SystemDefaultRoutePlanner; -import org.apache.hc.client5.http.socket.ConnectionSocketFactory; -import org.apache.hc.client5.http.socket.PlainConnectionSocketFactory; import org.apache.hc.client5.http.ssl.SSLConnectionSocketFactoryBuilder; -import org.apache.hc.core5.http.HttpException; -import org.apache.hc.core5.http.HttpHost; import org.apache.hc.core5.http.HttpResponse; -import org.apache.hc.core5.http.URIScheme; -import org.apache.hc.core5.http.config.RegistryBuilder; -import org.apache.hc.core5.http.protocol.HttpContext; import org.apache.hc.core5.http.ssl.TLS; import org.apache.hc.core5.util.Timeout; import org.apache.logging.log4j.Level; @@ -56,16 +49,20 @@ public class ProxyConfigurator { * Logger for this class */ private final static Logger LOGGER = LogManager.getLogger(ProxyConfigurator.class); - - private static AtomicReference apacheClient = new AtomicReference<>(); - - private static final TLS[] SUPPORTED_TLS_VERSIONS; + + private static final AtomicReference apacheClient = new AtomicReference<>(); + + private static final List TLS_CHECKLIST; private static final Timeout TIMEOUT_CONNECT = Timeout.ofSeconds(8); private static final Timeout TIMEOUT_SOCKET = Timeout.ofSeconds(8); private static final Timeout TIMEOUT_REQUEST = Timeout.ofSeconds(3); - + + private static SSLContext thriftCtx; + static { + List res = new ArrayList<>(); + res.add(null); boolean ok = false; try { SSLContext.getInstance("TLSv1.3"); @@ -73,43 +70,86 @@ public class ProxyConfigurator { } catch (Exception e) { } if (ok) { - SUPPORTED_TLS_VERSIONS = new TLS[] { TLS.V_1_3, TLS.V_1_2, TLS.V_1_1 }; - } else { - SUPPORTED_TLS_VERSIONS = new TLS[] { TLS.V_1_2, TLS.V_1_1 }; + res.add(new TLS[] { TLS.V_1_3, TLS.V_1_2 }); + } + res.add(new TLS[] { TLS.V_1_2 }); + res.add(new TLS[] { TLS.V_1_2, TLS.V_1_1 }); + TLS_CHECKLIST = Collections.unmodifiableList(res); + try { + if (ok) { + thriftCtx = SSLContext.getInstance("TLSv1.3"); + } else { + thriftCtx = SSLContext.getInstance("TLSv1.2"); + } + thriftCtx.init(null, null, null); + } catch (NoSuchAlgorithmException | KeyManagementException e) { + LOGGER.warn("Error creating default SSL context for thrift", e); } } - /** - * Initialization method. - */ - public static void init() { - MasterServer.Client masterClient = ThriftManager.getNewMasterClient(null, App.getMasterServerAddress(), - App.THRIFT_PORT, 4000); - if (masterClient != null) { + private static void tryAllThriftVariants() { + thriftCtx = null; + for (TLS[] tls : TLS_CHECKLIST) { + if (tls == null) + continue; + SSLContext ctx; + MasterServer.Client masterClient; try { - masterClient.ping(); - try { - masterClient.getInputProtocol().getTransport().close(); - masterClient.getOutputProtocol().getTransport().close(); - } catch (Throwable e) { + ctx = SSLContext.getInstance(tls[0].id); + ctx.init(null, null, null); + masterClient = ThriftManager.getNewMasterClient(ctx, + App.getMasterServerAddress(), + App.THRIFT_SSL_PORT, 4000); + if (masterClient != null) { + masterClient.ping(); + try { + masterClient.getInputProtocol().getTransport().close(); + masterClient.getOutputProtocol().getTransport().close(); + } catch (Throwable e) { + } + thriftCtx = ctx; + break; } } catch (Exception e) { - masterClient = null; } } - // To be discussed: Let's bail out if the master server is reachable - if (masterClient != null && testHttpsMaster()) { - LOGGER.info("Not setting up proxy because master server seems reachable."); - return; + } + + private static void tryAllHttpsVariants() { + apacheClient.set(null); + for (TLS[] tls : TLS_CHECKLIST) { + HttpClientBuilder builder; + try { + if (tls == null) { + builder = createDefaultBuilder(); + } else { + builder = createSlxBuilder(tls); + } + CloseableHttpClient client = builder.build(); + if (testHttpsMaster(client)) { + apacheClient.set(client); + break; + } + } catch (Exception e) { + } + } + } + + /** + * Initialization method. + */ + public static void init() { + tryAllThriftVariants(); + // Only try HTTPS if thrift succeeded + if (thriftCtx != null) { + tryAllHttpsVariants(); } - - // Build special HTTP Client Builder for apache and try again - apacheClient.set(createSlxBuilder().build()); - if (masterClient != null && testHttpsMaster()) { - LOGGER.info("Not setting up proxy since master server is reachable with custom client builder"); + // To be discussed: Let's bail out if the master server is reachable via thrift and https + if (apacheClient.get() != null) { + LOGGER.info("Not setting up proxy because master server seems reachable."); return; } - + // first setup the logger of proxy-vole com.btr.proxy.util.Logger.setBackend(new LogBackEnd() { @@ -148,15 +188,22 @@ public class ProxyConfigurator { myProxySelector = ss.getProxySelector(); } // final check to see if WPAD actually worked - if (myProxySelector != null) { - ProxySelector.setDefault(myProxySelector); - LOGGER.debug("Proxy initialised."); - Util.sleep(10); - } else { + if (myProxySelector == null) { LOGGER.error("Could not find a suitable proxy!"); + return; + } + // Seems to have worked + ProxySelector.setDefault(myProxySelector); + tryAllThriftVariants(); + tryAllHttpsVariants(); + if (thriftCtx == null || apacheClient.get() == null) { + LOGGER.warn("Could not establish Thrift/HTTPS connection after auto-configuring Proxy config"); + return; } + LOGGER.info("Proxy initialised."); + Util.sleep(10); } - + /** * Get the HttpClient to be used with apache * httpclient. @@ -167,19 +214,30 @@ public class ProxyConfigurator { CloseableHttpClient inst = apacheClient.get(); if (inst != null) return inst; - inst = createShortTimeoutBuilder().build(); + inst = createDefaultBuilder().build(); apacheClient.compareAndSet(null, inst); return inst; } - private static HttpClientBuilder createShortTimeoutBuilder() { + private static HttpClientBuilder createDefaultBuilder() { + return HttpClientBuilder.create() + .setConnectionManager(PoolingHttpClientConnectionManagerBuilder.create() + .setDefaultConnectionConfig(ConnectionConfig.custom() + .setConnectTimeout(ProxyConfigurator.TIMEOUT_CONNECT) + .setSocketTimeout(ProxyConfigurator.TIMEOUT_SOCKET) + .build()) + .setMaxConnPerRoute(4) + .build()); + } + + private static HttpClientBuilder createSlxBuilder(TLS[] tlsVersions) { return HttpClientBuilder.create() .setConnectionManager(PoolingHttpClientConnectionManagerBuilder.create() .setSSLSocketFactory(SSLConnectionSocketFactoryBuilder.create() - .setTlsVersions(ProxyConfigurator.SUPPORTED_TLS_VERSIONS) + .setTlsVersions(tlsVersions) .build()) .setDefaultTlsConfig(TlsConfig.custom() - .setSupportedProtocols(ProxyConfigurator.SUPPORTED_TLS_VERSIONS) + .setSupportedProtocols(tlsVersions) .build()) .setDefaultConnectionConfig(ConnectionConfig.custom() .setConnectTimeout(ProxyConfigurator.TIMEOUT_CONNECT) @@ -189,30 +247,7 @@ public class ProxyConfigurator { .build()); } - private static HttpClientBuilder createSlxBuilder() { - - final RegistryBuilder registryBuilder = RegistryBuilder.create() - .register(URIScheme.HTTP.id, SlxSocketFactory.getSocketFactory()) - .register(URIScheme.HTTPS.id, SSLConnectionSocketFactoryBuilder.create() - .setTlsVersions(ProxyConfigurator.SUPPORTED_TLS_VERSIONS) - .build()); - - final PoolingHttpClientConnectionManager connectionManager = new PoolingHttpClientConnectionManager(registryBuilder.build()); - connectionManager.setDefaultTlsConfig(TlsConfig.custom() - .setSupportedProtocols(ProxyConfigurator.SUPPORTED_TLS_VERSIONS) - .build()); - connectionManager.setDefaultConnectionConfig(ConnectionConfig.custom() - .setConnectTimeout(ProxyConfigurator.TIMEOUT_CONNECT) - .setSocketTimeout(ProxyConfigurator.TIMEOUT_SOCKET) - .build()); - connectionManager.setDefaultMaxPerRoute(4); - - return HttpClientBuilder.create() - .setRoutePlanner(new SlxRoutePlanner(null)) - .setConnectionManager(connectionManager); - } - - private static boolean testHttpsMaster() { + private static boolean testHttpsMaster(CloseableHttpClient client) { final RequestConfig requestConfig = RequestConfig.custom() .setConnectionRequestTimeout(ProxyConfigurator.TIMEOUT_REQUEST) .build(); @@ -222,48 +257,18 @@ public class ProxyConfigurator { httpGet.setHeader("PAOS", "ver=\"urn:liberty:paos:2003-08\";\"urn:oasis:names:tc:SAML:2.0:profiles:SSO:ecp\""); try { - HttpResponse response = getClient().execute(httpGet); + HttpResponse response = client.execute(httpGet); LOGGER.debug("Master server replies with " + response.getCode()); - return response.getCode() == 200; + int rc = response.getCode(); + return rc >= 200 && rc < 300; } catch (Exception e) { LOGGER.debug("Cannot reach master server via HTTPS", e); return false; } } - private static class SlxSocketFactory extends PlainConnectionSocketFactory { - - public static final SlxSocketFactory INSTANCE = new SlxSocketFactory(); - - public static SlxSocketFactory getSocketFactory() { - return INSTANCE; - } - - @Override - public Socket createSocket(HttpContext context) throws IOException { - Object obj = context.getAttribute("openslx.l7proxy"); - if (obj instanceof HttpRoute) { - HttpRoute route = (HttpRoute) obj; - if (route != null && route.getProxyHost() != null) { - return new Socket(Proxy.NO_PROXY); - } - } - return new Socket(); - } + public static SSLContext getThriftSslContext() { + return thriftCtx; } - private static class SlxRoutePlanner extends SystemDefaultRoutePlanner { - public SlxRoutePlanner(ProxySelector proxySelector) { - super(proxySelector); - } - - @Override - public HttpHost determineProxy(final HttpHost target, final HttpContext context) - throws HttpException { - HttpHost host = super.determineProxy(target, context); - context.setAttribute("openslx.l7proxy", host); - return host; - } - } - } -- cgit v1.2.3-55-g7522