eventuali_core/security/
rbac.rs

1use crate::{EventualiError, Result};
2use serde::{Deserialize, Serialize};
3use std::collections::{HashMap, HashSet};
4use chrono::{DateTime, Utc, Duration};
5use uuid::Uuid;
6
7/// Role-Based Access Control (RBAC) implementation
8pub struct RbacManager {
9    roles: HashMap<String, Role>,
10    users: HashMap<String, User>,
11    permissions: HashMap<String, Permission>,
12    sessions: HashMap<String, Session>,
13    audit_log: Vec<AuditEntry>,
14    role_hierarchy: RoleHierarchy,
15    #[allow(dead_code)] // Policy engine is part of the RBAC API but not yet implemented
16    policy_engine: PolicyEngine,
17}
18
19/// User in the RBAC system
20#[derive(Debug, Clone, Serialize, Deserialize)]
21pub struct User {
22    pub user_id: String,
23    pub username: String,
24    pub email: String,
25    pub roles: HashSet<String>,
26    pub attributes: HashMap<String, String>,
27    pub created_at: DateTime<Utc>,
28    pub last_login: Option<DateTime<Utc>>,
29    pub is_active: bool,
30    pub security_level: SecurityLevel,
31}
32
33/// Role with permissions and hierarchy
34#[derive(Debug, Clone, Serialize, Deserialize)]
35pub struct Role {
36    pub role_id: String,
37    pub name: String,
38    pub description: String,
39    pub permissions: HashSet<String>,
40    pub parent_roles: HashSet<String>,
41    pub child_roles: HashSet<String>,
42    pub created_at: DateTime<Utc>,
43    pub is_system_role: bool,
44}
45
46/// Permission definition
47#[derive(Debug, Clone, Serialize, Deserialize)]
48pub struct Permission {
49    pub permission_id: String,
50    pub name: String,
51    pub description: String,
52    pub resource_type: String,
53    pub action: String,
54    pub conditions: Vec<String>,
55    pub created_at: DateTime<Utc>,
56}
57
58/// Security level for clearance-based access
59#[derive(Debug, Clone, Serialize, Deserialize, PartialEq, Eq, Hash)]
60pub enum SecurityLevel {
61    Public,
62    Internal,
63    Confidential,
64    Secret,
65    TopSecret,
66}
67
68/// Active session
69#[derive(Debug, Clone, Serialize, Deserialize)]
70pub struct Session {
71    pub session_id: String,
72    pub user_id: String,
73    pub token: String,
74    pub created_at: DateTime<Utc>,
75    pub expires_at: DateTime<Utc>,
76    pub ip_address: Option<String>,
77    pub user_agent: Option<String>,
78    pub permissions_cache: HashSet<String>,
79    pub is_active: bool,
80}
81
82/// Access control decision
83#[derive(Debug, Clone, Serialize, Deserialize)]
84pub enum AccessDecision {
85    Allow,
86    Deny,
87    DenyWithReason(String),
88}
89
90/// Audit entry for compliance
91#[derive(Debug, Clone, Serialize, Deserialize)]
92pub struct AuditEntry {
93    pub audit_id: String,
94    pub user_id: String,
95    pub action: String,
96    pub resource: String,
97    pub resource_id: Option<String>,
98    pub decision: AccessDecision,
99    pub timestamp: DateTime<Utc>,
100    pub ip_address: Option<String>,
101    pub session_id: Option<String>,
102    pub reason: Option<String>,
103    pub metadata: HashMap<String, String>,
104}
105
106/// Role hierarchy manager
107pub struct RoleHierarchy {
108    hierarchy: HashMap<String, HashSet<String>>, // role -> parent roles
109}
110
111/// Policy engine for complex access control
112pub struct PolicyEngine {
113    #[allow(dead_code)] // Policies storage for future dynamic policy evaluation
114    policies: HashMap<String, AccessPolicy>,
115}
116
117/// Access policy
118#[derive(Debug, Clone, Serialize, Deserialize)]
119pub struct AccessPolicy {
120    pub policy_id: String,
121    pub name: String,
122    pub resource_pattern: String,
123    pub conditions: Vec<PolicyCondition>,
124    pub effect: PolicyEffect,
125    pub priority: i32,
126}
127
128/// Policy condition
129#[derive(Debug, Clone, Serialize, Deserialize)]
130pub struct PolicyCondition {
131    pub attribute: String,
132    pub operator: String,
133    pub value: String,
134}
135
136/// Policy effect
137#[derive(Debug, Clone, Serialize, Deserialize)]
138pub enum PolicyEffect {
139    Allow,
140    Deny,
141}
142
143impl RbacManager {
144    /// Create a new RBAC manager
145    pub fn new() -> Self {
146        let mut rbac = Self {
147            roles: HashMap::new(),
148            users: HashMap::new(),
149            permissions: HashMap::new(),
150            sessions: HashMap::new(),
151            audit_log: Vec::new(),
152            role_hierarchy: RoleHierarchy::new(),
153            policy_engine: PolicyEngine::new(),
154        };
155        
156        rbac.initialize_system_roles();
157        rbac
158    }
159    
160    /// Initialize default system roles
161    fn initialize_system_roles(&mut self) {
162        // System Administrator role
163        let admin_role = Role {
164            role_id: "system:admin".to_string(),
165            name: "System Administrator".to_string(),
166            description: "Full system access".to_string(),
167            permissions: HashSet::new(),
168            parent_roles: HashSet::new(),
169            child_roles: HashSet::new(),
170            created_at: Utc::now(),
171            is_system_role: true,
172        };
173        
174        // Manager role
175        let manager_role = Role {
176            role_id: "system:manager".to_string(),
177            name: "Manager".to_string(),
178            description: "Management access".to_string(),
179            permissions: HashSet::new(),
180            parent_roles: HashSet::new(),
181            child_roles: HashSet::new(),
182            created_at: Utc::now(),
183            is_system_role: true,
184        };
185        
186        // Employee role
187        let employee_role = Role {
188            role_id: "system:employee".to_string(),
189            name: "Employee".to_string(),
190            description: "Standard employee access".to_string(),
191            permissions: HashSet::new(),
192            parent_roles: HashSet::new(),
193            child_roles: HashSet::new(),
194            created_at: Utc::now(),
195            is_system_role: true,
196        };
197        
198        // Guest role
199        let guest_role = Role {
200            role_id: "system:guest".to_string(),
201            name: "Guest".to_string(),
202            description: "Limited read-only access".to_string(),
203            permissions: HashSet::new(),
204            parent_roles: HashSet::new(),
205            child_roles: HashSet::new(),
206            created_at: Utc::now(),
207            is_system_role: true,
208        };
209        
210        // Set up hierarchy: Admin > Manager > Employee > Guest
211        // Note: In this hierarchy, child roles inherit from parent roles
212        // Manager inherits from Employee, Employee inherits from Guest
213        self.role_hierarchy.add_parent("system:manager", "system:employee");
214        self.role_hierarchy.add_parent("system:employee", "system:guest");
215        
216        self.roles.insert("system:admin".to_string(), admin_role);
217        self.roles.insert("system:manager".to_string(), manager_role);
218        self.roles.insert("system:employee".to_string(), employee_role);
219        self.roles.insert("system:guest".to_string(), guest_role);
220        
221        // Initialize system permissions
222        self.initialize_system_permissions();
223    }
224    
225    /// Initialize default system permissions
226    fn initialize_system_permissions(&mut self) {
227        let permissions = vec![
228            ("events:read", "Event Store", "read", "Read events from event store"),
229            ("events:write", "Event Store", "write", "Write events to event store"),
230            ("events:delete", "Event Store", "delete", "Delete events from event store"),
231            ("aggregates:read", "Aggregates", "read", "Read aggregates"),
232            ("aggregates:write", "Aggregates", "write", "Write aggregates"),
233            ("projections:read", "Projections", "read", "Read projections"),
234            ("projections:write", "Projections", "write", "Write projections"),
235            ("system:admin", "System", "admin", "System administration"),
236            ("audit:read", "Audit", "read", "Read audit logs"),
237            ("users:manage", "Users", "manage", "Manage users and roles"),
238        ];
239        
240        for (perm_id, resource, action, desc) in permissions {
241            let permission = Permission {
242                permission_id: perm_id.to_string(),
243                name: format!("{resource} {action}"),
244                description: desc.to_string(),
245                resource_type: resource.to_string(),
246                action: action.to_string(),
247                conditions: Vec::new(),
248                created_at: Utc::now(),
249            };
250            
251            self.permissions.insert(perm_id.to_string(), permission);
252        }
253        
254        // Assign permissions to roles - build hierarchy from most restrictive to most permissive
255        
256        // Guest role (most restrictive) - read-only access to basic data
257        self.assign_permission_to_role("system:guest", "projections:read").unwrap();
258        
259        // Employee role - inherits Guest + basic event and aggregate access
260        self.assign_permission_to_role("system:employee", "events:read").unwrap();
261        self.assign_permission_to_role("system:employee", "aggregates:read").unwrap();
262        
263        // Manager role - inherits Employee + write access and management permissions
264        self.assign_permission_to_role("system:manager", "events:write").unwrap();
265        self.assign_permission_to_role("system:manager", "aggregates:write").unwrap();
266        self.assign_permission_to_role("system:manager", "projections:write").unwrap();
267        
268        // Admin role - full access to all systems
269        self.assign_permission_to_role("system:admin", "system:admin").unwrap();
270        self.assign_permission_to_role("system:admin", "users:manage").unwrap();
271        self.assign_permission_to_role("system:admin", "events:delete").unwrap();
272        self.assign_permission_to_role("system:admin", "audit:read").unwrap();
273    }
274    
275    /// Create a new user
276    pub fn create_user(
277        &mut self,
278        username: String,
279        email: String,
280        security_level: SecurityLevel,
281    ) -> Result<String> {
282        let user_id = Uuid::new_v4().to_string();
283        
284        let user = User {
285            user_id: user_id.clone(),
286            username: username.clone(),
287            email,
288            roles: HashSet::new(),
289            attributes: HashMap::new(),
290            created_at: Utc::now(),
291            last_login: None,
292            is_active: true,
293            security_level,
294        };
295        
296        self.users.insert(user_id.clone(), user);
297        
298        self.audit_log.push(AuditEntry {
299            audit_id: Uuid::new_v4().to_string(),
300            user_id: "system".to_string(),
301            action: "user:create".to_string(),
302            resource: "user".to_string(),
303            resource_id: Some(user_id.clone()),
304            decision: AccessDecision::Allow,
305            timestamp: Utc::now(),
306            ip_address: None,
307            session_id: None,
308            reason: Some(format!("User {username} created")),
309            metadata: HashMap::new(),
310        });
311        
312        Ok(user_id)
313    }
314    
315    /// Assign role to user
316    pub fn assign_role_to_user(&mut self, user_id: &str, role_id: &str) -> Result<()> {
317        if !self.users.contains_key(user_id) {
318            return Err(EventualiError::Validation(format!("User {user_id} not found")));
319        }
320        
321        if !self.roles.contains_key(role_id) {
322            return Err(EventualiError::Validation(format!("Role {role_id} not found")));
323        }
324        
325        let user = self.users.get_mut(user_id).unwrap();
326        user.roles.insert(role_id.to_string());
327        
328        self.audit_log.push(AuditEntry {
329            audit_id: Uuid::new_v4().to_string(),
330            user_id: user_id.to_string(),
331            action: "role:assign".to_string(),
332            resource: "user".to_string(),
333            resource_id: Some(user_id.to_string()),
334            decision: AccessDecision::Allow,
335            timestamp: Utc::now(),
336            ip_address: None,
337            session_id: None,
338            reason: Some(format!("Role {role_id} assigned to user")),
339            metadata: HashMap::new(),
340        });
341        
342        Ok(())
343    }
344    
345    /// Create role
346    pub fn create_role(&mut self, name: String, description: String) -> Result<String> {
347        let role_id = format!("custom:{}", Uuid::new_v4());
348        
349        let role = Role {
350            role_id: role_id.clone(),
351            name: name.clone(),
352            description,
353            permissions: HashSet::new(),
354            parent_roles: HashSet::new(),
355            child_roles: HashSet::new(),
356            created_at: Utc::now(),
357            is_system_role: false,
358        };
359        
360        self.roles.insert(role_id.clone(), role);
361        
362        self.audit_log.push(AuditEntry {
363            audit_id: Uuid::new_v4().to_string(),
364            user_id: "system".to_string(),
365            action: "role:create".to_string(),
366            resource: "role".to_string(),
367            resource_id: Some(role_id.clone()),
368            decision: AccessDecision::Allow,
369            timestamp: Utc::now(),
370            ip_address: None,
371            session_id: None,
372            reason: Some(format!("Role {name} created")),
373            metadata: HashMap::new(),
374        });
375        
376        Ok(role_id)
377    }
378    
379    /// Assign permission to role
380    pub fn assign_permission_to_role(&mut self, role_id: &str, permission_id: &str) -> Result<()> {
381        if !self.roles.contains_key(role_id) {
382            return Err(EventualiError::Validation(format!("Role {role_id} not found")));
383        }
384        
385        if !self.permissions.contains_key(permission_id) {
386            return Err(EventualiError::Validation(format!("Permission {permission_id} not found")));
387        }
388        
389        let role = self.roles.get_mut(role_id).unwrap();
390        role.permissions.insert(permission_id.to_string());
391        
392        Ok(())
393    }
394    
395    /// Authenticate user and create session
396    pub fn authenticate(&mut self, username: &str, password: &str, ip_address: Option<String>) -> Result<String> {
397        let user_info = {
398            let user = self.users.values()
399                .find(|u| u.username == username && u.is_active)
400                .ok_or_else(|| EventualiError::Authentication("Invalid credentials".to_string()))?;
401            (user.user_id.clone(), user.username.clone())
402        };
403        
404        // In production, verify password hash
405        if self.verify_password(password) {
406            let session_id = Uuid::new_v4().to_string();
407            let token = self.generate_session_token(&user_info.0);
408            
409            let session = Session {
410                session_id: session_id.clone(),
411                user_id: user_info.0.clone(),
412                token: token.clone(),
413                created_at: Utc::now(),
414                expires_at: Utc::now() + Duration::hours(8),
415                ip_address: ip_address.clone(),
416                user_agent: None,
417                permissions_cache: self.get_effective_permissions(&user_info.0)?,
418                is_active: true,
419            };
420            
421            self.sessions.insert(session_id.clone(), session);
422            
423            // Update user last login
424            let user = self.users.get_mut(&user_info.0).unwrap();
425            user.last_login = Some(Utc::now());
426            
427            self.audit_log.push(AuditEntry {
428                audit_id: Uuid::new_v4().to_string(),
429                user_id: user_info.0.clone(),
430                action: "authentication:success".to_string(),
431                resource: "session".to_string(),
432                resource_id: Some(session_id.clone()),
433                decision: AccessDecision::Allow,
434                timestamp: Utc::now(),
435                ip_address,
436                session_id: Some(session_id.clone()),
437                reason: Some("Authentication successful".to_string()),
438                metadata: HashMap::new(),
439            });
440            
441            Ok(token)
442        } else {
443            self.audit_log.push(AuditEntry {
444                audit_id: Uuid::new_v4().to_string(),
445                user_id: user_info.0.clone(),
446                action: "authentication:failure".to_string(),
447                resource: "session".to_string(),
448                resource_id: None,
449                decision: AccessDecision::Deny,
450                timestamp: Utc::now(),
451                ip_address,
452                session_id: None,
453                reason: Some("Invalid password".to_string()),
454                metadata: HashMap::new(),
455            });
456            
457            Err(EventualiError::Authentication("Invalid credentials".to_string()))
458        }
459    }
460    
461    /// Check access permission
462    pub fn check_access(
463        &mut self,
464        token: &str,
465        resource: &str,
466        action: &str,
467        context: Option<HashMap<String, String>>,
468    ) -> AccessDecision {
469        // Clone necessary data to avoid borrowing conflicts
470        let session_data = match self.get_session_by_token(token) {
471            Some(session) if session.is_active && session.expires_at > Utc::now() => {
472                (session.user_id.clone(), session.permissions_cache.clone())
473            },
474            _ => {
475                let decision = AccessDecision::DenyWithReason("Invalid or expired token".to_string());
476                self.audit_access(None, resource, action, decision.clone(), context);
477                return decision;
478            }
479        };
480        
481        let user_active = match self.users.get(&session_data.0) {
482            Some(user) if user.is_active => true,
483            _ => {
484                let decision = AccessDecision::DenyWithReason("User inactive".to_string());
485                self.audit_access(Some(&session_data.0), resource, action, decision.clone(), context);
486                return decision;
487            }
488        };
489        
490        if !user_active {
491            let decision = AccessDecision::DenyWithReason("User inactive".to_string());
492            self.audit_access(Some(&session_data.0), resource, action, decision.clone(), context);
493            return decision;
494        }
495        
496        // Check permission
497        let permission_id = format!("{resource}:{action}");
498        let decision = if session_data.1.contains(&permission_id) {
499            AccessDecision::Allow
500        } else {
501            AccessDecision::DenyWithReason(format!("Permission {permission_id} not granted"))
502        };
503        
504        self.audit_access(Some(&session_data.0), resource, action, decision.clone(), context);
505        decision
506    }
507    
508    /// Get effective permissions for user (including hierarchy)
509    pub fn get_effective_permissions(&self, user_id: &str) -> Result<HashSet<String>> {
510        let user = self.users.get(user_id)
511            .ok_or_else(|| EventualiError::Validation("User not found".to_string()))?;
512        
513        let mut permissions = HashSet::new();
514        
515        for role_id in &user.roles {
516            if let Some(role_permissions) = self.get_role_permissions_with_hierarchy(role_id) {
517                permissions.extend(role_permissions);
518            }
519        }
520        
521        Ok(permissions)
522    }
523    
524    /// Get role permissions including inherited ones
525    fn get_role_permissions_with_hierarchy(&self, role_id: &str) -> Option<HashSet<String>> {
526        let mut permissions = HashSet::new();
527        let mut visited = HashSet::new();
528        
529        self.collect_role_permissions(role_id, &mut permissions, &mut visited);
530        
531        if permissions.is_empty() {
532            None
533        } else {
534            Some(permissions)
535        }
536    }
537    
538    /// Recursively collect permissions from role hierarchy
539    fn collect_role_permissions(&self, role_id: &str, permissions: &mut HashSet<String>, visited: &mut HashSet<String>) {
540        if visited.contains(role_id) {
541            return; // Prevent infinite loops
542        }
543        visited.insert(role_id.to_string());
544        
545        if let Some(role) = self.roles.get(role_id) {
546            permissions.extend(role.permissions.iter().cloned());
547            
548            // Collect permissions from parent roles
549            if let Some(parent_roles) = self.role_hierarchy.hierarchy.get(role_id) {
550                for parent_role in parent_roles {
551                    self.collect_role_permissions(parent_role, permissions, visited);
552                }
553            }
554        }
555    }
556    
557    /// Generate session token
558    fn generate_session_token(&self, user_id: &str) -> String {
559        use std::collections::hash_map::DefaultHasher;
560        use std::hash::{Hash, Hasher};
561        
562        let mut hasher = DefaultHasher::new();
563        user_id.hash(&mut hasher);
564        Utc::now().timestamp_nanos_opt().unwrap_or_default().hash(&mut hasher);
565        
566        format!("eventuali_token_{:x}", hasher.finish())
567    }
568    
569    /// Get session by token
570    fn get_session_by_token(&self, token: &str) -> Option<&Session> {
571        self.sessions.values().find(|session| session.token == token)
572    }
573    
574    /// Verify password (simplified for example)
575    fn verify_password(&self, _password: &str) -> bool {
576        // In production, use proper password hashing (bcrypt, scrypt, argon2)
577        true
578    }
579    
580    /// Audit access attempt
581    fn audit_access(
582        &mut self,
583        user_id: Option<&str>,
584        resource: &str,
585        action: &str,
586        decision: AccessDecision,
587        context: Option<HashMap<String, String>>,
588    ) {
589        self.audit_log.push(AuditEntry {
590            audit_id: Uuid::new_v4().to_string(),
591            user_id: user_id.unwrap_or("unknown").to_string(),
592            action: format!("{resource}:{action}"),
593            resource: resource.to_string(),
594            resource_id: None,
595            decision,
596            timestamp: Utc::now(),
597            ip_address: None,
598            session_id: None,
599            reason: None,
600            metadata: context.unwrap_or_default(),
601        });
602    }
603    
604    /// Get audit trail
605    pub fn get_audit_trail(&self, limit: Option<usize>) -> Vec<&AuditEntry> {
606        let limit = limit.unwrap_or(100);
607        self.audit_log.iter().rev().take(limit).collect()
608    }
609    
610    /// Revoke session
611    pub fn revoke_session(&mut self, token: &str) -> Result<()> {
612        if let Some(session) = self.sessions.values_mut().find(|s| s.token == token) {
613            session.is_active = false;
614            
615            self.audit_log.push(AuditEntry {
616                audit_id: Uuid::new_v4().to_string(),
617                user_id: session.user_id.clone(),
618                action: "session:revoke".to_string(),
619                resource: "session".to_string(),
620                resource_id: Some(session.session_id.clone()),
621                decision: AccessDecision::Allow,
622                timestamp: Utc::now(),
623                ip_address: None,
624                session_id: Some(session.session_id.clone()),
625                reason: Some("Session revoked".to_string()),
626                metadata: HashMap::new(),
627            });
628            
629            Ok(())
630        } else {
631            Err(EventualiError::Validation("Session not found".to_string()))
632        }
633    }
634    
635    /// Clean up expired sessions
636    pub fn cleanup_expired_sessions(&mut self) {
637        let now = Utc::now();
638        let expired_sessions: Vec<String> = self.sessions
639            .iter()
640            .filter(|(_, session)| session.expires_at < now)
641            .map(|(id, _)| id.clone())
642            .collect();
643        
644        for session_id in expired_sessions {
645            self.sessions.remove(&session_id);
646        }
647    }
648    
649    /// Get system statistics
650    pub fn get_system_stats(&self) -> HashMap<String, serde_json::Value> {
651        let mut stats = HashMap::new();
652        
653        stats.insert("total_users".to_string(), serde_json::Value::Number(self.users.len().into()));
654        stats.insert("active_users".to_string(), serde_json::Value::Number(
655            self.users.values().filter(|u| u.is_active).count().into()
656        ));
657        stats.insert("total_roles".to_string(), serde_json::Value::Number(self.roles.len().into()));
658        stats.insert("total_permissions".to_string(), serde_json::Value::Number(self.permissions.len().into()));
659        stats.insert("active_sessions".to_string(), serde_json::Value::Number(
660            self.sessions.values().filter(|s| s.is_active && s.expires_at > Utc::now()).count().into()
661        ));
662        stats.insert("audit_entries".to_string(), serde_json::Value::Number(self.audit_log.len().into()));
663        
664        stats
665    }
666}
667
668impl RoleHierarchy {
669    fn new() -> Self {
670        Self {
671            hierarchy: HashMap::new(),
672        }
673    }
674    
675    fn add_parent(&mut self, child_role: &str, parent_role: &str) {
676        self.hierarchy
677            .entry(child_role.to_string())
678            .or_default()
679            .insert(parent_role.to_string());
680    }
681}
682
683impl PolicyEngine {
684    fn new() -> Self {
685        Self {
686            policies: HashMap::new(),
687        }
688    }
689}
690
691impl SecurityLevel {
692    pub fn level_value(&self) -> u8 {
693        match self {
694            SecurityLevel::Public => 0,
695            SecurityLevel::Internal => 1,
696            SecurityLevel::Confidential => 2,
697            SecurityLevel::Secret => 3,
698            SecurityLevel::TopSecret => 4,
699        }
700    }
701    
702    pub fn can_access(&self, required_level: &SecurityLevel) -> bool {
703        self.level_value() >= required_level.level_value()
704    }
705}
706
707impl Default for RbacManager {
708    fn default() -> Self {
709        Self::new()
710    }
711}
712
713#[cfg(test)]
714mod tests {
715    use super::*;
716
717    #[test]
718    fn test_rbac_initialization() {
719        let rbac = RbacManager::new();
720        assert_eq!(rbac.roles.len(), 4); // 4 system roles
721        assert!(rbac.roles.contains_key("system:admin"));
722        assert!(rbac.roles.contains_key("system:manager"));
723        assert!(rbac.roles.contains_key("system:employee"));
724        assert!(rbac.roles.contains_key("system:guest"));
725    }
726
727    #[test]
728    fn test_user_creation() {
729        let mut rbac = RbacManager::new();
730        let user_id = rbac.create_user(
731            "test_user".to_string(),
732            "test@example.com".to_string(),
733            SecurityLevel::Internal,
734        ).unwrap();
735        
736        assert!(rbac.users.contains_key(&user_id));
737        let user = rbac.users.get(&user_id).unwrap();
738        assert_eq!(user.username, "test_user");
739        assert_eq!(user.email, "test@example.com");
740        assert_eq!(user.security_level, SecurityLevel::Internal);
741    }
742
743    #[test]
744    fn test_role_assignment() {
745        let mut rbac = RbacManager::new();
746        let user_id = rbac.create_user(
747            "test_user".to_string(),
748            "test@example.com".to_string(),
749            SecurityLevel::Internal,
750        ).unwrap();
751        
752        rbac.assign_role_to_user(&user_id, "system:manager").unwrap();
753        
754        let user = rbac.users.get(&user_id).unwrap();
755        assert!(user.roles.contains("system:manager"));
756    }
757
758    #[test]
759    fn test_permission_inheritance() {
760        let mut rbac = RbacManager::new();
761        let user_id = rbac.create_user(
762            "admin_user".to_string(),
763            "admin@example.com".to_string(),
764            SecurityLevel::Secret,
765        ).unwrap();
766        
767        rbac.assign_role_to_user(&user_id, "system:admin").unwrap();
768        
769        let permissions = rbac.get_effective_permissions(&user_id).unwrap();
770        assert!(permissions.contains("system:admin"));
771        assert!(permissions.contains("events:read"));
772        assert!(permissions.contains("events:write"));
773    }
774
775    #[test]
776    fn test_authentication_flow() {
777        let mut rbac = RbacManager::new();
778        let user_id = rbac.create_user(
779            "auth_user".to_string(),
780            "auth@example.com".to_string(),
781            SecurityLevel::Internal,
782        ).unwrap();
783        
784        rbac.assign_role_to_user(&user_id, "system:employee").unwrap();
785        
786        let token = rbac.authenticate("auth_user", "password", Some("192.168.1.1".to_string())).unwrap();
787        assert!(!token.is_empty());
788        
789        // Test access
790        let decision = rbac.check_access(&token, "events", "read", None);
791        assert!(matches!(decision, AccessDecision::Allow));
792        
793        let decision = rbac.check_access(&token, "events", "delete", None);
794        assert!(matches!(decision, AccessDecision::DenyWithReason(_)));
795    }
796
797    #[test]
798    fn test_security_levels() {
799        assert!(SecurityLevel::Secret.can_access(&SecurityLevel::Internal));
800        assert!(!SecurityLevel::Internal.can_access(&SecurityLevel::Secret));
801        assert!(SecurityLevel::TopSecret.can_access(&SecurityLevel::Public));
802    }
803}