use crate::traits::{CircuitState, EndpointStats, EventBufferTrait, Priority};
use anyhow::{Context, Result};
use parking_lot::RwLock;
use serde::{Deserialize, Serialize};
use sha2::{Digest, Sha256};
use std::collections::HashMap;
use std::time::{Duration, Instant, SystemTime, UNIX_EPOCH};
#[derive(Debug, Clone, Serialize, Deserialize)]
pub enum SecurityEventType {
AuthSuccess {
client_id: String,
},
AuthFailure {
client_id: String,
reason: String,
},
TokenValidated {
client_id: String,
token_hash: String,
},
TokenExpired {
client_id: String,
},
MessageSigned {
client_id: String,
signature_hash: String,
},
SignatureVerified {
client_id: String,
valid: bool,
},
SignatureReplay {
client_id: String,
signature_hash: String,
},
RateLimitCheck {
client_id: String,
method: String,
allowed: bool,
},
RateLimitExceeded {
client_id: String,
method: String,
},
RateLimitPenalty {
client_id: String,
factor: f64,
},
RequestReceived {
client_id: String,
method: String,
request_id: String,
},
ResponseSent {
client_id: String,
method: String,
request_id: String,
duration_ms: u64,
},
ThreatDetected {
client_id: String,
threat_type: String,
severity: String,
},
CircuitOpened {
endpoint: String,
failure_count: u32,
},
CircuitClosed {
endpoint: String,
},
}
#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct SecurityEvent {
pub event_type: SecurityEventType,
pub timestamp: u64,
pub correlation_id: Option<String>,
pub metadata: Option<serde_json::Value>,
}
#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct EventProcessorConfig {
pub enabled: bool,
pub buffer_size_mb: usize,
pub max_endpoints: u32,
pub rate_limit: f64,
pub failure_threshold: u32,
pub retention_duration: Duration,
pub pattern_detection: bool,
pub correlation_enabled: bool,
pub enhanced_mode: Option<bool>,
}
impl Default for EventProcessorConfig {
fn default() -> Self {
Self {
enabled: false, buffer_size_mb: 20, max_endpoints: 1000,
rate_limit: 10000.0, failure_threshold: 5,
retention_duration: Duration::from_secs(3600), pattern_detection: true,
correlation_enabled: true,
enhanced_mode: None, }
}
}
pub struct SecurityEventProcessor {
config: EventProcessorConfig,
buffer: Option<Box<dyn EventBufferTrait>>,
endpoint_map: RwLock<HashMap<String, u32>>,
next_endpoint_id: RwLock<u32>,
}
#[derive(Debug, Clone)]
pub enum AttackPattern {
CredentialStuffing {
client_id: String,
attempts: u32,
},
TokenAbuse {
client_id: String,
reuse_count: u32,
},
RateLimitProbing {
client_id: String,
methods_tested: Vec<String>,
},
MultiStageAttack {
client_id: String,
stages: Vec<String>,
},
SignatureReplayAttack {
client_id: String,
replay_count: u32,
},
}
impl SecurityEventProcessor {
pub fn new(config: EventProcessorConfig) -> Result<Self> {
let buffer = if config.enabled {
crate::create_event_buffer(&config)?
} else {
None
};
Ok(Self {
config,
buffer,
endpoint_map: RwLock::new(HashMap::new()),
next_endpoint_id: RwLock::new(0),
})
}
pub fn track_event(&self, event: SecurityEvent) -> Result<()> {
if !self.config.enabled {
return Ok(()); }
let buffer = match &self.buffer {
Some(b) => b,
None => return Ok(()), };
let endpoint = match &event.event_type {
SecurityEventType::AuthSuccess { client_id, .. }
| SecurityEventType::AuthFailure { client_id, .. }
| SecurityEventType::TokenValidated { client_id, .. }
| SecurityEventType::TokenExpired { client_id } => {
format!("auth:{client_id}")
},
SecurityEventType::MessageSigned { client_id, .. }
| SecurityEventType::SignatureVerified { client_id, .. }
| SecurityEventType::SignatureReplay { client_id, .. } => {
format!("signing:{client_id}")
},
SecurityEventType::RateLimitCheck {
client_id, method, ..
}
| SecurityEventType::RateLimitExceeded { client_id, method } => {
format!("ratelimit:{client_id}:{method}")
},
SecurityEventType::RateLimitPenalty { client_id, .. } => {
format!("ratelimit:{client_id}")
},
SecurityEventType::RequestReceived {
client_id, method, ..
}
| SecurityEventType::ResponseSent {
client_id, method, ..
} => {
format!("mcp:{client_id}:{method}")
},
SecurityEventType::ThreatDetected { client_id, .. } => {
format!("threat:{client_id}")
},
SecurityEventType::CircuitOpened { endpoint, .. }
| SecurityEventType::CircuitClosed { endpoint } => endpoint.clone(),
};
let priority = match &event.event_type {
SecurityEventType::ThreatDetected { .. } => Priority::Urgent,
SecurityEventType::AuthFailure { .. }
| SecurityEventType::SignatureReplay { .. }
| SecurityEventType::RateLimitExceeded { .. } => Priority::Urgent,
SecurityEventType::CircuitOpened { .. } => Priority::Normal,
_ => Priority::Normal,
};
let data = serde_json::to_vec(&event).context("Failed to serialize security event")?;
let endpoint_id = self.get_or_create_endpoint_id(&endpoint)?;
let _handle = buffer
.enqueue_event(endpoint_id, &data, priority)
.map_err(|e| anyhow::anyhow!("Failed to enqueue event: {:?}", e))?;
if self.config.pattern_detection {
self.detect_patterns(&event)?;
}
Ok(())
}
fn get_or_create_endpoint_id(&self, endpoint: &str) -> Result<u32> {
let mut map = self.endpoint_map.write();
if let Some(&id) = map.get(endpoint) {
Ok(id)
} else {
let mut next_id = self.next_endpoint_id.write();
let id = *next_id;
*next_id += 1;
if id >= self.config.max_endpoints {
anyhow::bail!("Maximum endpoints exceeded");
}
map.insert(endpoint.to_string(), id);
Ok(id)
}
}
pub fn get_endpoint_stats(&self, endpoint: &str) -> Option<EndpointStats> {
let map = self.endpoint_map.read();
let endpoint_id = *map.get(endpoint)?;
self.buffer
.as_ref()?
.get_endpoint_stats(endpoint_id)
.map_err(|e| {
tracing::debug!("Failed to get endpoint stats: {:?}", e);
e
})
.ok()
}
pub fn is_monitored(&self, client_id: &str) -> bool {
if self.buffer.is_some() {
let endpoints = vec![
format!("auth:{}", client_id),
format!("threat:{}", client_id),
format!("ratelimit:{}", client_id),
];
let map = self.endpoint_map.read();
for endpoint in endpoints {
if let Some(&_endpoint_id) = map.get(&endpoint) {
if let Some(stats) = self.get_endpoint_stats(&endpoint) {
if matches!(stats.circuit_state, CircuitState::Open) {
return true;
}
if stats.available_tokens == 0 {
return true;
}
}
}
}
}
false
}
const fn detect_patterns(&self, _event: &SecurityEvent) -> Result<Option<AttackPattern>> {
Ok(None)
}
pub fn auth_event(client_id: &str, success: bool, reason: Option<&str>) -> SecurityEvent {
let event_type = if success {
SecurityEventType::AuthSuccess {
client_id: client_id.to_string(),
}
} else {
SecurityEventType::AuthFailure {
client_id: client_id.to_string(),
reason: reason.unwrap_or("unknown").to_string(),
}
};
SecurityEvent {
event_type,
timestamp: SystemTime::now()
.duration_since(UNIX_EPOCH)
.unwrap_or_default()
.as_secs(),
correlation_id: None,
metadata: None,
}
}
pub fn signature_event(client_id: &str, signature: &str, valid: bool) -> SecurityEvent {
let mut hasher = Sha256::new();
hasher.update(signature.as_bytes());
let signature_hash = format!("{:x}", hasher.finalize());
let event_type = if valid {
SecurityEventType::SignatureVerified {
client_id: client_id.to_string(),
valid: true,
}
} else {
SecurityEventType::SignatureReplay {
client_id: client_id.to_string(),
signature_hash,
}
};
SecurityEvent {
event_type,
timestamp: SystemTime::now()
.duration_since(UNIX_EPOCH)
.unwrap_or_default()
.as_secs(),
correlation_id: None,
metadata: None,
}
}
pub fn rate_limit_event(client_id: &str, method: &str, allowed: bool) -> SecurityEvent {
let event_type = if allowed {
SecurityEventType::RateLimitCheck {
client_id: client_id.to_string(),
method: method.to_string(),
allowed: true,
}
} else {
SecurityEventType::RateLimitExceeded {
client_id: client_id.to_string(),
method: method.to_string(),
}
};
SecurityEvent {
event_type,
timestamp: SystemTime::now()
.duration_since(UNIX_EPOCH)
.unwrap_or_default()
.as_secs(),
correlation_id: None,
metadata: None,
}
}
pub fn request_event(client_id: &str, method: &str, request_id: &str) -> SecurityEvent {
SecurityEvent {
event_type: SecurityEventType::RequestReceived {
client_id: client_id.to_string(),
method: method.to_string(),
request_id: request_id.to_string(),
},
timestamp: SystemTime::now()
.duration_since(UNIX_EPOCH)
.unwrap_or_default()
.as_secs(),
correlation_id: Some(request_id.to_string()),
metadata: None,
}
}
pub fn is_enabled(&self) -> bool {
self.config.enabled && self.buffer.is_some()
}
}
pub struct SimpleEventBuffer {
}
impl Default for SimpleEventBuffer {
fn default() -> Self {
Self::new()
}
}
impl SimpleEventBuffer {
pub const fn new() -> Self {
Self {}
}
}
impl EventBufferTrait for SimpleEventBuffer {
fn enqueue_event(&self, _endpoint_id: u32, _data: &[u8], _priority: Priority) -> Result<u64> {
Ok(0) }
fn get_endpoint_stats(&self, _endpoint_id: u32) -> Result<EndpointStats> {
Ok(EndpointStats {
success_count: 0,
failure_count: 0,
circuit_state: CircuitState::Closed,
available_tokens: 100,
})
}
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn test_event_processor_creation() {
let config = EventProcessorConfig::default();
let processor = SecurityEventProcessor::new(config).unwrap();
assert!(!processor.is_enabled()); }
#[test]
fn test_event_tracking() {
let mut config = EventProcessorConfig::default();
config.enabled = true;
let processor = SecurityEventProcessor::new(config).unwrap();
let event = SecurityEventProcessor::auth_event("test-client", true, None);
processor.track_event(event).unwrap();
}
}