use crate::sasl;
use anyhow::{anyhow, Result};
use async_trait::async_trait;
pub const PLAIN: &str = "PLAIN";
#[async_trait]
pub trait PlainAuthenticator: Send + Sync {
async fn authenticate(&mut self, identity: &str, username: &str, password: &str) -> Result<()>;
}
pub struct PlainServer<PA: PlainAuthenticator> {
authenticator: PA,
}
impl <PA: PlainAuthenticator> PlainServer<PA> {
pub fn new(authenticator: PA) -> Self {
Self { authenticator }
}
}
#[async_trait]
impl<PA: PlainAuthenticator> sasl::Server for PlainServer<PA> {
fn mechanism(&self) -> &str {
PLAIN
}
async fn next(&mut self, response: Option<&[u8]>) -> Result<(Vec<u8>, bool)> {
if response.is_none() {
return Ok((Vec::new(), false));
}
let response = response.unwrap();
let mut parts = response.split(|&b| b == b'\x00');
let identity = std::str::from_utf8(parts.next().ok_or_else(|| anyhow!("sasl: missing identity"))?)?;
let username = std::str::from_utf8(parts.next().ok_or_else(|| anyhow!("sasl: missing username"))?)?;
let password = std::str::from_utf8(parts.next().ok_or_else(|| anyhow!("sasl: missing password"))?)?;
self.authenticator.authenticate(identity, username, password).await?;
Ok((Vec::new(), true))
}
}