1use async_trait::async_trait;
9use serde::{Deserialize, Serialize};
10use std::collections::HashMap;
11use std::sync::Arc;
12use tokio::sync::RwLock;
13use tracing::{debug, info};
14
15#[derive(Debug, thiserror::Error)]
19pub enum StorageError {
20 #[error("Database error: {0}")]
21 Database(String),
22 #[error("Serialization error: {0}")]
23 Serialization(String),
24 #[error("Not found: {0}")]
25 NotFound(String),
26}
27
28pub type StorageResult<T> = Result<T, StorageError>;
30
31#[derive(Debug, Clone, Serialize, Deserialize)]
35pub struct StoredRole {
36 pub id: String,
37 pub name: String,
38 pub description: Option<String>,
39 pub permissions: Vec<StoredPermission>,
40}
41
42#[derive(Debug, Clone, Serialize, Deserialize)]
44pub struct StoredPermission {
45 pub action: String,
46 pub resource: String,
47 pub instance: Option<String>,
48}
49
50#[derive(Debug, Clone, Serialize, Deserialize)]
52pub struct RoleAssignment {
53 pub user_id: String,
54 pub role_id: String,
55 pub assigned_by: Option<String>,
56 pub expires_at: Option<chrono::DateTime<chrono::Utc>>,
57}
58
59#[derive(Debug, Clone, Serialize, Deserialize)]
61pub struct AuditEntry {
62 pub user_id: Option<String>,
63 pub action: String,
64 pub resource: Option<String>,
65 pub result: String,
66 pub context: HashMap<String, String>,
67}
68
69impl StoredRole {
72 pub fn to_role_system(&self) -> role_system::Role {
74 let mut role = role_system::Role::with_id(&self.id, &self.name);
75 if let Some(ref desc) = self.description {
76 role = role.with_description(desc);
77 }
78 for perm in &self.permissions {
79 role = role.add_permission(perm.to_role_system());
80 }
81 role
82 }
83
84 pub fn from_role_system(role: &role_system::Role) -> Self {
86 Self {
87 id: role.id().to_string(),
88 name: role.name().to_string(),
89 description: role.description().map(|s| s.to_string()),
90 permissions: role
91 .permissions()
92 .permissions()
93 .iter()
94 .map(StoredPermission::from_role_system)
95 .collect(),
96 }
97 }
98}
99
100impl StoredPermission {
101 pub fn to_role_system(&self) -> role_system::Permission {
103 if let Some(ref instance) = self.instance {
104 role_system::Permission::with_instance(&self.action, &self.resource, instance)
105 } else {
106 role_system::Permission::new(&self.action, &self.resource)
107 }
108 }
109
110 pub fn from_role_system(perm: &role_system::Permission) -> Self {
112 Self {
113 action: perm.action().to_string(),
114 resource: perm.resource_type().to_string(),
115 instance: perm.instance().map(|s| s.to_string()),
116 }
117 }
118}
119
120#[async_trait]
124pub trait RoleStorage: Send + Sync {
125 async fn create_role(&self, role: &StoredRole) -> StorageResult<()>;
126 async fn update_role(&self, role: &StoredRole) -> StorageResult<()>;
127 async fn delete_role(&self, role_id: &str) -> StorageResult<()>;
128 async fn get_role(&self, role_id: &str) -> StorageResult<Option<StoredRole>>;
129 async fn list_roles(&self) -> StorageResult<Vec<StoredRole>>;
130
131 async fn store_permission(&self, id: &str, permission: &StoredPermission) -> StorageResult<()>;
132 async fn get_permission(&self, permission_id: &str) -> StorageResult<Option<StoredPermission>>;
133
134 async fn assign_role(&self, assignment: &RoleAssignment) -> StorageResult<()>;
135 async fn revoke_role(&self, user_id: &str, role_id: &str) -> StorageResult<()>;
136 async fn get_user_roles(&self, user_id: &str) -> StorageResult<Vec<String>>;
137 async fn get_role_permissions(&self, role_id: &str) -> StorageResult<Vec<String>>;
138
139 async fn log_audit_entry(&self, entry: &AuditEntry) -> StorageResult<()>;
140}
141
142pub struct DatabaseStorage {
146 connection: Arc<dyn DatabaseConnection>,
147 role_cache: Arc<RwLock<HashMap<String, StoredRole>>>,
148 permission_cache: Arc<RwLock<HashMap<String, StoredPermission>>>,
149 cache_ttl: u64,
150}
151
152#[async_trait]
154pub trait DatabaseConnection: Send + Sync {
155 async fn execute_query(
156 &self,
157 query: &str,
158 params: &[&dyn DatabaseValue],
159 ) -> Result<QueryResult, DatabaseError>;
160 async fn fetch_one(
161 &self,
162 query: &str,
163 params: &[&dyn DatabaseValue],
164 ) -> Result<Row, DatabaseError>;
165 async fn fetch_all(
166 &self,
167 query: &str,
168 params: &[&dyn DatabaseValue],
169 ) -> Result<Vec<Row>, DatabaseError>;
170}
171
172pub trait DatabaseValue: Send + Sync {
174 fn as_str(&self) -> Option<&str>;
175 fn as_i64(&self) -> Option<i64>;
176 fn as_bool(&self) -> Option<bool>;
177}
178
179impl DatabaseValue for String {
180 fn as_str(&self) -> Option<&str> {
181 Some(self.as_ref())
182 }
183 fn as_i64(&self) -> Option<i64> {
184 None
185 }
186 fn as_bool(&self) -> Option<bool> {
187 None
188 }
189}
190
191impl DatabaseValue for &str {
192 fn as_str(&self) -> Option<&str> {
193 Some(self)
194 }
195 fn as_i64(&self) -> Option<i64> {
196 None
197 }
198 fn as_bool(&self) -> Option<bool> {
199 None
200 }
201}
202
203impl DatabaseValue for Option<&str> {
204 fn as_str(&self) -> Option<&str> {
205 *self
206 }
207 fn as_i64(&self) -> Option<i64> {
208 None
209 }
210 fn as_bool(&self) -> Option<bool> {
211 None
212 }
213}
214
215impl DatabaseValue for i64 {
216 fn as_str(&self) -> Option<&str> {
217 None
218 }
219 fn as_i64(&self) -> Option<i64> {
220 Some(*self)
221 }
222 fn as_bool(&self) -> Option<bool> {
223 None
224 }
225}
226
227impl DatabaseValue for bool {
228 fn as_str(&self) -> Option<&str> {
229 None
230 }
231 fn as_i64(&self) -> Option<i64> {
232 None
233 }
234 fn as_bool(&self) -> Option<bool> {
235 Some(*self)
236 }
237}
238
239#[derive(Debug)]
241pub struct QueryResult {
242 pub rows_affected: u64,
243}
244
245#[derive(Debug)]
247pub struct Row {
248 pub columns: HashMap<String, DatabaseColumnValue>,
249}
250
251#[derive(Debug, Clone)]
253pub enum DatabaseColumnValue {
254 String(String),
255 Integer(i64),
256 Boolean(bool),
257 Null,
258}
259
260#[derive(Debug, thiserror::Error)]
262pub enum DatabaseError {
263 #[error("Connection error: {0}")]
264 Connection(String),
265 #[error("Query error: {0}")]
266 Query(String),
267 #[error("Serialization error: {0}")]
268 Serialization(String),
269}
270
271impl DatabaseStorage {
272 pub fn new(connection: Arc<dyn DatabaseConnection>) -> Self {
274 Self {
275 connection,
276 role_cache: Arc::new(RwLock::new(HashMap::new())),
277 permission_cache: Arc::new(RwLock::new(HashMap::new())),
278 cache_ttl: 300, }
280 }
281
282 pub fn with_cache_ttl(mut self, ttl_seconds: u64) -> Self {
284 self.cache_ttl = ttl_seconds;
285 self
286 }
287
288 pub async fn initialize_schema(&self) -> Result<(), DatabaseError> {
290 self.connection
291 .execute_query(
292 r#"CREATE TABLE IF NOT EXISTS roles (
293 id VARCHAR(255) PRIMARY KEY,
294 name VARCHAR(255) NOT NULL UNIQUE,
295 description TEXT,
296 created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP,
297 updated_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP
298 )"#,
299 &[],
300 )
301 .await?;
302
303 self.connection
304 .execute_query(
305 r#"CREATE TABLE IF NOT EXISTS permissions (
306 id VARCHAR(255) PRIMARY KEY,
307 action VARCHAR(255) NOT NULL,
308 resource VARCHAR(255) NOT NULL,
309 instance VARCHAR(255),
310 created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP,
311 UNIQUE(action, resource)
312 )"#,
313 &[],
314 )
315 .await?;
316
317 self.connection
318 .execute_query(
319 r#"CREATE TABLE IF NOT EXISTS role_permissions (
320 role_id VARCHAR(255),
321 permission_id VARCHAR(255),
322 granted_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP,
323 PRIMARY KEY (role_id, permission_id),
324 FOREIGN KEY (role_id) REFERENCES roles(id) ON DELETE CASCADE,
325 FOREIGN KEY (permission_id) REFERENCES permissions(id) ON DELETE CASCADE
326 )"#,
327 &[],
328 )
329 .await?;
330
331 self.connection
332 .execute_query(
333 r#"CREATE TABLE IF NOT EXISTS user_roles (
334 user_id VARCHAR(255),
335 role_id VARCHAR(255),
336 assigned_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP,
337 assigned_by VARCHAR(255),
338 expires_at TIMESTAMP NULL,
339 PRIMARY KEY (user_id, role_id),
340 FOREIGN KEY (role_id) REFERENCES roles(id) ON DELETE CASCADE
341 )"#,
342 &[],
343 )
344 .await?;
345
346 self.connection
347 .execute_query(
348 r#"CREATE TABLE IF NOT EXISTS audit_log (
349 id BIGINT PRIMARY KEY AUTO_INCREMENT,
350 user_id VARCHAR(255),
351 action VARCHAR(255) NOT NULL,
352 resource VARCHAR(255),
353 result VARCHAR(50) NOT NULL,
354 context TEXT,
355 timestamp TIMESTAMP DEFAULT CURRENT_TIMESTAMP
356 )"#,
357 &[],
358 )
359 .await?;
360
361 info!("Database schema initialized successfully");
362 Ok(())
363 }
364
365 async fn clear_caches(&self) {
367 self.role_cache.write().await.clear();
368 self.permission_cache.write().await.clear();
369 debug!("Cleared authorization caches");
370 }
371
372 fn row_to_stored_role(&self, row: &Row) -> StorageResult<StoredRole> {
373 let id = self.get_string_column(row, "id")?;
374 let name = self.get_string_column(row, "name")?;
375 let description = self.get_optional_string_column(row, "description");
376 Ok(StoredRole {
377 id,
378 name,
379 description,
380 permissions: Vec::new(), })
382 }
383
384 fn row_to_stored_permission(&self, row: &Row) -> StorageResult<StoredPermission> {
385 let action = self.get_string_column(row, "action")?;
386 let resource = self.get_string_column(row, "resource")?;
387 let instance = self.get_optional_string_column(row, "instance");
388 Ok(StoredPermission {
389 action,
390 resource,
391 instance,
392 })
393 }
394
395 fn get_string_column(&self, row: &Row, column: &str) -> StorageResult<String> {
396 match row.columns.get(column) {
397 Some(DatabaseColumnValue::String(value)) => Ok(value.clone()),
398 Some(DatabaseColumnValue::Null) => {
399 Err(StorageError::Database(format!("Column {column} is null")))
400 }
401 Some(_) => Err(StorageError::Database(format!(
402 "Column {column} is not a string"
403 ))),
404 None => Err(StorageError::Database(format!("Column {column} not found"))),
405 }
406 }
407
408 fn get_optional_string_column(&self, row: &Row, column: &str) -> Option<String> {
409 match row.columns.get(column) {
410 Some(DatabaseColumnValue::String(value)) => Some(value.clone()),
411 _ => None,
412 }
413 }
414}
415
416#[async_trait]
417impl RoleStorage for DatabaseStorage {
418 async fn create_role(&self, role: &StoredRole) -> StorageResult<()> {
419 self.connection
420 .execute_query(
421 "INSERT INTO roles (id, name, description) VALUES (?, ?, ?)",
422 &[
423 &role.id as &dyn DatabaseValue,
424 &role.name as &dyn DatabaseValue,
425 &role.description.as_deref().unwrap_or("") as &dyn DatabaseValue,
426 ],
427 )
428 .await
429 .map_err(|e| StorageError::Database(e.to_string()))?;
430 self.clear_caches().await;
431 info!("Created role: {}", role.name);
432 Ok(())
433 }
434
435 async fn update_role(&self, role: &StoredRole) -> StorageResult<()> {
436 self.connection
437 .execute_query(
438 "UPDATE roles SET name = ?, description = ?, updated_at = CURRENT_TIMESTAMP WHERE id = ?",
439 &[
440 &role.name as &dyn DatabaseValue,
441 &role.description.as_deref().unwrap_or("") as &dyn DatabaseValue,
442 &role.id as &dyn DatabaseValue,
443 ],
444 )
445 .await
446 .map_err(|e| StorageError::Database(e.to_string()))?;
447 self.role_cache
448 .write()
449 .await
450 .insert(role.id.clone(), role.clone());
451 info!("Updated role: {}", role.name);
452 Ok(())
453 }
454
455 async fn delete_role(&self, role_id: &str) -> StorageResult<()> {
456 self.connection
457 .execute_query(
458 "DELETE FROM roles WHERE id = ?",
459 &[&role_id as &dyn DatabaseValue],
460 )
461 .await
462 .map_err(|e| StorageError::Database(e.to_string()))?;
463 self.role_cache.write().await.remove(role_id);
464 info!("Deleted role: {}", role_id);
465 Ok(())
466 }
467
468 async fn get_role(&self, role_id: &str) -> StorageResult<Option<StoredRole>> {
469 {
470 let cache = self.role_cache.read().await;
471 if let Some(role) = cache.get(role_id) {
472 return Ok(Some(role.clone()));
473 }
474 }
475 let row = match self
476 .connection
477 .fetch_one(
478 "SELECT id, name, description FROM roles WHERE id = ?",
479 &[&role_id as &dyn DatabaseValue],
480 )
481 .await
482 {
483 Ok(row) => row,
484 Err(DatabaseError::Query(_)) => return Ok(None),
485 Err(e) => return Err(StorageError::Database(e.to_string())),
486 };
487 let role = self.row_to_stored_role(&row)?;
488 self.role_cache
489 .write()
490 .await
491 .insert(role_id.to_string(), role.clone());
492 Ok(Some(role))
493 }
494
495 async fn list_roles(&self) -> StorageResult<Vec<StoredRole>> {
496 let rows = self
497 .connection
498 .fetch_all("SELECT id, name, description FROM roles ORDER BY name", &[])
499 .await
500 .map_err(|e| StorageError::Database(e.to_string()))?;
501 rows.iter().map(|r| self.row_to_stored_role(r)).collect()
502 }
503
504 async fn store_permission(&self, id: &str, permission: &StoredPermission) -> StorageResult<()> {
505 self.connection
506 .execute_query(
507 "INSERT INTO permissions (id, action, resource, instance) VALUES (?, ?, ?, ?)",
508 &[
509 &id as &dyn DatabaseValue,
510 &permission.action as &dyn DatabaseValue,
511 &permission.resource as &dyn DatabaseValue,
512 &permission.instance.as_deref() as &dyn DatabaseValue,
513 ],
514 )
515 .await
516 .map_err(|e| StorageError::Database(e.to_string()))?;
517 self.permission_cache
518 .write()
519 .await
520 .insert(id.to_string(), permission.clone());
521 info!(
522 "Created permission: {}:{}",
523 permission.action, permission.resource
524 );
525 Ok(())
526 }
527
528 async fn get_permission(&self, permission_id: &str) -> StorageResult<Option<StoredPermission>> {
529 {
530 let cache = self.permission_cache.read().await;
531 if let Some(p) = cache.get(permission_id) {
532 return Ok(Some(p.clone()));
533 }
534 }
535 let row = match self
536 .connection
537 .fetch_one(
538 "SELECT action, resource, instance FROM permissions WHERE id = ?",
539 &[&permission_id as &dyn DatabaseValue],
540 )
541 .await
542 {
543 Ok(row) => row,
544 Err(DatabaseError::Query(_)) => return Ok(None),
545 Err(e) => return Err(StorageError::Database(e.to_string())),
546 };
547 let perm = self.row_to_stored_permission(&row)?;
548 self.permission_cache
549 .write()
550 .await
551 .insert(permission_id.to_string(), perm.clone());
552 Ok(Some(perm))
553 }
554
555 async fn assign_role(&self, assignment: &RoleAssignment) -> StorageResult<()> {
556 self.connection
557 .execute_query(
558 "INSERT OR REPLACE INTO user_roles (user_id, role_id, assigned_by) VALUES (?, ?, ?)",
559 &[
560 &assignment.user_id as &dyn DatabaseValue,
561 &assignment.role_id as &dyn DatabaseValue,
562 &assignment.assigned_by.as_deref() as &dyn DatabaseValue,
563 ],
564 )
565 .await
566 .map_err(|e| StorageError::Database(e.to_string()))?;
567 info!(
568 "Assigned role {} to user {}",
569 assignment.role_id, assignment.user_id
570 );
571 Ok(())
572 }
573
574 async fn revoke_role(&self, user_id: &str, role_id: &str) -> StorageResult<()> {
575 self.connection
576 .execute_query(
577 "DELETE FROM user_roles WHERE user_id = ? AND role_id = ?",
578 &[
579 &user_id as &dyn DatabaseValue,
580 &role_id as &dyn DatabaseValue,
581 ],
582 )
583 .await
584 .map_err(|e| StorageError::Database(e.to_string()))?;
585 info!("Revoked role {} from user {}", role_id, user_id);
586 Ok(())
587 }
588
589 async fn get_user_roles(&self, user_id: &str) -> StorageResult<Vec<String>> {
590 let rows = self
591 .connection
592 .fetch_all(
593 "SELECT role_id FROM user_roles WHERE user_id = ? AND (expires_at IS NULL OR expires_at > CURRENT_TIMESTAMP)",
594 &[&user_id as &dyn DatabaseValue],
595 )
596 .await
597 .map_err(|e| StorageError::Database(e.to_string()))?;
598 Ok(rows
599 .iter()
600 .filter_map(|r| match r.columns.get("role_id") {
601 Some(DatabaseColumnValue::String(s)) => Some(s.clone()),
602 _ => None,
603 })
604 .collect())
605 }
606
607 async fn get_role_permissions(&self, role_id: &str) -> StorageResult<Vec<String>> {
608 let rows = self
609 .connection
610 .fetch_all(
611 "SELECT permission_id FROM role_permissions WHERE role_id = ?",
612 &[&role_id as &dyn DatabaseValue],
613 )
614 .await
615 .map_err(|e| StorageError::Database(e.to_string()))?;
616 Ok(rows
617 .iter()
618 .filter_map(|r| match r.columns.get("permission_id") {
619 Some(DatabaseColumnValue::String(s)) => Some(s.clone()),
620 _ => None,
621 })
622 .collect())
623 }
624
625 async fn log_audit_entry(&self, entry: &AuditEntry) -> StorageResult<()> {
626 let context_json = serde_json::to_string(&entry.context)
627 .map_err(|e| StorageError::Serialization(e.to_string()))?;
628 self.connection
629 .execute_query(
630 "INSERT INTO audit_log (user_id, action, resource, result, context) VALUES (?, ?, ?, ?, ?)",
631 &[
632 &entry.user_id.as_deref() as &dyn DatabaseValue,
633 &entry.action as &dyn DatabaseValue,
634 &entry.resource.as_deref() as &dyn DatabaseValue,
635 &entry.result as &dyn DatabaseValue,
636 &context_json as &dyn DatabaseValue,
637 ],
638 )
639 .await
640 .map_err(|e| StorageError::Database(e.to_string()))?;
641 debug!(
642 "Logged audit entry for user {:?}: {}",
643 entry.user_id, entry.action
644 );
645 Ok(())
646 }
647}
648
649pub struct MemoryRbacStorage {
653 roles: Arc<RwLock<HashMap<String, StoredRole>>>,
654 permissions: Arc<RwLock<HashMap<String, StoredPermission>>>,
655 user_roles: Arc<RwLock<HashMap<String, Vec<String>>>>,
656 role_permissions: Arc<RwLock<HashMap<String, Vec<String>>>>,
657 audit_log: Arc<RwLock<Vec<AuditEntry>>>,
658}
659
660impl Default for MemoryRbacStorage {
661 fn default() -> Self {
662 Self::new()
663 }
664}
665
666impl MemoryRbacStorage {
667 pub fn new() -> Self {
668 Self {
669 roles: Arc::new(RwLock::new(HashMap::new())),
670 permissions: Arc::new(RwLock::new(HashMap::new())),
671 user_roles: Arc::new(RwLock::new(HashMap::new())),
672 role_permissions: Arc::new(RwLock::new(HashMap::new())),
673 audit_log: Arc::new(RwLock::new(Vec::new())),
674 }
675 }
676
677 pub async fn clear(&self) {
679 self.roles.write().await.clear();
680 self.permissions.write().await.clear();
681 self.user_roles.write().await.clear();
682 self.role_permissions.write().await.clear();
683 self.audit_log.write().await.clear();
684 }
685}
686
687#[async_trait]
688impl RoleStorage for MemoryRbacStorage {
689 async fn create_role(&self, role: &StoredRole) -> StorageResult<()> {
690 self.roles
691 .write()
692 .await
693 .insert(role.id.clone(), role.clone());
694 info!("Created role in memory: {}", role.name);
695 Ok(())
696 }
697
698 async fn update_role(&self, role: &StoredRole) -> StorageResult<()> {
699 self.roles
700 .write()
701 .await
702 .insert(role.id.clone(), role.clone());
703 info!("Updated role in memory: {}", role.name);
704 Ok(())
705 }
706
707 async fn delete_role(&self, role_id: &str) -> StorageResult<()> {
708 self.roles.write().await.remove(role_id);
709 info!("Deleted role from memory: {}", role_id);
710 Ok(())
711 }
712
713 async fn get_role(&self, role_id: &str) -> StorageResult<Option<StoredRole>> {
714 Ok(self.roles.read().await.get(role_id).cloned())
715 }
716
717 async fn list_roles(&self) -> StorageResult<Vec<StoredRole>> {
718 Ok(self.roles.read().await.values().cloned().collect())
719 }
720
721 async fn store_permission(&self, id: &str, permission: &StoredPermission) -> StorageResult<()> {
722 self.permissions
723 .write()
724 .await
725 .insert(id.to_string(), permission.clone());
726 info!(
727 "Created permission in memory: {}:{}",
728 permission.action, permission.resource
729 );
730 Ok(())
731 }
732
733 async fn get_permission(&self, permission_id: &str) -> StorageResult<Option<StoredPermission>> {
734 Ok(self.permissions.read().await.get(permission_id).cloned())
735 }
736
737 async fn assign_role(&self, assignment: &RoleAssignment) -> StorageResult<()> {
738 self.user_roles
739 .write()
740 .await
741 .entry(assignment.user_id.clone())
742 .or_default()
743 .push(assignment.role_id.clone());
744 info!(
745 "Assigned role in memory: {} to {}",
746 assignment.role_id, assignment.user_id
747 );
748 Ok(())
749 }
750
751 async fn revoke_role(&self, user_id: &str, role_id: &str) -> StorageResult<()> {
752 if let Some(roles) = self.user_roles.write().await.get_mut(user_id) {
753 roles.retain(|r| r != role_id);
754 }
755 info!("Revoked role from memory: {} from {}", role_id, user_id);
756 Ok(())
757 }
758
759 async fn get_user_roles(&self, user_id: &str) -> StorageResult<Vec<String>> {
760 Ok(self
761 .user_roles
762 .read()
763 .await
764 .get(user_id)
765 .cloned()
766 .unwrap_or_default())
767 }
768
769 async fn get_role_permissions(&self, role_id: &str) -> StorageResult<Vec<String>> {
770 Ok(self
771 .role_permissions
772 .read()
773 .await
774 .get(role_id)
775 .cloned()
776 .unwrap_or_default())
777 }
778
779 async fn log_audit_entry(&self, entry: &AuditEntry) -> StorageResult<()> {
780 self.audit_log.write().await.push(entry.clone());
781 debug!(
782 "Logged audit entry in memory for user {:?}: {}",
783 entry.user_id, entry.action
784 );
785 Ok(())
786 }
787}
788
789#[cfg(test)]
790mod tests {
791 use super::*;
792
793 #[tokio::test]
794 async fn test_memory_storage_basic_operations() {
795 let storage = MemoryRbacStorage::new();
796
797 let role = StoredRole {
798 id: "test_role".to_string(),
799 name: "Test Role".to_string(),
800 description: Some("A test role".to_string()),
801 permissions: Vec::new(),
802 };
803
804 storage.create_role(&role).await.unwrap();
805
806 let retrieved = storage.get_role("test_role").await.unwrap();
807 assert!(retrieved.is_some());
808 assert_eq!(retrieved.unwrap().name, "Test Role");
809
810 let roles = storage.list_roles().await.unwrap();
811 assert_eq!(roles.len(), 1);
812
813 storage.delete_role("test_role").await.unwrap();
814 let retrieved = storage.get_role("test_role").await.unwrap();
815 assert!(retrieved.is_none());
816 }
817
818 #[tokio::test]
819 async fn test_memory_storage_permissions() {
820 let storage = MemoryRbacStorage::new();
821
822 let permission = StoredPermission {
823 action: "read".to_string(),
824 resource: "users".to_string(),
825 instance: None,
826 };
827
828 storage
829 .store_permission("test_perm", &permission)
830 .await
831 .unwrap();
832
833 let retrieved = storage.get_permission("test_perm").await.unwrap();
834 assert!(retrieved.is_some());
835 assert_eq!(retrieved.unwrap().action, "read");
836 }
837
838 #[tokio::test]
839 async fn test_memory_storage_role_assignment() {
840 let storage = MemoryRbacStorage::new();
841
842 let assignment = RoleAssignment {
843 user_id: "user1".to_string(),
844 role_id: "admin".to_string(),
845 assigned_by: Some("system".to_string()),
846 expires_at: None,
847 };
848
849 storage.assign_role(&assignment).await.unwrap();
850 let user_roles = storage.get_user_roles("user1").await.unwrap();
851 assert_eq!(user_roles, vec!["admin"]);
852
853 storage.revoke_role("user1", "admin").await.unwrap();
854 let user_roles = storage.get_user_roles("user1").await.unwrap();
855 assert!(user_roles.is_empty());
856 }
857
858 #[tokio::test]
859 async fn test_stored_role_conversion_roundtrip() {
860 let stored = StoredRole {
861 id: "role1".to_string(),
862 name: "Admin".to_string(),
863 description: Some("Administrator role".to_string()),
864 permissions: vec![StoredPermission {
865 action: "read".to_string(),
866 resource: "users".to_string(),
867 instance: None,
868 }],
869 };
870
871 let rs_role = stored.to_role_system();
872 assert_eq!(rs_role.id(), "role1");
873 assert_eq!(rs_role.name(), "Admin");
874 assert_eq!(rs_role.description(), Some("Administrator role"));
875
876 let back = StoredRole::from_role_system(&rs_role);
877 assert_eq!(back.id, "role1");
878 assert_eq!(back.name, "Admin");
879 assert_eq!(back.permissions.len(), 1);
880 assert_eq!(back.permissions[0].action, "read");
881 }
882
883 #[tokio::test]
884 async fn test_audit_logging() {
885 let storage = MemoryRbacStorage::new();
886
887 let entry = AuditEntry {
888 user_id: Some("user1".to_string()),
889 action: "login".to_string(),
890 resource: Some("auth".to_string()),
891 result: "success".to_string(),
892 context: HashMap::from([("ip".to_string(), "127.0.0.1".to_string())]),
893 };
894
895 storage.log_audit_entry(&entry).await.unwrap();
896 let log = storage.audit_log.read().await;
897 assert_eq!(log.len(), 1);
898 assert_eq!(log[0].action, "login");
899 }
900}