use anyhow::{anyhow, Result};
use chrono::{DateTime, Duration as ChronoDuration, Utc};
use serde::{Deserialize, Serialize};
use std::collections::{HashMap, HashSet};
use std::sync::Arc;
use std::time::Instant;
use tokio::sync::RwLock;
use uuid::Uuid;
#[derive(Debug, Clone, Serialize, Deserialize, Default)]
pub struct SecurityConfig {
pub authentication: AuthConfig,
pub authorization: AuthzConfig,
pub encryption: EncryptionConfig,
pub post_quantum: PostQuantumConfig,
pub quantum_resistant_certs: QuantumResistantCerts,
pub audit: AuditConfig,
pub threat_detection: ThreatDetectionConfig,
pub rate_limiting: RateLimitConfig,
pub session: SessionConfig,
}
#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct AuthConfig {
pub methods: Vec<AuthMethod>,
pub mfa: MfaConfig,
pub token: TokenConfig,
pub password_policy: PasswordPolicy,
}
impl Default for AuthConfig {
fn default() -> Self {
Self {
methods: vec![AuthMethod::ApiKey, AuthMethod::JWT],
mfa: MfaConfig::default(),
token: TokenConfig::default(),
password_policy: PasswordPolicy::default(),
}
}
}
#[derive(Debug, Clone, Serialize, Deserialize, PartialEq)]
pub enum AuthMethod {
ApiKey,
JWT,
OAuth2,
SAML,
Certificate,
Basic,
}
#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct MfaConfig {
pub enabled: bool,
pub required_for_admin: bool,
pub methods: Vec<MfaMethod>,
pub backup_codes: bool,
}
impl Default for MfaConfig {
fn default() -> Self {
Self {
enabled: false,
required_for_admin: true,
methods: vec![MfaMethod::TOTP],
backup_codes: true,
}
}
}
#[derive(Debug, Clone, Serialize, Deserialize)]
pub enum MfaMethod {
TOTP, SMS, Email, Hardware, }
#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct TokenConfig {
pub jwt_secret: String,
pub access_token_ttl: ChronoDuration,
pub refresh_token_ttl: ChronoDuration,
pub issuer: String,
pub audience: String,
}
impl Default for TokenConfig {
fn default() -> Self {
Self {
jwt_secret: "change-this-secret".to_string(),
access_token_ttl: ChronoDuration::hours(1),
refresh_token_ttl: ChronoDuration::days(30),
issuer: "oxirs-stream".to_string(),
audience: "oxirs-api".to_string(),
}
}
}
#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct PasswordPolicy {
pub min_length: usize,
pub require_uppercase: bool,
pub require_lowercase: bool,
pub require_numbers: bool,
pub require_symbols: bool,
pub max_age_days: Option<u32>,
pub history_count: usize,
}
impl Default for PasswordPolicy {
fn default() -> Self {
Self {
min_length: 12,
require_uppercase: true,
require_lowercase: true,
require_numbers: true,
require_symbols: true,
max_age_days: Some(90),
history_count: 5,
}
}
}
#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct AuthzConfig {
pub model: AuthzModel,
pub default_permissions: Vec<Permission>,
pub rbac: RbacConfig,
pub abac: AbacConfig,
}
impl Default for AuthzConfig {
fn default() -> Self {
Self {
model: AuthzModel::RBAC,
default_permissions: vec![Permission::Read],
rbac: RbacConfig::default(),
abac: AbacConfig::default(),
}
}
}
#[derive(Debug, Clone, Serialize, Deserialize)]
pub enum AuthzModel {
RBAC, ABAC, MAC, DAC, }
#[derive(Debug, Clone, Serialize, Deserialize, PartialEq, Eq, Hash)]
pub enum Permission {
Read,
Write,
Delete,
Admin,
Execute,
Stream,
Query,
Configure,
}
impl std::fmt::Display for Permission {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
match self {
Permission::Read => write!(f, "read"),
Permission::Write => write!(f, "write"),
Permission::Delete => write!(f, "delete"),
Permission::Admin => write!(f, "admin"),
Permission::Execute => write!(f, "execute"),
Permission::Stream => write!(f, "stream"),
Permission::Query => write!(f, "query"),
Permission::Configure => write!(f, "configure"),
}
}
}
#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct RbacConfig {
pub enabled: bool,
pub default_role: String,
pub role_hierarchy: HashMap<String, Vec<String>>,
pub role_permissions: HashMap<String, Vec<Permission>>,
}
impl Default for RbacConfig {
fn default() -> Self {
let mut role_permissions = HashMap::new();
role_permissions.insert(
"viewer".to_string(),
vec![Permission::Read, Permission::Query],
);
role_permissions.insert(
"user".to_string(),
vec![
Permission::Read,
Permission::Write,
Permission::Stream,
Permission::Query,
],
);
role_permissions.insert(
"admin".to_string(),
vec![
Permission::Read,
Permission::Write,
Permission::Delete,
Permission::Admin,
Permission::Execute,
Permission::Stream,
Permission::Query,
Permission::Configure,
],
);
let mut role_hierarchy = HashMap::new();
role_hierarchy.insert(
"admin".to_string(),
vec!["user".to_string(), "viewer".to_string()],
);
role_hierarchy.insert("user".to_string(), vec!["viewer".to_string()]);
Self {
enabled: true,
default_role: "viewer".to_string(),
role_hierarchy,
role_permissions,
}
}
}
#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct AbacConfig {
pub enabled: bool,
pub policy_engine: PolicyEngine,
pub attributes: Vec<AttributeDefinition>,
}
impl Default for AbacConfig {
fn default() -> Self {
Self {
enabled: false,
policy_engine: PolicyEngine::default(),
attributes: vec![
AttributeDefinition {
name: "department".to_string(),
attribute_type: AttributeType::String,
required: false,
},
AttributeDefinition {
name: "security_level".to_string(),
attribute_type: AttributeType::Integer,
required: true,
},
],
}
}
}
#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct PolicyEngine {
pub language: PolicyLanguage,
pub cache_policies: bool,
pub cache_ttl: ChronoDuration,
}
impl Default for PolicyEngine {
fn default() -> Self {
Self {
language: PolicyLanguage::OPA,
cache_policies: true,
cache_ttl: ChronoDuration::minutes(30),
}
}
}
#[derive(Debug, Clone, Serialize, Deserialize)]
pub enum PolicyLanguage {
OPA, Cedar, Custom, }
#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct AttributeDefinition {
pub name: String,
pub attribute_type: AttributeType,
pub required: bool,
}
#[derive(Debug, Clone, Serialize, Deserialize)]
pub enum AttributeType {
String,
Integer,
Boolean,
DateTime,
Array,
}
#[derive(Debug, Clone, Serialize, Deserialize, Default)]
pub struct EncryptionConfig {
pub at_rest: EncryptionAtRest,
pub in_transit: EncryptionInTransit,
pub field_level: FieldLevelEncryption,
}
#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct EncryptionAtRest {
pub enabled: bool,
pub algorithm: EncryptionAlgorithm,
pub key_management: KeyManagement,
}
impl Default for EncryptionAtRest {
fn default() -> Self {
Self {
enabled: true,
algorithm: EncryptionAlgorithm::AES256GCM,
key_management: KeyManagement::default(),
}
}
}
#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct EncryptionInTransit {
pub enabled: bool,
pub tls_version: TlsVersion,
pub cipher_suites: Vec<String>,
pub certificate_validation: bool,
}
impl Default for EncryptionInTransit {
fn default() -> Self {
Self {
enabled: true,
tls_version: TlsVersion::V1_3,
cipher_suites: vec![
"TLS_AES_256_GCM_SHA384".to_string(),
"TLS_CHACHA20_POLY1305_SHA256".to_string(),
],
certificate_validation: true,
}
}
}
#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct FieldLevelEncryption {
pub enabled: bool,
pub fields: Vec<String>,
pub algorithm: EncryptionAlgorithm,
}
impl Default for FieldLevelEncryption {
fn default() -> Self {
Self {
enabled: false,
fields: vec!["password".to_string(), "ssn".to_string()],
algorithm: EncryptionAlgorithm::AES256GCM,
}
}
}
#[derive(Debug, Clone, Serialize, Deserialize)]
pub enum EncryptionAlgorithm {
AES256GCM,
AES256CBC,
ChaCha20Poly1305,
Kyber512,
Kyber768,
Kyber1024,
NewHope1024,
FrodoKEM640,
FrodoKEM976,
FrodoKEM1344,
Rainbow1,
Rainbow3,
Rainbow5,
SphincsPlus128s,
SphincsPlus256s,
SikeP434,
SikeP503,
SikeP751,
McEliece348864,
McEliece460896,
McEliece6688128,
HybridAesKyber768,
HybridChaCha20NewHope,
}
#[derive(Debug, Clone, Serialize, Deserialize)]
pub enum TlsVersion {
V1_2,
V1_3,
}
#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct KeyManagement {
pub provider: KeyProvider,
pub rotation_interval: ChronoDuration,
pub key_derivation: KeyDerivation,
}
impl Default for KeyManagement {
fn default() -> Self {
Self {
provider: KeyProvider::Local,
rotation_interval: ChronoDuration::days(90),
key_derivation: KeyDerivation::PBKDF2,
}
}
}
#[derive(Debug, Clone, Serialize, Deserialize)]
pub enum KeyProvider {
Local,
HSM,
AwsKms,
AzureKeyVault,
HashiCorpVault,
}
#[derive(Debug, Clone, Serialize, Deserialize)]
pub enum KeyDerivation {
PBKDF2,
Scrypt,
Argon2,
LatticeBasedKDF,
HashBasedKDF,
CodeBasedKDF,
HybridArgon2Lattice,
HybridScryptHash,
}
#[derive(Debug, Clone, Serialize, Deserialize)]
pub enum PostQuantumSignature {
Dilithium2,
Dilithium3,
Dilithium5,
SphincsPlusSha2128s,
SphincsPlusSha2128f,
SphincsPlusSha2192s,
SphincsPlusSha2192f,
SphincsPlusSha2256s,
SphincsPlusSha2256f,
SphincsPlusShake128s,
SphincsPlusShake128f,
SphincsPlusShake192s,
SphincsPlusShake192f,
SphincsPlusShake256s,
SphincsPlusShake256f,
RainbowIClassic,
RainbowICircumzenithal,
RainbowICompressed,
RainbowIiiClassic,
RainbowIiiCircumzenithal,
RainbowIiiCompressed,
RainbowVClassic,
RainbowVCircumzenithal,
RainbowVCompressed,
Falcon512,
Falcon1024,
PicnicL1Fs,
PicnicL1Ur,
PicnicL3Fs,
PicnicL3Ur,
PicnicL5Fs,
PicnicL5Ur,
}
#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct PostQuantumConfig {
pub enabled: bool,
pub primary_kem: Option<EncryptionAlgorithm>,
pub signature_algorithm: Option<PostQuantumSignature>,
pub hybrid_mode: bool,
pub classical_fallback: bool,
pub quantum_security_level: QuantumSecurityLevel,
pub key_size_preferences: KeySizePreferences,
}
impl Default for PostQuantumConfig {
fn default() -> Self {
Self {
enabled: true,
primary_kem: Some(EncryptionAlgorithm::Kyber768),
signature_algorithm: Some(PostQuantumSignature::Dilithium3),
hybrid_mode: true,
classical_fallback: true,
quantum_security_level: QuantumSecurityLevel::Level3,
key_size_preferences: KeySizePreferences::default(),
}
}
}
#[derive(Debug, Clone, Serialize, Deserialize)]
pub enum QuantumSecurityLevel {
Level1, Level2, Level3, Level4, Level5, }
#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct KeySizePreferences {
pub prefer_smaller_keys: bool,
pub prefer_faster_signing: bool,
pub prefer_faster_verification: bool,
pub max_signature_size_kb: Option<u32>,
pub max_public_key_size_kb: Option<u32>,
}
impl Default for KeySizePreferences {
fn default() -> Self {
Self {
prefer_smaller_keys: true,
prefer_faster_signing: false,
prefer_faster_verification: true,
max_signature_size_kb: Some(50),
max_public_key_size_kb: Some(10),
}
}
}
#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct QuantumResistantCerts {
pub enabled: bool,
pub use_hybrid_certificates: bool,
pub pq_signature_algorithm: PostQuantumSignature,
pub classical_signature_fallback: bool,
pub certificate_chain_validation: PQCertValidation,
}
impl Default for QuantumResistantCerts {
fn default() -> Self {
Self {
enabled: false,
use_hybrid_certificates: true,
pq_signature_algorithm: PostQuantumSignature::Dilithium3,
classical_signature_fallback: true,
certificate_chain_validation: PQCertValidation::default(),
}
}
}
#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct PQCertValidation {
pub require_pq_signatures: bool,
pub allow_mixed_chain: bool,
pub minimum_security_level: QuantumSecurityLevel,
pub validate_quantum_resistance: bool,
}
impl Default for PQCertValidation {
fn default() -> Self {
Self {
require_pq_signatures: false,
allow_mixed_chain: true,
minimum_security_level: QuantumSecurityLevel::Level3,
validate_quantum_resistance: true,
}
}
}
#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct AuditConfig {
pub enabled: bool,
pub events: Vec<AuditEvent>,
pub retention_days: u32,
pub log_format: AuditLogFormat,
pub output: AuditOutput,
}
impl Default for AuditConfig {
fn default() -> Self {
Self {
enabled: true,
events: vec![
AuditEvent::Authentication,
AuditEvent::Authorization,
AuditEvent::DataAccess,
AuditEvent::ConfigChange,
],
retention_days: 365,
log_format: AuditLogFormat::JSON,
output: AuditOutput::File("/var/log/oxirs/audit.log".to_string()),
}
}
}
#[derive(Debug, Clone, Serialize, Deserialize)]
pub enum AuditEvent {
Authentication,
Authorization,
DataAccess,
ConfigChange,
UserManagement,
SecurityAlert,
}
#[derive(Debug, Clone, Serialize, Deserialize)]
pub enum AuditLogFormat {
JSON,
CEF, LEEF, Syslog,
}
#[derive(Debug, Clone, Serialize, Deserialize)]
pub enum AuditOutput {
File(String),
Syslog,
Database,
SIEM(String), }
#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct ThreatDetectionConfig {
pub enabled: bool,
pub rules: Vec<ThreatRule>,
pub anomaly_detection: AnomalyDetectionConfig,
pub response: ThreatResponseConfig,
}
impl Default for ThreatDetectionConfig {
fn default() -> Self {
Self {
enabled: true,
rules: vec![
ThreatRule {
name: "Multiple Failed Logins".to_string(),
description: "Detect multiple failed login attempts".to_string(),
condition: "failed_logins > 5 in 5m".to_string(),
severity: ThreatSeverity::High,
enabled: true,
},
ThreatRule {
name: "Unusual Access Pattern".to_string(),
description: "Detect unusual access patterns".to_string(),
condition: "requests > 1000 in 1m".to_string(),
severity: ThreatSeverity::Medium,
enabled: true,
},
],
anomaly_detection: AnomalyDetectionConfig::default(),
response: ThreatResponseConfig::default(),
}
}
}
#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct ThreatRule {
pub name: String,
pub description: String,
pub condition: String,
pub severity: ThreatSeverity,
pub enabled: bool,
}
#[derive(Debug, Clone, Serialize, Deserialize, PartialEq, Eq, Hash)]
pub enum ThreatSeverity {
Low,
Medium,
High,
Critical,
}
#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct AnomalyDetectionConfig {
pub enabled: bool,
pub algorithms: Vec<AnomalyAlgorithm>,
pub sensitivity: f64,
pub learning_period_days: u32,
}
impl Default for AnomalyDetectionConfig {
fn default() -> Self {
Self {
enabled: true,
algorithms: vec![
AnomalyAlgorithm::IsolationForest,
AnomalyAlgorithm::StatisticalOutlier,
],
sensitivity: 0.8,
learning_period_days: 30,
}
}
}
#[derive(Debug, Clone, Serialize, Deserialize)]
pub enum AnomalyAlgorithm {
IsolationForest,
StatisticalOutlier,
LSTM,
KMeans,
}
#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct ThreatResponseConfig {
pub auto_response: bool,
pub actions: Vec<ResponseAction>,
pub escalation: EscalationConfig,
}
impl Default for ThreatResponseConfig {
fn default() -> Self {
Self {
auto_response: true,
actions: vec![
ResponseAction::Block,
ResponseAction::RateLimit,
ResponseAction::Alert,
],
escalation: EscalationConfig::default(),
}
}
}
#[derive(Debug, Clone, Serialize, Deserialize)]
pub enum ResponseAction {
Block,
RateLimit,
Alert,
Quarantine,
Notify,
}
#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct EscalationConfig {
pub enabled: bool,
pub thresholds: HashMap<ThreatSeverity, u32>,
pub notifications: Vec<String>, }
impl Default for EscalationConfig {
fn default() -> Self {
let mut thresholds = HashMap::new();
thresholds.insert(ThreatSeverity::Low, 10);
thresholds.insert(ThreatSeverity::Medium, 5);
thresholds.insert(ThreatSeverity::High, 1);
thresholds.insert(ThreatSeverity::Critical, 1);
Self {
enabled: true,
thresholds,
notifications: vec!["security@example.com".to_string()],
}
}
}
#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct RateLimitConfig {
pub enabled: bool,
pub global_limit: RateLimit,
pub per_user_limit: RateLimit,
pub per_ip_limit: RateLimit,
pub burst_limit: RateLimit,
}
impl Default for RateLimitConfig {
fn default() -> Self {
Self {
enabled: true,
global_limit: RateLimit {
requests: 10000,
window: ChronoDuration::minutes(1),
},
per_user_limit: RateLimit {
requests: 100,
window: ChronoDuration::minutes(1),
},
per_ip_limit: RateLimit {
requests: 1000,
window: ChronoDuration::minutes(1),
},
burst_limit: RateLimit {
requests: 50,
window: ChronoDuration::seconds(10),
},
}
}
}
#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct RateLimit {
pub requests: u32,
pub window: ChronoDuration,
}
#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct SessionConfig {
pub timeout: ChronoDuration,
pub max_concurrent: u32,
pub secure_cookies: bool,
pub same_site: SameSite,
}
impl Default for SessionConfig {
fn default() -> Self {
Self {
timeout: ChronoDuration::hours(8),
max_concurrent: 5,
secure_cookies: true,
same_site: SameSite::Strict,
}
}
}
#[derive(Debug, Clone, Serialize, Deserialize)]
pub enum SameSite {
Strict,
Lax,
None,
}
#[derive(Debug, Clone)]
pub struct SecurityContext {
pub user_id: Option<String>,
pub session_id: Option<String>,
pub roles: HashSet<String>,
pub permissions: HashSet<Permission>,
pub attributes: HashMap<String, String>,
pub ip_address: Option<String>,
pub user_agent: Option<String>,
pub authentication_method: Option<AuthMethod>,
pub authenticated_at: Option<DateTime<Utc>>,
}
impl SecurityContext {
pub fn has_permission(&self, permission: &Permission) -> bool {
self.permissions.contains(permission)
}
pub fn has_role(&self, role: &str) -> bool {
self.roles.contains(role)
}
pub fn has_any_role(&self, roles: &[String]) -> bool {
roles.iter().any(|role| self.roles.contains(role))
}
pub fn get_attribute(&self, name: &str) -> Option<&String> {
self.attributes.get(name)
}
}
pub struct SecurityManager {
config: SecurityConfig,
auth_provider: Arc<dyn AuthenticationProvider>,
authz_provider: Arc<dyn AuthorizationProvider>,
audit_logger: Arc<dyn AuditLogger>,
threat_detector: Arc<dyn ThreatDetector>,
rate_limiter: Arc<dyn RateLimiter>,
metrics: Arc<RwLock<SecurityMetrics>>,
}
impl SecurityManager {
pub fn new(
config: SecurityConfig,
auth_provider: Arc<dyn AuthenticationProvider>,
authz_provider: Arc<dyn AuthorizationProvider>,
audit_logger: Arc<dyn AuditLogger>,
threat_detector: Arc<dyn ThreatDetector>,
rate_limiter: Arc<dyn RateLimiter>,
) -> Self {
Self {
config,
auth_provider,
authz_provider,
audit_logger,
threat_detector,
rate_limiter,
metrics: Arc::new(RwLock::new(SecurityMetrics::default())),
}
}
pub async fn authenticate(&self, credentials: &Credentials) -> Result<SecurityContext> {
let start_time = Instant::now();
if self.config.rate_limiting.enabled {
self.rate_limiter
.check_limit(&credentials.identifier())
.await?;
}
let result = self.auth_provider.authenticate(credentials).await;
let audit_event = AuditLogEntry {
event_type: AuditEvent::Authentication,
timestamp: Utc::now(),
user_id: credentials.user_id().map(|s| s.to_string()),
ip_address: credentials.ip_address().map(|s| s.to_string()),
success: result.is_ok(),
details: format!("Authentication attempt for {}", credentials.identifier()),
};
let _ = self.audit_logger.log(audit_event).await;
{
let mut metrics = self.metrics.write().await;
metrics.authentication_attempts += 1;
if result.is_ok() {
metrics.authentication_successes += 1;
} else {
metrics.authentication_failures += 1;
}
metrics.authentication_latency_ms = start_time.elapsed().as_millis() as f64;
}
if result.is_err() {
let _ = self
.threat_detector
.detect_threat(&ThreatContext {
event_type: "authentication_failure".to_string(),
user_id: credentials.user_id().map(|s| s.to_string()),
ip_address: credentials.ip_address().map(|s| s.to_string()),
timestamp: Utc::now(),
details: HashMap::new(),
})
.await;
}
result
}
pub async fn authorize(
&self,
context: &SecurityContext,
resource: &str,
action: &Permission,
) -> Result<bool> {
let start_time = Instant::now();
let result = self
.authz_provider
.authorize(context, resource, action)
.await;
let success = result.as_ref().map(|&b| b).unwrap_or(false);
let audit_event = AuditLogEntry {
event_type: AuditEvent::Authorization,
timestamp: Utc::now(),
user_id: context.user_id.clone(),
ip_address: context.ip_address.clone(),
success,
details: format!("Authorization check for {action} on {resource}"),
};
let _ = self.audit_logger.log(audit_event).await;
{
let mut metrics = self.metrics.write().await;
metrics.authorization_checks += 1;
if success {
metrics.authorization_successes += 1;
} else {
metrics.authorization_failures += 1;
}
metrics.authorization_latency_ms = start_time.elapsed().as_millis() as f64;
}
result
}
pub async fn log_data_access(
&self,
context: &SecurityContext,
resource: &str,
operation: &str,
) -> Result<()> {
let audit_event = AuditLogEntry {
event_type: AuditEvent::DataAccess,
timestamp: Utc::now(),
user_id: context.user_id.clone(),
ip_address: context.ip_address.clone(),
success: true,
details: format!("Data access: {operation} on {resource}"),
};
self.audit_logger.log(audit_event).await
}
pub async fn get_metrics(&self) -> SecurityMetrics {
self.metrics.read().await.clone()
}
}
#[async_trait::async_trait]
pub trait AuthenticationProvider: Send + Sync {
async fn authenticate(&self, credentials: &Credentials) -> Result<SecurityContext>;
async fn validate_token(&self, token: &str) -> Result<SecurityContext>;
async fn refresh_token(&self, refresh_token: &str) -> Result<(String, String)>; }
#[async_trait::async_trait]
pub trait AuthorizationProvider: Send + Sync {
async fn authorize(
&self,
context: &SecurityContext,
resource: &str,
action: &Permission,
) -> Result<bool>;
async fn get_user_permissions(&self, user_id: &str) -> Result<HashSet<Permission>>;
async fn get_user_roles(&self, user_id: &str) -> Result<HashSet<String>>;
}
#[async_trait::async_trait]
pub trait AuditLogger: Send + Sync {
async fn log(&self, entry: AuditLogEntry) -> Result<()>;
async fn query(&self, filter: AuditFilter) -> Result<Vec<AuditLogEntry>>;
}
#[async_trait::async_trait]
pub trait ThreatDetector: Send + Sync {
async fn detect_threat(&self, context: &ThreatContext) -> Result<Option<ThreatAlert>>;
async fn learn_pattern(&self, context: &ThreatContext) -> Result<()>;
}
#[async_trait::async_trait]
pub trait RateLimiter: Send + Sync {
async fn check_limit(&self, identifier: &str) -> Result<()>;
async fn reset_limit(&self, identifier: &str) -> Result<()>;
}
#[derive(Debug, Clone)]
pub enum Credentials {
ApiKey {
key: String,
ip_address: Option<String>,
},
JWT {
token: String,
ip_address: Option<String>,
},
UserPassword {
username: String,
password: String,
ip_address: Option<String>,
},
Certificate {
cert: Vec<u8>,
ip_address: Option<String>,
},
}
impl Credentials {
pub fn identifier(&self) -> String {
match self {
Credentials::ApiKey { key, .. } => format!("api_key:{key}"),
Credentials::JWT { token, .. } => format!("jwt:{token}"),
Credentials::UserPassword { username, .. } => format!("user:{username}"),
Credentials::Certificate { .. } => "certificate".to_string(),
}
}
pub fn user_id(&self) -> Option<&str> {
match self {
Credentials::UserPassword { username, .. } => Some(username),
_ => None,
}
}
pub fn ip_address(&self) -> Option<&str> {
match self {
Credentials::ApiKey { ip_address, .. }
| Credentials::JWT { ip_address, .. }
| Credentials::UserPassword { ip_address, .. }
| Credentials::Certificate { ip_address, .. } => ip_address.as_deref(),
}
}
}
#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct AuditLogEntry {
pub event_type: AuditEvent,
pub timestamp: DateTime<Utc>,
pub user_id: Option<String>,
pub ip_address: Option<String>,
pub success: bool,
pub details: String,
}
#[derive(Debug, Clone)]
pub struct AuditFilter {
pub event_types: Option<Vec<AuditEvent>>,
pub user_id: Option<String>,
pub ip_address: Option<String>,
pub start_time: Option<DateTime<Utc>>,
pub end_time: Option<DateTime<Utc>>,
pub success: Option<bool>,
}
#[derive(Debug, Clone)]
pub struct ThreatContext {
pub event_type: String,
pub user_id: Option<String>,
pub ip_address: Option<String>,
pub timestamp: DateTime<Utc>,
pub details: HashMap<String, String>,
}
#[derive(Debug, Clone)]
pub struct ThreatAlert {
pub id: Uuid,
pub rule_name: String,
pub severity: ThreatSeverity,
pub description: String,
pub context: ThreatContext,
pub timestamp: DateTime<Utc>,
pub resolved: bool,
}
#[derive(Debug, Clone, Default)]
pub struct SecurityMetrics {
pub authentication_attempts: u64,
pub authentication_successes: u64,
pub authentication_failures: u64,
pub authorization_checks: u64,
pub authorization_successes: u64,
pub authorization_failures: u64,
pub threat_alerts: u64,
pub rate_limit_violations: u64,
pub authentication_latency_ms: f64,
pub authorization_latency_ms: f64,
}
pub struct PostQuantumCryptoEngine {
config: Arc<PostQuantumConfig>,
key_store: Arc<RwLock<HashMap<String, PostQuantumKeyPair>>>,
signature_cache: Arc<RwLock<HashMap<String, SignatureInfo>>>,
metrics: Arc<RwLock<PQCryptoMetrics>>,
}
impl PostQuantumCryptoEngine {
pub fn new(config: PostQuantumConfig) -> Self {
Self {
config: Arc::new(config),
key_store: Arc::new(RwLock::new(HashMap::new())),
signature_cache: Arc::new(RwLock::new(HashMap::new())),
metrics: Arc::new(RwLock::new(PQCryptoMetrics::default())),
}
}
pub async fn generate_keypair(
&self,
algorithm: &PostQuantumSignature,
) -> Result<PostQuantumKeyPair> {
let start_time = Instant::now();
let keypair = match algorithm {
PostQuantumSignature::Dilithium2
| PostQuantumSignature::Dilithium3
| PostQuantumSignature::Dilithium5 => {
self.generate_dilithium_keypair(algorithm).await?
}
PostQuantumSignature::SphincsPlusSha2128s
| PostQuantumSignature::SphincsPlusSha2256s => {
self.generate_sphincs_keypair(algorithm).await?
}
PostQuantumSignature::Falcon512 | PostQuantumSignature::Falcon1024 => {
self.generate_falcon_keypair(algorithm).await?
}
_ => {
return Err(anyhow!("Algorithm {:?} not yet implemented", algorithm));
}
};
{
let mut metrics = self.metrics.write().await;
metrics.key_generation_count += 1;
metrics.avg_key_generation_time_ms = (metrics.avg_key_generation_time_ms
+ start_time.elapsed().as_millis() as f64)
/ 2.0;
}
{
let mut store = self.key_store.write().await;
store.insert(keypair.id.clone(), keypair.clone());
}
Ok(keypair)
}
pub async fn sign(&self, key_id: &str, data: &[u8]) -> Result<PostQuantumSignature> {
let start_time = Instant::now();
let key_store = self.key_store.read().await;
let keypair = key_store
.get(key_id)
.ok_or_else(|| anyhow!("Key not found: {}", key_id))?;
let signature = match keypair.algorithm {
PostQuantumSignature::Dilithium3 => {
self.dilithium_sign(&keypair.private_key, data).await?
}
PostQuantumSignature::SphincsPlusSha2256s => {
self.sphincs_sign(&keypair.private_key, data).await?
}
PostQuantumSignature::Falcon1024 => {
self.falcon_sign(&keypair.private_key, data).await?
}
_ => {
return Err(anyhow!(
"Signing with {:?} not implemented",
keypair.algorithm
));
}
};
{
let mut metrics = self.metrics.write().await;
metrics.signature_count += 1;
metrics.avg_signing_time_ms =
(metrics.avg_signing_time_ms + start_time.elapsed().as_millis() as f64) / 2.0;
}
Ok(signature)
}
pub async fn verify(
&self,
public_key: &[u8],
data: &[u8],
signature: &[u8],
algorithm: &PostQuantumSignature,
) -> Result<bool> {
let start_time = Instant::now();
let is_valid = match algorithm {
PostQuantumSignature::Dilithium3 => {
self.dilithium_verify(public_key, data, signature).await?
}
PostQuantumSignature::SphincsPlusSha2256s => {
self.sphincs_verify(public_key, data, signature).await?
}
PostQuantumSignature::Falcon1024 => {
self.falcon_verify(public_key, data, signature).await?
}
_ => {
return Err(anyhow!("Verification for {:?} not implemented", algorithm));
}
};
{
let mut metrics = self.metrics.write().await;
metrics.verification_count += 1;
metrics.avg_verification_time_ms =
(metrics.avg_verification_time_ms + start_time.elapsed().as_millis() as f64) / 2.0;
if is_valid {
metrics.successful_verifications += 1;
}
}
Ok(is_valid)
}
pub async fn encapsulate(
&self,
public_key: &[u8],
algorithm: &EncryptionAlgorithm,
) -> Result<(Vec<u8>, Vec<u8>)> {
match algorithm {
EncryptionAlgorithm::Kyber768 => self.kyber_encapsulate(public_key).await,
EncryptionAlgorithm::NewHope1024 => self.newhope_encapsulate(public_key).await,
EncryptionAlgorithm::FrodoKEM976 => self.frodokem_encapsulate(public_key).await,
_ => Err(anyhow!("KEM algorithm {:?} not implemented", algorithm)),
}
}
pub async fn decapsulate(
&self,
private_key: &[u8],
ciphertext: &[u8],
algorithm: &EncryptionAlgorithm,
) -> Result<Vec<u8>> {
match algorithm {
EncryptionAlgorithm::Kyber768 => self.kyber_decapsulate(private_key, ciphertext).await,
EncryptionAlgorithm::NewHope1024 => {
self.newhope_decapsulate(private_key, ciphertext).await
}
EncryptionAlgorithm::FrodoKEM976 => {
self.frodokem_decapsulate(private_key, ciphertext).await
}
_ => Err(anyhow!("KEM algorithm {:?} not implemented", algorithm)),
}
}
async fn generate_dilithium_keypair(
&self,
_variant: &PostQuantumSignature,
) -> Result<PostQuantumKeyPair> {
Ok(PostQuantumKeyPair {
id: Uuid::new_v4().to_string(),
algorithm: _variant.clone(),
public_key: vec![0u8; 1312], private_key: vec![0u8; 4000], created_at: Utc::now(),
})
}
async fn generate_sphincs_keypair(
&self,
_variant: &PostQuantumSignature,
) -> Result<PostQuantumKeyPair> {
Ok(PostQuantumKeyPair {
id: Uuid::new_v4().to_string(),
algorithm: _variant.clone(),
public_key: vec![0u8; 32], private_key: vec![0u8; 64], created_at: Utc::now(),
})
}
async fn generate_falcon_keypair(
&self,
_variant: &PostQuantumSignature,
) -> Result<PostQuantumKeyPair> {
Ok(PostQuantumKeyPair {
id: Uuid::new_v4().to_string(),
algorithm: _variant.clone(),
public_key: vec![0u8; 1793], private_key: vec![0u8; 2305], created_at: Utc::now(),
})
}
async fn dilithium_sign(
&self,
_private_key: &[u8],
_data: &[u8],
) -> Result<PostQuantumSignature> {
Ok(PostQuantumSignature::Dilithium3)
}
async fn sphincs_sign(
&self,
_private_key: &[u8],
_data: &[u8],
) -> Result<PostQuantumSignature> {
Ok(PostQuantumSignature::SphincsPlusSha2256s)
}
async fn falcon_sign(&self, _private_key: &[u8], _data: &[u8]) -> Result<PostQuantumSignature> {
Ok(PostQuantumSignature::Falcon1024)
}
async fn dilithium_verify(
&self,
_public_key: &[u8],
_data: &[u8],
_signature: &[u8],
) -> Result<bool> {
Ok(true)
}
async fn sphincs_verify(
&self,
_public_key: &[u8],
_data: &[u8],
_signature: &[u8],
) -> Result<bool> {
Ok(true)
}
async fn falcon_verify(
&self,
_public_key: &[u8],
_data: &[u8],
_signature: &[u8],
) -> Result<bool> {
Ok(true)
}
async fn kyber_encapsulate(&self, _public_key: &[u8]) -> Result<(Vec<u8>, Vec<u8>)> {
Ok((vec![0u8; 1088], vec![0u8; 32])) }
async fn newhope_encapsulate(&self, _public_key: &[u8]) -> Result<(Vec<u8>, Vec<u8>)> {
Ok((vec![0u8; 2048], vec![0u8; 32])) }
async fn frodokem_encapsulate(&self, _public_key: &[u8]) -> Result<(Vec<u8>, Vec<u8>)> {
Ok((vec![0u8; 15744], vec![0u8; 24])) }
async fn kyber_decapsulate(&self, _private_key: &[u8], _ciphertext: &[u8]) -> Result<Vec<u8>> {
Ok(vec![0u8; 32]) }
async fn newhope_decapsulate(
&self,
_private_key: &[u8],
_ciphertext: &[u8],
) -> Result<Vec<u8>> {
Ok(vec![0u8; 32]) }
async fn frodokem_decapsulate(
&self,
_private_key: &[u8],
_ciphertext: &[u8],
) -> Result<Vec<u8>> {
Ok(vec![0u8; 24]) }
pub async fn get_metrics(&self) -> PQCryptoMetrics {
self.metrics.read().await.clone()
}
}
#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct PostQuantumKeyPair {
pub id: String,
pub algorithm: PostQuantumSignature,
pub public_key: Vec<u8>,
pub private_key: Vec<u8>,
pub created_at: DateTime<Utc>,
}
#[derive(Debug, Clone)]
struct SignatureInfo {
signature: Vec<u8>,
algorithm: PostQuantumSignature,
created_at: DateTime<Utc>,
}
#[derive(Debug, Clone, Default)]
pub struct PQCryptoMetrics {
pub key_generation_count: u64,
pub signature_count: u64,
pub verification_count: u64,
pub successful_verifications: u64,
pub avg_key_generation_time_ms: f64,
pub avg_signing_time_ms: f64,
pub avg_verification_time_ms: f64,
pub encapsulation_count: u64,
pub decapsulation_count: u64,
pub avg_encapsulation_time_ms: f64,
pub avg_decapsulation_time_ms: f64,
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn test_security_config_defaults() {
let config = SecurityConfig::default();
assert!(config.authentication.methods.contains(&AuthMethod::ApiKey));
assert!(config.authorization.rbac.enabled);
assert!(config.encryption.at_rest.enabled);
assert!(config.audit.enabled);
}
#[test]
fn test_security_context_permissions() {
let mut context = SecurityContext {
user_id: Some("test_user".to_string()),
session_id: None,
roles: HashSet::new(),
permissions: HashSet::new(),
attributes: HashMap::new(),
ip_address: None,
user_agent: None,
authentication_method: None,
authenticated_at: None,
};
context.permissions.insert(Permission::Read);
assert!(context.has_permission(&Permission::Read));
assert!(!context.has_permission(&Permission::Write));
}
#[test]
fn test_credentials_identifier() {
let creds = Credentials::ApiKey {
key: "test_key".to_string(),
ip_address: None,
};
assert_eq!(creds.identifier(), "api_key:test_key");
}
#[test]
fn test_rbac_config_default_roles() {
let rbac = RbacConfig::default();
assert!(rbac.role_permissions.contains_key("admin"));
assert!(rbac.role_permissions.contains_key("user"));
assert!(rbac.role_permissions.contains_key("viewer"));
let admin_perms = rbac.role_permissions.get("admin").unwrap();
assert!(admin_perms.contains(&Permission::Admin));
assert!(admin_perms.contains(&Permission::Read));
assert!(admin_perms.contains(&Permission::Write));
}
}