Setup-Skript: Launch-URLs auf die SSO-Startpunkte der Tools setzen

Ein Klick auf die Kachel meldet damit direkt über die bestehende
Authentik-Sitzung an, statt auf der Anmeldeseite der App zu landen.

Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
This commit is contained in:
Kerim AtilganandClaude Opus 5.5 committed 2026-10-25 11:29:28 +01:00
1 parent 2f7184a8fd
commit dfcba39bdd
2 files changed
+30 -6

No files matched your search

+1 -1
View File
@@ -28,7 +28,7 @@ Eigene Icons können in Authentik hochgeladen werden, sonst nimmt das Portal sei
## Neues Tool ins Portal aufnehmen ## 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). 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/<slug>.svg` und Reihenfolge in `APP_ORDER`. 3. Optional: Icon `public/icons/<slug>.svg` und Reihenfolge in `APP_ORDER`.
4. Kopfleiste im Tool einbinden (siehe unten). 4. Kopfleiste im Tool einbinden (siehe unten).
+29 -5
View File
@@ -40,6 +40,16 @@ APP_ACCESS = {
"zeit-dev": ["HI-Admin"], "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_ACCOUNT = "hi-portal"
SERVICE_GROUP = "hi-portal-service" SERVICE_GROUP = "hi-portal-service"
SERVICE_ROLE = "Portal: Apps pro Benutzer lesen" SERVICE_ROLE = "Portal: Apps pro Benutzer lesen"
@@ -80,7 +90,7 @@ def step(title):
def bind_apps(groups, apps): 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(): for slug, group_names in APP_ACCESS.items():
app = apps.get(slug) app = apps.get(slug)
if not app: if not app:
@@ -106,8 +116,21 @@ def bind_apps(groups, apps):
call("PATCH", f"/core/applications/{slug}/", {"policy_engine_mode": "any"}) 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): 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") 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) provider = next((p for p in results("/providers/oauth2/") if p["name"] == "Portal"), None)
if provider: if provider:
@@ -144,7 +167,7 @@ def ensure_portal_app(apps):
def ensure_service_account(groups): 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) user = next((u for u in results(f"/core/users/?username={SERVICE_ACCOUNT}") if u["username"] == SERVICE_ACCOUNT), None)
token_key = None token_key = None
if user: if user:
@@ -187,7 +210,7 @@ def ensure_service_account(groups):
def branding(): def branding():
step("4. Branding") step("5. Branding")
try: try:
urllib.request.urlopen(f"{PORTAL_URL}/icon-192.png", timeout=10) urllib.request.urlopen(f"{PORTAL_URL}/icon-192.png", timeout=10)
except Exception: except Exception:
@@ -203,7 +226,7 @@ def branding():
def write_env(path, values): 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 "" text = open(path).read() if os.path.exists(path) else ""
for key, value in values.items(): for key, value in values.items():
if not value: if not value:
@@ -254,6 +277,7 @@ def main():
provider = ensure_portal_app(apps) provider = ensure_portal_app(apps)
bind_apps(groups, apps) bind_apps(groups, apps)
set_launch_urls(apps)
user, token = ensure_service_account(groups) user, token = ensure_service_account(groups)
if not args.skip_branding: if not args.skip_branding:
branding() branding()