summaryrefslogblamecommitdiffstats
path: root/dozentenmodul/src/main/java/org/openslx/dozmod/util/ProxyConfigurator.java
blob: a6dede1c05baf851aeee77066f0a68e4f93ceff1 (plain) (tree)
1
2
3
4
5
6
7
8
9
                                
 

                           
                              
                       
                               
                                                   
 




















                                                                                    


                                           

                                                  
                                                       
                                              
                             


                                                         

                                            






                         
                                



                                
                                                                                           
        

                                                                                                   





                                                                                                


                                 
                                   
                                                                                                                       








                                                                                                
                                               



                                                                                    

                                                                                                   
                               
                 







                                                                                                                        
                                                       

                                                                       
                                                                                                          
                                               




                                                               
                                                              

                                              
                                                              

                                              
                                                               
                                 
                                                                                                             






                                                                           
                                                                                               
                                                   

                                                                               
 



                                                                                         
                                                                


                                                             
                                                                  

                                                           



                                                                         
        














                                                              
                                                                      













                                                                                                                                


                                                             



















                                                                                                                                             

         
                                                  

                                                                                               
                                         
                                                                                
                                                 
                                                                                   

                                                                                                                     
                     
                                                                             

                                                                                         




                                                                                

                                                                                    






                                                                                       


















                                                                                    
                                                                                                
                                                      


                                                                              

                 
        
 
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.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;
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<CloseableHttpClient> apacheClient = new AtomicReference<>();
	
	private static final TLS[] SUPPORTED_TLS_VERSIONS = { TLS.V_1_3, TLS.V_1_2, TLS.V_1_1 };

	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);

	/**
	 * 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 HttpClientBuilder createShortTimeoutBuilder() {
		return HttpClientBuilder.create()
				.setConnectionManager(PoolingHttpClientConnectionManagerBuilder.create()
						.setSSLSocketFactory(SSLConnectionSocketFactoryBuilder.create()
								.setTlsVersions(ProxyConfigurator.SUPPORTED_TLS_VERSIONS)
								.build())
						.setDefaultTlsConfig(TlsConfig.custom()
								.setSupportedProtocols(ProxyConfigurator.SUPPORTED_TLS_VERSIONS)
								.build())
						.setDefaultConnectionConfig(ConnectionConfig.custom()
								.setConnectTimeout(ProxyConfigurator.TIMEOUT_CONNECT)
								.setSocketTimeout(ProxyConfigurator.TIMEOUT_SOCKET)
								.build())
						.setMaxConnPerRoute(4)
						.build());
	}

	private static HttpClientBuilder createSlxBuilder() {

		final RegistryBuilder<ConnectionSocketFactory> registryBuilder = RegistryBuilder.<ConnectionSocketFactory>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() {
		final RequestConfig requestConfig = RequestConfig.custom()
				.setConnectionRequestTimeout(ProxyConfigurator.TIMEOUT_REQUEST)
				.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.getCode());
			return response.getCode() == 200;
		} 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();
		}
	}

	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;
		}
	}
	
}