fix(wiki-config): hide local login via hideLocal, keep strategy enabled

Disabling local (previous approach) left the login page empty: Wiki.js needs a
form strategy to render the provider list, so with only OIDC the card was blank
and login hung. Keep local ENABLED and instead set the built-in authHideLocal
site config, which removes local from the provider list on the login page —
only "Login with Authentik" shows.

local stays usable because the config job logs in through it, and it is the
break-glass path, reachable via /login?all (Wiki.js honors ?all to bypass
hideLocal). Verified live end-to-end: job runs idempotently, both strategies
enabled, authHideLocal=true.
This commit is contained in:
Thore Cimbal
2026-08-13 12:00:00 +00:00
parent f034eabdd6
commit c4e67244fe
+31 -11
View File
@@ -7,8 +7,15 @@ stdlib. Alle Verträge wurden am 2026-08-12 live gegen die laufende Instanz gepr
Ablauf:
warten -> (falls Setup) /finalize mit SOPS-Admin -> warten auf Normalmodus
-> login -> OIDC-Strategy setzen -> Gruppen + Seitenregeln (Abschottung).
-> login -> Gruppen + Seitenregeln (Abschottung) -> OIDC-Strategy setzen
-> local auf der Login-Seite ausblenden (hideLocal).
Idempotent: jeder Schritt prüft erst den Ist-Zustand.
Variante B ("kein manuelles Login"): local wird NICHT deaktiviert, sondern nur per
Wiki.js-eigenem hideLocal aus der Login-Seite ausgeblendet. Grund: (a) local ist
nicht löschbar und Wiki.js braucht eine Formular-Strategie, sonst rendert die
Login-Seite leer; (b) der Job selbst loggt sich über local ein; (c) Break-Glass
bleibt über /login?all erreichbar.
"""
from __future__ import annotations
@@ -112,8 +119,9 @@ def finalize():
def login():
# Gibt JWT zurück, oder None, wenn local deaktiviert ist (Variante B, bereits
# konfiguriert) — dann ist nichts zu tun.
# Gibt JWT zurück. local bleibt bewusst aktiviert (Break-Glass + der Job loggt sich
# damit ein) — None nur, falls local doch mal deaktiviert wurde, dann kann der Job
# nichts tun.
d = gql(
'mutation($u:String!,$p:String!){authentication{login(username:$u,password:$p,'
'strategy:"local"){responseResult{succeeded message} jwt}}}',
@@ -122,12 +130,13 @@ def login():
return d["jwt"] if d["responseResult"]["succeeded"] else None
def _set_strategies(jwt: str, oidc_config: list, local_enabled: bool = True):
def _set_strategies(jwt: str, oidc_config: list):
strategies = [
{ # local bleibt in der Liste (nicht löschbar, Admin hängt dran), wird aber
# am Ende deaktiviert (Variante B): kein manuelles Login mehr im Alltag.
{ # local bleibt aktiviert: der Konfig-Job loggt sich damit ein und es ist der
# Break-Glass-Zugang (/login?all). Auf der Login-Seite wird es per hideLocal
# ausgeblendet (siehe set_hide_local) — kein manuelles Login im Alltag.
"key": "local", "strategyKey": "local", "displayName": "Local",
"order": 0, "isEnabled": local_enabled, "selfRegistration": False,
"order": 0, "isEnabled": True, "selfRegistration": False,
"domainWhitelist": [], "autoEnrollGroups": [], "config": [],
},
{
@@ -159,9 +168,19 @@ def ensure_oidc(jwt: str):
"groupsClaim": "groups", "mapGroups": True,
}
oidc_config = [{"key": k, "value": json.dumps({"v": v})} for k, v in cfg.items()]
# letzter updateStrategies-Aufruf: OIDC setzen UND local deaktivieren.
_set_strategies(jwt, oidc_config, local_enabled=False)
log("OIDC-Strategy gesetzt, local-Login deaktiviert")
_set_strategies(jwt, oidc_config)
log("OIDC-Strategy gesetzt (local bleibt aktiv als Break-Glass)")
def set_hide_local(jwt: str):
# Variante B ohne local zu deaktivieren: Wiki.js' eingebautes hideLocal entfernt den
# local-Provider aus der Login-Seite (nur noch "Login with Authentik" sichtbar).
# Break-Glass bleibt über /login?all. authHideLocal ist ein Site-Config-Feld.
r = gql('mutation{site{updateConfig(authHideLocal:true){responseResult{succeeded message}}}}',
jwt)["site"]["updateConfig"]["responseResult"]
if not r["succeeded"]:
sys.exit(f"authHideLocal setzen fehlgeschlagen: {r['message']}")
log("Login-Seite: local ausgeblendet (hideLocal=true; Break-Glass via /login?all)")
def group_id(jwt: str, name: str):
@@ -198,7 +217,7 @@ def main():
finalize()
jwt = login()
if jwt is None:
log("lokaler Login nicht möglich (local deaktiviert) — bereits konfiguriert, Ende.")
log("lokaler Login nicht möglich (local wurde deaktiviert) — kann nicht konfigurieren, Ende.")
return
log("eingeloggt")
# Erst Gruppen (Schreibvorgänge), DANN OIDC — ensure_oidc deaktiviert zuletzt local.
@@ -208,6 +227,7 @@ def main():
# Guests (id 2) alle Rechte entziehen — Login-Pflicht, keine öffentliche Sicht.
gql('mutation{groups{update(id:2,name:"Guests",redirectOnLogin:"/",permissions:[],pageRules:[]){responseResult{succeeded}}}}', jwt)
ensure_oidc(jwt)
set_hide_local(jwt)
log("fertig — Wiki.js konfiguriert")