use crate::context::ThisProvider;
use crate::error::{MechanismError, MechanismErrorKind, SessionError};
use crate::mechanism::Authentication;
use crate::property::AuthzId;
use crate::session::{MechanismData, MessageSent, State};
use core::str::Utf8Error;
use crate::io::Write;
use thiserror::Error;
#[derive(Debug, Eq, PartialEq, Copy, Clone, Error)]
#[error("the given external token is invalid UTF-8")]
pub struct ParseError(#[source] Utf8Error);
impl MechanismError for ParseError {
fn kind(&self) -> MechanismErrorKind {
MechanismErrorKind::Parse
}
}
#[derive(Copy, Clone, Debug)]
pub struct External;
impl Authentication for External {
fn step(
&mut self,
session: &mut MechanismData,
input: Option<&[u8]>,
_writer: &mut dyn Write,
) -> Result<State, SessionError> {
let input = input.unwrap_or(&[]);
let authzid = core::str::from_utf8(input).map_err(ParseError)?;
session.validate(&ThisProvider::<AuthzId>::with(authzid))?;
Ok(State::Finished(MessageSent::No))
}
}
#[cfg(test)]
mod tests {
use crate::callback::{Context, SessionCallback, SessionData};
use crate::property::AuthzId;
use crate::test;
use crate::validate::{Validate, ValidationError};
use std::io::Cursor;
#[derive(Default)]
struct C<'a> {
authzid: &'a str,
}
impl SessionCallback for C<'_> {
fn validate(
&self,
_session_data: &SessionData,
context: &Context,
_validate: &mut Validate<'_>,
) -> Result<(), ValidationError> {
let authzid = context.get_ref::<AuthzId>().unwrap();
println!("expected: {:?} provided: {:?}", self.authzid, authzid);
assert_eq!(authzid, self.authzid);
Ok(())
}
}
fn test_token(authzid: &'static str, input: &[u8]) {
let config = test::server_config(C { authzid });
let mut session = test::server_session(config, &super::super::mechinfo::EXTERNAL);
let mut out = Cursor::new(Vec::new());
let state = session.step(Some(input), &mut out).unwrap();
assert!(state.is_finished());
assert!(!state.has_sent_message());
}
#[test]
fn test_successful() {
let authzids = [
"", "heylookanauthzid",
"cn=this,ou=authzid,ou=has,o=weirdformatting",
"«küßî»",
"“ЌύБЇ”",
];
for authzid in authzids {
test_token(authzid, authzid.as_bytes());
}
}
#[test]
#[should_panic(
expected = "assertion `left == right` failed\n left: \"\"\n right: \"expectedauthzid\""
)]
fn test_reject_invalid_1() {
test_token("expectedauthzid", b"");
}
#[test]
#[should_panic(expected = "x")]
fn test_reject_invalid_2() {
test_token("", b"someunexpectedauthzid");
}
#[test]
fn test_no_input() {
let config = test::server_config(C::default());
let mut session = test::server_session(config, &super::super::mechinfo::EXTERNAL);
let mut out = Cursor::new(Vec::new());
let state = session.step(None, &mut out).unwrap();
assert!(state.is_finished());
assert!(!state.has_sent_message());
}
}