Mercurial > crates > nonstick
view testharness/src/bin/testharness.rs @ 189:b2456d274576 default tip
Add line breaks that rustfmt ate back to documentation.
author | Paul Fisher <paul@pfish.zone> |
---|---|
date | Thu, 31 Jul 2025 15:42:12 -0400 |
parents | 42f747774d94 |
children |
line wrap: on
line source
//! Test program to interact with PAM and `../lib.rs` to ensure that nonstick //! does everything right. use nonstick::conv::Exchange; use nonstick::items::Items; use nonstick::libpam::TransactionBuilder; use nonstick::EnvironMap; use nonstick::{ AuthnFlags, AuthtokFlags, Conversation, ErrorCode, LibPamTransaction, PamShared, Transaction, }; use std::cell::Cell; use std::collections::HashMap; use std::ffi::OsString; use std::os::unix::ffi::OsStrExt; macro_rules! run { ($x:expr) => { eprintln!("START {}", stringify!($x)); $x; eprintln!("..END {}", stringify!($x)); }; } fn main() { run!(test_wrong_user()); run!(test_wrong_password()); run!(test_correct()); } #[derive(Debug, Default)] struct TestHarness { username_requested: Cell<bool>, wrong_username: bool, wrong_password: bool, changing_password: Cell<bool>, change_prompt_count: Cell<usize>, } impl Conversation for &TestHarness { fn communicate(&self, messages: &[Exchange]) { if let [only_msg] = messages { match only_msg { Exchange::Prompt(p) => { if self.username_requested.get() { panic!("username already requested!") } if self.wrong_username { p.set_answer(Ok(OsString::from("not-right"))) } else { p.set_answer(Ok(OsString::from("initial"))) } self.username_requested.set(true) } Exchange::MaskedPrompt(p) => { let answer = if self.changing_password.get() { let prompt_count = self.change_prompt_count.get(); self.change_prompt_count.set(prompt_count + 1); // When changing passwords after logging in, Sun PAM // uses the existing authtok that was just entered as // the old_authtok. Other PAMs prompt the user to enter // their existing password again. let responses: &[&str] = if cfg!(pam_impl = "Sun") { &["mistake", "mismatch", "acceptable", "acceptable"] } else { &[ "old token!", "mistake", "mismatch", "old token!", "acceptable", "acceptable", ] }; responses[prompt_count] } else if self.wrong_password { "bogus" } else { "valid" }; p.set_answer(Ok(OsString::from(answer))); } Exchange::Error(e) if self.changing_password.get() => e.set_answer(Ok(())), other => panic!("Unknown message {other:?}!"), } } else { for msg in messages { match msg { Exchange::Info(i) => i.set_answer(Ok(())), Exchange::Error(e) => e.set_answer(Ok(())), Exchange::Prompt(p) => match p.question().as_bytes() { b"How many?" => p.set_answer(Ok(OsString::from("123"))), _ => p.set_answer(Err(ErrorCode::ConversationError)), }, Exchange::MaskedPrompt(p) => match p.question().as_bytes() { b"Where?" => p.set_answer(Ok(OsString::from("abc"))), _ => p.set_answer(Err(ErrorCode::ConversationError)), }, other => other.set_error(ErrorCode::Abort), } } } } } impl TestHarness { fn start(&self) -> LibPamTransaction<&Self> { TransactionBuilder::new_with_service("nonstick-testharness") .build(self) .expect("expected build success") } } fn test_wrong_user() { let harness = TestHarness { wrong_username: true, ..Default::default() }; let mut tx = harness.start(); let auth = tx.authenticate(AuthnFlags::empty()); assert_eq!(auth, Err(ErrorCode::UserUnknown)); } fn test_wrong_password() { let harness = TestHarness { wrong_password: true, ..Default::default() }; let mut tx = harness.start(); let auth = tx.authenticate(AuthnFlags::empty()); assert_eq!(auth, Err(ErrorCode::AuthenticationError)); } fn test_correct() { let harness = TestHarness::default(); let mut tx = harness.start(); tx.authenticate(AuthnFlags::empty()).unwrap(); assert_eq!(tx.items().user().unwrap().unwrap(), "updated-in-process"); let result = tx.account_management(AuthnFlags::empty()); assert_eq!(result, Err(ErrorCode::NewAuthTokRequired)); harness.changing_password.set(true); let change = tx.change_authtok(AuthtokFlags::CHANGE_EXPIRED_AUTHTOK); if cfg!(pam_impl = "Sun") { assert!(change.is_err()) } else { assert_eq!(change, Err(ErrorCode::TryAgain)); } tx.change_authtok(AuthtokFlags::CHANGE_EXPIRED_AUTHTOK) .unwrap(); let environ: HashMap<_, _> = tx.environ().iter().collect(); assert_eq!( environ, HashMap::from([("nin".into(), "nine inch nails".into())]) ); }