use crate::context::EmptyProvider;
use crate::error::SessionError;
use crate::mechanism::{Authentication, MechanismData};
use crate::property::{AuthId, Password};
use crate::session::{MessageSent, State};
use crate::io::Write;
#[derive(Debug, Ord, PartialOrd, Eq, PartialEq, Copy, Clone)]
enum LoginState {
Authid,
Password,
Done,
}
#[derive(Debug, Eq, PartialEq, Copy, Clone)]
pub(super) struct Login {
state: LoginState,
}
impl Login {
pub(crate) const fn new() -> Self {
Self {
state: LoginState::Authid,
}
}
}
impl Authentication for Login {
fn step(
&mut self,
session: &mut MechanismData,
_input: Option<&[u8]>,
writer: &mut dyn Write,
) -> Result<State, SessionError> {
match self.state {
LoginState::Authid => {
session.need_with::<AuthId, _, _>(&EmptyProvider, |authid| {
writer.write_all(authid.as_bytes())?;
Ok(())
})?;
self.state = LoginState::Password;
Ok(State::Running)
}
LoginState::Password => {
session.need_with::<Password, _, _>(&EmptyProvider, |password| {
writer.write_all(password)?;
Ok(())
})?;
self.state = LoginState::Done;
Ok(State::Finished(MessageSent::Yes))
}
LoginState::Done => Err(SessionError::MechanismDone),
}
}
}
#[cfg(test)]
mod tests {
use crate::config::SASLConfig;
use crate::mechanisms::login::mechinfo::LOGIN;
use crate::test::client_session;
use std::io::Cursor;
#[test]
fn simple_combination() {
let config =
SASLConfig::with_credentials(None, "testuser".to_string(), "password".to_string())
.unwrap();
let mut login = client_session(config, &LOGIN);
let mut out = Cursor::new(Vec::new());
assert!(login.step(None, &mut out).is_ok());
assert_eq!(&out.get_ref()[..], b"testuser");
let pos = usize::try_from(out.position()).unwrap();
assert!(login.step(None, &mut out).is_ok());
assert_eq!(&(out.get_ref())[pos..], b"password");
}
}