go-wiki/middleware/auth.go
2026-07-14 20:46:19 +02:00

43 lines
1.6 KiB
Go

// Package middleware enthält HTTP-Middleware — das sind Funktionen die sich
// "vor" den eigentlichen Handlern schalten und z.B. Authentifizierung prüfen.
package middleware
import (
"net/http"
"strings"
"wiki/handler"
)
// RequireTeamOrAdminKey schützt /api/upload, /api/delete und /mcp.
//
// Der Bearer-Key wird gegen die TeamRegistry aufgelöst: ein Team-Key beschränkt
// den Request auf das eigene Team, der globale Admin-Key (ADMIN_TOKEN) erlaubt
// Zugriff auf jedes Team, muss dafür aber explizit sagen welches (siehe api.go:
// Formfeld/Query-Param "team"; mcp.go: Header "X-Wiki-Team").
//
// Das aufgelöste Team (oder der Admin-Status) landet im Request-Context —
// siehe handler.WithTeam / handler.TeamFromContext.
func RequireTeamOrAdminKey(next http.Handler, registry *handler.TeamRegistry) http.Handler {
return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
authHeader := r.Header.Get("Authorization")
if !strings.HasPrefix(authHeader, "Bearer ") {
http.Error(w, "Authorization header fehlt", http.StatusUnauthorized)
return
}
key := strings.TrimPrefix(authHeader, "Bearer ")
// Timing-sicherer Vergleich passiert bereits innerhalb von registry.Resolve
// (subtle.ConstantTimeCompare, siehe registry.go) — verhindert dass ein
// Angreifer anhand der Antwortzeit erraten kann wie viele Zeichen seines
// Keys korrekt sind.
team, isAdmin, ok := registry.Resolve(key)
if !ok {
http.Error(w, "Ungültiger Key", http.StatusUnauthorized)
return
}
next.ServeHTTP(w, r.WithContext(handler.WithTeam(r.Context(), team, isAdmin)))
})
}