1use crate::security::{
11 emit_security_event_async,
12 events::{EventActor, EventOutcome, EventTarget, SecurityEvent, SecurityEventType},
13 justification_storage::{AccessJustification, JustificationStorage},
14 mfa_tracking::MfaStorage,
15};
16use crate::Error;
17use chrono::{DateTime, Duration, Utc};
18use serde::{Deserialize, Serialize};
19use serde_json;
20use std::collections::HashMap;
21use uuid::Uuid;
22
23#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash, Serialize, Deserialize)]
25#[serde(rename_all = "lowercase")]
26pub enum PrivilegedRole {
27 Admin,
29 Owner,
31 ServiceAccount,
33}
34
35#[derive(Debug, Clone, Copy, PartialEq, Eq, Serialize, Deserialize)]
37#[serde(rename_all = "lowercase")]
38pub enum RequestStatus {
39 PendingManager,
41 PendingSecurity,
43 Approved,
45 Denied,
47 Cancelled,
49}
50
51#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash, Serialize, Deserialize)]
53#[cfg_attr(feature = "schema", derive(schemars::JsonSchema))]
54#[serde(rename_all = "snake_case")]
55pub enum PrivilegedActionType {
56 UserCreate,
58 UserDelete,
60 UserModify,
62 RoleAssign,
64 RoleRevoke,
66 RoleEscalate,
68 PermissionGrant,
70 PermissionRevoke,
72 ConfigModify,
74 SecurityPolicyChange,
76 SecuritySettingChange,
78 AuditLogAccess,
80 DataExport,
82 DataDelete,
84 Other,
86}
87
88#[derive(Debug, Clone, Serialize, Deserialize)]
90pub struct PrivilegedAccessRequest {
91 pub request_id: Uuid,
93 pub user_id: Uuid,
95 pub requested_role: PrivilegedRole,
97 pub justification: String,
99 pub business_need: Option<String>,
101 pub manager_approval: Option<Uuid>,
103 pub security_approval: Option<Uuid>,
105 pub status: RequestStatus,
107 pub created_at: DateTime<Utc>,
109 pub updated_at: DateTime<Utc>,
111 pub expires_at: Option<DateTime<Utc>>,
113}
114
115impl PrivilegedAccessRequest {
116 pub fn new(
118 user_id: Uuid,
119 requested_role: PrivilegedRole,
120 justification: String,
121 business_need: Option<String>,
122 manager_approval: Option<Uuid>,
123 ) -> Self {
124 let now = Utc::now();
125 Self {
126 request_id: Uuid::new_v4(),
127 user_id,
128 requested_role,
129 justification,
130 business_need,
131 manager_approval,
132 security_approval: None,
133 status: RequestStatus::PendingManager,
134 created_at: now,
135 updated_at: now,
136 expires_at: None,
137 }
138 }
139
140 pub fn is_approved(&self) -> bool {
142 self.status == RequestStatus::Approved
143 }
144
145 pub fn is_expired(&self) -> bool {
147 self.expires_at.map(|exp| Utc::now() > exp).unwrap_or(false)
148 }
149}
150
151#[derive(Debug, Clone, Serialize, Deserialize)]
153pub struct PrivilegedAction {
154 pub action_id: Uuid,
156 pub user_id: Uuid,
158 pub action_type: PrivilegedActionType,
160 pub resource: Option<String>,
162 pub details: Option<String>,
164 pub ip_address: Option<String>,
166 pub user_agent: Option<String>,
168 pub session_id: Option<String>,
170 pub timestamp: DateTime<Utc>,
172}
173
174#[derive(Debug, Clone, Serialize, Deserialize)]
176pub struct PrivilegedSession {
177 pub session_id: String,
179 pub user_id: Uuid,
181 pub role: PrivilegedRole,
183 pub started_at: DateTime<Utc>,
185 pub last_activity: DateTime<Utc>,
187 pub ip_address: Option<String>,
189 pub user_agent: Option<String>,
191 pub is_active: bool,
193}
194
195#[derive(Debug, Clone, Serialize, Deserialize)]
197#[cfg_attr(feature = "schema", derive(schemars::JsonSchema))]
198pub struct PrivilegedAccessConfig {
199 pub require_mfa: bool,
201 pub mfa_grace_period_days: u64,
203 pub auto_suspend_no_mfa: bool,
205 pub session_timeout_minutes: u64,
207 pub max_concurrent_sessions: u32,
209 pub record_sensitive_actions: bool,
211 pub monitor_activity: bool,
213 pub sensitive_actions: Vec<PrivilegedActionType>,
215}
216
217impl Default for PrivilegedAccessConfig {
218 fn default() -> Self {
219 Self {
220 require_mfa: true,
221 mfa_grace_period_days: 7,
222 auto_suspend_no_mfa: true,
223 session_timeout_minutes: 30,
224 max_concurrent_sessions: 2,
225 record_sensitive_actions: true,
226 monitor_activity: true,
227 sensitive_actions: vec![
228 PrivilegedActionType::UserDelete,
229 PrivilegedActionType::RoleEscalate,
230 PrivilegedActionType::SecurityPolicyChange,
231 PrivilegedActionType::DataExport,
232 PrivilegedActionType::AuditLogAccess,
233 ],
234 }
235 }
236}
237
238pub struct PrivilegedAccessManager {
242 config: PrivilegedAccessConfig,
243 mfa_storage: Option<Arc<dyn MfaStorage>>,
244 justification_storage: Option<Arc<dyn JustificationStorage>>,
245 sessions: Arc<RwLock<HashMap<String, PrivilegedSession>>>,
247 actions: Arc<RwLock<Vec<PrivilegedAction>>>,
249 requests: Arc<RwLock<HashMap<Uuid, PrivilegedAccessRequest>>>,
251}
252
253impl PrivilegedAccessManager {
254 pub fn new(
256 config: PrivilegedAccessConfig,
257 mfa_storage: Option<Arc<dyn MfaStorage>>,
258 justification_storage: Option<Arc<dyn JustificationStorage>>,
259 ) -> Self {
260 Self {
261 config,
262 mfa_storage,
263 justification_storage,
264 sessions: Arc::new(RwLock::new(HashMap::new())),
265 actions: Arc::new(RwLock::new(Vec::new())),
266 requests: Arc::new(RwLock::new(HashMap::new())),
267 }
268 }
269
270 pub async fn request_privileged_access(
272 &self,
273 user_id: Uuid,
274 requested_role: PrivilegedRole,
275 justification: String,
276 business_need: Option<String>,
277 manager_approval: Option<Uuid>,
278 ) -> Result<PrivilegedAccessRequest, Error> {
279 let request = PrivilegedAccessRequest::new(
280 user_id,
281 requested_role,
282 justification,
283 business_need,
284 manager_approval,
285 );
286
287 let mut requests = self.requests.write().await;
288 requests.insert(request.request_id, request.clone());
289
290 Ok(request)
291 }
292
293 pub async fn approve_manager(&self, request_id: Uuid, approver_id: Uuid) -> Result<(), Error> {
295 let mut requests = self.requests.write().await;
296 let request = requests
297 .get_mut(&request_id)
298 .ok_or_else(|| Error::Generic("Request not found".to_string()))?;
299
300 if request.status != RequestStatus::PendingManager {
301 return Err(Error::Generic("Request is not pending manager approval".to_string()));
302 }
303
304 let user_id = request.user_id;
305 request.manager_approval = Some(approver_id);
306 request.status = RequestStatus::PendingSecurity;
307 request.updated_at = Utc::now();
308
309 let event = SecurityEvent::new(SecurityEventType::AuthzPrivilegeEscalation, None, None)
311 .with_actor(EventActor {
312 user_id: Some(approver_id.to_string()),
313 username: None,
314 ip_address: None,
315 user_agent: None,
316 })
317 .with_target(EventTarget {
318 resource_type: Some("privileged_access_request".to_string()),
319 resource_id: Some(request_id.to_string()),
320 method: None,
321 })
322 .with_outcome(EventOutcome {
323 success: true,
324 reason: Some("Manager approval granted".to_string()),
325 })
326 .with_metadata("request_user_id".to_string(), serde_json::json!(user_id.to_string()))
327 .with_metadata(
328 "requested_role".to_string(),
329 serde_json::json!(format!("{:?}", request.requested_role)),
330 );
331
332 emit_security_event_async(event);
333
334 Ok(())
335 }
336
337 pub async fn approve_security(
339 &self,
340 request_id: Uuid,
341 approver_id: Uuid,
342 expiration_days: u64,
343 ) -> Result<(), Error> {
344 let mut requests = self.requests.write().await;
345 let request = requests
346 .get_mut(&request_id)
347 .ok_or_else(|| Error::Generic("Request not found".to_string()))?;
348
349 if request.status != RequestStatus::PendingSecurity {
350 return Err(Error::Generic("Request is not pending security approval".to_string()));
351 }
352
353 request.security_approval = Some(approver_id);
354 request.status = RequestStatus::Approved;
355 request.expires_at = Some(Utc::now() + Duration::days(expiration_days as i64));
356 request.updated_at = Utc::now();
357
358 if let Some(ref just_storage) = self.justification_storage {
360 let justification = AccessJustification::new(
361 request.user_id,
362 request.justification.clone(),
363 request.business_need.clone(),
364 request.manager_approval,
365 request.expires_at,
366 );
367 just_storage.set_justification(justification).await?;
368 }
369
370 let event = SecurityEvent::new(SecurityEventType::AuthzPrivilegeEscalation, None, None)
372 .with_actor(EventActor {
373 user_id: Some(approver_id.to_string()),
374 username: None,
375 ip_address: None,
376 user_agent: None,
377 })
378 .with_target(EventTarget {
379 resource_type: Some("privileged_access_request".to_string()),
380 resource_id: Some(request_id.to_string()),
381 method: None,
382 })
383 .with_outcome(EventOutcome {
384 success: true,
385 reason: Some("Security approval granted".to_string()),
386 })
387 .with_metadata(
388 "request_user_id".to_string(),
389 serde_json::json!(request.user_id.to_string()),
390 )
391 .with_metadata(
392 "requested_role".to_string(),
393 serde_json::json!(format!("{:?}", request.requested_role)),
394 )
395 .with_metadata("expiration_days".to_string(), serde_json::json!(expiration_days));
396
397 emit_security_event_async(event);
398
399 Ok(())
400 }
401
402 pub async fn deny_request(&self, request_id: Uuid, reason: String) -> Result<(), Error> {
404 let mut requests = self.requests.write().await;
405 let request = requests
406 .get_mut(&request_id)
407 .ok_or_else(|| Error::Generic("Request not found".to_string()))?;
408
409 let user_id = request.user_id;
410 request.status = RequestStatus::Denied;
411 request.updated_at = Utc::now();
412
413 let event = SecurityEvent::new(SecurityEventType::AuthzAccessDenied, None, None)
415 .with_actor(EventActor {
416 user_id: Some(user_id.to_string()),
417 username: None,
418 ip_address: None,
419 user_agent: None,
420 })
421 .with_target(EventTarget {
422 resource_type: Some("privileged_access_request".to_string()),
423 resource_id: Some(request_id.to_string()),
424 method: None,
425 })
426 .with_outcome(EventOutcome {
427 success: false,
428 reason: Some(reason.clone()),
429 })
430 .with_metadata(
431 "requested_role".to_string(),
432 serde_json::json!(format!("{:?}", request.requested_role)),
433 );
434
435 emit_security_event_async(event);
436
437 Ok(())
438 }
439
440 pub async fn check_mfa_compliance(&self, user_id: Uuid) -> Result<bool, Error> {
442 if !self.config.require_mfa {
443 return Ok(true);
444 }
445
446 if let Some(ref mfa_storage) = self.mfa_storage {
447 let mfa_status = mfa_storage.get_mfa_status(user_id).await?;
448 Ok(mfa_status.map(|s| s.enabled).unwrap_or(false))
449 } else {
450 Ok(true)
452 }
453 }
454
455 pub async fn record_action(
457 &self,
458 user_id: Uuid,
459 action_type: PrivilegedActionType,
460 resource: Option<String>,
461 details: Option<String>,
462 ip_address: Option<String>,
463 user_agent: Option<String>,
464 session_id: Option<String>,
465 ) -> Result<Uuid, Error> {
466 let action = PrivilegedAction {
467 action_id: Uuid::new_v4(),
468 user_id,
469 action_type,
470 resource,
471 details,
472 ip_address,
473 user_agent,
474 session_id,
475 timestamp: Utc::now(),
476 };
477
478 let mut actions = self.actions.write().await;
479 actions.push(action.clone());
480
481 let event_type = if self.config.sensitive_actions.contains(&action_type) {
484 SecurityEventType::AuthzPrivilegeEscalation
485 } else {
486 SecurityEventType::AuthzAccessGranted
487 };
488
489 let event = SecurityEvent::new(event_type, None, None)
490 .with_actor(EventActor {
491 user_id: Some(action.user_id.to_string()),
492 username: None,
493 ip_address: action.ip_address.clone(),
494 user_agent: action.user_agent.clone(),
495 })
496 .with_target(EventTarget {
497 resource_type: Some(format!("privileged_action_{:?}", action_type)),
498 resource_id: Some(action.action_id.to_string()),
499 method: action.resource.clone(),
500 })
501 .with_outcome(EventOutcome {
502 success: true,
503 reason: action.details.clone(),
504 })
505 .with_metadata(
506 "action_type".to_string(),
507 serde_json::json!(format!("{:?}", action_type)),
508 )
509 .with_metadata(
510 "session_id".to_string(),
511 serde_json::json!(action.session_id.clone().unwrap_or_default()),
512 );
513
514 emit_security_event_async(event);
516
517 Ok(action.action_id)
518 }
519
520 pub async fn start_session(
522 &self,
523 session_id: String,
524 user_id: Uuid,
525 role: PrivilegedRole,
526 ip_address: Option<String>,
527 user_agent: Option<String>,
528 ) -> Result<(), Error> {
529 if !self.check_mfa_compliance(user_id).await? && self.config.auto_suspend_no_mfa {
531 return Err(Error::Generic("MFA not enabled for privileged user".to_string()));
532 }
533
534 let sessions = self.sessions.read().await;
536 let active_sessions =
537 sessions.values().filter(|s| s.user_id == user_id && s.is_active).count();
538
539 if active_sessions >= self.config.max_concurrent_sessions as usize {
540 return Err(Error::Generic("Maximum concurrent sessions reached".to_string()));
541 }
542 drop(sessions);
543
544 let ip_address_clone = ip_address.clone();
546 let user_agent_clone = user_agent.clone();
547
548 let session = PrivilegedSession {
549 session_id: session_id.clone(),
550 user_id,
551 role,
552 started_at: Utc::now(),
553 last_activity: Utc::now(),
554 ip_address,
555 user_agent,
556 is_active: true,
557 };
558
559 let mut sessions = self.sessions.write().await;
560 sessions.insert(session_id.clone(), session);
561
562 let event = SecurityEvent::new(SecurityEventType::AuthzPrivilegeEscalation, None, None)
564 .with_actor(EventActor {
565 user_id: Some(user_id.to_string()),
566 username: None,
567 ip_address: ip_address_clone,
568 user_agent: user_agent_clone,
569 })
570 .with_target(EventTarget {
571 resource_type: Some("privileged_session".to_string()),
572 resource_id: Some(session_id.clone()),
573 method: Some(format!("{:?}", role)),
574 })
575 .with_outcome(EventOutcome {
576 success: true,
577 reason: Some("Privileged session started".to_string()),
578 })
579 .with_metadata("role".to_string(), serde_json::json!(format!("{:?}", role)));
580
581 emit_security_event_async(event);
582
583 Ok(())
584 }
585
586 pub async fn update_session_activity(&self, session_id: &str) -> Result<(), Error> {
588 let mut sessions = self.sessions.write().await;
589 if let Some(session) = sessions.get_mut(session_id) {
590 session.last_activity = Utc::now();
591 }
592 Ok(())
593 }
594
595 pub async fn end_session(&self, session_id: &str) -> Result<(), Error> {
597 let mut sessions = self.sessions.write().await;
598 if let Some(session) = sessions.get_mut(session_id) {
599 let user_id = session.user_id;
600 let role = session.role;
601 session.is_active = false;
602
603 let event = SecurityEvent::new(SecurityEventType::AuthzAccessGranted, None, None)
605 .with_actor(EventActor {
606 user_id: Some(user_id.to_string()),
607 username: None,
608 ip_address: session.ip_address.clone(),
609 user_agent: session.user_agent.clone(),
610 })
611 .with_target(EventTarget {
612 resource_type: Some("privileged_session".to_string()),
613 resource_id: Some(session_id.to_string()),
614 method: Some(format!("{:?}", role)),
615 })
616 .with_outcome(EventOutcome {
617 success: true,
618 reason: Some("Privileged session ended".to_string()),
619 })
620 .with_metadata("role".to_string(), serde_json::json!(format!("{:?}", role)))
621 .with_metadata(
622 "duration_seconds".to_string(),
623 serde_json::json!((Utc::now() - session.started_at).num_seconds()),
624 );
625
626 emit_security_event_async(event);
627 }
628 Ok(())
629 }
630
631 pub async fn cleanup_expired_sessions(&self) -> Result<Vec<String>, Error> {
633 let timeout = Duration::minutes(self.config.session_timeout_minutes as i64);
634 let now = Utc::now();
635 let mut expired = Vec::new();
636
637 let mut sessions = self.sessions.write().await;
638 for (session_id, session) in sessions.iter_mut() {
639 if session.is_active && (now - session.last_activity) > timeout {
640 session.is_active = false;
641 expired.push(session_id.clone());
642 }
643 }
644
645 Ok(expired)
646 }
647
648 pub async fn get_user_actions(&self, user_id: Uuid) -> Result<Vec<PrivilegedAction>, Error> {
650 let actions = self.actions.read().await;
651 Ok(actions.iter().filter(|a| a.user_id == user_id).cloned().collect())
652 }
653
654 pub async fn get_active_sessions(&self) -> Result<Vec<PrivilegedSession>, Error> {
656 let sessions = self.sessions.read().await;
657 Ok(sessions.values().filter(|s| s.is_active).cloned().collect())
658 }
659
660 pub async fn get_request(
662 &self,
663 request_id: Uuid,
664 ) -> Result<Option<PrivilegedAccessRequest>, Error> {
665 let requests = self.requests.read().await;
666 Ok(requests.get(&request_id).cloned())
667 }
668
669 pub async fn get_user_requests(
671 &self,
672 user_id: Uuid,
673 ) -> Result<Vec<PrivilegedAccessRequest>, Error> {
674 let requests = self.requests.read().await;
675 Ok(requests.values().filter(|r| r.user_id == user_id).cloned().collect())
676 }
677}
678
679use std::sync::Arc;
681use tokio::sync::RwLock;
682
683#[cfg(test)]
684mod tests {
685 use super::*;
686
687 #[tokio::test]
688 async fn test_privileged_access_request() {
689 let manager = PrivilegedAccessManager::new(PrivilegedAccessConfig::default(), None, None);
690
691 let request = manager
692 .request_privileged_access(
693 Uuid::new_v4(),
694 PrivilegedRole::Admin,
695 "Required for system administration".to_string(),
696 Some("Manage production infrastructure".to_string()),
697 Some(Uuid::new_v4()),
698 )
699 .await
700 .unwrap();
701
702 assert_eq!(request.status, RequestStatus::PendingManager);
703 assert!(request.manager_approval.is_some());
704 }
705}