mirror of
https://github.com/shankar0123/certctl.git
synced 2026-06-07 16:01:30 +00:00
auth-bundle-1 Phase 0: extract internal/auth/ from middleware package
Bundle 1 / Phase 0: pure refactor splitting auth surface out of internal/api/middleware so Bundle 2 (OIDC + sessions) and the broader RBAC primitive (roles, permissions, scoped grants) have a clean home. Moved to internal/auth/: NamedAPIKey, HashAPIKey, AuthConfig, NewAuthWithNamedKeys, NewAuth, UserKey, AdminKey, GetUser, IsAdmin. Added testfixtures.go (WithActor / WithAdmin / WithActorAdmin) so handler tests don't construct context manually. Stayed in internal/api/middleware/: RequestID, Logging, NewLogging, Recovery, RateLimitConfig, NewRateLimiter (now imports auth.GetUser for per-user keying per audit Category C), CORSConfig, NewCORS, ContentType, CORS, GetRequestID, responseWriter, Chain, audit middleware (now imports auth.GetUser). Updated 22 caller files across cmd/, internal/api/handler/, internal/api/middleware/, internal/mcp/. Existing m008_admin_gate_test.go now scans for auth.IsAdmin( substring; Phase 3 will further evolve to track auth.RequirePermission. Behavior unchanged: all handler / middleware / service / connector / cmd / mcp tests pass with no test-logic edits, only import-path renames. Phase 0 exit criteria: internal/auth/ exists with 6 files; middleware.go went 575 -> 422 lines (auth-related ~150 lines moved out); grep -rE 'middleware\.(GetUser|IsAdmin|UserKey|AdminKey|NamedAPIKey|HashAPIKey|NewAuth)' returns 0 hits; context.WithValue(.*middleware.UserKey/AdminKey) returns 0 hits; go vet ./... clean; go test -short ./... green across all packages tested. Branch: dev/auth-bundle-1. Per cowork/auth-bundle-1-prompt.md, do not merge to master without (1) make verify green, (2) >= 2 external testers confirm, (3) >= 90% coverage on internal/auth/ in .github/coverage-thresholds.yml.
This commit is contained in:
@@ -9,6 +9,7 @@ import (
|
||||
"time"
|
||||
|
||||
"github.com/certctl-io/certctl/internal/api/middleware"
|
||||
"github.com/certctl-io/certctl/internal/auth"
|
||||
"github.com/certctl-io/certctl/internal/crypto/signer"
|
||||
"github.com/certctl-io/certctl/internal/domain"
|
||||
"github.com/certctl-io/certctl/internal/service"
|
||||
@@ -36,7 +37,7 @@ type IntermediateCAServicer interface {
|
||||
// All routes are pinned at /api/v1/issuers/{id}/intermediates and
|
||||
// /api/v1/intermediates/{id}.
|
||||
//
|
||||
// Admin gate: every method calls middleware.IsAdmin first and surfaces
|
||||
// Admin gate: every method calls auth.IsAdmin first and surfaces
|
||||
// HTTP 403 for non-admin Bearer callers (M-003 admin-gating pattern,
|
||||
// matches AdminCRLCacheHandler / AdminESTHandler / AdminSCEPIntuneHandler).
|
||||
// CA hierarchy management is a high-blast-radius surface — adding a
|
||||
@@ -111,7 +112,7 @@ func (h IntermediateCAHandler) Create(w http.ResponseWriter, r *http.Request) {
|
||||
Error(w, http.StatusMethodNotAllowed, "Method not allowed")
|
||||
return
|
||||
}
|
||||
if !middleware.IsAdmin(r.Context()) {
|
||||
if !auth.IsAdmin(r.Context()) {
|
||||
Error(w, http.StatusForbidden, "Admin access required")
|
||||
return
|
||||
}
|
||||
@@ -122,7 +123,7 @@ func (h IntermediateCAHandler) Create(w http.ResponseWriter, r *http.Request) {
|
||||
ErrorWithRequestID(w, http.StatusBadRequest, "issuer id required", requestID)
|
||||
return
|
||||
}
|
||||
actor, _ := r.Context().Value(middleware.UserKey{}).(string)
|
||||
actor, _ := r.Context().Value(auth.UserKey{}).(string)
|
||||
if actor == "" {
|
||||
ErrorWithRequestID(w, http.StatusUnauthorized,
|
||||
"authentication required", requestID)
|
||||
@@ -211,7 +212,7 @@ func (h IntermediateCAHandler) List(w http.ResponseWriter, r *http.Request) {
|
||||
Error(w, http.StatusMethodNotAllowed, "Method not allowed")
|
||||
return
|
||||
}
|
||||
if !middleware.IsAdmin(r.Context()) {
|
||||
if !auth.IsAdmin(r.Context()) {
|
||||
Error(w, http.StatusForbidden, "Admin access required")
|
||||
return
|
||||
}
|
||||
@@ -237,7 +238,7 @@ func (h IntermediateCAHandler) Get(w http.ResponseWriter, r *http.Request) {
|
||||
Error(w, http.StatusMethodNotAllowed, "Method not allowed")
|
||||
return
|
||||
}
|
||||
if !middleware.IsAdmin(r.Context()) {
|
||||
if !auth.IsAdmin(r.Context()) {
|
||||
Error(w, http.StatusForbidden, "Admin access required")
|
||||
return
|
||||
}
|
||||
@@ -270,7 +271,7 @@ func (h IntermediateCAHandler) Retire(w http.ResponseWriter, r *http.Request) {
|
||||
Error(w, http.StatusMethodNotAllowed, "Method not allowed")
|
||||
return
|
||||
}
|
||||
if !middleware.IsAdmin(r.Context()) {
|
||||
if !auth.IsAdmin(r.Context()) {
|
||||
Error(w, http.StatusForbidden, "Admin access required")
|
||||
return
|
||||
}
|
||||
@@ -281,7 +282,7 @@ func (h IntermediateCAHandler) Retire(w http.ResponseWriter, r *http.Request) {
|
||||
ErrorWithRequestID(w, http.StatusBadRequest, "id required", requestID)
|
||||
return
|
||||
}
|
||||
actor, _ := r.Context().Value(middleware.UserKey{}).(string)
|
||||
actor, _ := r.Context().Value(auth.UserKey{}).(string)
|
||||
if actor == "" {
|
||||
ErrorWithRequestID(w, http.StatusUnauthorized,
|
||||
"authentication required", requestID)
|
||||
|
||||
Reference in New Issue
Block a user