tests/ssh_auth_latency_test.rs
Ref: Size: 1.8 KiB History
mod common;
use std::process::Command;
use std::time::{Duration, Instant};
use common::ServerHarness;
/// OpenSSH probes with a "none" attempt and then offers each identity in
/// turn, so a client with one stray key ahead of the enrolled one is rejected
/// twice before it is accepted. The server must answer every rejection
/// promptly: it only accepts public keys, so a delay on rejection slows every
/// legitimate connection and protects nothing.
///
/// Measured before the fix: about one second per rejection, so a little over
/// two seconds here. After it: well under one.
#[test]
fn rejected_keys_are_answered_without_a_delay() {
let harness = ServerHarness::new("latency");
let stray = harness.named_key("stray");
harness.authorize_named_keys(&["enrolled"]);
let enrolled = harness.named_key("enrolled");
let started = Instant::now();
let output = Command::new("ssh")
.args([
"-p",
&harness.ssh_port().to_string(),
"-i",
stray.to_str().unwrap(),
"-i",
enrolled.to_str().unwrap(),
"-o",
"StrictHostKeyChecking=no",
"-o",
"UserKnownHostsFile=/dev/null",
"-o",
"IdentitiesOnly=yes",
"-o",
"BatchMode=yes",
"-o",
"ConnectTimeout=5",
"-v",
"git@127.0.0.1",
"true",
])
.output()
.expect("failed to run ssh");
let elapsed = started.elapsed();
let stderr = String::from_utf8_lossy(&output.stderr);
assert!(
stderr.contains("Authenticated to"),
"the enrolled key must be accepted; ssh said:\n{stderr}"
);
assert!(
elapsed < Duration::from_secs(1),
"two rejections then an accept took {elapsed:?}; the server is delaying rejections"
);
}