This repository has been archived on 2026-02-15. You can view files and clone it. You cannot open issues or pull requests or push a commit.
Files
breakpilot-pwa/docs-src/architecture/auth-system.md
Benjamin Admin 21a844cb8a fix: Restore all files lost during destructive rebase
A previous `git pull --rebase origin main` dropped 177 local commits,
losing 3400+ files across admin-v2, backend, studio-v2, website,
klausur-service, and many other services. The partial restore attempt
(660295e2) only recovered some files.

This commit restores all missing files from pre-rebase ref 98933f5e
while preserving post-rebase additions (night-scheduler, night-mode UI,
NightModeWidget dashboard integration).

Restored features include:
- AI Module Sidebar (FAB), OCR Labeling, OCR Compare
- GPU Dashboard, RAG Pipeline, Magic Help
- Klausur-Korrektur (8 files), Abitur-Archiv (5+ files)
- Companion, Zeugnisse-Crawler, Screen Flow
- Full backend, studio-v2, website, klausur-service
- All compliance SDKs, agent-core, voice-service
- CI/CD configs, documentation, scripts

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-02-09 09:51:32 +01:00

10 KiB

BreakPilot Authentifizierung & Autorisierung

Uebersicht

BreakPilot verwendet einen Hybrid-Ansatz fuer Authentifizierung und Autorisierung:

┌─────────────────────────────────────────────────────────────────────────┐
│                        AUTHENTIFIZIERUNG                                 │
│                     "Wer bist du?"                                       │
│  ┌────────────────────────────────────────────────────────────────────┐ │
│  │                    HybridAuthenticator                              │ │
│  │  ┌─────────────────────┐      ┌─────────────────────────────────┐  │ │
│  │  │   Keycloak          │      │   Lokales JWT                   │  │ │
│  │  │   (Produktion)      │  OR  │   (Entwicklung)                 │  │ │
│  │  │   RS256 + JWKS      │      │   HS256 + Secret                │  │ │
│  │  └─────────────────────┘      └─────────────────────────────────┘  │ │
│  └────────────────────────────────────────────────────────────────────┘ │
└─────────────────────────────────────────────────────────────────────────┘
                                    │
                                    ▼
┌─────────────────────────────────────────────────────────────────────────┐
│                         AUTORISIERUNG                                    │
│                      "Was darfst du?"                                    │
│  ┌────────────────────────────────────────────────────────────────────┐ │
│  │                    rbac.py (Eigenentwicklung)                       │ │
│  │  ┌─────────────────┐  ┌─────────────────┐  ┌───────────────────┐   │ │
│  │  │ Rollen-Hierarchie│  │ PolicySet       │  │ DEFAULT_PERMISSIONS│   │ │
│  │  │ 15+ Rollen       │  │ Bundesland-     │  │ Matrix            │   │ │
│  │  │ - Erstkorrektor  │  │ spezifisch      │  │ Rolle→Ressource→  │   │ │
│  │  │ - Klassenlehrer  │  │ - Niedersachsen │  │ Aktion            │   │ │
│  │  │ - Schulleitung   │  │ - Bayern        │  │                   │   │ │
│  │  └─────────────────┘  └─────────────────┘  └───────────────────┘   │ │
│  └────────────────────────────────────────────────────────────────────┘ │
└─────────────────────────────────────────────────────────────────────────┘

Warum dieser Ansatz?

Alternative Loesungen (verworfen)

Tool Problem fuer BreakPilot
Casbin Zu generisch fuer Bundesland-spezifische Policies
Cerbos Overhead: Externer PDP-Service fuer ~15 Rollen ueberdimensioniert
OpenFGA Zanzibar-Modell optimiert fuer Graph-Beziehungen, nicht Hierarchien
Keycloak RBAC Kann keine ressourcen-spezifischen Zuweisungen (User X ist Erstkorrektor fuer Package Y)

Vorteile des Hybrid-Ansatzes

  1. Keycloak fuer Authentifizierung:

    • Bewährtes IAM-System
    • SSO, Federation, MFA
    • Apache-2.0 Lizenz
  2. Eigenes rbac.py fuer Autorisierung:

    • Domaenenspezifische Logik (Korrekturkette, Zeugnis-Workflow)
    • Bundesland-spezifische Regeln
    • Zeitlich begrenzte Zuweisungen
    • Key-Sharing fuer verschluesselte Klausuren

Authentifizierung (auth/keycloak_auth.py)

Konfiguration

# Entwicklung: Lokales JWT (Standard)
JWT_SECRET=your-secret-key

# Produktion: Keycloak
KEYCLOAK_SERVER_URL=https://keycloak.breakpilot.app
KEYCLOAK_REALM=breakpilot
KEYCLOAK_CLIENT_ID=breakpilot-backend
KEYCLOAK_CLIENT_SECRET=your-client-secret

Token-Erkennung

Der HybridAuthenticator erkennt automatisch den Token-Typ:

# Keycloak-Token (RS256)
{
  "iss": "https://keycloak.breakpilot.app/realms/breakpilot",
  "sub": "user-uuid",
  "realm_access": {"roles": ["teacher", "admin"]},
  ...
}

# Lokales JWT (HS256)
{
  "iss": "breakpilot",
  "user_id": "user-uuid",
  "role": "admin",
  ...
}

FastAPI Integration

from auth import get_current_user

@app.get("/api/protected")
async def protected_endpoint(user: dict = Depends(get_current_user)):
    # user enthält: user_id, email, role, realm_roles, tenant_id
    return {"user_id": user["user_id"]}

Autorisierung (klausur-service/backend/rbac.py)

Rollen (15+)

Rolle Beschreibung Bereich
erstkorrektor Erster Prüfer Klausur
zweitkorrektor Zweiter Prüfer Klausur
drittkorrektor Dritter Prüfer Klausur
klassenlehrer Klassenleitung Zeugnis
fachlehrer Fachlehrkraft Noten
fachvorsitz Fachkonferenz-Leitung Fachschaft
schulleitung Schulleiter/in Schule
zeugnisbeauftragter Zeugnis-Koordination Zeugnis
sekretariat Verwaltung Schule
data_protection_officer DSB DSGVO
...

Ressourcentypen (25+)

class ResourceType(str, Enum):
    EXAM_PACKAGE = "exam_package"         # Klausurpaket
    STUDENT_SUBMISSION = "student_submission"
    CORRECTION = "correction"
    ZEUGNIS = "zeugnis"
    FACHNOTE = "fachnote"
    KOPFNOTE = "kopfnote"
    BEMERKUNG = "bemerkung"
    ...

Aktionen (17)

class Action(str, Enum):
    CREATE = "create"
    READ = "read"
    UPDATE = "update"
    DELETE = "delete"
    SIGN_OFF = "sign_off"        # Freigabe
    BREAK_GLASS = "break_glass"  # Notfall-Zugriff
    SHARE_KEY = "share_key"      # Schlüssel teilen
    ...

Permission-Pruefung

from klausur_service.backend.rbac import PolicyEngine

engine = PolicyEngine()

# Pruefe ob User X Klausur Y korrigieren darf
allowed = engine.check_permission(
    user_id="user-uuid",
    action=Action.UPDATE,
    resource_type=ResourceType.CORRECTION,
    resource_id="klausur-uuid"
)

Bundesland-spezifische Policies

@dataclass
class PolicySet:
    bundesland: str
    abitur_type: str  # "landesabitur" | "zentralabitur"

    # Korrekturkette
    korrektoren_anzahl: int  # 2 oder 3
    anonyme_erstkorrektur: bool

    # Sichtbarkeit
    zk_visibility_mode: ZKVisibilityMode  # BLIND | SEMI | FULL
    eh_visibility_mode: EHVisibilityMode

    # Zeugnis
    kopfnoten_enabled: bool
    ...

Beispiel: Niedersachsen

NIEDERSACHSEN_POLICY = PolicySet(
    bundesland="niedersachsen",
    abitur_type="landesabitur",
    korrektoren_anzahl=2,
    anonyme_erstkorrektur=True,
    zk_visibility_mode=ZKVisibilityMode.BLIND,
    eh_visibility_mode=EHVisibilityMode.SUMMARY_ONLY,
    kopfnoten_enabled=True,
)

Workflow-Beispiele

Klausurkorrektur-Workflow

1. Lehrer laedt Klausuren hoch
   └── Rolle: "lehrer" + Action.CREATE auf EXAM_PACKAGE

2. Erstkorrektor korrigiert
   └── Rolle: "erstkorrektor" (ressourcen-spezifisch) + Action.UPDATE auf CORRECTION

3. Zweitkorrektor ueberprueft
   └── Rolle: "zweitkorrektor" + Action.READ auf CORRECTION
   └── Policy: zk_visibility_mode bestimmt Sichtbarkeit

4. Drittkorrektor (bei Abweichung)
   └── Rolle: "drittkorrektor" + Action.SIGN_OFF

Zeugnis-Workflow

1. Fachlehrer traegt Noten ein
   └── Rolle: "fachlehrer" + Action.CREATE auf FACHNOTE

2. Klassenlehrer prueft
   └── Rolle: "klassenlehrer" + Action.READ auf ZEUGNIS
   └── Action.SIGN_OFF freigeben

3. Zeugnisbeauftragter final
   └── Rolle: "zeugnisbeauftragter" + Action.SIGN_OFF

4. Schulleitung unterzeichnet
   └── Rolle: "schulleitung" + Action.SIGN_OFF

Dateien

Datei Beschreibung
backend/auth/__init__.py Auth-Modul Exports
backend/auth/keycloak_auth.py Hybrid-Authentifizierung
klausur-service/backend/rbac.py Autorisierungs-Engine
backend/rbac_api.py REST API fuer Rollenverwaltung

Konfiguration

Entwicklung (ohne Keycloak)

# .env
ENVIRONMENT=development
JWT_SECRET=dev-secret-32-chars-minimum-here

Produktion (mit Keycloak)

# .env
ENVIRONMENT=production
JWT_SECRET=<openssl rand -hex 32>
KEYCLOAK_SERVER_URL=https://keycloak.breakpilot.app
KEYCLOAK_REALM=breakpilot
KEYCLOAK_CLIENT_ID=breakpilot-backend
KEYCLOAK_CLIENT_SECRET=<from keycloak admin console>

Sicherheitshinweise

  1. Secrets niemals im Code - Immer Umgebungsvariablen verwenden
  2. JWT_SECRET in Produktion - Mindestens 32 Bytes, generiert mit openssl rand -hex 32
  3. Keycloak HTTPS - KEYCLOAK_VERIFY_SSL=true in Produktion
  4. Token-Expiration - Keycloak-Tokens kurz halten (5-15 Minuten)
  5. Audit-Trail - Alle Berechtigungspruefungen werden geloggt