pub mod config;
pub mod middleware;
pub mod notification;
pub mod service;
pub use config::LockoutConfig;
pub use middleware::LockoutMiddleware;
pub use notification::{LockoutEvent, LockoutNotification, UnlockReason};
pub use service::{LockoutStatus, LoginLockout};
#[cfg(feature = "audit")]
mod audit_integration {
use async_trait::async_trait;
use crate::audit::{AuditEvent, AuditEventKind, AuditLogger, AuditSeverity};
use super::notification::{LockoutEvent, LockoutNotification};
pub struct AuditLockoutNotification {
audit_logger: AuditLogger,
}
impl AuditLockoutNotification {
pub fn new(audit_logger: AuditLogger) -> Self {
Self { audit_logger }
}
}
#[async_trait]
impl LockoutNotification for AuditLockoutNotification {
async fn on_event(&self, event: LockoutEvent) {
match event {
LockoutEvent::AccountLocked {
ref identity,
attempt_count,
lockout_duration_secs,
} => {
let audit_event = AuditEvent::new(
AuditEventKind::AuthAccountLocked,
AuditSeverity::Warning,
self.audit_logger.service_name().to_string(),
)
.with_metadata(serde_json::json!({
"identity": identity,
"attempt_count": attempt_count,
"lockout_duration_secs": lockout_duration_secs,
}));
self.audit_logger.log(audit_event).await;
}
LockoutEvent::AccountUnlocked {
ref identity,
ref reason,
} => {
let audit_event = AuditEvent::new(
AuditEventKind::AuthAccountUnlocked,
AuditSeverity::Notice,
self.audit_logger.service_name().to_string(),
)
.with_metadata(serde_json::json!({
"identity": identity,
"reason": reason.to_string(),
}));
self.audit_logger.log(audit_event).await;
}
_ => {}
}
}
}
}
#[cfg(feature = "audit")]
pub use audit_integration::AuditLockoutNotification;