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

                                              
                               
                           

                             
                                                   
 

                                




                                                                   
                                                                     
                                                                 
                                                                                    
                                                                        

                                        


                                           

                                                  
                                                       
                                              
                             


                                                         

                                            






                         
                                



                                
                                                                                           



                                                                                                         



                                                                            


                                            
                

                                                    






                                                          













                                                                                        

                 
 






                                                         
                             













                                                                                                        
                                 
                                               

                         





























                                                                             
                 


                                                                                                         

                               
 
                                                       

                                                                       
                                                                                                          
                                               




                                                               
                                                              

                                              
                                                              

                                              
                                                               
                                 
                                                                                                             






                                                                           
                                                                                               
                                                   

                                                                               
 



                                                                                         
                                                                

                                                             
                                              
                                                                         








                                                                                                                       
                 

                                                  
         
 









                                                              
                                                      



                                                       











                                                                                                                     


                                                                                                               
                                                                                            

                                                                                       
                                                                                                   






                                                                                                                     

         
                                                                            

                                                                                               
                                         
                                                                                
                                                 
                                                                                   

                                                                                                                     
                                                                                
                                                                                         

                                                     




                                                                                
 

                                                        

         
 
package org.openslx.dozmod.util;

import java.net.ProxySelector;
import java.security.KeyManagementException;
import java.security.NoSuchAlgorithmException;
import java.text.MessageFormat;
import java.util.ArrayList;
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.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.CloseableHttpResponse;
import org.apache.hc.client5.http.impl.classic.HttpClientBuilder;
import org.apache.hc.client5.http.impl.io.PoolingHttpClientConnectionManagerBuilder;
import org.apache.hc.client5.http.ssl.SSLConnectionSocketFactoryBuilder;
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 final AtomicReference<CloseableHttpClient> apacheClient = new AtomicReference<>();

	private static final List<TLS[]> 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<TLS[]> res = new ArrayList<>();
		res.add(null);
		boolean ok = false;
		try {
			SSLContext.getInstance("TLSv1.3");
			ok = true;
		} catch (Exception e) {
		}
		if (ok) {
			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);
		}
	}

	private static void tryAllThriftVariants() {
		thriftCtx = null;
		for (TLS[] tls : TLS_CHECKLIST) {
			if (tls == null)
				continue;
			SSLContext ctx;
			MasterServer.Client masterClient;
			try {
				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) {
			}
		}
	}

	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();
		}
		// 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() {

			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) {
			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.
	 *
	 * @return client
	 */
	public static CloseableHttpClient getClient() {
		CloseableHttpClient inst = apacheClient.get();
		if (inst != null)
			return inst;
		inst = createDefaultBuilder().build();
		apacheClient.compareAndSet(null, inst);
		return inst;
	}

	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(tlsVersions)
								.build())
						.setDefaultTlsConfig(TlsConfig.custom()
								.setSupportedProtocols(tlsVersions)
								.build())
						.setDefaultConnectionConfig(ConnectionConfig.custom()
								.setConnectTimeout(ProxyConfigurator.TIMEOUT_CONNECT)
								.setSocketTimeout(ProxyConfigurator.TIMEOUT_SOCKET)
								.build())
						.setMaxConnPerRoute(4)
						.build());
	}

	private static boolean testHttpsMaster(CloseableHttpClient client) {
		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 (CloseableHttpResponse response = client.execute(httpGet)) {
			LOGGER.debug("Master server replies with " + response.getCode());
			int rc = response.getCode();
			return rc >= 200 && rc < 300;
		} catch (Exception e) {
			LOGGER.debug("Cannot reach master server via HTTPS", e);
			return false;
		}
	}

	public static SSLContext getThriftSslContext() {
		return thriftCtx;
	}

}