Board-Entscheidung: Backend-API zuerst, echtes Next.js-Frontend als separates Folgeticket - vermeidet Pseudo-Frontend-Protokoll. internal/retentionapi: 4 Endpunkte (anlegen/aendern, deaktivieren, liste, vorschau), Vorschau nutzt dieselbe ListExpiringObjects-Funktion wie RET-02s periodischer Job (keine Doppel-Implementierung). RequireRole ist AUSDRUECKLICH kein RBAC-02-Ersatz, sondern ein dokumentiertes Provisorium (Header-Check) - RBAC-02 ist reiner Core-interner Go-Code ohne HTTP-Schnittstelle fuer andere Module, derselbe Befund wie FDN-03/FDN-09. Provisorium real getestet inkl. Negativfall (403 ohne/mit falscher Rolle). retention_class_rules um active-Flag erweitert (deaktivieren ohne Historienverlust). Real auf 131 deployed und per curl end-to-end verifiziert.
49 lines
1.9 KiB
Go
49 lines
1.9 KiB
Go
// Package retentionapi implementiert RET-06-API: die Backend-Seite der
|
|
// Aufbewahrungsfristen-Konfigurationsoberfläche (CRUD auf
|
|
// Aufbewahrungsklassen + Vorschauliste ablaufender Objekte). Das
|
|
// Next.js-Frontend selbst ist NICHT Teil dieses Tickets (Board-
|
|
// Entscheidung: Backend-API zuerst, Frontend als eigenes Folgeticket).
|
|
package retentionapi
|
|
|
|
import (
|
|
"net/http"
|
|
"strings"
|
|
)
|
|
|
|
// requiredRoleHeader ist der Header-Name des PROVISORISCHEN Rollen-
|
|
// Checks (siehe RequireRole-Dokumentation).
|
|
const requiredRoleHeader = "X-Admin-Roles"
|
|
|
|
// RequireRole ist ein PROVISORISCHER Rollen-Check, KEIN RBAC-02-Aufruf.
|
|
//
|
|
// Core RBAC-02 (internal/policy, Enforcer.Authorize) ist reiner
|
|
// Go-Code innerhalb des Core-Moduls, hat keine HTTP-Schnittstelle, über
|
|
// die Archive (physisch getrenntes Go-Modul) es aufrufen könnte —
|
|
// derselbe "gefunden, aber nicht modulübergreifend verdrahtet"-Befund
|
|
// wie bei Core FDN-03/FDN-09. Bis ein Core-seitiger HTTP-Wrapper um
|
|
// RBAC-02 existiert (eigenes, künftiges Core-Ticket, z. B. RBAC-06),
|
|
// prüft dieser Middleware NUR einen einfachen, selbst gesetzten Header
|
|
// (`X-Admin-Roles`, kommagetrennt) auf das Vorhandensein der
|
|
// geforderten Rolle — KEINE echte Autorisierung gegen Core, leicht zu
|
|
// fälschen von jedem, der den Header selbst setzen kann. Muss ersetzt
|
|
// werden, sobald der Core-HTTP-Wrapper existiert.
|
|
func RequireRole(requiredRole string, next http.HandlerFunc) http.HandlerFunc {
|
|
return func(w http.ResponseWriter, r *http.Request) {
|
|
roles := r.Header.Get(requiredRoleHeader)
|
|
if !containsRole(roles, requiredRole) {
|
|
http.Error(w, "zugriff verweigert: rolle "+requiredRole+" erforderlich (provisorischer check, siehe RequireRole)", http.StatusForbidden)
|
|
return
|
|
}
|
|
next(w, r)
|
|
}
|
|
}
|
|
|
|
func containsRole(commaSeparated, role string) bool {
|
|
for _, r := range strings.Split(commaSeparated, ",") {
|
|
if strings.TrimSpace(r) == role {
|
|
return true
|
|
}
|
|
}
|
|
return false
|
|
}
|