pub mod auth;
pub mod rate_limit;
pub mod validation;
pub mod encryption;
pub mod audit;
pub mod abuse_detection;
pub mod quotas;
pub mod config;
pub mod headers;
pub mod vulnerability;
pub mod monitoring;
pub mod middleware;
pub mod session;
pub use auth::{
AuthenticationService, AuthorizationService, ApiKeyAuth, JwtAuth,
OAuth2Auth, TotpAuth, WebAuthnAuth, AuthProvider, AuthConfig,
Credentials, AuthResult, Permission, Role, User, Session,
AuthenticationError, AuthorizationError
};
pub use rate_limit::{
RateLimiter, RateLimitStrategy, RateLimitConfig, RateLimitResult,
TokenBucket, SlidingWindow, FixedWindow, LeakyBucket,
RateLimitStore, InMemoryRateLimitStore, RedisRateLimitStore,
RateLimitKey, RateLimitError, RateLimitInfo, RateLimitQuota
};
pub use validation::{
InputValidator, ValidationRule, ValidationResult, ValidationError,
Sanitizer, SanitizationRule, SanitizationResult,
RequestValidator, ResponseValidator, SchemaValidator,
XssProtection, SqlInjectionProtection, PathTraversalProtection,
ContentSecurityPolicy, ValidationConfig
};
pub use encryption::{
EncryptionService, EncryptionConfig, EncryptionAlgorithm,
RequestEncryption, ResponseEncryption, DataProtection,
KeyManager, EncryptionKey, DecryptionKey, CryptoProvider,
Aes256Gcm, ChaCha20Poly1305, EncryptionError, DecryptionError
};
pub use audit::{
AuditLogger, AuditEvent, AuditLevel, AuditConfig, AuditResult,
SecurityEvent, AuthenticationEvent, AuthorizationEvent,
RateLimitEvent, ValidationEvent, AbuseDetectionEvent,
AuditStorage, FileAuditStorage, DatabaseAuditStorage,
AuditQuery, AuditReport, AuditAnalytics
};
pub use abuse_detection::{
AbuseDetector, AbuseDetectionConfig, AbusePattern, AbuseRule,
AnomalyDetector, BehaviorAnalyzer, ThreatIntelligence,
IpReputation, GeoLocation, DeviceFingerprinting,
BotDetection, CaptchaChallenge, AbuseResponse, AbuseMetrics
};
pub use quotas::{
QuotaManager, QuotaConfig, QuotaLimit, QuotaUsage, QuotaResult,
ResourceQuota, UserQuota, ApiQuota, TimeWindowQuota,
QuotaEnforcer, QuotaStorage, QuotaMetrics, ThrottleManager,
QueueManager, BackpressureController
};
pub use config::{
SecurityConfig, SecurityConfigBuilder, ConfigValidator,
SecureConfigManager, ConfigEncryption, EnvironmentConfig,
VaultIntegration, SecretsManager, ConfigAudit, ConfigVersioning
};
pub use headers::{
SecurityHeaders, SecurityHeadersConfig, CorsConfig, CorsPolicy,
ContentSecurityPolicyBuilder, HstsConfig, XFrameOptions,
XContentTypeOptions, ReferrerPolicy, PermissionsPolicy,
CrossOriginPolicy, SecurityHeadersMiddleware
};
pub use vulnerability::{
VulnerabilityScanner, SecurityAssessment, PenetrationTesting,
DependencyScanner, CodeAnalyzer, ConfigurationReview,
ThreatModeling, RiskAssessment, ComplianceChecker,
SecurityReport, VulnerabilityReport, RemediationPlan
};
pub use monitoring::{
SecurityMonitor, SecurityMetrics, SecurityDashboard,
ThreatDetection, IncidentResponse, AlertManager,
SecurityAnalytics, RealTimeMonitoring, ComplianceMonitoring,
SecurityKpi, ThreatIntelligenceFeed, SiemIntegration
};
pub use middleware::{
SecurityMiddleware, AuthMiddleware, RateLimitMiddleware,
ValidationMiddleware, AuditMiddleware, EncryptionMiddleware,
HeadersMiddleware, SecurityStack, MiddlewareChain
};
pub use session::{
SessionManager, SessionStore, SessionConfig, SessionSecurity,
SessionToken, SessionData, SessionValidator, SessionCleaner,
DistributedSessionStore, SessionReplication, SessionBackup
};
use crate::{RragError, RragResult};
use async_trait::async_trait;
use serde::{Deserialize, Serialize};
use std::collections::HashMap;
use std::sync::Arc;
use tokio::sync::RwLock;
use uuid::Uuid;
#[derive(Clone)]
pub struct SecurityService {
auth_service: Arc<AuthenticationService>,
authz_service: Arc<AuthorizationService>,
rate_limiter: Arc<dyn RateLimiter>,
input_validator: Arc<InputValidator>,
encryption_service: Arc<EncryptionService>,
audit_logger: Arc<AuditLogger>,
abuse_detector: Arc<AbuseDetector>,
quota_manager: Arc<QuotaManager>,
security_config: Arc<SecurityConfig>,
session_manager: Arc<SessionManager>,
monitor: Arc<SecurityMonitor>,
config: SecurityServiceConfig,
}
#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct SecurityServiceConfig {
pub enable_auth: bool,
pub enable_rate_limiting: bool,
pub enable_validation: bool,
pub enable_encryption: bool,
pub enable_audit: bool,
pub enable_abuse_detection: bool,
pub enable_quotas: bool,
pub enable_sessions: bool,
pub enable_monitoring: bool,
pub security_level: u8,
pub fips_mode: bool,
}
impl Default for SecurityServiceConfig {
fn default() -> Self {
Self {
enable_auth: true,
enable_rate_limiting: true,
enable_validation: true,
enable_encryption: false,
enable_audit: true,
enable_abuse_detection: true,
enable_quotas: true,
enable_sessions: true,
enable_monitoring: true,
security_level: 3,
fips_mode: false,
}
}
}
#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct SecurityContext {
pub request_id: Uuid,
pub user: Option<User>,
pub session: Option<Session>,
pub client_ip: Option<String>,
pub user_agent: Option<String>,
pub timestamp: chrono::DateTime<chrono::Utc>,
pub security_labels: HashMap<String, String>,
pub risk_score: f32,
pub auth_method: Option<String>,
pub rate_limit_info: Option<RateLimitInfo>,
pub validation_results: Vec<ValidationResult>,
}
impl SecurityContext {
pub fn new() -> Self {
Self {
request_id: Uuid::new_v4(),
user: None,
session: None,
client_ip: None,
user_agent: None,
timestamp: chrono::Utc::now(),
security_labels: HashMap::new(),
risk_score: 0.0,
auth_method: None,
rate_limit_info: None,
validation_results: Vec::new(),
}
}
pub fn is_authenticated(&self) -> bool {
self.user.is_some()
}
pub fn has_valid_session(&self) -> bool {
self.session.as_ref().map_or(false, |s| !s.is_expired())
}
pub fn user_id(&self) -> Option<&str> {
self.user.as_ref().map(|u| u.id.as_str())
}
pub fn add_label(&mut self, key: String, value: String) {
self.security_labels.insert(key, value);
}
pub fn update_risk_score(&mut self, score: f32) {
self.risk_score = score.clamp(0.0, 1.0);
}
pub fn is_high_risk(&self, threshold: f32) -> bool {
self.risk_score > threshold
}
}
impl Default for SecurityContext {
fn default() -> Self {
Self::new()
}
}
#[derive(Debug, Clone, PartialEq, Eq)]
pub enum SecurityDecision {
Allow,
Deny { reason: String },
Challenge { challenge_type: String },
Throttle { delay_ms: u64 },
}
impl SecurityDecision {
pub fn is_allowed(&self) -> bool {
matches!(self, SecurityDecision::Allow)
}
pub fn is_denied(&self) -> bool {
matches!(self, SecurityDecision::Deny { .. })
}
pub fn requires_challenge(&self) -> bool {
matches!(self, SecurityDecision::Challenge { .. })
}
pub fn requires_throttle(&self) -> bool {
matches!(self, SecurityDecision::Throttle { .. })
}
}
#[derive(Debug, Clone, PartialEq, Eq, Hash, Serialize, Deserialize)]
pub enum SecurityOperation {
Authentication,
Authorization,
DataAccess,
DocumentIngestion,
QueryExecution,
AdminOperation,
ConfigurationChange,
SystemMonitoring,
}
impl std::fmt::Display for SecurityOperation {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
match self {
Self::Authentication => write!(f, "authentication"),
Self::Authorization => write!(f, "authorization"),
Self::DataAccess => write!(f, "data_access"),
Self::DocumentIngestion => write!(f, "document_ingestion"),
Self::QueryExecution => write!(f, "query_execution"),
Self::AdminOperation => write!(f, "admin_operation"),
Self::ConfigurationChange => write!(f, "configuration_change"),
Self::SystemMonitoring => write!(f, "system_monitoring"),
}
}
}
impl SecurityService {
pub fn builder() -> SecurityServiceBuilder {
SecurityServiceBuilder::new()
}
pub async fn evaluate_security(
&self,
operation: SecurityOperation,
context: &mut SecurityContext,
data: Option<&[u8]>,
) -> RragResult<SecurityDecision> {
self.audit_logger.log_security_evaluation(operation.clone(), context).await?;
if self.config.enable_auth && !context.is_authenticated() {
let auth_required = self.requires_authentication(&operation)?;
if auth_required {
return Ok(SecurityDecision::Deny {
reason: "Authentication required".to_string()
});
}
}
if self.config.enable_rate_limiting {
let rate_limit_result = self.check_rate_limits(context).await?;
if !rate_limit_result.allowed {
return Ok(SecurityDecision::Throttle {
delay_ms: rate_limit_result.retry_after_ms.unwrap_or(1000)
});
}
context.rate_limit_info = Some(rate_limit_result.info);
}
if self.config.enable_auth && context.is_authenticated() {
let authz_result = self.authz_service.authorize(
context.user.as_ref().unwrap(),
&operation,
None
).await?;
if !authz_result.allowed {
return Ok(SecurityDecision::Deny {
reason: authz_result.reason.unwrap_or_else(|| "Access denied".to_string())
});
}
}
if self.config.enable_validation && data.is_some() {
let validation_result = self.input_validator.validate_bytes(data.unwrap()).await?;
context.validation_results.push(validation_result.clone());
if !validation_result.is_valid {
return Ok(SecurityDecision::Deny {
reason: format!("Validation failed: {}", validation_result.error_message.unwrap_or_default())
});
}
}
if self.config.enable_abuse_detection {
let abuse_result = self.abuse_detector.analyze_context(context).await?;
if abuse_result.is_suspicious {
context.update_risk_score(abuse_result.risk_score);
if abuse_result.requires_challenge {
return Ok(SecurityDecision::Challenge {
challenge_type: abuse_result.challenge_type.unwrap_or_else(|| "captcha".to_string())
});
}
}
}
if self.config.enable_quotas && context.is_authenticated() {
let quota_result = self.quota_manager.check_quota(
context.user_id().unwrap(),
&operation,
).await?;
if !quota_result.allowed {
return Ok(SecurityDecision::Deny {
reason: "Quota exceeded".to_string()
});
}
}
if self.config.enable_monitoring {
self.monitor.record_operation(&operation, context).await?;
let threat_result = self.monitor.detect_threats(context).await?;
if threat_result.threat_detected {
return Ok(SecurityDecision::Deny {
reason: format!("Security threat detected: {}", threat_result.threat_type)
});
}
}
Ok(SecurityDecision::Allow)
}
pub async fn authenticate(
&self,
credentials: Credentials,
context: &mut SecurityContext,
) -> RragResult<AuthResult> {
if !self.config.enable_auth {
return Ok(AuthResult::success(User::anonymous()));
}
let auth_result = self.auth_service.authenticate(credentials).await?;
if auth_result.success {
context.user = auth_result.user.clone();
context.auth_method = Some(auth_result.method.clone());
if self.config.enable_sessions {
let session = self.session_manager.create_session(
auth_result.user.as_ref().unwrap(),
context.client_ip.clone(),
).await?;
context.session = Some(session);
}
}
self.audit_logger.log_authentication_event(&auth_result, context).await?;
Ok(auth_result)
}
async fn check_rate_limits(&self, context: &SecurityContext) -> RragResult<RateLimitResult> {
let key = self.build_rate_limit_key(context)?;
self.rate_limiter.check_rate_limit(key).await
}
fn build_rate_limit_key(&self, context: &SecurityContext) -> RragResult<RateLimitKey> {
let mut key_parts = Vec::new();
if let Some(user_id) = context.user_id() {
key_parts.push(format!("user:{}", user_id));
}
if let Some(ip) = &context.client_ip {
key_parts.push(format!("ip:{}", ip));
}
if let Some(ua) = &context.user_agent {
use sha2::{Sha256, Digest};
let mut hasher = Sha256::new();
hasher.update(ua.as_bytes());
let hash = format!("{:x}", hasher.finalize());
key_parts.push(format!("ua:{}", &hash[..8]));
}
if key_parts.is_empty() {
key_parts.push("anonymous".to_string());
}
Ok(RateLimitKey::new(key_parts.join(";")))
}
fn requires_authentication(&self, operation: &SecurityOperation) -> RragResult<bool> {
match operation {
SecurityOperation::Authentication => Ok(false),
SecurityOperation::Authorization => Ok(true),
SecurityOperation::DataAccess => Ok(true),
SecurityOperation::DocumentIngestion => Ok(true),
SecurityOperation::QueryExecution => Ok(false), SecurityOperation::AdminOperation => Ok(true),
SecurityOperation::ConfigurationChange => Ok(true),
SecurityOperation::SystemMonitoring => Ok(true),
}
}
pub async fn get_security_metrics(&self) -> RragResult<SecurityMetrics> {
self.monitor.get_metrics().await
}
pub async fn health_check(&self) -> RragResult<SecurityHealthReport> {
let mut report = SecurityHealthReport::new();
if self.config.enable_auth {
let auth_health = self.auth_service.health_check().await?;
report.add_component_health("authentication", auth_health);
}
if self.config.enable_rate_limiting {
let rate_limit_health = self.rate_limiter.health_check().await?;
report.add_component_health("rate_limiting", rate_limit_health);
}
report.overall_health = report.calculate_overall_health();
Ok(report)
}
}
pub struct SecurityServiceBuilder {
auth_service: Option<Arc<AuthenticationService>>,
authz_service: Option<Arc<AuthorizationService>>,
rate_limiter: Option<Arc<dyn RateLimiter>>,
input_validator: Option<Arc<InputValidator>>,
encryption_service: Option<Arc<EncryptionService>>,
audit_logger: Option<Arc<AuditLogger>>,
abuse_detector: Option<Arc<AbuseDetector>>,
quota_manager: Option<Arc<QuotaManager>>,
security_config: Option<Arc<SecurityConfig>>,
session_manager: Option<Arc<SessionManager>>,
monitor: Option<Arc<SecurityMonitor>>,
config: SecurityServiceConfig,
}
impl SecurityServiceBuilder {
pub fn new() -> Self {
Self {
auth_service: None,
authz_service: None,
rate_limiter: None,
input_validator: None,
encryption_service: None,
audit_logger: None,
abuse_detector: None,
quota_manager: None,
security_config: None,
session_manager: None,
monitor: None,
config: SecurityServiceConfig::default(),
}
}
pub fn with_authentication(mut self, auth_service: Arc<AuthenticationService>) -> Self {
self.auth_service = Some(auth_service);
self
}
pub fn with_authorization(mut self, authz_service: Arc<AuthorizationService>) -> Self {
self.authz_service = Some(authz_service);
self
}
pub fn with_rate_limiting(mut self, rate_limiter: Arc<dyn RateLimiter>) -> Self {
self.rate_limiter = Some(rate_limiter);
self
}
pub fn with_config(mut self, config: SecurityServiceConfig) -> Self {
self.config = config;
self
}
pub async fn build(self) -> RragResult<SecurityService> {
let auth_service = self.auth_service.unwrap_or_else(|| {
Arc::new(AuthenticationService::new(AuthConfig::default()))
});
let authz_service = self.authz_service.unwrap_or_else(|| {
Arc::new(AuthorizationService::new())
});
let rate_limiter = self.rate_limiter.unwrap_or_else(|| {
Arc::new(InMemoryRateLimitStore::new())
});
let input_validator = self.input_validator.unwrap_or_else(|| {
Arc::new(InputValidator::new(ValidationConfig::default()))
});
let encryption_service = self.encryption_service.unwrap_or_else(|| {
Arc::new(EncryptionService::new(EncryptionConfig::default()))
});
let audit_logger = self.audit_logger.unwrap_or_else(|| {
Arc::new(AuditLogger::new(AuditConfig::default()))
});
let abuse_detector = self.abuse_detector.unwrap_or_else(|| {
Arc::new(AbuseDetector::new(AbuseDetectionConfig::default()))
});
let quota_manager = self.quota_manager.unwrap_or_else(|| {
Arc::new(QuotaManager::new(QuotaConfig::default()))
});
let security_config = self.security_config.unwrap_or_else(|| {
Arc::new(SecurityConfig::default())
});
let session_manager = self.session_manager.unwrap_or_else(|| {
Arc::new(SessionManager::new(SessionConfig::default()))
});
let monitor = self.monitor.unwrap_or_else(|| {
Arc::new(SecurityMonitor::new())
});
Ok(SecurityService {
auth_service,
authz_service,
rate_limiter,
input_validator,
encryption_service,
audit_logger,
abuse_detector,
quota_manager,
security_config,
session_manager,
monitor,
config: self.config,
})
}
}
#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct SecurityHealthReport {
pub overall_health: HealthStatus,
pub component_health: HashMap<String, HealthStatus>,
pub timestamp: chrono::DateTime<chrono::Utc>,
pub issues: Vec<SecurityIssue>,
}
impl SecurityHealthReport {
pub fn new() -> Self {
Self {
overall_health: HealthStatus::Unknown,
component_health: HashMap::new(),
timestamp: chrono::Utc::now(),
issues: Vec::new(),
}
}
pub fn add_component_health(&mut self, component: &str, health: HealthStatus) {
self.component_health.insert(component.to_string(), health);
}
pub fn calculate_overall_health(&self) -> HealthStatus {
if self.component_health.is_empty() {
return HealthStatus::Unknown;
}
let has_critical = self.component_health.values().any(|h| *h == HealthStatus::Critical);
let has_degraded = self.component_health.values().any(|h| *h == HealthStatus::Degraded);
if has_critical {
HealthStatus::Critical
} else if has_degraded {
HealthStatus::Degraded
} else {
HealthStatus::Healthy
}
}
}
impl Default for SecurityHealthReport {
fn default() -> Self {
Self::new()
}
}
#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)]
pub enum HealthStatus {
Healthy,
Degraded,
Critical,
Unknown,
}
#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct SecurityIssue {
pub severity: IssueSeverity,
pub component: String,
pub description: String,
pub recommendation: String,
pub timestamp: chrono::DateTime<chrono::Utc>,
}
#[derive(Debug, Clone, PartialEq, Eq, PartialOrd, Ord, Serialize, Deserialize)]
pub enum IssueSeverity {
Low,
Medium,
High,
Critical,
}
#[cfg(test)]
mod tests {
use super::*;
#[tokio::test]
async fn test_security_context_creation() {
let context = SecurityContext::new();
assert!(!context.is_authenticated());
assert!(!context.has_valid_session());
assert_eq!(context.risk_score, 0.0);
}
#[tokio::test]
async fn test_security_decision_checks() {
assert!(SecurityDecision::Allow.is_allowed());
assert!(!SecurityDecision::Allow.is_denied());
let deny = SecurityDecision::Deny { reason: "test".to_string() };
assert!(!deny.is_allowed());
assert!(deny.is_denied());
let challenge = SecurityDecision::Challenge { challenge_type: "captcha".to_string() };
assert!(challenge.requires_challenge());
let throttle = SecurityDecision::Throttle { delay_ms: 1000 };
assert!(throttle.requires_throttle());
}
#[tokio::test]
async fn test_security_service_builder() {
let service = SecurityService::builder()
.with_config(SecurityServiceConfig {
enable_auth: true,
enable_rate_limiting: true,
security_level: 5,
..Default::default()
})
.build()
.await
.unwrap();
assert_eq!(service.config.security_level, 5);
assert!(service.config.enable_auth);
}
}