Skip to main content

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 serde::{Deserialize, Serialize};
42use tokio::sync::RwLock;
43
44use super::{Permission::Permission, Role::Role};
45use crate::dev_log;
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		dev_log!("ipc", "[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			dev_log!(
247				"ipc",
248				"[PermissionManager] Operation '{}' requires no special permissions",
249				operation
250			);
251			return Ok(()); // No specific permissions required
252		}
253
254		// Collect all user permissions (direct + role-based)
255		let mut user_permissions:Vec<String> = context.permissions.iter().cloned().collect();
256
257		for role in context.roles.iter() {
258			let role_perms = self.get_role_permissions(role).await;
259			user_permissions.extend(role_perms);
260		}
261
262		// Check if user has all required permissions
263		for required in &required_permissions {
264			if !user_permissions.contains(required) {
265				let error = format!("Missing permission: {}", required);
266				dev_log!(
267					"ipc",
268					"[PermissionManager] Permission denied for user '{}' on operation '{}': {}",
269					context.user_id,
270					operation,
271					error
272				);
273
274				// Log permission denial
275				self.log_security_event(SecurityEvent {
276					event_type:SecurityEventType::PermissionDenied,
277					user_id:context.user_id.clone(),
278					operation:operation.to_string(),
279					timestamp:std::time::SystemTime::now(),
280					details:Some(format!("Permission denied: {}", error)),
281				})
282				.await;
283
284				return Err(error);
285			}
286		}
287
288		// Log successful access
289		self.log_security_event(SecurityEvent {
290			event_type:SecurityEventType::AccessGranted,
291			user_id:context.user_id.clone(),
292			operation:operation.to_string(),
293			timestamp:std::time::SystemTime::now(),
294			details:Some(format!("Access granted for operation: {}", operation)),
295		})
296		.await;
297
298		dev_log!(
299			"ipc",
300			"[PermissionManager] Access granted for user '{}' on operation '{}'",
301			context.user_id,
302			operation
303		);
304
305		Ok(())
306	}
307
308	/// Get required permissions for an operation
309	///
310	/// This method defines which permissions are required for which operations.
311	/// Operations not in the mapping require no special permissions by default.
312	///
313	/// ## Operation Permission Mapping
314	///
315	/// | Operation | Required Permissions |
316	/// |-----------|---------------------|
317	/// | file:write | file.write |
318	/// | file:delete | file.write |
319	/// | configuration:update | config.update |
320	/// | storage:set | storage.write |
321	/// | native:openExternal | system.external |
322	async fn get_required_permissions(&self, operation:&str) -> Vec<String> {
323		match operation {
324			"file:write" | "file:delete" => vec!["file.write".to_string()],
325			"configuration:update" => vec!["config.update".to_string()],
326			"storage:set" => vec!["storage.write".to_string()],
327			"native:openExternal" => vec!["system.external".to_string()],
328			// Operations not in the mapping require no special permissions by default
329			_ => Vec::new(),
330		}
331	}
332
333	/// Get permissions for a role
334	async fn get_role_permissions(&self, role_name:&str) -> Vec<String> {
335		let roles = self.roles.read().await;
336		roles.get(role_name).map(|role| role.permissions.clone()).unwrap_or_default()
337	}
338
339	/// Log security event
340	pub async fn log_security_event(&self, event:SecurityEvent) {
341		let mut audit_log = self.audit_log.write().await;
342		audit_log.push(event.clone());
343
344		// Keep only last 1000 events
345		if audit_log.len() > 1000 {
346			audit_log.remove(0);
347		}
348
349		match event.event_type {
350			SecurityEventType::PermissionDenied => {
351				dev_log!(
352					"ipc",
353					"warn: [SecurityEvent] Permission denied - User: {}, Operation: {}, Details: {:?}",
354					event.user_id,
355					event.operation,
356					event.details
357				);
358			},
359			SecurityEventType::SecurityViolation => {
360				dev_log!(
361					"ipc",
362					"error: [SecurityEvent] Security violation - User: {}, Operation: {}, Details: {:?}",
363					event.user_id,
364					event.operation,
365					event.details
366				);
367			},
368			SecurityEventType::AccessGranted => {
369				dev_log!(
370					"ipc",
371					"[SecurityEvent] Access granted - User: {}, Operation: {}",
372					event.user_id,
373					event.operation
374				);
375			},
376			_ => {
377				dev_log!(
378					"ipc",
379					"[SecurityEvent] {:?} - User: {}, Operation: {}",
380					event.event_type,
381					event.user_id,
382					event.operation
383				);
384			},
385		}
386	}
387
388	/// Get security audit log
389	///
390	/// Returns the most recent security events up to the specified limit.
391	pub async fn get_audit_log(&self, limit:usize) -> Vec<SecurityEvent> {
392		let audit_log = self.audit_log.read().await;
393		audit_log.iter().rev().take(limit).cloned().collect()
394	}
395
396	/// Initialize default roles and permissions
397	///
398	/// This method sets up the standard RBAC structure with three default roles
399	/// and their associated permissions.
400	pub async fn initialize_defaults(&self) {
401		dev_log!("ipc", "[PermissionManager] Initializing default roles and permissions");
402
403		let mut permissions = self.permissions.write().await;
404		let mut roles = self.roles.write().await;
405
406		// Define standard permissions
407		let standard_permissions = vec![
408			("file.read", "Read file operations"),
409			("file.write", "Write file operations"),
410			("config.read", "Read configuration"),
411			("config.update", "Update configuration"),
412			("storage.read", "Read storage"),
413			("storage.write", "Write storage"),
414			("system.external", "Access external system resources"),
415		];
416
417		for (name, description) in standard_permissions {
418			permissions.insert(
419				name.to_string(),
420				Permission {
421					name:name.to_string(),
422					description:description.to_string(),
423					category:"standard".to_string(),
424				},
425			);
426		}
427
428		// Define standard roles
429		let standard_roles = vec![
430			("user", vec!["file.read", "config.read", "storage.read"]),
431			(
432				"developer",
433				vec!["file.read", "file.write", "config.read", "storage.read", "storage.write"],
434			),
435			(
436				"admin",
437				vec![
438					"file.read",
439					"file.write",
440					"config.read",
441					"config.update",
442					"storage.read",
443					"storage.write",
444					"system.external",
445				],
446			),
447		];
448
449		for (name, role_permissions) in standard_roles {
450			roles.insert(
451				name.to_string(),
452				Role {
453					name:name.to_string(),
454					permissions:role_permissions.iter().map(|p| p.to_string()).collect(),
455					description:format!("{} role with standard permissions", name),
456				},
457			);
458		}
459
460		dev_log!(
461			"ipc",
462			"[PermissionManager] Initialized {} permissions and {} roles",
463			permissions.len(),
464			roles.len()
465		);
466	}
467
468	/// Add a custom role
469	pub async fn add_role(&self, role:Role) {
470		let role_name = role.name.clone();
471		let mut roles = self.roles.write().await;
472		roles.insert(role_name.clone(), role);
473		dev_log!("ipc", "[PermissionManager] Added role: {}", role_name);
474	}
475
476	/// Add a custom permission
477	pub async fn add_permission(&self, permission:Permission) {
478		let permission_name = permission.name.clone();
479		let mut permissions = self.permissions.write().await;
480		permissions.insert(permission_name.clone(), permission);
481		dev_log!("ipc", "[PermissionManager] Added permission: {}", permission_name);
482	}
483
484	/// Clear the audit log
485	pub async fn clear_audit_log(&self) {
486		let mut audit_log = self.audit_log.write().await;
487		audit_log.clear();
488		dev_log!("ipc", "[PermissionManager] Audit log cleared");
489	}
490
491	/// Get audit log statistics
492	pub async fn get_audit_log_stats(&self) -> (usize, Vec<(&'static str, usize)>) {
493		let audit_log = self.audit_log.read().await;
494
495		let mut type_counts:Vec<(&'static str, usize)> = vec![
496			("PermissionDenied", 0),
497			("AccessGranted", 0),
498			("ConfigurationChange", 0),
499			("SecurityViolation", 0),
500			("PerformanceAnomaly", 0),
501		];
502
503		for event in audit_log.iter() {
504			let type_name = match event.event_type {
505				SecurityEventType::PermissionDenied => "PermissionDenied",
506				SecurityEventType::AccessGranted => "AccessGranted",
507				SecurityEventType::ConfigurationChange => "ConfigurationChange",
508				SecurityEventType::SecurityViolation => "SecurityViolation",
509				SecurityEventType::PerformanceAnomaly => "PerformanceAnomaly",
510			};
511			if let Some((_, count)) = type_counts.iter_mut().find(|(name, _)| *name == type_name) {
512				*count += 1;
513			}
514		}
515
516		(audit_log.len(), type_counts)
517	}
518}
519
520#[cfg(test)]
521mod tests {
522	use super::*;
523
524	#[tokio::test]
525	async fn test_permission_manager_creation() {
526		let manager = PermissionManager::new();
527		assert_eq!(manager.get_audit_log(10).await.len(), 0);
528	}
529
530	#[tokio::test]
531	async fn test_initialize_defaults() {
532		let manager = PermissionManager::new();
533		manager.initialize_defaults().await;
534
535		let log = manager.get_audit_log(10).await;
536		// Should have logged initialization events
537		assert!(!log.is_empty());
538	}
539
540	#[tokio::test]
541	async fn test_security_context_ipc_default() {
542		let context = SecurityContext::ipc_default();
543		assert_eq!(context.user_id, "ipc-connection");
544		assert!(context.has_role("user"));
545		assert_eq!(context.ip_address, "127.0.0.1");
546	}
547
548	#[tokio::test]
549	async fn test_permission_validation_access_granted() {
550		let manager = PermissionManager::new();
551		manager.initialize_defaults().await;
552
553		let context = SecurityContext::new(
554			"test-user".to_string(),
555			vec!["admin".to_string()],
556			vec![],
557			"127.0.0.1".to_string(),
558		);
559
560		// Admin should have file.write permission
561		let result = manager.validate_permission("file:write", &context).await;
562		assert!(result.is_ok());
563
564		// Check that access was logged
565		let log = manager.get_audit_log(10).await;
566		assert!(log.iter().any(|e| matches!(e.event_type, SecurityEventType::AccessGranted)));
567	}
568
569	#[tokio::test]
570	async fn test_permission_validation_access_denied() {
571		let manager = PermissionManager::new();
572		manager.initialize_defaults().await;
573
574		let context = SecurityContext::new(
575			"test-user".to_string(),
576			vec!["user".to_string()], // User role doesn't have file.write
577			vec![],
578			"127.0.0.1".to_string(),
579		);
580
581		// User role should NOT have file.write permission
582		let result = manager.validate_permission("file:write", &context).await;
583		assert!(result.is_err());
584
585		// Check that denial was logged
586		let log = manager.get_audit_log(10).await;
587		assert!(log.iter().any(|e| matches!(e.event_type, SecurityEventType::PermissionDenied)));
588	}
589
590	#[tokio::test]
591	async fn test_operations_without_permissions() {
592		let manager = PermissionManager::new();
593		manager.initialize_defaults().await;
594
595		let context = SecurityContext::ipc_default();
596
597		// Operations not in the mapping should require no permissions
598		let result = manager.validate_permission("custom_operation", &context).await;
599		assert!(result.is_ok());
600	}
601
602	#[tokio::test]
603	async fn test_audit_log_limit() {
604		let manager = PermissionManager::new();
605		manager.initialize_defaults().await;
606
607		// Add more than 1000 events
608		for i in 0..1100 {
609			manager
610				.log_security_event(SecurityEvent {
611					event_type:SecurityEventType::AccessGranted,
612					user_id:format!("user-{}", i),
613					operation:"test".to_string(),
614					timestamp:std::time::SystemTime::now(),
615					details:None,
616				})
617				.await;
618		}
619
620		// Should only have last 1000 events
621		let log = manager.get_audit_log(2000).await;
622		assert_eq!(log.len(), 1000);
623	}
624
625	#[tokio::test]
626	async fn test_custom_role() {
627		let manager = PermissionManager::new();
628		manager.initialize_defaults().await;
629
630		let custom_role = Role {
631			name:"custom".to_string(),
632			permissions:vec!["file.read".to_string()],
633			description:"Custom role".to_string(),
634		};
635
636		manager.add_role(custom_role).await;
637
638		let context = SecurityContext::new(
639			"test-user".to_string(),
640			vec!["custom".to_string()],
641			vec![],
642			"127.0.0.1".to_string(),
643		);
644
645		// Custom role should work
646		let result = manager.validate_permission("file:read", &context).await;
647		assert!(result.is_ok());
648	}
649}