Live Demo: https://iam-demo.celox.io
Ein vollstaendiges Identity & Access Management Showcase-Projekt, das Keycloak-basiertes SSO, OAuth2/OIDC, SAML2, RBAC und 2FA (TOTP) in einer modernen Architektur demonstriert.
- Demo-Credentials
- Quick Start
- Architektur
- Security-Konzepte
- API-Referenz
- Keycloak Konfiguration
- Testing
- Deployment
- Showcase Features
- Lizenz
| User | Passwort | Rollen |
|---|---|---|
[email protected] |
Admin123 |
admin, api-admin, api-write, api-read |
[email protected] |
Manager123 |
manager, api-write, api-read |
[email protected] |
User1234 |
user, api-read |
[email protected] |
Viewer123 |
viewer |
# Repository klonen
git clone https://github.com/pepperonas/iam-showcase-keycloak.git
cd iam-showcase-keycloak
# Alle Services starten
docker compose -f docker/docker-compose.yml up -d
# Warten bis Keycloak bereit ist (~30s)
# Frontend: http://localhost:5173
# Backend API: http://localhost:8080/api/v1/public/health
# Keycloak: http://localhost:8180 +-------------------+
| Browser |
+--------+----------+
|
OIDC/PKCE Auth Flow
|
+--------------+--------------+
| |
+---------v----------+ +----------v---------+
| React SPA | | Keycloak |
| (Vite + TS + TW) | | (Auth Server) |
| Port 5173/80 | | Port 8180 |
+---------+----------+ +----------+----------+
| |
Bearer JWT JDBC (Realm DB)
| |
+---------v----------+ +----------v---------+
| Spring Boot API | | PostgreSQL |
| (Resource Server) | | (Keycloak DB) |
| Port 8080 | | Port 5432 |
+---------+----------+ +--------------------+
|
JDBC
|
+---------v----------+
| PostgreSQL |
| (App DB) |
| Port 5432 |
+--------------------+
Keycloak (Identity Provider)
- Realm:
iam-showcase - Protokolle: OIDC, SAML 2.0
- Features: SSO, RBAC, TOTP/2FA, Brute-Force-Schutz
- Custom SPI: Audit Event Listener fuer strukturiertes Logging
Spring Boot Backend (Resource Server)
- Security: OAuth2 Resource Server mit JWT-Validierung
- JWT Converter: Extrahiert Realm- und Client-Rollen
- API: RESTful mit Versionierung (
/api/v1/) - Persistenz: JPA + Flyway Migration
React Frontend (SPA)
- Auth: OIDC Authorization Code + PKCE via
react-oidc-context - Routing: React Router v6 mit rollenbasierten Guards
- API: Axios mit Token-Interceptor
- User klickt "Anmelden" im SPA
- SPA generiert
code_verifier+code_challenge(PKCE) - Redirect zu Keycloak mit
code_challenge - User authentifiziert sich (Passwort + optional TOTP)
- Keycloak redirectet mit Authorization Code
- SPA tauscht Code +
code_verifiergegen Tokens - Access Token (JWT) wird fuer API-Calls verwendet
- SPA sendet Request mit
Authorization: Bearer <JWT> - Spring Security validiert JWT-Signatur via JWKS
KeycloakJwtConverterextrahiert Rollen- RBAC-Check gegen
SecurityConfig - Response wird zurueckgegeben
| Umgebung | Methode | Config |
|---|---|---|
| Lokal | Docker Compose | docker/docker-compose.yml |
| VPS | Docker Compose + Nginx | docker-compose.prod.yml |
| Kubernetes | Helm Chart | helm/iam-showcase/ |
- Flow: Authorization Code mit PKCE (S256)
- Client-Typ: Public Client (SPA) - kein Client Secret
- Token-Typ: JWT (RS256 signiert)
- Token-Lebensdauer: Access 5 Min, Refresh 30 Min, SSO Session 8 Std.
- Silent Renew: Automatische Token-Erneuerung im Hintergrund
- SAML-Client in Keycloak konfiguriert (
iam-saml-client) - SP Metadata XML Endpoint (
/api/v1/saml/metadata) - Assertion Consumer Service URL konfiguriert
- Signierte Assertions (RSA-SHA256)
- Methode: TOTP (Time-based One-Time Password)
- Konfiguration: 6 Ziffern, 30 Sekunden Intervall
- Algorithmus: HMAC-SHA1
- Kompatible Apps: Google Authenticator, FreeOTP, Microsoft Authenticator
Realm-Rollen:
| Rolle | Beschreibung |
|---|---|
| admin | Vollzugriff auf alle Funktionen |
| manager | Verwaltung von Benutzern und Ressourcen |
| user | Standard-Benutzerrolle |
| viewer | Nur-Lese-Zugriff |
Client-Rollen (iam-backend):
| Rolle | Beschreibung |
|---|---|
| api-admin | Administrative API-Rechte (DELETE) |
| api-write | Schreibrechte (POST, PUT) |
| api-read | Leserechte (GET) |
- Keycloak stellt JWT mit
realm_access.rolesundresource_access.iam-backend.roles KeycloakJwtConverterextrahiert beide Rollen-Sets- Mapping auf Spring Security
GrantedAuthoritymitROLE_Prefix SecurityConfigdefiniert URL-basierte RBAC-Regeln
- CSRF deaktiviert (Stateless API mit JWT)
- CORS konfiguriert (nur erlaubte Origins)
- Session: STATELESS
- Brute-Force-Schutz via Keycloak (Details siehe Brute-Force-Schutz)
- Mindestens 8 Zeichen
- Mindestens 1 Grossbuchstabe
- Mindestens 1 Ziffer
- Custom Keycloak SPI Event Listener
- Strukturiertes JSON-Logging aller Auth-Events
- Anwendungsseitiges Audit-Log fuer API-Zugriffe
Basis-URL: http://localhost:8080/api/v1
Swagger UI: http://localhost:8080/swagger-ui.html
GET /public/health - Health Check, kein Token erforderlich.
curl http://localhost:8080/api/v1/public/healthResponse: {"status":"UP","timestamp":"2026-01-01T00:00:00Z"}
GET /public/info - Anwendungsinformationen.
curl http://localhost:8080/api/v1/public/infoGET /token/inspect - Decodiertes JWT mit Header, Claims, Rollen, Ablaufzeit.
curl -H "Authorization: Bearer <TOKEN>" http://localhost:8080/api/v1/token/inspectGET /token/permissions - Effektive Berechtigungen und Permission Matrix.
curl -H "Authorization: Bearer <TOKEN>" http://localhost:8080/api/v1/token/permissionsGET /users - Paginierte Benutzerliste. Rolle: api-read
curl -H "Authorization: Bearer <TOKEN>" "http://localhost:8080/api/v1/users?page=0&size=20"GET /users/{id} - Benutzer-Details. Rolle: api-read
POST /users - Benutzer erstellen. Rolle: api-write
curl -X POST -H "Authorization: Bearer <TOKEN>" -H "Content-Type: application/json" \
-d '{"username":"test","email":"[email protected]","password":"Test1234","firstName":"Test","lastName":"User"}' \
http://localhost:8080/api/v1/usersPUT /users/{id} - Benutzer aktualisieren. Rolle: api-write
DELETE /users/{id} - Benutzer loeschen. Rolle: api-admin
GET /roles - Alle Realm- und Client-Rollen. Rolle: api-read
GET /admin/dashboard - Aggregierte Statistiken. Rolle: admin
GET /admin/audit-log - Paginiertes Audit-Log. Rolle: admin
GET /saml/metadata - SAML Service Provider Metadata XML. Kein Token erforderlich.
TOKEN=$(curl -s -X POST "http://localhost:8180/realms/iam-showcase/protocol/openid-connect/token" \
-H "Content-Type: application/x-www-form-urlencoded" \
-d "grant_type=password&client_id=iam-frontend&[email protected]&password=Admin123" \
| jq -r '.access_token')| Client | Typ | Protokoll | Zweck |
|---|---|---|---|
iam-frontend |
Public | OIDC | React SPA (PKCE) |
iam-backend |
Confidential | OIDC | Spring Boot Resource Server |
iam-saml-client |
SAML | SAML 2.0 | Konzept-Demo |
Realm-Rollen: admin, manager, user, viewer
Client-Rollen (iam-backend): api-read, api-write, api-admin
Benutzer-Zuordnung:
| User | Realm-Rollen | Client-Rollen |
|---|---|---|
| [email protected] | admin | api-admin, api-write, api-read |
| [email protected] | manager | api-write, api-read |
| [email protected] | user | api-read |
| [email protected] | viewer | - |
- Password Policy: min 8 Zeichen, 1 Grossbuchstabe, 1 Ziffer
- OTP: TOTP, 6 Stellen, 30 Sekunden
- Brute Force: Aktiv, max 5 Fehlversuche, 15 Min Sperre (siehe Brute-Force-Schutz)
- Token Lifetimes: Access 5min, Refresh 30min, SSO 8h
- Provider-ID:
celox-audit-listener - Loggt: LOGIN, LOGOUT, REGISTER, ERROR Events
- Format: Strukturiertes JSON
- Deployment: JAR in
/opt/keycloak/providers/
Keycloak sperrt Accounts nach wiederholten Fehlversuchen automatisch:
| Parameter | Wert | Beschreibung |
|---|---|---|
failureFactor |
5 | Fehlversuche bis zur Sperre |
waitIncrementSeconds |
60 | Sperrdauer steigt pro Lockout um 60s |
maxFailureWaitSeconds |
900 | Maximale Sperrdauer (15 Min) |
permanentLockout |
false | Sperre ist temporaer, nicht dauerhaft |
Wichtig - Account Enumeration Prevention: Keycloak gibt bei gesperrten Accounts absichtlich die gleiche Fehlermeldung zurueck wie bei falschen Credentials (Invalid user credentials). Der HTTP-Statuscode bleibt 401. Dieses Verhalten ist ein Sicherheitsfeature - ein Angreifer kann nicht erkennen, ob ein Account existiert, gesperrt ist oder das Passwort falsch war.
Die Sperre laesst sich nicht durch die API-Antwort erkennen, sondern nur ueber die Keycloak Admin API:
# Brute-Force-Status eines Users pruefen (Admin-Token erforderlich)
GET /admin/realms/iam-showcase/attack-detection/brute-force/users/{userId}
# -> { "disabled": true, "numFailures": 5, ... }
# Sperre manuell aufheben
DELETE /admin/realms/iam-showcase/attack-detection/brute-force/users/{userId}Verifizierter Ablauf:
- Login mit korrektem Passwort → Token erhalten
- 5x falsches Passwort →
401 Invalid user credentials - Login mit korrektem Passwort →
401 Invalid user credentials(Account gesperrt) - Admin hebt Sperre auf → Login funktioniert wieder
Unit Tests
- Framework: JUnit 5
- Mocking: Mockito (Standard) + EasyMock (demonstriert beide Frameworks)
- Scope: Services, Converter, DTOs
Security Tests
- Mock JWT:
@WithMockUser,SecurityMockMvcRequestPostProcessors.jwt() - RBAC Tests: Alle Rollen-Kombinationen gegen alle Endpoints
- Scope: SecurityConfig, Zugriffsregeln
Integration Tests
- Testcontainers: PostgreSQL + Keycloak Container
- Scope: Kompletter Request-Lifecycle, DB-Operationen
Coverage
- Tool: Jacoco Maven Plugin
- Minimum: 80% Line Coverage
- Report:
backend/target/site/jacoco/
- Framework: Vitest
- DOM Testing: @testing-library/react
- Mocking: vi.mock fuer OIDC-Context
- Test-Dateien:
App.test.tsx,PermissionMatrix.test.tsx,TokenInspector.test.tsx
# Backend Tests
cd backend && mvn clean verify
# Frontend Tests
cd frontend && npm test
# Alle Tests
mvn clean verify && cd ../frontend && npm test# Alle Services starten
docker compose -f docker/docker-compose.yml up -d
# Status pruefen
docker compose -f docker/docker-compose.yml ps
# Logs anzeigen
docker compose -f docker/docker-compose.yml logs -f keycloak
# Services stoppen
docker compose -f docker/docker-compose.yml downURLs:
- Frontend: http://localhost:5173
- Backend API: http://localhost:8080/api/v1/public/health
- Keycloak: http://localhost:8180 (Admin: admin/admin)
- Swagger UI: http://localhost:8080/swagger-ui.html
Voraussetzungen:
- VPS mit Docker + Docker Compose
- DNS:
iam-demo.celox.io+auth.iam-demo.celox.io-> VPS IP - SSH-Zugang
# Auf VPS: Repository klonen
git clone https://github.com/pepperonas/iam-showcase-keycloak.git /opt/iam-showcase-keycloak
cd /opt/iam-showcase-keycloak
# .env erstellen (basierend auf .env.example)
cp .env.example .env
# Sichere Passwoerter setzen!
# Starten mit Produktion-Overrides
docker compose -f docker/docker-compose.yml -f docker/docker-compose.prod.yml up -d
# SSL einrichten
sudo bash scripts/setup-ssl.sh# Helm Chart installieren
helm install iam-showcase helm/iam-showcase/ -n iam-showcase --create-namespace
# Produktion
helm install iam-showcase helm/iam-showcase/ -f helm/iam-showcase/values-prod.yaml
# Lint pruefen
helm lint helm/iam-showcase/
# Template rendern
helm template iam-showcase helm/iam-showcase/| Kompetenz | Implementierung | Dateien |
|---|---|---|
| Keycloak Administration | Realm-Konfiguration, Clients, Rollen, Users, Policies | keycloak/realm-export.json |
| OAuth2 / OIDC | Authorization Code + PKCE, JWT-Validierung, Token-Inspection | SecurityConfig.java, KeycloakJwtConverter.java, AuthProvider.tsx |
| SAML 2.0 | Keycloak SAML-Client, SP Metadata Endpoint | realm-export.json, SamlController.java |
| RBAC | Realm- + Client-Rollen, URL-basierte Zugriffssteuerung | SecurityConfig.java, ProtectedRoute.tsx |
| 2FA / MFA | TOTP Konfiguration (6 Digits, 30s) | realm-export.json (OTP Policy) |
| SSO | Session-Management, Token-Lifetimes | Keycloak-Konfiguration |
| Custom SPI | Event Listener mit strukturiertem Audit-Logging | AuditEventListenerProvider.java |
| Spring Security | OAuth2 Resource Server, Method Security | SecurityConfig.java |
| React + OIDC | SPA mit PKCE, rollenbasierte UI | useAuth.ts, Sidebar.tsx |
| API Design | RESTful, Versioniert, Swagger/OpenAPI | Controller-Layer |
| Testing | Mockito, EasyMock, Testcontainers, Vitest | *Test.java, *.test.tsx |
| Docker | Multi-Stage Build, Compose Orchestrierung | Dockerfile, docker-compose.yml |
| Kubernetes | Helm Charts, HPA, Ingress, Secrets | helm/iam-showcase/ |
| CI/CD | GitHub Actions, Security Scans | .github/workflows/ |
- Token Inspector - JWT visuell decodiert, Expiry-Countdown, Copy-Button
- Role Switcher - One-Click User-Wechsel zwischen 4 Demo-Profilen
- API Tester - Interaktiver Endpoint-Tester mit Batch-Test und visueller Berechtigungsanzeige
- Permission Matrix - Endpoint x Rolle Grid (gruen/rot)
- OIDC Flow Diagram - 10-Schritt Sequenzdiagramm des Auth-Flows
- User Management - CRUD-Interface mit rollenbasierter UI
- Admin Dashboard - Statistiken + Audit-Log
- Identity Provider: Keycloak 24 (OAuth2, OIDC, SAML2, TOTP)
- Backend: Spring Boot 3.3, Java 21, Spring Security OAuth2 Resource Server
- Frontend: React 18, TypeScript, Vite, Tailwind CSS, Material Design 3
- Datenbank: PostgreSQL 16
- Infrastruktur: Docker Compose, Helm Charts, GitHub Actions
- Testing: JUnit 5, Mockito, EasyMock, Testcontainers, Vitest
MIT License - (c) 2026 Martin Pfeffer | celox.io





