mirror of
https://github.com/shankar0123/certctl.git
synced 2026-06-10 20:48:57 +00:00
feat(auth): backend endpoints for MED-7 + MED-11 + MED-12
Audit 2026-05-10 MED-7 + MED-11 + MED-12 backend halves.
WHAT.
Three new admin-gated endpoints:
GET /api/v1/auth/oidc/providers/{id}/jwks-status (auth.oidc.list) — MED-7
GET /api/v1/auth/users (auth.user.read) — MED-11
DELETE /api/v1/auth/users/{id} (auth.user.deactivate) — MED-11
GET /api/v1/auth/runtime-config (auth.role.assign) — MED-12
MED-7 — JWKS health surface
- providerEntry gains 4 counters (statsMu, lastRefreshAt, refreshCount,
lastError, rejectedJWSCount) updated under sync.Mutex
- RefreshKeys increments refreshCount + records lastRefreshAt
- New JWKSStatus(ctx, providerID) returns *JWKSStatusSnapshot —
surfaced via the new endpoint
- CurrentKIDs intentionally empty (go-oidc's internal JWKS cache
isn't exposed); shape kept for forward compat
MED-11 — federated-user admin
- AuthUsersHandler.List with optional ?oidc_provider_id filter
- AuthUsersHandler.Deactivate sets users.deactivated_at + cascade-
revokes sessions via UserSessionsRevoker (best-effort; revoke
failure does NOT roll back the deactivation)
- Idempotent: re-deactivating an already-deactivated user is a no-op
MED-12 — runtime config
- AuthRuntimeConfigHandler.Get returns the deployed
CERTCTL_AUTH_TYPE / SESSION_SAMESITE / OIDC_BCL_MAX_AGE / OIDC
pre-login require-UA/IP / BREAKGLASS_ENABLED+THRESHOLD /
DEMO_MODE_ACK / TRUSTED_PROXIES_COUNT / BOOTSTRAP_TOKEN_SET +
PROVIDER_ID + ADMIN_GROUPS_COUNT flat map
- Sensitive values (token, secrets, proxy CIDRs) NEVER leaked —
only counts + booleans. Token presence surfaced as 'set/unset'
- Gated auth.role.assign (admin-class) so non-admins can't
enumerate the deployment's auth knobs
cmd/server/main.go wires all three handlers into HandlerRegistry.
internal/api/router/router.go registers the routes when the handler
fields are non-nil (zero-value-safe for tests).
VERIFY.
- go vet ./internal/api/... ./internal/auth/... ./internal/repository/... PASS
- go build ./cmd/server/... PASS
- go test -short -count=1 ./internal/auth/oidc/... PASS (4.1s)
- go test -short -count=1 ./internal/api/handler/... PASS (4.1s)
GUI halves for MED-7 + MED-11 + MED-12 are the GUI batch (pending).
Refs: cowork/auth-bundles-audit-2026-05-10.md MED-7, MED-11, MED-12
cowork/auth-bundles-fixes-2026-05-10/HANDOFF.md items 11 14 15
This commit is contained in:
@@ -303,6 +303,21 @@ type HandlerRegistry struct {
|
||||
// Optional — when nil the routes are not registered.
|
||||
AuthBreakglass *handler.AuthBreakglassHandler
|
||||
|
||||
// AuthUsers handles the MED-11 federated-user admin surface
|
||||
// (GET /api/v1/auth/users; DELETE /api/v1/auth/users/{id}).
|
||||
// Optional — when nil the routes are not registered.
|
||||
AuthUsers *handler.AuthUsersHandler
|
||||
|
||||
// AuthRuntimeConfig handles the MED-12 admin-only runtime
|
||||
// config read endpoint (GET /api/v1/auth/runtime-config).
|
||||
// Optional — when nil the route is not registered.
|
||||
AuthRuntimeConfig *handler.AuthRuntimeConfigHandler
|
||||
|
||||
// AuthOIDCJWKSStatus handles the MED-7 per-provider JWKS health
|
||||
// endpoint (GET /api/v1/auth/oidc/providers/{id}/jwks-status).
|
||||
// Optional — when nil the route is not registered.
|
||||
AuthOIDCJWKSStatus *handler.AuthOIDCJWKSStatusHandler
|
||||
|
||||
// IntermediateCAs handles the admin-gated CA-hierarchy management
|
||||
// surface under /api/v1/issuers/{id}/intermediates and
|
||||
// /api/v1/intermediates/{id}. Rank 8 of the 2026-05-03 deep-
|
||||
@@ -464,6 +479,28 @@ func (r *Router) RegisterHandlers(reg HandlerRegistry) {
|
||||
// reachability without persisting.
|
||||
r.Register("POST /api/v1/auth/oidc/test", rbacGate(reg.Checker, "auth.oidc.create", reg.AuthSessionOIDC.TestProvider))
|
||||
|
||||
// Audit 2026-05-10 MED-7 — JWKS health surface.
|
||||
if reg.AuthOIDCJWKSStatus != nil {
|
||||
r.Register("GET /api/v1/auth/oidc/providers/{id}/jwks-status",
|
||||
rbacGate(reg.Checker, "auth.oidc.list", reg.AuthOIDCJWKSStatus.Status))
|
||||
}
|
||||
|
||||
// Audit 2026-05-10 MED-11 — federated-user admin surface.
|
||||
if reg.AuthUsers != nil {
|
||||
r.Register("GET /api/v1/auth/users",
|
||||
rbacGate(reg.Checker, "auth.user.read", reg.AuthUsers.List))
|
||||
r.Register("DELETE /api/v1/auth/users/{id}",
|
||||
rbacGate(reg.Checker, "auth.user.deactivate", reg.AuthUsers.Deactivate))
|
||||
}
|
||||
|
||||
// Audit 2026-05-10 MED-12 — auth runtime config read.
|
||||
// Gated auth.role.assign (admin-class) so non-admins can't
|
||||
// enumerate the deployment's auth knobs.
|
||||
if reg.AuthRuntimeConfig != nil {
|
||||
r.Register("GET /api/v1/auth/runtime-config",
|
||||
rbacGate(reg.Checker, "auth.role.assign", reg.AuthRuntimeConfig.Get))
|
||||
}
|
||||
|
||||
// Group-mapping CRUD.
|
||||
r.Register("GET /api/v1/auth/oidc/group-mappings", rbacGate(reg.Checker, "auth.oidc.list", reg.AuthSessionOIDC.ListGroupMappings))
|
||||
r.Register("POST /api/v1/auth/oidc/group-mappings", rbacGate(reg.Checker, "auth.oidc.edit", reg.AuthSessionOIDC.AddGroupMapping))
|
||||
|
||||
Reference in New Issue
Block a user