Skip to main content

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

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