#[cfg(test)]
#[allow(clippy::module_inception)] mod audit_logging {
use std::{collections::VecDeque, sync::Mutex};
#[derive(Debug, Clone, PartialEq, Eq)]
pub struct AuditLogEntry {
pub event_type: String,
pub secret_type: String,
pub subject: Option<String>,
pub operation: String,
pub success: bool,
pub error_message: Option<String>,
pub timestamp: u64,
}
pub struct MockAuditLogger {
logs: Mutex<VecDeque<AuditLogEntry>>,
}
impl MockAuditLogger {
pub fn new() -> Self {
Self {
logs: Mutex::new(VecDeque::new()),
}
}
pub fn log_entry(&self, entry: AuditLogEntry) {
self.logs.lock().unwrap().push_back(entry);
}
pub fn get_logs(&self) -> Vec<AuditLogEntry> {
self.logs.lock().unwrap().iter().cloned().collect()
}
pub fn clear(&self) {
self.logs.lock().unwrap().clear();
}
}
#[test]
fn test_jwt_validation_success_logged() {
let logger = MockAuditLogger::new();
let entry = AuditLogEntry {
event_type: "jwt_validation".to_string(),
secret_type: "jwt_token".to_string(),
subject: Some("user123".to_string()),
operation: "validate".to_string(),
success: true,
error_message: None,
timestamp: 1_234_567_890,
};
logger.log_entry(entry);
let logs = logger.get_logs();
assert_eq!(logs.len(), 1);
assert_eq!(logs[0].event_type, "jwt_validation");
assert!(logs[0].success);
assert_eq!(logs[0].subject, Some("user123".to_string()));
}
#[test]
fn test_jwt_validation_failure_logged() {
let logger = MockAuditLogger::new();
let entry = AuditLogEntry {
event_type: "jwt_validation".to_string(),
secret_type: "jwt_token".to_string(),
subject: Some("user123".to_string()),
operation: "validate".to_string(),
success: false,
error_message: Some("Invalid signature".to_string()),
timestamp: 1_234_567_890,
};
logger.log_entry(entry);
let logs = logger.get_logs();
assert_eq!(logs.len(), 1);
assert!(!(logs[0].success));
assert!(logs[0].error_message.is_some());
}
#[test]
fn test_jwt_validation_log_includes_timestamp() {
let logger = MockAuditLogger::new();
let timestamp = 1_234_567_890_u64;
let entry = AuditLogEntry {
event_type: "jwt_validation".to_string(),
secret_type: "jwt_token".to_string(),
subject: Some("user123".to_string()),
operation: "validate".to_string(),
success: true,
error_message: None,
timestamp,
};
logger.log_entry(entry);
let logs = logger.get_logs();
assert_eq!(logs[0].timestamp, timestamp);
}
#[test]
fn test_oidc_credential_access_logged() {
let logger = MockAuditLogger::new();
let entry = AuditLogEntry {
event_type: "oidc_credential_access".to_string(),
secret_type: "client_secret".to_string(),
subject: Some("service-account".to_string()),
operation: "retrieve".to_string(),
success: true,
error_message: None,
timestamp: 1_234_567_890,
};
logger.log_entry(entry);
let logs = logger.get_logs();
assert_eq!(logs.len(), 1);
assert_eq!(logs[0].secret_type, "client_secret");
assert_eq!(logs[0].operation, "retrieve");
}
#[test]
fn test_oidc_token_exchange_logged() {
let logger = MockAuditLogger::new();
let entry = AuditLogEntry {
event_type: "oidc_token_exchange".to_string(),
secret_type: "authorization_code".to_string(),
subject: Some("user456".to_string()),
operation: "exchange".to_string(),
success: true,
error_message: None,
timestamp: 1_234_567_891,
};
logger.log_entry(entry);
let logs = logger.get_logs();
assert_eq!(logs[0].event_type, "oidc_token_exchange");
assert_eq!(logs[0].operation, "exchange");
}
#[test]
fn test_session_token_creation_logged() {
let logger = MockAuditLogger::new();
let entry = AuditLogEntry {
event_type: "session_token_created".to_string(),
secret_type: "session_token".to_string(),
subject: Some("user789".to_string()),
operation: "create".to_string(),
success: true,
error_message: None,
timestamp: 1_234_567_892,
};
logger.log_entry(entry);
let logs = logger.get_logs();
assert_eq!(logs[0].event_type, "session_token_created");
assert_eq!(logs[0].subject, Some("user789".to_string()));
}
#[test]
fn test_session_token_validation_logged() {
let logger = MockAuditLogger::new();
let entry = AuditLogEntry {
event_type: "session_token_validation".to_string(),
secret_type: "session_token".to_string(),
subject: Some("user789".to_string()),
operation: "validate".to_string(),
success: true,
error_message: None,
timestamp: 1_234_567_893,
};
logger.log_entry(entry);
let logs = logger.get_logs();
assert_eq!(logs[0].event_type, "session_token_validation");
}
#[test]
fn test_session_token_revocation_logged() {
let logger = MockAuditLogger::new();
let entry = AuditLogEntry {
event_type: "session_token_revoked".to_string(),
secret_type: "session_token".to_string(),
subject: Some("user789".to_string()),
operation: "revoke".to_string(),
success: true,
error_message: None,
timestamp: 1_234_567_894,
};
logger.log_entry(entry);
let logs = logger.get_logs();
assert_eq!(logs[0].operation, "revoke");
}
#[test]
fn test_invalid_jwt_validation_includes_error() {
let logger = MockAuditLogger::new();
let entry = AuditLogEntry {
event_type: "jwt_validation".to_string(),
secret_type: "jwt_token".to_string(),
subject: Some("user123".to_string()),
operation: "validate".to_string(),
success: false,
error_message: Some("Token expired".to_string()),
timestamp: 1_234_567_895,
};
logger.log_entry(entry);
let logs = logger.get_logs();
assert!(!logs[0].success);
assert_eq!(logs[0].error_message, Some("Token expired".to_string()));
}
#[test]
fn test_denied_oidc_credential_access_logged() {
let logger = MockAuditLogger::new();
let entry = AuditLogEntry {
event_type: "oidc_credential_access".to_string(),
secret_type: "client_secret".to_string(),
subject: Some("service-account".to_string()),
operation: "retrieve".to_string(),
success: false,
error_message: Some("Unauthorized access".to_string()),
timestamp: 1_234_567_896,
};
logger.log_entry(entry);
let logs = logger.get_logs();
assert_eq!(logs.len(), 1);
assert!(!logs[0].success);
assert!(logs[0].error_message.is_some());
}
#[test]
fn test_audit_log_includes_subject_context() {
let logger = MockAuditLogger::new();
let entry = AuditLogEntry {
event_type: "jwt_validation".to_string(),
secret_type: "jwt_token".to_string(),
subject: Some("alice@example.com".to_string()),
operation: "validate".to_string(),
success: true,
error_message: None,
timestamp: 1_234_567_897,
};
logger.log_entry(entry);
let logs = logger.get_logs();
assert_eq!(logs[0].subject, Some("alice@example.com".to_string()));
}
#[test]
fn test_audit_log_subject_optional_for_anonymous() {
let logger = MockAuditLogger::new();
let entry = AuditLogEntry {
event_type: "public_key_fetch".to_string(),
secret_type: "public_key".to_string(),
subject: None,
operation: "retrieve".to_string(),
success: true,
error_message: None,
timestamp: 1_234_567_898,
};
logger.log_entry(entry);
let logs = logger.get_logs();
assert_eq!(logs[0].subject, None);
}
#[test]
fn test_multiple_operations_logged_in_sequence() {
let logger = MockAuditLogger::new();
let start_entry = AuditLogEntry {
event_type: "oauth_start".to_string(),
secret_type: "state_token".to_string(),
subject: Some("user123".to_string()),
operation: "create".to_string(),
success: true,
error_message: None,
timestamp: 1000,
};
let callback_entry = AuditLogEntry {
event_type: "oauth_callback".to_string(),
secret_type: "authorization_code".to_string(),
subject: Some("user123".to_string()),
operation: "verify".to_string(),
success: true,
error_message: None,
timestamp: 1001,
};
let exchange_entry = AuditLogEntry {
event_type: "token_exchange".to_string(),
secret_type: "access_token".to_string(),
subject: Some("user123".to_string()),
operation: "issue".to_string(),
success: true,
error_message: None,
timestamp: 1002,
};
logger.log_entry(start_entry);
logger.log_entry(callback_entry);
logger.log_entry(exchange_entry);
let logs = logger.get_logs();
assert_eq!(logs.len(), 3);
assert_eq!(logs[0].timestamp, 1000);
assert_eq!(logs[1].timestamp, 1001);
assert_eq!(logs[2].timestamp, 1002);
assert_eq!(logs[0].event_type, "oauth_start");
assert_eq!(logs[1].event_type, "oauth_callback");
assert_eq!(logs[2].event_type, "token_exchange");
}
#[test]
fn test_audit_log_clear_for_testing() {
let logger = MockAuditLogger::new();
let entry = AuditLogEntry {
event_type: "test_event".to_string(),
secret_type: "test_secret".to_string(),
subject: Some("test_user".to_string()),
operation: "test".to_string(),
success: true,
error_message: None,
timestamp: 1_234_567_899,
};
logger.log_entry(entry);
assert_eq!(logger.get_logs().len(), 1);
logger.clear();
assert_eq!(logger.get_logs().len(), 0);
}
#[test]
fn test_audit_log_with_very_long_error_message() {
let logger = MockAuditLogger::new();
let long_error = "a".repeat(1000);
let entry = AuditLogEntry {
event_type: "jwt_validation".to_string(),
secret_type: "jwt_token".to_string(),
subject: Some("user123".to_string()),
operation: "validate".to_string(),
success: false,
error_message: Some(long_error.clone()),
timestamp: 1_234_567_900,
};
logger.log_entry(entry);
let logs = logger.get_logs();
assert_eq!(logs[0].error_message.as_ref().unwrap().len(), 1000);
}
#[test]
fn test_audit_log_with_special_characters_in_subject() {
let logger = MockAuditLogger::new();
let entry = AuditLogEntry {
event_type: "jwt_validation".to_string(),
secret_type: "jwt_token".to_string(),
subject: Some("user+test@example.com".to_string()),
operation: "validate".to_string(),
success: true,
error_message: None,
timestamp: 1_234_567_901,
};
logger.log_entry(entry);
let logs = logger.get_logs();
assert_eq!(logs[0].subject, Some("user+test@example.com".to_string()));
}
#[test]
fn test_high_volume_audit_logging() {
let logger = MockAuditLogger::new();
for i in 0..1000 {
let entry = AuditLogEntry {
event_type: "test_event".to_string(),
secret_type: "test_secret".to_string(),
subject: Some(format!("user{}", i)),
operation: "test".to_string(),
success: i % 2 == 0,
error_message: if i % 2 == 0 {
None
} else {
Some("Test error".to_string())
},
timestamp: 1000 + i as u64,
};
logger.log_entry(entry);
}
let logs = logger.get_logs();
assert_eq!(logs.len(), 1000);
assert_eq!(logs[0].subject, Some("user0".to_string()));
assert_eq!(logs[999].subject, Some("user999".to_string()));
}
}