Zum Inhalt springen

Authentifizierung

Status: Entwurf · Spec-Kandidat: ja

Anforderung

Authentifizierung erfolgt über OIDC/OAuth2 (NFR-006).

OIDC-Provider: Authentik (gesetzt)

Als OIDC-Provider wird Authentik verwendet (self-hosted). Alle weiteren Annahmen in dieser Spec setzen das voraus.

AspektFestlegung
ProviderAuthentik (self-hosted)
Discovery-Endpointhttps://<authentik-host>/application/o/<app-slug>/.well-known/openid-configuration
JWKS-Endpointhttps://<authentik-host>/application/o/<app-slug>/jwks/
Token-SignaturRS256 (Default)
Pro AnwendungEigener „Provider”+„Application”-Eintrag in Authentik (z. B. mdm-api), eigene Client-ID/Secret
Token-TypJWT (Access-Token) — direkt im API-Layer validierbar, kein zusätzlicher UserInfo-Roundtrip nötig
Refresh-TokensAktiviert; Frontend nutzt Auth.js / NextAuth-Pattern
M2M / Service-AccountsAuthentik-Service-Accounts mit Client-Credentials-Flow → gemappt auf mdm.AA_SERVICE_ACCOUNT

Claim-Mapping

Authentik liefert per Default folgende Claims, die wir verbindlich nutzen:

ClaimQuelle (Authentik)Verwendung im MDM
issAuthentik-Issuer-URLValidierung
subAuthentik-User-UUID (pk als String)AA_APP_USER.external_id
audClient-ID der MDM-AnwendungValidierung
emailE-Mail des UsersAA_APP_USER.email
preferred_username / nameUser-NameAA_APP_USER.display_name
groupsAuthentik-Gruppen-Memberships (Property-Mapping „Authentik default OAuth Mapping: OpenID ‘groups’“)Mapping auf AA_PRINCIPAL_GROUP.key
tenant_idCustom Property-Mapping in Authentik (Pflicht für V2+)Tenant-Auflösung

Pflicht-Property-Mapping in Authentik

Für Multi-Tenancy ist in Authentik ein eigenes Property-Mapping vom Typ “Scope Mapping” anzulegen, das tenant_id aus einem User-Attribut (z. B. attributes.tenant_id) in den Token einbettet. Ohne dieses Mapping fehlt der Claim und der API-Layer bricht mit 401 ab (V2+).

In V1 ist der Claim optional — der API-Layer fällt auf den Default-Tenant public zurück.

Token-Validierung im API-Layer

  1. JWKS via Discovery-Endpoint laden, Cache-TTL ≤ 10 min, Force-Refresh bei kid-Miss.
  2. Signaturprüfung gegen JWKS, Algorithmus auf RS256 fest verdrahtet (kein Algorithm-Confusion).
  3. iss muss exakt der Authentik-Issuer-URL entsprechen, aud muss die konfigurierte Client-ID enthalten, exp/nbf werden geprüft.
  4. sub → Lookup in mdm.AA_APP_USER über (issuer, external_id). Unbekannter User: JIT-Provisionierung ohne Rollenvergabe (siehe Abschnitt unten).
  5. groups-Claim wird auf AA_PRINCIPAL_GROUP-Mitgliedschaft gemappt — Auto-Stub + Login-Sync (siehe Abschnitt unten).
  6. tenant_id-Claim ist Primärquelle des Tenant-Kontexts (siehe Autorisierung – Auflösung des Tenant-Kontexts).

Just-in-Time-Provisionierung (gesetzt)

Trifft ein gültiges, signaturgeprüftes Authentik-Token mit unbekanntem (issuer, sub) ein, legt der API-Layer den Benutzer automatisch an, weist aber keinerlei Rolle zu. Bis ein Administrator dem User Rollen über AA_PRINCIPAL_ROLE zuweist, liefert jede authentifizierte Anfrage 403 (kein Match in mdm.v_effective_permission, Default-Deny).

Ablauf in einer Transaktion:

  1. INSERT INTO mdm.AA_APP_USER (issuer, external_id, email, display_name, is_active, ...) mit is_active=true. Tenant-Bindung via tenant_id-Claim (V2+) bzw. public (V1).
  2. Keine AA_PRINCIPAL_ROLE-Zeile. Keine Default-Group-Mitgliedschaft (Group-Sync läuft separat über OP-27 und kann später Rechte beifügen, ist aber kein Auto-Allow).
  3. INSERT INTO mdm.AA_AUDIT_LOG (action='login', actor_principal_type='user', actor_principal_id=<neu>, payload->>'jit_provisioned'='true', ...).
  4. Folge-Anfrage des Users → Permission-Auflösung läuft in mdm.v_effective_permission ins Leere → 403 mit AA_AUDIT_LOG.action='access_denied'.

Begründung: Auto-Anlage erspart manuelles User-Management bei IdP-getriebenen Organisationen, Default-Deny ohne Rollen verhindert ungewollte Rechtevererbung allein durch IdP-Mitgliedschaft. Admin sieht den neuen User in einer Inbox-Sicht (z. B. mdm.v_app_user_unassigned) und vergibt Rollen bewusst.

Operative Konsequenzen:

  • Erst-Login eines neuen Mitarbeiters erzeugt automatisch eine AA_APP_USER-Zeile, ist aber sofort handlungsunfähig.
  • Disable-Pfad: Admin setzt is_active=false oder deleted_atmdm.v_effective_permission schließt den User aus.
  • Die Variante “Default-Reader-Rolle automatisch zuweisen” ist explizit nicht vorgesehen (verworfen).

Group-Sync aus Authentik (gesetzt, OP-27)

Bei jedem erfolgreichen Token-Validierungs-Roundtrip führt der API-Layer eine idempotente Synchronisation der Authentik-groups-Claim-Werte gegen AA_PRINCIPAL_GROUP und AA_PRINCIPAL_GROUP_MEMBER aus — in einer Transaktion am Login-Pfad, nicht per separatem Cron.

Mapping-Regel: Authentik-Group-Name → AA_PRINCIPAL_GROUP.key 1:1 nach Normalisierung (lower(), Whitespace → _, Sonderzeichen-Strip; Originalname landet in AA_PRINCIPAL_GROUP.name).

Ablauf je Login:

  1. Für jeden Wert im groups-Claim:
    • Lookup AA_PRINCIPAL_GROUP per normalisiertem key.
    • Auto-Stub: existiert die Gruppe nicht, lege sie an mit is_active=false, metadata={"source":"authentik","raw":"<original>"}. Stub trägt keine Rollen — bis ein Admin sie auf is_active=true setzt und Rollen über AA_PRINCIPAL_ROLE beibringt, hat die Gruppe keinerlei Wirkung in mdm.v_effective_permission.
    • Membership AA_PRINCIPAL_GROUP_MEMBER: INSERT … ON CONFLICT DO NOTHING für (principal_group_id, member_principal_type='user', member_principal_id=<AA_APP_USER.id>).
  2. Group-Memberships, die nicht mehr im aktuellen Claim stehen, werden soft-gelöscht (AA_PRINCIPAL_GROUP_MEMBER.deleted_at = now()). Authentik bleibt single source of truth für Mitgliedschaften.
  3. Inaktive Stub-Gruppen (is_active=false) tauchen in einer Admin-Sicht mdm.v_principal_group_unassigned auf — analog zu v_app_user_unassigned aus der JIT-Logik.
  4. Audit-Log: action='role_assign'/'role_unassign' werden nicht für Group-Sync geschrieben (nur für RBAC). Stattdessen action='login' mit payload.group_sync={ added: [...], removed: [...] } für Nachvollziehbarkeit.

Konsistenzversprechen: Authentik-Verlust einer Gruppe → User verliert vererbte Rollen sofort beim nächsten Login, ohne manuelle Pflege. Auto-Stub vermeidet, dass IdP-Group-Renames im MDM zu unsichtbaren Permission-Lücken führen.

Operative Konsequenzen:

  • Eine neue Authentik-Gruppe ist im MDM beim ersten Login eines Mitglieds als inaktiver Stub sichtbar; Admin aktiviert + bindet Rollen.
  • Login-Latenz steigt um die Sync-Transaktion (Anzahl Group-Claims × kleine Writes); bei sehr großen groups-Claims kann der Sync optional in einen Hintergrund-Job verschoben werden — V1 macht es synchron.
  • Variante “Whitelist” (nur vorab konfigurierte Gruppen erlaubt) wird nicht umgesetzt; Whitelist-Effekt wird über is_active=false-Stubs erreicht.

Pflichten

  • Jede API-Anfrage muss authentifiziert sein (Service-zu-Service-Pfade dürfen Client-Credentials nutzen).
  • Identitäten werden in created_by, updated_by, archived_by, deleted_by, changed_by (Audit) durchgereicht. Das genaue Feldformat ist offen (z. B. sub-Claim, E-Mail, interner Benutzer-ID).
  • Token-Validierung gegen den OIDC-Issuer (Signaturprüfung, aud, iss, Ablauf).

Erforderliche Token-Claims

ClaimPflichtZweck
issjaOIDC-Issuer
subjaExterner User-Identifier, gemappt auf AA_APP_USER.external_id
audjaAudience-Validierung
exp / iatjaAblauf, Issue-Time
tenant_idja (V2+)Mandantenbindung als UUID oder AA_TENANT.key. Primärquelle für Tenant-Kontext.
Gruppen-Claim (Name konfigurierbar)neinGemappt auf AA_PRINCIPAL_GROUP.key

Multi-Tenant-Nutzer können den aufgelösten Tenant pro Request via X-Tenant-Id-Header überschreiben. Der Service prüft dabei, ob der Principal eine aktive Rolle in diesem Tenant hat — andernfalls 403. Detail: Autorisierung – Auflösung des Tenant-Kontexts.

Offen

  • Wahl des OIDC-Providers. Gelöst: Authentik.
  • JIT-Provisionierung unbekannter OIDC-Subjekte. Gelöst: Auto-Anlage AA_APP_USER ohne Rollen, Admin-Freischaltung pflicht (siehe Abschnitt oben, OP-23).
  • Konkretes Mapping groups-Claim → AA_PRINCIPAL_GROUP.key (Sync-Strategie, Auto-Create vs. Whitelist). Gelöst: Auto-Stub is_active=false + Login-Sync, Admin schaltet Gruppe + Rollenbindung frei (siehe Abschnitt oben, OP-27).
  • Detail-Workflow Service-Account-Erstellung in Authentik ↔ mdm.AA_SERVICE_ACCOUNT (manuell vs. provisioniert).
  • Session-/Token-Lebensdauer (Access-Token, Refresh-Token) — Authentik-Default vs. MDM-Vorgabe.

Verwandte Dokumente