# 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 ```