refactor(client): make authentication explicit and redact HMAC keys
This commit is contained in:
16 files changed
+184
-119
No files matched your search
@@ -1,10 +1,10 @@
|
||||
use std::time::Duration;
|
||||
use std::{fmt, time::Duration};
|
||||
|
||||
use clap::ValueEnum;
|
||||
use irtt_client::{MAX_DSCP_CODEPOINT, MAX_SERVER_FILL_BYTES, MAX_TTL, MAX_UDP_PAYLOAD_LENGTH};
|
||||
use irtt_proto::{Clock, ReceivedStats, StampAt};
|
||||
|
||||
#[derive(Debug, Clone, clap::Args)]
|
||||
#[derive(Clone, clap::Args)]
|
||||
pub struct CommonClientArgs {
|
||||
/// Probe interval.
|
||||
#[arg(long, default_value = "1s", value_parser = parse_duration)]
|
||||
@@ -63,6 +63,23 @@ pub struct CommonClientArgs {
|
||||
pub loose: bool,
|
||||
}
|
||||
|
||||
impl fmt::Debug for CommonClientArgs {
|
||||
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
|
||||
f.debug_struct("CommonClientArgs")
|
||||
.field("interval", &self.interval)
|
||||
.field("length", &self.length)
|
||||
.field("hmac", &self.hmac.as_ref().map(|_| "[REDACTED]"))
|
||||
.field("clock", &self.clock)
|
||||
.field("tstamp", &self.tstamp)
|
||||
.field("stats", &self.stats)
|
||||
.field("server_fill", &self.server_fill)
|
||||
.field("dscp", &self.dscp)
|
||||
.field("ttl", &self.ttl)
|
||||
.field("loose", &self.loose)
|
||||
.finish()
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Debug, Clone, Copy, PartialEq, Eq, ValueEnum)]
|
||||
pub enum ClockArg {
|
||||
Wall,
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
use std::time::Duration;
|
||||
|
||||
use irtt_client::{ClientConfig, NegotiationPolicy, SocketConfig};
|
||||
use irtt_client::{Authentication, ClientConfig, HmacKey, NegotiationPolicy, SocketConfig};
|
||||
|
||||
use super::args::CommonClientArgs;
|
||||
|
||||
@@ -21,7 +21,12 @@ impl CommonClientArgs {
|
||||
stamp_at: self.tstamp.into(),
|
||||
clock: self.clock.into(),
|
||||
dscp: self.dscp,
|
||||
hmac_key: self.hmac.as_ref().map(|key| key.as_bytes().to_vec()),
|
||||
auth: self
|
||||
.hmac
|
||||
.as_ref()
|
||||
.map_or(Authentication::Unauthenticated, |key| {
|
||||
Authentication::Hmac(HmacKey::new(key.as_bytes()))
|
||||
}),
|
||||
server_fill: self.server_fill.clone(),
|
||||
negotiation_policy: if self.loose {
|
||||
NegotiationPolicy::Loose
|
||||
|
||||
@@ -2,8 +2,8 @@ use std::{collections::HashSet, fmt};
|
||||
|
||||
use clap::ValueEnum;
|
||||
use irtt_client::{
|
||||
managed::{ManagedPacing, ManagedTargetConfig, TargetId},
|
||||
ClientAuthConfig,
|
||||
managed::{ManagedPacing, ManagedTargetConfig, TargetAuth, TargetId},
|
||||
Authentication, HmacKey,
|
||||
};
|
||||
|
||||
/// One raw positional target captured by Clap.
|
||||
@@ -35,23 +35,6 @@ pub fn parse_target(input: &str) -> Result<TargetArg, String> {
|
||||
Ok(TargetArg::new(input))
|
||||
}
|
||||
|
||||
#[derive(Clone, PartialEq, Eq)]
|
||||
pub enum TargetAuth {
|
||||
Inherit,
|
||||
Override(Vec<u8>),
|
||||
Disable,
|
||||
}
|
||||
|
||||
impl fmt::Debug for TargetAuth {
|
||||
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
|
||||
match self {
|
||||
Self::Inherit => f.write_str("Inherit"),
|
||||
Self::Override(_) => f.write_str("Override(<redacted>)"),
|
||||
Self::Disable => f.write_str("Disable"),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Clone, PartialEq, Eq)]
|
||||
pub struct TargetSpec {
|
||||
pub label: String,
|
||||
@@ -80,16 +63,7 @@ impl fmt::Debug for PreparedTarget {
|
||||
f.debug_struct("PreparedTarget")
|
||||
.field("label", &self.label)
|
||||
.field("server_addr", &self.managed.server_addr)
|
||||
.field(
|
||||
"auth",
|
||||
&match &self.managed.auth {
|
||||
None => TargetAuth::Inherit,
|
||||
Some(ClientAuthConfig { hmac_key: Some(_) }) => {
|
||||
TargetAuth::Override(Vec::new())
|
||||
}
|
||||
Some(ClientAuthConfig { hmac_key: None }) => TargetAuth::Disable,
|
||||
},
|
||||
)
|
||||
.field("auth", &self.managed.auth)
|
||||
.finish()
|
||||
}
|
||||
}
|
||||
@@ -216,9 +190,9 @@ fn parse_target_syntax(
|
||||
Some(index) => {
|
||||
let value = unescape(&input[index + "@hmac=".len()..])?;
|
||||
let auth = if value.is_empty() {
|
||||
TargetAuth::Disable
|
||||
TargetAuth::Override(Authentication::Unauthenticated)
|
||||
} else {
|
||||
TargetAuth::Override(value.into_bytes())
|
||||
TargetAuth::Override(Authentication::Hmac(HmacKey::new(value.into_bytes())))
|
||||
};
|
||||
(&input[..index], auth)
|
||||
}
|
||||
@@ -287,13 +261,7 @@ pub fn prepare_managed_targets(specs: Vec<TargetSpec>) -> Result<Vec<PreparedTar
|
||||
let mut targets = Vec::with_capacity(specs.len());
|
||||
for spec in specs {
|
||||
let mut managed = ManagedTargetConfig::new(TargetId::from(spec.label.clone()), spec.addr);
|
||||
managed.auth = match spec.auth {
|
||||
TargetAuth::Inherit => None,
|
||||
TargetAuth::Override(hmac_key) => Some(ClientAuthConfig {
|
||||
hmac_key: Some(hmac_key),
|
||||
}),
|
||||
TargetAuth::Disable => Some(ClientAuthConfig { hmac_key: None }),
|
||||
};
|
||||
managed.auth = spec.auth;
|
||||
targets.push(PreparedTarget {
|
||||
label: spec.label,
|
||||
managed,
|
||||
|
||||
@@ -149,29 +149,37 @@ fn default_client_output_emits_a_packet_summary() {
|
||||
fn target_authentication_inherits_overrides_or_disables_the_global_key() {
|
||||
use clap::Parser;
|
||||
use irtt_app::cmd::client::args::ClientArgs;
|
||||
use irtt_client::{managed::TargetAuth, Authentication, HmacKey};
|
||||
let args = ClientArgs::try_parse_from([
|
||||
"irtt-client",
|
||||
"--hmac",
|
||||
"global-test-key",
|
||||
"CONSPICUOUS_GLOBAL_HMAC_KEY",
|
||||
"inherit=127.0.0.1:2112",
|
||||
"override=127.0.0.1:2113@hmac=target-test-key",
|
||||
"override=127.0.0.1:2113@hmac=CONSPICUOUS_TARGET_HMAC_KEY",
|
||||
"disable=127.0.0.1:2114@hmac=",
|
||||
])
|
||||
.unwrap();
|
||||
let setup = args.prepare().unwrap();
|
||||
assert_eq!(
|
||||
setup.managed_config().client.hmac_key.as_deref(),
|
||||
Some(b"global-test-key".as_slice())
|
||||
setup.managed_config().client.auth,
|
||||
Authentication::Hmac(HmacKey::new(b"CONSPICUOUS_GLOBAL_HMAC_KEY".as_slice()))
|
||||
);
|
||||
let targets = setup.managed_targets();
|
||||
let authentication: Vec<_> = targets
|
||||
.iter()
|
||||
.map(|target| target.auth.as_ref().map(|auth| auth.hmac_key.as_deref()))
|
||||
.collect();
|
||||
let authentication: Vec<_> = targets.iter().map(|target| target.auth.clone()).collect();
|
||||
assert_eq!(
|
||||
authentication,
|
||||
[None, Some(Some(b"target-test-key".as_slice())), Some(None)]
|
||||
[
|
||||
TargetAuth::Inherit,
|
||||
TargetAuth::Override(Authentication::Hmac(HmacKey::new(
|
||||
b"CONSPICUOUS_TARGET_HMAC_KEY".as_slice()
|
||||
))),
|
||||
TargetAuth::Override(Authentication::Unauthenticated)
|
||||
]
|
||||
);
|
||||
for output in [format!("{args:?}"), format!("{setup:?}")] {
|
||||
assert!(!output.contains("CONSPICUOUS_GLOBAL_HMAC_KEY"));
|
||||
assert!(!output.contains("CONSPICUOUS_TARGET_HMAC_KEY"));
|
||||
}
|
||||
}
|
||||
|
||||
// A real authenticated server detects broken client argument-to-config mapping.
|
||||
|
||||
@@ -34,6 +34,25 @@ dependency at all.
|
||||
|
||||
See `examples/` in the repository for runnable examples of each tier.
|
||||
|
||||
## Authentication
|
||||
|
||||
`ClientConfig.auth` is concrete: `Authentication::Unauthenticated` or
|
||||
`Authentication::Hmac(HmacKey::new(bytes))`. Keys share their bytes across
|
||||
clones and print only `HmacKey([REDACTED])` through `Debug`. Borrowing key
|
||||
material requires an explicit `as_bytes()` call. An empty key still selects
|
||||
HMAC authentication; textual key syntax belongs to the application.
|
||||
|
||||
For managed targets, `ManagedTargetConfig.auth` defaults to `TargetAuth::Inherit`.
|
||||
`TargetAuth::Override(Authentication::Unauthenticated)` disables shared
|
||||
authentication, and `TargetAuth::Override(Authentication::Hmac(key))` replaces
|
||||
the shared key. Initial construction and update planning resolve inheritance
|
||||
into concrete session authentication before execution. Switching between
|
||||
inheritance and an override replaces the target generation even when their
|
||||
resolved authentication is equal.
|
||||
|
||||
This replaces the former `ClientConfig.hmac_key` and `ClientAuthConfig` API;
|
||||
there are no compatibility aliases.
|
||||
|
||||
## Documentation
|
||||
|
||||
Full API documentation is on [docs.rs/irtt-client](https://docs.rs/irtt-client).
|
||||
|
||||
@@ -0,0 +1,44 @@
|
||||
use std::{fmt, sync::Arc};
|
||||
|
||||
/// Shared HMAC key bytes. Debug output never includes the bytes or a fingerprint.
|
||||
///
|
||||
/// An empty key is still an explicitly configured HMAC key.
|
||||
#[derive(Clone, PartialEq, Eq)]
|
||||
pub struct HmacKey(Arc<[u8]>);
|
||||
|
||||
impl HmacKey {
|
||||
/// Store key bytes without interpreting textual key syntax.
|
||||
pub fn new(bytes: impl Into<Arc<[u8]>>) -> Self {
|
||||
Self(bytes.into())
|
||||
}
|
||||
|
||||
/// Explicitly borrow the key material for authentication.
|
||||
pub fn as_bytes(&self) -> &[u8] {
|
||||
&self.0
|
||||
}
|
||||
}
|
||||
|
||||
impl fmt::Debug for HmacKey {
|
||||
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
|
||||
f.write_str("HmacKey([REDACTED])")
|
||||
}
|
||||
}
|
||||
|
||||
/// Concrete authentication for a low-level client session.
|
||||
#[derive(Clone, Debug, Default, PartialEq, Eq)]
|
||||
pub enum Authentication {
|
||||
/// Send and accept packets without HMAC authentication.
|
||||
#[default]
|
||||
Unauthenticated,
|
||||
/// Authenticate packets with this key, including when it is empty.
|
||||
Hmac(HmacKey),
|
||||
}
|
||||
|
||||
impl Authentication {
|
||||
pub(crate) fn hmac_key(&self) -> Option<&[u8]> {
|
||||
match self {
|
||||
Self::Unauthenticated => None,
|
||||
Self::Hmac(key) => Some(key.as_bytes()),
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,5 +1,7 @@
|
||||
use std::{net::SocketAddr, time::Duration};
|
||||
|
||||
use crate::Authentication;
|
||||
|
||||
/// Protocol compatibility bound for a requested `server_fill` value, in UTF-8
|
||||
/// bytes.
|
||||
///
|
||||
@@ -118,11 +120,10 @@ pub struct ClientConfig {
|
||||
/// This is the six-bit DSCP value, not the full traffic-class byte, and
|
||||
/// must be less than or equal to [`MAX_DSCP_CODEPOINT`].
|
||||
pub dscp: u8,
|
||||
/// Optional HMAC key used to authenticate IRTT packets.
|
||||
/// Concrete authentication for open, echo, and close packets.
|
||||
///
|
||||
/// When present, open, echo, and close packets are encoded and decoded with
|
||||
/// HMAC authentication. The peer must be configured with the same key.
|
||||
pub hmac_key: Option<Vec<u8>>,
|
||||
/// HMAC peers must use the same key. An empty HMAC key remains authenticated.
|
||||
pub auth: Authentication,
|
||||
/// Optional server payload fill request.
|
||||
///
|
||||
/// `None` leaves server fill behavior unspecified. `Some(value)` requests
|
||||
@@ -155,30 +156,6 @@ pub struct ClientConfig {
|
||||
pub max_pending_probes: usize,
|
||||
}
|
||||
|
||||
/// Authentication settings used by client sessions.
|
||||
///
|
||||
/// `ClientConfig` keeps its existing top-level HMAC field for source
|
||||
/// compatibility. Managed multi-target callers can use this smaller type for
|
||||
/// per-target auth overrides without carrying a full independent
|
||||
/// [`ClientConfig`].
|
||||
#[derive(Debug, Clone, PartialEq, Eq, Default)]
|
||||
pub struct ClientAuthConfig {
|
||||
/// Optional HMAC key used to authenticate IRTT packets.
|
||||
pub hmac_key: Option<Vec<u8>>,
|
||||
}
|
||||
|
||||
impl From<Option<Vec<u8>>> for ClientAuthConfig {
|
||||
fn from(hmac_key: Option<Vec<u8>>) -> Self {
|
||||
Self { hmac_key }
|
||||
}
|
||||
}
|
||||
|
||||
impl From<ClientAuthConfig> for Option<Vec<u8>> {
|
||||
fn from(auth: ClientAuthConfig) -> Self {
|
||||
auth.hmac_key
|
||||
}
|
||||
}
|
||||
|
||||
impl Default for ClientConfig {
|
||||
fn default() -> Self {
|
||||
Self {
|
||||
@@ -190,7 +167,7 @@ impl Default for ClientConfig {
|
||||
stamp_at: StampAt::Both,
|
||||
clock: Clock::Both,
|
||||
dscp: 0,
|
||||
hmac_key: None,
|
||||
auth: Authentication::Unauthenticated,
|
||||
server_fill: None,
|
||||
open_timeouts: DEFAULT_OPEN_TIMEOUTS.to_vec(),
|
||||
run_mode: RunMode::Normal,
|
||||
|
||||
@@ -34,6 +34,7 @@
|
||||
|
||||
#[cfg(feature = "tokio")]
|
||||
mod async_client;
|
||||
mod auth;
|
||||
mod client;
|
||||
mod config;
|
||||
mod error;
|
||||
@@ -49,10 +50,11 @@ mod timing;
|
||||
|
||||
#[cfg(feature = "tokio")]
|
||||
pub use async_client::AsyncClient;
|
||||
pub use auth::{Authentication, HmacKey};
|
||||
pub use client::Client;
|
||||
pub use config::{
|
||||
ClientAuthConfig, ClientConfig, NegotiationPolicy, RecvBudget, RunMode, SocketConfig,
|
||||
MAX_DSCP_CODEPOINT, MAX_SERVER_FILL_BYTES, MAX_TTL, MAX_UDP_PAYLOAD_LENGTH,
|
||||
ClientConfig, NegotiationPolicy, RecvBudget, RunMode, SocketConfig, MAX_DSCP_CODEPOINT,
|
||||
MAX_SERVER_FILL_BYTES, MAX_TTL, MAX_UDP_PAYLOAD_LENGTH,
|
||||
};
|
||||
pub use error::ClientError;
|
||||
pub use event::{
|
||||
|
||||
@@ -2,7 +2,7 @@ use std::{fmt, net::SocketAddr, sync::Arc, time::Duration};
|
||||
|
||||
use thiserror::Error;
|
||||
|
||||
use crate::{ClientAuthConfig, ClientConfig, ClientError, ClientEvent};
|
||||
use crate::{Authentication, ClientConfig, ClientError, ClientEvent};
|
||||
|
||||
use super::TargetId;
|
||||
|
||||
@@ -26,12 +26,34 @@ pub struct TargetInstance {
|
||||
pub generation: u64,
|
||||
}
|
||||
|
||||
/// Endpoint and optional authentication override for one managed target.
|
||||
/// Authentication specification for a managed target.
|
||||
///
|
||||
/// Equality preserves the specification: inheritance and an explicit override
|
||||
/// remain distinct even when they currently resolve to the same authentication.
|
||||
#[derive(Clone, Debug, Default, Eq, PartialEq)]
|
||||
pub enum TargetAuth {
|
||||
/// Use the shared client configuration's authentication.
|
||||
#[default]
|
||||
Inherit,
|
||||
/// Replace shared authentication. `Unauthenticated` explicitly disables it.
|
||||
Override(Authentication),
|
||||
}
|
||||
|
||||
impl TargetAuth {
|
||||
pub(crate) fn resolve(&self, shared: &Authentication) -> Authentication {
|
||||
match self {
|
||||
Self::Inherit => shared.clone(),
|
||||
Self::Override(auth) => auth.clone(),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// Endpoint and authentication specification for one managed target.
|
||||
#[derive(Clone, Debug, Eq, PartialEq)]
|
||||
pub struct ManagedTargetConfig {
|
||||
pub id: TargetId,
|
||||
pub server_addr: String,
|
||||
pub auth: Option<ClientAuthConfig>,
|
||||
pub auth: TargetAuth,
|
||||
}
|
||||
|
||||
impl ManagedTargetConfig {
|
||||
@@ -39,7 +61,7 @@ impl ManagedTargetConfig {
|
||||
Self {
|
||||
id: id.into(),
|
||||
server_addr: server_addr.into(),
|
||||
auth: None,
|
||||
auth: TargetAuth::Inherit,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -945,9 +945,7 @@ impl ManagedClientTask {
|
||||
}
|
||||
let mut client_config = self.config.client.clone();
|
||||
client_config.server_addr.clone_from(&target.server_addr);
|
||||
if let Some(auth) = &target.auth {
|
||||
client_config.hmac_key.clone_from(&auth.hmac_key);
|
||||
}
|
||||
client_config.auth = target.auth.resolve(&self.config.client.auth);
|
||||
validate_target_config(&client_config).map_err(|source| {
|
||||
ManagedCommandApplyError::InvalidTarget {
|
||||
id: target.id.clone(),
|
||||
@@ -2251,9 +2249,7 @@ fn build_task(
|
||||
.ok_or(ManagedConfigError::GenerationExhausted)?;
|
||||
let mut client_config = config.client.clone();
|
||||
client_config.server_addr.clone_from(&target.server_addr);
|
||||
if let Some(auth) = &target.auth {
|
||||
client_config.hmac_key.clone_from(&auth.hmac_key);
|
||||
}
|
||||
client_config.auth = target.auth.resolve(&config.client.auth);
|
||||
validate_target_config(&client_config).map_err(|source| {
|
||||
ManagedConfigError::InvalidTarget {
|
||||
id: target.id.clone(),
|
||||
|
||||
@@ -201,7 +201,7 @@ impl SessionMachine {
|
||||
}
|
||||
|
||||
pub(crate) fn has_hmac(&self) -> bool {
|
||||
self.config.hmac_key.is_some()
|
||||
self.config.auth.hmac_key().is_some()
|
||||
}
|
||||
|
||||
pub(crate) fn prepare_open_request(&self) -> Result<PreparedOpenRequest, ClientError> {
|
||||
@@ -211,7 +211,7 @@ impl SessionMachine {
|
||||
params: &self.requested,
|
||||
no_test: self.config.run_mode == RunMode::NoTest,
|
||||
},
|
||||
self.config.hmac_key.as_deref(),
|
||||
self.config.auth.hmac_key(),
|
||||
)?;
|
||||
Ok(PreparedOpenRequest {
|
||||
bytes: bytes.into_boxed_slice(),
|
||||
@@ -223,7 +223,7 @@ impl SessionMachine {
|
||||
packet: &[u8],
|
||||
) -> Result<OpenDatagramDisposition, ClientError> {
|
||||
self.ensure_connected()?;
|
||||
match irtt_proto::decode_open_reply(packet, self.config.hmac_key.as_deref()) {
|
||||
match irtt_proto::decode_open_reply(packet, self.config.auth.hmac_key()) {
|
||||
Ok(reply) => Ok(OpenDatagramDisposition::Trusted(reply)),
|
||||
Err(error @ irtt_proto::ProtoError::ZeroToken) => Err(ClientError::Protocol(error)),
|
||||
Err(
|
||||
@@ -250,7 +250,7 @@ impl SessionMachine {
|
||||
let cleanup_close = if !reply_is_close && reply.token != 0 {
|
||||
let bytes = encode_request(
|
||||
RequestToEncode::Close { token: reply.token },
|
||||
self.config.hmac_key.as_deref(),
|
||||
self.config.auth.hmac_key(),
|
||||
)
|
||||
.map_err(ClientError::from)
|
||||
.map_err(OpenAcceptanceFailure::without_cleanup)?;
|
||||
@@ -313,7 +313,7 @@ impl SessionMachine {
|
||||
params: &session.negotiated.params,
|
||||
payload: &[],
|
||||
},
|
||||
self.config.hmac_key.as_deref(),
|
||||
self.config.auth.hmac_key(),
|
||||
)?;
|
||||
Ok(PreparedProbe {
|
||||
bytes: bytes.into_boxed_slice(),
|
||||
@@ -679,7 +679,7 @@ impl SessionMachine {
|
||||
decode_echo_reply(
|
||||
packet,
|
||||
&session.negotiated.params,
|
||||
self.config.hmac_key.as_deref(),
|
||||
self.config.auth.hmac_key(),
|
||||
)
|
||||
.ok()
|
||||
}
|
||||
|
||||
@@ -1,10 +1,11 @@
|
||||
use super::*;
|
||||
use irtt_client::{Authentication, HmacKey};
|
||||
|
||||
#[test]
|
||||
fn hmac_open_ignores_missing_hmac_before_valid_reply() {
|
||||
let key = b"secret".to_vec();
|
||||
let mut config = default_test_config(SocketAddr::from(([127, 0, 0, 1], 1)));
|
||||
config.hmac_key = Some(key.clone());
|
||||
config.auth = Authentication::Hmac(HmacKey::new(key.clone()));
|
||||
let params = default_params();
|
||||
let server = start_fake_server(move |socket, tx| {
|
||||
let (_, peer) = recv_request(&socket, &tx);
|
||||
@@ -26,7 +27,7 @@ fn hmac_open_ignores_bad_hmac_before_valid_reply() {
|
||||
let key = b"secret".to_vec();
|
||||
let wrong_key = b"wrong".to_vec();
|
||||
let mut config = default_test_config(SocketAddr::from(([127, 0, 0, 1], 1)));
|
||||
config.hmac_key = Some(key.clone());
|
||||
config.auth = Authentication::Hmac(HmacKey::new(key.clone()));
|
||||
let params = default_params();
|
||||
let server = start_fake_server(move |socket, tx| {
|
||||
let (_, peer) = recv_request(&socket, &tx);
|
||||
@@ -47,7 +48,7 @@ fn hmac_open_ignores_bad_hmac_before_valid_reply() {
|
||||
fn post_token_hmac_negotiation_failure_sends_authenticated_cleanup_close() {
|
||||
let key = b"secret".to_vec();
|
||||
let mut config = default_test_config(SocketAddr::from(([127, 0, 0, 1], 1)));
|
||||
config.hmac_key = Some(key.clone());
|
||||
config.auth = Authentication::Hmac(HmacKey::new(key.clone()));
|
||||
let mut returned = default_params();
|
||||
returned.interval_ns += 1;
|
||||
let server_key = key.clone();
|
||||
|
||||
@@ -1,3 +1,4 @@
|
||||
use irtt_client::{Authentication, HmacKey};
|
||||
use std::{
|
||||
future::Future,
|
||||
net::UdpSocket,
|
||||
@@ -54,7 +55,9 @@ fn config(addr: SocketAddr, key: Option<Vec<u8>>, dscp: u8) -> ClientConfig {
|
||||
received_stats: ReceivedStats::None,
|
||||
stamp_at: StampAt::None,
|
||||
dscp,
|
||||
hmac_key: key,
|
||||
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_millis(200)),
|
||||
|
||||
@@ -1,3 +1,4 @@
|
||||
use irtt_client::{Authentication, HmacKey};
|
||||
mod support;
|
||||
|
||||
use std::time::Duration;
|
||||
@@ -27,7 +28,7 @@ fn hmac_open_success_negotiates_without_warnings() {
|
||||
TimestampFields::default(),
|
||||
Some(key),
|
||||
|addr| ClientConfig {
|
||||
hmac_key: Some(config_key),
|
||||
auth: Authentication::Hmac(HmacKey::new(config_key)),
|
||||
..config_for_params(addr, &config_params)
|
||||
},
|
||||
);
|
||||
@@ -52,7 +53,7 @@ fn hmac_echo_success_verifies_request_and_accepts_reply() {
|
||||
|
||||
let run = run_one_probe_with_config(params.clone(), standard_timestamps(), Some(key), |addr| {
|
||||
ClientConfig {
|
||||
hmac_key: Some(config_key),
|
||||
auth: Authentication::Hmac(HmacKey::new(config_key)),
|
||||
..config_for_params(addr, &config_params)
|
||||
}
|
||||
});
|
||||
@@ -94,7 +95,7 @@ fn hmac_close_success_sends_authenticated_close_and_closes_session() {
|
||||
let params = default_params();
|
||||
let server = start_hmac_close_server(params.clone(), key.clone());
|
||||
let mut config = config_for_params(server.addr, ¶ms);
|
||||
config.hmac_key = Some(key);
|
||||
config.auth = Authentication::Hmac(HmacKey::new(key));
|
||||
|
||||
let mut client = Client::connect(config).unwrap();
|
||||
let outcome = client.open().unwrap();
|
||||
@@ -135,7 +136,9 @@ fn hmac_required_server_rejects_missing_or_wrong_client_key() {
|
||||
let server = start_hmac_required_open_drop_server(server_key, Duration::from_millis(250));
|
||||
let mut config = config_for_params(server.addr, &default_params());
|
||||
config.open_timeouts = vec![Duration::from_millis(200)];
|
||||
config.hmac_key = hmac_key;
|
||||
config.auth = hmac_key.map_or(Authentication::Unauthenticated, |key| {
|
||||
Authentication::Hmac(HmacKey::new(key))
|
||||
});
|
||||
|
||||
let mut client = Client::connect(config).unwrap();
|
||||
assert!(matches!(client.open(), Err(ClientError::OpenTimeout)));
|
||||
@@ -158,7 +161,7 @@ fn bad_hmac_echo_reply_is_rejected_without_echo_reply_event() {
|
||||
let params = default_params();
|
||||
let server = start_bad_hmac_echo_reply_server(params.clone(), key.clone());
|
||||
let mut config = config_for_params(server.addr, ¶ms);
|
||||
config.hmac_key = Some(key);
|
||||
config.auth = Authentication::Hmac(HmacKey::new(key));
|
||||
config.socket_config = SocketConfig {
|
||||
recv_timeout: Some(Duration::from_millis(500)),
|
||||
..Default::default()
|
||||
@@ -205,7 +208,7 @@ fn hmac_open_reply_with_bad_hmac_is_ignored_until_timeout() {
|
||||
let params = default_params();
|
||||
let server = support::start_bad_hmac_open_reply_server(params.clone(), key.clone(), wrong_key);
|
||||
let mut config = config_for_params(server.addr, ¶ms);
|
||||
config.hmac_key = Some(key);
|
||||
config.auth = Authentication::Hmac(HmacKey::new(key));
|
||||
|
||||
let mut client = Client::connect(config).unwrap();
|
||||
assert!(matches!(client.open(), Err(ClientError::OpenTimeout)));
|
||||
@@ -221,7 +224,7 @@ fn non_hmac_client_open_does_not_set_hmac_flag() {
|
||||
);
|
||||
let server = support::start_open_server(params.clone(), None);
|
||||
let mut config = config_for_params(server.addr, ¶ms);
|
||||
config.hmac_key = None;
|
||||
config.auth = Authentication::Unauthenticated;
|
||||
|
||||
let mut client = Client::connect(config).unwrap();
|
||||
let outcome = client.open().unwrap();
|
||||
@@ -278,7 +281,7 @@ fn backend_hmac_correct_key_succeeds() {
|
||||
let params = default_params();
|
||||
let peer = BackendPeer::start_open_echo(Some(key.clone()));
|
||||
let mut config = config_for_params(peer.addr(), ¶ms);
|
||||
config.hmac_key = Some(key);
|
||||
config.auth = Authentication::Hmac(HmacKey::new(key));
|
||||
|
||||
let mut client = Client::connect(config).unwrap();
|
||||
let outcome = client.open().unwrap();
|
||||
@@ -301,7 +304,9 @@ fn backend_hmac_required_rejects_missing_or_wrong_client_key() {
|
||||
let peer = BackendPeer::start_hmac_required(server_key);
|
||||
let mut config = config_for_params(peer.addr(), &default_params());
|
||||
config.open_timeouts = vec![Duration::from_millis(200)];
|
||||
config.hmac_key = hmac_key;
|
||||
config.auth = hmac_key.map_or(Authentication::Unauthenticated, |key| {
|
||||
Authentication::Hmac(HmacKey::new(key))
|
||||
});
|
||||
|
||||
let mut client = Client::connect(config).unwrap();
|
||||
assert!(matches!(client.open(), Err(ClientError::OpenTimeout)));
|
||||
|
||||
@@ -1,3 +1,4 @@
|
||||
use irtt_client::{Authentication, HmacKey};
|
||||
use std::{
|
||||
future::Future,
|
||||
net::{SocketAddr, UdpSocket},
|
||||
@@ -14,8 +15,8 @@ use irtt_proto::{
|
||||
};
|
||||
use tokio::runtime::{Builder, Runtime};
|
||||
|
||||
use irtt_client::RunMode;
|
||||
use irtt_client::{managed::*, ClientConfig};
|
||||
use irtt_client::{ClientAuthConfig, RunMode};
|
||||
use tokio::sync::broadcast;
|
||||
|
||||
const TOKEN: u64 = 0x1234_5678_90ab_cdef;
|
||||
@@ -355,9 +356,7 @@ fn authenticated_peer_close_outcome() {
|
||||
let key = b"managed-peer-close".to_vec();
|
||||
let server = start_server(ServerBehavior::PeerClose, Some(key.clone()));
|
||||
let mut configured = target("peer", server.addr);
|
||||
configured.auth = Some(ClientAuthConfig {
|
||||
hmac_key: Some(key),
|
||||
});
|
||||
configured.auth = TargetAuth::Override(Authentication::Hmac(HmacKey::new(key)));
|
||||
let (task, _) =
|
||||
ManagedClient::task(config(ManagedPacing::Staggered), vec![configured]).unwrap();
|
||||
let outcome = runtime().block_on(task);
|
||||
@@ -418,9 +417,7 @@ fn pending_limit_failure_drains_reply_and_closes_session() {
|
||||
managed.client.max_pending_probes = 1;
|
||||
managed.final_drain = Duration::from_millis(50);
|
||||
let mut configured = target("one", server.addr);
|
||||
configured.auth = Some(ClientAuthConfig {
|
||||
hmac_key: Some(key),
|
||||
});
|
||||
configured.auth = TargetAuth::Override(Authentication::Hmac(HmacKey::new(key)));
|
||||
let (task, _) = ManagedClient::task(managed, vec![configured]).unwrap();
|
||||
let outcome = runtime().block_on(async {
|
||||
tokio::time::timeout(Duration::from_secs(1), task)
|
||||
|
||||
@@ -1,3 +1,4 @@
|
||||
use irtt_client::{Authentication, HmacKey};
|
||||
mod support;
|
||||
mod protocol_options {
|
||||
pub mod backend_smoke;
|
||||
@@ -148,7 +149,7 @@ fn hmac_rich_mode_uses_negotiated_echo_layout_and_decodes_reply() {
|
||||
let config_key = key.clone();
|
||||
let run = run_one_probe_with_config(params.clone(), standard_timestamps(), Some(key), |addr| {
|
||||
ClientConfig {
|
||||
hmac_key: Some(config_key),
|
||||
auth: Authentication::Hmac(HmacKey::new(config_key)),
|
||||
..config_for_params(addr, &config_params)
|
||||
}
|
||||
});
|
||||
|
||||
Reference in new issue
Block a user