Source identity
| Field | Recorded value |
|---|---|
| Source type | GitHub source |
| Original record | Janady13/missionmatch / internal/platform/security/rbac_middleware.go |
| Date | Not specified in source |
| Repository | Janady13/missionmatch |
| Revision | 720d47fae476b0d38477ae4401697d372b1ea2bc |
| Branch | feature/opportunity-to-outcome |
| Path or archive member | internal/platform/security/rbac_middleware.go |
| Original SHA-256 | d11a3aa629a9115329627d5538a5cb67a21807a575990fa79a1c919f9d820fdf |
| Git blob SHA | f83eaeea025d2bb350f5547a673d886c5e47777f |
| Reading-copy SHA-256 | d11a3aa629a9115329627d5538a5cb67a21807a575990fa79a1c919f9d820fdf |
Recovered source transcript
Download complete source text ↓67 lines · 2.8 KB
package security
import (
"net/http"
"github.com/missionworkforce/missionmatch/internal/platform/tenant"
)
// RequireCapability gates a route on a capability. The role is read from the validated session in
// context (set by the auth middleware), never from the request body or a header, so authorization
// cannot be spoofed and is enforced at the API rather than by hiding a control in the UI. A caller
// without the capability gets 403 before the handler runs.
func RequireCapability(cap Capability) func(http.Handler) http.Handler {
return func(next http.Handler) http.Handler {
return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
p, ok := tenant.UserFromContext(r.Context())
if !ok || !Has(Role(p.Role), cap) {
http.Error(w, "forbidden", http.StatusForbidden)
return
}
next.ServeHTTP(w, r)
})
}
}
// RequirePlatform gates a PLATFORM surface on the operator role, amendment 6 section 2 item 2. The
// platform surfaces (Organizations, cross tenant Users, Curation, Federation, and platform Metrics) act
// across every tenant at once, so they belong to the platform plane and to nothing else.
//
// It refuses with 404, not 403, and the distinction is the point. A 403 confirms the surface EXISTS and
// tells a tenant's top seat that a cross tenant control plane is there to be found; it is also exactly how
// this defect presented, a client shown platform shaped controls that refused her. A platform surface must
// be indistinguishable from a path that was never built. This matches RequireTool, which refuses an
// unentitled product the same way and for the same reason.
//
// The check is on the role in the validated session, never a header or a body, so it cannot be spoofed.
// Superuser does NOT pass: amendment 6 narrowed the tenant top seat to within its tenant, and a platform
// surface is not tenant scoped by definition.
func RequirePlatform() func(http.Handler) http.Handler {
return func(next http.Handler) http.Handler {
return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
p, ok := tenant.UserFromContext(r.Context())
if !ok || Role(p.Role) != RoleOperator {
w.Header().Set("Content-Type", "application/json")
w.WriteHeader(http.StatusNotFound)
_, _ = w.Write([]byte(`{"error":{"code":"not_found","message":"not found"}}`))
return
}
next.ServeHTTP(w, r)
})
}
}
// RequireRole gates a route on a minimum role in the hierarchy.
func RequireRole(min Role) func(http.Handler) http.Handler {
return func(next http.Handler) http.Handler {
return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
p, ok := tenant.UserFromContext(r.Context())
if !ok || !AtLeast(Role(p.Role), min) {
http.Error(w, "forbidden", http.StatusForbidden)
return
}
next.ServeHTTP(w, r)
})
}
}