Skip to main content

Mountain/IPC/Permission/Validate/ValidatePermission/
Validator.rs

1#![allow(non_snake_case)]
2
3//! `Validator::Struct` - role-based access control engine.
4//! Holds the role / permission tables and the operation →
5//! required-permission mapping; enforces the
6//! default-deny + RBAC policy through `ValidatePermission`.
7//! The struct + impl + tests stay in one file - tightly
8//! coupled cluster.
9
10use std::{
11	collections::HashMap,
12	sync::Arc,
13	time::{Duration, SystemTime},
14};
15
16use tokio::sync::RwLock;
17
18use crate::{
19	IPC::Permission::{
20		Role::ManageRole::{Permission::Struct as Permission, Role::Struct as Role},
21		Validate::ValidatePermission::SecurityContext::Struct as SecurityContext,
22	},
23	dev_log,
24};
25
26pub struct Struct {
27	pub(super) Roles:Arc<RwLock<HashMap<String, Role>>>,
28
29	pub(super) Permissions:Arc<RwLock<HashMap<String, Permission>>>,
30
31	pub(super) OperationPermissions:HashMap<String, Vec<String>>,
32
33	pub(super) ValidationTimeoutMillis:u64,
34}
35
36impl Struct {
37	pub fn New(ValidationTimeoutMillis:u64) -> Self {
38		Self {
39			Roles:Arc::new(RwLock::new(HashMap::new())),
40
41			Permissions:Arc::new(RwLock::new(HashMap::new())),
42
43			OperationPermissions:Self::BuildOperationMapping(),
44
45			ValidationTimeoutMillis,
46		}
47	}
48
49	fn BuildOperationMapping() -> HashMap<String, Vec<String>> {
50		let mut mapping = HashMap::new();
51
52		mapping.insert("file:write".to_string(), vec!["file.write".to_string()]);
53
54		mapping.insert("file:delete".to_string(), vec!["file.write".to_string()]);
55
56		mapping.insert("file:read".to_string(), vec!["file.read".to_string()]);
57
58		mapping.insert("configuration:update".to_string(), vec!["config.update".to_string()]);
59
60		mapping.insert("configuration:read".to_string(), vec!["config.read".to_string()]);
61
62		mapping.insert("storage:set".to_string(), vec!["storage.write".to_string()]);
63
64		mapping.insert("storage:get".to_string(), vec!["storage.read".to_string()]);
65
66		mapping.insert("native:openExternal".to_string(), vec!["system.external".to_string()]);
67
68		mapping.insert("system:execute".to_string(), vec!["system.execute".to_string()]);
69
70		mapping.insert("admin:manage".to_string(), vec!["admin.manage".to_string()]);
71
72		mapping
73	}
74
75	pub fn CreateSecurityContext(
76		UserId:String,
77
78		Roles:Vec<String>,
79
80		IpAddress:String,
81
82		DirectPermissions:Vec<String>,
83	) -> SecurityContext {
84		let ValidRoles = if Roles.is_empty() { vec!["user".to_string()] } else { Roles };
85
86		let ValidIpAddress = if IpAddress.is_empty() { "127.0.0.1".to_string() } else { IpAddress };
87
88		SecurityContext {
89			UserId,
90
91			Roles:ValidRoles,
92
93			Permissions:DirectPermissions,
94
95			IpAddress:ValidIpAddress,
96
97			Timestamp:SystemTime::now(),
98		}
99	}
100
101	pub async fn ValidatePermission(&self, Operation:&str, Context:&SecurityContext) -> Result<(), String> {
102		let timeout_duration = Duration::from_millis(self.ValidationTimeoutMillis);
103
104		let result = tokio::time::timeout(timeout_duration, async {
105			self.ValidatePermissionInternal(Operation, Context).await
106		})
107		.await;
108
109		match result {
110			Ok(validation_result) => validation_result,
111
112			Err(_) => {
113				dev_log!(
114					"ipc",
115					"error: [PermissionValidator] Permission validation timed out for operation: {}",
116					Operation
117				);
118
119				Err("Permission validation timeout".to_string())
120			},
121		}
122	}
123
124	async fn ValidatePermissionInternal(&self, Operation:&str, Context:&SecurityContext) -> Result<(), String> {
125		if Operation.is_empty() {
126			return Err("Operation name cannot be empty".to_string());
127		}
128
129		if Context.UserId.is_empty() {
130			return Err("User ID cannot be empty".to_string());
131		}
132
133		if Context.Roles.is_empty() && Context.Permissions.is_empty() {
134			return Err("User has no assigned roles or permissions".to_string());
135		}
136
137		let RequiredPermissions = match self.OperationPermissions.get(Operation) {
138			Some(perms) => perms.clone(),
139
140			None => return Ok(()),
141		};
142
143		if RequiredPermissions.is_empty() {
144			return Ok(());
145		}
146
147		let UserPermissions = self.AggregateUserPermissions(Context).await?;
148
149		for RequiredPermission in &RequiredPermissions {
150			if !UserPermissions.contains(RequiredPermission) {
151				return Err(format!("Missing required permission: {}", RequiredPermission));
152			}
153		}
154
155		Ok(())
156	}
157
158	async fn AggregateUserPermissions(&self, Context:&SecurityContext) -> Result<Vec<String>, String> {
159		let mut UserPermissions:Vec<String> = Context.Permissions.clone();
160
161		let roles_read = self.Roles.read().await;
162
163		for RoleName in &Context.Roles {
164			if let Some(role) = roles_read.get(RoleName) {
165				for Permission in &role.Permissions {
166					if !UserPermissions.contains(Permission) {
167						UserPermissions.push(Permission.clone());
168					}
169				}
170			} else {
171				dev_log!("ipc", "[PermissionValidator] Role not found: {}, skipping", RoleName);
172			}
173		}
174
175		Ok(UserPermissions)
176	}
177
178	pub async fn RegisterRole(&self, Role:Role) -> Result<(), String> {
179		if Role.Name.is_empty() {
180			return Err("Role name cannot be empty".to_string());
181		}
182
183		let mut roles = self.Roles.write().await;
184
185		let permissions_read = self.Permissions.read().await;
186
187		for PermissionName in &Role.Permissions {
188			if !permissions_read.contains_key(PermissionName) {
189				dev_log!(
190					"ipc",
191					"warn: [PermissionValidator] Permission '{}' referenced by role '{}' does not exist",
192					PermissionName,
193					Role.Name
194				);
195			}
196		}
197
198		drop(permissions_read);
199
200		let RoleName = Role.Name.clone();
201
202		roles.insert(RoleName.clone(), Role);
203
204		dev_log!("ipc", "[PermissionValidator] Role registered: {}", RoleName);
205
206		Ok(())
207	}
208
209	pub async fn RegisterPermission(&self, Permission:Permission) -> Result<(), String> {
210		if Permission.Name.is_empty() {
211			return Err("Permission name cannot be empty".to_string());
212		}
213
214		if Permission.Description.is_empty() {
215			return Err("Permission description cannot be empty".to_string());
216		}
217
218		let mut permissions = self.Permissions.write().await;
219
220		let PermissionName = Permission.Name.clone();
221
222		permissions.insert(PermissionName.clone(), Permission);
223
224		dev_log!("ipc", "[PermissionValidator] Permission registered: {}", PermissionName);
225
226		Ok(())
227	}
228
229	pub async fn GetRolePermissions(&self, RoleName:&str) -> Vec<String> {
230		let roles = self.Roles.read().await;
231
232		roles.get(RoleName).map(|role| role.Permissions.clone()).unwrap_or_default()
233	}
234
235	pub async fn HasPermission(&self, Context:&SecurityContext, PermissionName:&str) -> bool {
236		if Context.Permissions.contains(&PermissionName.to_string()) {
237			return true;
238		}
239
240		let roles = self.Roles.read().await;
241
242		for RoleName in &Context.Roles {
243			if let Some(role) = roles.get(RoleName) {
244				if role.Permissions.contains(&PermissionName.to_string()) {
245					return true;
246				}
247			}
248		}
249
250		false
251	}
252
253	pub async fn InitializeDefaults(&self) -> Result<(), String> {
254		dev_log!("ipc", "[PermissionValidator] Initializing default roles and permissions");
255
256		let DefaultPermissions = vec![
257			Permission {
258				Name:"file.read".to_string(),
259
260				Description:"Read file operations".to_string(),
261
262				Category:"file".to_string(),
263
264				IsSensitive:false,
265			},
266			Permission {
267				Name:"file.write".to_string(),
268
269				Description:"Write file operations".to_string(),
270
271				Category:"file".to_string(),
272
273				IsSensitive:false,
274			},
275			Permission {
276				Name:"config.read".to_string(),
277
278				Description:"Read configuration".to_string(),
279
280				Category:"config".to_string(),
281
282				IsSensitive:false,
283			},
284			Permission {
285				Name:"config.update".to_string(),
286
287				Description:"Update configuration".to_string(),
288
289				Category:"config".to_string(),
290
291				IsSensitive:false,
292			},
293			Permission {
294				Name:"storage.read".to_string(),
295
296				Description:"Read storage".to_string(),
297
298				Category:"storage".to_string(),
299
300				IsSensitive:false,
301			},
302			Permission {
303				Name:"storage.write".to_string(),
304
305				Description:"Write storage".to_string(),
306
307				Category:"storage".to_string(),
308
309				IsSensitive:false,
310			},
311			Permission {
312				Name:"system.external".to_string(),
313
314				Description:"Access external system resources".to_string(),
315
316				Category:"system".to_string(),
317
318				IsSensitive:true,
319			},
320			Permission {
321				Name:"system.execute".to_string(),
322
323				Description:"Execute system commands".to_string(),
324
325				Category:"system".to_string(),
326
327				IsSensitive:true,
328			},
329			Permission {
330				Name:"admin.manage".to_string(),
331
332				Description:"Administrative management operations".to_string(),
333
334				Category:"admin".to_string(),
335
336				IsSensitive:true,
337			},
338		];
339
340		for Permission in DefaultPermissions {
341			self.RegisterPermission(Permission).await?;
342		}
343
344		let DefaultRoles = vec![
345			Role {
346				Name:"user".to_string(),
347
348				Permissions:vec!["file.read".to_string(), "config.read".to_string(), "storage.read".to_string()],
349
350				Description:"Standard user with read access".to_string(),
351
352				ParentRole:None,
353
354				Priority:0,
355			},
356			Role {
357				Name:"developer".to_string(),
358
359				Permissions:vec![
360					"file.read".to_string(),
361					"file.write".to_string(),
362					"config.read".to_string(),
363					"storage.read".to_string(),
364					"storage.write".to_string(),
365				],
366
367				Description:"Developer with read/write access".to_string(),
368
369				ParentRole:None,
370
371				Priority:1,
372			},
373			Role {
374				Name:"admin".to_string(),
375
376				Permissions:vec![
377					"file.read".to_string(),
378					"file.write".to_string(),
379					"config.read".to_string(),
380					"config.update".to_string(),
381					"storage.read".to_string(),
382					"storage.write".to_string(),
383					"system.external".to_string(),
384					"system.execute".to_string(),
385					"admin.manage".to_string(),
386				],
387
388				Description:"Administrator with full access".to_string(),
389
390				ParentRole:None,
391
392				Priority:2,
393			},
394		];
395
396		for Role in DefaultRoles {
397			self.RegisterRole(Role).await?;
398		}
399
400		dev_log!(
401			"ipc",
402			"[PermissionValidator] Default roles and permissions initialized successfully"
403		);
404
405		Ok(())
406	}
407}