policy

package
v1.3.0 Latest Latest
Warning

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

Go to latest
Published: Oct 23, 2026 License: MIT, MIT Imports: 11 Imported by: 0

README

GoModularAuth Policy Plugin

gomodularauth-policy provides composable policy-based and attribute-based access control (ABAC) for GoModularAuth applications. It evaluates complex multidimensional authorization requirements over Principal, User, Organization, Resource, Action, and Context attributes using idiomatic Go constructs without forcing a proprietary policy language.

Installation

go get github.com/BladiCreator/go-modular-auth/plugins/policy

Quick Start

package main

import (
	"context"
	"log"

	auth "github.com/BladiCreator/go-modular-auth"
	adaptermem "github.com/BladiCreator/go-modular-auth/adapters/memory"
	policy "github.com/BladiCreator/go-modular-auth/plugins/policy"
	"github.com/BladiCreator/go-modular-auth/plugins/policy/plugins"
)

func main() {
	ctx := context.Background()

	// 1. Define composable rules
	ownerOnly := policy.AllOf(
		"doc:manage",
		"Requires authenticated principal and resource ownership",
		policy.RequireAuthenticated(),
		policy.RequireResourceOwner(),
	)

	// 2. Initialize Policy plugin
	policyPlugin := policy.New(
		policy.WithInitialPolicies(ownerOnly),
	)

	// 3. Register with GoModularAuth
	a, err := auth.New(auth.Config{
		Adapter: adaptermem.NewAdapter(),
		Plugins: []auth.PluginModule{policyPlugin},
	})
	if err != nil {
		log.Fatalf("failed to init auth: %v", err)
	}

	// 4. Resolve typed capability
	authz, err := auth.Get[plugins.Policy](a)
	if err != nil {
		log.Fatalf("failed to get policy capability: %v", err)
	}

	// 5. Authorize request
	principal := auth.Principal{Subject: "user_123", Type: auth.PrincipalUser}
	res := policy.NewResource("document", "doc_999").WithOwner("user_123")

	err = authz.Authorize(ctx, policy.Request{
		Principal: principal,
		Resource:  res,
		Action:    "edit",
	})
	if err != nil {
		log.Printf("access denied: %v", err)
		return
	}

	log.Println("Access granted!")
}

Detailed guide: doc/plugins/policy.md.

Documentation

Overview

Package policy provides composable policy-based and attribute-based access control (ABAC) for GoModularAuth applications, evaluating Principal, User, Organization, Resource, Action, and Context attributes without requiring proprietary policy languages.

Index

Constants

View Source
const (
	EventPolicyEvaluated  auth.EventName = "policy.evaluated"
	EventPolicyRegistered auth.EventName = "policy.registered"
	EventPolicyRemoved    auth.EventName = "policy.removed"
)
View Source
const (
	ModelPolicies = "policies"
)
View Source
const PluginID = "policy"

PluginID identifies this plugin in the GoModularAuth runtime.

Variables

View Source
var (
	// ErrForbidden indicates that the evaluated policy explicitly or implicitly denied access.
	ErrForbidden = errors.New("access denied by policy")

	// ErrChallengeRequired indicates that additional authentication or verification is required before access can be granted.
	ErrChallengeRequired = errors.New("authentication challenge required by policy")

	// ErrPrincipalRequired indicates that a request lacked an authenticated principal when evaluation required one.
	ErrPrincipalRequired = errors.New("authenticated principal is required")

	// ErrPolicyNotFound indicates that the requested policy does not exist.
	ErrPolicyNotFound = errors.New("policy not found")

	// ErrPolicyAlreadyExists indicates that a policy with the given ID is already registered.
	ErrPolicyAlreadyExists = errors.New("policy already registered")

	// ErrInvalidRequest indicates that the evaluation request was malformed or missing mandatory fields.
	ErrInvalidRequest = errors.New("invalid authorization request")

	// ErrNoApplicablePolicy indicates that no registered policy applied to the request under a strict evaluation mode.
	ErrNoApplicablePolicy = errors.New("no applicable policy found for request")
)

Functions

func RegisterSchema

func RegisterSchema(s *schema.Schema) error

RegisterSchema registers the policy models in the compiled schema.

Types

type Attributes

type Attributes map[string]any

Attributes represents arbitrary typed attributes for ABAC evaluations.

func (Attributes) Get

func (a Attributes) Get(key string) any

Get returns the attribute value or nil if not present.

func (Attributes) GetBool

func (a Attributes) GetBool(key string) bool

GetBool returns the boolean value of the attribute, or false.

func (Attributes) GetInt

func (a Attributes) GetInt(key string) int

GetInt returns the integer value of the attribute, or 0.

func (Attributes) GetString

func (a Attributes) GetString(key string) string

GetString returns the string value of the attribute, or empty string.

type ChallengeInfo

type ChallengeInfo struct {
	Type    string         `json:"type"`              // e.g. "mfa", "step_up", "reauth", "device_verification"
	Message string         `json:"message,omitempty"` // User-friendly description of why the challenge is required
	Details map[string]any `json:"details,omitempty"` // Contextual parameters for the challenge
}

ChallengeInfo describes the specific challenge requirement when Effect is EffectChallenge.

type CombinatorType

type CombinatorType string

CombinatorType defines the root policy composition algorithm.

const (
	CombinatorDenyOverrides CombinatorType = "deny_overrides"
	CombinatorAllOf         CombinatorType = "all_of"
	CombinatorAnyOf         CombinatorType = "any_of"
)

type Config

type Config struct {
	Cache           cache.Cache
	CacheTTL        time.Duration
	Combinator      CombinatorType
	InitialPolicies []Evaluator
	Clock           func() time.Time
}

Config holds configuration parameters for the policy plugin.

type Decision

type Decision struct {
	Effect      Effect         `json:"effect"`
	Reason      string         `json:"reason,omitempty"`
	Challenge   *ChallengeInfo `json:"challenge,omitempty"`
	PolicyID    string         `json:"policy_id,omitempty"`
	EvaluatedAt time.Time      `json:"evaluated_at"`
}

Decision represents the structured outcome of a policy evaluation.

func Allow

func Allow(policyID, reason string) Decision

Allow creates an allow decision.

func Challenge

func Challenge(policyID string, ch ChallengeInfo) Decision

Challenge creates a challenge decision.

func Deny

func Deny(policyID, reason string) Decision

Deny creates a deny decision.

func (Decision) IsAllowed

func (d Decision) IsAllowed() bool

IsAllowed returns true if the decision granted access.

func (Decision) IsChallenge

func (d Decision) IsChallenge() bool

IsChallenge returns true if the decision requires a challenge.

func (Decision) IsDenied

func (d Decision) IsDenied() bool

IsDenied returns true if the decision denied access.

type Effect

type Effect string

Effect defines the authorization outcome.

const (
	// EffectAllow grants access to the requested action on the target resource.
	EffectAllow Effect = "allow"

	// EffectDeny prohibits access to the requested action.
	EffectDeny Effect = "deny"

	// EffectChallenge indicates that access is pending an additional challenge (e.g. MFA, re-auth).
	EffectChallenge Effect = "challenge"
)

type Evaluator

type Evaluator interface {
	ID() string
	Description() string
	Evaluate(ctx context.Context, req Request) (Decision, error)
}

Evaluator is the contract implemented by every composable policy rule.

func AllOf

func AllOf(id, description string, evaluators ...Evaluator) Evaluator

AllOf combines multiple evaluators requiring ALL to allow access. If any evaluator denies, it denies immediately. If any requires a challenge and none denies, it returns the challenge.

func AnyOf

func AnyOf(id, description string, evaluators ...Evaluator) Evaluator

AnyOf combines multiple evaluators granting access if AT LEAST ONE allows access.

func DenyOverrides

func DenyOverrides(id, description string, evaluators ...Evaluator) Evaluator

DenyOverrides combines policies with standard ABAC deny-overrides semantics: If any policy denies, the decision is Deny. Otherwise, if any policy challenges, the decision is Challenge. Otherwise, if at least one policy allows, the decision is Allow. Otherwise, denies by default.

func NewRule

func NewRule(id, description string, fn Func) Evaluator

NewRule constructs a simple function-based Evaluator.

func Not

func Not(id, description string, eval Evaluator) Evaluator

Not inverts the decision of an evaluator: Allow becomes Deny, Deny becomes Allow. Challenge remains Challenge.

func RequireAuthenticated

func RequireAuthenticated() Evaluator

RequireAuthenticated ensures the request carries an authenticated principal.

func RequireOrganizationBoundary

func RequireOrganizationBoundary() Evaluator

RequireOrganizationBoundary enforces that request.Organization matches resource.OrganizationID.

func RequireResourceOwner

func RequireResourceOwner() Evaluator

RequireResourceOwner checks whether the principal subject matches resource.OwnerID.

type Func

type Func func(ctx context.Context, req Request) (Decision, error)

Func adapts an ordinary function to the Evaluator interface.

type Module

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

Module implements auth.PluginModule for composable policy and attribute-based authorization.

func New

func New(opts ...Option) *Module

New creates an installable Policy PluginModule configured with options.

func (*Module) ID

func (m *Module) ID() string

ID returns the module's unique identifier.

func (*Module) Init

func (m *Module) Init(h *auth.Host) error

Init configures infrastructure and registers the strongly typed Policy capability.

func (*Module) RegisterSchema

func (m *Module) RegisterSchema(s *schema.Schema) error

RegisterSchema registers the policy model in the compiled schema.

type Option

type Option func(*Config)

Option configures a policy plugin instance.

func WithCache

func WithCache(cacheImpl cache.Cache) Option

WithCache sets an explicit cache implementation for derived decisions.

func WithCacheTTL

func WithCacheTTL(ttl time.Duration) Option

WithCacheTTL sets the time-to-live for cached evaluation decisions.

func WithClock

func WithClock(clock func() time.Time) Option

WithClock sets a custom clock provider.

func WithCombinator

func WithCombinator(comb CombinatorType) Option

WithCombinator configures the top-level composition combination algorithm.

func WithInitialPolicies

func WithInitialPolicies(policies ...Evaluator) Option

WithInitialPolicies registers baseline policies at initialization.

type Policy

type Policy interface {
	// Authorize evaluates all registered policies against the request.
	// Returns nil if allowed, ErrForbidden if denied, or ErrChallengeRequired if challenge is needed.
	Authorize(ctx context.Context, req Request) error

	// Evaluate runs deterministic evaluation and returns the detailed structured Decision.
	Evaluate(ctx context.Context, req Request) (Decision, error)

	// RegisterPolicy registers a new composable policy evaluator.
	RegisterPolicy(p Evaluator) error

	// RemovePolicy unregisters an evaluator by its unique ID.
	RemovePolicy(policyID string) error

	// GetPolicy retrieves a registered policy evaluator by ID.
	GetPolicy(policyID string) (Evaluator, error)

	// ListPolicies returns all currently registered policy evaluators.
	ListPolicies() []Evaluator

	// InvalidatePrincipalCache evicts cached decisions for a specific principal.
	InvalidatePrincipalCache(ctx context.Context, principalSubject string) error

	// InvalidateResourceCache evicts cached decisions for a specific resource.
	InvalidateResourceCache(ctx context.Context, resourceType, resourceID string) error

	// InvalidateAllCache purges all cached policy decisions.
	InvalidateAllCache(ctx context.Context) error
}

Policy is the strongly typed capability exposed by the gomodularauth-policy plugin.

type PolicyEvaluatedPayload

type PolicyEvaluatedPayload struct {
	PrincipalSubject string    `json:"principal_subject"`
	PrincipalType    string    `json:"principal_type"`
	Organization     string    `json:"organization,omitempty"`
	ResourceType     string    `json:"resource_type"`
	ResourceID       string    `json:"resource_id"`
	Action           string    `json:"action"`
	Effect           Effect    `json:"effect"`
	Reason           string    `json:"reason,omitempty"`
	PolicyID         string    `json:"policy_id,omitempty"`
	Timestamp        time.Time `json:"timestamp"`
}

PolicyEvaluatedPayload is emitted when an authorization request is evaluated against policies.

type PolicyRecord

type PolicyRecord struct {
	ID          string    `json:"id"`
	Description string    `json:"description,omitempty"`
	Combinator  string    `json:"combinator,omitempty"` // e.g. "deny_overrides", "all_of", "any_of"
	CreatedAt   time.Time `json:"created_at"`
	UpdatedAt   time.Time `json:"updated_at"`
}

PolicyRecord represents a persisted policy metadata entry.

type PolicyRegisteredPayload

type PolicyRegisteredPayload struct {
	PolicyID    string    `json:"policy_id"`
	Description string    `json:"description,omitempty"`
	Timestamp   time.Time `json:"timestamp"`
}

PolicyRegisteredPayload is emitted when a new policy rule is registered.

type PolicyRemovedPayload

type PolicyRemovedPayload struct {
	PolicyID  string    `json:"policy_id"`
	Timestamp time.Time `json:"timestamp"`
}

PolicyRemovedPayload is emitted when a policy rule is removed.

type Request

type Request struct {
	Principal    auth.Principal `json:"principal"`
	User         *User          `json:"user,omitempty"`
	Organization string         `json:"organization,omitempty"`
	Resource     Resource       `json:"resource"`
	Action       string         `json:"action"`
	Attributes   Attributes     `json:"attributes,omitempty"`
}

Request bundles all parameters required for a policy evaluation.

type Resource

type Resource struct {
	Type           string     `json:"type"`
	ID             string     `json:"id"`
	OrganizationID string     `json:"organization_id,omitempty"`
	OwnerID        string     `json:"owner_id,omitempty"`
	Attributes     Attributes `json:"attributes,omitempty"`
}

Resource identifies the target entity and its contextual attributes.

func NewResource

func NewResource(resType, id string) Resource

NewResource constructs a resource descriptor.

func (Resource) WithAttribute

func (r Resource) WithAttribute(key string, val any) Resource

WithAttribute adds a key-value attribute to the resource.

func (Resource) WithOrg

func (r Resource) WithOrg(orgID string) Resource

WithOrg sets the organization boundary on the resource.

func (Resource) WithOwner

func (r Resource) WithOwner(ownerID string) Resource

WithOwner sets the owner identifier on the resource.

type User

type User = user.User

User aliases the Core User model.

Directories

Path Synopsis
Package plugins exposes capability aliases for GoModularAuth plugins.
Package plugins exposes capability aliases for GoModularAuth plugins.

Jump to

Keyboard shortcuts

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