use std::net::IpAddr;
use security_core::classification::DataClassification;
use security_core::severity::SecuritySeverity;
use security_events::event::{EventOutcome, EventValue, SecurityEvent};
use security_events::kind::EventKind;
use security_events::sink::SecuritySink;
#[derive(Debug, Clone)]
pub struct AuthEventContext {
pub user_id: String,
pub method: String,
pub source_ip: Option<IpAddr>,
pub user_agent: Option<String>,
}
pub struct AuthEventEmitter<S: SecuritySink> {
sink: S,
}
impl<S: SecuritySink> AuthEventEmitter<S> {
#[must_use]
pub fn new(sink: S) -> Self {
Self { sink }
}
pub fn emit_success(&self, context: AuthEventContext) {
let event = build_success_event(context);
self.sink.write_event(&event);
}
pub fn emit_failure(&self, context: AuthEventContext, reason_code: &'static str) {
let mut event = build_failure_event(context);
event.reason_code = Some(reason_code);
self.sink.write_event(&event);
}
}
#[must_use]
pub fn build_success_event(context: AuthEventContext) -> SecurityEvent {
let mut event = SecurityEvent::new(
EventKind::MfaEvent,
SecuritySeverity::Info,
EventOutcome::Success,
);
event.actor = Some(context.user_id);
event.source_ip = context.source_ip;
event.labels.insert(
"auth_method".to_string(),
EventValue::Classified {
value: context.method,
classification: DataClassification::Internal,
},
);
if let Some(user_agent) = context.user_agent {
event.labels.insert(
"user_agent".to_string(),
EventValue::Classified {
value: user_agent,
classification: DataClassification::Internal,
},
);
}
event
}
#[must_use]
pub fn build_failure_event(context: AuthEventContext) -> SecurityEvent {
let mut event = SecurityEvent::new(
EventKind::AuthnFailure,
SecuritySeverity::High,
EventOutcome::Failure,
);
event.actor = Some(context.user_id);
event.source_ip = context.source_ip;
event.labels.insert(
"auth_method".to_string(),
EventValue::Classified {
value: context.method,
classification: DataClassification::Internal,
},
);
if let Some(user_agent) = context.user_agent {
event.labels.insert(
"user_agent".to_string(),
EventValue::Classified {
value: user_agent,
classification: DataClassification::Internal,
},
);
}
event
}