1use std::collections::HashMap;
26use std::fmt;
27use std::sync::Arc;
28use std::time::{SystemTime, UNIX_EPOCH};
29
30use tokio::sync::RwLock;
31
32#[derive(Debug, Clone, PartialEq, Eq)]
34pub enum SecurityEventType {
35 AuthenticationSuccess,
38 AuthenticationFailure,
40 Logout,
42 SessionCreated,
44 SessionDestroyed,
46 SessionExpired,
48
49 AccessGranted,
52 AccessDenied,
54 InsufficientPermissions,
56
57 AccountLocked,
60 AccountUnlocked,
62 PasswordChanged,
64 PasswordResetRequested,
66
67 TokenGenerated,
70 TokenRefreshed,
72 TokenRevoked,
74 TokenExpired,
76 InvalidToken,
78
79 RateLimitExceeded,
82 RateLimitWarning,
84
85 CsrfValidationFailed,
88 CsrfTokenMissing,
90
91 BruteForceDetected,
94 SuspiciousIp,
96 MultipleFailures,
98
99 Custom(String),
102}
103
104impl fmt::Display for SecurityEventType {
105 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
106 match self {
107 SecurityEventType::AuthenticationSuccess => write!(f, "AUTHENTICATION_SUCCESS"),
108 SecurityEventType::AuthenticationFailure => write!(f, "AUTHENTICATION_FAILURE"),
109 SecurityEventType::Logout => write!(f, "LOGOUT"),
110 SecurityEventType::SessionCreated => write!(f, "SESSION_CREATED"),
111 SecurityEventType::SessionDestroyed => write!(f, "SESSION_DESTROYED"),
112 SecurityEventType::SessionExpired => write!(f, "SESSION_EXPIRED"),
113 SecurityEventType::AccessGranted => write!(f, "ACCESS_GRANTED"),
114 SecurityEventType::AccessDenied => write!(f, "ACCESS_DENIED"),
115 SecurityEventType::InsufficientPermissions => write!(f, "INSUFFICIENT_PERMISSIONS"),
116 SecurityEventType::AccountLocked => write!(f, "ACCOUNT_LOCKED"),
117 SecurityEventType::AccountUnlocked => write!(f, "ACCOUNT_UNLOCKED"),
118 SecurityEventType::PasswordChanged => write!(f, "PASSWORD_CHANGED"),
119 SecurityEventType::PasswordResetRequested => write!(f, "PASSWORD_RESET_REQUESTED"),
120 SecurityEventType::TokenGenerated => write!(f, "TOKEN_GENERATED"),
121 SecurityEventType::TokenRefreshed => write!(f, "TOKEN_REFRESHED"),
122 SecurityEventType::TokenRevoked => write!(f, "TOKEN_REVOKED"),
123 SecurityEventType::TokenExpired => write!(f, "TOKEN_EXPIRED"),
124 SecurityEventType::InvalidToken => write!(f, "INVALID_TOKEN"),
125 SecurityEventType::RateLimitExceeded => write!(f, "RATE_LIMIT_EXCEEDED"),
126 SecurityEventType::RateLimitWarning => write!(f, "RATE_LIMIT_WARNING"),
127 SecurityEventType::CsrfValidationFailed => write!(f, "CSRF_VALIDATION_FAILED"),
128 SecurityEventType::CsrfTokenMissing => write!(f, "CSRF_TOKEN_MISSING"),
129 SecurityEventType::BruteForceDetected => write!(f, "BRUTE_FORCE_DETECTED"),
130 SecurityEventType::SuspiciousIp => write!(f, "SUSPICIOUS_IP"),
131 SecurityEventType::MultipleFailures => write!(f, "MULTIPLE_FAILURES"),
132 SecurityEventType::Custom(name) => write!(f, "CUSTOM_{}", name.to_uppercase()),
133 }
134 }
135}
136
137#[derive(Debug, Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Default)]
139pub enum SecurityEventSeverity {
140 #[default]
142 Info,
143 Warning,
145 Error,
147 Critical,
149}
150
151impl fmt::Display for SecurityEventSeverity {
152 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
153 match self {
154 SecurityEventSeverity::Info => write!(f, "INFO"),
155 SecurityEventSeverity::Warning => write!(f, "WARNING"),
156 SecurityEventSeverity::Error => write!(f, "ERROR"),
157 SecurityEventSeverity::Critical => write!(f, "CRITICAL"),
158 }
159 }
160}
161
162impl SecurityEventType {
163 pub fn default_severity(&self) -> SecurityEventSeverity {
165 match self {
166 SecurityEventType::AuthenticationSuccess
167 | SecurityEventType::Logout
168 | SecurityEventType::SessionCreated
169 | SecurityEventType::AccessGranted
170 | SecurityEventType::TokenGenerated
171 | SecurityEventType::TokenRefreshed
172 | SecurityEventType::PasswordChanged => SecurityEventSeverity::Info,
173
174 SecurityEventType::SessionExpired
175 | SecurityEventType::TokenExpired
176 | SecurityEventType::RateLimitWarning => SecurityEventSeverity::Warning,
177
178 SecurityEventType::AuthenticationFailure
179 | SecurityEventType::SessionDestroyed
180 | SecurityEventType::AccessDenied
181 | SecurityEventType::InsufficientPermissions
182 | SecurityEventType::TokenRevoked
183 | SecurityEventType::InvalidToken
184 | SecurityEventType::RateLimitExceeded
185 | SecurityEventType::CsrfValidationFailed
186 | SecurityEventType::CsrfTokenMissing
187 | SecurityEventType::AccountLocked
188 | SecurityEventType::PasswordResetRequested => SecurityEventSeverity::Error,
189
190 SecurityEventType::BruteForceDetected
191 | SecurityEventType::SuspiciousIp
192 | SecurityEventType::MultipleFailures => SecurityEventSeverity::Critical,
193
194 SecurityEventType::AccountUnlocked | SecurityEventType::Custom(_) => {
195 SecurityEventSeverity::Info
196 }
197 }
198 }
199}
200
201#[derive(Debug, Clone)]
203pub struct SecurityEvent {
204 pub id: String,
206 pub timestamp: u64,
208 pub event_type: SecurityEventType,
210 pub severity: SecurityEventSeverity,
212 pub username: Option<String>,
214 pub ip_address: Option<String>,
216 pub user_agent: Option<String>,
218 pub path: Option<String>,
220 pub method: Option<String>,
222 pub session_id: Option<String>,
224 pub details: HashMap<String, String>,
226 pub error: Option<String>,
228}
229
230impl SecurityEvent {
231 pub fn new(event_type: SecurityEventType) -> Self {
233 let now = SystemTime::now()
234 .duration_since(UNIX_EPOCH)
235 .unwrap_or_default()
236 .as_millis() as u64;
237
238 Self {
239 id: generate_event_id(),
240 timestamp: now,
241 severity: event_type.default_severity(),
242 event_type,
243 username: None,
244 ip_address: None,
245 user_agent: None,
246 path: None,
247 method: None,
248 session_id: None,
249 details: HashMap::new(),
250 error: None,
251 }
252 }
253
254 pub fn username(mut self, username: impl Into<String>) -> Self {
256 self.username = Some(username.into());
257 self
258 }
259
260 pub fn ip_address(mut self, ip: impl Into<String>) -> Self {
262 self.ip_address = Some(ip.into());
263 self
264 }
265
266 pub fn user_agent(mut self, ua: impl Into<String>) -> Self {
268 self.user_agent = Some(ua.into());
269 self
270 }
271
272 pub fn path(mut self, path: impl Into<String>) -> Self {
274 self.path = Some(path.into());
275 self
276 }
277
278 pub fn method(mut self, method: impl Into<String>) -> Self {
280 self.method = Some(method.into());
281 self
282 }
283
284 pub fn session_id(mut self, id: impl Into<String>) -> Self {
286 self.session_id = Some(id.into());
287 self
288 }
289
290 pub fn severity(mut self, severity: SecurityEventSeverity) -> Self {
292 self.severity = severity;
293 self
294 }
295
296 pub fn detail(mut self, key: impl Into<String>, value: impl Into<String>) -> Self {
298 self.details.insert(key.into(), value.into());
299 self
300 }
301
302 pub fn error(mut self, error: impl Into<String>) -> Self {
304 self.error = Some(error.into());
305 self
306 }
307
308 pub fn login_success(username: &str, ip: &str) -> Self {
312 Self::new(SecurityEventType::AuthenticationSuccess)
313 .username(username)
314 .ip_address(ip)
315 }
316
317 pub fn login_failure(username: &str, ip: &str, reason: &str) -> Self {
319 Self::new(SecurityEventType::AuthenticationFailure)
320 .username(username)
321 .ip_address(ip)
322 .error(reason)
323 }
324
325 pub fn access_denied(username: &str, path: &str, ip: &str) -> Self {
327 Self::new(SecurityEventType::AccessDenied)
328 .username(username)
329 .path(path)
330 .ip_address(ip)
331 }
332
333 pub fn rate_limit_exceeded(ip: &str, path: &str) -> Self {
335 Self::new(SecurityEventType::RateLimitExceeded)
336 .ip_address(ip)
337 .path(path)
338 }
339
340 pub fn account_locked(username: &str, ip: &str, reason: &str) -> Self {
342 Self::new(SecurityEventType::AccountLocked)
343 .username(username)
344 .ip_address(ip)
345 .detail("reason", reason)
346 }
347
348 pub fn brute_force_detected(ip: &str, attempts: u32) -> Self {
350 Self::new(SecurityEventType::BruteForceDetected)
351 .ip_address(ip)
352 .detail("attempts", attempts.to_string())
353 }
354
355 pub fn to_log_line(&self) -> String {
357 let mut parts = vec![
358 format!("[{}]", self.severity),
359 format!("[{}]", self.event_type),
360 ];
361
362 if let Some(ref username) = self.username {
363 parts.push(format!("user={}", username));
364 }
365 if let Some(ref ip) = self.ip_address {
366 parts.push(format!("ip={}", ip));
367 }
368 if let Some(ref path) = self.path {
369 parts.push(format!("path={}", path));
370 }
371 if let Some(ref error) = self.error {
372 parts.push(format!("error=\"{}\"", error));
373 }
374 for (k, v) in &self.details {
375 parts.push(format!("{}={}", k, v));
376 }
377
378 parts.join(" ")
379 }
380
381 pub fn to_json(&self) -> String {
383 serde_json::to_string(self).unwrap_or_else(|_| self.to_log_line())
384 }
385}
386
387impl serde::Serialize for SecurityEvent {
388 fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
389 where
390 S: serde::Serializer,
391 {
392 use serde::ser::SerializeStruct;
393 let mut state = serializer.serialize_struct("SecurityEvent", 12)?;
394 state.serialize_field("id", &self.id)?;
395 state.serialize_field("timestamp", &self.timestamp)?;
396 state.serialize_field("event_type", &self.event_type.to_string())?;
397 state.serialize_field("severity", &self.severity.to_string())?;
398 state.serialize_field("username", &self.username)?;
399 state.serialize_field("ip_address", &self.ip_address)?;
400 state.serialize_field("user_agent", &self.user_agent)?;
401 state.serialize_field("path", &self.path)?;
402 state.serialize_field("method", &self.method)?;
403 state.serialize_field("session_id", &self.session_id)?;
404 state.serialize_field("details", &self.details)?;
405 state.serialize_field("error", &self.error)?;
406 state.end()
407 }
408}
409
410fn generate_event_id() -> String {
412 use rand::Rng;
413 let timestamp = SystemTime::now()
414 .duration_since(UNIX_EPOCH)
415 .unwrap_or_default()
416 .as_micros();
417 let random: u32 = rand::thread_rng().gen();
418 format!("{:x}-{:08x}", timestamp, random)
419}
420
421pub trait SecurityEventHandler: Send + Sync {
423 fn handle(&self, event: &SecurityEvent);
425}
426
427#[derive(Default)]
429pub struct StdoutHandler {
430 min_severity: SecurityEventSeverity,
431}
432
433impl StdoutHandler {
434 pub fn new() -> Self {
436 Self::default()
437 }
438
439 pub fn min_severity(mut self, severity: SecurityEventSeverity) -> Self {
441 self.min_severity = severity;
442 self
443 }
444}
445
446impl SecurityEventHandler for StdoutHandler {
447 fn handle(&self, event: &SecurityEvent) {
448 if event.severity >= self.min_severity {
449 println!("[SECURITY] {}", event.to_log_line());
450 }
451 }
452}
453
454pub struct ClosureHandler<F>
456where
457 F: Fn(&SecurityEvent) + Send + Sync,
458{
459 handler: F,
460}
461
462impl<F> ClosureHandler<F>
463where
464 F: Fn(&SecurityEvent) + Send + Sync,
465{
466 pub fn new(handler: F) -> Self {
468 Self { handler }
469 }
470}
471
472impl<F> SecurityEventHandler for ClosureHandler<F>
473where
474 F: Fn(&SecurityEvent) + Send + Sync,
475{
476 fn handle(&self, event: &SecurityEvent) {
477 (self.handler)(event);
478 }
479}
480
481#[derive(Clone)]
483pub struct InMemoryEventStore {
484 events: Arc<RwLock<Vec<SecurityEvent>>>,
485 max_events: usize,
486}
487
488impl Default for InMemoryEventStore {
489 fn default() -> Self {
490 Self::new()
491 }
492}
493
494impl InMemoryEventStore {
495 pub fn new() -> Self {
497 Self {
498 events: Arc::new(RwLock::new(Vec::new())),
499 max_events: 10000,
500 }
501 }
502
503 pub fn max_events(mut self, max: usize) -> Self {
505 self.max_events = max;
506 self
507 }
508
509 pub async fn get_events(&self) -> Vec<SecurityEvent> {
511 self.events.read().await.clone()
512 }
513
514 pub async fn get_events_by_type(&self, event_type: &SecurityEventType) -> Vec<SecurityEvent> {
516 self.events
517 .read()
518 .await
519 .iter()
520 .filter(|e| &e.event_type == event_type)
521 .cloned()
522 .collect()
523 }
524
525 pub async fn get_events_by_user(&self, username: &str) -> Vec<SecurityEvent> {
527 self.events
528 .read()
529 .await
530 .iter()
531 .filter(|e| e.username.as_deref() == Some(username))
532 .cloned()
533 .collect()
534 }
535
536 pub async fn clear(&self) {
538 self.events.write().await.clear();
539 }
540}
541
542impl SecurityEventHandler for InMemoryEventStore {
543 fn handle(&self, event: &SecurityEvent) {
544 let rt = tokio::runtime::Handle::try_current();
546 if let Ok(handle) = rt {
547 let events = Arc::clone(&self.events);
548 let event = event.clone();
549 let max = self.max_events;
550 handle.spawn(async move {
551 let mut guard = events.write().await;
552 guard.push(event);
553 if guard.len() > max {
554 guard.remove(0);
555 }
556 });
557 }
558 }
559}
560
561#[derive(Clone)]
563pub struct AuditLogger {
564 handlers: Arc<Vec<Arc<dyn SecurityEventHandler>>>,
565 enabled: bool,
566}
567
568impl Default for AuditLogger {
569 fn default() -> Self {
570 Self::new()
571 }
572}
573
574impl AuditLogger {
575 pub fn new() -> Self {
577 Self {
578 handlers: Arc::new(Vec::new()),
579 enabled: true,
580 }
581 }
582
583 pub fn with_stdout() -> Self {
585 Self::new().add_handler(StdoutHandler::new())
586 }
587
588 pub fn add_handler<H: SecurityEventHandler + 'static>(mut self, handler: H) -> Self {
590 let handlers = Arc::make_mut(&mut self.handlers);
591 handlers.push(Arc::new(handler));
592 self
593 }
594
595 pub fn with_handler<F>(self, handler: F) -> Self
597 where
598 F: Fn(&SecurityEvent) + Send + Sync + 'static,
599 {
600 self.add_handler(ClosureHandler::new(handler))
601 }
602
603 pub fn enabled(mut self, enabled: bool) -> Self {
605 self.enabled = enabled;
606 self
607 }
608
609 pub fn log(&self, event: SecurityEvent) {
611 if !self.enabled {
612 return;
613 }
614
615 for handler in self.handlers.iter() {
616 handler.handle(&event);
617 }
618 }
619
620 pub fn log_login_success(&self, username: &str, ip: &str) {
622 self.log(SecurityEvent::login_success(username, ip));
623 }
624
625 pub fn log_login_failure(&self, username: &str, ip: &str, reason: &str) {
627 self.log(SecurityEvent::login_failure(username, ip, reason));
628 }
629
630 pub fn log_access_denied(&self, username: &str, path: &str, ip: &str) {
632 self.log(SecurityEvent::access_denied(username, path, ip));
633 }
634
635 pub fn log_rate_limit_exceeded(&self, ip: &str, path: &str) {
637 self.log(SecurityEvent::rate_limit_exceeded(ip, path));
638 }
639}
640
641static GLOBAL_LOGGER: std::sync::OnceLock<AuditLogger> = std::sync::OnceLock::new();
643
644pub fn init_global_logger(logger: AuditLogger) {
646 let _ = GLOBAL_LOGGER.set(logger);
647}
648
649pub fn global_logger() -> &'static AuditLogger {
651 GLOBAL_LOGGER.get_or_init(AuditLogger::new)
652}
653
654pub fn audit_log(event: SecurityEvent) {
656 global_logger().log(event);
657}
658
659#[cfg(test)]
660mod tests {
661 use super::*;
662
663 #[test]
664 fn test_event_creation() {
665 let event = SecurityEvent::login_success("admin", "192.168.1.1");
666 assert_eq!(event.event_type, SecurityEventType::AuthenticationSuccess);
667 assert_eq!(event.username, Some("admin".to_string()));
668 assert_eq!(event.ip_address, Some("192.168.1.1".to_string()));
669 assert_eq!(event.severity, SecurityEventSeverity::Info);
670 }
671
672 #[test]
673 fn test_event_builder() {
674 let event = SecurityEvent::new(SecurityEventType::AccessDenied)
675 .username("user1")
676 .ip_address("10.0.0.1")
677 .path("/admin")
678 .detail("reason", "missing role")
679 .error("Access denied");
680
681 assert_eq!(event.username, Some("user1".to_string()));
682 assert_eq!(event.path, Some("/admin".to_string()));
683 assert!(event.details.contains_key("reason"));
684 assert_eq!(event.error, Some("Access denied".to_string()));
685 }
686
687 #[test]
688 fn test_severity_ordering() {
689 assert!(SecurityEventSeverity::Info < SecurityEventSeverity::Warning);
690 assert!(SecurityEventSeverity::Warning < SecurityEventSeverity::Error);
691 assert!(SecurityEventSeverity::Error < SecurityEventSeverity::Critical);
692 }
693
694 #[test]
695 fn test_event_type_display() {
696 assert_eq!(
697 SecurityEventType::AuthenticationSuccess.to_string(),
698 "AUTHENTICATION_SUCCESS"
699 );
700 assert_eq!(
701 SecurityEventType::Custom("test".to_string()).to_string(),
702 "CUSTOM_TEST"
703 );
704 }
705
706 #[test]
707 fn test_log_line_format() {
708 let event = SecurityEvent::login_failure("admin", "192.168.1.1", "Invalid password");
709 let log_line = event.to_log_line();
710
711 assert!(log_line.contains("[ERROR]"));
712 assert!(log_line.contains("[AUTHENTICATION_FAILURE]"));
713 assert!(log_line.contains("user=admin"));
714 assert!(log_line.contains("ip=192.168.1.1"));
715 }
716
717 #[test]
718 fn test_default_severity() {
719 assert_eq!(
720 SecurityEventType::AuthenticationSuccess.default_severity(),
721 SecurityEventSeverity::Info
722 );
723 assert_eq!(
724 SecurityEventType::BruteForceDetected.default_severity(),
725 SecurityEventSeverity::Critical
726 );
727 }
728
729 #[test]
730 fn test_audit_logger_with_closure() {
731 use std::sync::atomic::{AtomicUsize, Ordering};
732 let counter = Arc::new(AtomicUsize::new(0));
733 let counter_clone = counter.clone();
734
735 let logger = AuditLogger::new().with_handler(move |_event| {
736 counter_clone.fetch_add(1, Ordering::SeqCst);
737 });
738
739 logger.log_login_success("admin", "127.0.0.1");
740 logger.log_login_failure("user", "127.0.0.1", "Bad password");
741
742 assert_eq!(counter.load(Ordering::SeqCst), 2);
743 }
744
745 #[test]
746 fn test_disabled_logger() {
747 use std::sync::atomic::{AtomicUsize, Ordering};
748 let counter = Arc::new(AtomicUsize::new(0));
749 let counter_clone = counter.clone();
750
751 let logger = AuditLogger::new()
752 .with_handler(move |_event| {
753 counter_clone.fetch_add(1, Ordering::SeqCst);
754 })
755 .enabled(false);
756
757 logger.log_login_success("admin", "127.0.0.1");
758
759 assert_eq!(counter.load(Ordering::SeqCst), 0);
760 }
761}