Skip to main content

toolkit_security/
lib.rs

1//! Security primitives shared by every `ToolKit` gear: who a caller is, what
2//! they are allowed to reach, and how a service proves its own identity to
3//! another.
4//!
5//! A leaf crate by design — it depends on no other `ToolKit` library, so
6//! anything from a bootstrap path to a gear's domain layer can use it without
7//! pulling in the runtime.
8//!
9//! # The two planes
10//!
11//! `ToolKit` authenticates on two independent planes, and this crate carries
12//! the types for both (`cpt-cf-adr-two-plane-auth`):
13//!
14//! - **Tenant plane** — a user's request. [`SecurityContext`] is the result:
15//!   the subject, its tenant, and the token's capability scopes. Produced by a
16//!   [`BearerAuthenticator`] from an `Authorization: Bearer` JWT.
17//! - **Platform plane** — one service calling another. [`PlatformIdentity`] is
18//!   the result, produced by an [`InternalAuthenticator`] from the
19//!   [`constants::INTERNAL_TOKEN_HEADER`] credential. Never `Authorization`,
20//!   so the two planes cannot be confused for one another.
21//!
22//! # Authorization
23//!
24//! [`AccessScope`] is what a policy decision compiles down to: a disjunction of
25//! [`ScopeConstraint`]s, each a conjunction of [`ScopeFilter`]s over properties
26//! like `owner_tenant_id`. `toolkit-db` turns it into a SQL `WHERE` clause so
27//! row-level authorization is enforced by the query rather than by a check a
28//! caller has to remember.
29//!
30//! Two shapes carry meaning and are easy to misread: an *unconstrained* scope
31//! permits everything, and a *deny-all* scope permits nothing. The
32//! `contains_*` accessors report on the constraint list alone, so both answer
33//! "no" — see [`AccessScope::allows_uuid`] for the predicate that accounts for
34//! the difference.
35#![cfg_attr(coverage_nightly, feature(coverage_attribute))]
36
37/// What a caller is authorized to reach, and how it compiles to a query filter.
38pub mod access_scope;
39/// Traits for validating a credential on either plane, and object-safe wrappers.
40pub mod authenticator;
41/// Binary wire format for a [`SecurityContext`] over gRPC metadata.
42pub mod bin_codec;
43/// Well-known identifiers and header names.
44pub mod constants;
45/// The authenticated tenant-plane caller.
46pub mod context;
47/// Platform-plane identity, credentials, and the authenticator contract.
48pub mod internal_auth;
49/// TTL-bounded caching for platform-plane validation.
50#[cfg(feature = "internal-auth-cache")]
51pub mod internal_auth_cache;
52/// Configuration selecting how the platform plane authenticates.
53pub mod internal_auth_config;
54/// The types most gears need, re-exported for a single glob import.
55pub mod prelude;
56/// A pre-shared-secret [`InternalAuthenticator`], for development and simple
57/// deployments.
58pub mod shared_secret;
59
60pub use access_scope::{
61    AccessScope, EmptyScopeConstraint, EqScopeFilter, InGroupScopeFilter,
62    InGroupSubtreeScopeFilter, InScopeFilter, InTenantSubtreeScopeFilter, ScopeConstraint,
63    ScopeFilter, ScopeValue, pep_properties,
64};
65pub use authenticator::{
66    AuthNError, BearerAuthenticator, DynBearerAuthenticator, DynInternalAuthenticator,
67};
68pub use context::{SecurityContext, SecurityContextBuildError};
69pub use internal_auth::{
70    InternalAuthNError, InternalAuthenticator, InternalCredential, PeerAuthenticated,
71    PlatformAuthEnforced, PlatformIdentity, PlatformSecurityContext,
72};
73#[cfg(feature = "internal-auth-cache")]
74pub use internal_auth_cache::{
75    CachingInternalAuthenticator, DEFAULT_TOKEN_REVIEW_CACHE_TTL, InvalidCacheTtl,
76    MAX_TOKEN_REVIEW_CACHE_TTL,
77};
78pub use internal_auth_config::{
79    BuiltAuthenticator, DEFAULT_INTERNAL_PEER_NAME, InternalAuthConfig, InvalidInternalAuth,
80};
81pub use shared_secret::{
82    InvalidSharedSecret, REDACTED_PLACEHOLDER, SharedSecretInternalAuthenticator,
83};
84
85pub use bin_codec::{
86    SECCTX_BIN_VERSION, SecCtxDecodeError, SecCtxEncodeError, decode_bin, encode_bin,
87};