Documentation
¶
Overview ¶
Package acl indexes explicit subject/group grants and denials by action and resource type. New constructs a reusable read-only view; Evaluate matches exact identifiers and optional type-wide IDs, with explicit deny winning among matches. Standalone no-match is NotApplicable, not final authorization. Global inheritance is opt-in. Groups/tenant/identity are trusted mapped facts, not authenticated here. Entry containers are indexed but unused nested Subject attributes are borrowed. Calls own no I/O/goroutine; request containers must remain immutable. Document v1 is the application JSON format, not complete external ACL-standard conformance.
Example ¶
package main
import (
"context"
"fmt"
authorization "github.com/faustbrian/go-authorization/v3"
"github.com/faustbrian/go-authorization/v3/acl"
)
func main() {
accessList, err := acl.New([]acl.Entry{
{
ID: "reader",
Subject: authorization.Subject{
Kind: authorization.SubjectUser,
ID: "alice",
},
Action: "document.read",
ResourceType: "document",
Effect: authorization.Allow,
},
})
if err != nil {
panic(err)
}
decision, err := accessList.Evaluate(context.Background(), authorization.Request{
Subject: authorization.Subject{
Kind: authorization.SubjectUser,
ID: "alice",
},
Action: "document.read",
Resource: authorization.Resource{
Type: "document",
ID: "document-1",
},
})
if err != nil {
panic(err)
}
fmt.Println(decision.Outcome == authorization.Allow)
}
Output: true
Index ¶
- Constants
- Variables
- func EncodeDocument(document Document) ([]byte, error)
- type Decoder
- type Document
- type Entry
- type EntryDocument
- type EntryID
- type Evaluator
- func (evaluator *Evaluator) Evaluate(ctx context.Context, request authorization.Request) (authorization.Decision, error)
- func (evaluator *Evaluator) EvaluateBatch(ctx context.Context, requests []authorization.Request) ([]authorization.Decision, error)
- func (evaluator *Evaluator) ListResourceIDs(ctx context.Context, subject authorization.Subject, ...) ([]authorization.ResourceID, error)
- type Limits
- type Option
Examples ¶
Constants ¶
const ( // ReasonAllow marks a model grant. ReasonAllow authorization.ReasonCode = "acl-allow" // ReasonExplicitDeny marks a matching model denial. ReasonExplicitDeny authorization.ReasonCode = "acl-explicit-deny" // ReasonLimitExceeded marks model work rejected by a configured count/cost limit. ReasonLimitExceeded authorization.ReasonCode = "acl-limit-exceeded" )
const ( // EffectAllow is the serialized explicit allow label. EffectAllow = "allow" // EffectDeny is the serialized explicit deny label. EffectDeny = "deny" )
const DocumentVersion uint64 = 1
DocumentVersion is version 1 of this application model JSON profile.
Variables ¶
var ( // ErrInvalidEntry identifies invalid ACL entry. Compare with errors.Is, not error text. ErrInvalidEntry = errors.New("invalid ACL entry") // ErrDuplicateEntry identifies duplicate ACL entry. Compare with errors.Is, not error text. ErrDuplicateEntry = errors.New("duplicate ACL entry") // ErrEntryLimitExceeded identifies ACL entry limit exceeded. Compare with errors.Is, not error text. ErrEntryLimitExceeded = errors.New("ACL entry limit exceeded") // ErrGroupLimitExceeded identifies ACL group limit exceeded. Compare with errors.Is, not error text. ErrGroupLimitExceeded = errors.New("ACL group limit exceeded") // ErrMatchLimitExceeded identifies ACL match limit exceeded. Compare with errors.Is, not error text. ErrMatchLimitExceeded = errors.New("ACL match limit exceeded") // ErrBatchLimitExceeded identifies ACL batch limit exceeded. Compare with errors.Is, not error text. ErrBatchLimitExceeded = errors.New("ACL batch limit exceeded") // ErrUnboundedResourceSet identifies ACL resource set is unbounded. Compare with errors.Is, not error text. ErrUnboundedResourceSet = errors.New("ACL resource set is unbounded") )
var ( // ErrInvalidDocument identifies invalid ACL document. Compare with errors.Is, not error text. ErrInvalidDocument = errors.New("invalid ACL document") // ErrUnsupportedDocumentVersion identifies unsupported ACL document version. Compare with errors.Is, not error text. ErrUnsupportedDocumentVersion = errors.New("unsupported ACL document version") // ErrDocumentLimitExceeded identifies ACL document size limit exceeded. Compare with errors.Is, not error text. ErrDocumentLimitExceeded = errors.New("ACL document size limit exceeded") )
Functions ¶
func EncodeDocument ¶
EncodeDocument build-validates, then marshals indented JSON and checks the 1 MiB result cap after allocation. It returns no successful oversize output; field/string memory and caller document ownership remain outside that cap.
Types ¶
type Decoder ¶
type Decoder struct{}
Decoder is the stateless policy.Decoder binding for this version-1 model.
func (Decoder) Decode ¶
func (Decoder) Decode(document json.RawMessage) (authorization.Evaluator, error)
Decode delegates to DecodeDocument; no independent lifecycle or context is added.
type Document ¶
type Document struct {
// Version is the application model version; Build requires DocumentVersion (1).
Version uint64 `json:"version"`
// GlobalInheritance explicitly enables global assignments/grants for tenant requests.
GlobalInheritance bool `json:"global_inheritance,omitempty"`
// Limits supplies positive entry/group/match/batch count overrides; other values retain defaults.
Limits Limits `json:"limits,omitempty"`
// Entries is the editable ordered ACL document input, copied/indexed by Build/New.
Entries []EntryDocument `json:"entries"`
}
Document is the editable application version-1 JSON model, not an authenticated artifact. Build validates the selected model after caller-owned construction/JSON materialization; inactive fields can be present but unused.
type Entry ¶
type Entry struct {
// ID is an exact application-defined label; keep diagnostic identifiers non-secret.
ID EntryID
// Subject supplies trusted kind/ID and optional group/fact state; it is not authenticated here.
Subject authorization.Subject
// Action is matched byte-for-byte; no wildcard, normalization or permission discovery is implied.
Action authorization.Action
// ResourceType is matched exactly; no wildcard or external lookup is implied.
ResourceType authorization.ResourceType
// ResourceID is exact when nonempty; empty makes the grant/rule type-wide.
ResourceID authorization.ResourceID
// Tenant is exact scope; empty means global, not inferred tenant membership.
Tenant authorization.TenantID
// Effect must select an explicit allow or deny; model construction rejects other outcomes.
Effect authorization.Outcome
}
Entry grants or denies one subject an action on a resource type or instance.
type EntryDocument ¶
type EntryDocument struct {
// ID is an exact application-defined label; keep diagnostic identifiers non-secret.
ID EntryID `json:"id"`
// SubjectKind is the exact principal-kind label, not enforced authentication policy.
SubjectKind authorization.SubjectKind `json:"subject_kind"`
// SubjectID is the exact principal identity; application authentication must establish it.
SubjectID authorization.SubjectID `json:"subject_id"`
// Action is matched byte-for-byte; no wildcard, normalization or permission discovery is implied.
Action authorization.Action `json:"action"`
// ResourceType is matched exactly; no wildcard or external lookup is implied.
ResourceType authorization.ResourceType `json:"resource_type"`
// ResourceID is exact when nonempty; empty makes the grant/rule type-wide.
ResourceID authorization.ResourceID `json:"resource_id,omitempty"`
// Tenant is exact scope; empty means global, not inferred tenant membership.
Tenant authorization.TenantID `json:"tenant,omitempty"`
// Effect must select an explicit allow or deny; model construction rejects other outcomes.
Effect string `json:"effect"`
}
EntryDocument is the editable version-1 exact subject/action/resource grant.
type EntryID ¶
type EntryID = authorization.PolicyID
EntryID preserves PolicyID identity for ACL entry diagnostics.
type Evaluator ¶
type Evaluator struct {
// contains filtered or unexported fields
}
Evaluator resolves immutable ACL entries without external I/O.
func DecodeDocument ¶
DecodeDocument rejects input above 1 MiB before JSON decoding, unknown fields and trailing values, then builds the model. Duplicate JSON member names follow encoding/json last-wins semantics; duplicate model IDs are rejected. Parser diagnostics can include offending characters/field names. No context or pre-parser model-depth/count cap is supplied; decoded trees allocate before Build.
func New ¶
New checks entry count, unique IDs, required identity/action/type strings and allow/deny effects before publishing indexes. Entry values are copied, but nested Subject groups/attribute maps are not deeply isolated (they are unused for matching). Nil/custom options may panic; positive limits replace defaults and non-positive fields are ignored. No context/string-byte budget is applied.
func (*Evaluator) Evaluate ¶
func (evaluator *Evaluator) Evaluate( ctx context.Context, request authorization.Request, ) (authorization.Decision, error)
Evaluate matches the subject and deduplicated trusted groups in request order. Actions/types/tenant are exact; empty entry ResourceID is type-wide. All matches are collected up to MaxMatches and any deny overrides allows. Limit/cancel errors deny and discard partial diagnostics; no match is NotApplicable. It does not call Request.Validate and checks ctx between principals, not every entry.
func (*Evaluator) EvaluateBatch ¶
func (evaluator *Evaluator) EvaluateBatch( ctx context.Context, requests []authorization.Request, ) ([]authorization.Decision, error)
EvaluateBatch evaluates all requests against the same ACL view and returns each decision with joined per-request errors. Oversized input returns nil; cancellation is delegated to Evaluate and does not short-circuit the batch.
func (*Evaluator) ListResourceIDs ¶
func (evaluator *Evaluator) ListResourceIDs( ctx context.Context, subject authorization.Subject, action authorization.Action, resourceType authorization.ResourceType, tenant authorization.TenantID, ) ([]authorization.ResourceID, error)
ListResourceIDs returns only explicitly enumerable instance grants. A resource-type allow is reported as unbounded instead of triggering a storage scan; a type-wide deny returns an empty set immediately. Results are sorted, duplicate principals are ignored and exact matched-entry caps apply. No request authentication/validation is performed; context is checked between principals.
type Limits ¶
type Limits struct {
// MaxEntries admits ACL entries at construction; default is 10000.
MaxEntries int `json:"max_entries,omitempty"`
// MaxGroups caps admitted membership count; zero/default policy selects 100.
MaxGroups int `json:"max_groups,omitempty"`
// MaxMatches caps collected matching entries/permissions/rules; default is 100.
MaxMatches int `json:"max_matches,omitempty"`
// MaxBatchSize admits request count before result allocation; default is 1000.
MaxBatchSize int `json:"max_batch_size,omitempty"`
}
Limits bounds ACL construction and per-request evaluation work.
type Option ¶
type Option func(*Evaluator)
Option configures construction synchronously. Nil/custom options may panic; do not retain evaluator mutation access after New publishes its view.
func WithGlobalInheritance ¶
func WithGlobalInheritance() Option
WithGlobalInheritance makes global entries apply to tenant-scoped requests. Without this option, global and tenant scopes are isolated.
func WithLimits ¶
WithLimits configures positive bounds while retaining safe defaults for zero-valued fields.