Mountain/IPC/Security/
PermissionManager.rs

1//! # Permission Manager (IPC Security)
2//!
3//! ## RESPONSIBILITIES
4//! This module provides role-based access control (RBAC) for IPC operations.
5//! It validates permissions for all incoming IPC messages and logs security
6//! events for comprehensive audit trails.
7//!
8//! ## ARCHITECTURAL ROLE
9//! This module is the security enforcement layer in the IPC architecture,
10//! ensuring that all operations are authorized based on user roles and
11//! permissions.
12//!
13//! ## KEY COMPONENTS
14//!
15//! - **PermissionManager**: Main permission validation and management structure
16//! - **SecurityContext**: Context information for permission validation
17//! - **SecurityEvent**: Audit log entry for security events
18//! - **SecurityEventType**: Types of security events
19//!
20//! ## ERROR HANDLING
21//! Permission validation returns Result types with descriptive error messages
22//! when access is denied.
23//!
24//! ## LOGGING
25//! All security events are logged to the audit log. Info-level logging for
26//! access grants, error-level for permission denials.
27//!
28//! ## PERFORMANCE CONSIDERATIONS
29//! - Permission definitions cached in RwLock for fast concurrent access
30//! - Role resolution optimized with HashMap lookups (O(1) complexity)
31//! - Audit log limited to last 1000 events to prevent memory bloat
32//!
33//! ## TODO
34//! - Add permission caching with TTL
35//! - Implement permission inheritance
36//! - Add permission alias support
37//! - Implement group-based permissions
38
39use std::{collections::HashMap, sync::Arc};
40
41use log::debug;
42use serde::{Deserialize, Serialize};
43use tokio::sync::RwLock;
44
45use super::{Permission::Permission, Role::Role};
46
47/// Security context for permission validation
48///
49/// This structure contains all information needed to validate whether an
50/// operation should be allowed based on the requester's identity and
51/// permissions.
52///
53/// ## Context Flow
54///
55/// ```text
56/// IPC Message
57///     |
58///     | Extract user info
59///     v
60/// SecurityContext (user_id, roles, permissions, ip_address)
61///     |
62///     | PermissionManager.validate_permission()
63///     v
64/// Access Decision (Allowed/Denied)
65/// ```
66#[derive(Debug, Clone, Serialize, Deserialize)]
67pub struct SecurityContext {
68	/// User identifier requesting the operation
69	pub user_id:String,
70
71	/// List of roles assigned to the user
72	pub roles:Vec<String>,
73
74	/// Direct permissions granted to the user
75	pub permissions:Vec<String>,
76
77	/// IP address of the requester (for location-based restrictions)
78	pub ip_address:String,
79
80	/// Timestamp of the request (for time-based restrictions)
81	pub timestamp:std::time::SystemTime,
82}
83
84impl SecurityContext {
85	/// Create a new security context
86	pub fn new(user_id:String, roles:Vec<String>, permissions:Vec<String>, ip_address:String) -> Self {
87		Self { user_id, roles, permissions, ip_address, timestamp:std::time::SystemTime::now() }
88	}
89
90	/// Check if user has a specific role
91	pub fn has_role(&self, role:&str) -> bool { self.roles.iter().any(|r| r == role) }
92
93	/// Check if user has a specific permission
94	pub fn has_permission(&self, permission:&str) -> bool { self.permissions.iter().any(|p| p == permission) }
95
96	/// Create a default IPC context (used for local IPC connections)
97	/// IPC connections use loopback address for security (localhost only)
98	pub fn ipc_default() -> Self {
99		Self {
100			user_id:"ipc-connection".to_string(),
101			roles:vec!["user".to_string()],
102			permissions:vec![],
103			ip_address:"127.0.0.1".to_string(),
104			timestamp:std::time::SystemTime::now(),
105		}
106	}
107}
108
109/// Security event for auditing
110///
111/// This structure records all security-related events for comprehensive
112/// audit trails and compliance monitoring.
113#[derive(Debug, Clone, Serialize, Deserialize)]
114pub struct SecurityEvent {
115	/// Type of security event
116	pub event_type:SecurityEventType,
117
118	/// User identifier who triggered the event
119	pub user_id:String,
120
121	/// Operation that was attempted
122	pub operation:String,
123
124	/// When the event occurred
125	pub timestamp:std::time::SystemTime,
126
127	/// Additional details about the event
128	pub details:Option<String>,
129}
130
131impl SecurityEvent {
132	/// Create a new security event
133	pub fn new(event_type:SecurityEventType, user_id:String, operation:String, details:Option<String>) -> Self {
134		Self { event_type, user_id, operation, timestamp:std::time::SystemTime::now(), details }
135	}
136}
137
138/// Types of security events
139#[derive(Debug, Clone, Serialize, Deserialize)]
140pub enum SecurityEventType {
141	/// Access was denied due to insufficient permissions
142	PermissionDenied,
143
144	/// Access was granted
145	AccessGranted,
146
147	/// Configuration was changed
148	ConfigurationChange,
149
150	/// A security violation was detected
151	SecurityViolation,
152
153	/// Performance anomaly detected (could indicate attack)
154	PerformanceAnomaly,
155}
156
157/// Permission manager for IPC operations
158///
159/// This is the main security enforcement structure for the IPC layer. It
160/// maintains role and permission definitions, validates access requests, and
161/// logs security events for auditing.
162///
163/// ## Permission Flow
164///
165/// ```text
166/// IPC Message arrives
167///     |
168///     | validate_permission(operation, context)
169///     v
170/// Check if operation requires permissions
171///     |
172///     | Yes -> Get required permissions
173///     v
174/// Check user permissions (direct + role-based)
175///     |
176///     | Has all required permissions?
177///     v
178/// Yes -> Log AccessGranted -> Allow operation
179/// No  -> Log PermissionDenied -> Deny operation
180/// ```
181///
182/// ## Default Roles
183///
184/// The PermissionManager initializes with three default roles:
185///
186/// - **user**: Read-only access to files, configuration, and storage
187/// - **developer**: Read/write access to files and storage, configuration read
188/// - **admin**: Full access including system operations and configuration
189///   updates
190///
191/// ## Default Permissions
192///
193/// Standard permissions include:
194/// - file.read, file.write
195/// - config.read, config.update
196/// - storage.read, storage.write
197/// - system.external
198pub struct PermissionManager {
199	/// Role definitions with associated permissions
200	roles:Arc<RwLock<HashMap<String, Role>>>,
201
202	/// Permission definitions with descriptions
203	permissions:Arc<RwLock<HashMap<String, Permission>>>,
204
205	/// Security audit log (limited to last 1000 events)
206	audit_log:Arc<RwLock<Vec<SecurityEvent>>>,
207}
208
209impl PermissionManager {
210	/// Create a new permission manager
211	pub fn new() -> Self {
212		debug!("[PermissionManager] Creating new PermissionManager instance");
213
214		Self {
215			roles:Arc::new(RwLock::new(HashMap::new())),
216			permissions:Arc::new(RwLock::new(HashMap::new())),
217			audit_log:Arc::new(RwLock::new(Vec::new())),
218		}
219	}
220
221	/// Validate permission for an operation
222	///
223	/// This method checks if the given security context has sufficient
224	/// permissions to perform the specified operation.
225	///
226	/// ## Parameters
227	/// - `operation`: The operation being attempted (e.g., "file:write",
228	///   "config:update")
229	/// - `context`: The security context containing user information
230	///
231	/// ## Returns
232	/// - `Ok(())` if the operation is allowed
233	/// - `Err(String)` with reason if denied
234	///
235	/// ## Example
236	///
237	/// ```rust,ignore
238	/// let context = SecurityContext::ipc_default();
239	/// permission_manager.validate_permission("file:read", &context).await?;
240	/// ```
241	pub async fn validate_permission(&self, operation:&str, context:&SecurityContext) -> Result<(), String> {
242		// Check if operation requires specific permissions
243		let required_permissions = self.get_required_permissions(operation).await;
244
245		if required_permissions.is_empty() {
246			debug!("[PermissionManager] Operation '{}' requires no special permissions", operation);
247			return Ok(()); // No specific permissions required
248		}
249
250		// Collect all user permissions (direct + role-based)
251		let mut user_permissions:Vec<String> = context.permissions.iter().cloned().collect();
252
253		for role in context.roles.iter() {
254			let role_perms = self.get_role_permissions(role).await;
255			user_permissions.extend(role_perms);
256		}
257
258		// Check if user has all required permissions
259		for required in &required_permissions {
260			if !user_permissions.contains(required) {
261				let error = format!("Missing permission: {}", required);
262				debug!(
263					"[PermissionManager] Permission denied for user '{}' on operation '{}': {}",
264					context.user_id, operation, error
265				);
266
267				// Log permission denial
268				self.log_security_event(SecurityEvent {
269					event_type:SecurityEventType::PermissionDenied,
270					user_id:context.user_id.clone(),
271					operation:operation.to_string(),
272					timestamp:std::time::SystemTime::now(),
273					details:Some(format!("Permission denied: {}", error)),
274				})
275				.await;
276
277				return Err(error);
278			}
279		}
280
281		// Log successful access
282		self.log_security_event(SecurityEvent {
283			event_type:SecurityEventType::AccessGranted,
284			user_id:context.user_id.clone(),
285			operation:operation.to_string(),
286			timestamp:std::time::SystemTime::now(),
287			details:Some(format!("Access granted for operation: {}", operation)),
288		})
289		.await;
290
291		debug!(
292			"[PermissionManager] Access granted for user '{}' on operation '{}'",
293			context.user_id, operation
294		);
295
296		Ok(())
297	}
298
299	/// Get required permissions for an operation
300	///
301	/// This method defines which permissions are required for which operations.
302	/// Operations not in the mapping require no special permissions by default.
303	///
304	/// ## Operation Permission Mapping
305	///
306	/// | Operation | Required Permissions |
307	/// |-----------|---------------------|
308	/// | file:write | file.write |
309	/// | file:delete | file.write |
310	/// | configuration:update | config.update |
311	/// | storage:set | storage.write |
312	/// | native:openExternal | system.external |
313	async fn get_required_permissions(&self, operation:&str) -> Vec<String> {
314		match operation {
315			"file:write" | "file:delete" => vec!["file.write".to_string()],
316			"configuration:update" => vec!["config.update".to_string()],
317			"storage:set" => vec!["storage.write".to_string()],
318			"native:openExternal" => vec!["system.external".to_string()],
319			// Operations not in the mapping require no special permissions by default
320			_ => Vec::new(),
321		}
322	}
323
324	/// Get permissions for a role
325	async fn get_role_permissions(&self, role_name:&str) -> Vec<String> {
326		let roles = self.roles.read().await;
327		roles.get(role_name).map(|role| role.permissions.clone()).unwrap_or_default()
328	}
329
330	/// Log security event
331	pub async fn log_security_event(&self, event:SecurityEvent) {
332		let mut audit_log = self.audit_log.write().await;
333		audit_log.push(event.clone());
334
335		// Keep only last 1000 events
336		if audit_log.len() > 1000 {
337			audit_log.remove(0);
338		}
339
340		match event.event_type {
341			SecurityEventType::PermissionDenied => {
342				log::warn!(
343					"[SecurityEvent] Permission denied - User: {}, Operation: {}, Details: {:?}",
344					event.user_id,
345					event.operation,
346					event.details
347				);
348			},
349			SecurityEventType::SecurityViolation => {
350				log::error!(
351					"[SecurityEvent] Security violation - User: {}, Operation: {}, Details: {:?}",
352					event.user_id,
353					event.operation,
354					event.details
355				);
356			},
357			SecurityEventType::AccessGranted => {
358				log::info!(
359					"[SecurityEvent] Access granted - User: {}, Operation: {}",
360					event.user_id,
361					event.operation
362				);
363			},
364			_ => {
365				log::debug!(
366					"[SecurityEvent] {:?} - User: {}, Operation: {}",
367					event.event_type,
368					event.user_id,
369					event.operation
370				);
371			},
372		}
373	}
374
375	/// Get security audit log
376	///
377	/// Returns the most recent security events up to the specified limit.
378	pub async fn get_audit_log(&self, limit:usize) -> Vec<SecurityEvent> {
379		let audit_log = self.audit_log.read().await;
380		audit_log.iter().rev().take(limit).cloned().collect()
381	}
382
383	/// Initialize default roles and permissions
384	///
385	/// This method sets up the standard RBAC structure with three default roles
386	/// and their associated permissions.
387	pub async fn initialize_defaults(&self) {
388		debug!("[PermissionManager] Initializing default roles and permissions");
389
390		let mut permissions = self.permissions.write().await;
391		let mut roles = self.roles.write().await;
392
393		// Define standard permissions
394		let standard_permissions = vec![
395			("file.read", "Read file operations"),
396			("file.write", "Write file operations"),
397			("config.read", "Read configuration"),
398			("config.update", "Update configuration"),
399			("storage.read", "Read storage"),
400			("storage.write", "Write storage"),
401			("system.external", "Access external system resources"),
402		];
403
404		for (name, description) in standard_permissions {
405			permissions.insert(
406				name.to_string(),
407				Permission {
408					name:name.to_string(),
409					description:description.to_string(),
410					category:"standard".to_string(),
411				},
412			);
413		}
414
415		// Define standard roles
416		let standard_roles = vec![
417			("user", vec!["file.read", "config.read", "storage.read"]),
418			(
419				"developer",
420				vec!["file.read", "file.write", "config.read", "storage.read", "storage.write"],
421			),
422			(
423				"admin",
424				vec![
425					"file.read",
426					"file.write",
427					"config.read",
428					"config.update",
429					"storage.read",
430					"storage.write",
431					"system.external",
432				],
433			),
434		];
435
436		for (name, role_permissions) in standard_roles {
437			roles.insert(
438				name.to_string(),
439				Role {
440					name:name.to_string(),
441					permissions:role_permissions.iter().map(|p| p.to_string()).collect(),
442					description:format!("{} role with standard permissions", name),
443				},
444			);
445		}
446
447		debug!(
448			"[PermissionManager] Initialized {} permissions and {} roles",
449			permissions.len(),
450			roles.len()
451		);
452	}
453
454	/// Add a custom role
455	pub async fn add_role(&self, role:Role) {
456		let role_name = role.name.clone();
457		let mut roles = self.roles.write().await;
458		roles.insert(role_name.clone(), role);
459		debug!("[PermissionManager] Added role: {}", role_name);
460	}
461
462	/// Add a custom permission
463	pub async fn add_permission(&self, permission:Permission) {
464		let permission_name = permission.name.clone();
465		let mut permissions = self.permissions.write().await;
466		permissions.insert(permission_name.clone(), permission);
467		debug!("[PermissionManager] Added permission: {}", permission_name);
468	}
469
470	/// Clear the audit log
471	pub async fn clear_audit_log(&self) {
472		let mut audit_log = self.audit_log.write().await;
473		audit_log.clear();
474		debug!("[PermissionManager] Audit log cleared");
475	}
476
477	/// Get audit log statistics
478	pub async fn get_audit_log_stats(&self) -> (usize, Vec<(&'static str, usize)>) {
479		let audit_log = self.audit_log.read().await;
480
481		let mut type_counts:Vec<(&'static str, usize)> = vec![
482			("PermissionDenied", 0),
483			("AccessGranted", 0),
484			("ConfigurationChange", 0),
485			("SecurityViolation", 0),
486			("PerformanceAnomaly", 0),
487		];
488
489		for event in audit_log.iter() {
490			let type_name = match event.event_type {
491				SecurityEventType::PermissionDenied => "PermissionDenied",
492				SecurityEventType::AccessGranted => "AccessGranted",
493				SecurityEventType::ConfigurationChange => "ConfigurationChange",
494				SecurityEventType::SecurityViolation => "SecurityViolation",
495				SecurityEventType::PerformanceAnomaly => "PerformanceAnomaly",
496			};
497			if let Some((_, count)) = type_counts.iter_mut().find(|(name, _)| *name == type_name) {
498				*count += 1;
499			}
500		}
501
502		(audit_log.len(), type_counts)
503	}
504}
505
506#[cfg(test)]
507mod tests {
508	use super::*;
509
510	#[tokio::test]
511	async fn test_permission_manager_creation() {
512		let manager = PermissionManager::new();
513		assert_eq!(manager.get_audit_log(10).await.len(), 0);
514	}
515
516	#[tokio::test]
517	async fn test_initialize_defaults() {
518		let manager = PermissionManager::new();
519		manager.initialize_defaults().await;
520
521		let log = manager.get_audit_log(10).await;
522		// Should have logged initialization events
523		assert!(!log.is_empty());
524	}
525
526	#[tokio::test]
527	async fn test_security_context_ipc_default() {
528		let context = SecurityContext::ipc_default();
529		assert_eq!(context.user_id, "ipc-connection");
530		assert!(context.has_role("user"));
531		assert_eq!(context.ip_address, "127.0.0.1");
532	}
533
534	#[tokio::test]
535	async fn test_permission_validation_access_granted() {
536		let manager = PermissionManager::new();
537		manager.initialize_defaults().await;
538
539		let context = SecurityContext::new(
540			"test-user".to_string(),
541			vec!["admin".to_string()],
542			vec![],
543			"127.0.0.1".to_string(),
544		);
545
546		// Admin should have file.write permission
547		let result = manager.validate_permission("file:write", &context).await;
548		assert!(result.is_ok());
549
550		// Check that access was logged
551		let log = manager.get_audit_log(10).await;
552		assert!(log.iter().any(|e| matches!(e.event_type, SecurityEventType::AccessGranted)));
553	}
554
555	#[tokio::test]
556	async fn test_permission_validation_access_denied() {
557		let manager = PermissionManager::new();
558		manager.initialize_defaults().await;
559
560		let context = SecurityContext::new(
561			"test-user".to_string(),
562			vec!["user".to_string()], // User role doesn't have file.write
563			vec![],
564			"127.0.0.1".to_string(),
565		);
566
567		// User role should NOT have file.write permission
568		let result = manager.validate_permission("file:write", &context).await;
569		assert!(result.is_err());
570
571		// Check that denial was logged
572		let log = manager.get_audit_log(10).await;
573		assert!(log.iter().any(|e| matches!(e.event_type, SecurityEventType::PermissionDenied)));
574	}
575
576	#[tokio::test]
577	async fn test_operations_without_permissions() {
578		let manager = PermissionManager::new();
579		manager.initialize_defaults().await;
580
581		let context = SecurityContext::ipc_default();
582
583		// Operations not in the mapping should require no permissions
584		let result = manager.validate_permission("custom_operation", &context).await;
585		assert!(result.is_ok());
586	}
587
588	#[tokio::test]
589	async fn test_audit_log_limit() {
590		let manager = PermissionManager::new();
591		manager.initialize_defaults().await;
592
593		// Add more than 1000 events
594		for i in 0..1100 {
595			manager
596				.log_security_event(SecurityEvent {
597					event_type:SecurityEventType::AccessGranted,
598					user_id:format!("user-{}", i),
599					operation:"test".to_string(),
600					timestamp:std::time::SystemTime::now(),
601					details:None,
602				})
603				.await;
604		}
605
606		// Should only have last 1000 events
607		let log = manager.get_audit_log(2000).await;
608		assert_eq!(log.len(), 1000);
609	}
610
611	#[tokio::test]
612	async fn test_custom_role() {
613		let manager = PermissionManager::new();
614		manager.initialize_defaults().await;
615
616		let custom_role = Role {
617			name:"custom".to_string(),
618			permissions:vec!["file.read".to_string()],
619			description:"Custom role".to_string(),
620		};
621
622		manager.add_role(custom_role).await;
623
624		let context = SecurityContext::new(
625			"test-user".to_string(),
626			vec!["custom".to_string()],
627			vec![],
628			"127.0.0.1".to_string(),
629		);
630
631		// Custom role should work
632		let result = manager.validate_permission("file:read", &context).await;
633		assert!(result.is_ok());
634	}
635}