internal/policyapi: POST /authorize wrapt policy.Enforcer.Authorize (RBAC-02) fuer physisch getrennte Module (DMS, Mail, Archive) - reiner Wrapper, keine zweite Autorisierungslogik, 100 Stichproben beweisen Uebereinstimmung mit dem direkten Enforcer-Aufruf. Service-Auth ueber schlanken, timing-safe verglichenen Token statt moduleregistrys schwererem Credential-System (unnoetige internal/flag-Abhaengigkeit, nie mit internal/policy gemergt). Ersetzt spaeter das dokumentierte RET-06-API-Provisorium (Archive, eigenes Folgeticket). Reale Rechtevergabe-Luecke auf policy_rules gefunden und behoben (Tabelle von frueherem Testlauf unter anderem Owner). Real auf 131 deployed, beide Pfade (Allow/Deny) per curl end-to-end verifiziert.
39 lines
1.5 KiB
Go
39 lines
1.5 KiB
Go
// Package policyapi implementiert RBAC-06: einen HTTP-Endpunkt, der
|
|
// Core RBAC-02s Enforcer.Authorize für andere, physisch getrennte
|
|
// Go-Module (DMS, Mail, Archive) zugänglich macht — dieselbe
|
|
// Entscheidung wie der direkte Enforcer-Aufruf, nur per HTTP statt
|
|
// In-Process.
|
|
package policyapi
|
|
|
|
import (
|
|
"crypto/sha256"
|
|
"crypto/subtle"
|
|
"net/http"
|
|
)
|
|
|
|
// RequireServiceToken authentifiziert den Aufrufer service-zu-service
|
|
// über einen geteilten Token (Umgebungsvariable, nie im Code — siehe
|
|
// Ticket-Abschlussregel), timing-safe verglichen (dieselbe
|
|
// Referenzimplementierung wie AUD-02: subtle.ConstantTimeCompare,
|
|
// projektweite Konvention für jeden sicherheitsrelevanten Vergleich).
|
|
// Bewusst KEIN vollwertiges Credential-Ausstellungssystem
|
|
// (moduleregistry.Provision/Authenticate) — dieser Endpunkt braucht
|
|
// keine Modul-Aktivierungsverwaltung, nur einen einzelnen, über
|
|
// Konfiguration verteilten Zugangsschlüssel (Akzeptanzkriterium 2).
|
|
func RequireServiceToken(expectedToken string, next http.HandlerFunc) http.HandlerFunc {
|
|
return func(w http.ResponseWriter, r *http.Request) {
|
|
got := r.Header.Get("X-Service-Token")
|
|
if got == "" || !timingSafeEqual(got, expectedToken) {
|
|
http.Error(w, "authentifizierung fehlgeschlagen: gültiges X-Service-Token erforderlich", http.StatusUnauthorized)
|
|
return
|
|
}
|
|
next(w, r)
|
|
}
|
|
}
|
|
|
|
func timingSafeEqual(a, b string) bool {
|
|
ha := sha256.Sum256([]byte(a))
|
|
hb := sha256.Sum256([]byte(b))
|
|
return subtle.ConstantTimeCompare(ha[:], hb[:]) == 1
|
|
}
|