authorization

package
v0.1.0 Latest Latest
Warning

This package is not in the latest version of its module.

Go to latest
Published: Oct 6, 2026 License: MIT Imports: 13 Imported by: 0

Documentation

Overview

Package authorization compiles explicit declarations and evaluates roles before constructing policies. Prepared captures security metadata, not a permission: operations must evaluate it and recheck it before invoking a handler. Tenant membership remains an independent boundary, including on public operations.

Index

Examples

Constants

This section is empty.

Variables

View Source
var (
	// ErrDenied identifies ordinary authorization denial.
	ErrDenied = errors.New("authorization denied")
	// ErrInvalidConfiguration identifies malformed declaration or registry input.
	ErrInvalidConfiguration = errors.New("invalid authorization configuration")
	// ErrDuplicate identifies duplicate policies or artifact identities.
	ErrDuplicate = errors.New("duplicate authorization registration")
	// ErrFrozen identifies changes after successful Build.
	ErrFrozen = errors.New("authorization registry frozen")
	// ErrUnknownPolicy identifies an unregistered policy name.
	ErrUnknownPolicy = errors.New("unknown authorization policy")
	// ErrUnsupportedScheme identifies unsupported native authentication schemes.
	ErrUnsupportedScheme = errors.New("authentication schemes unsupported")
	// ErrUnknownTarget identifies a target absent from the compiled catalog.
	ErrUnknownTarget = errors.New("unknown authorization target")
	// ErrIdentityChanged identifies replacement of principal/tenant or their presence.
	ErrIdentityChanged = errors.New("authorization identity changed")
	// ErrNotPrepared identifies a zero Prepared value.
	ErrNotPrepared = errors.New("authorization not prepared")
)
View Source
var ErrCatalogMismatch = errors.New("authorization catalog mismatch")

ErrCatalogMismatch identifies missing targets or changed frozen declarations.

View Source
var ErrScopeRequired = errors.New("authorization policy requires an operation scope")

ErrScopeRequired identifies direct evaluation of an applicable scoped policy.

Functions

func RegisterPolicy

func RegisterPolicy[P Policy](r *Registry, name string, factory Factory[P], options PolicyOptions, keys ...di.Key) error

RegisterPolicy registers a lazy scoped policy without activating its factory. Nil factories, invalid keys and duplicate names fail. Optional exact dependency keys are copied and checked by pipeline Build without constructing the policy. Omit keys for manually wired factories. Resources own disposal of the policy.

Types

type ConfigurationError

type ConfigurationError struct {
	// Target is the malformed artifact, or zero for registry configuration.
	Target Target
	// Policy is the declaration's policy identity, if relevant.
	Policy string
	// Kind is the inspectable failure category.
	Kind error
}

ConfigurationError describes configuration identities, never request values.

func (*ConfigurationError) Error

func (e *ConfigurationError) Error() string

Error describes the configuration identity and failure category.

func (*ConfigurationError) Unwrap

func (e *ConfigurationError) Unwrap() []error

Unwrap preserves the category and general configuration failure identity.

type Context

type Context struct {
	// Principal is the authenticated actor snapshot, or empty for a guest.
	Principal identity.Principal
	// Tenant is the selected tenant, not evidence of membership.
	Tenant tenancy.ID
	// Target identifies the command or query.
	Target Target
	// Resource is borrowed for this evaluation only.
	Resource any
	// ReceivedAt is the operation dispatch receipt, if installed.
	ReceivedAt time.Time
}

Context is immutable operation metadata plus borrowed, operation-specific data. Policies must not mutate or retain Resource.

type Decision

type Decision struct {
	// contains filtered or unexported fields
}

Decision is an immutable verdict. Zero denies; it is not a reusable access token.

func Allow

func Allow() Decision

Allow returns an allowed verdict.

func Deny

func Deny(reason string) Decision

Deny returns a denied verdict with local diagnostic reason.

func (Decision) Err

func (d Decision) Err() error

Err returns nil for Allow, otherwise an ErrDenied wrapper.

func (Decision) IsAllowed

func (d Decision) IsAllowed() bool

IsAllowed reports the verdict.

func (Decision) Reason

func (d Decision) Reason() string

Reason returns local diagnostics, not automatically client-visible text.

type DeniedError

type DeniedError struct {
	// Reason is diagnostic application text, not safe HTTP response content.
	Reason string
}

DeniedError retains local diagnostic reason without including it in error text.

func (*DeniedError) Error

func (e *DeniedError) Error() string

Error returns generic denial text.

func (*DeniedError) Unwrap

func (e *DeniedError) Unwrap() error

Unwrap identifies ErrDenied.

type Evaluator

type Evaluator struct {
	// contains filtered or unexported fields
}

Evaluator is immutable and concurrent-safe with concurrently callable policies. It caches declarations, never decisions. Construct using Registry.Build.

func (*Evaluator) CheckCatalog

func (e *Evaluator) CheckCatalog(catalog metadata.Catalog) error

CheckCatalog verifies coverage and exact declaration content, including absent declarations and overridden model levels. Supersets are allowed. It does not run policies, and never treats matching names alone as compatible authority.

func (*Evaluator) CheckDependencies

func (e *Evaluator) CheckDependencies(catalog metadata.Catalog, dependencies di.Catalog) error

CheckDependencies checks effective policy manifests for the supplied catalog subset, after checking its frozen declarations. Overridden policies and other targets do not require dependencies for this pipeline. No policies or factories run. Missing/typed-nil catalogs fail only when applicable declared keys exist; manually captured dependencies remain the application's responsibility.

func (*Evaluator) Prepare

func (e *Evaluator) Prepare(ctx context.Context, target Target) (Prepared, error)

Prepare captures metadata without invoking policies or constructing dependencies.

type Factory

type Factory[P Policy] func(context.Context, *execution.Scope) (P, error)

Factory constructs a borrowed policy only during scoped evaluation. Its scope view is non-closing and expires on return from EvaluateScoped.

type Kind

type Kind uint8

Kind identifies an operation category.

const (
	// Command identifies a command artifact.
	Command Kind = iota + 1
	// Query identifies a read-model query method.
	Query
)

type Options

type Options struct {
	// Fallback applies only to undeclared operations and is copied by Build.
	Fallback *metadata.Authorization
}

Options configures frozen application fallback declarations.

type Policy

type Policy interface {
	Authorize(context.Context, Context) (Decision, error)
}

Policy evaluates synchronously and must honor cancellation. Shared policies must support concurrent use. Unexpected panics propagate to pipeline boundaries.

type PolicyFunc

type PolicyFunc func(context.Context, Context) (Decision, error)

PolicyFunc adapts a policy callback.

func (PolicyFunc) Authorize

func (f PolicyFunc) Authorize(ctx context.Context, value Context) (Decision, error)

Authorize invokes f with borrowed operation data.

type PolicyOptions

type PolicyOptions struct {
	// EvaluatesAnonymous explicitly opts this policy into guest evaluation.
	EvaluatesAnonymous bool
}

PolicyOptions controls whether policy-only declarations may evaluate guests.

type Prepared

type Prepared struct {
	// contains filtered or unexported fields
}

Prepared captures a declaration and security metadata before dependencies run. Zero is invalid. It is not an authorization token; Evaluate is required for every operation, and Check must run again immediately before handler invocation.

func (Prepared) Check

func (p Prepared) Check(ctx context.Context) error

Check verifies cancellation and unchanged principal/tenant, including presence. Receipt/correlation changes do not alter security ownership.

func (Prepared) Evaluate

func (p Prepared) Evaluate(ctx context.Context, resource any) (Decision, error)

Evaluate checks security metadata, roles, then direct policies in declaration order. A policy error returns a denied Decision plus its original error. Policy panics propagate to pipeline boundaries. Resource is borrowed, never retained. This API is container-neutral; it neither creates nor validates service scopes.

func (Prepared) EvaluateScoped

func (p Prepared) EvaluateScoped(ctx context.Context, scope *execution.Scope, resource any) (decision Decision, err error)

EvaluateScoped admits evaluation for the scope's lifetime. All authentication and role requirements run before any policy factory. Factories and policies receive only a non-closing view; panics become execution.PanicError. A scope grants no permission and decisions are never cached.

type Registry

type Registry struct {
	// contains filtered or unexported fields
}

Registry is a single-owner builder; zero is ready for use. Successful Build freezes it. Build validates configuration without constructing any policy.

Example
var registry authorization.Registry
err := registry.Register("owner", authorization.PolicyFunc(func(_ context.Context, value authorization.Context) (authorization.Decision, error) {
	if value.Principal.ID() == value.Resource {
		return authorization.Allow(), nil
	}
	return authorization.Deny("not owner"), nil
}), authorization.PolicyOptions{})
if err != nil {
	panic(err)
}
e, err := registry.Build(catalog(&metadata.Authorization{Requirements: []metadata.AuthorizationRequirement{{Policy: "owner"}}}), authorization.Options{})
if err != nil {
	panic(err)
}
ctx := identity.WithPrincipal(context.Background(), identity.NewPrincipal(identity.PrincipalData{ID: "alice", AuthenticationType: "verified"}))
prepared, err := e.Prepare(ctx, create)
if err != nil {
	panic(err)
}
decision, err := prepared.Evaluate(ctx, "alice")
if err != nil {
	panic(err)
}
fmt.Println(decision.IsAllowed())
Output:
true

func (*Registry) Build

func (r *Registry) Build(catalog metadata.Catalog, options Options) (*Evaluator, error)

Build validates every declaration, including overridden levels, and copies the effective graph. Commands use command then fallback; queries use method then read model then fallback. Queries of the same read model must supply identical read-model declarations by content. No declaration and no fallback is public.

func (*Registry) Register

func (r *Registry) Register(name string, policy Policy, options PolicyOptions) error

Register borrows a concurrently callable direct policy. Names are exact and nonempty, with no surrounding whitespace or control characters.

type Target

type Target struct {
	// Kind is Command or Query.
	Kind Kind
	// Identity is the exact namespace-qualified artifact identity.
	Identity string
}

Target identifies exactly one compiled catalog artifact.

Jump to

Keyboard shortcuts

? : This menu
/ : Search site
f or F : Jump to
y or Y : Canonical URL