1#[derive(Debug, Clone)]
19pub struct AbacPolicy {
20 pub attributes: HashMap<String, serde_json::Value>,
21 pub rules: Vec<AbacRule>,
22}
23
24#[derive(Debug, Clone)]
25pub struct AbacRule {
26 pub attribute: String,
27 pub expected_value: serde_json::Value,
28 pub permission: Permission,
29}
30
31impl AbacPolicy {
32 pub fn new() -> Self {
34 Self {
35 attributes: HashMap::new(),
36 rules: Vec::new(),
37 }
38 }
39
40 pub fn with_attribute(mut self, key: impl Into<String>, value: serde_json::Value) -> Self {
42 self.attributes.insert(key.into(), value);
43 self
44 }
45
46 pub fn with_attributes<I, K>(mut self, attributes: I) -> Self
48 where
49 I: IntoIterator<Item = (K, serde_json::Value)>,
50 K: Into<String>,
51 {
52 for (key, value) in attributes {
53 self.attributes.insert(key.into(), value);
54 }
55 self
56 }
57
58 pub fn with_rule(
60 mut self,
61 attribute: impl Into<String>,
62 expected_value: serde_json::Value,
63 permission: Permission,
64 ) -> Self {
65 self.rules.push(AbacRule {
66 attribute: attribute.into(),
67 expected_value,
68 permission,
69 });
70 self
71 }
72
73 pub fn with_rules<I>(mut self, rules: I) -> Self
75 where
76 I: IntoIterator<Item = AbacRule>,
77 {
78 self.rules.extend(rules);
79 self
80 }
81}
82
83#[derive(Debug, Clone)]
88pub struct Delegation {
89 pub delegator: String,
90 pub delegatee: String,
91 pub permissions: HashSet<Permission>,
92 pub expires_at: Option<chrono::DateTime<chrono::Utc>>,
93}
94
95impl Delegation {
96 pub fn new(delegator: impl Into<String>, delegatee: impl Into<String>) -> Self {
98 Self {
99 delegator: delegator.into(),
100 delegatee: delegatee.into(),
101 permissions: HashSet::new(),
102 expires_at: None,
103 }
104 }
105
106 pub fn with_permissions<I>(mut self, permissions: I) -> Self
108 where
109 I: IntoIterator<Item = Permission>,
110 {
111 self.permissions.extend(permissions);
112 self
113 }
114
115 pub fn with_permission(mut self, permission: Permission) -> Self {
117 self.permissions.insert(permission);
118 self
119 }
120
121 pub fn with_expiry(mut self, expires_at: chrono::DateTime<chrono::Utc>) -> Self {
123 self.expires_at = Some(expires_at);
124 self
125 }
126
127 pub fn permanent(mut self) -> Self {
129 self.expires_at = None;
130 self
131 }
132}
133
134impl PermissionChecker {
135 pub fn check_advanced_permission(
150 &self,
151 user_id: &str,
152 permission: &Permission,
153 user_attributes: &HashMap<String, serde_json::Value>,
154 abac_policy: Option<&AbacPolicy>,
155 delegations: Option<&[Delegation]>,
156 role_resolver: &dyn Fn(&str) -> Option<Role>,
157 ) -> bool {
158 let has_basic = self.user_permissions.get(user_id).is_some_and(|up| {
160 let mut up = up.clone();
161 up.has_permission(permission, role_resolver)
162 });
163 if has_basic {
164 return true;
165 }
166 if let Some(policy) = abac_policy
168 && self.check_abac(user_attributes, permission, policy)
169 {
170 return true;
171 }
172 if let Some(delegations) = delegations
174 && self.check_delegation(user_id, permission, delegations)
175 {
176 return true;
177 }
178 false
179 }
180 pub fn check_abac(
182 &self,
183 user_attributes: &HashMap<String, serde_json::Value>,
184 permission: &Permission,
185 abac_policy: &AbacPolicy,
186 ) -> bool {
187 for rule in &abac_policy.rules {
188 if let Some(attr_value) = user_attributes.get(&rule.attribute)
189 && attr_value == &rule.expected_value
190 && rule.permission.implies(permission)
191 {
192 return true;
193 }
194 }
195 false
196 }
197
198 pub fn check_delegation(
200 &self,
201 user_id: &str,
202 permission: &Permission,
203 delegations: &[Delegation],
204 ) -> bool {
205 for delegation in delegations {
206 if delegation.delegatee == user_id
207 && delegation.permissions.iter().any(|p| p.implies(permission))
208 {
209 if let Some(expiry) = delegation.expires_at
210 && expiry < chrono::Utc::now()
211 {
212 continue;
213 }
214 return true;
215 }
216 }
217 false
218 }
219}
220
221pub struct AdvancedPermissionCheck<'a> {
241 user_id: &'a str,
242 permission: &'a Permission,
243 user_attributes: Option<&'a HashMap<String, serde_json::Value>>,
244 abac_policy: Option<&'a AbacPolicy>,
245 delegations: Option<&'a [Delegation]>,
246 role_resolver: &'a dyn Fn(&str) -> Option<Role>,
247}
248
249impl<'a> AdvancedPermissionCheck<'a> {
250 pub fn new(
252 user_id: &'a str,
253 permission: &'a Permission,
254 role_resolver: &'a dyn Fn(&str) -> Option<Role>,
255 ) -> Self {
256 Self {
257 user_id,
258 permission,
259 user_attributes: None,
260 abac_policy: None,
261 delegations: None,
262 role_resolver,
263 }
264 }
265
266 pub fn user_attributes(mut self, attrs: &'a HashMap<String, serde_json::Value>) -> Self {
268 self.user_attributes = Some(attrs);
269 self
270 }
271
272 pub fn abac_policy(mut self, policy: &'a AbacPolicy) -> Self {
274 self.abac_policy = Some(policy);
275 self
276 }
277
278 pub fn delegations(mut self, delegations: &'a [Delegation]) -> Self {
280 self.delegations = Some(delegations);
281 self
282 }
283}
284
285impl PermissionChecker {
286 pub fn check_advanced(&self, check: AdvancedPermissionCheck<'_>) -> bool {
302 static EMPTY: std::sync::LazyLock<HashMap<String, serde_json::Value>> =
303 std::sync::LazyLock::new(HashMap::new);
304 self.check_advanced_permission(
305 check.user_id,
306 check.permission,
307 check.user_attributes.unwrap_or(&EMPTY),
308 check.abac_policy,
309 check.delegations,
310 check.role_resolver,
311 )
312 }
313}
314use crate::errors::{PermissionError, Result};
316use crate::tokens::AuthToken;
317use chrono;
318use serde::{Deserialize, Serialize};
319use serde_json;
320use std::collections::{HashMap, HashSet};
321
322#[derive(Debug, Clone, PartialEq, Eq, Hash, Serialize, Deserialize)]
324pub struct Permission {
325 pub action: String,
327
328 pub resource: String,
330
331 pub instance: Option<String>,
333}
334
335#[derive(Debug, Clone, Serialize, Deserialize)]
337pub struct Role {
338 pub id: Option<String>,
340
341 pub name: String,
343
344 pub description: Option<String>,
346
347 pub permissions: HashSet<Permission>,
349
350 pub parent_roles: HashSet<String>,
352
353 pub active: bool,
355
356 pub metadata: HashMap<String, String>,
358
359 pub created_at: Option<std::time::SystemTime>,
361
362 pub updated_at: Option<std::time::SystemTime>,
364}
365
366#[derive(Debug, Clone, Serialize, Deserialize)]
368pub struct UserPermissions {
369 pub user_id: String,
371
372 pub direct_permissions: HashSet<Permission>,
374
375 pub roles: HashSet<String>,
377
378 pub computed_permissions: Option<HashSet<Permission>>,
380
381 pub last_updated: chrono::DateTime<chrono::Utc>,
383}
384
385#[derive(Debug, Clone)]
387pub struct PermissionChecker {
388 roles: HashMap<String, Role>,
390
391 user_permissions: HashMap<String, UserPermissions>,
393
394 resource_hierarchy: HashMap<String, Vec<String>>,
396}
397
398impl Permission {
399 pub fn new(action: impl Into<String>, resource: impl Into<String>) -> Self {
401 Self {
402 action: action.into(),
403 resource: resource.into(),
404 instance: None,
405 }
406 }
407
408 pub fn from_action(action: impl Into<String>) -> Self {
410 Self {
411 action: action.into(),
412 resource: "*".to_string(),
413 instance: None,
414 }
415 }
416
417 pub fn with_instance(
419 action: impl Into<String>,
420 resource: impl Into<String>,
421 instance: impl Into<String>,
422 ) -> Self {
423 Self {
424 action: action.into(),
425 resource: resource.into(),
426 instance: Some(instance.into()),
427 }
428 }
429
430 pub fn parse(permission_str: &str) -> Result<Self> {
432 let parts: Vec<&str> = permission_str.split(':').collect();
433
434 match parts.len() {
435 2 => Ok(Self::new(parts[0], parts[1])),
436 3 => Ok(Self::with_instance(parts[0], parts[1], parts[2])),
437 _ => Err(PermissionError::invalid_format(format!(
438 "Invalid permission format: {permission_str}"
439 ))
440 .into()),
441 }
442 }
443}
444
445impl std::fmt::Display for Permission {
446 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
447 match &self.instance {
448 Some(instance) => write!(f, "{}:{}:{}", self.action, self.resource, instance),
449 None => write!(f, "{}:{}", self.action, self.resource),
450 }
451 }
452}
453
454impl Permission {
455 pub fn matches(&self, other: &Permission) -> bool {
457 if self.action != "*" && other.action != "*" && self.action != other.action {
459 return false;
460 }
461
462 if self.resource != "*" && other.resource != "*" && self.resource != other.resource {
464 return false;
465 }
466
467 match (&self.instance, &other.instance) {
469 (Some(self_instance), Some(other_instance)) => {
470 self_instance == "*" || other_instance == "*" || self_instance == other_instance
471 }
472 (None, None) => true,
473 (Some(_), None) => false, (None, Some(_)) => true, }
476 }
477
478 pub fn implies(&self, other: &Permission) -> bool {
480 let action_implies = self.action == "*" || self.action == other.action;
482 let resource_implies = self.resource == "*" || self.resource == other.resource;
483 let instance_implies = match (&self.instance, &other.instance) {
484 (None, _) => true, (Some(self_instance), Some(other_instance)) => {
486 self_instance == "*" || self_instance == other_instance
487 }
488 (Some(_), None) => false, };
490
491 action_implies && resource_implies && instance_implies
492 }
493}
494
495impl Role {
496 pub fn new(name: impl Into<String>) -> Self {
498 Self {
499 id: None,
500 name: name.into(),
501 description: None,
502 permissions: HashSet::new(),
503 parent_roles: HashSet::new(),
504 active: true,
505 metadata: HashMap::new(),
506 created_at: None,
507 updated_at: None,
508 }
509 }
510
511 pub fn with_description(mut self, description: impl Into<String>) -> Self {
513 self.description = Some(description.into());
514 self
515 }
516
517 pub fn add_permission(&mut self, permission: Permission) {
519 self.permissions.insert(permission);
520 }
521
522 pub fn with_permissions(mut self, permissions: Vec<Permission>) -> Self {
524 for permission in permissions {
525 self.permissions.insert(permission);
526 }
527 self
528 }
529
530 pub fn with_parent_roles<I, S>(mut self, parent_roles: I) -> Self
532 where
533 I: IntoIterator<Item = S>,
534 S: Into<String>,
535 {
536 for parent_role in parent_roles {
537 self.parent_roles.insert(parent_role.into());
538 }
539 self
540 }
541
542 pub fn with_metadata<I, K, V>(mut self, metadata: I) -> Self
544 where
545 I: IntoIterator<Item = (K, V)>,
546 K: Into<String>,
547 V: Into<String>,
548 {
549 for (key, value) in metadata {
550 self.metadata.insert(key.into(), value.into());
551 }
552 self
553 }
554
555 pub fn with_active(mut self, active: bool) -> Self {
557 self.active = active;
558 self
559 }
560
561 pub fn remove_permission(&mut self, permission: &Permission) {
563 self.permissions.remove(permission);
564 }
565
566 pub fn add_parent_role(&mut self, parent_role: impl Into<String>) {
568 self.parent_roles.insert(parent_role.into());
569 }
570
571 pub fn has_permission(&self, permission: &Permission) -> bool {
573 self.permissions.iter().any(|p| p.implies(permission))
574 }
575
576 pub fn get_all_permissions(
578 &self,
579 role_resolver: &dyn Fn(&str) -> Option<Role>,
580 ) -> HashSet<Permission> {
581 let mut all_permissions = self.permissions.clone();
582
583 for parent_role_name in &self.parent_roles {
585 if let Some(parent_role) = role_resolver(parent_role_name) {
586 all_permissions.extend(parent_role.get_all_permissions(role_resolver));
587 }
588 }
589
590 all_permissions
591 }
592
593 pub fn set_active(&mut self, active: bool) {
595 self.active = active;
596 }
597}
598
599impl PermissionChecker {
600 pub fn clear(&mut self) {
602 self.roles.clear();
603 self.user_permissions.clear();
604 self.resource_hierarchy.clear();
605 }
606
607 pub fn get_user_roles(&self, user_id: &str) -> Vec<String> {
609 self.user_permissions
610 .get(user_id)
611 .map(|permissions| permissions.roles.iter().cloned().collect())
612 .unwrap_or_default()
613 }
614}
615
616impl UserPermissions {
617 pub fn new(user_id: impl Into<String>) -> Self {
619 Self {
620 user_id: user_id.into(),
621 direct_permissions: HashSet::new(),
622 roles: HashSet::new(),
623 computed_permissions: None,
624 last_updated: chrono::Utc::now(),
625 }
626 }
627
628 pub fn add_permission(&mut self, permission: Permission) {
630 self.direct_permissions.insert(permission);
631 self.computed_permissions = None; self.last_updated = chrono::Utc::now();
633 }
634
635 pub fn remove_permission(&mut self, permission: &Permission) {
637 self.direct_permissions.remove(permission);
638 self.computed_permissions = None; self.last_updated = chrono::Utc::now();
640 }
641
642 pub fn add_role(&mut self, role: impl Into<String>) {
644 self.roles.insert(role.into());
645 self.computed_permissions = None; self.last_updated = chrono::Utc::now();
647 }
648
649 pub fn remove_role(&mut self, role: &str) {
651 self.roles.remove(role);
652 self.computed_permissions = None; self.last_updated = chrono::Utc::now();
654 }
655
656 pub fn compute_permissions(
658 &mut self,
659 role_resolver: &dyn Fn(&str) -> Option<Role>,
660 ) -> &HashSet<Permission> {
661 if self.computed_permissions.is_none() {
662 let mut all_permissions = self.direct_permissions.clone();
663
664 for role_name in &self.roles {
666 if let Some(role) = role_resolver(role_name)
667 && role.active
668 {
669 all_permissions.extend(role.get_all_permissions(role_resolver));
670 }
671 }
672
673 self.computed_permissions = Some(all_permissions);
674 }
675
676 self.computed_permissions
678 .as_ref()
679 .expect("computed_permissions is always Some after this block")
680 }
681
682 pub fn has_permission(
684 &mut self,
685 permission: &Permission,
686 role_resolver: &dyn Fn(&str) -> Option<Role>,
687 ) -> bool {
688 let all_permissions = self.compute_permissions(role_resolver);
689 all_permissions.iter().any(|p| p.implies(permission))
690 }
691}
692
693fn broader_action_implies(broader: &str, required: &str) -> bool {
699 if broader == required {
701 return true;
702 }
703 match broader {
704 "manage" | "admin" => matches!(
705 required,
706 "read" | "write" | "delete" | "create" | "list" | "update" | "get"
707 ),
708 "write" | "update" => matches!(required, "read" | "get" | "list"),
709 _ => false,
710 }
711}
712
713impl PermissionChecker {
714 pub fn new() -> Self {
716 Self {
717 roles: HashMap::new(),
718 user_permissions: HashMap::new(),
719 resource_hierarchy: HashMap::new(),
720 }
721 }
722
723 pub fn add_role(&mut self, role: Role) {
725 self.roles.insert(role.name.clone(), role);
726 }
727
728 pub fn remove_role(&mut self, role_name: &str) {
730 self.roles.remove(role_name);
731 }
732
733 pub fn get_role(&self, role_name: &str) -> Option<&Role> {
735 self.roles.get(role_name)
736 }
737
738 pub fn list_roles(&self) -> Vec<Role> {
740 self.roles.values().cloned().collect()
741 }
742
743 pub fn set_user_permissions(&mut self, user_permissions: UserPermissions) {
745 self.user_permissions
746 .insert(user_permissions.user_id.clone(), user_permissions);
747 }
748
749 pub fn get_user_permissions(&self, user_id: &str) -> Option<&UserPermissions> {
751 self.user_permissions.get(user_id)
752 }
753
754 pub fn get_user_permissions_mut(&mut self, user_id: &str) -> Option<&mut UserPermissions> {
756 self.user_permissions.get_mut(user_id)
757 }
758
759 pub fn add_user_permission(&mut self, user_id: &str, permission: Permission) {
761 let user_perms = self
762 .user_permissions
763 .entry(user_id.to_string())
764 .or_insert_with(|| UserPermissions::new(user_id));
765
766 user_perms.add_permission(permission);
767 }
768
769 pub fn add_user_role(&mut self, user_id: &str, role: impl Into<String>) {
771 let user_perms = self
772 .user_permissions
773 .entry(user_id.to_string())
774 .or_insert_with(|| UserPermissions::new(user_id));
775
776 user_perms.add_role(role);
777 }
778
779 pub fn remove_user_role(&mut self, user_id: &str, role_name: &str) {
781 if let Some(user_perms) = self.user_permissions.get_mut(user_id) {
782 user_perms.remove_role(role_name);
783 }
784 }
785
786 pub fn role_count(&self) -> usize {
788 self.roles.len()
789 }
790
791 pub fn user_count(&self) -> usize {
793 self.user_permissions.len()
794 }
795
796 pub fn total_direct_permission_count(&self) -> usize {
798 self.user_permissions
799 .values()
800 .map(|up| up.direct_permissions.len())
801 .sum()
802 }
803
804 pub fn check_permission(&mut self, user_id: &str, permission: &Permission) -> Result<bool> {
806 let user_perms = self.user_permissions.get_mut(user_id).ok_or_else(|| {
807 PermissionError::access_denied(permission.to_string(), "unknown user".to_string())
808 })?;
809
810 let role_resolver = |role_name: &str| self.roles.get(role_name).cloned();
811
812 Ok(user_perms.has_permission(permission, &role_resolver))
813 }
814
815 pub fn check_access(&mut self, user_id: &str, action: &str, resource: &str) -> Result<bool> {
817 let permission = Permission::new(action, resource);
818
819 if self.check_permission(user_id, &permission)? {
821 return Ok(true);
822 }
823
824 self.check_hierarchical_permission(user_id, action, resource)
826 }
827
828 pub fn check_instance_access(
830 &mut self,
831 user_id: &str,
832 action: &str,
833 resource: &str,
834 instance: &str,
835 ) -> Result<bool> {
836 let permission = Permission::with_instance(action, resource, instance);
837 self.check_permission(user_id, &permission)
838 }
839
840 pub fn check_token_permission(
842 &mut self,
843 token: &AuthToken,
844 permission: &Permission,
845 ) -> Result<bool> {
846 if !token.is_valid() {
847 return Ok(false);
848 }
849
850 let required_scope = permission.to_string();
852 if !token.has_scope(&required_scope) {
853 let wildcard_action = format!("*:{}", permission.resource);
855 let wildcard_resource = format!("{}:*", permission.action);
856 let wildcard_all = "*:*".to_string();
857
858 if !token.has_scope(&wildcard_action)
859 && !token.has_scope(&wildcard_resource)
860 && !token.has_scope(&wildcard_all)
861 {
862 return Ok(false);
863 }
864 }
865
866 self.check_permission(&token.user_id, permission)
868 }
869
870 pub fn add_resource_hierarchy(&mut self, parent: String, children: Vec<String>) {
872 self.resource_hierarchy.insert(parent, children);
873 }
874
875 pub fn get_child_resources(&self, parent: &str) -> Option<&Vec<String>> {
877 self.resource_hierarchy.get(parent)
878 }
879
880 pub fn check_hierarchical_permission(
882 &mut self,
883 user_id: &str,
884 action: &str,
885 resource: &str,
886 ) -> Result<bool> {
887 let hierarchy = self.resource_hierarchy.clone();
889
890 if self.has_ancestor_permission(&hierarchy, user_id, action, resource)? {
892 return Ok(true);
893 }
894
895 if self.check_wildcard_permissions(&hierarchy, user_id, action, resource)? {
897 return Ok(true);
898 }
899
900 Ok(false)
901 }
902
903 fn check_wildcard_permissions(
905 &mut self,
906 hierarchy: &HashMap<String, Vec<String>>,
907 user_id: &str,
908 action: &str,
909 resource: &str,
910 ) -> Result<bool> {
911 for (parent_resource, children) in hierarchy {
913 if children.contains(&resource.to_string()) {
914 let wildcard_permission = Permission::new(action, format!("{}.*", parent_resource));
916 if self
917 .check_permission(user_id, &wildcard_permission)
918 .unwrap_or(false)
919 {
920 return Ok(true);
921 }
922 }
923 }
924
925 if let Some(_children) = hierarchy.get(resource) {
927 let wildcard_permission = Permission::new(action, format!("{}.*", resource));
928 if self
929 .check_permission(user_id, &wildcard_permission)
930 .unwrap_or(false)
931 {
932 return Ok(true);
933 }
934 }
935
936 Ok(false)
937 }
938
939 fn has_ancestor_permission(
941 &mut self,
942 hierarchy: &HashMap<String, Vec<String>>,
943 user_id: &str,
944 action: &str,
945 resource: &str,
946 ) -> Result<bool> {
947 for (parent_resource, children) in hierarchy {
949 if children.contains(&resource.to_string()) {
950 if self.check_permission_with_action_hierarchy(user_id, action, parent_resource)? {
954 return Ok(true);
955 }
956
957 if self.has_ancestor_permission(hierarchy, user_id, action, parent_resource)? {
959 return Ok(true);
960 }
961 }
962 }
963
964 Ok(false)
965 }
966
967 fn check_permission_with_action_hierarchy(
973 &mut self,
974 user_id: &str,
975 required_action: &str,
976 resource: &str,
977 ) -> Result<bool> {
978 let exact = Permission::new(required_action, resource);
980 if self.check_permission(user_id, &exact).unwrap_or(false) {
981 return Ok(true);
982 }
983
984 let role_resolver = |role_name: &str| self.roles.get(role_name).cloned();
986 let user_perms = match self.user_permissions.get_mut(user_id) {
987 Some(p) => p,
988 None => return Ok(false),
989 };
990 let all_perms = user_perms.compute_permissions(&role_resolver);
991
992 Ok(all_perms.iter().any(|p| {
993 let resource_match = p.resource == "*" || p.resource == resource;
994 let action_match =
995 p.action == "*" || broader_action_implies(&p.action, required_action);
996 resource_match && action_match
997 }))
998 }
999
1000 pub fn create_default_roles(&mut self) {
1002 let mut admin_role = Role::new("admin").with_description("Administrator with full access");
1004 admin_role.add_permission(Permission::new("*", "*"));
1005 self.add_role(admin_role);
1006
1007 let mut user_role = Role::new("user").with_description("Regular user with basic access");
1009 user_role.add_permission(Permission::new("read", "profile"));
1010 user_role.add_permission(Permission::new("write", "profile"));
1011 user_role.add_permission(Permission::new("read", "public"));
1012 self.add_role(user_role);
1013
1014 let mut guest_role =
1016 Role::new("guest").with_description("Guest user with read-only access");
1017 guest_role.add_permission(Permission::new("read", "public"));
1018 self.add_role(guest_role);
1019 }
1020
1021 pub fn load_permissions(&mut self, _config: &str) -> Result<()> {
1023 self.create_default_roles();
1026 Ok(())
1027 }
1028
1029 pub fn assign_role_to_user(&mut self, user_id: &str, role_name: &str) -> Result<()> {
1031 if !self.roles.contains_key(role_name) {
1033 return Err(PermissionError::access_denied(
1034 role_name.to_string(),
1035 "Role does not exist".to_string(),
1036 )
1037 .into());
1038 }
1039
1040 self.add_user_role(user_id, role_name);
1042 Ok(())
1043 }
1044
1045 pub fn set_role_inheritance(&mut self, child_role: &str, parent_role: &str) -> Result<()> {
1047 if !self.roles.contains_key(child_role) {
1049 return Err(PermissionError::access_denied(
1050 child_role.to_string(),
1051 "Child role does not exist".to_string(),
1052 )
1053 .into());
1054 }
1055 if !self.roles.contains_key(parent_role) {
1056 return Err(PermissionError::access_denied(
1057 parent_role.to_string(),
1058 "Parent role does not exist".to_string(),
1059 )
1060 .into());
1061 }
1062
1063 if let Some(child) = self.roles.get_mut(child_role) {
1065 child.add_parent_role(parent_role);
1066 }
1067
1068 Ok(())
1069 }
1070
1071 pub fn remove_user_permission(&mut self, user_id: &str, permission: &Permission) {
1073 if let Some(user_perms) = self.user_permissions.get_mut(user_id) {
1074 user_perms.remove_permission(permission);
1075 }
1076 }
1077
1078 pub fn user_has_role(&self, user_id: &str, role_name: &str) -> bool {
1080 if let Some(user_perms) = self.user_permissions.get(user_id) {
1081 user_perms.roles.contains(role_name)
1082 } else {
1083 false
1084 }
1085 }
1086
1087 pub fn get_effective_permissions(&self, user_id: &str) -> Vec<String> {
1089 if let Some(user_perms) = self.user_permissions.get(user_id) {
1090 let role_resolver = |role_name: &str| self.roles.get(role_name).cloned();
1091
1092 let mut user_perms_clone = user_perms.clone();
1094 let all_permissions = user_perms_clone.compute_permissions(&role_resolver);
1095
1096 all_permissions.iter().map(|p| p.to_string()).collect()
1097 } else {
1098 Vec::new()
1099 }
1100 }
1101}
1102
1103impl Default for PermissionChecker {
1104 fn default() -> Self {
1105 Self::new()
1106 }
1107}
1108
1109#[cfg(test)]
1110mod tests {
1111 use super::*;
1112
1113 #[test]
1114 fn test_permission_parsing() {
1115 let perm = Permission::parse("read:documents").unwrap();
1116 assert_eq!(perm.action, "read");
1117 assert_eq!(perm.resource, "documents");
1118 assert_eq!(perm.instance, None);
1119
1120 let perm = Permission::parse("write:documents:123").unwrap();
1121 assert_eq!(perm.action, "write");
1122 assert_eq!(perm.resource, "documents");
1123 assert_eq!(perm.instance, Some("123".to_string()));
1124 }
1125
1126 #[test]
1127 fn test_permission_matching() {
1128 let perm1 = Permission::new("read", "documents");
1129 let perm2 = Permission::new("read", "documents");
1130 let perm3 = Permission::new("write", "documents");
1131 let wildcard = Permission::new("*", "documents");
1132
1133 assert!(perm1.matches(&perm2));
1134 assert!(!perm1.matches(&perm3));
1135 assert!(wildcard.matches(&perm1));
1136 assert!(wildcard.matches(&perm3));
1137 }
1138
1139 #[test]
1140 fn test_permission_implies() {
1141 let general = Permission::new("read", "documents");
1142 let specific = Permission::with_instance("read", "documents", "123");
1143 let wildcard = Permission::new("*", "*");
1144
1145 assert!(general.implies(&specific));
1146 assert!(!specific.implies(&general));
1147 assert!(wildcard.implies(&general));
1148 assert!(wildcard.implies(&specific));
1149 }
1150
1151 #[test]
1152 fn test_role_permissions() {
1153 let mut role = Role::new("editor");
1154 role.add_permission(Permission::new("read", "documents"));
1155 role.add_permission(Permission::new("write", "documents"));
1156
1157 let read_perm = Permission::new("read", "documents");
1158 let delete_perm = Permission::new("delete", "documents");
1159
1160 assert!(role.has_permission(&read_perm));
1161 assert!(!role.has_permission(&delete_perm));
1162 }
1163
1164 #[test]
1165 fn test_user_permissions() {
1166 let mut user_perms = UserPermissions::new("user123");
1167 user_perms.add_permission(Permission::new("read", "profile"));
1168 user_perms.add_role("user");
1169
1170 let role_resolver = |_: &str| Some(Role::new("user"));
1171
1172 let read_perm = Permission::new("read", "profile");
1173 assert!(user_perms.has_permission(&read_perm, &role_resolver));
1174 }
1175
1176 #[test]
1177 fn test_permission_checker() {
1178 let mut checker = PermissionChecker::new();
1179 checker.create_default_roles();
1180
1181 checker.add_user_role("user123", "admin");
1182
1183 let result = checker
1184 .check_access("user123", "read", "documents")
1185 .unwrap();
1186 assert!(result);
1187
1188 let result = checker.check_access("user123", "delete", "system").unwrap();
1189 assert!(result); }
1191}
1192
1193#[cfg(test)]
1194pub mod abac_delegation_tests;