- internal/auth/pocket_id.go: Middleware mit /login + /callback, OIDC-Discovery + JWKS-Cache, RS256-Signatur-Prüfung, PKCE S256, AES-256-GCM-versiegeltes Session-Cookie, Erzwingung von Gruppenmitgliedschaft 'proofedmesh-admin' (konfigurierbar). Protect(h) setzt WithPrincipal(sub) + WithSession(sid) auf ctx; fehlendes/ungültiges Cookie → 302 nach /login (next= bewahrt). - internal/auth/context.go: WithPrincipal/WithSession/PrincipalFrom /SessionFrom aus httpapi/rates.go in internal/auth gezogen, damit auth und httpapi dieselben Kontext-Keys teilen (keine import cycle: httpapi importiert auth). - httpapi/rates.go: delegiert jetzt an auth.*; die Shim-Exports WithPrincipal/WithSession bleiben für bestehende Tests. - cmd/admin-api/main.go: Pocket-ID-Middleware aktivieren, sobald -oidc-client-id, -oidc-client-secret, -oidc-redirect-url und -session-cookie-secret gesetzt sind; ohne sie bleibt das Stub-Admin-Prinzipal (bestehendes Verhalten für Dev-Mode). - Tests (10 neue, 36/36 insgesamt grün, go vet clean): httptest-Mock-Pocket-ID mit JWKS + /token-Endpoint deckt den vollständigen Flow ab, inkl. missing cookie, falsche Gruppe, Nonce/State-Mismatch, Audience-Mismatch, abgelaufenes ID-Token, unbekannte kid, und Session-Ablauf nach TTL. - README: Auth-Abschnitt + Konfigurations-Flags aktualisiert. DEV-603 Co-Authored-By: Paperclip <noreply@paperclip.ing>
38 lines
1.3 KiB
Go
38 lines
1.3 KiB
Go
// Package auth holds authentication wiring for admin-api: Pocket-ID
|
|
// Authorization-Code / session-cookie middleware and the context accessors
|
|
// used by downstream handlers to read the authenticated principal.
|
|
package auth
|
|
|
|
import "context"
|
|
|
|
type principalKey struct{}
|
|
type sessionKey struct{}
|
|
|
|
// WithPrincipal attaches the authenticated admin user (`sub` claim) to ctx.
|
|
func WithPrincipal(ctx context.Context, sub string) context.Context {
|
|
return context.WithValue(ctx, principalKey{}, sub)
|
|
}
|
|
|
|
// WithSession attaches the Pocket-ID session identifier (`sid` claim or
|
|
// server-side session id) to ctx. Downstream code carries it into
|
|
// attestations so audits show which session triggered the change.
|
|
func WithSession(ctx context.Context, sessionID string) context.Context {
|
|
return context.WithValue(ctx, sessionKey{}, sessionID)
|
|
}
|
|
|
|
// PrincipalFrom returns the `sub` previously set by WithPrincipal, or
|
|
// "unknown" if the context never passed through the auth middleware.
|
|
func PrincipalFrom(ctx context.Context) string {
|
|
if v, ok := ctx.Value(principalKey{}).(string); ok {
|
|
return v
|
|
}
|
|
return "unknown"
|
|
}
|
|
|
|
// SessionFrom returns the session id previously set by WithSession, or "".
|
|
func SessionFrom(ctx context.Context) string {
|
|
if v, ok := ctx.Value(sessionKey{}).(string); ok {
|
|
return v
|
|
}
|
|
return ""
|
|
}
|