Skip to main content

axess_core/
lib.rs

1#![forbid(unsafe_code)]
2#![deny(missing_docs)]
3#![deny(
4    rustdoc::broken_intra_doc_links,
5    rustdoc::private_intra_doc_links,
6    rustdoc::redundant_explicit_links
7)]
8// Opt into the nightly `doc(cfg(...))` attribute so docs.rs renders an
9// "available on feature `X`" badge on every feature-gated item. The
10// `#[cfg_attr(docsrs, doc(cfg(...)))]` tags below are no-ops on stable
11// builds; they only activate under docs.rs's `--cfg docsrs` flag (set in
12// `[package.metadata.docs.rs]`).
13#![cfg_attr(docsrs, feature(doc_cfg))]
14//! Core implementation for the Axess authentication and authorization library.
15//!
16//! # Re-export strategy
17//!
18//! Public types have one **canonical location** (the module that defines or
19//! that owns the canonical re-export from a sibling crate) and may also be
20//! convenience-re-exported at the crate root. Adopters can use either path;
21//! the canonical path is what `rustdoc` displays. When in doubt, prefer the
22//! canonical path in import statements; it survives crate-root churn.
23//!
24//! | Concern | Canonical | Crate-root convenience |
25//! |---------|-----------|-----------------------|
26//! | Session state | [`session`]`::*` | (none; depth-2 access only) |
27//! | Authn service / state machine | [`authn`]`::*` | (none) |
28//! | Authn factor configs | [`authn::factor`]`::*` | (none) |
29//! | Authn errors | [`authn::error`]`::*` | (none) |
30//! | Authz policy / decision | [`authz`]`::*` | (none) |
31//! | Identity (principal, IDs) | [`principal`]`::*` (re-exports `axess-identity`) | (none) |
32//! | Clock / RNG (DST foundation) | `axess_clock::*` / `axess_rng::*` | [`Clock`], [`SecureRng`], [`SystemClock`], [`SystemRng`] |
33//! | Health checks | [`health`]`::*` | [`HealthCheck`], [`HealthStatus`], [`CompositeHealthCheck`] |
34//! | Authn metrics | [`metrics`]`::*` | [`AuthnMetrics`], [`NoopMetrics`] |
35//! | Middleware (CSRF, rate-limit, request-id, trace-id) | [`middleware`]`::*` | [`RateLimitLayer`] + helpers; [`RequestIdLayer`] (feature-gated); [`TraceIdLayer`] + [`TraceContext`] (feature-gated) |
36//! | Test fixtures | [`testing`]`::*` (gated `cfg(any(test, feature = "testing"))`) | [`MockClock`], [`MockRng`], [`MockIdentityStore`], ... |
37//!
38//! **Why some types have crate-root convenience and others don't:** the
39//! ones promoted to the crate root are either DST primitives that every
40//! adopter touches (`Clock`, `SecureRng`) or framework integration points
41//! that read naturally as `axess_core::RateLimitLayer`. Authn / authz
42//! types stay at depth-2 so the import line reveals *which layer* the
43//! type belongs to. Useful when reading a route handler that mixes
44//! authn and authz concerns.
45//!
46//! # Feature flags
47//!
48//! | Feature | What it enables |
49//! |---------|----------------|
50//! | `authz` | Cedar Policy authorization (RBAC + ABAC + ReBAC). **On by default.** |
51//! | `device` | First-class [`device::Device`] identity with three-stage assurance ladder (`Unknown` → `Seen` → `Trusted`, plus terminal `Revoked`), per-tenant fingerprint pepper, refresh-family cascade, retention sweep, and `CachedDeviceStore` decorator. **On by default.** Pair with `sqlite` / `postgres` / `mysql` / `valkey` for persistent backends ([`SqliteDeviceStore`], [`PostgresDeviceStore`], [`MysqlDeviceStore`], [`ValkeyDeviceStore`]). See [`device`] and [`docs/identity/device.md`](https://github.com/GnomesOfZurich/axess/blob/main/docs/identity/device.md). |
52//! | `memory` | In-memory session store and registry (`MemorySessionStore`, `MemorySessionRegistry`). Dev/test only, not in default features. Production builds without this flag cannot import these types. |
53//! | `sqlite` | SQLite session store with AES-256-GCM encryption. |
54//! | `postgres` | PostgreSQL session store with AES-256-GCM encryption. |
55//! | `valkey` | Valkey/Redis session store and registry with optional encryption. |
56//! | `fido2` | FIDO2/WebAuthn passkey authentication. |
57//! | `oauth` | OAuth 2.0 / OIDC (AuthCode+PKCE, Client Credentials, Device Code). |
58//! | `ldap` | LDAP bind authentication (Active Directory, OpenLDAP). |
59//! | `request-id` | `X-Request-Id` middleware. |
60//! | `trace-id` | W3C Trace Context (`traceparent`) middleware. |
61//! | `default-error-response` | Built-in `IntoResponse` mapping for [`AuthnError`] (on by default). Disable to ship your own HTTP mapping; see [`authn::error`] for the recommended status-code table. |
62//! | `full` | All of the above. |
63//!
64//! Internal features (used by the library, not intended for direct use):
65//! `accept_client_id`.
66
67// ── Session layer ──────────────────────────────────────────────────────────────
68
69/// Custom tower session layer with HMAC-signed cookies and typed session data.
70pub mod session;
71
72pub use session::{
73    AuthSession, AuthState, RefreshError, RefreshToken, RefreshTokenConfig, RefreshTokenStore,
74    SameSite, SessionBinding, SessionConfig, SessionConfigBuilder, SessionData, SessionId,
75    SessionLayer, SessionRegistry, SessionRegistryAdapter, SessionRegistryHandle, SessionRevoker,
76    SessionStore, UserAgentBinding,
77};
78#[cfg(any(test, feature = "memory"))]
79pub use session::{MemorySessionRegistry, MemorySessionStore};
80
81// ── Authentication ─────────────────────────────────────────────────────────────
82
83/// Authentication service: identity lookup, factor verification, session management.
84pub mod authn;
85
86// ── Device identity ───────────────────────────────────────────────────────────
87//
88// First-class subsystem (typed `Device` aggregate, three-stage assurance
89// ladder, retention sweep, refresh-family cascade, PII tokenisation) rather
90// than an authn-flow submodule. Legacy `axess_core::authn::Device*` paths
91// continue to resolve via the re-export shim in `authn.rs`.
92/// First-class typed `Device` aggregate + three-layer assurance ladder.
93#[cfg(feature = "device")]
94#[cfg_attr(docsrs, doc(cfg(feature = "device")))]
95pub mod device;
96
97pub use authn::{
98    AuditContext, AuditQuery, AuthEvent, AuthEventBuilder, AuthEventStatus, AuthEventType,
99    AuthMethod, AuthnBackend, AuthnError, AuthnScope, AuthnService, DeviceId, EmailOtpConfig,
100    EntityState, EventQueryFilter, FactorConfig, FactorCredential, FactorKind, FactorOutcome,
101    FactorStep, FactorStore, FactorTemplate, FederatedProvider, Fido2Config, HotpConfig,
102    IdentityAdmin, IdentityAuthnLog, IdentityLookup, IdentityStore, IpPolicy, LdapBindFactorConfig,
103    LockoutPolicy, LoginOutcome, NoSessionRegistryError, NoopAuthnLog, OtpAlgorithm,
104    PasswordConfig, PasswordRules, PrepareOutcome, ProvisioningError, SessionValidator,
105    SignupOutcome, StatusDetail, Tenant, TenantBootstrap, TenantId, TotpConfig, User, UserId,
106    ZeroizedString, create_tenant, default_catalog, extract_audit_context,
107    extract_audit_context_async, require_valid_session,
108};
109
110// ── Federation; external-IdP adapters ───────────────────────────────────────
111//
112// External-IdP surface collected here: OAuth/OIDC, JWT, mTLS, LDAP, FIDO2,
113// PKCE, back-/front-channel logout, federation adapters (K8s SA / GitHub
114// Actions / generic OAuth-RS). Each submodule gated on its own per-feature
115// flag.
116/// External-IdP federation adapters: per-protocol + per-issuer.
117pub mod federation;
118
119// ── Authorization ──────────────────────────────────────────────────
120
121#[cfg(feature = "authz")]
122#[cfg_attr(docsrs, doc(cfg(feature = "authz")))]
123pub mod authz;
124
125#[cfg(feature = "authz")]
126#[cfg_attr(docsrs, doc(cfg(feature = "authz")))]
127pub use authz::{
128    AuthzDecision, AuthzDenied, AuthzEntityProvider, AuthzError, AuthzSession, AuthzStore,
129    BuildRequestContext, NoContext, PolicyEvaluator, PolicyStore, StandardRequestContext,
130    ip_from_headers, make_action_uid, make_entity_uid,
131};
132
133// ── Storage backends (re-exports from session::storage) ────────────────────────
134//
135// Pluggable storage backends for [`SessionStore`] and authentication state.
136// The actual modules live under [`session::storage`]; kept there because
137// every backend implements `SessionStore` and/or `SessionRegistry`, both
138// session-domain traits. The flat re-exports below preserve the historical
139// public API (`axess_core::SqliteSessionStore`, etc.) so downstream code
140// importing those types is unaffected by the layout cleanup.
141
142// `in_memory_backend` is gated behind `cfg(any(test, feature = "testing"))`
143// in `session.rs`; the re-export must match or non-testing builds fail
144// (E0432: unresolved import).
145#[cfg(any(test, feature = "testing"))]
146pub use session::storage::in_memory_backend::InMemoryBackend;
147
148#[cfg(feature = "sqlite")]
149#[cfg_attr(docsrs, doc(cfg(feature = "sqlite")))]
150pub use session::storage::sqlite::SqliteSessionStore;
151
152#[cfg(feature = "postgres")]
153#[cfg_attr(docsrs, doc(cfg(feature = "postgres")))]
154pub use session::storage::postgres::{PostgresSessionStore, PostgresStoreError};
155
156#[cfg(feature = "mysql")]
157#[cfg_attr(docsrs, doc(cfg(feature = "mysql")))]
158pub use session::storage::mysql::{MysqlSessionStore, MysqlStoreError};
159
160#[cfg(feature = "valkey")]
161#[cfg_attr(docsrs, doc(cfg(feature = "valkey")))]
162pub use session::storage::valkey::{ValkeySessionRegistry, ValkeySessionStore, ValkeyStoreError};
163
164#[cfg(feature = "ldap")]
165#[cfg_attr(docsrs, doc(cfg(feature = "ldap")))]
166pub use axess_factors::ldap::{
167    LdapBindResult, LdapError, LdapGroupSearch, LdapProvider, LdapProviderConfig, MockLdapProvider,
168};
169
170#[cfg(feature = "oauth")]
171#[cfg_attr(docsrs, doc(cfg(feature = "oauth")))]
172pub use axess_factors::oauth::{
173    AuthUrlResult, MockOAuthProvider, OAuthClaims, OAuthError, OAuthLoginOptions, OAuthProvider,
174    OAuthProviderConfig, ResponseMode, UserInfoClaims, spawn_jwks_refresh,
175};
176
177#[cfg(feature = "fapi")]
178#[cfg_attr(docsrs, doc(cfg(feature = "fapi")))]
179pub use axess_factors::oauth::{DpopProof, FapiConfig, ParResponse, SenderConstraint};
180
181#[cfg(feature = "device")]
182#[cfg_attr(docsrs, doc(cfg(feature = "device")))]
183pub use device::{
184    AttestationClass, CachedDeviceStore, DefaultFingerprintExtractor, Device, DeviceBinding,
185    DeviceEventSink, DeviceFingerprintExtractor, DeviceLifecycleService, DevicePiiCategory,
186    DevicePiiMapping, DevicePiiResolver, DevicePiiStore, DeviceResolver, DeviceStore,
187    DeviceTrustLevel, FingerprintHash, LifecycleDeviceResolver, MemoryDevicePiiStore,
188    MemoryDevicePiiStoreError, MemoryDeviceStore, MemoryDeviceStoreError, NoopDeviceEventSink,
189    NoopDeviceResolver, PiiToken, REDACTED_PLACEHOLDER, RedactedResolver, SweepConfig,
190    SweepConfigBuilder, SweepCounts, TenantPepperResolver, cascade_revoke_by_refresh_family,
191    cascade_revoke_devices,
192};
193
194#[cfg(feature = "device")]
195#[cfg_attr(docsrs, doc(cfg(feature = "device")))]
196pub use authn::service::{StepUpPolicy, StepUpPolicyBuilder, decide_step_up};
197
198#[cfg(all(
199    feature = "device",
200    any(feature = "sqlite", feature = "postgres", feature = "mysql")
201))]
202pub use device::storage::SqlDeviceStoreError;
203
204#[cfg(all(feature = "device", feature = "sqlite"))]
205pub use device::storage::SqliteDeviceStore;
206
207#[cfg(all(feature = "device", feature = "postgres"))]
208pub use device::storage::PostgresDeviceStore;
209
210#[cfg(all(feature = "device", feature = "mysql"))]
211pub use device::storage::MysqlDeviceStore;
212
213#[cfg(all(feature = "device", feature = "valkey"))]
214pub use device::storage::{ValkeyDeviceStore, ValkeyDeviceStoreError};
215
216// ── Principal abstraction ────────────────────────────────────────────
217
218/// Unified identity abstraction covering humans and workloads.
219/// See [`docs/workload-identity/README.md`](https://github.com/GnomesOfZurich/axess/blob/main/docs/workload-identity/README.md).
220pub mod principal;
221
222/// Workload identity hub: re-exports inbound resolvers and houses
223/// outbound primitives. See [`workload`] module docs.
224pub mod workload;
225
226/// On-behalf-of (OBO) access: axess acts *as a user* at a
227/// downstream service. Two flow shapes share one conceptual
228/// abstraction; see [`delegated::stored`] and [`delegated::exchange`]
229/// for the per-flow contracts.
230#[cfg(any(feature = "delegated-stored", feature = "delegated-exchange"))]
231#[cfg_attr(
232    docsrs,
233    doc(cfg(any(feature = "delegated-stored", feature = "delegated-exchange")))
234)]
235pub mod delegated;
236
237pub use principal::{
238    AuthHumanPrincipal, AuthPrincipal, AuthWorkloadPrincipal, CliResolver, CliResolverBuilder,
239    HumanPrincipal, IdentityError, Issuer, Principal, PrincipalRejection, PrincipalResolver,
240    SessionResolver, TrustDomain, WorkloadId, WorkloadPrincipal,
241};
242
243#[cfg(feature = "authz")]
244#[cfg_attr(docsrs, doc(cfg(feature = "authz")))]
245pub use principal::ToCedarEntity;
246
247// ── Shared store abstraction ───────────────────────────────────────────────────
248
249/// Generic key/value-with-TTL store + codec, shared across backend
250/// implementations.
251pub mod store;
252
253// ── Top-level utilities ────────────────────────────────────────────────────────
254
255/// HTTP cookie parsing helpers (`extract_named_cookie` + caps).
256/// Re-exported from [`session::cookies`]; lives next to the session
257/// middleware that is its primary consumer.
258pub use session::cookies;
259/// Composite health-check primitives.
260pub mod health;
261/// HMAC helpers used by the session-layer signing + CSRF middleware.
262/// Re-exported from [`session::hmac`]; lives next to the session
263/// middleware that is its primary consumer.
264pub use session::hmac;
265/// Production-grade in-process IdP: mints workload-identity JWTs
266/// against an adopter-supplied [`local_idp::LocalIdpKeyStore`] and
267/// exposes JWKS for verifiers. Test counterpart lives at
268/// [`testing::local_idp`]. Gated on the `local-idp` feature.
269#[cfg(feature = "local-idp")]
270#[cfg_attr(docsrs, doc(cfg(feature = "local-idp")))]
271pub mod local_idp;
272/// `AuthnMetrics` trait + `NoopMetrics` default implementation.
273pub mod metrics;
274/// Mock authentication/identity stores, deterministic clocks/RNGs,
275/// fixture builders, and other test doubles. Gated behind
276/// `cfg(any(test, feature = "testing"))` so production builds cannot
277/// import them; in-crate tests get them via `cfg(test)`.
278#[cfg(any(test, feature = "testing"))]
279pub mod testing;
280/// Identifier / e-mail / URL validation helpers.
281pub mod validation;
282
283pub use axess_clock::{Clock, SystemClock};
284pub use axess_rng::{SecureRng, SystemRng};
285pub use health::{CompositeHealthCheck, CompositeStatus, HealthCheck, HealthStatus};
286pub use metrics::{AuthnMetrics, NoopMetrics};
287
288#[cfg(any(test, feature = "testing"))]
289pub use testing::mock_tracing::TracingCapture;
290
291#[cfg(any(test, feature = "testing"))]
292pub use testing::{
293    MemoryRefreshStoreError, MemoryRefreshTokenStore, MockClock, MockFactorStore,
294    MockIdentityStore, MockResolver, MockRng,
295};
296
297#[cfg(all(feature = "authz", any(test, feature = "testing")))]
298pub use testing::mock_policy::{MockEntityProvider, MockPolicyEvaluator};
299
300// ── Middleware ─────────────────────────────────────────────────────────────────
301
302/// Optional axum/tower middleware: request ID, W3C trace context, rate
303/// limiting, CSRF. Renamed from `extras` in (the prior name was
304/// meant to signal "outside the core auth flow"; `middleware` is what
305/// these actually are).
306pub mod middleware;
307
308#[cfg(feature = "request-id")]
309#[cfg_attr(docsrs, doc(cfg(feature = "request-id")))]
310pub use middleware::request_id::RequestIdLayer;
311
312#[cfg(feature = "trace-id")]
313#[cfg_attr(docsrs, doc(cfg(feature = "trace-id")))]
314pub use middleware::trace_id::{TraceContext, TraceContextLayer, TraceIdLayer};
315
316pub use middleware::ratelimit::{
317    KeyExtractor, RateLimitConfig, RateLimitConfigBuilder, RateLimitLayer,
318    RateLimitLoginIdentifier, RateLimitService, RateLimitTenantId, RateLimitUserId,
319};
320
321// ── Re-export axum and tracing for macro hygiene ────────────────────────────────
322
323#[doc(hidden)]
324pub use axum;
325#[doc(hidden)]
326pub use tracing;