1use std::{
87 collections::HashMap,
88 sync::Arc,
89 time::{Duration, SystemTime},
90};
91
92use tokio::sync::RwLock;
93use serde::{Deserialize, Serialize};
94
95use super::super::Role::ManageRole::{Permission, Role};
96use crate::dev_log;
97
98#[derive(Debug, Clone, Serialize, Deserialize)]
100pub struct SecurityContext {
101 pub UserId:String,
103
104 pub Roles:Vec<String>,
106
107 pub Permissions:Vec<String>,
109
110 pub IpAddress:String,
112
113 pub Timestamp:SystemTime,
115}
116
117pub struct PermissionValidator {
119 Roles:Arc<RwLock<HashMap<String, Role>>>,
121
122 Permissions:Arc<RwLock<HashMap<String, Permission>>>,
124
125 OperationPermissions:HashMap<String, Vec<String>>,
127
128 ValidationTimeoutMillis:u64,
130}
131
132impl PermissionValidator {
133 pub fn New(ValidationTimeoutMillis:u64) -> Self {
142 let OperationPermissions = Self::BuildOperationMapping();
143
144 Self {
145 Roles:Arc::new(RwLock::new(HashMap::new())),
146 Permissions:Arc::new(RwLock::new(HashMap::new())),
147 OperationPermissions,
148 ValidationTimeoutMillis,
149 }
150 }
151
152 fn BuildOperationMapping() -> HashMap<String, Vec<String>> {
157 let mut mapping = HashMap::new();
158
159 mapping.insert("file:write".to_string(), vec!["file.write".to_string()]);
160 mapping.insert("file:delete".to_string(), vec!["file.write".to_string()]);
161 mapping.insert("file:read".to_string(), vec!["file.read".to_string()]);
162 mapping.insert("configuration:update".to_string(), vec!["config.update".to_string()]);
163 mapping.insert("configuration:read".to_string(), vec!["config.read".to_string()]);
164 mapping.insert("storage:set".to_string(), vec!["storage.write".to_string()]);
165 mapping.insert("storage:get".to_string(), vec!["storage.read".to_string()]);
166 mapping.insert("native:openExternal".to_string(), vec!["system.external".to_string()]);
167 mapping.insert("system:execute".to_string(), vec!["system.execute".to_string()]);
168 mapping.insert("admin:manage".to_string(), vec!["admin.manage".to_string()]);
169
170 mapping
171 }
172
173 pub fn CreateSecurityContext(
184 UserId:String,
185 Roles:Vec<String>,
186 IpAddress:String,
187 DirectPermissions:Vec<String>,
188 ) -> SecurityContext {
189 let ValidRoles = if Roles.is_empty() { vec!["user".to_string()] } else { Roles };
190
191 let ValidIpAddress = if IpAddress.is_empty() { "127.0.0.1".to_string() } else { IpAddress };
192
193 SecurityContext {
194 UserId,
195 Roles:ValidRoles,
196 Permissions:DirectPermissions,
197 IpAddress:ValidIpAddress,
198 Timestamp:SystemTime::now(),
199 }
200 }
201
202 pub async fn ValidatePermission(&self, Operation:&str, Context:&SecurityContext) -> Result<(), String> {
217 let timeout_duration = Duration::from_millis(self.ValidationTimeoutMillis);
219
220 let result = tokio::time::timeout(timeout_duration, async {
222 self.ValidatePermissionInternal(Operation, Context).await
223 })
224 .await;
225
226 match result {
227 Ok(validation_result) => validation_result,
228 Err(_) => {
229 dev_log!(
230 "ipc",
231 "error: [PermissionValidator] Permission validation timed out for operation: {}",
232 Operation
233 );
234 Err("Permission validation timeout".to_string())
235 },
236 }
237 }
238
239 async fn ValidatePermissionInternal(&self, Operation:&str, Context:&SecurityContext) -> Result<(), String> {
248 if Operation.is_empty() {
250 dev_log!("ipc", "warn: [PermissionValidator] Empty operation name provided");
251 return Err("Operation name cannot be empty".to_string());
252 }
253
254 if Context.UserId.is_empty() {
255 dev_log!("ipc", "warn: [PermissionValidator] Empty user ID in security context");
256 return Err("User ID cannot be empty".to_string());
257 }
258
259 if Context.Roles.is_empty() && Context.Permissions.is_empty() {
260 dev_log!(
261 "ipc",
262 "warn: [PermissionValidator] User has no roles or permissions: {}",
263 Context.UserId
264 );
265 return Err("User has no assigned roles or permissions".to_string());
266 }
267
268 let RequiredPermissions = match self.OperationPermissions.get(Operation) {
270 Some(perms) => perms.clone(),
271 None => {
272 dev_log!(
274 "ipc",
275 "[PermissionValidator] No specific permissions required for operation: {}",
276 Operation
277 );
278 return Ok(());
279 },
280 };
281
282 if RequiredPermissions.is_empty() {
283 dev_log!(
285 "ipc",
286 "[PermissionValidator] Access granted (no permissions required): {} by {}",
287 Operation,
288 Context.UserId
289 );
290 Ok(())
291 } else {
292 let UserPermissions = self.AggregateUserPermissions(Context).await?;
294
295 for RequiredPermission in &RequiredPermissions {
297 if !UserPermissions.contains(RequiredPermission) {
298 dev_log!(
299 "ipc",
300 "warn: [PermissionValidator] Permission denied: {} required, user {} has {:?}",
301 RequiredPermission,
302 Context.UserId,
303 UserPermissions
304 );
305 return Err(format!("Missing required permission: {}", RequiredPermission));
306 }
307 }
308
309 dev_log!(
311 "ipc",
312 "[PermissionValidator] Access granted: {} by {}",
313 Operation,
314 Context.UserId
315 );
316 Ok(())
317 }
318 }
319
320 async fn AggregateUserPermissions(&self, Context:&SecurityContext) -> Result<Vec<String>, String> {
328 let mut UserPermissions:Vec<String> = Context.Permissions.clone();
329
330 let roles_read = self.Roles.read().await;
332 for RoleName in &Context.Roles {
333 if let Some(role) = roles_read.get(RoleName) {
334 for Permission in &role.Permissions {
335 if !UserPermissions.contains(Permission) {
336 UserPermissions.push(Permission.clone());
337 }
338 }
339 } else {
340 dev_log!("ipc", "[PermissionValidator] Role not found: {}, skipping", RoleName);
341 }
342 }
343
344 Ok(UserPermissions)
345 }
346
347 pub async fn RegisterRole(&self, Role:Role) -> Result<(), String> {
355 if Role.Name.is_empty() {
357 return Err("Role name cannot be empty".to_string());
358 }
359
360 if Role.Permissions.is_empty() {
361 dev_log!("ipc", "warn: [PermissionValidator] Role '{}' has no permissions", Role.Name);
362 }
363
364 let mut roles = self.Roles.write().await;
365
366 let permissions_read = self.Permissions.read().await;
368 for PermissionName in &Role.Permissions {
369 if !permissions_read.contains_key(PermissionName) {
370 dev_log!(
371 "ipc",
372 "warn: [PermissionValidator] Permission '{}' referenced by role '{}' does not exist",
373 PermissionName,
374 Role.Name
375 );
376 }
377 }
378 drop(permissions_read);
379
380 let RoleName = Role.Name.clone();
381 roles.insert(RoleName.clone(), Role);
382 dev_log!("ipc", "[PermissionValidator] Role registered: {}", RoleName);
383 Ok(())
384 }
385
386 pub async fn RegisterPermission(&self, Permission:Permission) -> Result<(), String> {
394 if Permission.Name.is_empty() {
396 return Err("Permission name cannot be empty".to_string());
397 }
398
399 if Permission.Description.is_empty() {
400 return Err("Permission description cannot be empty".to_string());
401 }
402
403 let mut permissions = self.Permissions.write().await;
404 let PermissionName = Permission.Name.clone();
405 permissions.insert(PermissionName.clone(), Permission);
406 dev_log!("ipc", "[PermissionValidator] Permission registered: {}", PermissionName);
407 Ok(())
408 }
409
410 pub async fn GetRolePermissions(&self, RoleName:&str) -> Vec<String> {
418 let roles = self.Roles.read().await;
419 roles.get(RoleName).map(|role| role.Permissions.clone()).unwrap_or_default()
420 }
421
422 pub async fn HasPermission(&self, Context:&SecurityContext, PermissionName:&str) -> bool {
431 if Context.Permissions.contains(&PermissionName.to_string()) {
433 return true;
434 }
435
436 let roles = self.Roles.read().await;
438 for RoleName in &Context.Roles {
439 if let Some(role) = roles.get(RoleName) {
440 if role.Permissions.contains(&PermissionName.to_string()) {
441 return true;
442 }
443 }
444 }
445
446 false
447 }
448
449 pub async fn InitializeDefaults(&self) -> Result<(), String> {
459 dev_log!("ipc", "[PermissionValidator] Initializing default roles and permissions");
460
461 let DefaultPermissions = vec![
463 Permission {
464 Name:"file.read".to_string(),
465 Description:"Read file operations".to_string(),
466 Category:"file".to_string(),
467 IsSensitive:false,
468 },
469 Permission {
470 Name:"file.write".to_string(),
471 Description:"Write file operations".to_string(),
472 Category:"file".to_string(),
473 IsSensitive:false,
474 },
475 Permission {
476 Name:"config.read".to_string(),
477 Description:"Read configuration".to_string(),
478 Category:"config".to_string(),
479 IsSensitive:false,
480 },
481 Permission {
482 Name:"config.update".to_string(),
483 Description:"Update configuration".to_string(),
484 Category:"config".to_string(),
485 IsSensitive:false,
486 },
487 Permission {
488 Name:"storage.read".to_string(),
489 Description:"Read storage".to_string(),
490 Category:"storage".to_string(),
491 IsSensitive:false,
492 },
493 Permission {
494 Name:"storage.write".to_string(),
495 Description:"Write storage".to_string(),
496 Category:"storage".to_string(),
497 IsSensitive:false,
498 },
499 Permission {
500 Name:"system.external".to_string(),
501 Description:"Access external system resources".to_string(),
502 Category:"system".to_string(),
503 IsSensitive:true,
504 },
505 Permission {
506 Name:"system.execute".to_string(),
507 Description:"Execute system commands".to_string(),
508 Category:"system".to_string(),
509 IsSensitive:true,
510 },
511 Permission {
512 Name:"admin.manage".to_string(),
513 Description:"Administrative management operations".to_string(),
514 Category:"admin".to_string(),
515 IsSensitive:true,
516 },
517 ];
518
519 for Permission in DefaultPermissions {
521 self.RegisterPermission(Permission).await?;
522 }
523
524 let DefaultRoles = vec![
526 Role {
527 Name:"user".to_string(),
528 Permissions:vec!["file.read".to_string(), "config.read".to_string(), "storage.read".to_string()],
529 Description:"Standard user with read access".to_string(),
530 ParentRole:None,
531 Priority:0,
532 },
533 Role {
534 Name:"developer".to_string(),
535 Permissions:vec![
536 "file.read".to_string(),
537 "file.write".to_string(),
538 "config.read".to_string(),
539 "storage.read".to_string(),
540 "storage.write".to_string(),
541 ],
542 Description:"Developer with read/write access".to_string(),
543 ParentRole:None,
544 Priority:1,
545 },
546 Role {
547 Name:"admin".to_string(),
548 Permissions:vec![
549 "file.read".to_string(),
550 "file.write".to_string(),
551 "config.read".to_string(),
552 "config.update".to_string(),
553 "storage.read".to_string(),
554 "storage.write".to_string(),
555 "system.external".to_string(),
556 "system.execute".to_string(),
557 "admin.manage".to_string(),
558 ],
559 Description:"Administrator with full access".to_string(),
560 ParentRole:None,
561 Priority:2,
562 },
563 ];
564
565 for Role in DefaultRoles {
567 self.RegisterRole(Role).await?;
568 }
569
570 dev_log!(
571 "ipc",
572 "[PermissionValidator] Default roles and permissions initialized successfully"
573 );
574 Ok(())
575 }
576}
577
578#[cfg(test)]
579mod Tests {
580 use super::*;
581
582 #[tokio::test]
583 async fn TestCreateSecurityContext() {
584 let context = PermissionValidator::CreateSecurityContext(
585 "test-user".to_string(),
586 vec!["user".to_string(), "admin".to_string()],
587 "192.168.1.1".to_string(),
588 vec!["custom.permission".to_string()],
589 );
590
591 assert_eq!(context.UserId, "test-user".to_string());
592 assert_eq!(context.Roles, vec!["user".to_string(), "admin".to_string()]);
593 assert_eq!(context.IpAddress, "192.168.1.1".to_string());
594 assert_eq!(context.Permissions, vec!["custom.permission".to_string()]);
595 }
596
597 #[tokio::test]
598 async fn TestCreateSecurityContextDefaults() {
599 let context =
600 PermissionValidator::CreateSecurityContext("test-user".to_string(), vec![], "".to_string(), vec![]);
601
602 assert_eq!(context.UserId, "test-user".to_string());
603 assert_eq!(context.Roles, vec!["user".to_string()]);
604 assert_eq!(context.IpAddress, "127.0.0.1".to_string());
605 }
606
607 #[tokio::test]
608 async fn TestValidatePermissionNoPermissionsRequired() {
609 let validator = PermissionValidator::New(1000);
610 let context = SecurityContext {
611 UserId:"test-user".to_string(),
612 Roles:vec!["user".to_string()],
613 Permissions:vec![],
614 IpAddress:"127.0.0.1".to_string(),
615 Timestamp:SystemTime::now(),
616 };
617
618 let result = validator.ValidatePermission("unknown:operation", &context).await;
619 assert!(result.is_ok(), "Should succeed when no permissions are required");
620 }
621
622 #[tokio::test]
623 async fn TestValidatePermissionMissingPermission() {
624 let validator = PermissionValidator::New(1000);
625 let context = SecurityContext {
626 UserId:"test-user".to_string(),
627 Roles:vec!["user".to_string()],
628 Permissions:vec![],
629 IpAddress:"127.0.0.1".to_string(),
630 Timestamp:SystemTime::now(),
631 };
632
633 let result = validator.ValidatePermission("file:write", &context).await;
634 assert!(result.is_err(), "Should fail without required permission");
635 assert!(result.unwrap_err().contains("Missing required permission"));
636 }
637
638 #[tokio::test]
639 async fn TestValidatePermissionWithDirectPermission() {
640 let validator = PermissionValidator::New(1000);
641 let context = SecurityContext {
642 UserId:"test-user".to_string(),
643 Roles:vec![],
644 Permissions:vec!["file.write".to_string()],
645 IpAddress:"127.0.0.1".to_string(),
646 Timestamp:SystemTime::now(),
647 };
648
649 let result = validator.ValidatePermission("file:write", &context).await;
650 assert!(result.is_ok(), "Should succeed with direct permission");
651 }
652
653 #[tokio::test]
654 async fn TestValidatePermissionViaRole() {
655 let validator = PermissionValidator::New(1000);
656 validator.InitializeDefaults().await.unwrap();
657
658 let context = SecurityContext {
659 UserId:"test-user".to_string(),
660 Roles:vec!["admin".to_string()],
661 Permissions:vec![],
662 IpAddress:"127.0.0.1".to_string(),
663 Timestamp:SystemTime::now(),
664 };
665
666 let result = validator.ValidatePermission("file:write", &context).await;
667 assert!(result.is_ok(), "Should succeed via role permission");
668 }
669
670 #[tokio::test]
671 async fn TestValidatePermissionEmptyOperation() {
672 let validator = PermissionValidator::New(1000);
673 let context = SecurityContext {
674 UserId:"test-user".to_string(),
675 Roles:vec!["user".to_string()],
676 Permissions:vec![],
677 IpAddress:"127.0.0.1".to_string(),
678 Timestamp:SystemTime::now(),
679 };
680
681 let result = validator.ValidatePermission("", &context).await;
682 assert!(result.is_err(), "Should fail with empty operation name");
683 }
684
685 #[tokio::test]
686 async fn TestValidatePermissionEmptyUserId() {
687 let validator = PermissionValidator::New(1000);
688 let context = SecurityContext {
689 UserId:"".to_string(),
690 Roles:vec!["user".to_string()],
691 Permissions:vec![],
692 IpAddress:"127.0.0.1".to_string(),
693 Timestamp:SystemTime::now(),
694 };
695
696 let result = validator.ValidatePermission("file:read", &context).await;
697 assert!(result.is_err(), "Should fail with empty user ID");
698 }
699
700 #[tokio::test]
701 async fn TestInitializeDefaults() {
702 let validator = PermissionValidator::New(1000);
703 let result = validator.InitializeDefaults().await;
704 assert!(result.is_ok(), "Should initialize defaults successfully");
705
706 let user_perms = validator.GetRolePermissions("user").await;
708 assert!(user_perms.contains(&"file.read".to_string()));
709
710 let admin_perms = validator.GetRolePermissions("admin").await;
711 assert_ne!(admin_perms.len(), 0, "Admin should have many permissions");
712 }
713
714 #[tokio::test]
715 async fn TestGetRolePermissions() {
716 let validator = PermissionValidator::New(1000);
717 validator.InitializeDefaults().await.unwrap();
718
719 let role_perms = validator.GetRolePermissions("developer").await;
720 assert!(role_perms.contains(&"file.read".to_string()));
721 assert!(role_perms.contains(&"file.write".to_string()));
722 }
723
724 #[tokio::test]
725 async fn TestHasPermissionWithRole() {
726 let validator = PermissionValidator::New(1000);
727 validator.InitializeDefaults().await.unwrap();
728
729 let context = SecurityContext {
730 UserId:"test-user".to_string(),
731 Roles:vec!["admin".to_string()],
732 Permissions:vec![],
733 IpAddress:"127.0.0.1".to_string(),
734 Timestamp:SystemTime::now(),
735 };
736
737 assert!(validator.HasPermission(&context, "file.read").await);
738 assert!(validator.HasPermission(&context, "config.update").await);
739 }
740
741 #[tokio::test]
742 async fn TestHasPermissionDirect() {
743 let validator = PermissionValidator::New(1000);
744
745 let context = SecurityContext {
746 UserId:"test-user".to_string(),
747 Roles:vec![],
748 Permissions:vec!["custom.perm".to_string()],
749 IpAddress:"127.0.0.1".to_string(),
750 Timestamp:SystemTime::now(),
751 };
752
753 assert!(validator.HasPermission(&context, "custom.perm").await);
754 assert!(!validator.HasPermission(&context, "file.read").await);
755 }
756}