'use client' import { useState } from 'react' import AdminLayout from '@/components/admin/AdminLayout' import { WizardStepper, WizardNavigation, EducationCard, ArchitectureContext, TestRunner, TestSummary, type WizardStep, type TestCategoryResult, type FullTestResults, type EducationContent, type ArchitectureContextType, } from '@/components/wizard' // ============================================== // Constants // ============================================== const BACKEND_URL = process.env.NEXT_PUBLIC_BACKEND_URL || 'http://localhost:8000' const STEPS: WizardStep[] = [ { id: 'welcome', name: 'Willkommen', icon: '👋', status: 'pending' }, { id: 'authentication', name: 'Authentifizierung', icon: '🔐', status: 'pending', category: 'authentication' }, { id: 'roles', name: 'Rollen', icon: '👥', status: 'pending', category: 'roles' }, { id: 'permissions', name: 'Berechtigungen', icon: '🔑', status: 'pending', category: 'permissions' }, { id: 'users', name: 'Benutzer', icon: '👤', status: 'pending', category: 'users' }, { id: 'summary', name: 'Zusammenfassung', icon: '📊', status: 'pending' }, ] const EDUCATION_CONTENT: Record = { 'welcome': { title: 'Willkommen zum RBAC Wizard', content: [ 'RBAC (Role-Based Access Control) ist das Herzstück der Zugriffskontrolle.', '', 'Das System basiert auf drei Konzepten:', '• Benutzer: Personen die das System nutzen', '• Rollen: Gruppen von Berechtigungen (z.B. Admin, Lehrer)', '• Berechtigungen: Einzelne Aktionen (z.B. users:read)', '', 'Standard-Rollen in BreakPilot:', '• user: Basis-Benutzer mit Leserechten', '• admin: Verwaltungsrechte', '• data_protection_officer: DSGVO-Freigaben', '', 'JWT-Tokens enthalten Rollen und werden bei jedem Request geprueft.', ], }, 'authentication': { title: 'Authentifizierung - Login & JWT', content: [ 'Die Authentifizierung prueft die Identitaet des Benutzers.', '', 'Login-Flow:', '1. Benutzer sendet Email + Passwort', '2. Backend prueft Credentials gegen DB', '3. Bei Erfolg: JWT-Token wird generiert', '4. Token enthaelt: User-ID, Rollen, Ablaufzeit', '', 'JWT-Validierung:', '• Signatur wird bei jedem Request geprueft', '• Abgelaufene Tokens werden abgelehnt', '• Manipulierte Tokens werden erkannt', '', 'Sicherheit: bcrypt fuer Passwort-Hashing', ], }, 'roles': { title: 'Rollen - Berechtigungsgruppen', content: [ 'Rollen buendeln Berechtigungen fuer einfache Verwaltung.', '', 'Standard-Rollen:', '• user: Basis-Zugriff, eigene Daten lesen', '• admin: Alle Verwaltungsfunktionen', '• data_protection_officer: DSGVO-Freigaben', '', 'Rollen-Hierarchie:', 'admin erbt alle user-Rechte', 'DSB hat spezielle DSGVO-Rechte', '', 'Best Practices:', '• Minimale Rechte vergeben (Least Privilege)', '• Rollen regelmaessig ueberpruefen', '• Keine direkten Berechtigungen an Benutzer', ], }, 'permissions': { title: 'Berechtigungen - Granulare Kontrolle', content: [ 'Berechtigungen definieren einzelne erlaubte Aktionen.', '', 'Format: resource:action', '• users:read - Benutzer lesen', '• users:write - Benutzer erstellen/aendern', '• consent:approve - Einwilligungen freigeben', '• dsr:process - Datenschutzanfragen bearbeiten', '', 'Zuordnung:', 'Berechtigungen → Rollen → Benutzer', '', 'Pruefung im Code:', 'if user.has_permission("consent:approve"):', ' # Aktion erlauben', ], }, 'users': { title: 'Benutzer - Identitaeten verwalten', content: [ 'Benutzer sind die Personen die das System nutzen.', '', 'Benutzer-Attribute:', '• ID: Eindeutige Kennung (UUID)', '• Email: Login-Kennung', '• Name: Anzeigename', '• Rollen: Zugewiesene Rollen', '• Status: aktiv/inaktiv', '', 'Verwaltungs-Aktionen:', '• Benutzer erstellen', '• Rollen zuweisen/entziehen', '• Benutzer deaktivieren', '• Passwort zuruecksetzen', '', 'DSGVO: Benutzer koennen Datenlöschung beantragen', ], }, 'summary': { title: 'Test-Zusammenfassung', content: [ 'Hier sehen Sie eine Uebersicht aller durchgefuehrten Tests:', '• Authentifizierungs-Endpoints', '• Rollen-Verwaltung', '• Berechtigungs-System', '• Benutzer-API', ], }, } const ARCHITECTURE_CONTEXTS: Record = { 'authentication': { layer: 'api', services: ['backend', 'consent-service'], dependencies: ['PostgreSQL', 'JWT', 'bcrypt'], dataFlow: ['Browser', 'FastAPI', 'Auth Service', 'PostgreSQL'], }, 'roles': { layer: 'service', services: ['backend'], dependencies: ['PostgreSQL', 'Roles Table', 'RBAC Middleware'], dataFlow: ['API Request', 'RBAC Check', 'Roles Table', 'Response'], }, 'permissions': { layer: 'service', services: ['backend'], dependencies: ['PostgreSQL', 'Permissions Table', 'Role-Permission Mapping'], dataFlow: ['User Action', 'Permission Check', 'DB Lookup', 'Allow/Deny'], }, 'users': { layer: 'database', services: ['backend', 'consent-service'], dependencies: ['PostgreSQL', 'Users Table', 'Valkey Session'], dataFlow: ['Admin UI', 'FastAPI', 'User Service', 'PostgreSQL'], }, } // ============================================== // Main Component // ============================================== export default function RBACWizardPage() { const [currentStep, setCurrentStep] = useState(0) const [steps, setSteps] = useState(STEPS) const [categoryResults, setCategoryResults] = useState>({}) const [fullResults, setFullResults] = useState(null) const [isLoading, setIsLoading] = useState(false) const [error, setError] = useState(null) const currentStepData = steps[currentStep] const isTestStep = currentStepData?.category !== undefined const isWelcome = currentStepData?.id === 'welcome' const isSummary = currentStepData?.id === 'summary' const runCategoryTest = async (category: string) => { setIsLoading(true) setError(null) try { const response = await fetch(`${BACKEND_URL}/api/admin/rbac-tests/${category}`, { method: 'POST', }) if (!response.ok) { throw new Error(`HTTP ${response.status}: ${response.statusText}`) } const result: TestCategoryResult = await response.json() setCategoryResults((prev) => ({ ...prev, [category]: result })) setSteps((prev) => prev.map((step) => step.category === category ? { ...step, status: result.failed === 0 ? 'completed' : 'failed' } : step ) ) } catch (err) { setError(err instanceof Error ? err.message : 'Unbekannter Fehler') } finally { setIsLoading(false) } } const runAllTests = async () => { setIsLoading(true) setError(null) try { const response = await fetch(`${BACKEND_URL}/api/admin/rbac-tests/run-all`, { method: 'POST', }) if (!response.ok) { throw new Error(`HTTP ${response.status}: ${response.statusText}`) } const results: FullTestResults = await response.json() setFullResults(results) setSteps((prev) => prev.map((step) => { if (step.category) { const catResult = results.categories.find((c) => c.category === step.category) if (catResult) { return { ...step, status: catResult.failed === 0 ? 'completed' : 'failed' } } } return step }) ) const newCategoryResults: Record = {} results.categories.forEach((cat) => { newCategoryResults[cat.category] = cat }) setCategoryResults(newCategoryResults) } catch (err) { setError(err instanceof Error ? err.message : 'Unbekannter Fehler') } finally { setIsLoading(false) } } const goToNext = () => { if (currentStep < steps.length - 1) { setSteps((prev) => prev.map((step, idx) => idx === currentStep && step.status === 'pending' ? { ...step, status: 'completed' } : step ) ) setCurrentStep((prev) => prev + 1) } } const goToPrev = () => { if (currentStep > 0) { setCurrentStep((prev) => prev - 1) } } const handleStepClick = (index: number) => { if (index <= currentStep || steps[index - 1]?.status !== 'pending') { setCurrentStep(index) } } return ( {/* Header */}
🔐

RBAC Wizard

Rollen, Berechtigungen & Authentifizierung

← Zurueck zu RBAC
{/* Stepper */}
{/* Content */}
{currentStepData?.icon}

Schritt {currentStep + 1}: {currentStepData?.name}

{currentStep + 1} von {steps.length}

{isTestStep && currentStepData?.category && ARCHITECTURE_CONTEXTS[currentStepData.category] && ( )} {error && (
Fehler: {error}
)} {isWelcome && (
)} {isTestStep && currentStepData?.category && ( runCategoryTest(currentStepData.category!)} /> )} {isSummary && (
{!fullResults ? (

Fuehren Sie alle Tests aus um eine Zusammenfassung zu sehen.

) : ( )}
)}
Diese Tests pruefen die Zugriffskontroll-Infrastruktur. Bei Fragen wenden Sie sich an das Security-Team.
) }