1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
//! Self-hosted relationship-based authorization (`ReBAC`) over a Corium
//! database.
//!
//! `corium-protocol`'s [`Authorizer`](corium_protocol::authz::Authorizer) seam
//! was built so a deployment could point authorization at an external policy
//! service. This crate is the answer for deployments that would rather not run
//! one: Corium's own data model — entities, reference attributes, immutable
//! history — is a good fit for the tuple shape `ReBAC` needs, so the policy
//! lives in an ordinary Corium database and the check is a bounded in-memory
//! graph walk over a compiled snapshot of it.
//!
//! ```text
//! Check(subject, action, object, database, at_authz_t)
//! action -> required relation(s) (permission map)
//! subject --relation/derived--> object (tuples + rewrites)
//! optional binding -> ViewFilter (bindings + views)
//! ```
//!
//! # The pieces
//!
//! * [`schema`] — the reserved attributes of the authz database, and the EDN
//! an operator installs to create one.
//! * [`model`] — the policy vocabulary: objects, tuples, permissions,
//! rewrites, views, bindings. Relation names are *data*, not Rust enums.
//! * [`policy::Policy`] — an immutable compiled snapshot keyed by the authz
//! database's basis `t`, with the indexes a check needs.
//! * [`eval`] — the bounded, cycle-safe relationship search.
//! * [`subject`] — how a request [`Principal`](corium_protocol::authz::Principal)
//! becomes the subjects the search starts from.
//! * [`source::PolicySource`] — where snapshots come from; each surface
//! supplies the database value it already holds.
//! * [`SystemDbAuthorizer`] — the `Authorizer` itself: snapshot caching,
//! consistency, result caching, fail-closed behaviour, break-glass, audit.
//! * [`bootstrap`] — building an authz database in process, and the EDN an
//! operator's grant/revoke sends to a real one.
//!
//! # Fail closed
//!
//! Every failure that leaves the authorizer without a policy — a missing authz
//! database, an unreadable snapshot, a policy that does not compile — denies.
//! The one exception is an explicit [`BreakGlass`] configuration for operator
//! recovery, and it is audited at `warn` every time it grants. A snapshot that
//! stops compiling never *replaces* the last good one either: the process
//! keeps deciding from the policy it already has.
//!
//! # Example
//!
//! ```
//! use std::sync::Arc;
//!
//! use corium_authz::{SystemDbAuthorizer, bootstrap, source::MemoryPolicySource};
//! use corium_protocol::authz::{Access, Action, Authorizer, Decision, Principal};
//!
//! # #[tokio::main(flavor = "current_thread")]
//! # async fn main() {
//! let db = bootstrap::policy_db(r#"
//! [{:db/id "read" :authz.permission/object-type "database"
//! :authz.permission/action "read" :authz.permission/relation ["viewer"]}
//! {:db/id "t1" :authz.tuple/subject "group:eng#member"
//! :authz.tuple/relation "viewer" :authz.tuple/object "database:music"}
//! {:db/id "t2" :authz.tuple/subject "user:alice"
//! :authz.tuple/relation "member" :authz.tuple/object "group:eng"}]
//! "#).expect("policy compiles");
//!
//! let authorizer = SystemDbAuthorizer::new(Arc::new(MemoryPolicySource::new("authz", db)));
//! let alice = Principal::new("oidc", "alice");
//! let bob = Principal::new("oidc", "bob");
//!
//! assert!(matches!(
//! authorizer.authorize(&alice, &Access::on(Action::Query, "music")).await,
//! Decision::Allow
//! ));
//! assert!(matches!(
//! authorizer.authorize(&bob, &Access::on(Action::Query, "music")).await,
//! Decision::Deny(_)
//! ));
//! # }
//! ```
pub use ;
pub use ;
pub use ;
pub use ;
pub use DEFAULT_AUTHZ_DB;
pub use ;
pub use SubjectMapping;