auth_framework/
permissions.rs

1/// Attribute-Based Access Control (ABAC) stub
2#[derive(Debug, Clone)]
3pub struct AbacPolicy {
4    pub attributes: HashMap<String, serde_json::Value>,
5    pub rules: Vec<AbacRule>,
6}
7
8#[derive(Debug, Clone)]
9pub struct AbacRule {
10    pub attribute: String,
11    pub expected_value: serde_json::Value,
12    pub permission: Permission,
13}
14
15/// Delegation model stub
16#[derive(Debug, Clone)]
17pub struct Delegation {
18    pub delegator: String,
19    pub delegatee: String,
20    pub permissions: HashSet<Permission>,
21    pub expires_at: Option<chrono::DateTime<chrono::Utc>>,
22}
23
24impl PermissionChecker {
25    /// Check permission for a user with ABAC and delegation support.
26    pub fn check_advanced_permission(
27        &self,
28        user_id: &str,
29        permission: &Permission,
30        user_attributes: &HashMap<String, serde_json::Value>,
31        abac_policy: Option<&AbacPolicy>,
32        delegations: Option<&[Delegation]>,
33        role_resolver: &dyn Fn(&str) -> Option<Role>,
34    ) -> bool {
35        // Check direct and role permissions
36        let has_basic = self.user_permissions.get(user_id).is_some_and(|up| {
37            let mut up = up.clone();
38            up.has_permission(permission, role_resolver)
39        });
40        if has_basic {
41            return true;
42        }
43        // Check ABAC policy
44        if let Some(policy) = abac_policy
45            && self.check_abac(user_attributes, permission, policy)
46        {
47            return true;
48        }
49        // Check delegation
50        if let Some(delegations) = delegations
51            && self.check_delegation(user_id, permission, delegations)
52        {
53            return true;
54        }
55        false
56    }
57    /// Check permission with ABAC policy
58    pub fn check_abac(
59        &self,
60        user_attributes: &HashMap<String, serde_json::Value>,
61        permission: &Permission,
62        abac_policy: &AbacPolicy,
63    ) -> bool {
64        for rule in &abac_policy.rules {
65            if let Some(attr_value) = user_attributes.get(&rule.attribute)
66                && attr_value == &rule.expected_value
67                && rule.permission.implies(permission)
68            {
69                return true;
70            }
71        }
72        false
73    }
74
75    /// Check permission with delegation
76    pub fn check_delegation(
77        &self,
78        user_id: &str,
79        permission: &Permission,
80        delegations: &[Delegation],
81    ) -> bool {
82        for delegation in delegations {
83            if delegation.delegatee == user_id
84                && delegation.permissions.iter().any(|p| p.implies(permission))
85            {
86                if let Some(expiry) = delegation.expires_at
87                    && expiry < chrono::Utc::now()
88                {
89                    continue;
90                }
91                return true;
92            }
93        }
94        false
95    }
96}
97/// Permission and role-based access control system.
98use crate::errors::{PermissionError, Result};
99use crate::tokens::AuthToken;
100use serde::{Deserialize, Serialize};
101use std::collections::{HashMap, HashSet};
102
103/// Represents a permission with action and resource.
104#[derive(Debug, Clone, PartialEq, Eq, Hash, Serialize, Deserialize)]
105pub struct Permission {
106    /// The action being performed (e.g., "read", "write", "delete")
107    pub action: String,
108
109    /// The resource being accessed (e.g., "documents", "users", "settings")
110    pub resource: String,
111
112    /// Optional resource instance (e.g., specific document ID)
113    pub instance: Option<String>,
114}
115
116/// Represents a role with associated permissions.
117#[derive(Debug, Clone, Serialize, Deserialize)]
118pub struct Role {
119    /// Role name
120    pub name: String,
121
122    /// Role description
123    pub description: Option<String>,
124
125    /// Permissions granted to this role
126    pub permissions: HashSet<Permission>,
127
128    /// Parent roles this role inherits from
129    pub parent_roles: HashSet<String>,
130
131    /// Whether this role is active
132    pub active: bool,
133}
134
135/// User permissions and roles.
136#[derive(Debug, Clone, Serialize, Deserialize)]
137pub struct UserPermissions {
138    /// User ID
139    pub user_id: String,
140
141    /// Direct permissions granted to the user
142    pub direct_permissions: HashSet<Permission>,
143
144    /// Roles assigned to the user
145    pub roles: HashSet<String>,
146
147    /// Cached computed permissions (includes role permissions)
148    pub computed_permissions: Option<HashSet<Permission>>,
149
150    /// When the permissions were last updated
151    pub last_updated: chrono::DateTime<chrono::Utc>,
152}
153
154/// Permission checker for validating access rights.
155#[derive(Debug, Clone)]
156pub struct PermissionChecker {
157    /// All defined roles
158    roles: HashMap<String, Role>,
159
160    /// User permissions cache
161    user_permissions: HashMap<String, UserPermissions>,
162
163    /// Permission hierarchy (for resource hierarchies)
164    resource_hierarchy: HashMap<String, Vec<String>>,
165}
166
167impl Permission {
168    /// Create a new permission.
169    pub fn new(action: impl Into<String>, resource: impl Into<String>) -> Self {
170        Self {
171            action: action.into(),
172            resource: resource.into(),
173            instance: None,
174        }
175    }
176
177    /// Create a new permission with just an action (resource defaults to "*").
178    pub fn from_action(action: impl Into<String>) -> Self {
179        Self {
180            action: action.into(),
181            resource: "*".to_string(),
182            instance: None,
183        }
184    }
185
186    /// Create a new permission with a specific instance.
187    pub fn with_instance(
188        action: impl Into<String>,
189        resource: impl Into<String>,
190        instance: impl Into<String>,
191    ) -> Self {
192        Self {
193            action: action.into(),
194            resource: resource.into(),
195            instance: Some(instance.into()),
196        }
197    }
198
199    /// Parse a permission from a string format "action:resource" or "action:resource:instance".
200    pub fn parse(permission_str: &str) -> Result<Self> {
201        let parts: Vec<&str> = permission_str.split(':').collect();
202
203        match parts.len() {
204            2 => Ok(Self::new(parts[0], parts[1])),
205            3 => Ok(Self::with_instance(parts[0], parts[1], parts[2])),
206            _ => Err(PermissionError::invalid_format(format!(
207                "Invalid permission format: {permission_str}"
208            ))
209            .into()),
210        }
211    }
212}
213
214impl std::fmt::Display for Permission {
215    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
216        match &self.instance {
217            Some(instance) => write!(f, "{}:{}:{}", self.action, self.resource, instance),
218            None => write!(f, "{}:{}", self.action, self.resource),
219        }
220    }
221}
222
223impl Permission {
224    /// Check if this permission matches another permission (considering wildcards).
225    pub fn matches(&self, other: &Permission) -> bool {
226        // Check action
227        if self.action != "*" && other.action != "*" && self.action != other.action {
228            return false;
229        }
230
231        // Check resource
232        if self.resource != "*" && other.resource != "*" && self.resource != other.resource {
233            return false;
234        }
235
236        // Check instance
237        match (&self.instance, &other.instance) {
238            (Some(self_instance), Some(other_instance)) => {
239                self_instance == "*" || other_instance == "*" || self_instance == other_instance
240            }
241            (None, None) => true,
242            (Some(_), None) => false, // Specific instance doesn't match general permission
243            (None, Some(_)) => true,  // General permission matches specific instance
244        }
245    }
246
247    /// Check if this permission implies another permission.
248    pub fn implies(&self, other: &Permission) -> bool {
249        // A permission implies another if it's more general or equal
250        let action_implies = self.action == "*" || self.action == other.action;
251        let resource_implies = self.resource == "*" || self.resource == other.resource;
252        let instance_implies = match (&self.instance, &other.instance) {
253            (None, _) => true, // General permission implies specific
254            (Some(self_instance), Some(other_instance)) => {
255                self_instance == "*" || self_instance == other_instance
256            }
257            (Some(_), None) => false, // Specific doesn't imply general
258        };
259
260        action_implies && resource_implies && instance_implies
261    }
262}
263
264impl Role {
265    /// Create a new role.
266    pub fn new(name: impl Into<String>) -> Self {
267        Self {
268            name: name.into(),
269            description: None,
270            permissions: HashSet::new(),
271            parent_roles: HashSet::new(),
272            active: true,
273        }
274    }
275
276    /// Set the role description.
277    pub fn with_description(mut self, description: impl Into<String>) -> Self {
278        self.description = Some(description.into());
279        self
280    }
281
282    /// Add a permission to the role.
283    pub fn add_permission(&mut self, permission: Permission) {
284        self.permissions.insert(permission);
285    }
286
287    /// Add multiple permissions to the role.
288    pub fn with_permissions(mut self, permissions: Vec<Permission>) -> Self {
289        for permission in permissions {
290            self.permissions.insert(permission);
291        }
292        self
293    }
294
295    /// Remove a permission from the role.
296    pub fn remove_permission(&mut self, permission: &Permission) {
297        self.permissions.remove(permission);
298    }
299
300    /// Add a parent role.
301    pub fn add_parent_role(&mut self, parent_role: impl Into<String>) {
302        self.parent_roles.insert(parent_role.into());
303    }
304
305    /// Check if the role has a specific permission.
306    pub fn has_permission(&self, permission: &Permission) -> bool {
307        self.permissions.iter().any(|p| p.implies(permission))
308    }
309
310    /// Get all permissions including inherited ones.
311    pub fn get_all_permissions(
312        &self,
313        role_resolver: &dyn Fn(&str) -> Option<Role>,
314    ) -> HashSet<Permission> {
315        let mut all_permissions = self.permissions.clone();
316
317        // Add permissions from parent roles
318        for parent_role_name in &self.parent_roles {
319            if let Some(parent_role) = role_resolver(parent_role_name) {
320                all_permissions.extend(parent_role.get_all_permissions(role_resolver));
321            }
322        }
323
324        all_permissions
325    }
326
327    /// Activate or deactivate the role.
328    pub fn set_active(&mut self, active: bool) {
329        self.active = active;
330    }
331}
332
333impl UserPermissions {
334    /// Create new user permissions.
335    pub fn new(user_id: impl Into<String>) -> Self {
336        Self {
337            user_id: user_id.into(),
338            direct_permissions: HashSet::new(),
339            roles: HashSet::new(),
340            computed_permissions: None,
341            last_updated: chrono::Utc::now(),
342        }
343    }
344
345    /// Add a direct permission to the user.
346    pub fn add_permission(&mut self, permission: Permission) {
347        self.direct_permissions.insert(permission);
348        self.computed_permissions = None; // Invalidate cache
349        self.last_updated = chrono::Utc::now();
350    }
351
352    /// Remove a direct permission from the user.
353    pub fn remove_permission(&mut self, permission: &Permission) {
354        self.direct_permissions.remove(permission);
355        self.computed_permissions = None; // Invalidate cache
356        self.last_updated = chrono::Utc::now();
357    }
358
359    /// Add a role to the user.
360    pub fn add_role(&mut self, role: impl Into<String>) {
361        self.roles.insert(role.into());
362        self.computed_permissions = None; // Invalidate cache
363        self.last_updated = chrono::Utc::now();
364    }
365
366    /// Remove a role from the user.
367    pub fn remove_role(&mut self, role: &str) {
368        self.roles.remove(role);
369        self.computed_permissions = None; // Invalidate cache
370        self.last_updated = chrono::Utc::now();
371    }
372
373    /// Compute all permissions for the user (including role permissions).
374    pub fn compute_permissions(
375        &mut self,
376        role_resolver: &dyn Fn(&str) -> Option<Role>,
377    ) -> &HashSet<Permission> {
378        if self.computed_permissions.is_none() {
379            let mut all_permissions = self.direct_permissions.clone();
380
381            // Add permissions from roles
382            for role_name in &self.roles {
383                if let Some(role) = role_resolver(role_name)
384                    && role.active
385                {
386                    all_permissions.extend(role.get_all_permissions(role_resolver));
387                }
388            }
389
390            self.computed_permissions = Some(all_permissions);
391        }
392
393        self.computed_permissions.as_ref().unwrap()
394    }
395
396    /// Check if the user has a specific permission.
397    pub fn has_permission(
398        &mut self,
399        permission: &Permission,
400        role_resolver: &dyn Fn(&str) -> Option<Role>,
401    ) -> bool {
402        let all_permissions = self.compute_permissions(role_resolver);
403        all_permissions.iter().any(|p| p.implies(permission))
404    }
405}
406
407impl PermissionChecker {
408    /// Create a new permission checker.
409    pub fn new() -> Self {
410        Self {
411            roles: HashMap::new(),
412            user_permissions: HashMap::new(),
413            resource_hierarchy: HashMap::new(),
414        }
415    }
416
417    /// Add a role definition.
418    pub fn add_role(&mut self, role: Role) {
419        self.roles.insert(role.name.clone(), role);
420    }
421
422    /// Remove a role definition.
423    pub fn remove_role(&mut self, role_name: &str) {
424        self.roles.remove(role_name);
425    }
426
427    /// Get a role by name.
428    pub fn get_role(&self, role_name: &str) -> Option<&Role> {
429        self.roles.get(role_name)
430    }
431
432    /// Set user permissions.
433    pub fn set_user_permissions(&mut self, user_permissions: UserPermissions) {
434        self.user_permissions
435            .insert(user_permissions.user_id.clone(), user_permissions);
436    }
437
438    /// Get user permissions.
439    pub fn get_user_permissions(&self, user_id: &str) -> Option<&UserPermissions> {
440        self.user_permissions.get(user_id)
441    }
442
443    /// Get mutable user permissions.
444    pub fn get_user_permissions_mut(&mut self, user_id: &str) -> Option<&mut UserPermissions> {
445        self.user_permissions.get_mut(user_id)
446    }
447
448    /// Add a permission to a user.
449    pub fn add_user_permission(&mut self, user_id: &str, permission: Permission) {
450        let user_perms = self
451            .user_permissions
452            .entry(user_id.to_string())
453            .or_insert_with(|| UserPermissions::new(user_id));
454
455        user_perms.add_permission(permission);
456    }
457
458    /// Add a role to a user.
459    pub fn add_user_role(&mut self, user_id: &str, role: impl Into<String>) {
460        let user_perms = self
461            .user_permissions
462            .entry(user_id.to_string())
463            .or_insert_with(|| UserPermissions::new(user_id));
464
465        user_perms.add_role(role);
466    }
467
468    /// Check if a user has a specific permission.
469    pub fn check_permission(&mut self, user_id: &str, permission: &Permission) -> Result<bool> {
470        let user_perms = self.user_permissions.get_mut(user_id).ok_or_else(|| {
471            PermissionError::access_denied(permission.to_string(), "unknown user".to_string())
472        })?;
473
474        let role_resolver = |role_name: &str| self.roles.get(role_name).cloned();
475
476        Ok(user_perms.has_permission(permission, &role_resolver))
477    }
478
479    /// Check if a user has permission for a specific action on a resource.
480    pub fn check_access(&mut self, user_id: &str, action: &str, resource: &str) -> Result<bool> {
481        let permission = Permission::new(action, resource);
482
483        // First check direct permission
484        if self.check_permission(user_id, &permission)? {
485            return Ok(true);
486        }
487
488        // Check hierarchical permissions if direct permission not found
489        self.check_hierarchical_permission(user_id, action, resource)
490    }
491
492    /// Check if a user has permission for a specific action on a resource instance.
493    pub fn check_instance_access(
494        &mut self,
495        user_id: &str,
496        action: &str,
497        resource: &str,
498        instance: &str,
499    ) -> Result<bool> {
500        let permission = Permission::with_instance(action, resource, instance);
501        self.check_permission(user_id, &permission)
502    }
503
504    /// Check permission from an auth token.
505    pub fn check_token_permission(
506        &mut self,
507        token: &AuthToken,
508        permission: &Permission,
509    ) -> Result<bool> {
510        if !token.is_valid() {
511            return Ok(false);
512        }
513
514        // Check if the token has the required scope
515        let required_scope = permission.to_string();
516        if !token.has_scope(&required_scope) {
517            // Also check for wildcard scopes
518            let wildcard_action = format!("*:{}", permission.resource);
519            let wildcard_resource = format!("{}:*", permission.action);
520            let wildcard_all = "*:*".to_string();
521
522            if !token.has_scope(&wildcard_action)
523                && !token.has_scope(&wildcard_resource)
524                && !token.has_scope(&wildcard_all)
525            {
526                return Ok(false);
527            }
528        }
529
530        // Check user permissions
531        self.check_permission(&token.user_id, permission)
532    }
533
534    /// Add resource hierarchy relationship
535    pub fn add_resource_hierarchy(&mut self, parent: String, children: Vec<String>) {
536        self.resource_hierarchy.insert(parent, children);
537    }
538
539    /// Get child resources for a parent resource
540    pub fn get_child_resources(&self, parent: &str) -> Option<&Vec<String>> {
541        self.resource_hierarchy.get(parent)
542    }
543
544    /// Check hierarchical permission - if user has permission on parent, they have it on children
545    pub fn check_hierarchical_permission(
546        &mut self,
547        user_id: &str,
548        action: &str,
549        resource: &str,
550    ) -> Result<bool> {
551        // Clone the hierarchy to avoid borrow checker issues
552        let hierarchy = self.resource_hierarchy.clone();
553
554        // Check all ancestor resources recursively
555        if self.has_ancestor_permission(&hierarchy, user_id, action, resource)? {
556            return Ok(true);
557        }
558
559        // Check for wildcard permissions that might apply
560        if self.check_wildcard_permissions(&hierarchy, user_id, action, resource)? {
561            return Ok(true);
562        }
563
564        Ok(false)
565    }
566
567    /// Check wildcard permissions that might apply to this resource
568    fn check_wildcard_permissions(
569        &mut self,
570        hierarchy: &HashMap<String, Vec<String>>,
571        user_id: &str,
572        action: &str,
573        resource: &str,
574    ) -> Result<bool> {
575        // Check if any parent resource has a wildcard permission that applies
576        for (parent_resource, children) in hierarchy {
577            if children.contains(&resource.to_string()) {
578                // Check for wildcard permission on parent (e.g., "projects.*" covering "documents")
579                let wildcard_permission = Permission::new(action, format!("{}.*", parent_resource));
580                if self
581                    .check_permission(user_id, &wildcard_permission)
582                    .unwrap_or(false)
583                {
584                    return Ok(true);
585                }
586            }
587        }
588
589        // Also check direct wildcard on resource itself
590        if let Some(_children) = hierarchy.get(resource) {
591            let wildcard_permission = Permission::new(action, format!("{}.*", resource));
592            if self
593                .check_permission(user_id, &wildcard_permission)
594                .unwrap_or(false)
595            {
596                return Ok(true);
597            }
598        }
599
600        Ok(false)
601    }
602
603    /// Recursively check if user has permission on any ancestor resource
604    fn has_ancestor_permission(
605        &mut self,
606        hierarchy: &HashMap<String, Vec<String>>,
607        user_id: &str,
608        action: &str,
609        resource: &str,
610    ) -> Result<bool> {
611        // Find direct parent resources
612        for (parent_resource, children) in hierarchy {
613            if children.contains(&resource.to_string()) {
614                // Check if user has permission on the parent resource
615                let parent_permission = Permission::new(action, parent_resource);
616                if self.check_permission(user_id, &parent_permission)? {
617                    return Ok(true);
618                }
619
620                // Recursively check if user has permission on ancestor of this parent
621                if self.has_ancestor_permission(hierarchy, user_id, action, parent_resource)? {
622                    return Ok(true);
623                }
624            }
625        }
626
627        Ok(false)
628    }
629
630    /// Create some default roles for common use cases.
631    pub fn create_default_roles(&mut self) {
632        // Admin role with all permissions
633        let mut admin_role = Role::new("admin").with_description("Administrator with full access");
634        admin_role.add_permission(Permission::new("*", "*"));
635        self.add_role(admin_role);
636
637        // User role with basic permissions
638        let mut user_role = Role::new("user").with_description("Regular user with basic access");
639        user_role.add_permission(Permission::new("read", "profile"));
640        user_role.add_permission(Permission::new("write", "profile"));
641        user_role.add_permission(Permission::new("read", "public"));
642        self.add_role(user_role);
643
644        // Guest role with read-only access
645        let mut guest_role =
646            Role::new("guest").with_description("Guest user with read-only access");
647        guest_role.add_permission(Permission::new("read", "public"));
648        self.add_role(guest_role);
649    }
650
651    /// Load permissions from a configuration or database.
652    pub fn load_permissions(&mut self, _config: &str) -> Result<()> {
653        // This would typically load from a configuration file or database
654        // For now, we'll create some default permissions
655        self.create_default_roles();
656        Ok(())
657    }
658
659    /// Assign a role to a user.
660    pub fn assign_role_to_user(&mut self, user_id: &str, role_name: &str) -> Result<()> {
661        // Validate that role exists
662        if !self.roles.contains_key(role_name) {
663            return Err(PermissionError::access_denied(
664                role_name.to_string(),
665                "Role does not exist".to_string(),
666            )
667            .into());
668        }
669
670        // Add role to user
671        self.add_user_role(user_id, role_name);
672        Ok(())
673    }
674
675    /// Set role inheritance relationship.
676    pub fn set_role_inheritance(&mut self, child_role: &str, parent_role: &str) -> Result<()> {
677        // Validate that both roles exist
678        if !self.roles.contains_key(child_role) {
679            return Err(PermissionError::access_denied(
680                child_role.to_string(),
681                "Child role does not exist".to_string(),
682            )
683            .into());
684        }
685        if !self.roles.contains_key(parent_role) {
686            return Err(PermissionError::access_denied(
687                parent_role.to_string(),
688                "Parent role does not exist".to_string(),
689            )
690            .into());
691        }
692
693        // Update role inheritance
694        if let Some(child) = self.roles.get_mut(child_role) {
695            child.add_parent_role(parent_role);
696        }
697
698        Ok(())
699    }
700
701    /// Remove a permission from a user.
702    pub fn remove_user_permission(&mut self, user_id: &str, permission: &Permission) {
703        if let Some(user_perms) = self.user_permissions.get_mut(user_id) {
704            user_perms.remove_permission(permission);
705        }
706    }
707
708    /// Check if a user has a specific role.
709    pub fn user_has_role(&self, user_id: &str, role_name: &str) -> bool {
710        if let Some(user_perms) = self.user_permissions.get(user_id) {
711            user_perms.roles.contains(role_name)
712        } else {
713            false
714        }
715    }
716
717    /// Get effective permissions for a user (including role-based permissions).
718    pub fn get_effective_permissions(&self, user_id: &str) -> Vec<String> {
719        if let Some(user_perms) = self.user_permissions.get(user_id) {
720            let role_resolver = |role_name: &str| self.roles.get(role_name).cloned();
721
722            // Create a mutable clone to compute permissions
723            let mut user_perms_clone = user_perms.clone();
724            let all_permissions = user_perms_clone.compute_permissions(&role_resolver);
725
726            all_permissions.iter().map(|p| p.to_string()).collect()
727        } else {
728            Vec::new()
729        }
730    }
731}
732
733impl Default for PermissionChecker {
734    fn default() -> Self {
735        Self::new()
736    }
737}
738
739#[cfg(test)]
740mod tests {
741    use super::*;
742
743    #[test]
744    fn test_permission_parsing() {
745        let perm = Permission::parse("read:documents").unwrap();
746        assert_eq!(perm.action, "read");
747        assert_eq!(perm.resource, "documents");
748        assert_eq!(perm.instance, None);
749
750        let perm = Permission::parse("write:documents:123").unwrap();
751        assert_eq!(perm.action, "write");
752        assert_eq!(perm.resource, "documents");
753        assert_eq!(perm.instance, Some("123".to_string()));
754    }
755
756    #[test]
757    fn test_permission_matching() {
758        let perm1 = Permission::new("read", "documents");
759        let perm2 = Permission::new("read", "documents");
760        let perm3 = Permission::new("write", "documents");
761        let wildcard = Permission::new("*", "documents");
762
763        assert!(perm1.matches(&perm2));
764        assert!(!perm1.matches(&perm3));
765        assert!(wildcard.matches(&perm1));
766        assert!(wildcard.matches(&perm3));
767    }
768
769    #[test]
770    fn test_permission_implies() {
771        let general = Permission::new("read", "documents");
772        let specific = Permission::with_instance("read", "documents", "123");
773        let wildcard = Permission::new("*", "*");
774
775        assert!(general.implies(&specific));
776        assert!(!specific.implies(&general));
777        assert!(wildcard.implies(&general));
778        assert!(wildcard.implies(&specific));
779    }
780
781    #[test]
782    fn test_role_permissions() {
783        let mut role = Role::new("editor");
784        role.add_permission(Permission::new("read", "documents"));
785        role.add_permission(Permission::new("write", "documents"));
786
787        let read_perm = Permission::new("read", "documents");
788        let delete_perm = Permission::new("delete", "documents");
789
790        assert!(role.has_permission(&read_perm));
791        assert!(!role.has_permission(&delete_perm));
792    }
793
794    #[test]
795    fn test_user_permissions() {
796        let mut user_perms = UserPermissions::new("user123");
797        user_perms.add_permission(Permission::new("read", "profile"));
798        user_perms.add_role("user");
799
800        let role_resolver = |_: &str| Some(Role::new("user"));
801
802        let read_perm = Permission::new("read", "profile");
803        assert!(user_perms.has_permission(&read_perm, &role_resolver));
804    }
805
806    #[test]
807    fn test_permission_checker() {
808        let mut checker = PermissionChecker::new();
809        checker.create_default_roles();
810
811        checker.add_user_role("user123", "admin");
812
813        let result = checker
814            .check_access("user123", "read", "documents")
815            .unwrap();
816        assert!(result);
817
818        let result = checker.check_access("user123", "delete", "system").unwrap();
819        assert!(result); // Admin has all permissions
820    }
821}
822
823#[cfg(test)]
824pub mod abac_delegation_tests;
825
826