1use crate::{
7 AuthContext,
8 security::{SecuritySeverity, SecurityViolation, SecurityViolationType},
9 session::Session,
10};
11use serde::{Deserialize, Serialize};
12use std::collections::{HashMap, VecDeque};
13use std::sync::Arc;
14use thiserror::Error;
15use tokio::sync::RwLock;
16use tracing::{debug, error, info, warn};
17use uuid::Uuid;
18
19#[derive(Debug, Error)]
21pub enum MonitoringError {
22 #[error("Alert not found: {alert_id}")]
23 AlertNotFound { alert_id: String },
24
25 #[error("Metric not found: {metric_name}")]
26 MetricNotFound { metric_name: String },
27
28 #[error("Configuration error: {reason}")]
29 ConfigError { reason: String },
30
31 #[error("Storage error: {0}")]
32 StorageError(String),
33
34 #[error("Serialization error: {0}")]
35 SerializationError(String),
36}
37
38#[derive(Debug, Clone, PartialEq, Eq, Hash, Serialize, Deserialize)]
40pub enum SecurityEventType {
41 AuthSuccess,
43 AuthFailure,
44 InvalidApiKey,
45 ExpiredToken,
46
47 SessionCreated,
49 SessionExpired,
50 SessionTerminated,
51 MaxSessionsExceeded,
52
53 InjectionAttempt,
55 SizeLimit,
56 RateLimit,
57 UnauthorizedAccess,
58
59 PermissionDenied,
61 RoleEscalation,
62
63 SystemError,
65 ConfigChange,
66}
67
68#[derive(Debug, Clone, Serialize, Deserialize)]
70pub struct SecurityEvent {
71 pub event_id: String,
73
74 pub event_type: SecurityEventType,
76
77 pub severity: SecuritySeverity,
79
80 pub timestamp: chrono::DateTime<chrono::Utc>,
82
83 pub user_id: Option<String>,
85 pub session_id: Option<String>,
86 pub api_key_id: Option<String>,
87
88 pub client_ip: Option<String>,
90 pub user_agent: Option<String>,
91 pub method: Option<String>,
92
93 pub description: String,
95 pub metadata: HashMap<String, String>,
96
97 pub country: Option<String>,
99 pub city: Option<String>,
100}
101
102impl SecurityEvent {
103 pub fn new(
105 event_type: SecurityEventType,
106 severity: SecuritySeverity,
107 description: String,
108 ) -> Self {
109 Self {
110 event_id: Uuid::new_v4().to_string(),
111 event_type,
112 severity,
113 timestamp: chrono::Utc::now(),
114 user_id: None,
115 session_id: None,
116 api_key_id: None,
117 client_ip: None,
118 user_agent: None,
119 method: None,
120 description,
121 metadata: HashMap::new(),
122 country: None,
123 city: None,
124 }
125 }
126
127 pub fn with_user_context(mut self, auth_context: &AuthContext) -> Self {
129 self.user_id = auth_context.user_id.clone();
130 self.api_key_id = auth_context.api_key_id.clone();
131 self
132 }
133
134 pub fn with_session_context(mut self, session: &Session) -> Self {
136 self.session_id = Some(session.session_id.clone());
137 self.user_id = Some(session.user_id.clone());
138 self.client_ip = session.client_ip.clone();
139 self.user_agent = session.user_agent.clone();
140 self
141 }
142
143 pub fn with_request_context(
145 mut self,
146 client_ip: Option<String>,
147 user_agent: Option<String>,
148 method: Option<String>,
149 ) -> Self {
150 self.client_ip = client_ip;
151 self.user_agent = user_agent;
152 self.method = method;
153 self
154 }
155
156 pub fn with_metadata(mut self, key: String, value: String) -> Self {
158 self.metadata.insert(key, value);
159 self
160 }
161}
162
163#[derive(Debug, Clone, Serialize, Deserialize)]
165pub struct SecurityMetrics {
166 pub period_start: chrono::DateTime<chrono::Utc>,
168 pub period_end: chrono::DateTime<chrono::Utc>,
169
170 pub auth_success_count: u64,
172 pub auth_failure_count: u64,
173 pub invalid_api_key_count: u64,
174 pub expired_token_count: u64,
175
176 pub sessions_created: u64,
178 pub sessions_expired: u64,
179 pub sessions_terminated: u64,
180 pub active_sessions: u64,
181
182 pub injection_attempts: u64,
184 pub size_limit_violations: u64,
185 pub rate_limit_violations: u64,
186 pub unauthorized_access_attempts: u64,
187
188 pub permission_denied_count: u64,
190 pub role_escalation_attempts: u64,
191
192 pub top_source_ips: Vec<(String, u64)>,
194
195 pub top_user_agents: Vec<(String, u64)>,
197
198 pub top_methods: Vec<(String, u64)>,
200
201 pub country_distribution: HashMap<String, u64>,
203}
204
205impl Default for SecurityMetrics {
206 fn default() -> Self {
207 let now = chrono::Utc::now();
208 Self {
209 period_start: now,
210 period_end: now,
211 auth_success_count: 0,
212 auth_failure_count: 0,
213 invalid_api_key_count: 0,
214 expired_token_count: 0,
215 sessions_created: 0,
216 sessions_expired: 0,
217 sessions_terminated: 0,
218 active_sessions: 0,
219 injection_attempts: 0,
220 size_limit_violations: 0,
221 rate_limit_violations: 0,
222 unauthorized_access_attempts: 0,
223 permission_denied_count: 0,
224 role_escalation_attempts: 0,
225 top_source_ips: Vec::new(),
226 top_user_agents: Vec::new(),
227 top_methods: Vec::new(),
228 country_distribution: HashMap::new(),
229 }
230 }
231}
232
233#[derive(Debug, Clone, Serialize, Deserialize)]
235pub struct AlertRule {
236 pub rule_id: String,
238
239 pub name: String,
241
242 pub description: String,
244
245 pub event_types: Vec<SecurityEventType>,
247
248 pub min_severity: SecuritySeverity,
250
251 pub threshold: AlertThreshold,
253
254 pub time_window: chrono::Duration,
256
257 pub cooldown: chrono::Duration,
259
260 pub enabled: bool,
262
263 pub actions: Vec<AlertAction>,
265}
266
267#[derive(Debug, Clone, Serialize, Deserialize)]
269pub enum AlertThreshold {
270 Count(u64),
272
273 Rate {
275 count: u64,
276 duration: chrono::Duration,
277 },
278
279 Percentage {
281 numerator_events: Vec<SecurityEventType>,
282 denominator_events: Vec<SecurityEventType>,
283 threshold: f64,
284 },
285}
286
287#[derive(Debug, Clone, Serialize, Deserialize)]
289pub enum AlertAction {
290 Log { level: String },
292
293 Email { recipients: Vec<String> },
295
296 Webhook {
298 url: String,
299 payload_template: String,
300 },
301
302 BlockIp { duration: chrono::Duration },
304
305 DisableUser { user_id: String },
307
308 RateLimit {
310 user_id: String,
311 limit: u32,
312 duration: chrono::Duration,
313 },
314}
315
316#[derive(Debug, Clone, Serialize, Deserialize)]
318pub struct SecurityAlert {
319 pub alert_id: String,
321
322 pub rule_id: String,
324
325 pub rule_name: String,
327
328 pub triggered_at: chrono::DateTime<chrono::Utc>,
330
331 pub resolved_at: Option<chrono::DateTime<chrono::Utc>>,
333
334 pub severity: SecuritySeverity,
336
337 pub description: String,
339
340 pub triggering_events: Vec<String>, pub metadata: HashMap<String, String>,
345
346 pub actions_taken: Vec<String>,
348}
349
350#[derive(Debug, Clone)]
352pub struct SecurityMonitorConfig {
353 pub max_events_in_memory: usize,
355
356 pub max_alerts_in_memory: usize,
358
359 pub event_retention: chrono::Duration,
361
362 pub alert_retention: chrono::Duration,
364
365 pub metrics_interval: chrono::Duration,
367
368 pub enable_geolocation: bool,
370
371 pub enable_realtime: bool,
373
374 pub enable_alerts: bool,
376}
377
378impl Default for SecurityMonitorConfig {
379 fn default() -> Self {
380 Self {
381 max_events_in_memory: 10000,
382 max_alerts_in_memory: 1000,
383 event_retention: chrono::Duration::days(7),
384 alert_retention: chrono::Duration::days(30),
385 metrics_interval: chrono::Duration::minutes(5),
386 enable_geolocation: false,
387 enable_realtime: true,
388 enable_alerts: true,
389 }
390 }
391}
392
393pub struct SecurityMonitor {
395 config: SecurityMonitorConfig,
396 events: Arc<RwLock<VecDeque<SecurityEvent>>>,
397 alerts: Arc<RwLock<Vec<SecurityAlert>>>,
398 alert_rules: Arc<RwLock<Vec<AlertRule>>>,
399 metrics_cache: Arc<RwLock<HashMap<String, SecurityMetrics>>>,
400 last_cleanup: Arc<RwLock<chrono::DateTime<chrono::Utc>>>,
401}
402
403impl SecurityMonitor {
404 pub fn new(config: SecurityMonitorConfig) -> Self {
406 Self {
407 config,
408 events: Arc::new(RwLock::new(VecDeque::new())),
409 alerts: Arc::new(RwLock::new(Vec::new())),
410 alert_rules: Arc::new(RwLock::new(Vec::new())),
411 metrics_cache: Arc::new(RwLock::new(HashMap::new())),
412 last_cleanup: Arc::new(RwLock::new(chrono::Utc::now())),
413 }
414 }
415
416 pub fn with_default_config() -> Self {
418 Self::new(SecurityMonitorConfig::default())
419 }
420
421 pub async fn record_event(&self, event: SecurityEvent) {
423 debug!("Recording security event: {:?}", event.event_type);
424
425 let mut events = self.events.write().await;
426 events.push_back(event.clone());
427
428 while events.len() > self.config.max_events_in_memory {
430 events.pop_front();
431 }
432
433 drop(events);
434
435 if self.config.enable_alerts {
437 self.process_alerts_for_event(&event).await;
438 }
439
440 if self.config.enable_realtime {
442 self.update_realtime_metrics(&event).await;
443 }
444 }
445
446 pub async fn record_violation(&self, violation: &SecurityViolation) {
448 let event_type = match violation.violation_type {
449 SecurityViolationType::InjectionAttempt => SecurityEventType::InjectionAttempt,
450 SecurityViolationType::SizeLimit => SecurityEventType::SizeLimit,
451 SecurityViolationType::RateLimit => SecurityEventType::RateLimit,
452 SecurityViolationType::UnauthorizedMethod => SecurityEventType::UnauthorizedAccess,
453 _ => SecurityEventType::SystemError,
454 };
455
456 let mut event = SecurityEvent::new(
457 event_type,
458 violation.severity.clone(),
459 violation.description.clone(),
460 );
461
462 if let Some(field) = &violation.field {
463 event = event.with_metadata("field".to_string(), field.clone());
464 }
465
466 if let Some(value) = &violation.value {
467 event = event.with_metadata("value".to_string(), value.clone());
468 }
469
470 self.record_event(event).await;
471 }
472
473 pub async fn record_auth_event(
475 &self,
476 event_type: SecurityEventType,
477 auth_context: Option<&AuthContext>,
478 client_ip: Option<String>,
479 user_agent: Option<String>,
480 description: String,
481 ) {
482 let severity = match event_type {
483 SecurityEventType::AuthFailure | SecurityEventType::InvalidApiKey => {
484 SecuritySeverity::Medium
485 }
486 SecurityEventType::ExpiredToken => SecuritySeverity::Low,
487 SecurityEventType::AuthSuccess => SecuritySeverity::Low,
488 _ => SecuritySeverity::Medium,
489 };
490
491 let mut event = SecurityEvent::new(event_type, severity, description)
492 .with_request_context(client_ip, user_agent, None);
493
494 if let Some(auth) = auth_context {
495 event = event.with_user_context(auth);
496 }
497
498 self.record_event(event).await;
499 }
500
501 pub async fn record_session_event(
503 &self,
504 event_type: SecurityEventType,
505 session: &Session,
506 description: String,
507 ) {
508 let severity = match event_type {
509 SecurityEventType::MaxSessionsExceeded => SecuritySeverity::High,
510 SecurityEventType::SessionExpired => SecuritySeverity::Low,
511 _ => SecuritySeverity::Low,
512 };
513
514 let event =
515 SecurityEvent::new(event_type, severity, description).with_session_context(session);
516
517 self.record_event(event).await;
518 }
519
520 pub async fn get_recent_events(&self, limit: Option<usize>) -> Vec<SecurityEvent> {
522 let events = self.events.read().await;
523 let limit = limit.unwrap_or(100);
524
525 events.iter().rev().take(limit).cloned().collect()
526 }
527
528 pub async fn get_events_by_type(
530 &self,
531 event_type: SecurityEventType,
532 since: Option<chrono::DateTime<chrono::Utc>>,
533 limit: Option<usize>,
534 ) -> Vec<SecurityEvent> {
535 let events = self.events.read().await;
536 let since = since.unwrap_or_else(|| chrono::Utc::now() - chrono::Duration::hours(24));
537 let limit = limit.unwrap_or(1000);
538
539 events
540 .iter()
541 .filter(|e| e.event_type == event_type && e.timestamp >= since)
542 .rev()
543 .take(limit)
544 .cloned()
545 .collect()
546 }
547
548 pub async fn get_events_by_user(
550 &self,
551 user_id: &str,
552 since: Option<chrono::DateTime<chrono::Utc>>,
553 limit: Option<usize>,
554 ) -> Vec<SecurityEvent> {
555 let events = self.events.read().await;
556 let since = since.unwrap_or_else(|| chrono::Utc::now() - chrono::Duration::hours(24));
557 let limit = limit.unwrap_or(1000);
558
559 events
560 .iter()
561 .filter(|e| {
562 e.user_id.as_ref().map(|u| u == user_id).unwrap_or(false) && e.timestamp >= since
563 })
564 .rev()
565 .take(limit)
566 .cloned()
567 .collect()
568 }
569
570 pub async fn generate_metrics(
572 &self,
573 start: chrono::DateTime<chrono::Utc>,
574 end: chrono::DateTime<chrono::Utc>,
575 ) -> SecurityMetrics {
576 let events = self.events.read().await;
577 let mut metrics = SecurityMetrics {
578 period_start: start,
579 period_end: end,
580 ..Default::default()
581 };
582
583 let mut ip_counts = HashMap::new();
584 let mut user_agent_counts = HashMap::new();
585 let mut method_counts = HashMap::new();
586
587 for event in events.iter() {
588 if event.timestamp >= start && event.timestamp <= end {
589 match event.event_type {
591 SecurityEventType::AuthSuccess => metrics.auth_success_count += 1,
592 SecurityEventType::AuthFailure => metrics.auth_failure_count += 1,
593 SecurityEventType::InvalidApiKey => metrics.invalid_api_key_count += 1,
594 SecurityEventType::ExpiredToken => metrics.expired_token_count += 1,
595 SecurityEventType::SessionCreated => metrics.sessions_created += 1,
596 SecurityEventType::SessionExpired => metrics.sessions_expired += 1,
597 SecurityEventType::SessionTerminated => metrics.sessions_terminated += 1,
598 SecurityEventType::InjectionAttempt => metrics.injection_attempts += 1,
599 SecurityEventType::SizeLimit => metrics.size_limit_violations += 1,
600 SecurityEventType::RateLimit => metrics.rate_limit_violations += 1,
601 SecurityEventType::UnauthorizedAccess => {
602 metrics.unauthorized_access_attempts += 1
603 }
604 SecurityEventType::PermissionDenied => metrics.permission_denied_count += 1,
605 SecurityEventType::RoleEscalation => metrics.role_escalation_attempts += 1,
606 _ => {}
607 }
608
609 if let Some(ip) = &event.client_ip {
611 *ip_counts.entry(ip.clone()).or_insert(0) += 1;
612 }
613
614 if let Some(ua) = &event.user_agent {
616 *user_agent_counts.entry(ua.clone()).or_insert(0) += 1;
617 }
618
619 if let Some(method) = &event.method {
621 *method_counts.entry(method.clone()).or_insert(0) += 1;
622 }
623
624 if let Some(country) = &event.country {
626 *metrics
627 .country_distribution
628 .entry(country.clone())
629 .or_insert(0) += 1;
630 }
631 }
632 }
633
634 metrics.top_source_ips = Self::top_items(ip_counts, 10);
636 metrics.top_user_agents = Self::top_items(user_agent_counts, 10);
637 metrics.top_methods = Self::top_items(method_counts, 10);
638
639 metrics
640 }
641
642 pub async fn get_dashboard_data(&self) -> SecurityDashboard {
644 let now = chrono::Utc::now();
645 let hour_ago = now - chrono::Duration::hours(1);
646 let day_ago = now - chrono::Duration::days(1);
647
648 let hourly_metrics = self.generate_metrics(hour_ago, now).await;
649 let daily_metrics = self.generate_metrics(day_ago, now).await;
650 let recent_events = self.get_recent_events(Some(50)).await;
651 let active_alerts = self.get_active_alerts().await;
652
653 SecurityDashboard {
654 timestamp: now,
655 hourly_metrics,
656 daily_metrics,
657 recent_events,
658 active_alerts,
659 system_health: self.get_system_health().await,
660 }
661 }
662
663 pub async fn add_alert_rule(&self, rule: AlertRule) {
665 let mut rules = self.alert_rules.write().await;
666 rules.push(rule);
667 info!("Added new alert rule");
668 }
669
670 pub async fn get_active_alerts(&self) -> Vec<SecurityAlert> {
672 let alerts = self.alerts.read().await;
673 alerts
674 .iter()
675 .filter(|a| a.resolved_at.is_none())
676 .cloned()
677 .collect()
678 }
679
680 pub async fn resolve_alert(&self, alert_id: &str) -> Result<(), MonitoringError> {
682 let mut alerts = self.alerts.write().await;
683
684 if let Some(alert) = alerts.iter_mut().find(|a| a.alert_id == alert_id) {
685 alert.resolved_at = Some(chrono::Utc::now());
686 info!("Resolved alert: {}", alert_id);
687 Ok(())
688 } else {
689 Err(MonitoringError::AlertNotFound {
690 alert_id: alert_id.to_string(),
691 })
692 }
693 }
694
695 pub async fn start_background_tasks(&self) -> tokio::task::JoinHandle<()> {
697 let monitor = self.clone();
698
699 tokio::spawn(async move {
700 let mut cleanup_interval =
701 tokio::time::interval(chrono::Duration::hours(1).to_std().unwrap());
702 let mut metrics_interval =
703 tokio::time::interval(monitor.config.metrics_interval.to_std().unwrap());
704
705 loop {
706 tokio::select! {
707 _ = cleanup_interval.tick() => {
708 if let Err(e) = monitor.cleanup_old_data().await {
709 error!("Failed to cleanup old monitoring data: {}", e);
710 }
711 }
712 _ = metrics_interval.tick() => {
713 if let Err(e) = monitor.update_metrics_cache().await {
714 error!("Failed to update metrics cache: {}", e);
715 }
716 }
717 }
718 }
719 })
720 }
721
722 fn top_items(mut counts: HashMap<String, u64>, limit: usize) -> Vec<(String, u64)> {
725 let mut items: Vec<(String, u64)> = counts.drain().collect();
726 items.sort_by(|a, b| b.1.cmp(&a.1));
727 items.truncate(limit);
728 items
729 }
730
731 async fn process_alerts_for_event(&self, event: &SecurityEvent) {
732 let rules = self.alert_rules.read().await;
733
734 for rule in rules.iter() {
735 if !rule.enabled {
736 continue;
737 }
738
739 if rule.event_types.contains(&event.event_type) && event.severity >= rule.min_severity {
740 if self.check_alert_threshold(rule, event).await {
742 self.trigger_alert(rule, event).await;
743 }
744 }
745 }
746 }
747
748 async fn check_alert_threshold(&self, rule: &AlertRule, _event: &SecurityEvent) -> bool {
749 let now = chrono::Utc::now();
750 let window_start = now - rule.time_window;
751
752 let events = self.events.read().await;
753 let relevant_events: Vec<&SecurityEvent> = events
754 .iter()
755 .filter(|e| {
756 e.timestamp >= window_start
757 && rule.event_types.contains(&e.event_type)
758 && e.severity >= rule.min_severity
759 })
760 .collect();
761
762 match &rule.threshold {
763 AlertThreshold::Count(threshold) => relevant_events.len() as u64 >= *threshold,
764 AlertThreshold::Rate { count, duration: _ } => relevant_events.len() as u64 >= *count,
765 AlertThreshold::Percentage {
766 numerator_events,
767 denominator_events,
768 threshold,
769 } => {
770 let numerator = relevant_events
771 .iter()
772 .filter(|e| numerator_events.contains(&e.event_type))
773 .count() as f64;
774
775 let denominator = relevant_events
776 .iter()
777 .filter(|e| denominator_events.contains(&e.event_type))
778 .count() as f64;
779
780 if denominator > 0.0 {
781 (numerator / denominator) * 100.0 >= *threshold
782 } else {
783 false
784 }
785 }
786 }
787 }
788
789 async fn trigger_alert(&self, rule: &AlertRule, event: &SecurityEvent) {
790 let alert = SecurityAlert {
791 alert_id: Uuid::new_v4().to_string(),
792 rule_id: rule.rule_id.clone(),
793 rule_name: rule.name.clone(),
794 triggered_at: chrono::Utc::now(),
795 resolved_at: None,
796 severity: event.severity.clone(),
797 description: format!("Alert triggered: {}", rule.description),
798 triggering_events: vec![event.event_id.clone()],
799 metadata: HashMap::new(),
800 actions_taken: Vec::new(),
801 };
802
803 warn!(
804 "Security alert triggered: {} - {}",
805 alert.rule_name, alert.description
806 );
807
808 let mut alerts = self.alerts.write().await;
809 alerts.push(alert);
810
811 while alerts.len() > self.config.max_alerts_in_memory {
813 alerts.remove(0);
814 }
815 }
816
817 async fn update_realtime_metrics(&self, _event: &SecurityEvent) {
818 debug!("Updated real-time metrics");
821 }
822
823 async fn cleanup_old_data(&self) -> Result<(), MonitoringError> {
824 let now = chrono::Utc::now();
825 let event_cutoff = now - self.config.event_retention;
826 let alert_cutoff = now - self.config.alert_retention;
827
828 let mut events = self.events.write().await;
830 let original_count = events.len();
831 events.retain(|e| e.timestamp >= event_cutoff);
832 let events_removed = original_count - events.len();
833
834 drop(events);
835
836 let mut alerts = self.alerts.write().await;
838 let original_alert_count = alerts.len();
839 alerts.retain(|a| a.triggered_at >= alert_cutoff);
840 let alerts_removed = original_alert_count - alerts.len();
841
842 if events_removed > 0 || alerts_removed > 0 {
843 info!(
844 "Cleaned up {} old events and {} old alerts",
845 events_removed, alerts_removed
846 );
847 }
848
849 Ok(())
850 }
851
852 async fn update_metrics_cache(&self) -> Result<(), MonitoringError> {
853 let now = chrono::Utc::now();
854 let hour_ago = now - chrono::Duration::hours(1);
855
856 let metrics = self.generate_metrics(hour_ago, now).await;
857
858 let mut cache = self.metrics_cache.write().await;
859 cache.insert("hourly".to_string(), metrics);
860
861 let day_ago = now - chrono::Duration::days(1);
863 cache.retain(|_, metrics| metrics.period_start >= day_ago);
864
865 Ok(())
866 }
867
868 async fn get_system_health(&self) -> SystemHealth {
869 let events = self.events.read().await;
870 let alerts = self.alerts.read().await;
871
872 SystemHealth {
873 events_in_memory: events.len(),
874 active_alerts: alerts.iter().filter(|a| a.resolved_at.is_none()).count(),
875 last_event_time: events.back().map(|e| e.timestamp),
876 memory_usage_mb: self.estimate_memory_usage().await,
877 }
878 }
879
880 async fn estimate_memory_usage(&self) -> u64 {
881 let events = self.events.read().await;
883 let alerts = self.alerts.read().await;
884
885 let event_size_estimate = events.len() * 1024; let alert_size_estimate = alerts.len() * 512; ((event_size_estimate + alert_size_estimate) / 1024 / 1024) as u64
889 }
890}
891
892impl Clone for SecurityMonitor {
893 fn clone(&self) -> Self {
894 Self {
895 config: self.config.clone(),
896 events: Arc::clone(&self.events),
897 alerts: Arc::clone(&self.alerts),
898 alert_rules: Arc::clone(&self.alert_rules),
899 metrics_cache: Arc::clone(&self.metrics_cache),
900 last_cleanup: Arc::clone(&self.last_cleanup),
901 }
902 }
903}
904
905#[derive(Debug, Clone, Serialize, Deserialize)]
907pub struct SecurityDashboard {
908 pub timestamp: chrono::DateTime<chrono::Utc>,
909 pub hourly_metrics: SecurityMetrics,
910 pub daily_metrics: SecurityMetrics,
911 pub recent_events: Vec<SecurityEvent>,
912 pub active_alerts: Vec<SecurityAlert>,
913 pub system_health: SystemHealth,
914}
915
916#[derive(Debug, Clone, Serialize, Deserialize)]
918pub struct SystemHealth {
919 pub events_in_memory: usize,
920 pub active_alerts: usize,
921 pub last_event_time: Option<chrono::DateTime<chrono::Utc>>,
922 pub memory_usage_mb: u64,
923}
924
925pub fn create_default_alert_rules() -> Vec<AlertRule> {
927 vec![
928 AlertRule {
929 rule_id: "high_auth_failures".to_string(),
930 name: "High Authentication Failures".to_string(),
931 description: "Multiple authentication failures detected".to_string(),
932 event_types: vec![
933 SecurityEventType::AuthFailure,
934 SecurityEventType::InvalidApiKey,
935 ],
936 min_severity: SecuritySeverity::Medium,
937 threshold: AlertThreshold::Count(10),
938 time_window: chrono::Duration::minutes(5),
939 cooldown: chrono::Duration::minutes(15),
940 enabled: true,
941 actions: vec![AlertAction::Log {
942 level: "warn".to_string(),
943 }],
944 },
945 AlertRule {
946 rule_id: "injection_attempts".to_string(),
947 name: "Injection Attempts".to_string(),
948 description: "Potential injection attacks detected".to_string(),
949 event_types: vec![SecurityEventType::InjectionAttempt],
950 min_severity: SecuritySeverity::High,
951 threshold: AlertThreshold::Count(3),
952 time_window: chrono::Duration::minutes(10),
953 cooldown: chrono::Duration::minutes(30),
954 enabled: true,
955 actions: vec![
956 AlertAction::Log {
957 level: "error".to_string(),
958 },
959 AlertAction::BlockIp {
960 duration: chrono::Duration::hours(1),
961 },
962 ],
963 },
964 AlertRule {
965 rule_id: "rate_limit_violations".to_string(),
966 name: "Rate Limit Violations".to_string(),
967 description: "Excessive rate limit violations".to_string(),
968 event_types: vec![SecurityEventType::RateLimit],
969 min_severity: SecuritySeverity::Medium,
970 threshold: AlertThreshold::Count(20),
971 time_window: chrono::Duration::minutes(5),
972 cooldown: chrono::Duration::minutes(10),
973 enabled: true,
974 actions: vec![AlertAction::Log {
975 level: "warn".to_string(),
976 }],
977 },
978 ]
979}
980
981#[cfg(test)]
982mod tests {
983 use super::*;
984
985 #[tokio::test]
986 async fn test_security_monitor_creation() {
987 let monitor = SecurityMonitor::with_default_config();
988
989 assert!(monitor.config.enable_realtime);
991 assert!(monitor.config.enable_alerts);
992 }
993
994 #[tokio::test]
995 async fn test_event_recording() {
996 let monitor = SecurityMonitor::with_default_config();
997
998 let event = SecurityEvent::new(
999 SecurityEventType::AuthFailure,
1000 SecuritySeverity::Medium,
1001 "Test authentication failure".to_string(),
1002 );
1003
1004 monitor.record_event(event).await;
1005
1006 let events = monitor.get_recent_events(Some(10)).await;
1007 assert_eq!(events.len(), 1);
1008 assert_eq!(events[0].event_type, SecurityEventType::AuthFailure);
1009 }
1010
1011 #[tokio::test]
1012 async fn test_metrics_generation() {
1013 let monitor = SecurityMonitor::with_default_config();
1014
1015 monitor
1017 .record_event(SecurityEvent::new(
1018 SecurityEventType::AuthSuccess,
1019 SecuritySeverity::Low,
1020 "Success".to_string(),
1021 ))
1022 .await;
1023
1024 monitor
1025 .record_event(SecurityEvent::new(
1026 SecurityEventType::AuthFailure,
1027 SecuritySeverity::Medium,
1028 "Failure".to_string(),
1029 ))
1030 .await;
1031
1032 let now = chrono::Utc::now();
1033 let hour_ago = now - chrono::Duration::hours(1);
1034
1035 let metrics = monitor.generate_metrics(hour_ago, now).await;
1036
1037 assert_eq!(metrics.auth_success_count, 1);
1038 assert_eq!(metrics.auth_failure_count, 1);
1039 }
1040
1041 #[tokio::test]
1042 async fn test_alert_rules() {
1043 let monitor = SecurityMonitor::with_default_config();
1044
1045 let rule = AlertRule {
1046 rule_id: "test_rule".to_string(),
1047 name: "Test Rule".to_string(),
1048 description: "Test alert rule".to_string(),
1049 event_types: vec![SecurityEventType::AuthFailure],
1050 min_severity: SecuritySeverity::Medium,
1051 threshold: AlertThreshold::Count(1),
1052 time_window: chrono::Duration::minutes(5),
1053 cooldown: chrono::Duration::minutes(1),
1054 enabled: true,
1055 actions: vec![AlertAction::Log {
1056 level: "warn".to_string(),
1057 }],
1058 };
1059
1060 monitor.add_alert_rule(rule).await;
1061
1062 monitor
1064 .record_event(SecurityEvent::new(
1065 SecurityEventType::AuthFailure,
1066 SecuritySeverity::Medium,
1067 "Test failure".to_string(),
1068 ))
1069 .await;
1070
1071 tokio::time::sleep(tokio::time::Duration::from_millis(100)).await;
1073
1074 let active_alerts = monitor.get_active_alerts().await;
1075 assert!(!active_alerts.is_empty());
1076 }
1077
1078 #[tokio::test]
1079 async fn test_dashboard_data() {
1080 let monitor = SecurityMonitor::with_default_config();
1081
1082 monitor
1084 .record_event(SecurityEvent::new(
1085 SecurityEventType::SessionCreated,
1086 SecuritySeverity::Low,
1087 "Session created".to_string(),
1088 ))
1089 .await;
1090
1091 let dashboard = monitor.get_dashboard_data().await;
1092
1093 assert!(!dashboard.recent_events.is_empty());
1094 assert_eq!(dashboard.hourly_metrics.sessions_created, 1);
1095 }
1096}