fraiseql_auth/
security_init.rs1use serde_json::Value as JsonValue;
7use tracing::{debug, info, warn};
8
9use super::security_config::SecurityConfigFromSchema;
10use crate::{AuthError, error::Result};
11
12const MAX_SCHEMA_JSON_SIZE: usize = 10 * 1024 * 1024; const MAX_SECURITY_CONFIG_SIZE: usize = 100 * 1024; pub fn init_security_config(schema_json_str: &str) -> Result<SecurityConfigFromSchema> {
58 debug!("Parsing schema JSON for security configuration");
59
60 if schema_json_str.len() > MAX_SCHEMA_JSON_SIZE {
62 warn!(
63 "Schema JSON exceeds maximum size: {} > {} bytes",
64 schema_json_str.len(),
65 MAX_SCHEMA_JSON_SIZE
66 );
67 return Err(AuthError::ConfigError {
68 message: format!("Schema JSON exceeds maximum size of {} bytes", MAX_SCHEMA_JSON_SIZE),
69 });
70 }
71
72 let schema_json: JsonValue = serde_json::from_str(schema_json_str).map_err(|e| {
74 warn!("Failed to parse schema JSON: {e}");
75 AuthError::ConfigError {
76 message: format!("Invalid schema JSON: {e}"),
77 }
78 })?;
79
80 init_security_config_from_value(&schema_json)
81}
82
83pub(crate) fn init_security_config_from_value(
103 schema_json: &JsonValue,
104) -> Result<SecurityConfigFromSchema> {
105 debug!("Initializing security configuration from schema");
106
107 let security_value = schema_json.get("security").ok_or_else(|| {
109 warn!("No security configuration found in schema, using defaults");
110 AuthError::ConfigError {
111 message: "Missing security configuration in schema".to_string(),
112 }
113 })?;
114
115 let security_json_str = security_value.to_string();
117 if security_json_str.len() > MAX_SECURITY_CONFIG_SIZE {
118 warn!(
119 "Security configuration exceeds maximum size: {} > {} bytes",
120 security_json_str.len(),
121 MAX_SECURITY_CONFIG_SIZE
122 );
123 return Err(AuthError::ConfigError {
124 message: format!(
125 "Security configuration exceeds maximum size of {} bytes",
126 MAX_SECURITY_CONFIG_SIZE
127 ),
128 });
129 }
130
131 let mut config = SecurityConfigFromSchema::from_json(security_value).map_err(|e| {
133 warn!("Failed to parse security configuration: {e}");
134 AuthError::ConfigError {
135 message: format!("Invalid security configuration: {e}"),
136 }
137 })?;
138
139 info!("Security configuration loaded from schema");
140
141 config.apply_env_overrides();
143 debug!("Security environment variable overrides applied");
144
145 Ok(config)
146}
147
148pub fn init_default_security_config() -> SecurityConfigFromSchema {
157 info!("Initializing default security configuration");
158 let mut config = SecurityConfigFromSchema::default();
159 config.apply_env_overrides();
160 debug!("Default security configuration applied with environment overrides");
161 config
162}
163
164pub fn log_security_config(config: &SecurityConfigFromSchema) {
173 info!(
174 audit_logging_enabled = config.audit_logging.enabled,
175 audit_log_level = %config.audit_logging.log_level,
176 audit_async_logging = config.audit_logging.async_logging,
177 audit_buffer_size = config.audit_logging.buffer_size,
178 "Audit logging configuration"
179 );
180
181 info!(
182 error_sanitization_enabled = config.error_sanitization.enabled,
183 error_generic_messages = config.error_sanitization.generic_messages,
184 error_internal_logging = config.error_sanitization.internal_logging,
185 error_leak_sensitive = config.error_sanitization.leak_sensitive_details,
186 "Error sanitization configuration"
187 );
188
189 info!(
190 rate_limiting_enabled = config.rate_limiting.enabled,
191 auth_start_max = config.rate_limiting.auth_start_max_requests,
192 auth_callback_max = config.rate_limiting.auth_callback_max_requests,
193 auth_refresh_max = config.rate_limiting.auth_refresh_max_requests,
194 failed_login_max = config.rate_limiting.failed_login_max_requests,
195 "Rate limiting configuration"
196 );
197
198 info!(
199 state_encryption_enabled = config.state_encryption.enabled,
200 state_encryption_algorithm = %config.state_encryption.algorithm,
201 state_encryption_nonce_size = config.state_encryption.nonce_size,
202 state_encryption_key_size = config.state_encryption.key_size,
203 "State encryption configuration"
204 );
205}
206
207pub fn validate_security_config(config: &SecurityConfigFromSchema) -> Result<()> {
226 if config.error_sanitization.leak_sensitive_details {
228 warn!("SECURITY WARNING: leak_sensitive_details is enabled! This is a security risk.");
229 return Err(AuthError::ConfigError {
230 message: "leak_sensitive_details must be false in production".to_string(),
231 });
232 }
233
234 if config.rate_limiting.enabled {
236 if config.rate_limiting.auth_start_max_requests == 0 {
237 return Err(AuthError::ConfigError {
238 message: "auth_start_max_requests must be greater than 0".to_string(),
239 });
240 }
241 if config.rate_limiting.auth_start_window_secs == 0 {
242 return Err(AuthError::ConfigError {
243 message: "auth_start_window_secs must be greater than 0".to_string(),
244 });
245 }
246 }
247
248 if config.state_encryption.enabled && config.state_encryption.key_size != 32 {
250 warn!(
251 "State encryption key size is {} bytes, expected 32 bytes for ChaCha20-Poly1305",
252 config.state_encryption.key_size
253 );
254 }
255
256 info!("Security configuration validation passed");
257 Ok(())
258}