Skip to main content

oxirs_stream/security/
mod.rs

1//! # Advanced Security Framework
2//!
3//! Comprehensive security implementation for OxiRS Stream, providing authentication,
4//! authorization, encryption, audit logging, and threat detection capabilities.
5
6use anyhow::Result;
7use chrono::{Duration as ChronoDuration, Utc};
8use serde::{Deserialize, Serialize};
9use std::collections::HashMap;
10use std::sync::Arc;
11use std::time::Instant;
12use tokio::sync::RwLock;
13
14pub mod post_quantum;
15pub mod traits;
16
17pub use post_quantum::{PQCryptoMetrics, PostQuantumCryptoEngine, PostQuantumKeyPair};
18pub use traits::{
19    AuditFilter, AuditLogEntry, AuditLogger, AuthenticationProvider, AuthorizationProvider,
20    Credentials, RateLimiter, SecurityContext, SecurityMetrics, ThreatAlert, ThreatContext,
21    ThreatDetector,
22};
23
24/// Security configuration
25#[derive(Debug, Clone, Serialize, Deserialize, Default)]
26pub struct SecurityConfig {
27    /// Authentication configuration
28    pub authentication: AuthConfig,
29    /// Authorization configuration
30    pub authorization: AuthzConfig,
31    /// Encryption configuration
32    pub encryption: EncryptionConfig,
33    /// Post-quantum cryptography configuration
34    pub post_quantum: PostQuantumConfig,
35    /// Quantum-resistant certificates configuration
36    pub quantum_resistant_certs: QuantumResistantCerts,
37    /// Audit logging configuration
38    pub audit: AuditConfig,
39    /// Threat detection configuration
40    pub threat_detection: ThreatDetectionConfig,
41    /// Rate limiting configuration
42    pub rate_limiting: RateLimitConfig,
43    /// Session management configuration
44    pub session: SessionConfig,
45}
46
47/// Authentication configuration
48#[derive(Debug, Clone, Serialize, Deserialize)]
49pub struct AuthConfig {
50    /// Enabled authentication methods
51    pub methods: Vec<AuthMethod>,
52    /// Multi-factor authentication settings
53    pub mfa: MfaConfig,
54    /// Token settings
55    pub token: TokenConfig,
56    /// Password policy
57    pub password_policy: PasswordPolicy,
58}
59
60impl Default for AuthConfig {
61    fn default() -> Self {
62        Self {
63            methods: vec![AuthMethod::ApiKey, AuthMethod::JWT],
64            mfa: MfaConfig::default(),
65            token: TokenConfig::default(),
66            password_policy: PasswordPolicy::default(),
67        }
68    }
69}
70
71/// Authentication methods
72#[derive(Debug, Clone, Serialize, Deserialize, PartialEq)]
73pub enum AuthMethod {
74    ApiKey,
75    JWT,
76    OAuth2,
77    SAML,
78    Certificate,
79    Basic,
80}
81
82/// Multi-factor authentication configuration
83#[derive(Debug, Clone, Serialize, Deserialize)]
84pub struct MfaConfig {
85    pub enabled: bool,
86    pub required_for_admin: bool,
87    pub methods: Vec<MfaMethod>,
88    pub backup_codes: bool,
89}
90
91impl Default for MfaConfig {
92    fn default() -> Self {
93        Self {
94            enabled: false,
95            required_for_admin: true,
96            methods: vec![MfaMethod::TOTP],
97            backup_codes: true,
98        }
99    }
100}
101
102/// Multi-factor authentication methods
103#[derive(Debug, Clone, Serialize, Deserialize)]
104pub enum MfaMethod {
105    TOTP,     // Time-based One-Time Password
106    SMS,      // SMS-based codes
107    Email,    // Email-based codes
108    Hardware, // Hardware keys (FIDO2/WebAuthn)
109}
110
111/// Token configuration
112#[derive(Debug, Clone, Serialize, Deserialize)]
113pub struct TokenConfig {
114    pub jwt_secret: String,
115    pub access_token_ttl: ChronoDuration,
116    pub refresh_token_ttl: ChronoDuration,
117    pub issuer: String,
118    pub audience: String,
119}
120
121impl Default for TokenConfig {
122    fn default() -> Self {
123        Self {
124            jwt_secret: "change-this-secret".to_string(),
125            access_token_ttl: ChronoDuration::hours(1),
126            refresh_token_ttl: ChronoDuration::days(30),
127            issuer: "oxirs-stream".to_string(),
128            audience: "oxirs-api".to_string(),
129        }
130    }
131}
132
133/// Password policy configuration
134#[derive(Debug, Clone, Serialize, Deserialize)]
135pub struct PasswordPolicy {
136    pub min_length: usize,
137    pub require_uppercase: bool,
138    pub require_lowercase: bool,
139    pub require_numbers: bool,
140    pub require_symbols: bool,
141    pub max_age_days: Option<u32>,
142    pub history_count: usize,
143}
144
145impl Default for PasswordPolicy {
146    fn default() -> Self {
147        Self {
148            min_length: 12,
149            require_uppercase: true,
150            require_lowercase: true,
151            require_numbers: true,
152            require_symbols: true,
153            max_age_days: Some(90),
154            history_count: 5,
155        }
156    }
157}
158
159/// Authorization configuration
160#[derive(Debug, Clone, Serialize, Deserialize)]
161pub struct AuthzConfig {
162    /// Authorization model
163    pub model: AuthzModel,
164    /// Default permissions
165    pub default_permissions: Vec<Permission>,
166    /// Role-based access control
167    pub rbac: RbacConfig,
168    /// Attribute-based access control
169    pub abac: AbacConfig,
170}
171
172impl Default for AuthzConfig {
173    fn default() -> Self {
174        Self {
175            model: AuthzModel::RBAC,
176            default_permissions: vec![Permission::Read],
177            rbac: RbacConfig::default(),
178            abac: AbacConfig::default(),
179        }
180    }
181}
182
183/// Authorization models
184#[derive(Debug, Clone, Serialize, Deserialize)]
185pub enum AuthzModel {
186    RBAC, // Role-Based Access Control
187    ABAC, // Attribute-Based Access Control
188    MAC,  // Mandatory Access Control
189    DAC,  // Discretionary Access Control
190}
191
192/// Permissions
193#[derive(Debug, Clone, Serialize, Deserialize, PartialEq, Eq, Hash)]
194pub enum Permission {
195    Read,
196    Write,
197    Delete,
198    Admin,
199    Execute,
200    Stream,
201    Query,
202    Configure,
203}
204
205impl std::fmt::Display for Permission {
206    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
207        match self {
208            Permission::Read => write!(f, "read"),
209            Permission::Write => write!(f, "write"),
210            Permission::Delete => write!(f, "delete"),
211            Permission::Admin => write!(f, "admin"),
212            Permission::Execute => write!(f, "execute"),
213            Permission::Stream => write!(f, "stream"),
214            Permission::Query => write!(f, "query"),
215            Permission::Configure => write!(f, "configure"),
216        }
217    }
218}
219
220/// Role-based access control configuration
221#[derive(Debug, Clone, Serialize, Deserialize)]
222pub struct RbacConfig {
223    pub enabled: bool,
224    pub default_role: String,
225    pub role_hierarchy: HashMap<String, Vec<String>>,
226    pub role_permissions: HashMap<String, Vec<Permission>>,
227}
228
229impl Default for RbacConfig {
230    fn default() -> Self {
231        let mut role_permissions = HashMap::new();
232        role_permissions.insert(
233            "viewer".to_string(),
234            vec![Permission::Read, Permission::Query],
235        );
236        role_permissions.insert(
237            "user".to_string(),
238            vec![
239                Permission::Read,
240                Permission::Write,
241                Permission::Stream,
242                Permission::Query,
243            ],
244        );
245        role_permissions.insert(
246            "admin".to_string(),
247            vec![
248                Permission::Read,
249                Permission::Write,
250                Permission::Delete,
251                Permission::Admin,
252                Permission::Execute,
253                Permission::Stream,
254                Permission::Query,
255                Permission::Configure,
256            ],
257        );
258
259        let mut role_hierarchy = HashMap::new();
260        role_hierarchy.insert(
261            "admin".to_string(),
262            vec!["user".to_string(), "viewer".to_string()],
263        );
264        role_hierarchy.insert("user".to_string(), vec!["viewer".to_string()]);
265
266        Self {
267            enabled: true,
268            default_role: "viewer".to_string(),
269            role_hierarchy,
270            role_permissions,
271        }
272    }
273}
274
275/// Attribute-based access control configuration
276#[derive(Debug, Clone, Serialize, Deserialize)]
277pub struct AbacConfig {
278    pub enabled: bool,
279    pub policy_engine: PolicyEngine,
280    pub attributes: Vec<AttributeDefinition>,
281}
282
283impl Default for AbacConfig {
284    fn default() -> Self {
285        Self {
286            enabled: false,
287            policy_engine: PolicyEngine::default(),
288            attributes: vec![
289                AttributeDefinition {
290                    name: "department".to_string(),
291                    attribute_type: AttributeType::String,
292                    required: false,
293                },
294                AttributeDefinition {
295                    name: "security_level".to_string(),
296                    attribute_type: AttributeType::Integer,
297                    required: true,
298                },
299            ],
300        }
301    }
302}
303
304/// Policy engine configuration
305#[derive(Debug, Clone, Serialize, Deserialize)]
306pub struct PolicyEngine {
307    pub language: PolicyLanguage,
308    pub cache_policies: bool,
309    pub policy_files: Vec<String>,
310}
311
312impl Default for PolicyEngine {
313    fn default() -> Self {
314        Self {
315            language: PolicyLanguage::OPA,
316            cache_policies: true,
317            policy_files: vec!["/etc/oxirs/policies/".to_string()],
318        }
319    }
320}
321
322/// Policy languages
323#[derive(Debug, Clone, Serialize, Deserialize)]
324pub enum PolicyLanguage {
325    OPA,    // Open Policy Agent (Rego)
326    XACML,  // eXtensible Access Control Markup Language
327    Cedar,  // Amazon Cedar
328    Custom, // Custom policy language
329}
330
331/// Attribute definition for ABAC
332#[derive(Debug, Clone, Serialize, Deserialize)]
333pub struct AttributeDefinition {
334    pub name: String,
335    pub attribute_type: AttributeType,
336    pub required: bool,
337}
338
339/// Attribute types
340#[derive(Debug, Clone, Serialize, Deserialize)]
341pub enum AttributeType {
342    String,
343    Integer,
344    Boolean,
345    Float,
346    List,
347}
348
349/// Encryption configuration
350#[derive(Debug, Clone, Serialize, Deserialize, Default)]
351pub struct EncryptionConfig {
352    /// Data at rest encryption
353    pub at_rest: EncryptionAtRest,
354    /// Data in transit encryption
355    pub in_transit: EncryptionInTransit,
356    /// Field-level encryption
357    pub field_level: FieldLevelEncryption,
358}
359
360/// Data at rest encryption
361#[derive(Debug, Clone, Serialize, Deserialize)]
362pub struct EncryptionAtRest {
363    pub enabled: bool,
364    pub algorithm: EncryptionAlgorithm,
365    pub key_management: KeyManagement,
366}
367
368impl Default for EncryptionAtRest {
369    fn default() -> Self {
370        Self {
371            enabled: true,
372            algorithm: EncryptionAlgorithm::AES256GCM,
373            key_management: KeyManagement::default(),
374        }
375    }
376}
377
378/// Data in transit encryption
379#[derive(Debug, Clone, Serialize, Deserialize)]
380pub struct EncryptionInTransit {
381    pub enabled: bool,
382    pub tls_version: TlsVersion,
383    pub cipher_suites: Vec<String>,
384    pub certificate_validation: bool,
385}
386
387impl Default for EncryptionInTransit {
388    fn default() -> Self {
389        Self {
390            enabled: true,
391            tls_version: TlsVersion::V1_3,
392            cipher_suites: vec![
393                "TLS_AES_256_GCM_SHA384".to_string(),
394                "TLS_CHACHA20_POLY1305_SHA256".to_string(),
395            ],
396            certificate_validation: true,
397        }
398    }
399}
400
401/// Field-level encryption
402#[derive(Debug, Clone, Serialize, Deserialize)]
403pub struct FieldLevelEncryption {
404    pub enabled: bool,
405    pub fields: Vec<String>,
406    pub algorithm: EncryptionAlgorithm,
407}
408
409impl Default for FieldLevelEncryption {
410    fn default() -> Self {
411        Self {
412            enabled: false,
413            fields: vec!["password".to_string(), "ssn".to_string()],
414            algorithm: EncryptionAlgorithm::AES256GCM,
415        }
416    }
417}
418
419/// Encryption algorithms
420#[derive(Debug, Clone, Serialize, Deserialize)]
421pub enum EncryptionAlgorithm {
422    // Classical symmetric encryption
423    AES256GCM,
424    AES256CBC,
425    ChaCha20Poly1305,
426
427    // Post-quantum key encapsulation mechanisms (KEMs)
428    Kyber512,
429    Kyber768,
430    Kyber1024,
431
432    // Lattice-based encryption
433    NewHope1024,
434    FrodoKEM640,
435    FrodoKEM976,
436    FrodoKEM1344,
437
438    // Multivariate-based encryption
439    Rainbow1,
440    Rainbow3,
441    Rainbow5,
442
443    // Hash-based signatures with encryption
444    SphincsPlus128s,
445    SphincsPlus256s,
446
447    // Isogeny-based encryption
448    SikeP434,
449    SikeP503,
450    SikeP751,
451
452    // Code-based encryption
453    McEliece348864,
454    McEliece460896,
455    McEliece6688128,
456
457    // Hybrid classical-quantum
458    HybridAesKyber768,
459    HybridChaCha20NewHope,
460}
461
462/// TLS versions
463#[derive(Debug, Clone, Serialize, Deserialize)]
464pub enum TlsVersion {
465    V1_2,
466    V1_3,
467}
468
469/// Key management configuration
470#[derive(Debug, Clone, Serialize, Deserialize)]
471pub struct KeyManagement {
472    pub provider: KeyProvider,
473    pub rotation_interval: ChronoDuration,
474    pub key_derivation: KeyDerivation,
475}
476
477impl Default for KeyManagement {
478    fn default() -> Self {
479        Self {
480            provider: KeyProvider::Local,
481            rotation_interval: ChronoDuration::days(90),
482            key_derivation: KeyDerivation::PBKDF2,
483        }
484    }
485}
486
487/// Key providers
488#[derive(Debug, Clone, Serialize, Deserialize)]
489pub enum KeyProvider {
490    Local,
491    HSM,
492    AwsKms,
493    AzureKeyVault,
494    HashiCorpVault,
495}
496
497/// Key derivation functions
498#[derive(Debug, Clone, Serialize, Deserialize)]
499pub enum KeyDerivation {
500    // Classical key derivation
501    PBKDF2,
502    Scrypt,
503    Argon2,
504
505    // Post-quantum key derivation
506    LatticeBasedKDF,
507    HashBasedKDF,
508    CodeBasedKDF,
509
510    // Quantum-resistant hybrid approaches
511    HybridArgon2Lattice,
512    HybridScryptHash,
513}
514
515/// Post-quantum signature algorithms
516#[derive(Debug, Clone, Serialize, Deserialize)]
517pub enum PostQuantumSignature {
518    // Lattice-based signatures
519    Dilithium2,
520    Dilithium3,
521    Dilithium5,
522
523    // Hash-based signatures
524    SphincsPlusSha2128s,
525    SphincsPlusSha2128f,
526    SphincsPlusSha2192s,
527    SphincsPlusSha2192f,
528    SphincsPlusSha2256s,
529    SphincsPlusSha2256f,
530    SphincsPlusShake128s,
531    SphincsPlusShake128f,
532    SphincsPlusShake192s,
533    SphincsPlusShake192f,
534    SphincsPlusShake256s,
535    SphincsPlusShake256f,
536
537    // Multivariate signatures
538    RainbowIClassic,
539    RainbowICircumzenithal,
540    RainbowICompressed,
541    RainbowIiiClassic,
542    RainbowIiiCircumzenithal,
543    RainbowIiiCompressed,
544    RainbowVClassic,
545    RainbowVCircumzenithal,
546    RainbowVCompressed,
547
548    // Falcon signatures
549    Falcon512,
550    Falcon1024,
551
552    // PICNIC signatures
553    PicnicL1Fs,
554    PicnicL1Ur,
555    PicnicL3Fs,
556    PicnicL3Ur,
557    PicnicL5Fs,
558    PicnicL5Ur,
559}
560
561/// Post-quantum cryptography configuration
562#[derive(Debug, Clone, Serialize, Deserialize)]
563pub struct PostQuantumConfig {
564    pub enabled: bool,
565    pub primary_kem: Option<EncryptionAlgorithm>,
566    pub signature_algorithm: Option<PostQuantumSignature>,
567    pub hybrid_mode: bool,
568    pub classical_fallback: bool,
569    pub quantum_security_level: QuantumSecurityLevel,
570    pub key_size_preferences: KeySizePreferences,
571}
572
573impl Default for PostQuantumConfig {
574    fn default() -> Self {
575        Self {
576            enabled: true,
577            primary_kem: Some(EncryptionAlgorithm::Kyber768),
578            signature_algorithm: Some(PostQuantumSignature::Dilithium3),
579            hybrid_mode: true,
580            classical_fallback: true,
581            quantum_security_level: QuantumSecurityLevel::Level3,
582            key_size_preferences: KeySizePreferences::default(),
583        }
584    }
585}
586
587/// Quantum security levels (NIST standardization levels)
588#[derive(Debug, Clone, Serialize, Deserialize)]
589pub enum QuantumSecurityLevel {
590    Level1, // Equivalent to AES-128
591    Level2, // Equivalent to SHA-256
592    Level3, // Equivalent to AES-192
593    Level4, // Equivalent to SHA-384
594    Level5, // Equivalent to AES-256
595}
596
597/// Key size preferences for post-quantum algorithms
598#[derive(Debug, Clone, Serialize, Deserialize)]
599pub struct KeySizePreferences {
600    pub prefer_smaller_keys: bool,
601    pub prefer_faster_signing: bool,
602    pub prefer_faster_verification: bool,
603    pub max_signature_size_kb: Option<u32>,
604    pub max_public_key_size_kb: Option<u32>,
605}
606
607impl Default for KeySizePreferences {
608    fn default() -> Self {
609        Self {
610            prefer_smaller_keys: true,
611            prefer_faster_signing: false,
612            prefer_faster_verification: true,
613            max_signature_size_kb: Some(50),
614            max_public_key_size_kb: Some(10),
615        }
616    }
617}
618
619/// Quantum-resistant certificate configuration
620#[derive(Debug, Clone, Serialize, Deserialize)]
621pub struct QuantumResistantCerts {
622    pub enabled: bool,
623    pub use_hybrid_certificates: bool,
624    pub pq_signature_algorithm: PostQuantumSignature,
625    pub classical_signature_fallback: bool,
626    pub certificate_chain_validation: PQCertValidation,
627}
628
629impl Default for QuantumResistantCerts {
630    fn default() -> Self {
631        Self {
632            enabled: false,
633            use_hybrid_certificates: true,
634            pq_signature_algorithm: PostQuantumSignature::Dilithium3,
635            classical_signature_fallback: true,
636            certificate_chain_validation: PQCertValidation::default(),
637        }
638    }
639}
640
641/// Post-quantum certificate validation rules
642#[derive(Debug, Clone, Serialize, Deserialize)]
643pub struct PQCertValidation {
644    pub require_pq_signatures: bool,
645    pub allow_mixed_chain: bool,
646    pub minimum_security_level: QuantumSecurityLevel,
647    pub validate_quantum_resistance: bool,
648}
649
650impl Default for PQCertValidation {
651    fn default() -> Self {
652        Self {
653            require_pq_signatures: false,
654            allow_mixed_chain: true,
655            minimum_security_level: QuantumSecurityLevel::Level3,
656            validate_quantum_resistance: true,
657        }
658    }
659}
660
661/// Audit configuration
662#[derive(Debug, Clone, Serialize, Deserialize)]
663pub struct AuditConfig {
664    pub enabled: bool,
665    pub events: Vec<AuditEvent>,
666    pub retention_days: u32,
667    pub log_format: AuditLogFormat,
668    pub output: AuditOutput,
669}
670
671impl Default for AuditConfig {
672    fn default() -> Self {
673        Self {
674            enabled: true,
675            events: vec![
676                AuditEvent::Authentication,
677                AuditEvent::Authorization,
678                AuditEvent::DataAccess,
679                AuditEvent::ConfigChange,
680            ],
681            retention_days: 365,
682            log_format: AuditLogFormat::JSON,
683            output: AuditOutput::File("/var/log/oxirs/audit.log".to_string()),
684        }
685    }
686}
687
688/// Audit events
689#[derive(Debug, Clone, Serialize, Deserialize)]
690pub enum AuditEvent {
691    Authentication,
692    Authorization,
693    DataAccess,
694    ConfigChange,
695    UserManagement,
696    SecurityAlert,
697}
698
699/// Audit log formats
700#[derive(Debug, Clone, Serialize, Deserialize)]
701pub enum AuditLogFormat {
702    JSON,
703    CEF,  // Common Event Format
704    LEEF, // Log Event Extended Format
705    Syslog,
706}
707
708/// Audit output destinations
709#[derive(Debug, Clone, Serialize, Deserialize)]
710pub enum AuditOutput {
711    File(String),
712    Syslog,
713    Database,
714    SIEM(String), // SIEM endpoint
715}
716
717/// Threat detection configuration
718#[derive(Debug, Clone, Serialize, Deserialize)]
719pub struct ThreatDetectionConfig {
720    pub enabled: bool,
721    pub rules: Vec<ThreatRule>,
722    pub anomaly_detection: AnomalyDetectionConfig,
723    pub response: ThreatResponseConfig,
724}
725
726impl Default for ThreatDetectionConfig {
727    fn default() -> Self {
728        Self {
729            enabled: true,
730            rules: vec![
731                ThreatRule {
732                    name: "Multiple Failed Logins".to_string(),
733                    description: "Detect multiple failed login attempts".to_string(),
734                    condition: "failed_logins > 5 in 5m".to_string(),
735                    severity: ThreatSeverity::High,
736                    enabled: true,
737                },
738                ThreatRule {
739                    name: "Unusual Access Pattern".to_string(),
740                    description: "Detect unusual access patterns".to_string(),
741                    condition: "requests > 1000 in 1m".to_string(),
742                    severity: ThreatSeverity::Medium,
743                    enabled: true,
744                },
745            ],
746            anomaly_detection: AnomalyDetectionConfig::default(),
747            response: ThreatResponseConfig::default(),
748        }
749    }
750}
751
752/// Threat detection rule
753#[derive(Debug, Clone, Serialize, Deserialize)]
754pub struct ThreatRule {
755    pub name: String,
756    pub description: String,
757    pub condition: String,
758    pub severity: ThreatSeverity,
759    pub enabled: bool,
760}
761
762/// Threat severity levels
763#[derive(Debug, Clone, Serialize, Deserialize, PartialEq, Eq, Hash)]
764pub enum ThreatSeverity {
765    Low,
766    Medium,
767    High,
768    Critical,
769}
770
771/// Anomaly detection configuration
772#[derive(Debug, Clone, Serialize, Deserialize)]
773pub struct AnomalyDetectionConfig {
774    pub enabled: bool,
775    pub algorithms: Vec<AnomalyAlgorithm>,
776    pub sensitivity: f64,
777    pub learning_period_days: u32,
778}
779
780impl Default for AnomalyDetectionConfig {
781    fn default() -> Self {
782        Self {
783            enabled: true,
784            algorithms: vec![
785                AnomalyAlgorithm::IsolationForest,
786                AnomalyAlgorithm::StatisticalOutlier,
787            ],
788            sensitivity: 0.8,
789            learning_period_days: 30,
790        }
791    }
792}
793
794/// Anomaly detection algorithms
795#[derive(Debug, Clone, Serialize, Deserialize)]
796pub enum AnomalyAlgorithm {
797    IsolationForest,
798    StatisticalOutlier,
799    LSTM,
800    KMeans,
801}
802
803/// Threat response configuration
804#[derive(Debug, Clone, Serialize, Deserialize)]
805pub struct ThreatResponseConfig {
806    pub auto_response: bool,
807    pub actions: Vec<ResponseAction>,
808    pub escalation: EscalationConfig,
809}
810
811impl Default for ThreatResponseConfig {
812    fn default() -> Self {
813        Self {
814            auto_response: true,
815            actions: vec![
816                ResponseAction::Block,
817                ResponseAction::RateLimit,
818                ResponseAction::Alert,
819            ],
820            escalation: EscalationConfig::default(),
821        }
822    }
823}
824
825/// Response actions
826#[derive(Debug, Clone, Serialize, Deserialize)]
827pub enum ResponseAction {
828    Block,
829    RateLimit,
830    Alert,
831    Quarantine,
832    Notify,
833}
834
835/// Escalation configuration
836#[derive(Debug, Clone, Serialize, Deserialize)]
837pub struct EscalationConfig {
838    pub enabled: bool,
839    pub thresholds: HashMap<ThreatSeverity, u32>,
840    pub notifications: Vec<String>, // email addresses or webhook URLs
841}
842
843impl Default for EscalationConfig {
844    fn default() -> Self {
845        let mut thresholds = HashMap::new();
846        thresholds.insert(ThreatSeverity::Low, 10);
847        thresholds.insert(ThreatSeverity::Medium, 5);
848        thresholds.insert(ThreatSeverity::High, 1);
849        thresholds.insert(ThreatSeverity::Critical, 1);
850
851        Self {
852            enabled: true,
853            thresholds,
854            notifications: vec!["security@example.com".to_string()],
855        }
856    }
857}
858
859/// Rate limiting configuration
860#[derive(Debug, Clone, Serialize, Deserialize)]
861pub struct RateLimitConfig {
862    pub enabled: bool,
863    pub global_limit: RateLimit,
864    pub per_user_limit: RateLimit,
865    pub per_ip_limit: RateLimit,
866    pub burst_limit: RateLimit,
867}
868
869impl Default for RateLimitConfig {
870    fn default() -> Self {
871        Self {
872            enabled: true,
873            global_limit: RateLimit {
874                requests: 10000,
875                window: ChronoDuration::minutes(1),
876            },
877            per_user_limit: RateLimit {
878                requests: 100,
879                window: ChronoDuration::minutes(1),
880            },
881            per_ip_limit: RateLimit {
882                requests: 1000,
883                window: ChronoDuration::minutes(1),
884            },
885            burst_limit: RateLimit {
886                requests: 50,
887                window: ChronoDuration::seconds(10),
888            },
889        }
890    }
891}
892
893/// Rate limit definition
894#[derive(Debug, Clone, Serialize, Deserialize)]
895pub struct RateLimit {
896    pub requests: u32,
897    pub window: ChronoDuration,
898}
899
900/// Session management configuration
901#[derive(Debug, Clone, Serialize, Deserialize)]
902pub struct SessionConfig {
903    pub timeout: ChronoDuration,
904    pub max_concurrent: u32,
905    pub secure_cookies: bool,
906    pub same_site: SameSite,
907}
908
909impl Default for SessionConfig {
910    fn default() -> Self {
911        Self {
912            timeout: ChronoDuration::hours(8),
913            max_concurrent: 5,
914            secure_cookies: true,
915            same_site: SameSite::Strict,
916        }
917    }
918}
919
920/// SameSite cookie attribute
921#[derive(Debug, Clone, Serialize, Deserialize)]
922pub enum SameSite {
923    Strict,
924    Lax,
925    None,
926}
927
928/// Security manager
929pub struct SecurityManager {
930    config: SecurityConfig,
931    auth_provider: Arc<dyn AuthenticationProvider>,
932    authz_provider: Arc<dyn AuthorizationProvider>,
933    audit_logger: Arc<dyn AuditLogger>,
934    threat_detector: Arc<dyn ThreatDetector>,
935    rate_limiter: Arc<dyn RateLimiter>,
936    metrics: Arc<RwLock<SecurityMetrics>>,
937}
938
939impl SecurityManager {
940    /// Create a new security manager
941    pub fn new(
942        config: SecurityConfig,
943        auth_provider: Arc<dyn AuthenticationProvider>,
944        authz_provider: Arc<dyn AuthorizationProvider>,
945        audit_logger: Arc<dyn AuditLogger>,
946        threat_detector: Arc<dyn ThreatDetector>,
947        rate_limiter: Arc<dyn RateLimiter>,
948    ) -> Self {
949        Self {
950            config,
951            auth_provider,
952            authz_provider,
953            audit_logger,
954            threat_detector,
955            rate_limiter,
956            metrics: Arc::new(RwLock::new(SecurityMetrics::default())),
957        }
958    }
959
960    /// Authenticate a request
961    pub async fn authenticate(&self, credentials: &Credentials) -> Result<SecurityContext> {
962        let start_time = Instant::now();
963
964        // Check rate limits first
965        if self.config.rate_limiting.enabled {
966            self.rate_limiter
967                .check_limit(&credentials.identifier())
968                .await?;
969        }
970
971        // Perform authentication
972        let result = self.auth_provider.authenticate(credentials).await;
973
974        // Log audit event
975        let audit_event = AuditLogEntry {
976            event_type: AuditEvent::Authentication,
977            timestamp: Utc::now(),
978            user_id: credentials.user_id().map(|s| s.to_string()),
979            ip_address: credentials.ip_address().map(|s| s.to_string()),
980            success: result.is_ok(),
981            details: format!("Authentication attempt for {}", credentials.identifier()),
982        };
983
984        let _ = self.audit_logger.log(audit_event).await;
985
986        // Update metrics
987        {
988            let mut metrics = self.metrics.write().await;
989            metrics.authentication_attempts += 1;
990            if result.is_ok() {
991                metrics.authentication_successes += 1;
992            } else {
993                metrics.authentication_failures += 1;
994            }
995            metrics.authentication_latency_ms = start_time.elapsed().as_millis() as f64;
996        }
997
998        // Check for threats
999        if result.is_err() {
1000            let _ = self
1001                .threat_detector
1002                .detect_threat(&ThreatContext {
1003                    event_type: "authentication_failure".to_string(),
1004                    user_id: credentials.user_id().map(|s| s.to_string()),
1005                    ip_address: credentials.ip_address().map(|s| s.to_string()),
1006                    timestamp: Utc::now(),
1007                    details: HashMap::new(),
1008                })
1009                .await;
1010        }
1011
1012        result
1013    }
1014
1015    /// Authorize a request
1016    pub async fn authorize(
1017        &self,
1018        context: &SecurityContext,
1019        resource: &str,
1020        action: &Permission,
1021    ) -> Result<bool> {
1022        let start_time = Instant::now();
1023
1024        let result = self
1025            .authz_provider
1026            .authorize(context, resource, action)
1027            .await;
1028        let success = result.as_ref().map(|&b| b).unwrap_or(false);
1029
1030        // Log audit event
1031        let audit_event = AuditLogEntry {
1032            event_type: AuditEvent::Authorization,
1033            timestamp: Utc::now(),
1034            user_id: context.user_id.clone(),
1035            ip_address: context.ip_address.clone(),
1036            success,
1037            details: format!("Authorization check for {action} on {resource}"),
1038        };
1039
1040        let _ = self.audit_logger.log(audit_event).await;
1041
1042        // Update metrics
1043        {
1044            let mut metrics = self.metrics.write().await;
1045            metrics.authorization_checks += 1;
1046            if success {
1047                metrics.authorization_successes += 1;
1048            } else {
1049                metrics.authorization_failures += 1;
1050            }
1051            metrics.authorization_latency_ms = start_time.elapsed().as_millis() as f64;
1052        }
1053
1054        result
1055    }
1056
1057    /// Log data access
1058    pub async fn log_data_access(
1059        &self,
1060        context: &SecurityContext,
1061        resource: &str,
1062        operation: &str,
1063    ) -> Result<()> {
1064        let audit_event = AuditLogEntry {
1065            event_type: AuditEvent::DataAccess,
1066            timestamp: Utc::now(),
1067            user_id: context.user_id.clone(),
1068            ip_address: context.ip_address.clone(),
1069            success: true,
1070            details: format!("Data access: {operation} on {resource}"),
1071        };
1072
1073        self.audit_logger.log(audit_event).await
1074    }
1075
1076    /// Get security metrics
1077    pub async fn get_metrics(&self) -> SecurityMetrics {
1078        self.metrics.read().await.clone()
1079    }
1080}
1081
1082#[cfg(test)]
1083mod tests {
1084    use super::*;
1085    use std::collections::HashSet;
1086
1087    #[test]
1088    fn test_security_config_defaults() {
1089        let config = SecurityConfig::default();
1090        assert!(config.authentication.methods.contains(&AuthMethod::ApiKey));
1091        assert!(config.authorization.rbac.enabled);
1092        assert!(config.encryption.at_rest.enabled);
1093        assert!(config.audit.enabled);
1094    }
1095
1096    #[test]
1097    fn test_security_context_permissions() {
1098        let mut context = SecurityContext {
1099            user_id: Some("test_user".to_string()),
1100            session_id: None,
1101            roles: HashSet::new(),
1102            permissions: HashSet::new(),
1103            attributes: HashMap::new(),
1104            ip_address: None,
1105            user_agent: None,
1106            authentication_method: None,
1107            authenticated_at: None,
1108        };
1109
1110        context.permissions.insert(Permission::Read);
1111        assert!(context.has_permission(&Permission::Read));
1112        assert!(!context.has_permission(&Permission::Write));
1113    }
1114
1115    #[test]
1116    fn test_credentials_identifier() {
1117        let creds = Credentials::ApiKey {
1118            key: "test_key".to_string(),
1119            ip_address: None,
1120        };
1121
1122        assert_eq!(creds.identifier(), "api_key:test_key");
1123    }
1124
1125    #[test]
1126    fn test_rbac_config_default_roles() {
1127        let rbac = RbacConfig::default();
1128        assert!(rbac.role_permissions.contains_key("admin"));
1129        assert!(rbac.role_permissions.contains_key("user"));
1130        assert!(rbac.role_permissions.contains_key("viewer"));
1131
1132        let admin_perms = rbac.role_permissions.get("admin").unwrap();
1133        assert!(admin_perms.contains(&Permission::Admin));
1134        assert!(admin_perms.contains(&Permission::Read));
1135        assert!(admin_perms.contains(&Permission::Write));
1136    }
1137
1138    // ------------------------------------------------------------------
1139    // Post-quantum cryptography tests
1140    // ------------------------------------------------------------------
1141
1142    /// Without the `post-quantum` feature the engine must return a descriptive
1143    /// error rather than fake zero bytes.
1144    #[cfg(not(feature = "post-quantum"))]
1145    #[tokio::test]
1146    async fn test_pq_dilithium_requires_feature_flag() {
1147        let config = PostQuantumConfig::default();
1148        let engine = PostQuantumCryptoEngine::new(config);
1149        let result = engine
1150            .generate_keypair(&PostQuantumSignature::Dilithium3)
1151            .await;
1152        assert!(result.is_err());
1153        let msg = result.unwrap_err().to_string();
1154        assert!(
1155            msg.contains("post-quantum"),
1156            "error should mention the feature flag, got: {msg}"
1157        );
1158    }
1159
1160    #[cfg(not(feature = "post-quantum"))]
1161    #[tokio::test]
1162    async fn test_pq_kyber_encapsulate_requires_feature_flag() {
1163        let config = PostQuantumConfig::default();
1164        let engine = PostQuantumCryptoEngine::new(config);
1165        let dummy_pk = vec![0u8; 32];
1166        let result = engine
1167            .encapsulate(&dummy_pk, &EncryptionAlgorithm::Kyber768)
1168            .await;
1169        assert!(result.is_err());
1170        let msg = result.unwrap_err().to_string();
1171        assert!(
1172            msg.contains("post-quantum"),
1173            "error should mention the feature flag, got: {msg}"
1174        );
1175    }
1176
1177    /// With the `post-quantum` feature a Dilithium3 round-trip must succeed.
1178    #[cfg(feature = "post-quantum")]
1179    #[tokio::test]
1180    async fn test_pq_dilithium3_round_trip() {
1181        let config = PostQuantumConfig::default();
1182        let engine = PostQuantumCryptoEngine::new(config);
1183
1184        let keypair = engine
1185            .generate_keypair(&PostQuantumSignature::Dilithium3)
1186            .await
1187            .expect("Dilithium3 key generation failed");
1188
1189        let data = b"OxiRS post-quantum signing test vector";
1190        let sig_bytes = engine
1191            .sign(&keypair.id, data)
1192            .await
1193            .expect("Dilithium3 signing failed");
1194
1195        let valid = engine
1196            .verify(
1197                &keypair.public_key,
1198                data,
1199                &sig_bytes,
1200                &PostQuantumSignature::Dilithium3,
1201            )
1202            .await
1203            .expect("Dilithium3 verification failed");
1204        assert!(valid, "valid Dilithium3 signature must verify as true");
1205
1206        let tampered = b"OxiRS post-quantum signing test vector TAMPERED";
1207        let invalid = engine
1208            .verify(
1209                &keypair.public_key,
1210                tampered,
1211                &sig_bytes,
1212                &PostQuantumSignature::Dilithium3,
1213            )
1214            .await
1215            .expect("Dilithium3 tampered-data verification call failed");
1216        assert!(
1217            !invalid,
1218            "Dilithium3 signature over tampered data must not verify"
1219        );
1220    }
1221
1222    /// With the `post-quantum` feature a Kyber768 KEM round-trip must succeed.
1223    #[cfg(feature = "post-quantum")]
1224    #[tokio::test]
1225    async fn test_pq_kyber768_kem_round_trip() {
1226        let config = PostQuantumConfig::default();
1227        let engine = PostQuantumCryptoEngine::new(config);
1228
1229        // Generate a fresh Kyber768 key pair for KEM
1230        use pqcrypto_traits::kem::{PublicKey as _, SecretKey as _};
1231        let (pk, sk) = pqcrypto_kyber::kyber768::keypair();
1232        let pk_bytes = pk.as_bytes().to_vec();
1233        let sk_bytes = sk.as_bytes().to_vec();
1234
1235        // Encapsulate
1236        let (ct, ss_enc) = engine
1237            .encapsulate(&pk_bytes, &EncryptionAlgorithm::Kyber768)
1238            .await
1239            .expect("Kyber768 encapsulation failed");
1240
1241        // Decapsulate
1242        let ss_dec = engine
1243            .decapsulate(&sk_bytes, &ct, &EncryptionAlgorithm::Kyber768)
1244            .await
1245            .expect("Kyber768 decapsulation failed");
1246
1247        assert_eq!(
1248            ss_enc, ss_dec,
1249            "encapsulated and decapsulated shared secrets must match"
1250        );
1251        assert_eq!(ss_enc.len(), 32, "Kyber768 shared secret must be 32 bytes");
1252    }
1253
1254    /// With the `post-quantum` feature, SPHINCS+ SHA2-256s round-trip.
1255    #[cfg(feature = "post-quantum")]
1256    #[tokio::test]
1257    async fn test_pq_sphincsplus_sha2_256s_round_trip() {
1258        let config = PostQuantumConfig::default();
1259        let engine = PostQuantumCryptoEngine::new(config);
1260
1261        let keypair = engine
1262            .generate_keypair(&PostQuantumSignature::SphincsPlusSha2256s)
1263            .await
1264            .expect("SPHINCS+ SHA2-256s key generation failed");
1265
1266        let data = b"SPHINCS+ signing test vector";
1267        let sig_bytes = engine
1268            .sign(&keypair.id, data)
1269            .await
1270            .expect("SPHINCS+ signing failed");
1271
1272        let valid = engine
1273            .verify(
1274                &keypair.public_key,
1275                data,
1276                &sig_bytes,
1277                &PostQuantumSignature::SphincsPlusSha2256s,
1278            )
1279            .await
1280            .expect("SPHINCS+ verification failed");
1281        assert!(valid, "valid SPHINCS+ signature must verify");
1282    }
1283
1284    /// Without the `post-quantum` feature Falcon must return a descriptive error.
1285    #[cfg(not(feature = "post-quantum"))]
1286    #[tokio::test]
1287    async fn test_pq_falcon_requires_feature_flag() {
1288        let config = PostQuantumConfig::default();
1289        let engine = PostQuantumCryptoEngine::new(config);
1290        let result = engine
1291            .generate_keypair(&PostQuantumSignature::Falcon1024)
1292            .await;
1293        assert!(result.is_err());
1294        let msg = result.unwrap_err().to_string();
1295        assert!(
1296            msg.contains("post-quantum"),
1297            "error should mention the feature flag, got: {msg}"
1298        );
1299    }
1300
1301    /// With the `post-quantum` feature a Falcon512 round-trip must succeed.
1302    #[cfg(feature = "post-quantum")]
1303    #[tokio::test]
1304    async fn test_pq_falcon512_round_trip() {
1305        let config = PostQuantumConfig::default();
1306        let engine = PostQuantumCryptoEngine::new(config);
1307
1308        let keypair = engine
1309            .generate_keypair(&PostQuantumSignature::Falcon512)
1310            .await
1311            .expect("Falcon512 key generation failed");
1312
1313        let data = b"OxiRS Falcon512 signing test vector";
1314
1315        let sig_bytes = engine
1316            .sign(&keypair.id, data)
1317            .await
1318            .expect("Falcon512 signing failed");
1319        assert!(
1320            !sig_bytes.is_empty(),
1321            "Falcon512 signature must not be empty"
1322        );
1323
1324        // Correct data → valid
1325        let valid = engine
1326            .verify(
1327                &keypair.public_key,
1328                data,
1329                &sig_bytes,
1330                &PostQuantumSignature::Falcon512,
1331            )
1332            .await
1333            .expect("Falcon512 verification failed");
1334        assert!(valid, "valid Falcon512 signature must verify as true");
1335
1336        // Tampered data → invalid
1337        let tampered = b"OxiRS Falcon512 signing test vector TAMPERED";
1338        let invalid = engine
1339            .verify(
1340                &keypair.public_key,
1341                tampered,
1342                &sig_bytes,
1343                &PostQuantumSignature::Falcon512,
1344            )
1345            .await
1346            .expect("Falcon512 tampered-data verification call failed");
1347        assert!(
1348            !invalid,
1349            "Falcon512 signature over tampered data must not verify"
1350        );
1351    }
1352
1353    /// With the `post-quantum` feature a Falcon1024 round-trip must succeed.
1354    #[cfg(feature = "post-quantum")]
1355    #[tokio::test]
1356    async fn test_pq_falcon1024_round_trip() {
1357        let config = PostQuantumConfig::default();
1358        let engine = PostQuantumCryptoEngine::new(config);
1359
1360        let keypair = engine
1361            .generate_keypair(&PostQuantumSignature::Falcon1024)
1362            .await
1363            .expect("Falcon1024 key generation failed");
1364
1365        let data = b"OxiRS Falcon1024 signing test vector";
1366
1367        let sig_bytes = engine
1368            .sign(&keypair.id, data)
1369            .await
1370            .expect("Falcon1024 signing failed");
1371        assert!(
1372            !sig_bytes.is_empty(),
1373            "Falcon1024 signature must not be empty"
1374        );
1375
1376        // Correct data → valid
1377        let valid = engine
1378            .verify(
1379                &keypair.public_key,
1380                data,
1381                &sig_bytes,
1382                &PostQuantumSignature::Falcon1024,
1383            )
1384            .await
1385            .expect("Falcon1024 verification failed");
1386        assert!(valid, "valid Falcon1024 signature must verify as true");
1387
1388        // Tampered data → invalid
1389        let tampered = b"OxiRS Falcon1024 signing test vector TAMPERED";
1390        let invalid = engine
1391            .verify(
1392                &keypair.public_key,
1393                tampered,
1394                &sig_bytes,
1395                &PostQuantumSignature::Falcon1024,
1396            )
1397            .await
1398            .expect("Falcon1024 tampered-data verification call failed");
1399        assert!(
1400            !invalid,
1401            "Falcon1024 signature over tampered data must not verify"
1402        );
1403    }
1404
1405    /// NewHope and FrodoKEM are always unavailable (no crate exists).
1406    #[tokio::test]
1407    async fn test_pq_newhope_not_yet_supported() {
1408        let config = PostQuantumConfig::default();
1409        let engine = PostQuantumCryptoEngine::new(config);
1410        let dummy_pk = vec![0u8; 32];
1411        let result = engine
1412            .encapsulate(&dummy_pk, &EncryptionAlgorithm::NewHope1024)
1413            .await;
1414        assert!(result.is_err());
1415        let msg = result.unwrap_err().to_string();
1416        assert!(
1417            msg.contains("NewHope"),
1418            "error should mention NewHope, got: {msg}"
1419        );
1420    }
1421
1422    #[tokio::test]
1423    async fn test_pq_frodokem_not_yet_supported() {
1424        let config = PostQuantumConfig::default();
1425        let engine = PostQuantumCryptoEngine::new(config);
1426        let dummy_pk = vec![0u8; 32];
1427        let result = engine
1428            .encapsulate(&dummy_pk, &EncryptionAlgorithm::FrodoKEM976)
1429            .await;
1430        assert!(result.is_err());
1431        let msg = result.unwrap_err().to_string();
1432        assert!(
1433            msg.contains("FrodoKEM"),
1434            "error should mention FrodoKEM, got: {msg}"
1435        );
1436    }
1437}