Commit Graph

4 Commits

Author SHA1 Message Date
a9bf8ecdd1 Final commit. 2026-06-01 17:12:28 +02:00
cb22fff407 Phase B Fixes: AppAuth-Stored-State + LAN-Cleartext + force prompt=login
Drei zusammenhängende Korrekturen, die den OIDC-Flow auf realen Geräten
durchgehen lassen:

1. taskAffinity="" raus aus MainActivity — sonst landet die
   RedirectUriReceiverActivity beim Rücksprung aus Samsung Internet
   Custom Tabs (FLAG_ACTIVITY_NEW_TASK) in einem zweiten Task und
   zweitem App-Prozess, AppAuth findet seinen in-memory PKCE-State
   nicht und meldet 'No stored state - unable to handle response'.

2. network_security_config.xml: base-config cleartextTrafficPermitted
   statt einzelner localhost/10.0.2.2-Domains. Notwendig für Tests
   gegen die LAN-IP des Dev-Macs (z.B. 192.168.x.x); AndroidConfig kann
   keine IP-Wildcards. Klar als Dev-only markiert.

3. promptValues=['login'] auf der AuthorizationTokenRequest — verhindert
   den Instant-SSO-Cookie-Redirect-Race, bei dem Chrome Custom Tabs
   schliesst, bevor der Redirect-Intent ankommt; AppAuth wuerde sonst
   'User cancelled flow' melden, obwohl der Nutzer nicht abgebrochen
   hat. UX-mässig auch gewollt: jeder Login frisch (Account-Wechsel
   am gleichen Geraet ist denkbar), Restore laeuft über den Refresh-
   Token aus der Secure Storage.
2026-05-15 11:16:18 +02:00
08824290ff Phase B: Token-Provider und AuthBloc robust gegen Storage-Plugin-Fehler
Beobachtung: Nach 'flutter_secure_storage' frisch dazugepackt ohne
Cold-Restart kam eine MissingPluginException auf dem AuthBloc-Stream
durch (read auf channel plugins.it_nomads.com/flutter_secure_storage)
und hat den ganzen Bloc-Event-Loop mitgerissen.

Fix:
- KeycloakOidcTokenProvider.restoreSession / _persistRefreshToken /
  logout fangen Plugin-Exceptions ab und loggen sie über debugPrint,
  statt sie hochzureichen. Restore-Pfad endet sauber mit 'kein Restore
  möglich', Login-Pfad hält den Token in Memory weiter.
- AuthBloc._handleRestore mit eigener try/catch als zweite Schutzschicht
  für jeden anderen Fehler aus dem Provider.

Bestehender Cold-Restart-Workaround (App stoppen + flutter run) für die
ursprüngliche MissingPluginException bleibt natürlich nötig — diese
Änderung sorgt nur dafür, dass künftige Storage-Probleme (Keychain
zerschossen, Restore-Backup, …) nicht die Auth komplett killen.
2026-05-14 23:04:12 +02:00
6d7e58fc0f Phase B: Keycloak OIDC (PKCE) statt Cookie-Session-Login
App-Code:
- KeycloakOidcTokenProvider: PKCE-Login via flutter_appauth, Refresh via
  Refresh-Token aus flutter_secure_storage, Session-Restore beim
  App-Start, Logout.
- AuthSessionEvent als Provider→Bloc-Brücke (LoggedIn/LoggedOut/
  SessionExpired) auf einem Broadcast-Stream.
- AuthBloc komplett umgebaut: nimmt jetzt den KeycloakOidcTokenProvider
  statt UserInfoService, mappt eingehende Provider-Events auf eigene
  Zustände. Authenticated.fromClaims() liest personalnummer + Name aus
  dem ID-Token-Payload.
- LoginPage: kein Browser+Deep-Link mehr — Button feuert
  LoginRequested, der Provider übernimmt den restlichen Flow.
- network_locator: produktiver KeycloakOidcTokenProvider, doppelt
  registriert (KeycloakOidcTokenProvider für AuthBloc,
  AuthTokenProvider für Interceptor).
- Auth-State trägt zusätzlich personalnummer/displayName/email; das
  Legacy-User-Objekt + sessionId bleiben temporär drin, damit die
  alten ERPframe-Services (Phase D) noch kompilieren.

Plattform-Setup:
- Android: appAuthRedirectScheme=holzleitner in build.gradle.kts,
  NetworkSecurityConfig erlaubt HTTP zu localhost/10.0.2.2/127.0.0.1.
- iOS: holzleitner als URL-Scheme im Info.plist, ATS-Ausnahme für
  localhost (HTTP-Keycloak im Dev-Setup).

Out of scope:
- Keine echte App-Run-Smoke — kommt mit dem User-Test.
- iOS-pod-install läuft beim ersten 'flutter run ios' automatisch.
- Old ERPframe-Services bleiben aktiv und werfen ab jetzt 401 (kein
  Cookie-Session-Token mehr) — wird in Phase D entfernt.
2026-05-14 22:59:36 +02:00