security(P0): fail-closed when auth is enabled but cannot initialize
Previously, if enable_auth=true but the database or auth services failed to initialize, the server silently started in PUBLIC mode — all API routes accessible without authentication. This is a critical fail-open bug. Fixes (fail-closed behavior): 1. main.rs: DB pool creation failure with enable_auth=true now panics instead of falling through with db_pool=None 2. di.rs: create_auth_services() failure now propagates the error via ? instead of logging and continuing with auth_services=None 3. main.rs: Added defensive assert! that auth_service is Some when enable_auth=true, preventing any future refactor from reintroducing the silent degradation The server will now refuse to start if authentication is configured but cannot be properly initialized.
This commit is contained in:
+19
-8
@@ -459,22 +459,33 @@ impl AppServiceFactory {
|
|||||||
|
|
||||||
// Auth services
|
// Auth services
|
||||||
if self.config.features.enable_auth {
|
if self.config.features.enable_auth {
|
||||||
match crate::infrastructure::auth_factory::create_auth_services(
|
let services = crate::infrastructure::auth_factory::create_auth_services(
|
||||||
&self.config,
|
&self.config,
|
||||||
pool.clone(),
|
pool.clone(),
|
||||||
Some(apps.folder_service_concrete.clone()),
|
Some(apps.folder_service_concrete.clone()),
|
||||||
)
|
)
|
||||||
.await
|
.await
|
||||||
{
|
.map_err(|e| {
|
||||||
Ok(services) => {
|
// SECURITY: fail-closed. If auth is required but the auth
|
||||||
|
// services cannot be created, propagate the error so the
|
||||||
|
// server refuses to start — never degrade to public mode.
|
||||||
|
tracing::error!(
|
||||||
|
"FATAL: enable_auth=true but auth services failed to initialize: {}",
|
||||||
|
e
|
||||||
|
);
|
||||||
|
DomainError::internal_error(
|
||||||
|
"AuthInit",
|
||||||
|
format!(
|
||||||
|
"Authentication is enabled but auth services failed: {}. \
|
||||||
|
Refusing to start without authentication.",
|
||||||
|
e
|
||||||
|
),
|
||||||
|
)
|
||||||
|
})?;
|
||||||
|
|
||||||
tracing::info!("Authentication services initialized successfully");
|
tracing::info!("Authentication services initialized successfully");
|
||||||
auth_services = Some(services);
|
auth_services = Some(services);
|
||||||
}
|
}
|
||||||
Err(e) => {
|
|
||||||
tracing::error!("Failed to initialize authentication services: {}", e);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// 7. Preload translations
|
// 7. Preload translations
|
||||||
|
|||||||
+18
-3
@@ -72,8 +72,13 @@ async fn main() -> Result<(), Box<dyn std::error::Error>> {
|
|||||||
Some(Arc::new(pool))
|
Some(Arc::new(pool))
|
||||||
}
|
}
|
||||||
Err(e) => {
|
Err(e) => {
|
||||||
tracing::error!("Failed to initialize database pool: {}", e);
|
// SECURITY: fail-closed. If auth is required but the database
|
||||||
None
|
// is unreachable, the server MUST NOT start in public mode.
|
||||||
|
panic!(
|
||||||
|
"FATAL: enable_auth=true but database connection failed: {}. \
|
||||||
|
Refusing to start without authentication.",
|
||||||
|
e
|
||||||
|
);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
@@ -134,7 +139,17 @@ async fn main() -> Result<(), Box<dyn std::error::Error>> {
|
|||||||
};
|
};
|
||||||
|
|
||||||
// Apply auth middleware to protected API routes when auth is enabled
|
// Apply auth middleware to protected API routes when auth is enabled
|
||||||
if config.features.enable_auth && app_state.auth_service.is_some() {
|
if config.features.enable_auth {
|
||||||
|
// SECURITY: if auth is required, auth_service MUST be present at this
|
||||||
|
// point. The earlier guards in di.rs and main.rs guarantee this, but
|
||||||
|
// add a defensive check so a future refactor cannot silently degrade.
|
||||||
|
assert!(
|
||||||
|
app_state.auth_service.is_some(),
|
||||||
|
"FATAL: enable_auth=true but auth_service is None. \
|
||||||
|
This should have been caught during initialization."
|
||||||
|
);
|
||||||
|
}
|
||||||
|
if config.features.enable_auth {
|
||||||
use interfaces::api::handlers::auth_handler::auth_routes;
|
use interfaces::api::handlers::auth_handler::auth_routes;
|
||||||
use oxicloud::interfaces::middleware::auth::auth_middleware;
|
use oxicloud::interfaces::middleware::auth::auth_middleware;
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user