diff --git a/README.md b/README.md index 10fb8d2..1a08386 100644 --- a/README.md +++ b/README.md @@ -28,7 +28,7 @@ Eigene Icons können in Authentik hochgeladen werden, sonst nimmt das Portal sei ## Neues Tool ins Portal aufnehmen -1. In Authentik eine Application anlegen (Name, Slug, Launch-URL). +1. In Authentik eine Application anlegen (Name, Slug, Launch-URL). Als Launch-URL den **SSO-Startpunkt** der App nehmen (z.B. `https://vvl.handy-insel.de/auth/login`), nicht die Startseite. Dann ist man nach dem Klick auf die Kachel direkt angemeldet, statt erst auf der Anmeldeseite der App zu landen. Die Launch-URLs der eigenen Tools stehen in `LAUNCH_URLS` im Setup-Skript. 2. Slug in `APP_ACCESS` eintragen und `scripts/authentik-setup.py --apply` laufen lassen (oder die Gruppe in Authentik direkt binden). 3. Optional: Icon `public/icons/.svg` und Reihenfolge in `APP_ORDER`. 4. Kopfleiste im Tool einbinden (siehe unten). diff --git a/scripts/authentik-setup.py b/scripts/authentik-setup.py index 9de1df8..cbeae55 100644 --- a/scripts/authentik-setup.py +++ b/scripts/authentik-setup.py @@ -40,6 +40,16 @@ APP_ACCESS = { "zeit-dev": ["HI-Admin"], } +# Launch-URL = SSO-Startpunkt der App. Mit bestehender Authentik-Sitzung ist man nach dem +# Klick auf die Kachel ohne Zwischenschritt angemeldet (statt auf der Anmeldeseite der App). +LAUNCH_URLS = { + "vvl": "https://vvl.handy-insel.de/auth/login", + "timer": "https://timer.handy-insel.de/auth/login", + "zeiterfassung": "https://zeit.handy-insel.de/api/auth/sso/login", + "preisliste": "https://preis.handy-insel.de/api/auth/oidc/start", + "datenuebertragungen": "https://data.handy-insel.de/api/auth/oidc/start", +} + SERVICE_ACCOUNT = "hi-portal" SERVICE_GROUP = "hi-portal-service" SERVICE_ROLE = "Portal: Apps pro Benutzer lesen" @@ -80,7 +90,7 @@ def step(title): def bind_apps(groups, apps): - step("1. Apps an Gruppen binden") + step("2. Apps an Gruppen binden") for slug, group_names in APP_ACCESS.items(): app = apps.get(slug) if not app: @@ -106,8 +116,21 @@ def bind_apps(groups, apps): call("PATCH", f"/core/applications/{slug}/", {"policy_engine_mode": "any"}) +def set_launch_urls(apps): + step("3. Launch-URLs (Kachel meldet direkt per SSO an)") + for slug, url in LAUNCH_URLS.items(): + app = apps.get(slug) + if not app: + print(f" - {slug}: App existiert (noch) nicht, übersprungen") + elif app.get("meta_launch_url") == url: + print(f" = {slug}: {url}") + else: + call("PATCH", f"/core/applications/{slug}/", {"meta_launch_url": url}) + print(f" + {slug}: {app.get('meta_launch_url') or '-'} -> {url}") + + def ensure_portal_app(apps): - step("2. OIDC-Provider und App 'Portal'") + step("1. OIDC-Provider und App 'Portal'") template = next(p for p in results("/providers/oauth2/") if p["name"] == "Preisliste") provider = next((p for p in results("/providers/oauth2/") if p["name"] == "Portal"), None) if provider: @@ -144,7 +167,7 @@ def ensure_portal_app(apps): def ensure_service_account(groups): - step("3. Service-Account für die App-Liste") + step("4. Service-Account für die App-Liste") user = next((u for u in results(f"/core/users/?username={SERVICE_ACCOUNT}") if u["username"] == SERVICE_ACCOUNT), None) token_key = None if user: @@ -187,7 +210,7 @@ def ensure_service_account(groups): def branding(): - step("4. Branding") + step("5. Branding") try: urllib.request.urlopen(f"{PORTAL_URL}/icon-192.png", timeout=10) except Exception: @@ -203,7 +226,7 @@ def branding(): def write_env(path, values): - step(f"5. {path} aktualisieren") + step(f"6. {path} aktualisieren") text = open(path).read() if os.path.exists(path) else "" for key, value in values.items(): if not value: @@ -254,6 +277,7 @@ def main(): provider = ensure_portal_app(apps) bind_apps(groups, apps) + set_launch_urls(apps) user, token = ensure_service_account(groups) if not args.skip_branding: branding()