64 lines
1.6 KiB
Go
64 lines
1.6 KiB
Go
// Package authorization owns the fixed, low-cardinality permission vocabulary
|
|
// used by HTTP authentication and endpoint handlers.
|
|
package authorization
|
|
|
|
import (
|
|
"errors"
|
|
"strings"
|
|
)
|
|
|
|
const (
|
|
All = "*"
|
|
AdminRead = "admin:read"
|
|
AdminWrite = "admin:write"
|
|
DistributionExtract = "distribution:extract"
|
|
)
|
|
|
|
var ErrInvalidPermissions = errors.New("invalid permissions")
|
|
|
|
// Validate accepts an omitted permission set for backwards-compatible full
|
|
// access. An explicit set is strict, finite, duplicate-free, and cannot mix
|
|
// the global permission with narrower grants.
|
|
func Validate(permissions []string) error {
|
|
if len(permissions) == 0 {
|
|
return nil
|
|
}
|
|
seen := make(map[string]struct{}, len(permissions))
|
|
for _, permission := range permissions {
|
|
if strings.TrimSpace(permission) != permission || !known(permission) {
|
|
return ErrInvalidPermissions
|
|
}
|
|
if _, exists := seen[permission]; exists {
|
|
return ErrInvalidPermissions
|
|
}
|
|
seen[permission] = struct{}{}
|
|
}
|
|
if _, hasAll := seen[All]; hasAll && len(seen) != 1 {
|
|
return ErrInvalidPermissions
|
|
}
|
|
return nil
|
|
}
|
|
|
|
// Allows reports whether one authenticated identity can invoke an endpoint.
|
|
// Empty permissions preserve pre-scope configurations as full access.
|
|
func Allows(permissions []string, required string) bool {
|
|
if len(permissions) == 0 {
|
|
return true
|
|
}
|
|
for _, permission := range permissions {
|
|
if permission == All || permission == required {
|
|
return true
|
|
}
|
|
}
|
|
return false
|
|
}
|
|
|
|
func known(permission string) bool {
|
|
switch permission {
|
|
case All, AdminRead, AdminWrite, DistributionExtract:
|
|
return true
|
|
default:
|
|
return false
|
|
}
|
|
}
|