use crate::users::Users; use rsasl::error::{SessionError}; use rsasl::mechname::Mechname; use rsasl::property::{AuthId, Password}; use rsasl::session::{Session, SessionData}; use rsasl::validate::{validations, Validation}; use rsasl::{Property, SASL}; use std::sync::Arc; use rsasl::registry::Mechanism; use crate::authentication::fabfire::FabFireCardKey; mod fabfire; struct Callback { users: Users, } impl Callback { pub fn new(users: Users) -> Self { Self { users } } } impl rsasl::callback::Callback for Callback { fn provide_prop( &self, session: &mut rsasl::session::SessionData, property: Property, ) -> Result<(), SessionError> { match property { fabfire::FABFIRECARDKEY => { let authcid = session.get_property_or_callback::()?; let user = self.users.get_user(authcid.unwrap().as_ref()) .ok_or(SessionError::AuthenticationFailure)?; let kv = user.userdata.kv.get("cardkey") .ok_or(SessionError::AuthenticationFailure)?; let card_key = <[u8; 16]>::try_from(hex::decode(kv) .map_err(|_| SessionError::AuthenticationFailure)?) .map_err(|_| SessionError::AuthenticationFailure)?; session.set_property::(Arc::new(card_key)); Ok(()) } _ => Err(SessionError::NoProperty { property }), } } fn validate( &self, session: &mut SessionData, validation: Validation, _mechanism: &Mechname, ) -> Result<(), SessionError> { match validation { validations::SIMPLE => { let authnid = session .get_property::() .ok_or(SessionError::no_property::())?; let user = self .users .get_user(authnid.as_str()) .ok_or(SessionError::AuthenticationFailure)?; let passwd = session .get_property::() .ok_or(SessionError::no_property::())?; if user .check_password(passwd.as_bytes()) .map_err(|_e| SessionError::AuthenticationFailure)? { Ok(()) } else { Err(SessionError::AuthenticationFailure) } } _ => Err(SessionError::no_validate(validation)), } } } struct Inner { rsasl: SASL, } impl Inner { pub fn new(rsasl: SASL) -> Self { Self { rsasl } } } #[derive(Clone)] pub struct AuthenticationHandle { inner: Arc, } impl AuthenticationHandle { pub fn new(userdb: Users) -> Self { let span = tracing::debug_span!("authentication"); let _guard = span.enter(); let mut rsasl = SASL::new(); rsasl.install_callback(Arc::new(Callback::new(userdb))); let mechs: Vec<&'static str> = rsasl.server_mech_list().into_iter() .map(|m| m.mechanism.as_str()) .collect(); tracing::info!(available_mechs=mechs.len(), "initialized sasl backend"); tracing::debug!(?mechs, "available mechs"); Self { inner: Arc::new(Inner::new(rsasl)), } } pub fn start(&self, mechanism: &Mechname) -> anyhow::Result { Ok(self.inner.rsasl.server_start(mechanism)?) } pub fn list_available_mechs(&self) -> impl IntoIterator { self.inner .rsasl .server_mech_list() .into_iter() .map(|m| m.mechanism) } }