package org.openslx.dozmod.util; import java.io.IOException; import java.net.Proxy; import java.net.ProxySelector; import java.net.Socket; import java.text.MessageFormat; import java.util.concurrent.atomic.AtomicReference; import org.apache.http.HttpException; import org.apache.http.HttpHost; import org.apache.http.HttpRequest; import org.apache.http.HttpResponse; import org.apache.http.client.config.RequestConfig; import org.apache.http.client.methods.HttpGet; import org.apache.http.config.Registry; import org.apache.http.config.RegistryBuilder; import org.apache.http.config.SocketConfig; import org.apache.http.conn.routing.HttpRoute; import org.apache.http.conn.socket.ConnectionSocketFactory; import org.apache.http.conn.socket.PlainConnectionSocketFactory; import org.apache.http.conn.ssl.SSLConnectionSocketFactory; import org.apache.http.impl.client.CloseableHttpClient; import org.apache.http.impl.client.HttpClientBuilder; import org.apache.http.impl.conn.PoolingHttpClientConnectionManager; import org.apache.http.impl.conn.SystemDefaultRoutePlanner; import org.apache.http.protocol.HttpContext; import org.apache.http.ssl.SSLContexts; import org.apache.logging.log4j.Level; import org.apache.logging.log4j.LogManager; import org.apache.logging.log4j.Logger; import org.openslx.bwlp.thrift.iface.MasterServer; import org.openslx.dozmod.App; import org.openslx.dozmod.authentication.ShibbolethEcp; import org.openslx.thrifthelper.ThriftManager; import org.openslx.util.Util; import com.btr.proxy.search.ProxySearch; import com.btr.proxy.search.wpad.WpadProxySearchStrategy; import com.btr.proxy.util.Logger.LogBackEnd; import com.btr.proxy.util.Logger.LogLevel; /** * Configures the proxy * * @author Jonathan Bauer */ public class ProxyConfigurator { /** * Logger for this class */ private final static Logger LOGGER = LogManager.getLogger(ProxyConfigurator.class); private static AtomicReference apacheClient = new AtomicReference<>(); /** * Initialization method. */ public static void init() { MasterServer.Client masterClient = ThriftManager.getNewMasterClient(null, App.getMasterServerAddress(), App.THRIFT_PORT, 4000); if (masterClient != null) { try { masterClient.ping(); try { masterClient.getInputProtocol().getTransport().close(); masterClient.getOutputProtocol().getTransport().close(); } catch (Throwable e) { } } 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; } // 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"); return; } // first setup the logger of proxy-vole com.btr.proxy.util.Logger.setBackend(new LogBackEnd() { public void log(Class clazz, LogLevel loglevel, String msg, Object... params) { Level priority; switch (loglevel) { case ERROR: priority = Level.ERROR; break; case WARNING: priority = Level.WARN; break; case INFO: priority = Level.INFO; break; default: priority = Level.DEBUG; } LogManager.getLogger(clazz).log(priority, MessageFormat.format(msg, params)); } public boolean isLogginEnabled(LogLevel logLevel) { return true; } }); LOGGER.info("Master server not directly reachable; trying to determine proxy"); // try to find local proxy settings ProxySearch proxySearch = ProxySearch.getDefaultProxySearch(); ProxySelector myProxySelector = proxySearch.getProxySelector(); if (myProxySelector == null) { // didn't work, try WPAD detection LOGGER.error("No suitable proxy settings found, trying WPAD..."); WpadProxySearchStrategy ss = new WpadProxySearchStrategy(); 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 { LOGGER.error("Could not find a suitable proxy!"); } } /** * Get the HttpClient to be used with apache * httpclient. * * @return client */ public static CloseableHttpClient getClient() { CloseableHttpClient inst = apacheClient.get(); if (inst != null) return inst; inst = createShortTimeoutBuilder().build(); apacheClient.compareAndSet(null, inst); return inst; } private static SSLConnectionSocketFactory createSslFactory() { // TODO: Geht nich for (String proto : new String[] { "TLSv1.2", "TLSv1.1", "TLS" }) { try { return new SSLConnectionSocketFactory(SSLContexts.custom().setProtocol(proto).build()); } catch (Exception e) { LOGGER.warn(proto + " not available", e); } } return SSLConnectionSocketFactory.getSystemSocketFactory(); } private static HttpClientBuilder createShortTimeoutBuilder() { HttpClientBuilder builder = HttpClientBuilder.create().setSSLSocketFactory(createSslFactory()); builder.setDefaultSocketConfig(SocketConfig.custom().setSoTimeout(8000).build()); PoolingHttpClientConnectionManager pm = new PoolingHttpClientConnectionManager(); pm.setDefaultMaxPerRoute(4); builder.setConnectionManager(pm); return builder; } private static HttpClientBuilder createSlxBuilder() { HttpClientBuilder builder = HttpClientBuilder.create(); builder.setRoutePlanner(new SlxRoutePlanner(null)); builder.setDefaultSocketConfig(SocketConfig.custom().setSoTimeout(8000).build()); Registry csf = RegistryBuilder. create() .register("http", new SlxSocketFactory()) .register("https", createSslFactory()) .build(); PoolingHttpClientConnectionManager cm = new PoolingHttpClientConnectionManager(csf); cm.setDefaultMaxPerRoute(4); builder.setConnectionManager(cm); return builder; } private static boolean testHttpsMaster() { RequestConfig requestConfig = RequestConfig.custom() .setConnectionRequestTimeout(3000) .setConnectTimeout(3000) .setSocketTimeout(3000) .build(); HttpGet httpGet = new HttpGet(ShibbolethEcp.BWLP_SP.toString()); httpGet.setConfig(requestConfig); httpGet.setHeader("Accept", "text/html, application/vnd.paos+xml"); 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); LOGGER.debug("Master server replies with " + response.getStatusLine().getStatusCode()); return response.getStatusLine().getStatusCode() == 200; } catch (Exception e) { LOGGER.debug("Cannot reach master server via HTTPS", e); return false; } } private static class SlxSocketFactory extends PlainConnectionSocketFactory { @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(); } } private static class SlxRoutePlanner extends SystemDefaultRoutePlanner { public SlxRoutePlanner(ProxySelector proxySelector) { super(proxySelector); } @Override public HttpRoute determineRoute(HttpHost host, HttpRequest request, HttpContext context) throws HttpException { HttpRoute route = super.determineRoute(host, request, context); context.setAttribute("openslx.l7proxy", route); return route; } } }