Fuenfte und letzte Erweiterung aus M6. Loest den in SecurityConfigs eigenem Javadoc (aus
M4) bereits benannten "naheliegenden naechsten Ausbauschritt" ein: HTTP Basic + In-Memory-
Benutzerspeicher war fuer M4 als angemessener erster Schritt begruendet (reine JSON-REST-API,
keine Session/kein eigenes Frontend), aber mit Klartext-aehnlichen Passwoertern im
Anwendungscode nicht praxistauglich.
PolicyAdmin/Underwriter/CustomerServiceRep) und ihre
Zuordnung in @PreAuthorize auf PolicyManagementService bleiben unveraendert - nur
die Quelle der Rolleninformation aendert sich.SecurityConfig: OAuth2-Resource-Server statt httpBasic() + User.withUsername(...).
JwtAuthenticationConverter mit eigenem JwtGrantedAuthoritiesConverter, da Keycloak
Realm-Rollen unter dem verschachtelten Claim realm_access.roles ablegt - Spring
Securitys eingebauter Converter kennt nur flache Claims wie scope.application.yml: spring.security.oauth2.resourceserver.jwt.issuer-uri (Discovery-URI
statt direkter jwk-set-uri - Spring Boot loest daraus automatisch den
JWK-Set-Endpunkt per /.well-known/openid-configuration auf).novaris-modern-parent/keycloak/novaris-realm.json: importierbarer Keycloak-Realm
novaris mit Client novaris-policy-core (public, directAccessGrantsEnabled fuer
Password-Grant-Tests), drei Realm-Rollen und drei Testnutzern, deren Rollenverteilung
exakt der vorherigen HTTP-Basic-Konfiguration entspricht (admin: alle drei Rollen,
underwriter: Underwriter + CustomerServiceRep, csr: nur CustomerServiceRep).Urspruengliche Annahme beim Schreiben von SecurityConfig war, dass Spring Boots
OAuth2-Resource-Server-Autokonfiguration das OIDC-Discovery-Dokument blockierend beim Start
abruft und die Anwendung ohne erreichbaren Issuer deshalb gar nicht erst hochfaehrt - analog
zur bewussten Ausnahme vom sonstigen "lauffaehig ohne externe Abhaengigkeit"-Prinzip
(Oracle/DB2/Kafka haben alle einen lokalen Fallback: H2 statt Oracle,
initializationFailTimeout(-1) fuer DB2).
Ein echter Test (Keycloak-Container gestoppt, Anwendung neu gestartet) widerlegte diese
Annahme: Spring Boot 3.2 baut den JwtDecoder bei issuer-uri-Konfiguration ueber einen
SupplierJwtDecoder, der das Discovery-Dokument erst beim ersten tatsaechlichen
Decodierversuch abruft, nicht beim Kontextstart. Real verifiziert:
GET /api/policies ohne Token -> weiterhin 401 (kein Decodierversuch noetig).GET /api/policies mit einem strukturell gueltigen, aber nicht mehr verifizierbaren
Bearer-Token -> ebenfalls 401 (der verzoegerte Decodierversuch schlaegt fehl, Spring
Security behandelt das als Authentifizierungsfehler), kein 500 und keine haengende
Anfrage.Das Verhalten liegt damit tatsaechlich naeher am uebrigen Projekt-Prinzip als urspruenglich angenommen - nur mit dem unveraendert gueltigen Unterschied, dass ohne erreichbaren Identity Provider niemand erfolgreich authentifiziert werden kann.
Beim ersten echten Token-Abruf gegen den frisch importierten Realm schlug der
Password-Grant fuer alle drei Testnutzer mit invalid_grant /
"Account is not fully set up" fehl, obwohl Nutzer, Passwoerter und Rollen korrekt importiert
waren (per Admin-REST-API bestaetigt: Credential vorhanden, requiredActions: []).
Server-Log zeigte den eigentlichen Fehler: error="resolve_required_actions". Ursache:
Keycloak 24 aktiviert standardmaessig eine User-Profile-Validierung, die fuer die Rolle
user ein email-Attribut erfordert (users/profile-Konfiguration,
"required": {"roles": ["user"]} fuer email) - die importierten Nutzer hatten keine
E-Mail-Adresse, wodurch Keycloak dynamisch eine VERIFY_PROFILE-Required-Action ergaenzte,
die den Password-Grant blockierte, ohne dass dies in requiredActions des Nutzers sichtbar
wurde. Behoben durch Ergaenzen von email/emailVerified: true/firstName/lastName fuer
alle drei Nutzer in novaris-realm.json (und per Admin-REST-API am bereits laufenden
Test-Container nachgezogen) - kein Konfigurationsfehler auf Anwendungsseite, sondern ein
Keycloak-Default, der bei minimalen Realm-Exports leicht uebersehen wird.
Real gegen einen laufenden Keycloak-24-Container (quay.io/keycloak/keycloak:24.0
start-dev --import-realm) verifiziert, keine Mocks:
/realms/novaris/protocol/openid-connect/token) bezogen.novaris-policy-core-modern gegen den echten Issuer gebootet (bestaetigt: die
OIDC-Discovery-Abfrage beim Start gelingt).PolicyController
verifiziert:
- kein Token, GET /api/policies -> 401
- csr-Token, POST /api/policies (nur PolicyAdmin/Underwriter) -> 403
- underwriter-Token, GET /api/policies -> 200
- underwriter-Token, POST /api/policies mit gueltigem Produktcode -> 201, echte
Police in H2 angelegt (JPA-Schreibpfad inklusive der @Primary-DataSource-Klaerung aus
09-offene-punkte-geschlossen.md bestaetigt weiterhin funktionsfaehig)
- underwriter-Token, POST /{policyNumber}/cancel (nur PolicyAdmin) -> 403
- admin-Token, POST /{policyNumber}/cancel -> 204
- ungueltiger/erfundener Bearer-Token -> 401Dieselbe Pruefrigorositaet wie bereits fuer die HTTP-Basic-Implementierung in M4
angewendet - nur curl -u user:pass durch curl -H "Authorization: Bearer $TOKEN" ersetzt.
novaris-policy-web-modern-spa)Der urspruengliche Stand dieses Dokuments beschrieb kein Frontend-Login als offene Luecke -
mittlerweile geschlossen: novaris-policy-web-modern-spa implementiert den
Authorization-Code-Flow mit PKCE gegen genau diesen Keycloak-Realm (siehe dessen README,
Abschnitt "Real verifiziert"). Weiterhin offen: kein Refresh-Token-Flow (bei
Token-Ablauf muss sich die Nutzerin erneut einloggen statt automatisch verlaengert zu
werden) - fuer dieses Lernprojekt bewusst nicht gebaut, waere aber der naheliegende naechste
Schritt.