Files
irtt-rs/crates/irtt-client/tests/authentication.rs
T

97 lines
3.8 KiB
Rust

use std::{net::UdpSocket, thread, time::Duration};
use irtt_client::{Authentication, Client, ClientConfig, ClientEvent, HmacKey, SocketConfig};
use irtt_proto::{decode_request, verify_packet_hmac};
use irtt_server::{ServerConfig, ServerCore};
// Exercise the runtime-free API against the production server core, including
// the wire HMAC flag on Open, Echo and Close for an explicitly empty key.
#[test]
fn concrete_authentication_preserves_session_and_empty_key_behavior() {
for key in [None, Some(b"session-test-key".as_slice()), Some(&[])] {
let socket = UdpSocket::bind("127.0.0.1:0").unwrap();
socket
.set_read_timeout(Some(Duration::from_secs(2)))
.unwrap();
let addr = socket.local_addr().unwrap();
let server = thread::spawn(move || {
let config = key.map_or_else(ServerConfig::default, |key| {
ServerConfig::default().with_hmac_key(key)
});
let mut core = ServerCore::new(config);
let mut buffer = [0; 2048];
for _ in 0..3 {
let (len, peer) = socket.recv_from(&mut buffer).unwrap();
let packet = &buffer[..len];
assert_eq!(decode_request(packet).unwrap().hmac_present, key.is_some());
if let Some(key) = key {
verify_packet_hmac(key, packet).unwrap();
}
if let Some(reply) = core.handle_datagram(peer, packet).unwrap() {
socket.send_to(reply.bytes(), peer).unwrap();
}
}
assert_eq!(core.session_count(), 0, "Close must release the session");
});
let mut client = Client::connect(ClientConfig {
server_addr: addr.to_string(),
auth: key.map_or(Authentication::Unauthenticated, |key| {
Authentication::Hmac(HmacKey::new(key))
}),
open_timeouts: vec![Duration::from_millis(200)],
socket_config: SocketConfig {
recv_timeout: Some(Duration::from_secs(1)),
..SocketConfig::default()
},
..ClientConfig::default()
})
.unwrap();
client.open().unwrap();
client.send_probe().unwrap();
assert!(client
.recv_once()
.unwrap()
.iter()
.any(|event| { matches!(event, ClientEvent::EchoReply { .. }) }));
client.close().unwrap();
server.join().unwrap();
}
}
#[test]
fn authentication_debug_redacts_keys_in_enclosing_configurations() {
let sentinel = b"CONSPICUOUS_HMAC_SECRET_DO_NOT_PRINT";
let key = HmacKey::new(sentinel.as_slice());
let auth = Authentication::Hmac(key.clone());
let config = ClientConfig {
auth: auth.clone(),
..ClientConfig::default()
};
let mut outputs = vec![
format!("{key:?}"),
format!("{auth:?}"),
format!("{config:?}"),
];
#[cfg(feature = "tokio")]
{
use irtt_client::managed::{ManagedClientConfig, ManagedTargetConfig, TargetAuth};
let mut target = ManagedTargetConfig::new("one", "127.0.0.1:2112");
target.auth = TargetAuth::Override(auth);
outputs.push(format!("{target:?}"));
outputs.push(format!(
"{:?}",
ManagedClientConfig {
client: config,
..ManagedClientConfig::default()
}
));
}
// Check both textual and ordinary byte-slice Debug encodings so replacing
// the opaque formatter with a derived formatter cannot slip through.
for output in outputs.drain(..) {
assert!(!output.contains(std::str::from_utf8(sentinel).unwrap()));
assert!(!output.contains(&format!("{sentinel:?}")));
assert!(output.contains("[REDACTED]"));
}
}