Documentation
¶
Overview ¶
Package spocputil provides shared utilities for working with SPOCP S-expressions, including parsing human-readable "advanced form" into sexp.Element trees and loading rules from files.
Index ¶
- func BuildTaggedQuery(tag string, dims []string, values map[string]string) sexp.Element
- func LoadRulesFromFile(engine *spocp.AdaptiveEngine, path string, ...) error
- func ParseAdvancedSExp(input string) (sexp.Element, error)
- func ValidateRuleElement(elem sexp.Element, tag string, dims []string, requireValue bool, source string) error
- type Engine
Constants ¶
This section is empty.
Variables ¶
This section is empty.
Functions ¶
func BuildTaggedQuery ¶
BuildTaggedQuery constructs `(tag (dim1 val1)(dim2 val2)...)` in the given dimension order. A dimension with no matching entry in `values` is emitted as an empty list `(dim)`, which SPOCP wildcard rules match.
func LoadRulesFromFile ¶
func LoadRulesFromFile(engine *spocp.AdaptiveEngine, path string, validate func(elem sexp.Element, source string) error) error
LoadRulesFromFile reads human-readable SPOCP rules (one per line) from a file and adds them to the engine using ParseAdvancedSExp. If validate is non-nil, each parsed rule is passed to it (with a source string identifying the file and line number) before being added; a returned error aborts loading.
func ParseAdvancedSExp ¶
ParseAdvancedSExp parses a human-readable ("advanced form") S-expression into a sexp.Element. This allows users to write rules as:
(credential (scope org_cred)(acr urn:example:loa3)(email_verified true))
instead of canonical form:
(10:credential(5:scope8:org_cred)(3:acr19:urn:example:loa3)(14:email_verified4:true))
It also supports star forms:
(*) → wildcard (* prefix urn:example:) → prefix match (* suffix @example.com) → suffix match (* set loa3 loa4) → set match
func ValidateRuleElement ¶
func ValidateRuleElement(elem sexp.Element, tag string, dims []string, requireValue bool, source string) error
ValidateRuleElement checks that a parsed rule is a list tagged `tag` containing exactly len(dims) sub-lists in the given order, each tagged with the corresponding dimension name. SPOCP matching is positional, so wrong order, wrong count, or an unexpectedly multi-valued part would silently never match at query time -- reject those up front instead.
requireValue controls whether a dimension may be written as an empty list, e.g. (email_verified), to mean "any value" (SPOCP's native wildcard form, and what BuildTaggedQuery itself emits for an absent value):
- true: every dimension must hold exactly one value; write the literal atom "*" for wildcards. This is the endpoint-access convention.
- false: a dimension may hold zero or one value; more than one is always rejected regardless. This is the issuance-policy convention, which already authors wildcards as empty dimensions.
The two domains' existing rule files use different conventions here, so this can't be collapsed into one fixed choice without either breaking issuance's existing wildcard style or silently loosening endpoint-access validation.
Types ¶
type Engine ¶
type Engine struct {
// contains filtered or unexported fields
}
Engine wraps a SPOCP AdaptiveEngine with a mutex, safe for concurrent QueryElement/RuleCount/ExportRules access after construction. Shared by both HTTP endpoint-access rules (pkg/httphelpers) and OIDC credential-issuance policy rules (pkg/issuance), so both rule sets are built, validated, and queried through the same machinery rather than each maintaining its own copy.
func BuildEngine ¶
func BuildEngine(tag string, dims []string, requireValue bool, ruleLabel string, inlineRules []string, rulesFile string) (*Engine, error)
BuildEngine parses inline rules and an optional rules file into a new Engine tagged for this rule set's domain. Returns (nil, nil) when neither inline rules nor a rules file are configured.
ruleLabel names the rule set for error messages (e.g. "SPOCP" or "issuance policy") so callers get a domain-specific error without each needing to re-wrap it.
When dims is non-nil, every rule -- inline and file-loaded alike -- is validated against tag/dims via ValidateRuleElement before being added. Pass nil to skip shape validation for rule sets whose dimensions aren't statically fixed (e.g. an issuance policy with no configured QueryTemplate, which queries with whatever OIDC claims happen to be present on a given request rather than a fixed, known set of dimensions).
requireValue is forwarded to ValidateRuleElement -- see its doc comment for why this can't be a fixed choice shared by every caller.
func (*Engine) ExportRules ¶
ExportRules returns the raw parsed rule elements (read-locked), for callers that need to inspect rule structure directly (e.g. resolving the set of resources a subject is authorized for, rather than just answering yes/no for one specific query).
func (*Engine) QueryElement ¶
QueryElement checks if the query is authorized (read-locked).