Skip to main content

oxigdal_security/audit/
events.rs

1//! Audit event definitions.
2
3use crate::audit::{AuditEventType, AuditLogEntry, AuditResult};
4use serde::{Deserialize, Serialize};
5
6/// Authentication event builder.
7pub struct AuthenticationEvent {
8    subject: String,
9    method: Option<String>,
10    result: AuditResult,
11    reason: Option<String>,
12}
13
14impl AuthenticationEvent {
15    /// Create new authentication event.
16    pub fn new(subject: String, result: AuditResult) -> Self {
17        Self {
18            subject,
19            method: None,
20            result,
21            reason: None,
22        }
23    }
24
25    /// Set authentication method.
26    pub fn with_method(mut self, method: String) -> Self {
27        self.method = Some(method);
28        self
29    }
30
31    /// Set failure reason.
32    pub fn with_reason(mut self, reason: String) -> Self {
33        self.reason = Some(reason);
34        self
35    }
36
37    /// Build audit log entry.
38    pub fn build(self) -> AuditLogEntry {
39        let mut entry = AuditLogEntry::new(AuditEventType::Authentication, self.result)
40            .with_subject(self.subject);
41
42        if let Some(method) = self.method {
43            entry = entry.with_metadata("method".to_string(), method);
44        }
45
46        if let Some(reason) = self.reason {
47            entry = entry.with_message(reason);
48        }
49
50        entry
51    }
52}
53
54/// Data access event builder.
55pub struct DataAccessEvent {
56    subject: String,
57    resource: String,
58    action: String,
59    result: AuditResult,
60    rows_accessed: Option<u64>,
61}
62
63impl DataAccessEvent {
64    /// Create new data access event.
65    pub fn new(subject: String, resource: String, action: String, result: AuditResult) -> Self {
66        Self {
67            subject,
68            resource,
69            action,
70            result,
71            rows_accessed: None,
72        }
73    }
74
75    /// Set rows accessed.
76    pub fn with_rows_accessed(mut self, count: u64) -> Self {
77        self.rows_accessed = Some(count);
78        self
79    }
80
81    /// Build audit log entry.
82    pub fn build(self) -> AuditLogEntry {
83        let mut entry = AuditLogEntry::new(AuditEventType::DataAccess, self.result)
84            .with_subject(self.subject)
85            .with_resource(self.resource)
86            .with_action(self.action);
87
88        if let Some(count) = self.rows_accessed {
89            entry = entry.with_metadata("rows_accessed".to_string(), count.to_string());
90        }
91
92        entry
93    }
94}
95
96/// Compliance event.
97#[derive(Debug, Clone, Serialize, Deserialize)]
98pub struct ComplianceEvent {
99    /// Event type.
100    pub event_type: String,
101    /// Regulation (GDPR, HIPAA, etc.).
102    pub regulation: String,
103    /// Subject.
104    pub subject: Option<String>,
105    /// Data subject (person whose data is involved).
106    pub data_subject: Option<String>,
107    /// Result.
108    pub result: AuditResult,
109    /// Details.
110    pub details: String,
111}
112
113impl ComplianceEvent {
114    /// Create new compliance event.
115    pub fn new(event_type: String, regulation: String, result: AuditResult) -> Self {
116        Self {
117            event_type,
118            regulation,
119            subject: None,
120            data_subject: None,
121            result,
122            details: String::new(),
123        }
124    }
125
126    /// Set subject.
127    pub fn with_subject(mut self, subject: String) -> Self {
128        self.subject = Some(subject);
129        self
130    }
131
132    /// Set data subject.
133    pub fn with_data_subject(mut self, data_subject: String) -> Self {
134        self.data_subject = Some(data_subject);
135        self
136    }
137
138    /// Set details.
139    pub fn with_details(mut self, details: String) -> Self {
140        self.details = details;
141        self
142    }
143
144    /// Build audit log entry.
145    pub fn build(self) -> AuditLogEntry {
146        let mut entry = AuditLogEntry::new(AuditEventType::Compliance, self.result)
147            .with_metadata("regulation".to_string(), self.regulation)
148            .with_metadata("event_type".to_string(), self.event_type)
149            .with_message(self.details);
150
151        if let Some(subject) = self.subject {
152            entry = entry.with_subject(subject);
153        }
154
155        if let Some(data_subject) = self.data_subject {
156            entry = entry.with_metadata("data_subject".to_string(), data_subject);
157        }
158
159        entry
160    }
161}
162
163#[cfg(test)]
164mod tests {
165    use super::*;
166
167    #[test]
168    fn test_authentication_event() {
169        let event = AuthenticationEvent::new("user-123".to_string(), AuditResult::Success)
170            .with_method("password".to_string())
171            .build();
172
173        assert_eq!(event.event_type, AuditEventType::Authentication);
174        assert_eq!(event.subject, Some("user-123".to_string()));
175        assert_eq!(event.metadata.get("method"), Some(&"password".to_string()));
176    }
177
178    #[test]
179    fn test_data_access_event() {
180        let event = DataAccessEvent::new(
181            "user-123".to_string(),
182            "dataset-456".to_string(),
183            "read".to_string(),
184            AuditResult::Success,
185        )
186        .with_rows_accessed(100)
187        .build();
188
189        assert_eq!(event.event_type, AuditEventType::DataAccess);
190        assert_eq!(
191            event.metadata.get("rows_accessed"),
192            Some(&"100".to_string())
193        );
194    }
195}