diff options
author | Simon Rettberg | 2020-04-15 15:40:55 +0200 |
---|---|---|
committer | Simon Rettberg | 2020-04-15 15:40:55 +0200 |
commit | 41186ddf8eef2530b95fe90f03bd84ee841115d9 (patch) | |
tree | d131446372d68738d6d22993f64ca52ea90732f6 /src/main/java/de/bwlehrpool/bwlp_guac/ConnectionManager.java | |
download | bwlp-guacamole-ext-41186ddf8eef2530b95fe90f03bd84ee841115d9.tar.gz bwlp-guacamole-ext-41186ddf8eef2530b95fe90f03bd84ee841115d9.tar.xz bwlp-guacamole-ext-41186ddf8eef2530b95fe90f03bd84ee841115d9.zip |
First Commit
Diffstat (limited to 'src/main/java/de/bwlehrpool/bwlp_guac/ConnectionManager.java')
-rw-r--r-- | src/main/java/de/bwlehrpool/bwlp_guac/ConnectionManager.java | 219 |
1 files changed, 219 insertions, 0 deletions
diff --git a/src/main/java/de/bwlehrpool/bwlp_guac/ConnectionManager.java b/src/main/java/de/bwlehrpool/bwlp_guac/ConnectionManager.java new file mode 100644 index 0000000..0132e43 --- /dev/null +++ b/src/main/java/de/bwlehrpool/bwlp_guac/ConnectionManager.java @@ -0,0 +1,219 @@ +package de.bwlehrpool.bwlp_guac; + +import java.io.BufferedInputStream; +import java.io.ByteArrayOutputStream; +import java.io.IOException; +import java.net.HttpURLConnection; +import java.net.MalformedURLException; +import java.net.URL; +import java.security.KeyManagementException; +import java.security.NoSuchAlgorithmException; +import java.security.cert.CertificateException; +import java.security.cert.X509Certificate; +import java.util.Iterator; +import java.util.LinkedHashMap; + +import javax.net.ssl.HostnameVerifier; +import javax.net.ssl.HttpsURLConnection; +import javax.net.ssl.SSLContext; +import javax.net.ssl.SSLSession; +import javax.net.ssl.SSLSocketFactory; +import javax.net.ssl.TrustManager; +import javax.net.ssl.X509TrustManager; + +import org.codehaus.jackson.map.ObjectMapper; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +/** + * Broker for all clients available. + * Keeps track of which clients are online, offline, assigned to a user etc. + */ +public class ConnectionManager { + + private static final Logger LOGGER = LoggerFactory.getLogger(ConnectionManager.class); + + // TODO: Config + private static final String SOURCE_URL = SlxConfig.clientListUrl(); + + private static final LinkedHashMap<String, AvailableClient> clientPool = new LinkedHashMap<String, AvailableClient>(); + + /** + * Pass plain user name, get existing connection (if any), or a fresh one + * @param user (LDAP) user name + */ + public static WrappedConnection getForUser(String user) { + if (SOURCE_URL == null) { + LOGGER.warn("Don't have a source URL for client machines!"); + return null; + } + try { + updateList(); + // Find existing/free client + AvailableClient freeClient; + for (;;) { + freeClient = null; + synchronized (clientPool) { + for (AvailableClient ac : clientPool.values()) { + if (ac.isInUseBy(user)) { + freeClient = ac; + break; + } + } + if (freeClient == null) { + for (AvailableClient ac : clientPool.values()) { + if (ac.claim(user)) { + freeClient = ac; + break; + } + } + } + } + if (freeClient == null) + return null; // TODO: No more clients available -- how to handle? + // Found free or existing client, check if connection is (still) possible + if (freeClient.checkConnection(0)) { + LOGGER.info("Establishing mapping for user " + user + " to " + freeClient); + return freeClient.getConnection(user); + } + // Connection check failed - release and loop again + freeClient.releaseConnection(user); + } + } catch (Exception e) { + LOGGER.warn("KACKE AM DAMPFEN", e); + return null; + } + } + + private static long lastUpdate = 0; + + /** + * Fetch fresh client list from satellite server. + * Cache for 15 seconds. + */ + private static synchronized void updateList() { + long now = System.currentTimeMillis(); + if (now < lastUpdate) { + lastUpdate = now; + } + if (now - lastUpdate < 15000) + return; + // OK GO + lastUpdate = now; + ByteArrayOutputStream baos = new ByteArrayOutputStream(3000); + HttpURLConnection con; + try { + con = (HttpURLConnection) new URL(SOURCE_URL).openConnection(); + } catch (MalformedURLException e1) { + LOGGER.warn("Bad Connection Pool URL", e1); + return; + } catch (IOException e1) { + LOGGER.warn("Cannot connect to Connection Pool URL", e1); + return; + } + if (con instanceof HttpsURLConnection) { + ((HttpsURLConnection) con).setHostnameVerifier(ignorer); + ((HttpsURLConnection) con).setSSLSocketFactory(sockFac); + } + try (BufferedInputStream in = new BufferedInputStream(con.getInputStream())) { + byte dataBuffer[] = new byte[2048]; + int bytesRead; + while ((bytesRead = in.read(dataBuffer, 0, dataBuffer.length)) != -1) { + baos.write(dataBuffer, 0, bytesRead); + } + } catch (IOException e) { + LOGGER.warn("Error while reading reply of Connection Pool", e); + return; + } + populateList(baos.toByteArray()); + } + + private static void populateList(byte[] data) { + ObjectMapper mapper = new ObjectMapper(); + JsonClient[] list; + try { + list = mapper.readValue(data, JsonClient[].class); + } catch (Exception e) { + LOGGER.warn("Could not deserialize JSON from Connection Pool", e); + LOGGER.warn("Not updating local list"); + return; + } + synchronized (clientPool) { + for (JsonClient cnew : list) { + if (cnew.password == null || cnew.clientip == null) + continue; // Invalid + AvailableClient existing = clientPool.get(cnew.clientip); + if (existing == null) { + // New client + clientPool.put(cnew.clientip, new AvailableClient(cnew)); + LOGGER.info("New client " + cnew.clientip); + } else { + existing.update(cnew); + } + } + final long NOW = System.currentTimeMillis(); + for (Iterator<AvailableClient> it = clientPool.values().iterator(); it.hasNext();) { + AvailableClient c = it.next(); + if (c.isTimeout(NOW)) { + LOGGER.info("Removing client " + c + " from list"); + it.remove(); + } + + } + LOGGER.info("List updated. " + clientPool.size() + " clients."); + } + } + + /* + * Make SSL insecure + */ + + static { + SSLContext ctx = null; + try { + ctx = SSLContext.getInstance("TLSv1.2"); + } catch (NoSuchAlgorithmException e) { + LOGGER.warn("Could not get TLSv1.2 context, SSL will be secure :-(", e); + } + if (ctx != null) { + try { + ctx.init(null, new TrustManager[] { new X509TrustManager() { + @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 null; + } + + } }, null); + } catch (KeyManagementException e) { + LOGGER.warn("Could not initialize TLSv1.2 SSL context", e); + ctx = null; + } + } + if (ctx == null) { + sockFac = null; + } else { + sockFac = ctx.getSocketFactory(); + } + } + + private static final SSLSocketFactory sockFac; + + private static final HostnameVerifier ignorer = new HostnameVerifier() { + + @Override + public boolean verify(String hostname, SSLSession session) { + return true; + } + }; + +} |