38 lines
1.2 KiB
Go
38 lines
1.2 KiB
Go
|
|
package httpauth
|
||
|
|
|
||
|
|
import (
|
||
|
|
"context"
|
||
|
|
"net/http"
|
||
|
|
|
||
|
|
"code.nochebuena.dev/go/rbac"
|
||
|
|
)
|
||
|
|
|
||
|
|
// PermissionProvider resolves the permission mask for a given uid on a resource.
|
||
|
|
type PermissionProvider interface {
|
||
|
|
ResolveMask(ctx context.Context, uid, resource string) (rbac.PermissionMask, error)
|
||
|
|
}
|
||
|
|
|
||
|
|
// AuthzMiddleware reads the rbac.Identity from context (set by EnrichmentMiddleware)
|
||
|
|
// and gates the request against the required permission on resource.
|
||
|
|
// Returns 401 if no identity is in the context.
|
||
|
|
// Returns 403 if the identity lacks the required permission or if the provider errors.
|
||
|
|
func AuthzMiddleware(provider PermissionProvider, resource string, required rbac.Permission) func(http.Handler) http.Handler {
|
||
|
|
return func(next http.Handler) http.Handler {
|
||
|
|
return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
|
||
|
|
identity, ok := rbac.FromContext(r.Context())
|
||
|
|
if !ok {
|
||
|
|
http.Error(w, "unauthorized", http.StatusUnauthorized)
|
||
|
|
return
|
||
|
|
}
|
||
|
|
|
||
|
|
mask, err := provider.ResolveMask(r.Context(), identity.UID, resource)
|
||
|
|
if err != nil || !mask.Has(required) {
|
||
|
|
http.Error(w, "forbidden", http.StatusForbidden)
|
||
|
|
return
|
||
|
|
}
|
||
|
|
|
||
|
|
next.ServeHTTP(w, r)
|
||
|
|
})
|
||
|
|
}
|
||
|
|
}
|