b9a433f772
Completed OIDC Authorization Code Flow with PKCE (S256) for JS and JVM platforms. - Added `launchOidcFlow`, `consumePendingOidcCallback`, and `getOidcRedirectUri` with platform-specific implementations. - Integrated SHA-256 and Base64URL helpers for PKCE. - Updated `LoginViewModel` with OIDC logic (key handling, token exchange, state validation). - Enhanced `LoginScreen` with an OIDC login button and loading spinner. - Verified implementation with system hardening roadmap tasks. Includes browser redirects for JS, localhost HTTP callback for JVM, and built-in Keycloak URL construction. Signed-off-by: Stefan Mogeritsch <stefan.mo.co@gmail.com>
5.9 KiB
5.9 KiB
Journal - 2026-03-09
📝 Zusammenfassung
Keycloak-Härtung der Realm-Konfiguration (meldestelle-realm.json). Aufbauend auf dem Infrastruktur-Fix vom
2026-03-06 (korrektes start --optimized, Healthcheck) wurden nun die Client-Konfigurationen und
Sicherheitseinstellungen auf einen produktionsreifen Stand gebracht.
🛠️ Änderungen
1. config/docker/keycloak/meldestelle-realm.json
Wildcard aus webOrigins entfernt
- Vorher:
api-gatewayundweb-apphatten"*"inwebOrigins(CORS-Sicherheitslücke). - Nachher: Nur explizit erlaubte Origins (
localhost:*,app.meldestelle.at).
Neuer Client: frontend-client (KMP Desktop & Mobile)
- Public Client mit PKCE S256 (kein Client-Secret nötig, sicher für native Apps).
- Redirect URIs:
meldestelle://callback(Custom URI Scheme für Desktop),http://localhost:*(Dev),https://app.meldestelle.at/*(Prod). - Kein
directAccessGrantsEnabled— verhindert Password-Grant-Flow (unsicher für native Apps).
Password-Policy gestärkt
- Vorher:
length(8)— zu schwach. - Nachher:
length(10) and digits(1) and upperCase(1) and specialChars(1) and notUsername(undefined).
post.logout.redirect.uris konfiguriert
- Alle relevanten Clients (
api-gateway,web-app,frontend-client) haben nun korrekte Logout-Redirect-URIs gemäß OIDC Back-Channel Logout Standard.
📚 Gelerntes / Entscheidungen
meldestelle://callbackals Custom URI Scheme: Für KMP Compose Desktop ist ein eigenes URI-Schema der sichere Standard (kein offener HTTP-Port nötig). Muss im OS registriert werden.- PKCE S256 ist Pflicht für Public Clients: Verhindert Authorization Code Interception Attacks. Keycloak
26.xunterstützt dies nativ. frontend-clientvs.web-app: Klare Trennung:web-appfür Browser-basierte Web-App,frontend-clientfür native KMP Desktop/Mobile-App.
✅ Micrometer Upgrade (2026-03-09, gleiche Session)
Verifiziert: micrometer = "1.16.1" und micrometerTracing = "1.6.1" waren bereits korrekt in
gradle/libs.versions.toml gesetzt — kein Code-Change erforderlich. Archiv-Roadmaps entsprechend abgehakt.
✅ Zipkin Integration (2026-03-09, gleiche Session)
Analyse ergab: Infrastruktur war bereits zu ~90% korrekt aufgebaut. Einzige Lücke war eine falsche Propagation-Konfiguration im Gateway.
Befund
dc-infra.yaml: Zipkin-Container (openzipkin/zipkin:3, Port 9411) bereits vorhanden.monitoring-client-Bundle: enthältmicrometer-tracing-bridge-brave,zipkin-reporter-brave,zipkin-sender-okhttp3— von allen Services eingebunden.monitoring-defaults.properties: setztmanagement.zipkin.tracing.endpoint=http://localhost:9411/api/v2/spansals Default, überschreibbar viaMANAGEMENT_ZIPKIN_TRACING_ENDPOINT.dc-backend.yaml: setztMANAGEMENT_ZIPKIN_TRACING_ENDPOINT=http://zipkin:9411/api/v2/spansfür alle Services inkl. Gateway.
Fix: Gateway application.yaml
management.tracing.propagation.type:w3c→b3(B3 ist das native Format von Brave/Zipkin; W3C wäre für OpenTelemetry — Mismatch hätte Trace-Korrelation zwischen Gateway und Services gebrochen).management.zipkin.tracing.endpoint: Explizit mit lokalem Default + ENV-Override ergänzt.TRACING_SAMPLING_PROBABILITY: Konsistent mit Services via ENV-Variable.
Fix: Gateway build.gradle.kts
- Redundante direkte
micrometer-tracing-bridge-brave-Dependency entfernt (bereits transitiv viamonitoring-clientvorhanden).
✅ OIDC Client im Frontend (2026-03-09, gleiche Session)
Login-Flow mit PKCE Authorization Code Flow (S256) für frontend-client implementiert.
Neue Dateien
frontend/core/auth/src/commonMain/.../Sha256.kt: Pure Kotlin SHA-256 (FIPS 180-4) + Base64URL-Encoding — kein expect/actual, läuft auf JVM/JS/Wasm.frontend/core/auth/src/commonMain/.../PkceHelper.kt: Code Verifier, Code Challenge (S256), State Generator.frontend/core/auth/src/commonMain/.../OidcCallback.kt:OidcCallbackResultsealed class + expectlaunchOidcFlow(),consumePendingOidcCallback(),getOidcRedirectUri().frontend/core/auth/src/jvmMain/.../OidcCallback.jvm.kt: EingebetteterHttpServer(Port 18080) +Desktop.browse()+CompletableDeferred(Timeout 5 min).frontend/core/auth/src/jsMain/.../OidcCallback.js.kt:window.location.hrefRedirect + URL-Parameter-Parsing beim App-Start + History-Bereinigung viareplaceState.
Geänderte Dateien
frontend/core/domain/.../AppConstants.kt:KEYCLOAK_CLIENT_ID→frontend-client, OIDC-Konstanten ergänzt.frontend/core/auth/src/commonMain/.../AuthApiClient.kt:buildAuthorizationUrl()(PKCE URL-Builder) +exchangeCodeForToken()(Code → Token).frontend/core/auth/src/commonMain/.../LoginViewModel.kt:isOidcLoading-State,startOidcFlow(),handleOidcCallbackResult(), JS-Init-Callback-Check.frontend/core/auth/src/commonMain/.../LoginScreen.kt: Divider +OutlinedButton„Mit Keycloak anmelden" mit Spinner bei laufendem Flow.
Architektur-Entscheidungen
- Kein
ktor-client-auth: Der OIDC-Flow wird manuell implementiert —ktor-client-authunterstützt Authorization Code + PKCE nicht nativ für KMP. - Pure Kotlin SHA-256: Kein
expect/actualnötig —kotlin.math+ reine Bitoperationen reichen aus. - JVM-Callback-Server auf
localhost:18080: Standard-Muster für Desktop-Apps (RFC 8252 „OAuth 2.0 for Native Apps"). - JS-Redirect-Flow: Kein Popup — volle Seitenweiterleitung. Code Verifier wird in
sessionStoragegespeichert (nur aktueller Tab). - State-Validierung: CSRF-Schutz via State-Parameter-Vergleich im ViewModel.
🔜 Nächste Schritte
- TLS/HTTPS — Langfristig:
KC_HOSTNAME_STRICT_HTTPS=truesetzen, sobald TLS eingerichtet ist. - Gateway CircuitBreaker — Verifizieren ob durch Spring Cloud 2025.0.1 bereits behoben.