use serde::{Deserialize, Serialize};
#[derive(
Debug, Clone, Serialize, Deserialize, zerompk::ToMessagePack, zerompk::FromMessagePack,
)]
#[serde(tag = "method", rename_all = "snake_case")]
#[non_exhaustive]
pub enum AuthMethod {
#[serde(rename = "trust")]
Trust { username: String },
#[serde(rename = "password")]
Password { username: String, password: String },
#[serde(rename = "api_key")]
ApiKey { token: String },
#[serde(rename = "oidc_bearer")]
OidcBearer {
token: String,
#[serde(default)]
provider: Option<String>,
},
}
#[derive(
Debug, Clone, Serialize, Deserialize, zerompk::ToMessagePack, zerompk::FromMessagePack,
)]
pub struct AuthResponse {
pub username: String,
pub tenant_id: u64,
}
#[cfg(test)]
mod tests {
use super::AuthMethod;
#[test]
fn auth_method_variants() {
let trust = AuthMethod::Trust {
username: "admin".into(),
};
let bytes = zerompk::to_msgpack_vec(&trust).unwrap();
let decoded: AuthMethod = zerompk::from_msgpack(&bytes).unwrap();
match decoded {
AuthMethod::Trust { username } => assert_eq!(username, "admin"),
_ => panic!("expected Trust variant"),
}
let pw = AuthMethod::Password {
username: "user".into(),
password: "secret".into(),
};
let bytes = zerompk::to_msgpack_vec(&pw).unwrap();
let decoded: AuthMethod = zerompk::from_msgpack(&bytes).unwrap();
match decoded {
AuthMethod::Password { username, password } => {
assert_eq!(username, "user");
assert_eq!(password, "secret");
}
_ => panic!("expected Password variant"),
}
}
#[test]
fn trust_missing_username_rejected_by_serde() {
let value = serde_json::json!({ "method": "trust" });
let decoded: Result<AuthMethod, _> = serde_json::from_value(value);
assert!(
decoded.is_err(),
"trust auth frame without username must not decode"
);
}
#[test]
fn trust_explicit_username_accepted_by_serde() {
let value = serde_json::json!({ "method": "trust", "username": "alice" });
let decoded: AuthMethod = serde_json::from_value(value).expect("must decode");
match decoded {
AuthMethod::Trust { username } => assert_eq!(username, "alice"),
other => panic!("expected Trust variant, got {other:?}"),
}
}
#[test]
fn trust_missing_username_rejected_by_zerompk() {
let bytes: &[u8] = &[0x81, 0xA5, b't', b'r', b'u', b's', b't', 0x80];
let decoded: Result<AuthMethod, _> = zerompk::from_msgpack(bytes);
assert!(
decoded.is_err(),
"trust auth frame without username must not decode via zerompk"
);
}
#[test]
fn trust_explicit_username_accepted_by_zerompk() {
let trust = AuthMethod::Trust {
username: "alice".into(),
};
let bytes = zerompk::to_msgpack_vec(&trust).unwrap();
let decoded: AuthMethod = zerompk::from_msgpack(&bytes).unwrap();
match decoded {
AuthMethod::Trust { username } => assert_eq!(username, "alice"),
other => panic!("expected Trust variant, got {other:?}"),
}
}
}