summaryrefslogtreecommitdiffstats
path: root/dozentenmodul/src/main
diff options
context:
space:
mode:
authorSimon Rettberg2015-08-18 19:49:30 +0200
committerSimon Rettberg2015-08-18 19:49:30 +0200
commit6e1b0f5a5da9bb8f73ff62166d09647d9d479ad8 (patch)
tree2b8dd3e12f96f2dbd5df8fa7caa1e8c34af06745 /dozentenmodul/src/main
parent[client] Remove old unused class (diff)
downloadtutor-module-6e1b0f5a5da9bb8f73ff62166d09647d9d479ad8.tar.gz
tutor-module-6e1b0f5a5da9bb8f73ff62166d09647d9d479ad8.tar.xz
tutor-module-6e1b0f5a5da9bb8f73ff62166d09647d9d479ad8.zip
[client] Use TLS to talk to master and satellite
Diffstat (limited to 'dozentenmodul/src/main')
-rw-r--r--dozentenmodul/src/main/java/org/openslx/dozmod/App.java20
-rw-r--r--dozentenmodul/src/main/java/org/openslx/dozmod/Config.java2
-rw-r--r--dozentenmodul/src/main/java/org/openslx/dozmod/authentication/EcpAuthenticator.java3
-rw-r--r--dozentenmodul/src/main/java/org/openslx/dozmod/authentication/FingerprintManager.java49
-rw-r--r--dozentenmodul/src/main/java/org/openslx/dozmod/authentication/TestAccountAuthenticator.java3
-rw-r--r--dozentenmodul/src/main/java/org/openslx/dozmod/gui/GraphicalCertHandler.java115
-rw-r--r--dozentenmodul/src/main/java/org/openslx/dozmod/gui/Gui.java21
-rw-r--r--dozentenmodul/src/main/java/org/openslx/dozmod/gui/MainWindow.java25
-rw-r--r--dozentenmodul/src/main/java/org/openslx/dozmod/gui/window/LoginWindow.java7
9 files changed, 228 insertions, 17 deletions
diff --git a/dozentenmodul/src/main/java/org/openslx/dozmod/App.java b/dozentenmodul/src/main/java/org/openslx/dozmod/App.java
index 29e6d961..4be5a34d 100644
--- a/dozentenmodul/src/main/java/org/openslx/dozmod/App.java
+++ b/dozentenmodul/src/main/java/org/openslx/dozmod/App.java
@@ -8,11 +8,13 @@ import java.awt.event.ComponentEvent;
import java.awt.event.ContainerEvent;
import java.io.File;
import java.io.IOException;
+import java.security.NoSuchAlgorithmException;
import java.util.HashSet;
import java.util.Set;
import java.util.regex.Matcher;
import java.util.regex.Pattern;
+import javax.net.ssl.SSLContext;
import javax.swing.SwingUtilities;
import javax.swing.UIDefaults;
import javax.swing.UIManager;
@@ -35,6 +37,12 @@ public class App {
// Logger
private final static Logger LOGGER = Logger.getLogger(App.class);
+ public static final int THRIFT_PORT = 9090;
+
+ public static final int THRIFT_SSL_PORT = THRIFT_PORT + 1;
+
+ public static final int THRIFT_TIMEOUT_MS = 15000;
+
private static Thread proxyThread = null;
private static void setupLogger() {
@@ -141,7 +149,17 @@ public class App {
// setup global thrift connection error handler before anything else
// Set master server to use (TODO: make configurable via command line)
- ThriftManager.setMasterServerAddress("bwlp-masterserver.ruf.uni-freiburg.de");
+ try {
+ ThriftManager.setMasterServerAddress(SSLContext.getDefault(), "bwlp-masterserver.ruf.uni-freiburg.de", THRIFT_SSL_PORT,
+ THRIFT_TIMEOUT_MS);
+ } catch (final NoSuchAlgorithmException e1) {
+ SwingUtilities.invokeLater(new Runnable() {
+ @Override
+ public void run() {
+ Gui.showMessageBox(null, "SSL nicht verfügbar", MessageType.ERROR, LOGGER, e1);
+ }
+ });
+ }
SwingUtilities.invokeLater(new Runnable() {
@Override
diff --git a/dozentenmodul/src/main/java/org/openslx/dozmod/Config.java b/dozentenmodul/src/main/java/org/openslx/dozmod/Config.java
index db384ecf..f242f31f 100644
--- a/dozentenmodul/src/main/java/org/openslx/dozmod/Config.java
+++ b/dozentenmodul/src/main/java/org/openslx/dozmod/Config.java
@@ -85,7 +85,7 @@ public class Config {
// Check if we got a path
configFile = new File(configPath + File.separatorChar + "bwSuite" + File.separatorChar
- + "config.properties");
+ + "config.properties").getAbsoluteFile();
// Check if the directory exists.
if (!configFile.getParentFile().exists()) {
diff --git a/dozentenmodul/src/main/java/org/openslx/dozmod/authentication/EcpAuthenticator.java b/dozentenmodul/src/main/java/org/openslx/dozmod/authentication/EcpAuthenticator.java
index 4e0174d4..5b7b1ccd 100644
--- a/dozentenmodul/src/main/java/org/openslx/dozmod/authentication/EcpAuthenticator.java
+++ b/dozentenmodul/src/main/java/org/openslx/dozmod/authentication/EcpAuthenticator.java
@@ -64,9 +64,10 @@ public class EcpAuthenticator implements Authenticator {
}
// create the session for the user from the response of the ECP
List<Satellite> sats = new ArrayList<>();
+ // TODO: Handle cert fingerprint
if (response.satellites2 != null) {
for (Entry<String, List<String>> it : response.satellites2.entrySet()) {
- sats.add(new Satellite(it.getValue(), it.getKey()));
+ sats.add(new Satellite(it.getValue(), it.getKey(), null));
}
}
data = new AuthenticationData(response.token, response.sessionId, sats);
diff --git a/dozentenmodul/src/main/java/org/openslx/dozmod/authentication/FingerprintManager.java b/dozentenmodul/src/main/java/org/openslx/dozmod/authentication/FingerprintManager.java
new file mode 100644
index 00000000..58b0d305
--- /dev/null
+++ b/dozentenmodul/src/main/java/org/openslx/dozmod/authentication/FingerprintManager.java
@@ -0,0 +1,49 @@
+package org.openslx.dozmod.authentication;
+
+import java.io.File;
+import java.io.FileInputStream;
+import java.io.FileOutputStream;
+import java.io.IOException;
+import java.util.Properties;
+
+import org.apache.commons.codec.binary.Base64;
+import org.apache.log4j.Logger;
+import org.openslx.dozmod.Config;
+
+public class FingerprintManager {
+
+ private static final Logger LOGGER = Logger.getLogger(FingerprintManager.class);
+
+ private static final File file = new File(Config.getPath(), "fingerprints.properties");
+ private static final Properties prop = new Properties();
+
+ static {
+ if (file.exists()) {
+ try {
+ prop.load(new FileInputStream(file));
+ } catch (IOException e) {
+ LOGGER.warn("Could not load cached fingerprints from " + file.toString());
+ }
+ }
+ }
+
+ public static void saveFingerprint(String address, byte[] fingerprint) {
+ saveFingerprint(address, fingerprint, true);
+ }
+
+ public static void saveFingerprint(String address, byte[] fingerprint, boolean replace) {
+ if (replace || !prop.containsKey(address)) {
+ prop.setProperty(address, Base64.encodeBase64String(fingerprint));
+ try {
+ prop.store(new FileOutputStream(file), "Written by bwLehrstuhl");
+ } catch (IOException e) {
+ LOGGER.warn("Could not store fingerprint");
+ }
+ }
+ }
+
+ public static byte[] getFingerprint(String address) {
+ return Base64.decodeBase64(prop.getProperty(address));
+ }
+
+}
diff --git a/dozentenmodul/src/main/java/org/openslx/dozmod/authentication/TestAccountAuthenticator.java b/dozentenmodul/src/main/java/org/openslx/dozmod/authentication/TestAccountAuthenticator.java
index 8868b53a..5d254d85 100644
--- a/dozentenmodul/src/main/java/org/openslx/dozmod/authentication/TestAccountAuthenticator.java
+++ b/dozentenmodul/src/main/java/org/openslx/dozmod/authentication/TestAccountAuthenticator.java
@@ -34,7 +34,8 @@ public class TestAccountAuthenticator implements Authenticator {
if (authResult != null && authResult.authToken != null) {
LOGGER.info(authResult);
List<Satellite> sats = new ArrayList<>();
- sats.add(new Satellite(Arrays.asList(new String[] { authResult.serverAddress }), "default"));
+ // TODO: Handle cert fingerprint
+ sats.add(new Satellite(Arrays.asList(new String[] { authResult.serverAddress }), "default", null));
AuthenticationData data = new AuthenticationData(authResult.authToken, authResult.sessionId, sats);
callback.postLogin(ReturnCode.NO_ERROR, data, null);
} else {
diff --git a/dozentenmodul/src/main/java/org/openslx/dozmod/gui/GraphicalCertHandler.java b/dozentenmodul/src/main/java/org/openslx/dozmod/gui/GraphicalCertHandler.java
new file mode 100644
index 00000000..07b44175
--- /dev/null
+++ b/dozentenmodul/src/main/java/org/openslx/dozmod/gui/GraphicalCertHandler.java
@@ -0,0 +1,115 @@
+package org.openslx.dozmod.gui;
+
+import java.math.BigInteger;
+import java.security.KeyManagementException;
+import java.security.MessageDigest;
+import java.security.NoSuchAlgorithmException;
+import java.security.cert.CertificateException;
+import java.security.cert.X509Certificate;
+import java.util.Arrays;
+
+import javax.net.ssl.SSLContext;
+import javax.net.ssl.TrustManager;
+import javax.net.ssl.X509TrustManager;
+
+import org.apache.log4j.Logger;
+import org.openslx.dozmod.authentication.FingerprintManager;
+import org.openslx.dozmod.gui.Gui.GuiCallable;
+import org.openslx.dozmod.gui.helper.MessageType;
+
+public class GraphicalCertHandler {
+
+ private static final Logger LOGGER = Logger.getLogger(GraphicalCertHandler.GuiTrustManager.class);
+
+ private class GuiTrustManager implements X509TrustManager {
+
+ @Override
+ public void checkClientTrusted(X509Certificate[] certs, String authType) throws CertificateException {
+ }
+
+ @Override
+ public void checkServerTrusted(X509Certificate[] certs, String authType) throws CertificateException {
+ if (certs == null || certs.length == 0) {
+ Gui.asyncMessageBox(
+ "Der Satellit besitzt kein Zertifikat. Verschlüsselte Verbindung nicht möglich.\n\n"
+ + "Möchten Sie trotzdem fortfahren?", MessageType.WARNING, LOGGER, null);
+ // TODO: Ask and do
+ throw new CertificateException("No certificate provided by server");
+ }
+ byte[] encoded = certs[0].getEncoded();
+ MessageDigest md;
+ try {
+ md = MessageDigest.getInstance("SHA-256");
+ } catch (NoSuchAlgorithmException e) {
+ LOGGER.warn("Could not get SHA-256 hash of certificate", e);
+ throw new CertificateException("Could not get SHA-256 hash of certificate");
+ }
+ md.update(encoded);
+ byte[] actualFingerprint = md.digest();
+ final String actualFingerprintReadable = new BigInteger(actualFingerprint).toString(16);
+ // Now check the fingerprint
+ byte[] expectedFingerprint = FingerprintManager.getFingerprint(address);
+ final String question;
+ if (expectedFingerprint == null) {
+ // Not known yet, ask
+ question = "Magst du die Zahl " + actualFingerprintReadable + "?";
+ } else if (Arrays.equals(actualFingerprint, expectedFingerprint)) {
+ // Known, matches, everything's fine
+ return;
+ } else {
+ // Known, mismatch, panic!
+ question = "!!! ALARM !!!! ALARM !!! *trage hol*\n\n" + "Der Fingerabdruck von " + address
+ + " hat sich verändert.\n" + "Erwartet: "
+ + new BigInteger(expectedFingerprint).toString(16) + "\n" + "Vorgefunden: "
+ + actualFingerprintReadable + "\n\n"
+ + "Möchten Sie trotzdem zu diesem Satelliten verbinden?";
+ }
+ // Some question needs to be asked
+ Boolean userOk = Gui.syncExec(new GuiCallable<Boolean>() {
+ @Override
+ public Boolean run() {
+ return Gui.showMessageBox(null, question, MessageType.QUESTION_YESNO, null, null);
+ }
+ });
+ if (userOk) {
+ FingerprintManager.saveFingerprint(address, actualFingerprint);
+ } else {
+ throw new CertificateException("Rejected by user");
+ }
+ }
+
+ @Override
+ public X509Certificate[] getAcceptedIssuers() {
+ return null;
+ }
+
+ }
+
+ private final String address;
+
+ private final SSLContext sslContext;
+
+ private GraphicalCertHandler(String address) {
+ SSLContext ctx = null;
+ try {
+ ctx = SSLContext.getInstance("TLSv1.2");
+ } catch (NoSuchAlgorithmException e) {
+ Gui.asyncMessageBox("Could not get TLSv1.2 SSL context", MessageType.ERROR, LOGGER, e);
+ }
+ if (ctx != null) {
+ try {
+ ctx.init(null, new TrustManager[] { new GuiTrustManager() }, null);
+ } catch (KeyManagementException e) {
+ Gui.asyncMessageBox("Could not initialize TLSv1.2 SSL context", MessageType.ERROR, LOGGER, e);
+ ctx = null;
+ }
+ }
+ this.sslContext = ctx;
+ this.address = address;
+ }
+
+ public static SSLContext getSslContext(String address) {
+ return new GraphicalCertHandler(address).sslContext;
+ }
+
+}
diff --git a/dozentenmodul/src/main/java/org/openslx/dozmod/gui/Gui.java b/dozentenmodul/src/main/java/org/openslx/dozmod/gui/Gui.java
index 0b961461..a40600fe 100644
--- a/dozentenmodul/src/main/java/org/openslx/dozmod/gui/Gui.java
+++ b/dozentenmodul/src/main/java/org/openslx/dozmod/gui/Gui.java
@@ -271,4 +271,25 @@ public class Gui {
return ret == JOptionPane.OK_OPTION || ret == JOptionPane.YES_OPTION;
}
+ /**
+ * Show a message box to the user asynchronously, and optionally log the
+ * message to the log file. This is most useful when working from another
+ * thread.
+ *
+ * @param message Message to display. Can be multi line.
+ * @param messageType Type of message (warning, information)
+ * @param logger Logger instance to log to. Can be null.
+ * @param exception Exception related to this message. Can be null.
+ * @return true if OK or YES was clicked, false for CANCEL/NO/(X)
+ */
+ public static void asyncMessageBox(final String message, final MessageType messageType,
+ final Logger logger, final Throwable exception) {
+ SwingUtilities.invokeLater(new Runnable() {
+ @Override
+ public void run() {
+ showMessageBox(null, message, messageType, logger, exception);
+ }
+ });
+ }
+
}
diff --git a/dozentenmodul/src/main/java/org/openslx/dozmod/gui/MainWindow.java b/dozentenmodul/src/main/java/org/openslx/dozmod/gui/MainWindow.java
index 2f9fbf50..f8c179b0 100644
--- a/dozentenmodul/src/main/java/org/openslx/dozmod/gui/MainWindow.java
+++ b/dozentenmodul/src/main/java/org/openslx/dozmod/gui/MainWindow.java
@@ -64,7 +64,6 @@ public abstract class MainWindow {
private static final List<ActivityPanel> activities = new ArrayList<>();
-
/**
* Set the visible page of the main window.
*
@@ -148,10 +147,10 @@ public abstract class MainWindow {
return Gui.syncExec(new GuiCallable<Boolean>() {
@Override
public Boolean run() {
- return Gui.showMessageBox(mainWindow, "Die Kommunikation mit dem bwLehrpool-Zentralserver ist"
- + " gestört. Der Aufruf der Funktion " + method
- + " ist fehlgeschlagen.\n\n"
- + "Möchten Sie den Aufruf wiederholen?",
+ return Gui.showMessageBox(mainWindow,
+ "Die Kommunikation mit dem bwLehrpool-Zentralserver ist"
+ + " gestört. Der Aufruf der Funktion " + method
+ + " ist fehlgeschlagen.\n\n" + "Möchten Sie den Aufruf wiederholen?",
MessageType.ERROR_RETRY, LOGGER, t);
}
});
@@ -167,10 +166,10 @@ public abstract class MainWindow {
return Gui.syncExec(new GuiCallable<Boolean>() {
@Override
public Boolean run() {
- return Gui.showMessageBox(mainWindow, "Die Kommunikation mit dem Satellitenserver ist"
- + " gestört. Der Aufruf der Funktion " + method
- + " ist fehlgeschlagen.\n\n"
- + "Möchten Sie den Aufruf wiederholen?",
+ return Gui.showMessageBox(mainWindow,
+ "Die Kommunikation mit dem Satellitenserver ist"
+ + " gestört. Der Aufruf der Funktion " + method
+ + " ist fehlgeschlagen.\n\n" + "Möchten Sie den Aufruf wiederholen?",
MessageType.ERROR_RETRY, LOGGER, t);
}
});
@@ -251,10 +250,14 @@ public abstract class MainWindow {
// Wait for proxy server init
App.waitForInit();
try {
- WhoamiInfo whoami = ThriftManager.getNewSatClient(session.address).whoami(session.token);
+ WhoamiInfo whoami = ThriftManager.getNewSatelliteClient(
+ GraphicalCertHandler.getSslContext(session.address), session.address,
+ App.THRIFT_SSL_PORT, App.THRIFT_TIMEOUT_MS).whoami(session.token);
// TODO: Satellite whoami call
Session.initialize(whoami, session.address, session.token, session.masterToken);
- ThriftManager.setSatelliteAddress(Session.getSatelliteAddress());
+ ThriftManager.setSatelliteAddress(
+ GraphicalCertHandler.getSslContext(Session.getSatelliteAddress()),
+ Session.getSatelliteAddress(), App.THRIFT_SSL_PORT, App.THRIFT_TIMEOUT_MS);
LOGGER.info("Saved session used for resume.");
} catch (Exception e1) {
LOGGER.info("Session resume failed.", e1);
diff --git a/dozentenmodul/src/main/java/org/openslx/dozmod/gui/window/LoginWindow.java b/dozentenmodul/src/main/java/org/openslx/dozmod/gui/window/LoginWindow.java
index 36b59eed..56a0607c 100644
--- a/dozentenmodul/src/main/java/org/openslx/dozmod/gui/window/LoginWindow.java
+++ b/dozentenmodul/src/main/java/org/openslx/dozmod/gui/window/LoginWindow.java
@@ -32,6 +32,7 @@ import org.openslx.dozmod.authentication.EcpAuthenticator;
import org.openslx.dozmod.authentication.ShibbolethEcp;
import org.openslx.dozmod.authentication.ShibbolethEcp.ReturnCode;
import org.openslx.dozmod.authentication.TestAccountAuthenticator;
+import org.openslx.dozmod.gui.GraphicalCertHandler;
import org.openslx.dozmod.gui.Gui;
import org.openslx.dozmod.gui.MainWindow;
import org.openslx.dozmod.gui.helper.MessageType;
@@ -333,7 +334,8 @@ public class LoginWindow extends LoginWindowLayout {
// TODO: Show satellite selection if > 1
//String satAddress = data.satellites.get(0).addressList.get(0);
String satAddress = "132.230.8.113"; // TODO: HACK HACK
- Client client = ThriftManager.getNewSatClient(satAddress);
+ Client client = ThriftManager.getNewSatelliteClient(GraphicalCertHandler.getSslContext(satAddress), satAddress,
+ App.THRIFT_SSL_PORT, App.THRIFT_TIMEOUT_MS);
if (client == null) {
Gui.showMessageBox(this, "Login erfolgreich, aber der Satellit antwortet nicht",
MessageType.ERROR, LOGGER, null);
@@ -360,7 +362,8 @@ public class LoginWindow extends LoginWindowLayout {
}
if (whoami != null) {
Session.initialize(whoami, satAddress, data.satelliteToken, data.masterToken);
- ThriftManager.setSatelliteAddress(Session.getSatelliteAddress());
+ ThriftManager.setSatelliteAddress(GraphicalCertHandler.getSslContext(Session.getSatelliteAddress()),
+ Session.getSatelliteAddress(), App.THRIFT_SSL_PORT, App.THRIFT_TIMEOUT_MS);
// now read the config to see if the user already agreed to the disclaimer
// if (DisclaimerWindow.shouldBeShown())
// VirtualizerNoticeWindow.open();