pub struct AccessScope { /* private fields */ }Expand description
A disjunction (OR) of scope constraints defining what data is accessible.
Each constraint is an independent access path (OR-ed). Filters within a constraint are AND-ed. An unconstrained scope bypasses row-level filtering.
§Examples
use toolkit_security::access_scope::{AccessScope, ScopeConstraint, ScopeFilter, pep_properties};
use uuid::Uuid;
// deny-all (default)
let scope = AccessScope::deny_all();
assert!(scope.is_deny_all());
// single tenant
let tid = Uuid::new_v4();
let scope = AccessScope::for_tenant(tid);
assert!(!scope.is_deny_all());
assert!(scope.contains_uuid(pep_properties::OWNER_TENANT_ID, tid));Implementations§
Source§impl AccessScope
impl AccessScope
Sourcepub fn from_constraints(constraints: Vec<ScopeConstraint>) -> Self
pub fn from_constraints(constraints: Vec<ScopeConstraint>) -> Self
Create an access scope from a list of constraints (OR-ed).
Sourcepub fn single(constraint: ScopeConstraint) -> Self
pub fn single(constraint: ScopeConstraint) -> Self
Create an access scope with a single constraint.
Sourcepub fn allow_all() -> Self
pub fn allow_all() -> Self
Create an “allow all” (unconstrained) scope.
This represents a legitimate PDP decision with no row-level filtering. Not a bypass — it’s a valid authorization outcome.
Sourcepub fn for_tenants(ids: Vec<Uuid>) -> Self
pub fn for_tenants(ids: Vec<Uuid>) -> Self
Create a scope for a set of tenant IDs.
Sourcepub fn for_tenant(id: Uuid) -> Self
pub fn for_tenant(id: Uuid) -> Self
Create a scope for a single tenant ID.
Sourcepub fn for_resources(ids: Vec<Uuid>) -> Self
pub fn for_resources(ids: Vec<Uuid>) -> Self
Create a scope for a set of resource IDs.
Sourcepub fn for_resource(id: Uuid) -> Self
pub fn for_resource(id: Uuid) -> Self
Create a scope for a single resource ID.
Sourcepub fn constraints(&self) -> &[ScopeConstraint]
pub fn constraints(&self) -> &[ScopeConstraint]
The constraints in this scope (OR-ed).
Sourcepub fn is_unconstrained(&self) -> bool
pub fn is_unconstrained(&self) -> bool
Returns true if this scope is unconstrained (allow-all).
Sourcepub fn is_deny_all(&self) -> bool
pub fn is_deny_all(&self) -> bool
Returns true if this scope denies all access.
A scope is deny-all when it is not unconstrained and has no constraints.
Sourcepub fn all_values_for(&self, property: &str) -> Vec<&ScopeValue>
pub fn all_values_for(&self, property: &str) -> Vec<&ScopeValue>
Collect all values for a given property across all constraints.
Reports on the constraint list only. An allow-all scope has no
constraints, so this returns an empty Vec for it — which means “no
constraint names this property”, never “this scope permits nothing”.
An allow-all scope permits every value, and no finite list can say so.
Check AccessScope::is_unconstrained before reading anything into an
empty result.
Sourcepub fn all_uuid_values_for(&self, property: &str) -> Vec<Uuid>
pub fn all_uuid_values_for(&self, property: &str) -> Vec<Uuid>
Collect all UUID values for a given property across all constraints.
Convenience wrapper — skips non-UUID values.
Reports on the constraint list only, with the same caveat as
AccessScope::all_values_for: empty on an allow-all scope, which
permits everything rather than nothing.
Sourcepub fn contains_uuid(&self, property: &str, id: Uuid) -> bool
pub fn contains_uuid(&self, property: &str, id: Uuid) -> bool
Whether any filter, in any constraint, names property with this UUID.
Matches both ScopeValue::Uuid and ScopeValue::String variants so
that UUID-as-string values are treated consistently with
AccessScope::all_uuid_values_for, which also parses strings via
ScopeValue::as_uuid.
§This is not an authorization decision
It searches filter values. It does not evaluate a constraint, which is
a conjunction: for a grant of [owner_tenant_id = A AND owner_id = Alice]
this answers true for (owner_tenant_id, A) even when the row in
question belongs to Bob. A true here means “the scope mentions this
value somewhere”, nothing more.
It also reports on the constraint list alone, so an allow-all scope —
which has no constraints — answers false for a value it permits, and
a subquery filter (InGroup, InGroupSubtree, InTenantSubtree)
exposes no in-memory values at all, so it answers false for a grant
that does apply.
Authorize a write by passing the scope to the insert and letting
SecureORM evaluate it — validate_insert_scope ANDs across the filters
of a constraint and ORs across constraints, which is the whole decision.
Not marked #[deprecated] yet: the workspace builds with -D warnings,
so the attribute would break the build at all of its current call sites
at once. It goes on once the three gear gates
(resource-group, ledger, pricing) have moved to SecureORM.
Sourcepub fn has_property(&self, property: &str) -> bool
pub fn has_property(&self, property: &str) -> bool
Check if any constraint references the given property.
Reports on the constraint list only: an allow-all scope has no
constraints and so answers false, which is not a statement about what
it permits. Check AccessScope::is_unconstrained first.
Sourcepub fn tenant_only(&self) -> Self
pub fn tenant_only(&self) -> Self
Create a new scope retaining only owner_tenant_id filters.
Useful for entities declared with no_owner (e.g., messages, reactions),
where owner_id constraints cannot be resolved and would cause fail-closed
deny-all behaviour.
- Unconstrained scopes become deny-all (fail-closed).
- Constraints that contain no
owner_tenant_idfilter are dropped entirely. - If all constraints are dropped, the result is deny-all.
§This widens the grant, by design — check that you want it
Filters on other properties are removed from surviving constraints,
and a constraint is a conjunction, so dropping one of its terms admits
everything that term excluded. [owner_tenant_id = T, id IN (r1)]
becomes owner_tenant_id = T: one resource turned into the whole tenant.
That is correct for the case this exists for — re-targeting a scope at a
different entity, one with no owner_id/id column of its own, where
the removed terms never applied to the rows being filtered. It is wrong
if you are narrowing a scope for the same entity, and the resulting
scope must not be the only thing authorizing the access: mini-chat, for
example, checks the parent chat against the full scope first and only
then uses tenant_only() for its messages.
Sourcepub fn tenant_and_owner(&self) -> Self
pub fn tenant_and_owner(&self) -> Self
Create a new scope retaining only owner_tenant_id and owner_id filters.
Useful for entities that have both tenant and owner columns but no resource-level constraints (e.g., reactions scoped to the acting user).
- Unconstrained scopes become deny-all (fail-closed).
- Constraints that contain neither retained property are dropped.
- Filters on other properties are removed from surviving
constraints, which widens them — see the warning on
AccessScope::tenant_only; it applies here in full. - If all constraints are dropped, the result is deny-all.
Sourcepub fn ensure_owner(&self, owner_id: Uuid) -> Self
pub fn ensure_owner(&self, owner_id: Uuid) -> Self
Create a new scope that guarantees an owner_id equality filter
matching exactly the supplied owner_id is present in every constraint.
Intersection semantics: if a constraint already contains an
owner_id filter, the supplied value must be among its values —
otherwise the constraint is dropped. When it matches, the filter is
narrowed to exactly that single value.
- Unconstrained → single constraint with only the
owner_idfilter. - Deny-all → stays deny-all.
- No existing owner filter →
owner_idis injected. - Existing owner filter containing
owner_id→ narrowed toEq. - Existing owner filter NOT containing
owner_id→ constraint dropped (constraints use OR semantics, so dropping one narrows access; dropping all yields deny-all).
Use this as a defence-in-depth measure for user-owned resources when
the PDP may not always return owner_id constraints or may return a
broader set than the current subject.
Trait Implementations§
Source§impl Clone for AccessScope
impl Clone for AccessScope
Source§fn clone(&self) -> AccessScope
fn clone(&self) -> AccessScope
1.0.0 (const: unstable) · Source§fn clone_from(&mut self, source: &Self)
fn clone_from(&mut self, source: &Self)
source. Read more