mockforge_core/security/
events.rs

1//! Security event definitions for MockForge
2//!
3//! This module defines all security events that can be emitted by MockForge for SIEM integration
4//! and compliance monitoring. Events are categorized by type (authentication, authorization, access
5//! management, configuration, data, security, compliance) and include compliance mapping for
6//! SOC 2 and ISO 27001.
7
8use chrono::{DateTime, Utc};
9use serde::{Deserialize, Serialize};
10use std::collections::HashMap;
11
12/// Security event severity levels
13#[derive(Debug, Clone, Copy, PartialEq, Eq, Serialize, Deserialize)]
14#[serde(rename_all = "lowercase")]
15pub enum SecurityEventSeverity {
16    /// Low severity - informational events
17    Low,
18    /// Medium severity - events requiring attention
19    Medium,
20    /// High severity - security concerns
21    High,
22    /// Critical severity - immediate security threats
23    Critical,
24}
25
26/// Security event type categories
27#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)]
28#[serde(rename_all = "snake_case")]
29pub enum SecurityEventType {
30    // Authentication events
31    /// Successful authentication
32    AuthSuccess,
33    /// Failed authentication attempt
34    AuthFailure,
35    /// Token expiration
36    AuthTokenExpired,
37    /// Token revocation
38    AuthTokenRevoked,
39    /// Multi-factor authentication enabled
40    AuthMfaEnabled,
41    /// Multi-factor authentication disabled
42    AuthMfaDisabled,
43    /// Password change
44    AuthPasswordChanged,
45    /// Password reset
46    AuthPasswordReset,
47
48    // Authorization events
49    /// Access granted
50    AuthzAccessGranted,
51    /// Access denied
52    AuthzAccessDenied,
53    /// Privilege escalation
54    AuthzPrivilegeEscalation,
55    /// Role change
56    AuthzRoleChanged,
57    /// Permission change
58    AuthzPermissionChanged,
59
60    // Access management events
61    /// User account created
62    AccessUserCreated,
63    /// User account deleted
64    AccessUserDeleted,
65    /// User account suspended
66    AccessUserSuspended,
67    /// User account activated
68    AccessUserActivated,
69    /// API token created
70    AccessApiTokenCreated,
71    /// API token deleted
72    AccessApiTokenDeleted,
73    /// API token rotated
74    AccessApiTokenRotated,
75
76    // Configuration events
77    /// Configuration changed
78    ConfigChanged,
79    /// Security policy updated
80    ConfigSecurityPolicyUpdated,
81    /// Encryption key rotated
82    ConfigEncryptionKeyRotated,
83    /// TLS certificate updated
84    ConfigTlsCertificateUpdated,
85
86    // Data events
87    /// Data exported
88    DataExported,
89    /// Data deleted
90    DataDeleted,
91    /// Data encrypted
92    DataEncrypted,
93    /// Data decrypted
94    DataDecrypted,
95    /// Data classified
96    DataClassified,
97
98    // Security events
99    /// Vulnerability detected
100    SecurityVulnerabilityDetected,
101    /// Threat detected
102    SecurityThreatDetected,
103    /// Anomaly detected
104    SecurityAnomalyDetected,
105    /// Rate limit exceeded
106    SecurityRateLimitExceeded,
107    /// Suspicious activity detected
108    SecuritySuspiciousActivity,
109
110    // Compliance events
111    /// Audit log accessed
112    ComplianceAuditLogAccessed,
113    /// Compliance check performed
114    ComplianceComplianceCheck,
115    /// Policy violation detected
116    CompliancePolicyViolation,
117}
118
119impl SecurityEventType {
120    /// Get the event type string identifier (e.g., "auth.success")
121    pub fn as_str(&self) -> &'static str {
122        match self {
123            SecurityEventType::AuthSuccess => "auth.success",
124            SecurityEventType::AuthFailure => "auth.failure",
125            SecurityEventType::AuthTokenExpired => "auth.token_expired",
126            SecurityEventType::AuthTokenRevoked => "auth.token_revoked",
127            SecurityEventType::AuthMfaEnabled => "auth.mfa_enabled",
128            SecurityEventType::AuthMfaDisabled => "auth.mfa_disabled",
129            SecurityEventType::AuthPasswordChanged => "auth.password_changed",
130            SecurityEventType::AuthPasswordReset => "auth.password_reset",
131            SecurityEventType::AuthzAccessGranted => "authz.access_granted",
132            SecurityEventType::AuthzAccessDenied => "authz.access_denied",
133            SecurityEventType::AuthzPrivilegeEscalation => "authz.privilege_escalation",
134            SecurityEventType::AuthzRoleChanged => "authz.role_changed",
135            SecurityEventType::AuthzPermissionChanged => "authz.permission_changed",
136            SecurityEventType::AccessUserCreated => "access.user_created",
137            SecurityEventType::AccessUserDeleted => "access.user_deleted",
138            SecurityEventType::AccessUserSuspended => "access.user_suspended",
139            SecurityEventType::AccessUserActivated => "access.user_activated",
140            SecurityEventType::AccessApiTokenCreated => "access.api_token_created",
141            SecurityEventType::AccessApiTokenDeleted => "access.api_token_deleted",
142            SecurityEventType::AccessApiTokenRotated => "access.api_token_rotated",
143            SecurityEventType::ConfigChanged => "config.changed",
144            SecurityEventType::ConfigSecurityPolicyUpdated => "config.security_policy_updated",
145            SecurityEventType::ConfigEncryptionKeyRotated => "config.encryption_key_rotated",
146            SecurityEventType::ConfigTlsCertificateUpdated => "config.tls_certificate_updated",
147            SecurityEventType::DataExported => "data.exported",
148            SecurityEventType::DataDeleted => "data.deleted",
149            SecurityEventType::DataEncrypted => "data.encrypted",
150            SecurityEventType::DataDecrypted => "data.decrypted",
151            SecurityEventType::DataClassified => "data.classified",
152            SecurityEventType::SecurityVulnerabilityDetected => "security.vulnerability_detected",
153            SecurityEventType::SecurityThreatDetected => "security.threat_detected",
154            SecurityEventType::SecurityAnomalyDetected => "security.anomaly_detected",
155            SecurityEventType::SecurityRateLimitExceeded => "security.rate_limit_exceeded",
156            SecurityEventType::SecuritySuspiciousActivity => "security.suspicious_activity",
157            SecurityEventType::ComplianceAuditLogAccessed => "compliance.audit_log_accessed",
158            SecurityEventType::ComplianceComplianceCheck => "compliance.compliance_check",
159            SecurityEventType::CompliancePolicyViolation => "compliance.policy_violation",
160        }
161    }
162
163    /// Get the default severity for this event type
164    pub fn default_severity(&self) -> SecurityEventSeverity {
165        match self {
166            SecurityEventType::AuthSuccess
167            | SecurityEventType::AuthzAccessGranted
168            | SecurityEventType::AccessUserCreated
169            | SecurityEventType::AccessUserActivated
170            | SecurityEventType::AccessApiTokenCreated
171            | SecurityEventType::AuthMfaEnabled
172            | SecurityEventType::DataEncrypted
173            | SecurityEventType::DataClassified
174            | SecurityEventType::ComplianceComplianceCheck => SecurityEventSeverity::Low,
175
176            SecurityEventType::AuthFailure
177            | SecurityEventType::AuthTokenExpired
178            | SecurityEventType::AuthTokenRevoked
179            | SecurityEventType::AuthMfaDisabled
180            | SecurityEventType::AuthPasswordChanged
181            | SecurityEventType::AuthPasswordReset
182            | SecurityEventType::AuthzAccessDenied
183            | SecurityEventType::AuthzRoleChanged
184            | SecurityEventType::AuthzPermissionChanged
185            | SecurityEventType::AccessUserSuspended
186            | SecurityEventType::AccessApiTokenDeleted
187            | SecurityEventType::ConfigChanged
188            | SecurityEventType::DataExported
189            | SecurityEventType::DataDeleted
190            | SecurityEventType::SecurityRateLimitExceeded
191            | SecurityEventType::ComplianceAuditLogAccessed => SecurityEventSeverity::Medium,
192
193            SecurityEventType::AuthzPrivilegeEscalation
194            | SecurityEventType::AccessUserDeleted
195            | SecurityEventType::AccessApiTokenRotated
196            | SecurityEventType::ConfigSecurityPolicyUpdated
197            | SecurityEventType::ConfigEncryptionKeyRotated
198            | SecurityEventType::ConfigTlsCertificateUpdated
199            | SecurityEventType::DataDecrypted
200            | SecurityEventType::SecurityThreatDetected
201            | SecurityEventType::SecurityAnomalyDetected
202            | SecurityEventType::SecuritySuspiciousActivity
203            | SecurityEventType::CompliancePolicyViolation => SecurityEventSeverity::High,
204
205            SecurityEventType::SecurityVulnerabilityDetected => SecurityEventSeverity::Critical,
206        }
207    }
208
209    /// Get SOC 2 Common Criteria mappings for this event type
210    pub fn soc2_cc(&self) -> Vec<&'static str> {
211        match self {
212            SecurityEventType::AuthSuccess
213            | SecurityEventType::AuthFailure
214            | SecurityEventType::AuthTokenExpired
215            | SecurityEventType::AuthTokenRevoked
216            | SecurityEventType::AuthMfaEnabled
217            | SecurityEventType::AuthMfaDisabled
218            | SecurityEventType::AuthPasswordChanged
219            | SecurityEventType::AuthPasswordReset
220            | SecurityEventType::AccessUserCreated
221            | SecurityEventType::AccessUserDeleted
222            | SecurityEventType::AccessUserSuspended
223            | SecurityEventType::AccessUserActivated
224            | SecurityEventType::AccessApiTokenCreated
225            | SecurityEventType::AccessApiTokenDeleted
226            | SecurityEventType::AccessApiTokenRotated
227            | SecurityEventType::AuthzPrivilegeEscalation
228            | SecurityEventType::AuthzRoleChanged
229            | SecurityEventType::AuthzPermissionChanged => vec!["CC6"],
230
231            SecurityEventType::AuthzAccessGranted | SecurityEventType::AuthzAccessDenied => {
232                vec!["CC6"]
233            }
234
235            SecurityEventType::ConfigChanged
236            | SecurityEventType::ConfigSecurityPolicyUpdated
237            | SecurityEventType::ConfigEncryptionKeyRotated
238            | SecurityEventType::ConfigTlsCertificateUpdated => vec!["CC7"],
239
240            SecurityEventType::DataExported
241            | SecurityEventType::DataDeleted
242            | SecurityEventType::DataEncrypted
243            | SecurityEventType::DataDecrypted
244            | SecurityEventType::DataClassified
245            | SecurityEventType::SecurityVulnerabilityDetected
246            | SecurityEventType::SecurityThreatDetected
247            | SecurityEventType::SecurityAnomalyDetected
248            | SecurityEventType::SecurityRateLimitExceeded
249            | SecurityEventType::SecuritySuspiciousActivity
250            | SecurityEventType::ComplianceAuditLogAccessed
251            | SecurityEventType::ComplianceComplianceCheck
252            | SecurityEventType::CompliancePolicyViolation => vec!["CC4"],
253        }
254    }
255
256    /// Get ISO 27001 control mappings for this event type
257    pub fn iso27001(&self) -> Vec<&'static str> {
258        match self {
259            SecurityEventType::AuthSuccess
260            | SecurityEventType::AuthFailure
261            | SecurityEventType::AuthTokenExpired
262            | SecurityEventType::AuthTokenRevoked
263            | SecurityEventType::AuthMfaEnabled
264            | SecurityEventType::AuthMfaDisabled
265            | SecurityEventType::AuthPasswordChanged
266            | SecurityEventType::AuthPasswordReset
267            | SecurityEventType::AccessUserCreated
268            | SecurityEventType::AccessUserDeleted
269            | SecurityEventType::AccessUserSuspended
270            | SecurityEventType::AccessUserActivated
271            | SecurityEventType::AccessApiTokenCreated
272            | SecurityEventType::AccessApiTokenDeleted
273            | SecurityEventType::AccessApiTokenRotated
274            | SecurityEventType::AuthzPrivilegeEscalation
275            | SecurityEventType::AuthzRoleChanged
276            | SecurityEventType::AuthzPermissionChanged => vec!["A.9.2"],
277
278            SecurityEventType::AuthzAccessGranted | SecurityEventType::AuthzAccessDenied => {
279                vec!["A.9.4"]
280            }
281
282            SecurityEventType::ConfigChanged
283            | SecurityEventType::ConfigSecurityPolicyUpdated
284            | SecurityEventType::ConfigEncryptionKeyRotated
285            | SecurityEventType::ConfigTlsCertificateUpdated => vec!["A.12.1"],
286
287            SecurityEventType::DataExported
288            | SecurityEventType::DataDeleted
289            | SecurityEventType::DataEncrypted
290            | SecurityEventType::DataDecrypted
291            | SecurityEventType::DataClassified
292            | SecurityEventType::SecurityVulnerabilityDetected
293            | SecurityEventType::SecurityThreatDetected
294            | SecurityEventType::SecurityAnomalyDetected
295            | SecurityEventType::SecurityRateLimitExceeded
296            | SecurityEventType::SecuritySuspiciousActivity
297            | SecurityEventType::ComplianceAuditLogAccessed
298            | SecurityEventType::ComplianceComplianceCheck
299            | SecurityEventType::CompliancePolicyViolation => vec!["A.12.4"],
300        }
301    }
302}
303
304/// Source information for a security event
305#[derive(Debug, Clone, Serialize, Deserialize)]
306pub struct EventSource {
307    /// System name (e.g., "mockforge")
308    pub system: String,
309    /// Component name (e.g., "auth", "api")
310    pub component: String,
311    /// System version
312    pub version: String,
313}
314
315impl Default for EventSource {
316    fn default() -> Self {
317        Self {
318            system: "mockforge".to_string(),
319            component: "core".to_string(),
320            version: env!("CARGO_PKG_VERSION").to_string(),
321        }
322    }
323}
324
325/// Actor information for a security event (who performed the action)
326#[derive(Debug, Clone, Serialize, Deserialize)]
327pub struct EventActor {
328    /// User identifier
329    pub user_id: Option<String>,
330    /// Username
331    pub username: Option<String>,
332    /// IP address
333    pub ip_address: Option<String>,
334    /// User agent
335    pub user_agent: Option<String>,
336}
337
338/// Target resource information for a security event
339#[derive(Debug, Clone, Serialize, Deserialize)]
340pub struct EventTarget {
341    /// Resource type (e.g., "api", "workspace", "user")
342    pub resource_type: Option<String>,
343    /// Resource identifier
344    pub resource_id: Option<String>,
345    /// HTTP method (if applicable)
346    pub method: Option<String>,
347}
348
349/// Outcome information for a security event
350#[derive(Debug, Clone, Serialize, Deserialize)]
351pub struct EventOutcome {
352    /// Whether the action was successful
353    pub success: bool,
354    /// Reason for success or failure
355    pub reason: Option<String>,
356}
357
358/// Compliance mapping for a security event
359#[derive(Debug, Clone, Serialize, Deserialize)]
360pub struct EventCompliance {
361    /// SOC 2 Common Criteria
362    pub soc2_cc: Vec<String>,
363    /// ISO 27001 controls
364    pub iso27001: Vec<String>,
365}
366
367/// Security event structure
368#[derive(Debug, Clone, Serialize, Deserialize)]
369pub struct SecurityEvent {
370    /// Event timestamp (ISO 8601)
371    pub timestamp: DateTime<Utc>,
372    /// Event type identifier (e.g., "auth.failure")
373    pub event_type: String,
374    /// Event severity
375    pub severity: SecurityEventSeverity,
376    /// Source information
377    pub source: EventSource,
378    /// Actor information (who performed the action)
379    pub actor: Option<EventActor>,
380    /// Target resource information
381    pub target: Option<EventTarget>,
382    /// Outcome information
383    pub outcome: Option<EventOutcome>,
384    /// Additional metadata
385    pub metadata: HashMap<String, serde_json::Value>,
386    /// Compliance mappings
387    pub compliance: EventCompliance,
388}
389
390impl SecurityEvent {
391    /// Create a new security event
392    pub fn new(
393        event_type: SecurityEventType,
394        severity: Option<SecurityEventSeverity>,
395        source: Option<EventSource>,
396    ) -> Self {
397        let default_severity = event_type.default_severity();
398        let severity = severity.unwrap_or(default_severity);
399
400        Self {
401            timestamp: Utc::now(),
402            event_type: event_type.as_str().to_string(),
403            severity,
404            source: source.unwrap_or_default(),
405            actor: None,
406            target: None,
407            outcome: None,
408            metadata: HashMap::new(),
409            compliance: EventCompliance {
410                soc2_cc: event_type.soc2_cc().iter().map(|s| s.to_string()).collect(),
411                iso27001: event_type.iso27001().iter().map(|s| s.to_string()).collect(),
412            },
413        }
414    }
415
416    /// Set the actor information
417    pub fn with_actor(mut self, actor: EventActor) -> Self {
418        self.actor = Some(actor);
419        self
420    }
421
422    /// Set the target resource information
423    pub fn with_target(mut self, target: EventTarget) -> Self {
424        self.target = Some(target);
425        self
426    }
427
428    /// Set the outcome information
429    pub fn with_outcome(mut self, outcome: EventOutcome) -> Self {
430        self.outcome = Some(outcome);
431        self
432    }
433
434    /// Add metadata key-value pair
435    pub fn with_metadata(mut self, key: String, value: serde_json::Value) -> Self {
436        self.metadata.insert(key, value);
437        self
438    }
439
440    /// Convert to JSON string
441    pub fn to_json(&self) -> Result<String, serde_json::Error> {
442        serde_json::to_string(self)
443    }
444
445    /// Convert to JSON value
446    pub fn to_json_value(&self) -> serde_json::Value {
447        serde_json::to_value(self).unwrap_or_default()
448    }
449}
450
451#[cfg(test)]
452mod tests {
453    use super::*;
454
455    #[test]
456    fn test_event_type_strings() {
457        assert_eq!(SecurityEventType::AuthSuccess.as_str(), "auth.success");
458        assert_eq!(SecurityEventType::AuthFailure.as_str(), "auth.failure");
459        assert_eq!(
460            SecurityEventType::AuthzPrivilegeEscalation.as_str(),
461            "authz.privilege_escalation"
462        );
463    }
464
465    #[test]
466    fn test_event_severity() {
467        assert_eq!(SecurityEventType::AuthSuccess.default_severity(), SecurityEventSeverity::Low);
468        assert_eq!(
469            SecurityEventType::AuthFailure.default_severity(),
470            SecurityEventSeverity::Medium
471        );
472        assert_eq!(
473            SecurityEventType::AuthzPrivilegeEscalation.default_severity(),
474            SecurityEventSeverity::High
475        );
476        assert_eq!(
477            SecurityEventType::SecurityVulnerabilityDetected.default_severity(),
478            SecurityEventSeverity::Critical
479        );
480    }
481
482    #[test]
483    fn test_compliance_mappings() {
484        let auth_success = SecurityEventType::AuthSuccess;
485        assert!(auth_success.soc2_cc().contains(&"CC6"));
486        assert!(auth_success.iso27001().contains(&"A.9.2"));
487
488        let config_changed = SecurityEventType::ConfigChanged;
489        assert!(config_changed.soc2_cc().contains(&"CC7"));
490        assert!(config_changed.iso27001().contains(&"A.12.1"));
491    }
492
493    #[test]
494    fn test_security_event_creation() {
495        let event = SecurityEvent::new(SecurityEventType::AuthSuccess, None, None);
496        assert_eq!(event.event_type, "auth.success");
497        assert_eq!(event.severity, SecurityEventSeverity::Low);
498        assert_eq!(event.source.system, "mockforge");
499    }
500
501    #[test]
502    fn test_security_event_builder() {
503        let event = SecurityEvent::new(SecurityEventType::AuthFailure, None, None)
504            .with_actor(EventActor {
505                user_id: Some("user-123".to_string()),
506                username: Some("admin".to_string()),
507                ip_address: Some("192.168.1.100".to_string()),
508                user_agent: Some("Mozilla/5.0".to_string()),
509            })
510            .with_target(EventTarget {
511                resource_type: Some("api".to_string()),
512                resource_id: Some("/api/v1/workspaces".to_string()),
513                method: Some("GET".to_string()),
514            })
515            .with_outcome(EventOutcome {
516                success: false,
517                reason: Some("Invalid credentials".to_string()),
518            })
519            .with_metadata("attempt_count".to_string(), serde_json::json!(3));
520
521        assert_eq!(event.event_type, "auth.failure");
522        assert!(event.actor.is_some());
523        assert!(event.target.is_some());
524        assert!(event.outcome.is_some());
525        assert_eq!(event.metadata.get("attempt_count"), Some(&serde_json::json!(3)));
526    }
527
528    #[test]
529    fn test_security_event_serialization() {
530        let event = SecurityEvent::new(SecurityEventType::AuthSuccess, None, None);
531        let json = event.to_json().unwrap();
532        assert!(json.contains("auth.success"));
533        assert!(json.contains("mockforge"));
534    }
535}