feat: complete session preferences and PAM fixture gates

This commit is contained in:
2026-09-26 02:44:29 +05:30
parent 83345a1842
commit ee6186ed0b
34 changed files with 801 additions and 327 deletions

View File

@@ -1,8 +1,6 @@
//! Redacted security audit events.
//!
//! Audit records deliberately contain no password, token, PAM message, or
//! command-line detail. Callers can send the fields to a structured logger
//! without accidentally turning an authentication failure into a secret dump.
//! Audit records exclude secrets, PAM messages, and command arguments.
use std::fmt;
@@ -11,11 +9,8 @@ use crate::error::Error;
/// The security operation that produced an audit event.
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
pub enum AuditAction {
/// A PAM authentication attempt.
Authentication,
/// A PAM password-change transaction.
PasswordChange,
/// A user session handoff.
Session,
}
@@ -32,13 +27,9 @@ impl fmt::Display for AuditAction {
/// The outcome of a security operation.
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
pub enum AuditOutcome {
/// The operation was requested.
Started,
/// The operation completed successfully.
Succeeded,
/// The operation was rejected or failed.
Failed,
/// PAM requires a password change before proceeding.
PasswordChangeRequired,
}
@@ -56,21 +47,13 @@ impl fmt::Display for AuditOutcome {
/// A safe category for a PAM failure, without exposing PAM's free-form text.
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
pub enum PamReason {
/// Password or other authentication material was rejected.
AuthenticationRejected,
/// PAM could not reach its backing authentication service.
AuthenticationUnavailable,
/// PAM reports that the account has expired.
AccountExpired,
/// PAM requires a password change.
PasswordChangeRequired,
/// PAM reports that the retry limit was reached.
TooManyAttempts,
/// PAM conversation or token handling failed.
Conversation,
/// A PAM/system operation failed.
System,
/// An unclassified PAM status was returned.
Unknown,
}
@@ -92,18 +75,14 @@ impl fmt::Display for PamReason {
/// A structured event whose fields are safe to send to an audit logger.
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
pub struct AuditEvent<'a> {
/// Security operation.
pub action: AuditAction,
/// Operation outcome.
pub outcome: AuditOutcome,
/// Account name supplied by the user; never a password or token.
pub account: &'a str,
/// Sanitized PAM failure category, when applicable.
pub pam_reason: Option<PamReason>,
}
impl<'a> AuditEvent<'a> {
/// Creates an event for an operation that has just started.
pub const fn started(action: AuditAction, account: &'a str) -> Self {
Self {
action,
@@ -113,7 +92,6 @@ impl<'a> AuditEvent<'a> {
}
}
/// Creates a successful event.
pub const fn succeeded(action: AuditAction, account: &'a str) -> Self {
Self {
action,
@@ -123,7 +101,6 @@ impl<'a> AuditEvent<'a> {
}
}
/// Creates a failure event with a sanitized PAM category.
pub fn failed(action: AuditAction, account: &'a str, error: &Error) -> Self {
Self {
action,