Nachdem in den letzten Monaten die spannendsten Themen um mich herum mit Windeln und Ausscheidungen jeglicher Art von Babys zu tun hatten, habe ich diese Woche wieder ein spannendes IT Problem auf dem Schreibtisch gehabt.
In meinem aktuellen Projekt soll ein Single Sign On (SSO) eingeführt werden. Das spannende dabei ist, das Web-Applikationen und eine Java-Spring Applikation mit SSO versehen werden sollen. Was daran spannend ist, wird deutlich, wenn man sich skizenhaft anschaut wie gängige SSO Provider arbeiten.
Es soll eine Applikation abgesichert werden, die unter myService.someDomain.de
erreichbar ist, dabei passiert folgendes:
- User öffnet myService.someDomain.de.
GET myService.someDomain.de
- Der Server erkennt, dass der User nicht eingeloggt ist und leitet diesen zum SSO Provider um. Dabei gibt er ihm einen Backlink auf sich mit:
302 sso.anydomain.de/login?backlink=https://myService.someDomain.de
- Der SSO Provider prüft anhand der Cookies in seiner Domäne, die Identität des Users. Falls der User noch nicht eingeloggt ist, bekommt er ein User-Login angezeigt
- Nachdem der User erfolgreich angemeldet wurde, wird der Browser auf den Backlink umgeleitet und eine TicketId mitgegeben:
302 myService.someDomain.de?ticket=123456789
- Die Applikation nimmt die TicketId und fragt anhand dieser die Identiät des Users über eine API an.
Solange man sich im Webumfeld befindet, alles gut. Aber eine Desktop Applikation wird nun Probleme haben an die Identität des Users zu kommen, da diese in den Cookies des Browsers steht.
Man könnte sich auch einen Speicherort außerhalb des Cookies überlegen, an den die Desktop Applikation ohne weiteres kommt (z.B. das lokale Filesystem), da wird aber der Browser Probleme haben dran zu kommen, da der in einer Sandbox läuft und an keine lokalen Ressourcen des Rechners dran kommt.
Wie mans nun dreht und wendet, man muss sich einen Hack überlegen, wie man
- es der Desktop Applikation erlaubt an die Identität in den Cookies zu kommen
oder
- es dem Browser erlaubt an die lokal gespeicherte Identität zu kommen.
Da die meisten SSO Provider die Webschine standardmäßig unterstützten, fährt man deutlich standardkonformer und damit risikoärmer, wenn man die Desktop Applikation dahingehend anpasst, dass diese die Cookies ausliest.
Java bietet die Desktop-API, über die man u.a. eine Url im Standardbrowser des Systems öffnen kann.
Desktop.getDesktop().browser(new URI("https://
sso.anydomain.de/login
"));
Damit geht ein Browser-Fenster auf, das den User authentifizert, entweder über ein bereits vorhandenes Login, oder über eine Username/Passwort Eingabe.
Nun haben wir zwar schon einen Browser, der den User kennt, geöffnet, stehen aber weiterhin vor dem Problem, dass die Applikation ohne tiefere Kenntnis der Browserinterna nicht an die Information rankommt, wer eingeloggt ist. Der Browser darf leider auch nicht viel, um die Login-Information an die Applikation weiterzugeben. Aber eins kann ein Browser sehr gut: HTTP.
Wenn wir für den Login in der Desktop Applikation einen HTTP Server öffnen, dann kann der Browser seine Informationen dorthin weitergeben. Dafür kann sogar standard SSO-Vorgehen genutzt werden. Da der geöffnete Browser auf der selben Maschine läuft wie die startende Desktop Applikation, kann er die TicketId einfach an localhost
weiterleiten.
sso.anydomain.de/login?backlink=http://localhost
Der Webserver muss nichts anderes tun können, als einen GET-Request entgegen zu nehmen und zu beantworten, daher muss es kein ausgewachsener Tomcat oder Jetty sein, es tut auch ein JLHTTP.
Der Java-Code dazu kann wie folgt aussehen:
Semaphore ticketIdSemaphore = new Semaphore();
HttpServer server = new HttpServer();
server.onRequest(req -> {
ticketIdSemaphore.set(req.getParameter("ticketId"));
});
server.start();
Desktop.getDesktop().browser(new URI("https://sso.anydomain.de/login?backlink=http://localhost
"));
String ticketId = semaphore.get();
User user = new MySSoProviderApi().validate(ticketId);
Ein Nachteil dieser Methode ist natürlich, dass es für das Login einen Medienbruch gibt und der User die native Applikation verlässt, um sich anzumelden. Ob dies akzeptabel ist, muss fachlich geprüft werden. Die Vorteile auf technischer Seite sind:
- Die Lösung ist OS- und Browser-unabhängig, da nur Standard-Java und HTTP verwendet wird.
- Man kann SSO wie es vom Provider kommt out of the box benutzen und auf diese Weise Implementierungsaufwände sparen und geht keine Security Risiken bei selbstgestrickten Lösungen ein.