diff --git a/README-mobile-oidc-bridge-readme.docx b/README-mobile-oidc-bridge-readme.docx new file mode 100644 index 0000000..d18c6ba Binary files /dev/null and b/README-mobile-oidc-bridge-readme.docx differ diff --git a/README-mobile-oidc-bridge-readme.md b/README-mobile-oidc-bridge-readme.md new file mode 100644 index 0000000..99a2ada --- /dev/null +++ b/README-mobile-oidc-bridge-readme.md @@ -0,0 +1,691 @@ +# Mattermost OIDC Mobile Bridge + +## Zweck + +Diese Dokumentation beschreibt die Installation und Konfiguration der `mobile-bridge` aus dem Projekt `mattermost-oidc` für eine native Mattermost-Mobile-App. + +Die Bridge wird benötigt, wenn Mattermost für die Anmeldung das Plugin `mattermost-oidc` verwendet, die native Mobile-App aber den eingebauten Mattermost-OpenID-Endpunkt erwartet. Die Bridge verändert Mattermost selbst nicht. Sie fängt nur zwei HTTP-Endpunkte ab: + +- `/api/v4/config/client` +- `/oauth/openid/mobile_login` + +Für die native Mattermost-App wird in der Client-Konfiguration `EnableSignUpWithOpenId=true` signalisiert. Der Mobile-Login wird anschließend zum `mattermost-oidc`-Plugin umgeleitet. + +Web- und Desktop-Clients bleiben unverändert. + +## Versions- und Umgebungsvariablen + +Die Anleitung ist bewusst versionsunabhängig aufgebaut. Vor Beginn werden die für die jeweilige Installation gültigen Versionen, URLs und Pfade einmal in der aktuellen Root-Shell gesetzt. Die nachfolgenden Befehle verwenden diese Variablen. + +```bash +export MM_VER="11.7.11" +export MM_OIDC_VER="0.6.1" +export MM_SITE_URL="https://mm.nd.digital" + +export MM_SRC_BASE="/usr/local/src/mattermost-oidc" +export MM_OIDC_REPO="https://github.com/server-camp/mattermost-oidc-plugin.git" +export MM_OIDC_SRC="${MM_SRC_BASE}/mattermost-oidc-plugin-${MM_OIDC_VER}" + +export MM_UPSTREAM="http://127.0.0.1:8065" +export MM_BRIDGE_LISTEN="127.0.0.1:8066" + +export MM_BRIDGE_BIN_DIR="/usr/local/sbin" +export MM_BRIDGE_BIN="${MM_BRIDGE_BIN_DIR}/mattermost-oidc-mobile-bridge-${MM_OIDC_VER}" +export MM_BRIDGE_LINK="${MM_BRIDGE_BIN_DIR}/mattermost-oidc-mobile-bridge" +``` + +`MM_VER` dokumentiert die aktuell eingesetzte Mattermost-Version. Für Download und Build der Bridge ist insbesondere `MM_OIDC_VER` relevant. Bei einer späteren Aktualisierung wird die gewünschte Version im Variablenblock geändert und der Ablauf mit dem neuen Release wiederholt. + +Die hier beschriebene Installation wurde mit den oben beispielhaft eingetragenen Versionen getestet. Weitere Rahmenbedingungen waren Debian 13, nginx als Reverse Proxy, Mattermost auf `127.0.0.1:8065`, die Mobile Bridge auf `127.0.0.1:8066` und Keycloak als OIDC-Provider. + +Die Bridge benötigt **kein eigenes OIDC-Client-Secret**. Client-ID, Client-Secret und Kommunikation mit dem OIDC-Provider bleiben Aufgabe des `mattermost-oidc`-Plugins. + +## Funktionsweise + +Der relevante Ablauf ist: + +```text +Mattermost Mobile App + | + | GET /api/v4/config/client + v + nginx + | + +--> mobile-bridge :8066 + | + +--> Mattermost :8065 + | + +--> bei Mobile User-Agent: + EnableSignUpWithOpenId=true + +Mobile App + | + | /oauth/openid/mobile_login?redirect_to=mmauth://callback + v + nginx + | + +--> mobile-bridge :8066 + | + +--> 302 /plugins/mattermost-oidc/oauth2/connect + ?mobile_redirect=mmauth://callback + | + v + Keycloak + | + v + /plugins/mattermost-oidc/oauth2/callback + | + v + mmauth://callback + | + v + Mattermost App +``` + +Alle anderen Requests, insbesondere REST, WebSocket, Dateien und `/plugins/...`, gehen weiterhin direkt an Mattermost. + +## Voraussetzungen + +Vor Installation der Bridge müssen folgende Bedingungen erfüllt sein: + +1. Das Plugin `mattermost-oidc` ist installiert und aktiviert. +2. Der normale OIDC-Web-Login funktioniert bereits vollständig. +3. Der OIDC-Provider ist korrekt eingerichtet. +4. Die bestehende Redirect-URI des Plugins funktioniert: + `/plugins/mattermost-oidc/oauth2/callback` +5. nginx leitet die normale Mattermost-Site bereits auf `127.0.0.1:8065` weiter. +6. Go ist zum Bauen der Bridge verfügbar. + +Die benötigte Go-Version ist nicht in dieser Anleitung fest verdrahtet. Nach dem Download wird sie direkt aus `mobile-bridge/go.mod` abgelesen. Falls die Debian-Standardversion nicht ausreicht, kann eine passende Go-Version beispielsweise aus den Debian-Backports verwendet werden. + +## 1. Quellcode herunterladen + +Das Repository wird versionsbezogen unter `MM_SRC_BASE` abgelegt. Dadurch können mehrere Release-Stände parallel vorhanden sein und die Herkunft einer installierten Binary bleibt nachvollziehbar. + +Arbeitsverzeichnis anlegen: + +```bash +mkdir -p "$MM_SRC_BASE" +``` + +Gewünschten Release-Tag direkt in ein versionsbezogenes Verzeichnis klonen: + +```bash +git clone --branch "v${MM_OIDC_VER}" --depth 1 \ + "$MM_OIDC_REPO" \ + "$MM_OIDC_SRC" +``` + +Ausgecheckten Stand kontrollieren: + +```bash +cd "$MM_OIDC_SRC" +git status +git describe --tags --exact-match +``` + +Bei einem direkt ausgecheckten Release-Tag ist ein `detached HEAD` normal. `git describe --tags --exact-match` sollte `v${MM_OIDC_VER}` ausgeben. + +Die Mobile Bridge befindet sich anschließend unter: + +```text +${MM_OIDC_SRC}/mobile-bridge +``` + +## 2. Go installieren + +Benötigte Go-Version aus dem Release ermitteln: + +```bash +awk '/^go / {print "benötigte Go-Version:", $2}' \ + "$MM_OIDC_SRC/mobile-bridge/go.mod" +``` + +Installierte Version prüfen: + +```bash +go version +``` + +Falls die vorhandene Go-Version nicht ausreicht, eine passende Version installieren. Unter Debian 13 kann - sofern `trixie-backports` bereits konfiguriert ist - beispielsweise verwendet werden: + +```bash +apt install -t trixie-backports golang-go +``` + +Danach erneut prüfen: + +```bash +go version +``` + +## 3. Mobile Bridge bauen + +In das Bridge-Verzeichnis wechseln: + +```bash +cd "$MM_OIDC_SRC/mobile-bridge" +``` + +Binary bauen: + +```bash +go build -o mobile-bridge . +``` + +Ergebnis kontrollieren: + +```bash +file mobile-bridge +ls -lh mobile-bridge +``` + +## 4. Bridge vor der Installation manuell testen + +Port 8066 sollte zunächst frei sein: + +```bash +ss -lntp | grep ':8066' +``` + +Die Bridge testweise nur auf Loopback starten: + +```bash +LISTEN="$MM_BRIDGE_LISTEN" UPSTREAM="$MM_UPSTREAM" ./mobile-bridge +``` + +Die Bindung an `127.0.0.1` ist beabsichtigt. Die Bridge muss nicht direkt aus dem Internet erreichbar sein; nginx ist der öffentliche Einstiegspunkt. + +### Mobile Client-Konfiguration testen + +In einem zweiten Terminal: + +```bash +curl -s -A 'Mattermost Mobile/' \ + http://127.0.0.1:8066/api/v4/config/client | + grep -o '"EnableSignUpWithOpenId":"[^"]*"' +``` + +Erwartet: + +```text +"EnableSignUpWithOpenId":"true" +``` + +Mit einem Browser-User-Agent: + +```bash +curl -s -A 'Mozilla/5.0' \ + http://127.0.0.1:8066/api/v4/config/client | + grep -o '"EnableSignUpWithOpenId":"[^"]*"' +``` + +Bei der dokumentierten Konfiguration war das Ergebnis: + +```text +"EnableSignUpWithOpenId":"false" +``` + +Damit ist sichergestellt, dass die Änderung nur für die Mobile-App erfolgt. + +### Mobile-Login-Redirect testen + +```bash +curl -si \ + 'http://127.0.0.1:8066/oauth/openid/mobile_login?redirect_to=mmauth%3A%2F%2Fcallback' | + head -20 +``` + +Erwartet wird HTTP 302 mit einem `Location`-Header in Richtung: + +```text +/plugins/mattermost-oidc/oauth2/connect?mobile_redirect=mmauth%3A%2F%2Fcallback +``` + +Danach den manuellen Prozess mit `Ctrl-C` beenden. + +## 5. Binary versionsbezogen installieren + +Die gebaute Bridge wird mit ihrer Plugin-/Bridge-Version im Dateinamen unter `/usr/local/sbin` installiert. Ein stabiler Symlink ohne Versionsnummer zeigt auf die aktuell aktive Binary. Dadurch kann ein Update oder Rollback durch Umschalten des Symlinks erfolgen, während die systemd-Unit unverändert bleibt. + +Binary installieren: + +```bash +install -o root -g root -m 755 \ + mobile-bridge \ + "$MM_BRIDGE_BIN" +``` + +Stabilen Symlink auf diese Version setzen: + +```bash +ln -sfn "$(basename "$MM_BRIDGE_BIN")" "$MM_BRIDGE_LINK" +``` + +Ergebnis kontrollieren: + +```bash +ls -l "$MM_BRIDGE_BIN" "$MM_BRIDGE_LINK" +readlink -f "$MM_BRIDGE_LINK" +``` + +Beispiel für Version `0.6.1`: + +```text +/usr/local/sbin/mattermost-oidc-mobile-bridge-0.6.1 +/usr/local/sbin/mattermost-oidc-mobile-bridge -> mattermost-oidc-mobile-bridge-0.6.1 +``` + +## 6. systemd-Service einrichten + +Datei anlegen: + +```text +/etc/systemd/system/mattermost-oidc-mobile-bridge.service +``` + +Inhalt: + +```ini +[Unit] +Description=Mattermost OIDC Mobile Bridge +After=network.target mattermost.service +Requires=mattermost.service + +[Service] +Type=simple +User=mattermost +Group=mattermost +Environment=LISTEN=127.0.0.1:8066 +Environment=UPSTREAM=http://127.0.0.1:8065 +ExecStart=/usr/local/sbin/mattermost-oidc-mobile-bridge +Restart=on-failure +RestartSec=5s + +[Install] +WantedBy=multi-user.target +``` + +`ExecStart` verweist bewusst auf den versionsunabhängigen Symlink. Bei einem Update muss die Unit-Datei deshalb nicht geändert werden. + +Konfiguration laden und prüfen: + +```bash +systemctl daemon-reload +systemd-analyze verify /etc/systemd/system/mattermost-oidc-mobile-bridge.service +``` + +Dienst zunächst nur starten: + +```bash +systemctl start mattermost-oidc-mobile-bridge.service +``` + +Status prüfen: + +```bash +systemctl status mattermost-oidc-mobile-bridge.service +ss -lntp | grep ':8066' +``` + +Erwartet wird ein Listener ausschließlich auf: + +```text +127.0.0.1:8066 +``` + +Nach erfolgreichem End-to-End-Test den Autostart aktivieren: + +```bash +systemctl enable mattermost-oidc-mobile-bridge.service +``` + +Kontrolle: + +```bash +systemctl is-enabled mattermost-oidc-mobile-bridge.service +systemctl is-active mattermost-oidc-mobile-bridge.service +``` + +Erwartet: + +```text +enabled +active +``` + +## 7. nginx konfigurieren + +In der dokumentierten Installation ist die aktive Konfiguration: + +```text +/etc/nginx/sites-available/mm.nd.digital.conf +``` + +mit Symlink unter `sites-enabled`. + +Vor der Änderung ein Backup der realen Datei anlegen, nicht nur des Symlinks. + +Vor den allgemeinen Mattermost-`location`-Blöcken werden zwei Exact-Match-Locations eingefügt: + +```nginx +# Mattermost OIDC Mobile Bridge +location = /api/v4/config/client { + proxy_set_header Host $host; + proxy_set_header X-Real-IP $remote_addr; + proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for; + proxy_set_header X-Forwarded-Proto $scheme; + proxy_pass http://127.0.0.1:8066; +} + +location = /oauth/openid/mobile_login { + proxy_set_header Host $host; + proxy_set_header X-Real-IP $remote_addr; + proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for; + proxy_set_header X-Forwarded-Proto $scheme; + proxy_pass http://127.0.0.1:8066; +} +``` + +Die vorhandenen WebSocket- und Catch-all-Locations bleiben unverändert und zeigen weiterhin direkt auf Mattermost. + +Die Exact-Match-Locations sind wichtig: Nur diese beiden Endpunkte sollen über die Bridge laufen. + +Konfiguration prüfen: + +```bash +nginx -t +``` + +Bei erfolgreicher Prüfung: + +```bash +systemctl reload nginx +``` + +## 8. Öffentliche Endpunkte testen + +### Mobile User-Agent + +```bash +curl -s -A 'Mattermost Mobile/' \ + ${MM_SITE_URL}/api/v4/config/client | + grep -o '"EnableSignUpWithOpenId":"[^"]*"' +``` + +Erwartet: + +```text +"EnableSignUpWithOpenId":"true" +``` + +### Browser User-Agent + +```bash +curl -s -A 'Mozilla/5.0' \ + ${MM_SITE_URL}/api/v4/config/client | + grep -o '"EnableSignUpWithOpenId":"[^"]*"' +``` + +Bei der dokumentierten Installation: + +```text +"EnableSignUpWithOpenId":"false" +``` + +### Mobile Login + +```bash +curl -si \ + "${MM_SITE_URL}/oauth/openid/mobile_login?redirect_to=mmauth%3A%2F%2Fcallback" | + head -20 +``` + +Erwartet wird HTTP 302 auf den Connect-Endpunkt des OIDC-Plugins. + +## 9. End-to-End-Test mit der Mattermost-App + +In der nativen Mattermost-App: + +1. Server aus `MM_SITE_URL` hinzufügen (im dokumentierten Beispiel `https://mm.nd.digital`). +2. Die App muss zusätzlich zur normalen Anmeldung einen Button **Log in with OIDC** anzeigen. +3. OIDC-Login auswählen. +4. Bei Keycloak anmelden. +5. Nach erfolgreicher Authentifizierung muss die App über `mmauth://callback` zurückkehren. +6. Team und Channels müssen anschließend geladen werden. + +## 10. Wichtiger Sonderfall: Default Team und erlaubte E-Mail-Domains + +Das `mattermost-oidc`-Plugin kann neu angelegte OIDC-Benutzer automatisch einem **Default Team** hinzufügen. + +In der dokumentierten Installation ist im Plugin konfiguriert: + +```text +Default Team: nd +``` + +Das Team `nd` erlaubt jedoch nur Benutzer mit einer bestimmten E-Mail-Domain: + +```text +nd-online.de +``` + +Beim Test wurde ein OIDC-Benutzer mit einer anderen Domain erfolgreich angelegt und authentifiziert, konnte aber nicht automatisch dem Team `nd` hinzugefügt werden. Mattermost protokollierte sinngemäß: + +```text +Failed to add user to default team +The user cannot be added as the domain associated with the account is not permitted. +``` + +Das Fehlerbild in der Mobile-App war: + +```text +Konnte nicht geladen werden +``` + +Das Profil des angemeldeten Benutzers war trotzdem erreichbar. Ursache war **nicht die Mobile Bridge und nicht der OIDC-Token**, sondern die fehlende Team-Mitgliedschaft. + +### Diagnose + +Team-Domain aus PostgreSQL nur lesend prüfen: + +```bash +su - postgres -c \ + "psql -d mattermost -c \"SELECT name, displayname, type, allowopeninvite, alloweddomains FROM teams WHERE name='nd';\"" +``` + +Alternativ in der System Console: + +```text +User Management + -> Teams + -> ND + -> Team Management + -> Only specific email domains can join this team +``` + +Wenn ein Testbenutzer aus einer anderen Domain verwendet wird, sollte die Domain-Beschränkung **nicht dauerhaft aufgeweicht** werden. + +Für den dokumentierten Test wurde die zusätzliche Testdomain kurzzeitig in der kommagetrennten Domainliste zugelassen, der Testbenutzer administrativ zum Team hinzugefügt und die Domainliste anschließend wieder auf den ursprünglichen Wert zurückgesetzt. + +## 11. Logs und Fehlersuche + +### Bridge + +Status: + +```bash +systemctl status mattermost-oidc-mobile-bridge.service +``` + +Journal: + +```bash +journalctl -u mattermost-oidc-mobile-bridge.service +``` + +Für eine gezielte Fehlersuche kann die Bridge mit `DEBUG=1` betrieben werden. Dies sollte nur bei Bedarf aktiviert werden, da dann beobachtete User-Agents protokolliert werden. + +### Mattermost + +```bash +journalctl -u mattermost.service +``` + +Bei OIDC-Problemen insbesondere nach Meldungen mit folgenden Begriffen suchen: + +```text +oidc +mobile +session +mattermost-oidc +``` + +### Typische Fehlerbilder + +**Kein OIDC-Button in der App** + +Prüfen: + +- `mattermost-oidc` ist aktiviert. +- Web-OIDC funktioniert. +- `/api/v4/config/client` wird für Mobile User-Agents über die Bridge geleitet. +- `EnableSignUpWithOpenId` ist für `Mattermost Mobile/` auf `true`. +- nginx wurde nach der Änderung erfolgreich neu geladen. + +**OIDC-Button erscheint, Login startet nicht korrekt** + +Prüfen: + +- `/oauth/openid/mobile_login` liefert HTTP 302. +- Ziel ist `/plugins/mattermost-oidc/oauth2/connect`. +- nginx routet exakt diesen Endpunkt auf Port 8066. + +**Login bei Keycloak erfolgreich, App lädt aber kein Team** + +Prüfen: + +- Wurde der Benutzer in Mattermost angelegt? +- Ist der Benutzer Mitglied eines Teams? +- Ist im OIDC-Plugin ein `Default Team` konfiguriert? +- Verhindert `AllowedDomains` des Teams das automatische Hinzufügen? + +## 12. Umgebungsvariablen der Bridge + +Die Bridge unterstützt laut Projekt-README folgende Variablen: + +| Variable | Standard | Zweck | +|---|---|---| +| `LISTEN` | `:8066` | Listen-Adresse | +| `UPSTREAM` | `http://127.0.0.1:8065` | Mattermost-Upstream | +| `PLUGIN_CONNECT_PATH` | `/plugins/mattermost-oidc/oauth2/connect` | Connect-Endpunkt des Plugins | +| `PLUGIN_CONFIG_PATH` | `/plugins/mattermost-oidc/api/v1/config` | öffentliche Plugin-Konfiguration | +| `MOBILE_UA_MATCH` | `Mattermost Mobile/` | Erkennung der nativen App | +| `OPENID_BUTTON_TEXT` | leer / automatisch | optionaler fester Button-Text | +| `OPENID_BUTTON_COLOR` | leer / automatisch | optionale feste Button-Farbe | +| `DEBUG` | leer | bei `1` User-Agent-Logging | + +In der dokumentierten Installation werden nur `LISTEN` und `UPSTREAM` explizit gesetzt. Die übrigen Werte bleiben auf den Defaults. + +## 13. Update der Bridge + +Für ein Update wird die neue Version zunächst im Variablenblock als `MM_OIDC_VER` gesetzt. `MM_OIDC_SRC` und `MM_BRIDGE_BIN` ergeben sich daraus automatisch. Die bisherige versionsbezogene Binary bleibt zunächst erhalten. + +Beispiel: Variablenblock mit der gewünschten neuen Version erneut setzen und anschließend den Release wie in Abschnitt 1 herunterladen. Danach: + +```bash +cd "$MM_OIDC_SRC/mobile-bridge" +go build -o mobile-bridge . +``` + +Neue versionsbezogene Binary installieren: + +```bash +install -o root -g root -m 755 \ + mobile-bridge \ + "$MM_BRIDGE_BIN" +``` + +Vor dem Umschalten kontrollieren: + +```bash +file "$MM_BRIDGE_BIN" +ls -lh "$MM_BRIDGE_BIN" +``` + +Symlink atomar auf die neue Version umstellen und Dienst neu starten: + +```bash +ln -sfn "$(basename "$MM_BRIDGE_BIN")" "$MM_BRIDGE_LINK" +systemctl restart mattermost-oidc-mobile-bridge.service +systemctl is-active mattermost-oidc-mobile-bridge.service +readlink -f "$MM_BRIDGE_LINK" +``` + +Danach die HTTP-Tests und einen Mobile-Login erneut durchführen. Die alte versionsbezogene Binary sollte erst entfernt werden, wenn der neue Stand erfolgreich getestet wurde. + +## 14. Rollback + +Soll die Bridge wieder entfernt werden: + +1. Die beiden Exact-Match-`location`-Blöcke aus nginx entfernen. +2. `nginx -t` ausführen. +3. nginx neu laden. +4. Bridge stoppen und deaktivieren. +5. Optional Unit-Datei und Binary entfernen. + +### Rollback auf eine vorherige Bridge-Version + +Solange die vorherige versionsbezogene Binary noch vorhanden ist, genügt es, den Symlink zurückzusetzen und den Dienst neu zu starten. Beispiel: + +```bash +ln -sfn mattermost-oidc-mobile-bridge- \ + /usr/local/sbin/mattermost-oidc-mobile-bridge +systemctl restart mattermost-oidc-mobile-bridge.service +readlink -f /usr/local/sbin/mattermost-oidc-mobile-bridge +``` + +### Bridge vollständig entfernen + +```bash +systemctl disable --now mattermost-oidc-mobile-bridge.service +rm -f /etc/systemd/system/mattermost-oidc-mobile-bridge.service +systemctl daemon-reload +rm -f /usr/local/sbin/mattermost-oidc-mobile-bridge +# Versionsbezogene Binaries bei Bedarf anschließend gezielt entfernen. +``` + +Das `mattermost-oidc`-Plugin und der normale Web-OIDC-Login können dabei unverändert weiterbetrieben werden. + +## 15. Sicherheitsaspekte + +- Die Bridge nur auf `127.0.0.1:8066` binden. +- Port 8066 nicht öffentlich in der Firewall freigeben. +- Nur die beiden benötigten Exact-Match-Endpunkte über nginx zur Bridge leiten. +- Keine OIDC-Secrets in die systemd-Unit eintragen; die Bridge benötigt keine. +- Client Secret und andere Zugangsdaten nicht in Dokumentationen oder Logs übernehmen. +- Nach Änderungen an OIDC immer Web- und Mobile-Login testen. +- Team-Domain-Beschränkungen nicht nur für einen Test dauerhaft erweitern. + +## 16. Abschlusskontrolle + +Nach einer vollständigen Installation sollten folgende Prüfungen erfolgreich sein: + +```bash +systemctl is-enabled mattermost-oidc-mobile-bridge.service +systemctl is-active mattermost-oidc-mobile-bridge.service +ss -lntp | grep ':8066' +nginx -t +``` + +Zusätzlich: + +```text +Mobile UA -> EnableSignUpWithOpenId=true +Browser UA -> unveränderte Mattermost-Konfiguration +mobile_login -> HTTP 302 zum mattermost-oidc-Plugin +Web-OIDC -> funktioniert +Mobile-OIDC -> funktioniert +Team/Channels -> werden in der App geladen +``` +