use anyhow::{Result, anyhow};
use serde::{Deserialize, Serialize};
use std::collections::{BTreeMap, HashMap};
use std::sync::{Arc, Mutex, RwLock};
use std::time::SystemTime;
#[derive(Debug, Clone, Serialize, Deserialize)]
pub enum UserRole {
Admin,
Developer,
Operator,
Auditor,
Guest,
Custom(String),
}
#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct UserPermissions {
pub can_execute: bool,
pub can_read: bool,
pub can_write: bool,
pub can_delete: bool,
pub can_manage_users: bool,
pub can_access_sandbox: bool,
pub can_view_audit_logs: bool,
}
#[derive(Debug, Clone)]
pub struct User {
pub id: String,
pub username: String,
pub role: UserRole,
pub permissions: UserPermissions,
pub tenant_id: Option<String>,
}
#[derive(Debug, Clone, Serialize, Deserialize)]
pub enum SecurityPolicy {
Permissive,
Restrictive,
Custom(HashMap<String, SecurityRule>),
}
#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct SecurityRule {
pub name: String,
pub description: String,
pub allowed: bool,
pub conditions: Vec<String>,
pub resource_type: String,
pub action: String,
}
#[derive(Debug)]
pub struct SecurityManager {
policies: HashMap<String, SecurityPolicy>,
audit_log: Arc<RwLock<Vec<SecurityEvent>>>,
users: Arc<RwLock<HashMap<String, User>>>,
roles: Arc<RwLock<HashMap<String, UserPermissions>>>,
}
#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct SecurityEvent {
pub timestamp: std::time::SystemTime,
pub event_type: String,
pub source: String,
pub action: String,
pub result: SecurityResult,
pub details: HashMap<String, String>,
}
#[derive(Debug, Clone, Serialize, Deserialize)]
pub enum SecurityResult {
Allowed,
Denied(String),
}
impl SecurityManager {
pub fn new() -> Self {
let mut manager = Self {
policies: HashMap::new(),
audit_log: Arc::new(Mutex::new(Vec::new()))
users: Arc::new(Mutex::new(HashMap::new()))
roles: Arc::new(Mutex::new(HashMap::new()))
};
manager.initialize_default_roles();
manager.policies.insert(
"default".to_string(),
SecurityPolicy::Permissive,
);
manager
}
fn initialize_default_roles(&self) {
let mut roles = self.roles.blocking_write();
roles.insert("Admin".to_string(), UserPermissions {
can_execute: true,
can_read: true,
can_write: true,
can_delete: true,
can_manage_users: true,
can_access_sandbox: true,
can_view_audit_logs: true,
});
roles.insert("Developer".to_string(), UserPermissions {
can_execute: true,
can_read: true,
can_write: true,
can_delete: false,
can_manage_users: false,
can_access_sandbox: true,
can_view_audit_logs: false,
});
roles.insert("Operator".to_string(), UserPermissions {
can_execute: true,
can_read: true,
can_write: false,
can_delete: false,
can_manage_users: false,
can_access_sandbox: true,
can_view_audit_logs: true,
});
roles.insert("Auditor".to_string(), UserPermissions {
can_execute: false,
can_read: true,
can_write: false,
can_delete: false,
can_manage_users: false,
can_access_sandbox: false,
can_view_audit_logs: true,
});
roles.insert("Guest".to_string(), UserPermissions {
can_execute: false,
can_read: true,
can_write: false,
can_delete: false,
can_manage_users: false,
can_access_sandbox: false,
can_view_audit_logs: false,
});
}
pub fn add_policy(&mut self, name: String, policy: SecurityPolicy) {
self.policies.insert(name, policy);
}
pub async fn register_user(&self, user: User) -> Result<()> {
let mut users = self.users.write().await;
users.insert(user.id.clone(), user);
Ok(())
}
pub async fn authenticate_user(&self, username: &str) -> Option<User> {
let users: _ = self.users.read().await;
users.values().find(|u| u.username == username).cloned()
}
pub async fn check_user_permission(
&self,
user_id: &str,
operation: &str,
) -> Result<SecurityResult> {
let users: _ = self.users.read().await;
if let Some(user) = users.get(user_id) {
let allowed: _ = match operation {
"execute" => user.permissions.can_execute,
"read" => user.permissions.can_read,
"write" => user.permissions.can_write,
"delete" => user.permissions.can_delete,
"manage_users" => user.permissions.can_manage_users,
"access_sandbox" => user.permissions.can_access_sandbox,
"view_audit_logs" => user.permissions.can_view_audit_logs,
_ => false,
};
let result: _ = if allowed {
SecurityResult::Allowed
} else {
SecurityResult::Denied(format!("User '{}' not allowed to '{}'", user.username, operation))
};
self.log_event(
"user_permission_check".to_string(),
"rbac_system".to_string(),
format!("{}:{}", user.username, operation),
result.clone(),
HashMap::new(),
).await;
Ok(result)
} else {
Ok(SecurityResult::Denied("User not found".to_string())
}
}
pub fn check_permission(
&self,
policy_name: &str,
operation: &str,
context: &HashMap<String, String>,
) -> Result<SecurityResult> {
let policy: _ = self.policies.get(policy_name)
.ok_or_else(|| anyhow!("Policy not found: {}", policy_name))?;
let result: _ = match policy {
SecurityPolicy::Permissive => SecurityResult::Allowed,
SecurityPolicy::Restrictive => {
SecurityResult::Denied("Restrictive policy blocks operation".to_string())
}
SecurityPolicy::Custom(rules) => {
if let Some(rule) = rules.get(operation) {
if rule.allowed {
SecurityResult::Allowed
} else {
SecurityResult::Denied(format!("Operation '{}' denied by rule: {}", operation, rule.name))
}
} else {
SecurityResult::Denied(format!("No rule found for operation: {}", operation))
}
}
};
let details: _ = context.clone();
let event: _ = SecurityEvent {
timestamp: std::time::SystemTime::now(),
event_type: "permission_check".to_string(),
source: "security_manager".to_string(),
action: operation.to_string(),
result: result.clone(),
details,
};
println!("Security Event: {:?}", event);
Ok(result)
}
pub async fn log_event(
&self,
event_type: String,
source: String,
action: String,
result: SecurityResult,
mut details: HashMap<String, String>,
) {
let event: _ = SecurityEvent {
timestamp: std::time::SystemTime::now(),
event_type,
source,
action,
result,
details,
};
let mut log = self.audit_log.write().await;
log.push(event);
}
pub async fn get_audit_log(&self) -> Vec<SecurityEvent> {
let log: _ = self.audit_log.read().await;
log.clone()
}
pub async fn get_user_stats(&self) -> HashMap<String, serde_json::Value> {
let users: _ = self.users.read().await;
let mut stats = HashMap::new();
stats.insert("total_users".to_string(), serde_json::Value::from(users.len());
let mut role_counts = HashMap::new();
for user in users.values() {
let role_name: _ = match &user.role {
UserRole::Admin => "Admin",
UserRole::Developer => "Developer",
UserRole::Operator => "Operator",
UserRole::Auditor => "Auditor",
UserRole::Guest => "Guest",
UserRole::Custom(name) => name.as_str(),
};
*role_counts.entry(role_name.to_string()).or_insert(0) += 1;
}
stats.insert("role_distribution".to_string(), serde_json::to_value(role_counts).unwrap());
stats
}
}
impl Default for SecurityManager {
fn default() -> Self {
Self::new()
}
}
#[cfg(test)]
mod tests {
#[tokio::test]
async fn test_security_manager_creation() {
let manager: _ = SecurityManager::new();
assert!(!manager.policies.is_empty());
}
#[tokio::test]
async fn test_rbac_user_registration() {
let manager: _ = SecurityManager::new();
let user: _ = User {
id: "user1".to_string(),
username: "alice".to_string(),
role: UserRole::Developer,
permissions: UserPermissions {
can_execute: true,
can_read: true,
can_write: true,
can_delete: false,
can_manage_users: false,
can_access_sandbox: true,
can_view_audit_logs: false,
},
tenant_id: None,
};
let result: _ = manager.register_user(user).await;
assert!(result.is_ok());
}
#[tokio::test]
async fn test_user_permission_check() {
let manager: _ = SecurityManager::new();
let user: _ = User {
id: "user1".to_string(),
username: "alice".to_string(),
role: UserRole::Developer,
permissions: UserPermissions {
can_execute: true,
can_read: true,
can_write: true,
can_delete: false,
can_manage_users: false,
can_access_sandbox: true,
can_view_audit_logs: false,
},
tenant_id: None,
};
manager.register_user(user).await.unwrap();
let result: _ = manager.check_user_permission("user1", "execute").await;
assert!(matches!(result, Ok(SecurityResult::Allowed));
let result: _ = manager.check_user_permission("user1", "delete").await;
assert!(matches!(result, Ok(SecurityResult::Denied(_));
}
#[test]
fn test_permissive_policy() {
let manager: _ = SecurityManager::new();
let result: _ = manager.check_permission("default", "execute_script", &HashMap::new());
assert!(matches!(result, Ok(SecurityResult::Allowed));
}
#[tokio::test]
async fn test_audit_log() {
let manager: _ = SecurityManager::new();
manager.log_event(
"test_event".to_string(),
"test_source".to_string(),
"test_action".to_string(),
SecurityResult::Allowed,
HashMap::new(),
).await;
let log: _ = manager.get_audit_log().await;
assert_eq!(log.len(), 1);
assert_eq!(log[0].event_type, "test_event");
}
#[tokio::test]
async fn test_user_stats() {
let manager: _ = SecurityManager::new();
let admin_user: _ = User {
id: "admin1".to_string(),
username: "admin".to_string(),
role: UserRole::Admin,
permissions: UserPermissions {
can_execute: true,
can_read: true,
can_write: true,
can_delete: true,
can_manage_users: true,
can_access_sandbox: true,
can_view_audit_logs: true,
},
tenant_id: None,
};
manager.register_user(admin_user).await.unwrap();
let stats: _ = manager.get_user_stats().await;
assert_eq!(stats["total_users"], serde_json::Value::from(1));
}
}