auth_framework/server/core/
common_config.rs

1//! Common Configuration Framework
2//!
3//! This module provides shared configuration patterns and utilities
4//! to eliminate duplication across server modules.
5
6use crate::errors::Result;
7use serde::{Deserialize, Serialize};
8use std::collections::HashMap;
9use std::time::Duration;
10
11/// Base configuration trait that all server configs can implement
12pub trait ServerConfig {
13    /// Validate the configuration
14    fn validate(&self) -> Result<()> {
15        Ok(())
16    }
17
18    /// Get configuration name for logging/debugging
19    fn config_name(&self) -> &'static str;
20
21    /// Check if configuration is enabled
22    fn is_enabled(&self) -> bool {
23        true
24    }
25}
26
27/// Common timeout configuration used across modules
28#[derive(Debug, Clone, Serialize, Deserialize)]
29pub struct TimeoutConfig {
30    /// Connection timeout
31    pub connect_timeout: Duration,
32    /// Read timeout
33    pub read_timeout: Duration,
34    /// Write timeout
35    pub write_timeout: Duration,
36}
37
38impl Default for TimeoutConfig {
39    fn default() -> Self {
40        Self {
41            connect_timeout: Duration::from_secs(30),
42            read_timeout: Duration::from_secs(30),
43            write_timeout: Duration::from_secs(30),
44        }
45    }
46}
47
48/// Common security configuration patterns
49#[derive(Debug, Clone, Serialize, Deserialize)]
50pub struct SecurityConfig {
51    /// Enable TLS
52    pub enable_tls: bool,
53    /// Minimum TLS version
54    pub min_tls_version: String,
55    /// Allowed cipher suites
56    pub cipher_suites: Vec<String>,
57    /// Certificate validation mode
58    pub cert_validation: CertificateValidation,
59    /// Whether to verify certificates (legacy compatibility)
60    pub verify_certificates: bool,
61}
62
63impl Default for SecurityConfig {
64    fn default() -> Self {
65        Self {
66            enable_tls: true,
67            min_tls_version: "1.2".to_string(),
68            cipher_suites: vec![
69                "TLS_AES_256_GCM_SHA384".to_string(),
70                "TLS_CHACHA20_POLY1305_SHA256".to_string(),
71                "TLS_AES_128_GCM_SHA256".to_string(),
72            ],
73            cert_validation: CertificateValidation::Full,
74            verify_certificates: true,
75        }
76    }
77}
78
79/// Certificate validation modes
80#[derive(Debug, Clone, Serialize, Deserialize)]
81pub enum CertificateValidation {
82    /// Full certificate chain validation
83    Full,
84    /// Skip hostname verification
85    SkipHostname,
86    /// Skip all certificate validation (insecure)
87    None,
88}
89
90/// Common endpoint configuration
91#[derive(Debug, Clone, Serialize, Deserialize)]
92pub struct EndpointConfig {
93    /// Base URL
94    pub base_url: String,
95    /// API version
96    pub api_version: Option<String>,
97    /// Custom headers
98    pub headers: HashMap<String, String>,
99    /// Timeout configuration
100    pub timeout: TimeoutConfig,
101    /// Security configuration
102    pub security: SecurityConfig,
103}
104
105impl EndpointConfig {
106    /// Create a new endpoint config with defaults
107    pub fn new(base_url: impl Into<String>) -> Self {
108        Self {
109            base_url: base_url.into(),
110            api_version: None,
111            headers: HashMap::new(),
112            timeout: TimeoutConfig::default(),
113            security: SecurityConfig::default(),
114        }
115    }
116
117    /// Add a custom header
118    pub fn with_header(mut self, key: impl Into<String>, value: impl Into<String>) -> Self {
119        self.headers.insert(key.into(), value.into());
120        self
121    }
122
123    /// Set API version
124    pub fn with_api_version(mut self, version: impl Into<String>) -> Self {
125        self.api_version = Some(version.into());
126        self
127    }
128}
129
130/// Common retry configuration
131#[derive(Debug, Clone, Serialize, Deserialize)]
132pub struct RetryConfig {
133    /// Maximum retry attempts
134    pub max_attempts: u32,
135    /// Initial delay between retries
136    pub initial_delay: Duration,
137    /// Maximum delay between retries
138    pub max_delay: Duration,
139    /// Backoff multiplier
140    pub backoff_multiplier: f64,
141    /// Jitter factor (0.0 to 1.0)
142    pub jitter_factor: f64,
143}
144
145impl Default for RetryConfig {
146    fn default() -> Self {
147        Self {
148            max_attempts: 3,
149            initial_delay: Duration::from_millis(100),
150            max_delay: Duration::from_secs(30),
151            backoff_multiplier: 2.0,
152            jitter_factor: 0.1,
153        }
154    }
155}
156
157/// Common logging configuration
158#[derive(Debug, Clone, Serialize, Deserialize)]
159pub struct LoggingConfig {
160    /// Enable debug logging
161    pub debug: bool,
162    /// Log request/response bodies
163    pub log_bodies: bool,
164    /// Log sensitive fields (tokens, keys)
165    pub log_sensitive: bool,
166    /// Maximum log message size
167    pub max_log_size: usize,
168}
169
170impl Default for LoggingConfig {
171    fn default() -> Self {
172        Self {
173            debug: false,
174            log_bodies: false,
175            log_sensitive: false,
176            max_log_size: 4096,
177        }
178    }
179}
180
181/// Configuration validation utilities
182pub mod validation {
183    use super::*;
184
185    /// Validate URL format
186    pub fn validate_url(url: &str) -> Result<()> {
187        if url.is_empty() {
188            return Err(crate::errors::AuthError::ConfigurationError(
189                "URL cannot be empty".to_string(),
190            ));
191        }
192
193        if !url.starts_with("http://") && !url.starts_with("https://") {
194            return Err(crate::errors::AuthError::ConfigurationError(format!(
195                "Invalid URL format: {}",
196                url
197            )));
198        }
199
200        Ok(())
201    }
202
203    /// Validate duration is positive
204    pub fn validate_positive_duration(duration: &Duration, field_name: &str) -> Result<()> {
205        if duration.is_zero() {
206            return Err(crate::errors::AuthError::ConfigurationError(format!(
207                "{} must be greater than zero",
208                field_name
209            )));
210        }
211        Ok(())
212    }
213
214    /// Validate port number
215    pub fn validate_port(port: u16) -> Result<()> {
216        if port == 0 {
217            return Err(crate::errors::AuthError::ConfigurationError(
218                "Port cannot be zero".to_string(),
219            ));
220        }
221        Ok(())
222    }
223
224    /// Validate required field is not empty
225    pub fn validate_required_field(value: &str, field_name: &str) -> Result<()> {
226        if value.trim().is_empty() {
227            return Err(crate::errors::AuthError::ConfigurationError(format!(
228                "{} is required and cannot be empty",
229                field_name
230            )));
231        }
232        Ok(())
233    }
234}
235
236