Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01QPsyieCYwvbUBsnN598SbP
63 lines
2.0 KiB
Go
63 lines
2.0 KiB
Go
package auth
|
|
|
|
import (
|
|
"context"
|
|
"net/http"
|
|
)
|
|
|
|
const CookieName = "nexarch_session"
|
|
|
|
type contextKey int
|
|
|
|
const claimsContextKey contextKey = iota
|
|
|
|
// RequireAuth schuetzt eine Route: ohne gueltiges, nicht abgelaufenes UND
|
|
// nicht widerrufenes Token im Session-Cookie wird 401 zurueckgegeben und der
|
|
// Handler nicht aufgerufen (IAM-02 Akzeptanzkriterium 3, IAM-17
|
|
// Akzeptanzkriterium 3: Widerrufspruefung zusaetzlich zur Signatur).
|
|
//
|
|
// revocation ist bewusst variadisch (0 oder 1 Wert) statt eines Pflicht-
|
|
// parameters: mehrere andere Kacheln (RBAC, TOTP, OIDC, Benachrichtigungs-
|
|
// praeferenzen) rufen RequireAuth bereits mit der bisherigen 2-Parameter-
|
|
// Form auf, und ein Pflicht-Widerrufscheck ist ausdruecklich nicht Teil
|
|
// dieser Kachel fuer JENE Module — hier geht es nur um IAM-02/IAM-17. Ohne
|
|
// uebergebenen RevocationChecker entfaellt nur die zusaetzliche Pruefung,
|
|
// die Signaturpruefung bleibt unveraendert.
|
|
func RequireAuth(issuer *TokenIssuer, next http.HandlerFunc, revocation ...RevocationChecker) http.HandlerFunc {
|
|
return func(w http.ResponseWriter, r *http.Request) {
|
|
cookie, err := r.Cookie(CookieName)
|
|
if err != nil {
|
|
http.Error(w, "nicht angemeldet", http.StatusUnauthorized)
|
|
return
|
|
}
|
|
|
|
claims, err := issuer.Verify(cookie.Value)
|
|
if err != nil {
|
|
http.Error(w, "nicht angemeldet", http.StatusUnauthorized)
|
|
return
|
|
}
|
|
|
|
if len(revocation) > 0 && revocation[0] != nil {
|
|
revoked, err := revocation[0].IsRevoked(r.Context(), claims)
|
|
if err != nil {
|
|
http.Error(w, "interner fehler bei der widerrufspruefung", http.StatusInternalServerError)
|
|
return
|
|
}
|
|
if revoked {
|
|
http.Error(w, "nicht angemeldet", http.StatusUnauthorized)
|
|
return
|
|
}
|
|
}
|
|
|
|
ctx := context.WithValue(r.Context(), claimsContextKey, claims)
|
|
next(w, r.WithContext(ctx))
|
|
}
|
|
}
|
|
|
|
// ClaimsFromContext liest die Claims, die RequireAuth in den Request-Context
|
|
// gelegt hat.
|
|
func ClaimsFromContext(ctx context.Context) (*Claims, bool) {
|
|
c, ok := ctx.Value(claimsContextKey).(*Claims)
|
|
return c, ok
|
|
}
|