ProofedMesh/services/admin-api/internal/auth/context.go
CTO (Paperclip) 9f1eb84032
All checks were successful
validate / Go (vet + test) (push) Successful in 23s
validate / Rego (opa fmt + opa test) (push) Successful in 15s
validate / JSON Schema (ajv) (push) Successful in 20s
admin-api: Pocket-ID session-cookie verifier (OIDC Authorization-Code + PKCE, JWKS, group check)
- 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>
2026-10-25 18:10:02 +00:00

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 ""
}