Skip to main content

aura_core/effects/
authorization.rs

1//! Authorization Effects
2//!
3//! Provides capability-based authorization primitives for access control across
4//! the Aura system. These effects enable verification of permissions, delegation
5//! of authority, and enforcement of security policies.
6//!
7//! # Effect Classification
8//!
9//! - **Category**: Application Effect
10//! - **Implementation**: `aura-authorization` / `aura-protocol` (Layer 2/4)
11//! - **Usage**: Biscuit token evaluation and capability-based authorization
12//!
13//! This is an application effect implemented in domain crates by composing
14//! infrastructure effects with authorization-specific logic.
15
16use crate::types::identifiers::AuthorityId;
17use crate::types::scope::{AuthorizationOp, ResourceScope};
18use crate::{AuraError, Cap};
19use async_trait::async_trait;
20
21/// Authorization operations for capability-based access control
22///
23/// This trait provides pure authorization primitives that can be composed
24/// into complex permission systems. All operations are stateless and work
25/// with explicit capability tokens and access policies.
26#[async_trait]
27pub trait AuthorizationEffects {
28    /// Verify that capabilities grant permission for a specific operation
29    ///
30    /// # Arguments
31    /// * `capabilities` - The capability lattice to check
32    /// * `operation` - The operation requiring authorization
33    /// * `resource` - The resource being accessed
34    ///
35    /// # Returns
36    /// * `Ok(true)` if authorization is granted
37    /// * `Ok(false)` if authorization is denied
38    /// * `Err(_)` if verification failed due to system error
39    async fn verify_capability(
40        &self,
41        capabilities: &Cap,
42        operation: AuthorizationOp,
43        scope: &ResourceScope,
44    ) -> Result<bool, AuthorizationError>;
45
46    /// Delegate a subset of capabilities to another entity
47    ///
48    /// Creates a new capability set that contains only the permissions
49    /// that are both requested and present in the source capabilities.
50    /// This implements the principle of least privilege using meet-semilattice operations.
51    ///
52    /// # Arguments
53    /// * `source_capabilities` - The capabilities to delegate from
54    /// * `requested_capabilities` - The capabilities being requested
55    /// * `target_authority` - The authority receiving the delegation
56    ///
57    /// # Returns
58    /// The intersection of source and requested capabilities (source ⊓ requested)
59    async fn delegate_capabilities(
60        &self,
61        source_capabilities: &Cap,
62        requested_capabilities: &Cap,
63        target_authority: &AuthorityId,
64    ) -> Result<Cap, AuthorizationError>;
65}
66
67/// Errors that can occur during authorization operations
68#[derive(Debug, thiserror::Error)]
69pub enum AuthorizationError {
70    /// The requested operation is not permitted
71    #[error("Access denied: {operation} on {resource}")]
72    AccessDenied { operation: String, resource: String },
73
74    /// The capability set is invalid or malformed
75    #[error("Invalid capability set: {reason}")]
76    InvalidCapabilities { reason: String },
77
78    /// The access token is invalid, expired, or revoked
79    #[error("Invalid access token: {reason}")]
80    InvalidToken { reason: String },
81
82    /// Cryptographic verification failed
83    #[error("Signature verification failed")]
84    SignatureError,
85
86    /// System error during authorization
87    #[error("Authorization system error: {0}")]
88    SystemError(#[from] AuraError),
89}
90
91/// Authorization decision result
92#[derive(Debug, Clone)]
93pub struct AuthorizationDecision {
94    /// Whether the operation is authorized
95    pub authorized: bool,
96    /// Optional reason for the decision
97    pub reason: Option<String>,
98}
99
100/// Biscuit token-based authorization effects
101///
102/// This trait enables Biscuit authorization checks without creating domain dependencies.
103/// The journal domain can use this trait while the implementation lives in aura-authorization.
104#[async_trait]
105pub trait BiscuitAuthorizationEffects {
106    /// Authorize an operation against a Biscuit token and resource scope
107    ///
108    /// # Arguments
109    /// * `token_data` - Raw Biscuit token bytes
110    /// * `operation` - The operation being attempted
111    /// * `scope` - The resource scope for the operation
112    ///
113    /// # Returns
114    /// Authorization decision with detailed reasoning
115    async fn authorize_biscuit(
116        &self,
117        token_data: &[u8],
118        operation: AuthorizationOp,
119        scope: &ResourceScope,
120    ) -> Result<AuthorizationDecision, AuthorizationError>;
121
122    /// Verify a fact authorization using Biscuit tokens
123    ///
124    /// # Arguments
125    /// * `token_data` - Raw Biscuit token bytes
126    /// * `fact_type` - Type of fact being authorized
127    /// * `scope` - Resource scope for the fact
128    ///
129    /// # Returns
130    /// Whether the fact is authorized
131    async fn authorize_fact(
132        &self,
133        token_data: &[u8],
134        fact_type: &str,
135        scope: &ResourceScope,
136    ) -> Result<bool, AuthorizationError>;
137}
138
139/// Blanket implementation for Arc<T> where T: AuthorizationEffects
140#[async_trait]
141impl<T> AuthorizationEffects for std::sync::Arc<T>
142where
143    T: AuthorizationEffects + ?Sized + Send + Sync,
144{
145    async fn verify_capability(
146        &self,
147        capabilities: &Cap,
148        operation: AuthorizationOp,
149        scope: &ResourceScope,
150    ) -> Result<bool, AuthorizationError> {
151        (**self)
152            .verify_capability(capabilities, operation, scope)
153            .await
154    }
155
156    async fn delegate_capabilities(
157        &self,
158        source_capabilities: &Cap,
159        requested_capabilities: &Cap,
160        target_authority: &AuthorityId,
161    ) -> Result<Cap, AuthorizationError> {
162        (**self)
163            .delegate_capabilities(
164                source_capabilities,
165                requested_capabilities,
166                target_authority,
167            )
168            .await
169    }
170}
171
172/// Blanket implementation for Arc<T> where T: BiscuitAuthorizationEffects
173#[async_trait]
174impl<T> BiscuitAuthorizationEffects for std::sync::Arc<T>
175where
176    T: BiscuitAuthorizationEffects + ?Sized + Send + Sync,
177{
178    async fn authorize_biscuit(
179        &self,
180        token_data: &[u8],
181        operation: AuthorizationOp,
182        scope: &ResourceScope,
183    ) -> Result<AuthorizationDecision, AuthorizationError> {
184        (**self)
185            .authorize_biscuit(token_data, operation, scope)
186            .await
187    }
188
189    async fn authorize_fact(
190        &self,
191        token_data: &[u8],
192        fact_type: &str,
193        scope: &ResourceScope,
194    ) -> Result<bool, AuthorizationError> {
195        (**self).authorize_fact(token_data, fact_type, scope).await
196    }
197}