Elektronischer Semesterapparat¶
Einleitung¶
Übersicht¶
Für die transparente Anmeldung in den elektronischen Semesterapparat (ESA) des Visual Library Servers (VLS) ist das hier beschriebene Protokoll vorgesehen.
Prozess¶
Dem im Fremdportal angemeldeten Dozenten <Dozent> wird dort ein Hyperlink angeboten, über den er den ESA der VLS erreichen kann. Dieser Hyperlink enthält eine zeitlich begrenzt gültige und digital signierte Berechtigung, sich bei der VLS-Instanz anzumelden.
Der Hyperlink kann eventuell auch für den Dozenten transparent zum Beispiel innerhalb eines Inlineframes aufgelöst werden.
Anmeldeverfahren¶
Die Anmeldung des Dozenten für einen Kursraum in einer VLS-Instanz
vls.example.com
erfolgt direkt über eine speziell formatierte URL:
http://vls.example.com/order/start?uct=eJytUstu00AUXSEWLPgBkKxZgRRcjx-[...mehr...]
Die URL besteht aus einem statischen Teil und einem dynamischen Teil.
Der statische Teil umfasst den Hostnamen der VLS-Instanz und die Route
order/start
. Der dynamische Teil umfasst den GET
Parameter uct
(Untrusted Client Transport), dessen Wert ein mehrfach kodierter
Datensatz ist.
Der Name „Untrusted Client Transport“ weist darauf hin, dass die Anmeldedaten über einen Benutzer transportiert werden können, dem nicht vertraut werden muss. Technische Maßnahmen sichern das Verfahren dahingehend ab, dass die Anmeldung nur für diesen Dozenten und Kursraum für eine begrenzte Zeit möglich ist.
Konfiguration¶
In der Domain-Konfiguration der VLS-Instanz sind im Abschnitt [moodle]
folgende Einstellungen verfügbar:
passphrase
(Zwingend erforderlich)Pre-shared Key (PSK), der auch im Fremdportal hinterlegt ist, und zur Erzeugung der digitalen Signatur in der Sicherheitsschicht des Protokolls verwendet wird.
Der PSK muss im ASCII Format kodiert sein und darf nur druckbare Zeichen sowie Leerzeichen enthalten (
0x20-0x7e
).hashname
(Optional, voreingestellt:sha256
)Name des Hash-Algorithmus, der zur Erzeugung der digitalen Signatur verwendet wird. Die folgenden Namen sind möglich (entsprechend dem Python-Modul
hashlib
):md5
(aus Sicherheitsgründen nicht empfohlen)sha1
(aus Sicherheitsgründen nicht empfohlen)sha224
sha256
(Voreinstellung)sha384
sha512
Empfohlen ist die Voreinstellung
sha256
. Da der verwendete Hash-Algorithmus nicht mit übertragen wird, muss in der Domain-Konfiguration und im Fremdportal der gleiche Hash-Algorithmus fest eingestellt werden.
Nutzdatenschicht¶
Die Nutzdaten werden vom Fremdportal erzeugt und dann im JSON-Format serialisiert. Die zu verwendende Kodierung ist UTF-8.
Das Format der Nutzdaten ist ausführlich im Abschnitt „signindata“ beschrieben.
Sicherheitsschicht¶
In der Sicherheitsschicht wird dem Datensatz eine digitale Signature angefügt. Um eine aufwändige Public-Key Infrastruktur zu vermeiden, wird diese nach dem HMAC Verfahren aus dem PSK und dem Nutzdatensatz erzeugt. Das verwendete Hash-Verfahren ist konfigurierbar, die empfohlene Voreinstellung ist SHA-256.
Der HMAC-Digest wird im Binärformat ohne Trennzeichen an den Nutzdatensatz angefügt. Da die Länge des Digest durch den Hash-Algorithmus festgelegt ist, kann dieser auf der Empfängerseite wieder eindeutig abgetrennt werden.
Kompressionsschicht¶
In der Kompressionsschicht wird der signierte Datensatz mit dem ZLIB Verfahren komprimiert.
Transportschicht¶
Der komprimierte Datensatz wird Base64-kodiert. Als Alphabet wird,
abweichend von der üblichen Praxis, das Zeichen -
(Minus) anstelle von
+
(Plus) und _
(Unterstrich) anstelle von /
(Schrägstrich)
verwendet. Diese Konvention erlaubt es, den Datensatz ohne weitere
Verarbeitung in die URL einzufügen.
Anmeldedaten¶
In diesem Abschnitt werden die zu übertragenden Nutzdaten bei der Anmeldung beschrieben.
Die Nutzdaten sind ein Objekt mit folgenden Einträgen:
time
(number, erforderlich)Der Zeitstempel der Anmeldung in Sekunden seit Mitternacht am 1. 1. 1970 (UNIX epoch) für UTC (Coordinated Universal Time, auch bekannt als Greenwich Mean Time, GMT).
Beispiel:
"time": 1384349644
Hinweis
Da die Anmeldedaten nur für eine begrenzte Zeit gültig sind, müssen die Uhren auf dem Fremdportal und der VLS-Instanz synchronisiert sein. Eine Angabe der Zeit in localtime ist nicht zulässig und führt zu einem Datenpaket, das in der Vergangenheit gültig war oder erst in der Zukunft gültig sein wird.
token_uid
(string, optional)Eine eindeutige Token-ID des Fremdportals für dieses UCT-Paket. Wird vom VLS ESA ignoriert.
user
(object, erforderlich)Der Dozent, für den die Anmeldung erfolgen soll. Dozenten sind ihrerseits Objekte, deren Nutzdaten weiter unten erklärt sind.
course
(object, erforderlich)Der Kursraum, für den die Anmeldung erfolgen soll. Kursräume sind ihrerseits Objekte, deren Nutzdaten weiter unten erklärt sind.
categories
(object, optional)Kategorien, unter denen der Kursraum abgelegt ist. Kategorien sind ihrerseits Objekte, deren Nutzdaten weiter unten erklärt sind.
Hinweis
Kategorien sind eine optionale Erweiterung. Wird keine Kategorie
im Kursraum referenziert, kann das categories
Objekt
vollständig entfallen.
server
(object, optional)Das Fremdportal, welches die Anmeldung durchführt. Server sind ihrerseits Objekte, deren Nutzdaten weiter unten erklärt sind.
Hinweis
Die Serverdaten sind nicht in jedem Fall erforderlich. Werden
keine Serverdaten übertragen, kann das server
Objekt
vollständig entfallen.
Dozentendaten¶
Ein Benutzer-Objekt (user
) hat folgende Einträge:
id
(number, erforderlich)Eine eindeutige Kenn-Nummer für diesen Dozenten.
0
ist reserviert und keine gültige Kenn-Nummer.Beispiel:
"id": 45
username
(string, erforderlich)Die Benutzerkennung des Dozenten (kodiert in UTF-8).
Beispiel:
"username": "rfeynman"
firstname
(string, erforderlich)Der Vorname des Dozenten.
Beispiel:
"firstname": "Richard"
lastname
(string, erforderlich)Der Nachname des Dozenten.
Beispiel:
"lastname": "Feynman"
email
(string, erforderlich)Die Email-Adresse des Dozenten.
Beispiel:
"email": "rf@caltech.example.com"
timemodified
(number, optional)Der Zeitstempel (in Sekunden seit Mitternacht am 1. 1. 1970, UTC) der letzten Änderung an den Kursraumdaten. Wenn der Zeitstempel gegeben ist, wird der Kursraum-Datensatz im VLS ESA nur aktualisiert, wenn die dortige Version älter ist als
timemodified
.Beispiel:
"timemodified": 1384328462
Kursraumdaten¶
Ein Kursraum-Objekt (course
) hat folgende Einträge:
id
(number, erforderlich)Eine eindeutige Kenn-Nummer für diesen Kursraum.
0
ist reserviert und keine gültige Kenn-Nummer.Beispiel:
"id": 123
fullname
(string, erforderlich)Der vollständige Name des Kursraums (kodiert in UTF-8).
Beispiel:
"fullname": "Lectures on Physics, Part I"
shortname
(string, optional)Der Kurz-Name des Kursraums (kodiert in UTF-8). Die Voreinstellung ist
fullname
.Beispiel:
"shortname": "Physics I"
term
(string, erforderlich für alle außer Moodle)Eine Kennzeichnung für das Semester für diesen Kursraum. Die Kennzeichnung ist:
WS<JJ>
für das WintersemesterSS<JJ>
für das Sommersemester
Hierbei ist
<JJ>
die 2-stellige Jahresangabe.Beispiel:
"term": "SS61"
Hinweis
Für Moodle wird stattdessen das Feld idnumber
verwendet.
url
(string, optional)Rücksprungadresse für den Kursraum im Fremdportal. Diese sollte eine vollständige URL sein, welche dem Dozenten in einem Link zur Verfügung gestellt werden kann.
Beispiel:
"url": "https://caltech.example.com:8080/course/123"
Hinweis
Fehlt das Feld, so wird eine Rücksprungadresse aus den Serverdaten
ermittelt, falls vorhanden. Die Angabe über das Feld course.url
ist aber empfohlen.
timemodified
(number, optional)Der Zeitstempel (in Sekunden seit Mitternacht am 1. 1. 1970, UTC) der letzten Änderung an den Kursraumdaten. Wenn der Zeitstempel gegeben ist, wird der Kursraum-Datensatz im VLS ESA nur aktualisiert, wenn die dortige Version älter ist als
timemodified
.Beispiel:
"timemodified": 1384328462
category
(number, optional)Die Kenn-Nummer der Kategorie für diesen Kursraum. Wird keine Kategorie angegeben, so werden alle Kurse eines Semesters in einer automatische erzeugten Kategorie gesammelt.
Beispiel:
"category": 5
sortorder
(number, optional)Eine Ordnungsnummer zur Sortierung der Kursräume.
idnumber
(string, optional)Dieses Feld ist für die Anbindung an Moodle reserviert, und darf nicht von anderen Fremdportalen verwendet werden.
Beispiel:
"idnumber": "LecPhys_SS61_01"
Kategoriendaten¶
Ein Kategorien-Objekt (categories
) hat folgende Einträge (<ID>
ist
ein Platzhalter für eine beliebige Kenn-Nummer):
<ID>
(object)Das Kategorie-Objekt mit der Kenn-Nummer
<ID>
. Jede Kategorie ist seinerseits ein Objekt, deren Nutzdaten weiter unten erklärt sind.Beispiel:
"5" : { "id": 5, [...mehr...] }
Im Kategorien-Objekt muss ein Kategorie-Objekt für die Kategorie des
Kursraum (course.category
), sowie je eins für alle Elternkategorien
(<ID>.parent
) bis zur Wurzelkategorie (<ID>.parent: 0
) enthalten
sein.
Beispiel:
"categories": {
"5" : { "id": 5, "parent": 3, [...mehr...] },
"3" : { "id": 3, "parent": 0, [...mehr...] }
}
Hinweis
Kategoriedaten sind nur dann erforderlich, wenn course.category
angegeben wird. In dem Fall müssen allerdings alle Kategorien bis zur
Wurzel-Kategorie in den Nutzdaten enthalten sein.
Kategorie¶
Ein Kategorie-Objekt hat folgende Einträge:
id
(number, erforderlich)Eine eindeutige Kenn-Nummer für diese Kategorie.
0
ist reserviert und keine gültige Kenn-Nummer.Beispiel:
"id": 5
parent
(number), erforderlich)Die Kenn-Nummer des übergeordneten Kategorie-Objekts. Handelt es sich bei dieser Kategorie um eine Wurzelkategorie, so ist
parent: 0
zu setzen.Beispiel:
"parent": 3
name
(string, erforderlich)Der Name der Kategorie.
sortorder
(number, optional)Eine Ordnungsnummer zur Sortierung der Kategorien.
timemodified
(number, optional)Der Zeitstempel (in Sekunden seit Mitternacht am 1. 1. 1970 für UTC) der letzten Änderung an den Kategoriedaten. Wenn der Zeitstempel gegeben ist, wird der Kategorie-Datensatz im VLS ESA nur aktualisiert, wenn die dortige Version älter ist als
timemodified
.Beispiel:
"timemodified": 1384328462
Serverdaten¶
Ein Server-Objekt (server
) hat folgende Einträge:
Rücksprungadresse¶
Die Serverdaten dieses Abschnitts werden nur dann verwendet, wenn keine
Rücksprungaddresse unter course.url
angegeben wird. In dem Fall kann
die Rücksprungadresse aus den folgenden Serverdaten gewonnen werden.
Hinweis
Die folgenden Einträge sind als Gruppe optional. Dies bedeutet, dass entweder kein Eintrag oder alle Einträge vorhanden sein müssen.
HTTPS
(boolean)Wahr, wenn die Anmeldedaten über eine HTTPS-Verbindung bereitgestellt wurden. Ansonsten falsch.
REQUEST_URI
(string)Der (absolute) URL-Pfad, für welche die Anmeldedaten bereitgestellt wurden. Diese kann (zusammen mit den anderen Daten) verwendet werden, um vom VLS ESA zurück in das Fremdportal zu navigieren.
Beispiel:
"REQUEST_URI": "/esa/portal.php?id=456"
SERVER_ADDR
(string)Die IP-Adresse des Fremdportals.
Beispiel:
"SERVER_ADDR": "192.168.123.45"
SERVER_NAME
(string)Der Host-Name des Fremdportals.
Beispiel:
"SERVER_ADDR": "moodle.example.com"
SERVER_PORT
(number)Die Port-Nummer des Fremdportals.
Beispiel:
"SERVER_PORT": 80
Beispiele¶
Anmeldungsdaten¶
Minimale Nutzdaten zur Dozentenanmeldung an einen Kursraum in VLS:
{
"time": 1384349644,
"user": {
"id": 45,
"username": "rfeynman",
"firstname": "Richard",
"lastname": "Feynman"
"email": "rf@caltech.example.com",
},
"course": {
"id": 123,
"fullname": "Lectures on Physics, Part I",
"term": "SS61",
"url": "https://caltech.example.com:8080/course/123"
}
}
Python-Programm zur Übersetzung der Nutzdaten in das UCT-Format:
import json, hashlib, hmac, zlib, base64
def data2uct(data, passphrase, hashname="sha256"):
# Nutzdatenschicht
data = json.dumps(data)
# Sicherheitsschicht
hash_factory = lambda: hashlib.new(hashname)
sig = hmac.HMAC(passphrase, data, hash_factory).digest()
data = data + sig
# Kompressionsschicht
data = zlib.compress(data)
# Transportschicht
return base64.b64encode(data, "-_")
Python-Programm zur Überprüfung des UCT-Format und zur Extraktion der Nutzdaten:
import json, hashlib, hmac, zlib, base64
def uct2data(uct, passphrase, hashname="sha256"):
# Transportschicht
data = base64.b64decode(uct, "-_")
# Kompressionsschicht
data = zlib.decompress(data)
# Sicherheitsschicht
hash_factory = lambda: hashlib.new(hashname)
sig_len = hash_factory().digest_size
data, orig_sig = data[:-sig_len], data[-sig_len:]
# Validierung
sig = hmac.HMAC(passphrase, data, hash_factory).digest()
if sig != orig_sig:
raise ValueError("invalid signature")
# Nutzdatenschicht
return json.loads(data)
Quellen und externe Links¶
- ZLIB Compressed Data Format Specification version 3.3
- DEFLATE Compressed Data Format Specification version 1.3
- HMAC: Keyed-Hashing for Message Authentication
- The application/json Media Type for JavaScript Object Notation (JSON)
- The Base16, Base32, and Base64 Data Encodings