auth: offload IDENTIFY + SASL PLAIN verify off the engine lock
All checks were successful
CI / check (push) Successful in 3m47s

Both ran scram verify_plain (~1s PBKDF2 at 1.2M iters) inline under the engine
lock, freezing the whole daemon per login. Add NetAction::DeferAuthenticate +
AuthThen continuation + ctx.defer_authenticate, mirroring DeferPassword: the
module/SASL path fetches the verifier cheaply and defers; the link layer runs
verify_plain on spawn_blocking, then Engine::complete_authenticate finishes the
login (IDENTIFY reuses the same ctx helpers, so its login/AJOIN/vhost/memo
side-effects are unchanged). Tests resolve the defer inline (cfg(test)). The
gRPC web-login path was already fixed; no login path stalls services now.
(GHOST/DROP/CERT/GROUP still verify inline but are rare account ops, not logins.)
This commit is contained in:
Jean Chevronnet 2026-07-16 19:04:18 +00:00
parent 63fc2fb2c0
commit 2f9790feac
No known key found for this signature in database
9 changed files with 144 additions and 36 deletions

View file

@ -122,6 +122,15 @@ pub async fn run(mut proto: Box<dyn Protocol>, engine: Arc<Mutex<Engine>>, addr:
.await?;
engine.lock().await.complete_password_change(&account, creds, &agent, &uid)
}
// Password verify (IDENTIFY / SASL PLAIN): run the ~1s
// PBKDF2 off the reactor, then finish under the lock.
NetAction::DeferAuthenticate { verifier, password, then } => {
let ok = tokio::task::spawn_blocking(move || {
crate::engine::scram::verify_plain(crate::engine::scram::Hash::Sha256, &verifier, &password)
})
.await?;
engine.lock().await.complete_authenticate(ok, then)
}
action => vec![action],
};
for act in outs {