role_system/
async_support.rs

1//! Async support for the role system (requires 'async' feature).
2
3use crate::{
4    core::{RoleSystem, RoleSystemConfig},
5    error::Result,
6    resource::Resource,
7    role::Role,
8    storage::Storage,
9    subject::Subject,
10};
11use std::{
12    collections::{HashMap, HashSet},
13    sync::Arc,
14    time::Duration,
15};
16use tokio::sync::{RwLock, Mutex};
17
18/// Async wrapper around the role system for non-blocking operations.
19pub struct AsyncRoleSystem<S>
20where
21    S: Storage + Send + Sync,
22{
23    inner: Arc<RwLock<RoleSystem<S>>>,
24}
25
26impl<S> AsyncRoleSystem<S>
27where
28    S: Storage + Send + Sync,
29{
30    /// Create a new async role system.
31    pub fn new(role_system: RoleSystem<S>) -> Self {
32        Self {
33            inner: Arc::new(RwLock::new(role_system)),
34        }
35    }
36
37    /// Register a new role in the system.
38    pub async fn register_role(&self, role: Role) -> Result<()> {
39        let mut system = self.inner.write().await;
40        system.register_role(role)
41    }
42
43    /// Get a role by name.
44    pub async fn get_role(&self, name: &str) -> Result<Option<Role>> {
45        let system = self.inner.read().await;
46        system.get_role(name)
47    }
48
49    /// Add role inheritance (child inherits from parent).
50    pub async fn add_role_inheritance(&self, child: &str, parent: &str) -> Result<()> {
51        let mut system = self.inner.write().await;
52        system.add_role_inheritance(child, parent)
53    }
54
55    /// Remove role inheritance.
56    pub async fn remove_role_inheritance(&self, child: &str, parent: &str) -> Result<()> {
57        let mut system = self.inner.write().await;
58        system.remove_role_inheritance(child, parent)
59    }
60
61    /// Assign a role to a subject.
62    pub async fn assign_role(&self, subject: &Subject, role_name: &str) -> Result<()> {
63        let mut system = self.inner.write().await;
64        system.assign_role(subject, role_name)
65    }
66
67    /// Remove a role from a subject.
68    pub async fn remove_role(&self, subject: &Subject, role_name: &str) -> Result<()> {
69        let mut system = self.inner.write().await;
70        system.remove_role(subject, role_name)
71    }
72
73    /// Temporarily elevate a subject's role.
74    pub async fn elevate_role(
75        &self,
76        subject: &Subject,
77        role_name: &str,
78        duration: Option<Duration>,
79    ) -> Result<()> {
80        let mut system = self.inner.write().await;
81        system.elevate_role(subject, role_name, duration)
82    }
83
84    /// Check if a subject has a specific permission on a resource.
85    pub async fn check_permission(
86        &self,
87        subject: &Subject,
88        action: &str,
89        resource: &Resource,
90    ) -> Result<bool> {
91        let system = self.inner.read().await;
92        system.check_permission(subject, action, resource)
93    }
94
95    /// Check permission with additional context.
96    pub async fn check_permission_with_context(
97        &self,
98        subject: &Subject,
99        action: &str,
100        resource: &Resource,
101        context: &HashMap<String, String>,
102    ) -> Result<bool> {
103        let system = self.inner.read().await;
104        system.check_permission_with_context(subject, action, resource, context)
105    }
106
107    /// Get all roles assigned to a subject.
108    pub async fn get_subject_roles(&self, subject: &Subject) -> Result<HashSet<String>> {
109        let system = self.inner.read().await;
110        system.get_subject_roles(subject)
111    }
112
113    /// Batch check multiple permissions for a subject.
114    pub async fn batch_check_permissions(
115        &self,
116        subject: &Subject,
117        checks: &[(String, Resource)], // (action, resource) pairs
118    ) -> Result<Vec<(String, Resource, bool)>> {
119        let system = self.inner.read().await;
120        let mut results = Vec::new();
121        
122        for (action, resource) in checks {
123            let granted = system.check_permission(subject, action, resource)?;
124            results.push((action.clone(), resource.clone(), granted));
125        }
126        
127        Ok(results)
128    }
129
130    /// Perform multiple role operations atomically.
131    pub async fn atomic_role_operations<F, R>(&self, operations: F) -> Result<R>
132    where
133        F: FnOnce(&mut RoleSystem<S>) -> Result<R> + Send,
134    {
135        let mut system = self.inner.write().await;
136        operations(&mut *system)
137    }
138
139    /// Get a read-only reference to the role system for complex queries.
140    pub async fn with_read_access<F, R>(&self, operation: F) -> R
141    where
142        F: FnOnce(&RoleSystem<S>) -> R + Send,
143    {
144        let system = self.inner.read().await;
145        operation(&*system)
146    }
147}
148
149impl<S> Clone for AsyncRoleSystem<S>
150where
151    S: Storage + Send + Sync,
152{
153    fn clone(&self) -> Self {
154        Self {
155            inner: Arc::clone(&self.inner),
156        }
157    }
158}
159
160/// Async trait for storage backends that support async operations.
161#[async_trait::async_trait]
162pub trait AsyncStorage: Send + Sync {
163    /// Store a role asynchronously.
164    async fn store_role(&mut self, role: Role) -> Result<()>;
165
166    /// Get a role by name asynchronously.
167    async fn get_role(&self, name: &str) -> Result<Option<Role>>;
168
169    /// Check if a role exists asynchronously.
170    async fn role_exists(&self, name: &str) -> Result<bool>;
171
172    /// Delete a role asynchronously.
173    async fn delete_role(&mut self, name: &str) -> Result<bool>;
174
175    /// List all role names asynchronously.
176    async fn list_roles(&self) -> Result<Vec<String>>;
177
178    /// Update an existing role asynchronously.
179    async fn update_role(&mut self, role: Role) -> Result<()>;
180}
181
182/// Async memory storage implementation.
183#[derive(Debug, Default)]
184pub struct AsyncMemoryStorage {
185    roles: Arc<RwLock<HashMap<String, Role>>>,
186}
187
188impl AsyncMemoryStorage {
189    /// Create a new async memory storage instance.
190    pub fn new() -> Self {
191        Self {
192            roles: Arc::new(RwLock::new(HashMap::new())),
193        }
194    }
195
196    /// Get the number of stored roles.
197    pub async fn role_count(&self) -> usize {
198        self.roles.read().await.len()
199    }
200
201    /// Clear all stored data.
202    pub async fn clear(&self) {
203        self.roles.write().await.clear();
204    }
205}
206
207#[async_trait::async_trait]
208impl AsyncStorage for AsyncMemoryStorage {
209    async fn store_role(&mut self, role: Role) -> Result<()> {
210        let name = role.name().to_string();
211        self.roles.write().await.insert(name, role);
212        Ok(())
213    }
214
215    async fn get_role(&self, name: &str) -> Result<Option<Role>> {
216        Ok(self.roles.read().await.get(name).cloned())
217    }
218
219    async fn role_exists(&self, name: &str) -> Result<bool> {
220        Ok(self.roles.read().await.contains_key(name))
221    }
222
223    async fn delete_role(&mut self, name: &str) -> Result<bool> {
224        Ok(self.roles.write().await.remove(name).is_some())
225    }
226
227    async fn list_roles(&self) -> Result<Vec<String>> {
228        Ok(self.roles.read().await.keys().cloned().collect())
229    }
230
231    async fn update_role(&mut self, role: Role) -> Result<()> {
232        let name = role.name().to_string();
233        self.roles.write().await.insert(name, role);
234        Ok(())
235    }
236}
237
238/// Helper trait for converting sync storage to async.
239pub struct AsyncStorageAdapter<S>
240where
241    S: Storage + Send + Sync,
242{
243    storage: Arc<Mutex<S>>,
244}
245
246impl<S> AsyncStorageAdapter<S>
247where
248    S: Storage + Send + Sync,
249{
250    /// Create a new async storage adapter.
251    pub fn new(storage: S) -> Self {
252        Self {
253            storage: Arc::new(Mutex::new(storage)),
254        }
255    }
256}
257
258#[async_trait::async_trait]
259impl<S> AsyncStorage for AsyncStorageAdapter<S>
260where
261    S: Storage + Send + Sync,
262{
263    async fn store_role(&mut self, role: Role) -> Result<()> {
264        let mut storage = self.storage.lock().await;
265        storage.store_role(role)
266    }
267
268    async fn get_role(&self, name: &str) -> Result<Option<Role>> {
269        let storage = self.storage.lock().await;
270        storage.get_role(name)
271    }
272
273    async fn role_exists(&self, name: &str) -> Result<bool> {
274        let storage = self.storage.lock().await;
275        storage.role_exists(name)
276    }
277
278    async fn delete_role(&mut self, name: &str) -> Result<bool> {
279        let mut storage = self.storage.lock().await;
280        storage.delete_role(name)
281    }
282
283    async fn list_roles(&self) -> Result<Vec<String>> {
284        let storage = self.storage.lock().await;
285        storage.list_roles()
286    }
287
288    async fn update_role(&mut self, role: Role) -> Result<()> {
289        let mut storage = self.storage.lock().await;
290        storage.update_role(role)
291    }
292}
293
294/// Async role system builder for easy configuration.
295pub struct AsyncRoleSystemBuilder<S>
296where
297    S: Storage + Send + Sync,
298{
299    config: RoleSystemConfig,
300    storage: Option<S>,
301}
302
303impl<S> AsyncRoleSystemBuilder<S>
304where
305    S: Storage + Send + Sync + Default,
306{
307    /// Create a new builder with default storage.
308    pub fn new() -> Self {
309        Self {
310            config: RoleSystemConfig::default(),
311            storage: None,
312        }
313    }
314}
315
316impl<S> Default for AsyncRoleSystemBuilder<S>
317where
318    S: Storage + Send + Sync + Default,
319{
320    fn default() -> Self {
321        Self::new()
322    }
323}
324
325impl<S> AsyncRoleSystemBuilder<S>
326where
327    S: Storage + Send + Sync,
328{
329    /// Create a new builder with custom storage.
330    pub fn with_storage(storage: S) -> Self {
331        Self {
332            config: RoleSystemConfig::default(),
333            storage: Some(storage),
334        }
335    }
336
337    /// Set the configuration.
338    pub fn config(mut self, config: RoleSystemConfig) -> Self {
339        self.config = config;
340        self
341    }
342
343    /// Set the maximum hierarchy depth.
344    pub fn max_hierarchy_depth(mut self, depth: usize) -> Self {
345        self.config.max_hierarchy_depth = depth;
346        self
347    }
348
349    /// Enable or disable permission caching.
350    pub fn enable_caching(mut self, enabled: bool) -> Self {
351        self.config.enable_caching = enabled;
352        self
353    }
354
355    /// Set the cache TTL in seconds.
356    pub fn cache_ttl_seconds(mut self, ttl: u64) -> Self {
357        self.config.cache_ttl_seconds = ttl;
358        self
359    }
360
361    /// Enable or disable audit logging.
362    pub fn enable_audit(mut self, enabled: bool) -> Self {
363        self.config.enable_audit = enabled;
364        self
365    }
366
367    /// Build the async role system.
368    pub fn build(self) -> AsyncRoleSystem<S>
369    where
370        S: Default,
371    {
372        let storage = self.storage.unwrap_or_default();
373        let role_system = RoleSystem::with_storage(storage, self.config);
374        AsyncRoleSystem::new(role_system)
375    }
376
377    /// Build the async role system with provided storage.
378    pub fn build_with_storage(self, storage: S) -> AsyncRoleSystem<S> {
379        let role_system = RoleSystem::with_storage(storage, self.config);
380        AsyncRoleSystem::new(role_system)
381    }
382}
383
384#[cfg(test)]
385mod tests {
386    use super::*;
387    use crate::{permission::Permission, storage::MemoryStorage};
388
389    #[tokio::test]
390    async fn test_async_role_system() {
391        let storage = MemoryStorage::new();
392        let config = RoleSystemConfig::default();
393        let role_system = RoleSystem::with_storage(storage, config);
394        let async_system = AsyncRoleSystem::new(role_system);
395
396        // Create and register a role
397        let role = Role::new("async-test")
398            .add_permission(Permission::new("read", "documents"));
399        
400        async_system.register_role(role).await.unwrap();
401
402        // Create a subject and assign the role
403        let subject = Subject::user("user1");
404        async_system.assign_role(&subject, "async-test").await.unwrap();
405
406        // Check permission
407        let resource = Resource::new("doc1", "documents");
408        let can_read = async_system
409            .check_permission(&subject, "read", &resource)
410            .await
411            .unwrap();
412        
413        assert!(can_read);
414    }
415
416    #[tokio::test]
417    async fn test_async_batch_permissions() {
418        let storage = MemoryStorage::new();
419        let config = RoleSystemConfig::default();
420        let role_system = RoleSystem::with_storage(storage, config);
421        let async_system = AsyncRoleSystem::new(role_system);
422
423        // Setup role and subject
424        let role = Role::new("batch-test")
425            .add_permission(Permission::new("read", "documents"))
426            .add_permission(Permission::new("write", "documents"));
427        
428        async_system.register_role(role).await.unwrap();
429
430        let subject = Subject::user("user1");
431        async_system.assign_role(&subject, "batch-test").await.unwrap();
432
433        // Batch check permissions
434        let checks = vec![
435            ("read".to_string(), Resource::new("doc1", "documents")),
436            ("write".to_string(), Resource::new("doc1", "documents")),
437            ("delete".to_string(), Resource::new("doc1", "documents")),
438        ];
439
440        let results = async_system
441            .batch_check_permissions(&subject, &checks)
442            .await
443            .unwrap();
444
445        assert_eq!(results.len(), 3);
446        assert!(results[0].2); // read granted
447        assert!(results[1].2); // write granted
448        assert!(!results[2].2); // delete denied
449    }
450
451    #[tokio::test]
452    async fn test_async_memory_storage() {
453        let mut storage = AsyncMemoryStorage::new();
454        
455        let role = Role::new("async-storage-test")
456            .add_permission(Permission::new("read", "documents"));
457        
458        // Store role
459        storage.store_role(role.clone()).await.unwrap();
460        assert_eq!(storage.role_count().await, 1);
461        
462        // Check existence
463        assert!(storage.role_exists("async-storage-test").await.unwrap());
464        
465        // Get role
466        let retrieved = storage.get_role("async-storage-test").await.unwrap().unwrap();
467        assert_eq!(retrieved.name(), "async-storage-test");
468        
469        // List roles
470        let roles = storage.list_roles().await.unwrap();
471        assert_eq!(roles.len(), 1);
472        
473        // Delete role
474        assert!(storage.delete_role("async-storage-test").await.unwrap());
475        assert_eq!(storage.role_count().await, 0);
476    }
477
478    #[tokio::test]
479    async fn test_async_builder() {
480        let async_system = AsyncRoleSystemBuilder::<MemoryStorage>::new()
481            .max_hierarchy_depth(5)
482            .enable_caching(false)
483            .build();
484
485        // Should be able to use the system
486        let role = Role::new("builder-test");
487        async_system.register_role(role).await.unwrap();
488        
489        let retrieved = async_system.get_role("builder-test").await.unwrap();
490        assert!(retrieved.is_some());
491    }
492}