use crate::eval::Value;
use crate::diagnostics::{Error, Result};
use std::collections::{HashMap, HashSet};
use std::sync::{Arc, RwLock};
use std::time::{Duration, Instant};
#[derive(Debug, Clone, PartialEq, Eq, Hash)]
pub enum Permission {
Eval,
Compile,
FileSystem {
path: String,
read: bool,
write: bool
},
Network {
host: String,
port: Option<u16>
},
Environment {
read: bool,
write: bool
},
Reflection,
Ffi,
Module {
load: bool,
unload: bool
},
Memory {
allocate: bool,
gc: bool
},
System,
Custom(String),
}
#[derive(Debug, Clone)]
pub struct SecurityPolicy {
pub name: String,
pub allowed_permissions: HashSet<Permission>,
pub resource_limits: ResourceLimits,
pub time_limit: Option<Duration>,
pub memory_limit: Option<usize>,
pub stack_depth_limit: Option<usize>,
pub custom_restrictions: HashMap<String, Value>,
}
#[derive(Debug, Clone)]
#[derive(Default)]
pub struct ResourceLimits {
pub max_allocations: Option<usize>,
pub max_memory: Option<usize>,
pub max_execution_time: Option<Duration>,
pub max_stack_depth: Option<usize>,
pub max_file_operations: Option<usize>,
pub max_network_operations: Option<usize>,
}
#[derive(Debug, Clone)]
pub struct AccessControlEntry {
pub principal: String,
pub resource: String,
pub operation: String,
pub allowed: bool,
pub conditions: Vec<AccessCondition>,
}
#[derive(Debug, Clone)]
pub enum AccessCondition {
TimeRange {
start: Instant,
end: Instant
},
ResourceLimit {
resource: String,
limit: usize
},
Context {
key: String,
value: String
},
Custom(String),
}
#[derive(Debug, Clone)]
pub struct SecurityContext {
pub principal: String,
pub policy: SecurityPolicy,
pub permissions: HashSet<Permission>,
pub resource_usage: ResourceUsage,
pub start_time: Instant,
}
#[derive(Debug, Clone)]
pub struct ResourceUsage {
pub allocations: usize,
pub memory_used: usize,
pub stack_depth: usize,
pub file_operations: usize,
pub network_operations: usize,
pub execution_time: Duration,
}
#[derive(Debug, Clone)]
pub struct SecurityManager {
policies: HashMap<String, SecurityPolicy>,
acl: Vec<AccessControlEntry>,
contexts: Arc<RwLock<HashMap<String, SecurityContext>>>,
default_policy: SecurityPolicy,
}
impl SecurityPolicy {
pub fn restrictive() -> Self {
Self {
name: "restrictive".to_string(),
allowed_permissions: HashSet::new(),
resource_limits: ResourceLimits::default(),
time_limit: Some(Duration::from_secs(30)),
memory_limit: Some(1024 * 1024), stack_depth_limit: Some(100),
custom_restrictions: HashMap::new(),
}
}
pub fn permissive() -> Self {
let mut permissions = HashSet::new();
permissions.insert(Permission::Eval);
permissions.insert(Permission::Compile);
permissions.insert(Permission::Reflection);
permissions.insert(Permission::Environment { read: true, write: true });
Self {
name: "permissive".to_string(),
allowed_permissions: permissions,
resource_limits: ResourceLimits::default(),
time_limit: None,
memory_limit: None,
stack_depth_limit: None,
custom_restrictions: HashMap::new(),
}
}
}
impl SecurityManager {
pub fn new() -> Self {
let default_policy = SecurityPolicy {
name: "default".to_string(),
allowed_permissions: HashSet::new(),
resource_limits: ResourceLimits::default(),
time_limit: Some(Duration::from_secs(10)),
memory_limit: Some(1024 * 1024), stack_depth_limit: Some(100),
custom_restrictions: HashMap::new(),
};
Self {
policies: HashMap::new(),
acl: Vec::new(),
contexts: Arc::new(RwLock::new(HashMap::new())),
default_policy,
}
}
pub fn install_default_policies(&mut self) {
let mut sandbox_policy = SecurityPolicy {
name: "sandbox".to_string(),
allowed_permissions: HashSet::new(),
resource_limits: ResourceLimits {
max_allocations: Some(1000),
max_memory: Some(512 * 1024), max_execution_time: Some(Duration::from_secs(5)),
max_stack_depth: Some(50),
max_file_operations: Some(0), max_network_operations: Some(0), },
time_limit: Some(Duration::from_secs(5)),
memory_limit: Some(512 * 1024),
stack_depth_limit: Some(50),
custom_restrictions: HashMap::new(),
};
sandbox_policy.allowed_permissions.insert(Permission::Eval);
sandbox_policy.allowed_permissions.insert(Permission::Reflection);
let mut trusted_policy = SecurityPolicy {
name: "trusted".to_string(),
allowed_permissions: HashSet::new(),
resource_limits: ResourceLimits::default(),
time_limit: None,
memory_limit: None,
stack_depth_limit: None,
custom_restrictions: HashMap::new(),
};
trusted_policy.allowed_permissions.insert(Permission::Eval);
trusted_policy.allowed_permissions.insert(Permission::Compile);
trusted_policy.allowed_permissions.insert(Permission::Reflection);
trusted_policy.allowed_permissions.insert(Permission::Environment { read: true, write: true });
trusted_policy.allowed_permissions.insert(Permission::Module { load: true, unload: true });
self.policies.insert("sandbox".to_string(), sandbox_policy);
self.policies.insert("trusted".to_string(), trusted_policy);
}
pub fn create_context(&self, principal: String, policy_name: &str) -> Result<SecurityContext> {
let policy = self.policies.get(policy_name)
.unwrap_or(&self.default_policy)
.clone();
let context = SecurityContext {
principal: principal.clone(),
permissions: policy.allowed_permissions.clone(),
policy,
resource_usage: ResourceUsage::default(),
start_time: Instant::now(),
};
let mut contexts = self.contexts.write().unwrap();
contexts.insert(principal.clone(), context.clone());
Ok(context)
}
pub fn check_permission(&self, principal: &str, permission: &Permission) -> Result<bool> {
let contexts = self.contexts.read().unwrap();
if let Some(context) = contexts.get(principal) {
Ok(context.permissions.contains(permission))
} else {
Ok(false)
}
}
pub fn check_access(&self, principal: &str, resource: &str, operation: &str) -> Result<bool> {
for entry in &self.acl {
if entry.principal == principal && entry.resource == resource && entry.operation == operation
&& self.evaluate_conditions(&entry.conditions)? {
return Ok(entry.allowed);
}
}
Ok(false) }
pub fn update_resource_usage<F>(&self, principal: &str, updater: F) -> Result<()>
where
F: FnOnce(&mut ResourceUsage),
{
let mut contexts = self.contexts.write().unwrap();
if let Some(context) = contexts.get_mut(principal) {
updater(&mut context.resource_usage);
self.check_resource_limits(context)?;
}
Ok(())
}
fn check_resource_limits(&self, context: &SecurityContext) -> Result<()> {
let limits = &context.policy.resource_limits;
let usage = &context.resource_usage;
if let Some(max_allocations) = limits.max_allocations {
if usage.allocations > max_allocations {
return Err(Box::new(Error::runtime_error(
format!("Allocation limit exceeded: {} > {}", usage.allocations, max_allocations),
None,
)));
}
}
if let Some(max_memory) = limits.max_memory {
if usage.memory_used > max_memory {
return Err(Box::new(Error::runtime_error(
format!("Memory limit exceeded: {} > {}", usage.memory_used, max_memory),
None,
)));
}
}
if let Some(max_time) = limits.max_execution_time {
if usage.execution_time > max_time {
return Err(Box::new(Error::runtime_error(
format!("Execution time limit exceeded: {:?} > {:?}", usage.execution_time, max_time),
None,
)));
}
}
if let Some(max_stack) = limits.max_stack_depth {
if usage.stack_depth > max_stack {
return Err(Box::new(Error::runtime_error(
format!("Stack depth limit exceeded: {} > {}", usage.stack_depth, max_stack),
None,
)));
}
}
Ok(())
}
fn evaluate_conditions(&self, conditions: &[AccessCondition]) -> Result<bool> {
for condition in conditions {
match condition {
AccessCondition::TimeRange { start, end } => {
let now = Instant::now();
if now < *start || now > *end {
return Ok(false);
}
}
AccessCondition::ResourceLimit { limit, .. } => {
if *limit == 0 {
return Ok(false);
}
}
_ => {
}
}
}
Ok(true)
}
pub fn add_access_control_entry(&mut self, entry: AccessControlEntry) {
self.acl.push(entry);
}
pub fn add_policy(&mut self, policy: SecurityPolicy) {
self.policies.insert(policy.name.clone(), policy);
}
pub fn get_context(&self, principal: &str) -> Option<SecurityContext> {
let contexts = self.contexts.read().unwrap();
contexts.get(principal).cloned()
}
pub fn remove_context(&self, principal: &str) {
let mut contexts = self.contexts.write().unwrap();
contexts.remove(principal);
}
}
impl Default for SecurityManager {
fn default() -> Self {
let mut manager = Self::new();
manager.install_default_policies();
manager
}
}
impl Default for ResourceUsage {
fn default() -> Self {
Self {
allocations: 0,
memory_used: 0,
stack_depth: 0,
file_operations: 0,
network_operations: 0,
execution_time: Duration::from_secs(0),
}
}
}
#[derive(Debug)]
pub struct PermissionSystem {
granted_permissions: HashMap<String, HashSet<Permission>>,
permission_hierarchy: HashMap<Permission, Vec<Permission>>,
}
impl PermissionSystem {
pub fn new() -> Self {
Self {
granted_permissions: HashMap::new(),
permission_hierarchy: HashMap::new(),
}
}
pub fn grant_permission(&mut self, principal: String, permission: Permission) {
self.granted_permissions
.entry(principal)
.or_default()
.insert(permission);
}
pub fn revoke_permission(&mut self, principal: &str, permission: &Permission) {
if let Some(permissions) = self.granted_permissions.get_mut(principal) {
permissions.remove(permission);
}
}
pub fn has_permission(&self, principal: &str, permission: &Permission) -> bool {
if let Some(permissions) = self.granted_permissions.get(principal) {
if permissions.contains(permission) {
return true;
}
for granted in permissions {
if self.implies_permission(granted, permission) {
return true;
}
}
}
false
}
fn implies_permission(&self, granted: &Permission, required: &Permission) -> bool {
if let Some(implied) = self.permission_hierarchy.get(granted) {
implied.contains(required)
} else {
false
}
}
pub fn add_permission_implication(&mut self, parent: Permission, child: Permission) {
self.permission_hierarchy
.entry(parent)
.or_default()
.push(child);
}
}
#[derive(Debug)]
pub struct AccessControl {
security_manager: SecurityManager,
permission_system: PermissionSystem,
}
impl AccessControl {
pub fn new() -> Self {
Self {
security_manager: SecurityManager::default(),
permission_system: PermissionSystem::new(),
}
}
pub fn check_operation(
&self,
principal: &str,
resource: &str,
operation: &str,
permission: &Permission,
) -> Result<bool> {
if !self.permission_system.has_permission(principal, permission) {
return Ok(false);
}
self.security_manager.check_access(principal, resource, operation)
}
pub fn security_manager(&self) -> &SecurityManager {
&self.security_manager
}
pub fn permission_system(&self) -> &PermissionSystem {
&self.permission_system
}
pub fn security_manager_mut(&mut self) -> &mut SecurityManager {
&mut self.security_manager
}
pub fn permission_system_mut(&mut self) -> &mut PermissionSystem {
&mut self.permission_system
}
}
impl Default for AccessControl {
fn default() -> Self {
Self::new()
}
}
impl Default for PermissionSystem {
fn default() -> Self {
Self::new()
}
}