elan ev logo
elan ev logo
Contact sales

JWT und Opencast: aktuelle Entwicklungen und Pläne

Das Thema JWT wird in der Opencast-Community schon seit einiger Zeit diskutiert, jedoch bisher nur im limitierten Umfang unterstützt. Seit 2024 – aber insbesondere in den letzten Monaten – hat der elan e.V. viel Zeit in Konzeption und Implementierung gesteckt, um dieses Thema voranzutreiben. Die Entwicklung wurde dabei community-getrieben von Hochschulen in Deutschland und der Schweiz finanziert.

Doch bevor ich die aktuellen Entwicklungen weiter erläutere, sollten wir erstmal das Problem verstehen, welches wir zu lösen versuchen.

Das Problem

Rund um die Kern-Software Opencast tummeln sich diverse "externe Apps", also Applikationen, die an Opencast angeschlossen sind. Dazu zählen sowohl Plugins für LMS (Learning Management Systems, wie Stud.IP, Moodle und Ilias) als auch Tobira und andere. Die meisten Nutzenden interagieren mit Opencast nur durch diese Apps und haben auch nur dort eine Login-Session. Diese Apps entscheiden selber, wer welche Inhalte sehen kann (z.B. anhand von Kurs-Zugehörigkeit).

Die externen Apps wollen natürlich Video-Thumbnails anzeigen, das Video abspielen lassen und den Nutzenden Funktionen wie Opencast Studio oder den Opencast Editor bereitstellen. Das stellt aber ein Problem dar, weil all diese Dinge auf dem Opencast-Server leben. Der Browser des Users würde die Inhalte ohne user-session laden (ohne Session-Cookies), also sieht es für Opencast so aus, als wäre der Nutzende nicht eingeloggt. Wie soll Opencast also entscheiden, ob Zugriff auf die Ressource gewährt werden soll? Kann es eben nicht.

Zurzeit wird teilweise LTI genutzt, das ist aber eingeschränkt und hat Probleme mit strikteren 3rd-party Cookie Regeln in Browsern. Auch ist dies keine Lösung für das Einbinden von Bildern/Videos direkt in die externen Apps. Der Status-Quo ist, dass Universitäts-Administratoren in Opencast die "static file authorization" deaktivieren und Opencast somit Bilder und Videodateien an alle herausgibt, die anfragen – selbst für geschützte Videos!

Das ist offensichtlich keine gute Lösung. Doch wie geht es besser?

JWTs

JSON Web Tokens sind ein technischer Standard, mit dem sich signierte Daten zwischen Applikationen austauschen lassen. So lassen sich diverse Autorisierungsprobleme lösen. Grob zusammengefasst enthält ein JWT eine Reihe von "claims" (Behauptungen) und eine kryptografische Signatur. Letztere erlaubt es dem Empfänger sicherzustellen, dass der JWT von einer vertrauenswürdigen Quelle stammt und den claims somit vertraut werden kann.

Spielen wir das mal konkret für Opencast und Tobira durch. Zuerst muss Opencast von einem Administrator so konfiguriert werden, dass es Tobira vertraut. Technisch heißt das: Opencast bekommt eine URL zu dem öffentlichen Schlüssel von Tobira. Wenn ein Tobira User nun z.B. ein Video schauen möchte, passiert Folgendes:

  • Tobira erzeugt einen JWT mit dem claim "darf Video 123 angucken" und signiert diesen.
  • Der JWT wird an den Browser des Users gesendet. Wenn der Browser nun das Video von Opencast lädt, wird der JWT angehangen.
  • Opencast enthält jetzt also eine mit JWT bestückte Anfrage, ein Video herunterzuladen. Opencast verifiziert zuerst die Signatur, um zu wissen, dass der JWT tatsächlich von dem vertrauten Tobira kommt. Ist das der Fall, glaubt Opencast einfach blind den claims/Behauptungen in dem JWT, in diesem Fall: "darf Video 123 angucken". Also liefert Opencast das Video aus.

Ein JWT fungiert also sozusagen als Ticket: Jeder, der diesen JWT hat, hat die Berechtigung, das Video zu schauen. Dazu ein paar wichtige technische Details:

  • JWTs enthalten fast immer ein Ablaufdatum, nach dem sie nicht mehr gültig sind. So kann vermieden werden, dass das "Ticket" für alle Ewigkeit benutzt werden kann, was auch den Schaden reduziert, wenn ein Angreifer einen JWT in die Hände bekommt. Je kürzer die Lebensdauer, desto sicherer – üblicherweise zwischen zehn Sekunden und wenigen Minuten.
  • Anders als bei den unsicheren Unterschriften aus der echten Welt leiten sich kryptografische Signaturen auch vom signierten Inhalt ab. Würde jemand in einem JWT den claim ändern oder die Lebensdauer verlängern, wäre die Signatur nicht mehr gültig.
  • Konkret sehen JWTs so aus: eyJhbGciOiJ.eyJvYyI6e319.GnWtwg6Du, nur in Realität länger. Es gibt drei durch “.”-getrennte Teile, alle Base64-kodiert. Die ersten beiden sind JSON Objekte (Header & Payload), der letzte Teil ist die Signatur.

Von Theorie zu Praxis

Opencast bietet schon seit vielen Jahren JWT-Unterstützung, jedoch wurde diese in der Praxis nur wenig genutzt. Um sie tatsächlich für alle genannten Anwendungsfälle nutzbar zu machen, waren und sind weitere Arbeiten nötig. Zum einen wurde ein Standard geschaffen, der vorschreibt, wie welche claims in der Opencast-Community genutzt werden sollen. Das Opencast-Feature "Magic roles" ist für weitere Implementierungen ebenfalls sehr hilfreich.

Zwei wichtige Dinge fehlen aber noch.

Opencast: JWT fürs statische Dateien ausliefern

Die JWT-Funktionen in Opencast erlauben es theoretisch, auch statische Dateien (Videos, Bilder, …) für JWT-autorisierte Anfragen auszuliefern. Jedoch gibt es dabei Probleme. Insbesondere Opencast ist zurzeit so strukturiert, dass autorisierte Anfragen immer auch Nutzer-Informationen (wie Nutzername, E-Mail, …) erwarten. Das ist bei JWTs aber nicht unbedingt der Fall, z.B. wenn nur der claim "darf Video 123 sehen" enthalten ist.

Natürlich ließe sich Opencast verändern, um diese Einschränkung aufzuheben. Das ist auch weiterhin geplant, aber zuerst wurde ein alternativer Ansatz gewählt und umgesetzt: ein seperater Dienst, der auf dem gleichen Server wie Opencast läuft und sich nur um Anfragen nach statischen Dateien kümmert. So wurde das Projekt "octoka" geboren.

Diese Herangehensweise hat mehrere Vorteile:

  • octoka kann weiterlaufen, wenn Opencast gecrashed ist oder geupdated wird. So können weiterhin statische Dateien mit korrekter Authorisierung ausgeliefert werden, sodass externe Dienste wie z.B. Tobira weiterhin funktionieren.
  • Es ist ein Schritt Richtung "dumb delivery", was bessere Skalierbarkeit und Verfügbarkeit als Vorteil hat.
  • octoka ist deutlich schneller & effizienter als Opencast.
  • Und zuletzt: die Umsetzung war vermutlich schneller, als die Änderungen in Opencast umzusetzen.

Die initiale Implementierung habe ich erst vor kurzem abgeschlossen und jetzt kann octoka durch die Community evaluiert werden. Es ist zu erwarten, dass es in naher Zukunft weiter verbessert wird, sich "best practices" entwickeln und es testweise auf diversen Servern installiert wird.

Externe Apps: JWTs an Anfragen anhängen

Die zweite große Baustelle sind die externen Apps (LMS, Tobira, ...) selber. Diese müssen erstmal eine Möglichkeit haben, JWTs zu erzeugen, zu signieren und ihren öffentlichen Schlüssel frei zugänglich zu machen.

Das Hauptproblem ist jedoch, JWTs an alle Opencast-Anfragen anzuhängen. Man könnte erstmal auf die Idee kommen, einfach an alle Bild- und Video-URLs einen JWT anzuhängen, bevor diese an den Browser des Users geschickt werden. Aber als Erinnerung: Ziel ist es, die Lebensdauer von JWTs möglichst gering zu halten, z.B. 30s. Wenn JWTs aber nur beim Laden der LMS/Tobira Seite erzeugt werden, führt das zu Problemen, wenn die Dateien erst später angefragt werden. Beispielsweise wird ein Video erst heruntergeladen, wenn der Nutzende auf "Play" klickt. Oder Bilder werden erst geladen, wenn sie nahe des Scrollbereichs sind; und es werden nur Teile des Videos heruntergeladen, kurz bevor diese tatsächlich angezeigt werden.

Durch diese Effekte kann die Opencast-Anfrage teilweise deutlich nach der JWT-Erzeugung passieren. Aber dann ist der JWT schon abgelaufen und Opencast akzeptiert diesen nicht.

Es muss also so gelöst werden, dass der JWT unmittelbar vor der Nutzung erzeugt wird. Das ist jedoch aufwändig, technisch teilweise sehr herausfordernd und würde Unterstützung vom Paella player benötigen. Entsprechend habe ich mich auf die Suche nach einer besseren Lösung begeben und testweise in Tobira implementiert.

Web Workers

Browser bieten seit diversen Jahren die Funktion "Web Workers" an. Das erlaubt, alle Anfragen, die von einer Seite gesendet werden, zu inspizieren und zu verändern. Hauptsächlich wird das für Offline-Funktionalität genutzt, aber es kann auch für unseren Anwendungsfall genutzt werden, indem automatisch JWTs an Opencast-Anfragen angefügt werden.

Dies wäre eine zentrale Lösung, die man als Software-Bibliothek veröffentlichen und dann leicht in unterschiedlichen Applikationen einbinden kann. Außerdem erlaubt es, anders als bei anderen Lösungen, den JWT als HTTP-Header statt als Query-Parameter in der URL zu schicken. Das erlaubt es dem Browser, Dateien zu cachen, also vorzuhalten, um erneutes Herunterladen zu vermeiden.

Dieser Ansatz bietet zwar eine Reihe von Vorteilen und wurde auch schon in Tobira erfolgreich implementiert und getestet, muss jedoch in Ruhe evaluiert werden, da noch viele offene Fragen existieren. Gibt es z.B. Nutzende, die Web Worker im Browser deaktiviert haben? Darüber hinaus stellen sich diverse Fragen zu technischen Feinheiten. Es ist geplant, in naher Zukunft den Code als Bibliothek zu veröffentlichen.

Weitere Arbeiten

Neben den beschriebenen aktuellen Entwicklungen und nächsten Schritten gibt es noch viele weitere Überlegungen, Aufgaben und Abwägungen. In der Opencast-LMS Community wird gerade überlegt, wie man in der Zukunft den Paella player einbinden würde – wovon auch abhängt, wie JWTs integriert werden. Wenn Paella beispielsweise immer als iframe eingebunden wird, sind web workers für LMS möglicherweise nicht nötig, dafür muss aber eine Lösung für iframes gefunden werden. Der "Tool usecase", also wenn eine externe App den Nutzenden zu Opencast Studio oder andere Tools weiterleiten möchte, benötigt auch weitere Arbeiten.

Um den aktuellen Stand der Entwicklungen zu verfolgen, kann diese GitHub Diskussion genutzt werden. Abschließend lässt sich aber sagen, dass wir auf einem guten Weg sind, in absehbarer Zeit statische Dateien mit JWTs schützen zu können.

Porträt Lukas
Autor: Lukas Kalbertodt