1use crate::{EventualiError, Result};
2use serde::{Deserialize, Serialize};
3use std::collections::{HashMap, HashSet};
4use chrono::{DateTime, Utc, Duration};
5use uuid::Uuid;
6
7pub 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: PolicyEngine,
17}
18
19#[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#[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#[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#[derive(Debug, Clone, Serialize, Deserialize, PartialEq, Eq, Hash)]
60pub enum SecurityLevel {
61 Public,
62 Internal,
63 Confidential,
64 Secret,
65 TopSecret,
66}
67
68#[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#[derive(Debug, Clone, Serialize, Deserialize)]
84pub enum AccessDecision {
85 Allow,
86 Deny,
87 DenyWithReason(String),
88}
89
90#[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
106pub struct RoleHierarchy {
108 hierarchy: HashMap<String, HashSet<String>>, }
110
111pub struct PolicyEngine {
113 #[allow(dead_code)] policies: HashMap<String, AccessPolicy>,
115}
116
117#[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#[derive(Debug, Clone, Serialize, Deserialize)]
130pub struct PolicyCondition {
131 pub attribute: String,
132 pub operator: String,
133 pub value: String,
134}
135
136#[derive(Debug, Clone, Serialize, Deserialize)]
138pub enum PolicyEffect {
139 Allow,
140 Deny,
141}
142
143impl RbacManager {
144 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 fn initialize_system_roles(&mut self) {
162 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 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 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 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 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 self.initialize_system_permissions();
223 }
224
225 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 self.assign_permission_to_role("system:guest", "projections:read").unwrap();
258
259 self.assign_permission_to_role("system:employee", "events:read").unwrap();
261 self.assign_permission_to_role("system:employee", "aggregates:read").unwrap();
262
263 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 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 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 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 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 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 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 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 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 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 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 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 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 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 fn collect_role_permissions(&self, role_id: &str, permissions: &mut HashSet<String>, visited: &mut HashSet<String>) {
540 if visited.contains(role_id) {
541 return; }
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 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 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 fn get_session_by_token(&self, token: &str) -> Option<&Session> {
571 self.sessions.values().find(|session| session.token == token)
572 }
573
574 fn verify_password(&self, _password: &str) -> bool {
576 true
578 }
579
580 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 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 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 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 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); 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 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}