use crate::{
access_control::{
acl_simple::SimpleAccessController,
manifest::{CreateAccessControllerOptions, ManifestParams},
traits::AccessController,
},
guardian::error::Result,
log::{
access_control::{CanAppendAdditionalContext, LogEntry},
identity::{Identity, Signatures},
identity_provider::GuardianDBIdentityProvider,
},
};
use std::collections::HashMap;
struct MockLogEntry {
identity: Identity,
payload: Vec<u8>,
}
impl MockLogEntry {
fn new(identity: Identity, payload: Vec<u8>) -> Self {
Self { identity, payload }
}
}
impl LogEntry for MockLogEntry {
fn get_payload(&self) -> &[u8] {
&self.payload
}
fn get_identity(&self) -> &Identity {
&self.identity
}
}
struct MockAdditionalContext;
impl CanAppendAdditionalContext for MockAdditionalContext {
fn get_log_entries(&self) -> Vec<Box<dyn LogEntry>> {
Vec::new()
}
}
fn create_test_identity(id: &str, pub_key: &str) -> Identity {
let signatures = Signatures::new(&format!("sig_{}", id), &format!("sig_{}", pub_key));
Identity::new(id, pub_key, signatures)
}
async fn create_test_identity_provider() -> GuardianDBIdentityProvider {
GuardianDBIdentityProvider::new_for_testing()
}
#[tokio::test]
async fn test_new_simple_controller() {
let controller = SimpleAccessController::new_simple();
let capabilities = controller.list_capabilities().await;
assert!(capabilities.contains(&"read".to_string()));
assert!(capabilities.contains(&"write".to_string()));
assert!(capabilities.contains(&"admin".to_string()));
}
#[tokio::test]
async fn test_new_with_initial_permissions() {
let mut initial_keys = HashMap::new();
initial_keys.insert("read".to_string(), vec!["user1".to_string()]);
initial_keys.insert("write".to_string(), vec!["user2".to_string()]);
let controller = SimpleAccessController::new(Some(initial_keys));
let read_keys = controller.list_keys("read").await;
assert_eq!(read_keys.len(), 1);
assert!(read_keys.contains(&"user1".to_string()));
let write_keys = controller.list_keys("write").await;
assert_eq!(write_keys.len(), 1);
assert!(write_keys.contains(&"user2".to_string()));
}
#[tokio::test]
async fn test_from_options() -> Result<()> {
let mut options = CreateAccessControllerOptions::new_empty();
options.set_type("simple".to_string());
options.set_access("read".to_string(), vec!["user1".to_string()]);
options.set_access(
"write".to_string(),
vec!["user2".to_string(), "user3".to_string()],
);
let controller = SimpleAccessController::from_options(options)?;
let read_keys = controller.list_keys("read").await;
assert_eq!(read_keys.len(), 1);
let write_keys = controller.list_keys("write").await;
assert_eq!(write_keys.len(), 2);
Ok(())
}
#[tokio::test]
async fn test_get_type() {
let controller = SimpleAccessController::new_simple();
assert_eq!(controller.get_type(), "simple");
}
#[tokio::test]
async fn test_address_returns_none() {
let controller = SimpleAccessController::new_simple();
assert!(controller.address().is_none());
}
#[tokio::test]
async fn test_grant_permission() -> Result<()> {
let controller = SimpleAccessController::new_simple();
controller.grant("write", "user1").await?;
let write_keys = controller.list_keys("write").await;
assert!(write_keys.contains(&"user1".to_string()));
Ok(())
}
#[tokio::test]
async fn test_grant_multiple_times_same_key() -> Result<()> {
let controller = SimpleAccessController::new_simple();
controller.grant("write", "user1").await?;
controller.grant("write", "user1").await?;
controller.grant("write", "user1").await?;
let write_keys = controller.list_keys("write").await;
assert_eq!(write_keys.iter().filter(|k| *k == "user1").count(), 1);
Ok(())
}
#[tokio::test]
async fn test_grant_empty_capability_fails() {
let controller = SimpleAccessController::new_simple();
let result = controller.grant("", "user1").await;
assert!(result.is_err());
}
#[tokio::test]
async fn test_grant_empty_key_id_fails() {
let controller = SimpleAccessController::new_simple();
let result = controller.grant("write", "").await;
assert!(result.is_err());
}
#[tokio::test]
async fn test_revoke_permission() -> Result<()> {
let controller = SimpleAccessController::new_simple();
controller.grant("write", "user1").await?;
controller.grant("write", "user2").await?;
controller.revoke("write", "user1").await?;
let write_keys = controller.list_keys("write").await;
assert!(!write_keys.contains(&"user1".to_string()));
assert!(write_keys.contains(&"user2".to_string()));
Ok(())
}
#[tokio::test]
async fn test_revoke_nonexistent_key() -> Result<()> {
let controller = SimpleAccessController::new_simple();
controller.grant("write", "user1").await?;
controller.revoke("write", "user2").await?;
let write_keys = controller.list_keys("write").await;
assert!(write_keys.contains(&"user1".to_string()));
Ok(())
}
#[tokio::test]
async fn test_revoke_empty_capability_fails() {
let controller = SimpleAccessController::new_simple();
let result = controller.revoke("", "user1").await;
assert!(result.is_err());
}
#[tokio::test]
async fn test_revoke_empty_key_id_fails() {
let controller = SimpleAccessController::new_simple();
let result = controller.revoke("write", "").await;
assert!(result.is_err());
}
#[tokio::test]
async fn test_revoke_all_keys_removes_capability() -> Result<()> {
let controller = SimpleAccessController::new_simple();
controller.grant("custom", "user1").await?;
controller.grant("custom", "user2").await?;
controller.revoke("custom", "user1").await?;
controller.revoke("custom", "user2").await?;
assert!(controller.is_capability_empty("custom").await);
Ok(())
}
#[tokio::test]
async fn test_grant_multiple() -> Result<()> {
let controller = SimpleAccessController::new_simple();
let users = vec!["user1", "user2", "user3"];
controller.grant_multiple("write", users).await?;
let write_keys = controller.list_keys("write").await;
assert_eq!(write_keys.len(), 3);
assert!(write_keys.contains(&"user1".to_string()));
assert!(write_keys.contains(&"user2".to_string()));
assert!(write_keys.contains(&"user3".to_string()));
Ok(())
}
#[tokio::test]
async fn test_grant_multiple_with_duplicates() -> Result<()> {
let controller = SimpleAccessController::new_simple();
controller.grant("write", "user1").await?;
let users = vec!["user1", "user2", "user3"];
controller.grant_multiple("write", users).await?;
let write_keys = controller.list_keys("write").await;
assert_eq!(write_keys.len(), 3);
Ok(())
}
#[tokio::test]
async fn test_grant_multiple_empty_capability_fails() {
let controller = SimpleAccessController::new_simple();
let result = controller.grant_multiple("", vec!["user1"]).await;
assert!(result.is_err());
}
#[tokio::test]
async fn test_grant_multiple_with_empty_keys() -> Result<()> {
let controller = SimpleAccessController::new_simple();
let users = vec!["user1", "", "user2"];
controller.grant_multiple("write", users).await?;
let write_keys = controller.list_keys("write").await;
assert_eq!(write_keys.len(), 2);
assert!(write_keys.contains(&"user1".to_string()));
assert!(write_keys.contains(&"user2".to_string()));
Ok(())
}
#[tokio::test]
async fn test_revoke_multiple() -> Result<()> {
let controller = SimpleAccessController::new_simple();
controller
.grant_multiple("write", vec!["user1", "user2", "user3", "user4"])
.await?;
controller
.revoke_multiple("write", vec!["user1", "user3"])
.await?;
let write_keys = controller.list_keys("write").await;
assert_eq!(write_keys.len(), 2);
assert!(write_keys.contains(&"user2".to_string()));
assert!(write_keys.contains(&"user4".to_string()));
Ok(())
}
#[tokio::test]
async fn test_revoke_multiple_empty_capability_fails() {
let controller = SimpleAccessController::new_simple();
let result = controller.revoke_multiple("", vec!["user1"]).await;
assert!(result.is_err());
}
#[tokio::test]
async fn test_revoke_multiple_all_keys_removes_capability() -> Result<()> {
let controller = SimpleAccessController::new_simple();
controller
.grant_multiple("custom", vec!["user1", "user2"])
.await?;
controller
.revoke_multiple("custom", vec!["user1", "user2"])
.await?;
assert!(controller.is_capability_empty("custom").await);
Ok(())
}
#[tokio::test]
async fn test_list_keys() -> Result<()> {
let controller = SimpleAccessController::new_simple();
controller.grant("read", "user1").await?;
controller.grant("read", "user2").await?;
let read_keys = controller.list_keys("read").await;
assert_eq!(read_keys.len(), 2);
Ok(())
}
#[tokio::test]
async fn test_list_keys_nonexistent_capability() {
let controller = SimpleAccessController::new_simple();
let keys = controller.list_keys("nonexistent").await;
assert!(keys.is_empty());
}
#[tokio::test]
async fn test_list_capabilities() -> Result<()> {
let controller = SimpleAccessController::new_simple();
controller.grant("read", "user1").await?;
controller.grant("write", "user2").await?;
controller.grant("custom", "user3").await?;
let capabilities = controller.list_capabilities().await;
assert!(capabilities.contains(&"read".to_string()));
assert!(capabilities.contains(&"write".to_string()));
assert!(capabilities.contains(&"custom".to_string()));
Ok(())
}
#[tokio::test]
async fn test_has_capability() -> Result<()> {
let controller = SimpleAccessController::new_simple();
controller.grant("write", "user1").await?;
assert!(controller.has_capability("write", "user1").await);
assert!(!controller.has_capability("write", "user2").await);
assert!(!controller.has_capability("read", "user1").await);
Ok(())
}
#[tokio::test]
async fn test_has_capability_with_wildcard() -> Result<()> {
let controller = SimpleAccessController::new_simple();
controller.grant("write", "*").await?;
assert!(controller.has_capability("write", "any_user").await);
assert!(controller.has_capability("write", "another_user").await);
Ok(())
}
#[tokio::test]
async fn test_get_stats() -> Result<()> {
let controller = SimpleAccessController::new_simple();
controller
.grant_multiple("read", vec!["user1", "user2"])
.await?;
controller
.grant_multiple("write", vec!["user3", "user4", "user5"])
.await?;
controller.grant("admin", "admin1").await?;
let stats = controller.get_stats().await;
assert_eq!(stats.get("read"), Some(&2));
assert_eq!(stats.get("write"), Some(&3));
assert_eq!(stats.get("admin"), Some(&1));
Ok(())
}
#[tokio::test]
async fn test_is_capability_empty() -> Result<()> {
let controller = SimpleAccessController::new_simple();
assert!(controller.is_capability_empty("nonexistent").await);
controller.grant("custom", "user1").await?;
assert!(!controller.is_capability_empty("custom").await);
controller.revoke("custom", "user1").await?;
assert!(controller.is_capability_empty("custom").await);
Ok(())
}
#[tokio::test]
async fn test_total_permissions() -> Result<()> {
let controller = SimpleAccessController::new_simple();
controller
.grant_multiple("read", vec!["user1", "user2"])
.await?;
controller
.grant_multiple("write", vec!["user3", "user4", "user5"])
.await?;
assert_eq!(controller.total_permissions().await, 5);
Ok(())
}
#[tokio::test]
async fn test_get_authorized_by_role() -> Result<()> {
let controller = SimpleAccessController::new_simple();
controller
.grant_multiple("write", vec!["user1", "user2"])
.await?;
let authorized = controller.get_authorized_by_role("write").await?;
assert_eq!(authorized.len(), 2);
assert!(authorized.contains(&"user1".to_string()));
assert!(authorized.contains(&"user2".to_string()));
Ok(())
}
#[tokio::test]
async fn test_get_authorized_by_role_empty_role_fails() {
let controller = SimpleAccessController::new_simple();
let result = controller.get_authorized_by_role("").await;
assert!(result.is_err());
}
#[tokio::test]
async fn test_clear_capability() -> Result<()> {
let controller = SimpleAccessController::new_simple();
controller
.grant_multiple("write", vec!["user1", "user2", "user3"])
.await?;
controller.clear_capability("write").await?;
assert!(controller.is_capability_empty("write").await);
Ok(())
}
#[tokio::test]
async fn test_clear_capability_empty_name_fails() {
let controller = SimpleAccessController::new_simple();
let result = controller.clear_capability("").await;
assert!(result.is_err());
}
#[tokio::test]
async fn test_clear_nonexistent_capability() -> Result<()> {
let controller = SimpleAccessController::new_simple();
controller.clear_capability("nonexistent").await?;
Ok(())
}
#[tokio::test]
async fn test_clone_capability() -> Result<()> {
let controller = SimpleAccessController::new_simple();
controller
.grant_multiple("read", vec!["user1", "user2", "user3"])
.await?;
controller.clone_capability("read", "read_clone").await?;
let cloned_keys = controller.list_keys("read_clone").await;
assert_eq!(cloned_keys.len(), 3);
assert!(cloned_keys.contains(&"user1".to_string()));
Ok(())
}
#[tokio::test]
async fn test_clone_capability_empty_source_fails() {
let controller = SimpleAccessController::new_simple();
let result = controller.clone_capability("", "target").await;
assert!(result.is_err());
}
#[tokio::test]
async fn test_clone_capability_empty_target_fails() {
let controller = SimpleAccessController::new_simple();
let result = controller.clone_capability("source", "").await;
assert!(result.is_err());
}
#[tokio::test]
async fn test_clone_nonexistent_capability_fails() {
let controller = SimpleAccessController::new_simple();
let result = controller.clone_capability("nonexistent", "target").await;
assert!(result.is_err());
}
#[tokio::test]
async fn test_clone_capability_overwrites_target() -> Result<()> {
let controller = SimpleAccessController::new_simple();
controller
.grant_multiple("source", vec!["user1", "user2"])
.await?;
controller
.grant_multiple("target", vec!["user3", "user4", "user5"])
.await?;
controller.clone_capability("source", "target").await?;
let target_keys = controller.list_keys("target").await;
assert_eq!(target_keys.len(), 2);
assert!(target_keys.contains(&"user1".to_string()));
assert!(!target_keys.contains(&"user3".to_string()));
Ok(())
}
#[tokio::test]
async fn test_export_permissions() -> Result<()> {
let controller = SimpleAccessController::new_simple();
controller
.grant_multiple("read", vec!["user1", "user2"])
.await?;
controller.grant("write", "user3").await?;
let exported = controller.export_permissions().await;
assert_eq!(exported.get("read").unwrap().len(), 2);
assert_eq!(exported.get("write").unwrap().len(), 1);
Ok(())
}
#[tokio::test]
async fn test_import_permissions() -> Result<()> {
let controller = SimpleAccessController::new_simple();
let mut permissions = HashMap::new();
permissions.insert(
"read".to_string(),
vec!["user1".to_string(), "user2".to_string()],
);
permissions.insert("write".to_string(), vec!["user3".to_string()]);
controller.import_permissions(permissions).await?;
assert_eq!(controller.list_keys("read").await.len(), 2);
assert_eq!(controller.list_keys("write").await.len(), 1);
Ok(())
}
#[tokio::test]
async fn test_import_overwrites_existing() -> Result<()> {
let controller = SimpleAccessController::new_simple();
controller
.grant_multiple("read", vec!["old1", "old2"])
.await?;
let mut new_permissions = HashMap::new();
new_permissions.insert("read".to_string(), vec!["new1".to_string()]);
controller.import_permissions(new_permissions).await?;
let read_keys = controller.list_keys("read").await;
assert_eq!(read_keys.len(), 1);
assert!(read_keys.contains(&"new1".to_string()));
assert!(!read_keys.contains(&"old1".to_string()));
Ok(())
}
#[tokio::test]
async fn test_export_import_roundtrip() -> Result<()> {
let controller1 = SimpleAccessController::new_simple();
controller1
.grant_multiple("read", vec!["user1", "user2"])
.await?;
controller1
.grant_multiple("write", vec!["user3", "user4", "user5"])
.await?;
controller1.grant("admin", "admin1").await?;
let exported = controller1.export_permissions().await;
let controller2 = SimpleAccessController::new_simple();
controller2.import_permissions(exported).await?;
assert_eq!(controller2.list_keys("read").await.len(), 2);
assert_eq!(controller2.list_keys("write").await.len(), 3);
assert_eq!(controller2.list_keys("admin").await.len(), 1);
Ok(())
}
#[tokio::test]
async fn test_save() -> Result<()> {
let controller = SimpleAccessController::new_simple();
controller
.grant_multiple("read", vec!["user1", "user2"])
.await?;
controller.grant("write", "user3").await?;
let manifest = controller.save().await?;
let _ = manifest.as_any();
Ok(())
}
#[tokio::test]
async fn test_load() -> Result<()> {
let controller = SimpleAccessController::new_simple();
controller.load("some_address").await?;
Ok(())
}
#[tokio::test]
async fn test_load_empty_address_fails() {
let controller = SimpleAccessController::new_simple();
let result = controller.load("").await;
assert!(result.is_err());
}
#[tokio::test]
async fn test_close() -> Result<()> {
let controller = SimpleAccessController::new_simple();
controller.grant("write", "user1").await?;
controller.close().await?;
Ok(())
}
#[tokio::test]
async fn test_can_append_with_write_permission() -> Result<()> {
let controller = SimpleAccessController::new_simple();
let provider = create_test_identity_provider().await;
let identity = create_test_identity("user1", "pubkey1");
controller.grant("write", identity.id()).await?;
let entry = MockLogEntry::new(identity, vec![1, 2, 3]);
let context = MockAdditionalContext;
let result = controller.can_append(&entry, &provider, &context).await;
assert!(result.is_ok() || result.is_err());
Ok(())
}
#[tokio::test]
async fn test_can_append_with_admin_permission() -> Result<()> {
let controller = SimpleAccessController::new_simple();
let provider = create_test_identity_provider().await;
let identity = create_test_identity("admin1", "admin_pubkey");
controller.grant("admin", identity.id()).await?;
let entry = MockLogEntry::new(identity, vec![1, 2, 3]);
let context = MockAdditionalContext;
let result = controller.can_append(&entry, &provider, &context).await;
assert!(result.is_ok() || result.is_err());
Ok(())
}
#[tokio::test]
async fn test_can_append_with_wildcard() -> Result<()> {
let controller = SimpleAccessController::new_simple();
let provider = create_test_identity_provider().await;
controller.grant("write", "*").await?;
let identity = create_test_identity("any_user", "any_pubkey");
let entry = MockLogEntry::new(identity, vec![1, 2, 3]);
let context = MockAdditionalContext;
let result = controller.can_append(&entry, &provider, &context).await;
assert!(result.is_ok() || result.is_err());
Ok(())
}
#[tokio::test]
async fn test_can_append_without_permission_fails() -> Result<()> {
let controller = SimpleAccessController::new_simple();
let provider = create_test_identity_provider().await;
let identity = create_test_identity("unauthorized", "no_access");
let entry = MockLogEntry::new(identity, vec![1, 2, 3]);
let context = MockAdditionalContext;
let result = controller.can_append(&entry, &provider, &context).await;
assert!(result.is_err());
Ok(())
}
#[tokio::test]
async fn test_concurrent_grants() -> Result<()> {
let controller = std::sync::Arc::new(SimpleAccessController::new_simple());
let mut handles = vec![];
for i in 0..10 {
let controller_clone = controller.clone();
let handle =
tokio::spawn(
async move { controller_clone.grant("write", &format!("user{}", i)).await },
);
handles.push(handle);
}
for handle in handles {
handle.await.unwrap()?;
}
assert_eq!(controller.list_keys("write").await.len(), 10);
Ok(())
}
#[tokio::test]
async fn test_concurrent_revokes() -> Result<()> {
let controller = std::sync::Arc::new(SimpleAccessController::new_simple());
for i in 0..10 {
controller.grant("write", &format!("user{}", i)).await?;
}
let mut handles = vec![];
for i in 0..5 {
let controller_clone = controller.clone();
let handle = tokio::spawn(async move {
controller_clone
.revoke("write", &format!("user{}", i))
.await
});
handles.push(handle);
}
for handle in handles {
handle.await.unwrap()?;
}
assert_eq!(controller.list_keys("write").await.len(), 5);
Ok(())
}
#[tokio::test]
async fn test_concurrent_reads_and_writes() -> Result<()> {
let controller = std::sync::Arc::new(SimpleAccessController::new_simple());
let mut handles = vec![];
for i in 0..5 {
let controller_clone = controller.clone();
let handle =
tokio::spawn(
async move { controller_clone.grant("write", &format!("user{}", i)).await },
);
handles.push(handle);
}
for _ in 0..5 {
let controller_clone = controller.clone();
let handle = tokio::spawn(async move {
let _ = controller_clone.list_keys("write").await;
Ok(())
});
handles.push(handle);
}
for handle in handles {
handle.await.unwrap()?;
}
Ok(())
}
#[tokio::test]
async fn test_empty_permissions() {
let controller = SimpleAccessController::new(Some(HashMap::new()));
let capabilities = controller.list_capabilities().await;
assert!(capabilities.contains(&"read".to_string()));
assert!(capabilities.contains(&"write".to_string()));
assert!(capabilities.contains(&"admin".to_string()));
}
#[tokio::test]
async fn test_very_long_capability_name() -> Result<()> {
let controller = SimpleAccessController::new_simple();
let long_name = "a".repeat(1000);
controller.grant(&long_name, "user1").await?;
let keys = controller.list_keys(&long_name).await;
assert_eq!(keys.len(), 1);
Ok(())
}
#[tokio::test]
async fn test_very_long_key_id() -> Result<()> {
let controller = SimpleAccessController::new_simple();
let long_key = "k".repeat(1000);
controller.grant("write", &long_key).await?;
let keys = controller.list_keys("write").await;
assert!(keys.contains(&long_key));
Ok(())
}
#[tokio::test]
async fn test_special_characters_in_names() -> Result<()> {
let controller = SimpleAccessController::new_simple();
controller.grant("write", "user@domain.com").await?;
controller.grant("write", "user-with-dashes").await?;
controller.grant("write", "user_with_underscores").await?;
let keys = controller.list_keys("write").await;
assert_eq!(keys.len(), 3);
Ok(())
}
#[tokio::test]
async fn test_unicode_in_names() -> Result<()> {
let controller = SimpleAccessController::new_simple();
controller.grant("write", "usuário_português").await?;
controller.grant("write", "用户中文").await?;
controller.grant("write", "المستخدم_العربي").await?;
let keys = controller.list_keys("write").await;
assert_eq!(keys.len(), 3);
Ok(())
}
#[tokio::test]
async fn test_large_number_of_permissions() -> Result<()> {
let controller = SimpleAccessController::new_simple();
for i in 0..1000 {
controller.grant("write", &format!("user{}", i)).await?;
}
assert_eq!(controller.list_keys("write").await.len(), 1000);
assert_eq!(controller.total_permissions().await, 1000);
Ok(())
}
#[tokio::test]
async fn test_large_number_of_capabilities() -> Result<()> {
let controller = SimpleAccessController::new_simple();
for i in 0..100 {
controller.grant(&format!("cap{}", i), "user1").await?;
}
assert_eq!(controller.list_capabilities().await.len(), 103);
Ok(())
}
#[tokio::test]
async fn test_complex_permission_workflow() -> Result<()> {
let controller = SimpleAccessController::new_simple();
controller
.grant_multiple("read", vec!["user1", "user2", "user3"])
.await?;
controller
.grant_multiple("write", vec!["user1", "user2"])
.await?;
controller.grant("admin", "admin1").await?;
assert_eq!(controller.total_permissions().await, 6);
controller.clone_capability("read", "read_backup").await?;
controller.revoke("write", "user2").await?;
controller.grant("write", "user4").await?;
controller.clear_capability("admin").await?;
let stats = controller.get_stats().await;
assert_eq!(stats.get("read"), Some(&3));
assert_eq!(stats.get("write"), Some(&2));
assert_eq!(stats.get("read_backup"), Some(&3));
Ok(())
}
#[tokio::test]
async fn test_save_and_export_consistency() -> Result<()> {
let controller = SimpleAccessController::new_simple();
controller
.grant_multiple("read", vec!["user1", "user2"])
.await?;
controller.grant("write", "user3").await?;
let exported = controller.export_permissions().await;
let _manifest = controller.save().await?;
assert_eq!(exported.get("read").unwrap().len(), 2);
assert_eq!(exported.get("write").unwrap().len(), 1);
Ok(())
}