use security_core::severity::SecuritySeverity;
use security_events::event::{EventOutcome, SecurityEvent};
use security_events::kind::EventKind;
use std::time::Duration;
#[derive(Clone, Copy, Debug, PartialEq, Eq, Hash)]
pub enum StepUpDecision {
Required,
NotRequired,
}
#[derive(Clone, Debug)]
pub struct StepUpPolicy {
operation: String,
max_auth_age: Option<Duration>,
}
impl StepUpPolicy {
#[must_use]
pub fn new(operation: impl Into<String>, max_auth_age: Duration) -> Self {
Self {
operation: operation.into(),
max_auth_age: Some(max_auth_age),
}
}
#[must_use]
pub fn always(operation: impl Into<String>) -> Self {
Self {
operation: operation.into(),
max_auth_age: None,
}
}
#[must_use]
pub fn operation(&self) -> &str {
&self.operation
}
#[must_use]
pub fn evaluate(&self, last_auth_age: Duration) -> StepUpDecision {
match self.max_auth_age {
None => StepUpDecision::Required,
Some(max_age) => {
if last_auth_age > max_age {
StepUpDecision::Required
} else {
StepUpDecision::NotRequired
}
}
}
}
#[must_use]
pub fn evaluate_with_events(&self, last_auth_age: Duration) -> Vec<SecurityEvent> {
let decision = self.evaluate(last_auth_age);
match decision {
StepUpDecision::NotRequired => vec![],
StepUpDecision::Required => {
let mut event = SecurityEvent::new(
EventKind::StepUpAuthFailure,
SecuritySeverity::High,
EventOutcome::Blocked,
);
event.reason_code = Some("step_up_required");
event.resource = Some(self.operation.clone());
vec![event]
}
}
}
}