Authorization code flow – Step by Step
Im Kontext unseres Beispiels:
- User = Anwenderinnen/Anwender
- Client/Application = Spring Boot Demo Application
- IDP = Identity Provider Keycloak
Die Demo-Anwendung authorization-code-flow
zielt darauf ab, Entwicklern einen praktischen Leitfaden zu bieten, wie sie den Authorization Code Flow und den Resource Owner Password Credentials Flow in ihren Projekten umsetzen können, um eine sichere und effiziente Benutzerverwaltung zu gewährleisten.
Konfiguration der Projektstruktur und Abhängigkeiten
Die Grundlage unserer Demo-Anwendung ist ein Maven-Projekt, welches das Spring Boot Framework nutzt. Spring Boot erleichtert uns die Konfiguration und das Setup, damit wir uns auf die wichtigen Aspekte der Keycloak-Integration konzentrieren können.
Hier ist ein Überblick über die wesentlichen Teile der `pom.xml`, die für unser Projekt konfiguriert wurden:
- Spring Boot Starter Parent: Durch die Nutzung des `spring-boot-starter-parent` mit der Version 3.0.4 stellen wir sicher, dass unser Projekt auf der neuesten stabilen Spring Boot Version aufbaut. Dies ermöglicht uns, von den neuesten Features und Verbesserungen zu profitieren.
- Java-Version: Mit `maven.compiler.source` und `maven.compiler.target` auf Version `17` eingestellt, verwenden wir eine aktuelle Version mit stabilen Features der Java-Sprache, was uns verbesserte Performance und eine modernere Syntax bietet.
- Spring Boot Starter Web: Diese Abhängigkeit zieht alles Notwendige für die Erstellung einer Webanwendung heran, inklusive Tomcat als embedded Servlet Container und Spring MVC.
- Spring Boot Starter Security und Spring Security OAuth2 Resource Server: Diese Pakete bieten die Tools, um unsere Anwendung abzusichern und den Schutz unserer Endpunkte über OAuth2 Token zu gewährleisten
- Spring Boot Starter OAuth2 Client: Damit wird die Anwendung um die Fähigkeit erweitert, sich als OAuth2-Client zu authentifizieren, was für die Kommunikation mit Keycloak notwendig ist.
- Lombok: Durch diese Bibliothek reduzieren wir den zu schreibenden Boilerplate-Code erheblich, was unsere Anwendung übersichtlicher und wartbarer macht.
- Spring Boot Maven Plugin: Dieses Plugin hilft uns, die Anwendung zu verpacken und auszuführen.
Der Controller der Demo-Anwendung
Unsere Demo-Anwendung verwendet einen Spring-Controller, um verschiedene Endpunkte für unsere Webanwendung bereitzustellen. Jede Methode im Controller ist einem spezifischen Pfad zugeordnet und definiert, was passiert, wenn ein Benutzer diesen Pfad aufruft.
Basis-Endpunkte
@GetMapping("/")
Das Root-Verzeichnis der Anwendung leitet einfach zur `index.html` weiter, welche als unsere Startseite fungiert.@GetMapping("/public")
Der öffentliche Endpunkt, zu dem jeder Zugang hat, ohne sich authentifizieren zu müssen.@GetMapping("/secured")
Ein gesicherter Endpunkt, der nur nach erfolgreicher Authentifizierung erreichbar ist.
Rollenbasierte Zugriffskontrolle
Unsere Anwendung implementiert rollenbasierte Zugriffskontrolle mit benutzerdefinierten Annotations:
@GetMapping("/realm-admin-realm-user-only")
@CustomRolesAllowed({"admin", "user"})
Dieser Endpunkt ist nur für Benutzer mit den Rollen „admin“oder „user“ im Realm zugänglich.@GetMapping("/realm-admin-only")
@RealmAdminOnly
Spezifisch für Realm-Administratoren.@GetMapping("/resource-admin-only")
@ResourceAdminOnly(resource = "athen", role = "client_admin")
Hier wird der Zugriff auf Benutzer beschränkt, die in einer bestimmten Resource in diesem Fall client-id „athen“ die Rolle „client_admin“ haben.@GetMapping("/composite-role-endpoint")
@CompositeRoles({"athen:client_admin", "olymp:admin"})
Zugänglich für Benutzer, die komplexe Rollenanforderungen erfüllen, hier sowohl „client_admin“ in Client-id „athen“ als auch „admin“ in Realm „olymp“
Logout-Funktionalität
@GetMapping("/logout")
Hier wird der Benutzer ausgeloggt. Die Spring-Security-Infrastruktur kümmert sich darum, den `Authentication`-Kontext zu leeren und die Sitzung zu invalidieren.
Absicherung der Endpunkte durch die Spring Security und TokenUtils Klasse
Die Sicherung der Endpunkte in unserer Anwendung wird durch benutzerdefinierte Annotationen wie @CustomRolesAllowed, @RealmAdminOnly, @ResourceAdminOnly und @CompositeRoles gewährleistet. Diese Annotationen stellen eine effektive Methode dar, um spezifische Sicherheitslogiken zu implementieren. Indem sie direkt in den Controller-Code integriert werden, verbessern sie nicht nur die Lesbarkeit, sondern auch die Wartbarkeit der Zugriffskontrollregeln.
Jede dieser Annotations arbeitet mit der `TokenUtils` – Klasse zusammen, um zu überprüfen, ob der aktuelle Benutzer die erforderlichen Rollen für den Zugriff auf einen Endpunkt besitzt. Dies zeigt die Flexibilität von Spring Security, wenn es um die Erweiterung und Anpassung an komplexe Sicherheitsanforderungen geht.
Diese Klasse ist ein maßgeblicher Bestandteil des Sicherheitssystems der Applikation, da sie verantwortlich für die Auwertung und die Verarbeitung von JWTs (JSON Web Tokens) ist, die von Keycloak für die Authentifizierung und Autorisierung ausgestellt werden. JWTs sind ein integraler Bestandteil moderner Authentifizierungsmechanismen in verteilten Systemen. Ein Token besteht aus drei durch Punkte getrennten Teilen: Header, Payload und Signatur. Die `TokenUtils`-Klasse konzentriert sich auf den Payload, der die relevanten Benutzeransprüche (Claims) enthält
Konfiguration und Initialisierung
Bevor die `TokenUtils` ihre Funktionen ausführen kann, muss sie mit der erforderlichen Konfiguration initialisiert werden. Konfigurationsparameter wie der `externalOauth2Provider` oder Schalter für das Logging werden über `@Value`-Annotationen geladen und steuern das Verhalten der Klasse.
Kernfunktionen
- Laden und Parsen des Tokens
Die primäre Aufgabe der Klasse ist das Laden und Parsen des Access Tokens eines Benutzers, um Zugang zu den darin enthaltenen Informationen zu erhalten. Die Methode `loadPayload()` nimmt den Benutzernamen entgegen, lädt den entsprechenden OAuth2AuthorizedClient und extrahiert den Payload aus dem Access Token. Hierbei wird auch geprüft, ob das Token im korrekten Format vorliegt. - Rollen- und Rechteprüfung
Mit Methoden wie `hasAnyRealmRole()`, `hasRealmRole()` und `hasResourceRole()` bietet `TokenUtils` die Möglichkeit, zu überprüfen, ob ein Benutzer bestimmte Rollen oder Rechte besitzt. Diese Funktionen sind entscheidend, um sicherzustellen, dass Benutzer nur auf die für sie bestimmten Ressourcen zugreifen können. - Zusätzliche Hilfsmethoden
Die Klasse stellt weitere Methoden wie `getScopesFromToken()` zur Verfügung, um die Scopes eines Tokens abzurufen. Scopes sind essentiell, um zu bestimmen, auf welche Bereiche der Anwendung der Benutzer Zugriff hat. - Logging und Feedback
`TokenUtils` bietet umfangreiche Logging-Funktionen, um die Token- und Rollendaten eines Benutzers für Debugging und Überwachungszwecke auszugeben. Die Methoden `printUserRolesAndAuthorities()`, `printTokens()` und `printScopes()` dienen dazu, die Token-Informationen in einem lesbaren Format auszugeben.
Anpassung und Erweiterbarkeit
Während die aktuelle Implementierung von `TokenUtils` eine breite Palette von Funktionen abdeckt, ist es möglich und erwartet, dass die Klasse angepasst oder erweitert wird, um spezifische Sicherheitsanforderungen eines Projekts zu erfüllen.
Die TokenUtils
-Klasse ist ein unverzichtbares Werkzeug in unserer Anwendung, die mit Keycloak als Authentifizierungsprovider arbeitet und speziell als Teil unserer Demo für Trainingszwecke konzipiert wurde. Sie bietet eine zuverlässige Schnittstelle zum Laden, Parsen und Inspektieren von OAuth2-Token, um die Sicherheitsmechanismen der Anwendung zu unterstützen. Wichtig zu beachten ist, dass das Logging von Token-Informationen ausschließlich zu Trainings- und Testzwecken in einer sicheren Testumgebung empfohlen wird. In einer Produktionsumgebung sollten Token-Informationen aus Sicherheitsgründen nicht geloggt werden, um das Risiko von Datenlecks und anderen Sicherheitsbedrohungen zu minimieren.
Wir sind am Ende unserer Entdeckungsreise angelangt! Sie haben jetzt einen umfassenden Einblick in die Welt des Authorization Code Flows mittels der Spring Boot Keycloak-Demo-Anwendung erhalten. Online-Sicherheit ist kein Hexenwerk, sondern das Resultat sorgfältig entwickelter und implementierter Mechanismen. Mit der Einbindung des Authorization Code Flows in Ihre Projekte können Sie nicht nur die Sicherheit Ihrer Anwendungen erheblich steigern, sondern bieten Ihren Nutzern auch eine komfortable Authentifizierungserfahrung. Ich hoffe, dass dieser Blog-Post für Sie hilfreich war und bin gespannt darauf, wie Sie diese Techniken in Ihren eigenen Projekten umsetzen werden. Bleiben Sie sicher und viel Spaß beim Programmieren!
Mit nur wenigen Anpassungen kann über die Demo-Anwendung auch der Ressource Owner Password Credentials Flow
realisiert werden. Das zeige ich im nächsten Beitrag. Einfach wieder reinschauen.