fabaccess-bffh/bffhd/authentication/mod.rs

148 lines
4.5 KiB
Rust
Raw Permalink Normal View History

2022-03-15 17:52:47 +01:00
use crate::users::Users;
2022-06-02 17:46:26 +02:00
use miette::{Context, IntoDiagnostic};
2022-05-05 15:50:44 +02:00
use rsasl::error::SessionError;
2022-03-12 01:27:58 +01:00
use rsasl::mechname::Mechname;
2022-03-15 17:52:47 +01:00
use rsasl::property::{AuthId, Password};
2022-03-13 22:50:37 +01:00
use rsasl::session::{Session, SessionData};
2022-03-15 17:52:47 +01:00
use rsasl::validate::{validations, Validation};
use rsasl::{Property, SASL};
2022-03-15 17:52:47 +01:00
use std::sync::Arc;
2022-04-26 23:21:43 +02:00
use crate::authentication::fabfire::FabFireCardKey;
2022-03-16 19:29:36 +01:00
mod fabfire;
2022-03-08 18:52:49 +01:00
2022-03-13 22:50:37 +01:00
struct Callback {
users: Users,
span: tracing::Span,
2022-03-13 22:50:37 +01:00
}
impl Callback {
pub fn new(users: Users) -> Self {
let span = tracing::info_span!("SASL callback");
Self { users, span }
2022-03-13 22:50:37 +01:00
}
}
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::<AuthId>()?;
2022-05-05 15:50:44 +02:00
let user = self
.users
.get_user(authcid.unwrap().as_ref())
.ok_or(SessionError::AuthenticationFailure)?;
2022-05-05 15:50:44 +02:00
let kv = user
.userdata
.kv
.get("cardkey")
.ok_or(SessionError::AuthenticationFailure)?;
2022-05-05 15:50:44 +02:00
let card_key = <[u8; 16]>::try_from(
hex::decode(kv).map_err(|_| SessionError::AuthenticationFailure)?,
)
.map_err(|_| SessionError::AuthenticationFailure)?;
session.set_property::<FabFireCardKey>(Arc::new(card_key));
Ok(())
}
_ => Err(SessionError::NoProperty { property }),
}
}
2022-03-15 17:52:47 +01:00
fn validate(
&self,
session: &mut SessionData,
validation: Validation,
2022-03-15 20:00:43 +01:00
_mechanism: &Mechname,
2022-03-15 17:52:47 +01:00
) -> Result<(), SessionError> {
let span = tracing::info_span!(parent: &self.span, "validate");
let _guard = span.enter();
2022-03-15 17:52:47 +01:00
match validation {
validations::SIMPLE => {
let authnid = session
.get_property::<AuthId>()
.ok_or(SessionError::no_property::<AuthId>())?;
tracing::debug!(authid=%authnid, "SIMPLE validation requested");
2022-05-05 15:50:44 +02:00
if let Some(user) = self.users.get_user(authnid.as_str()) {
let passwd = session
.get_property::<Password>()
.ok_or(SessionError::no_property::<Password>())?;
2022-03-15 17:52:47 +01:00
if user
.check_password(passwd.as_bytes())
.map_err(|_e| SessionError::AuthenticationFailure)?
{
return Ok(());
} else {
tracing::warn!(authid=%authnid, "AUTH FAILED: bad password");
}
2022-03-15 17:52:47 +01:00
} else {
tracing::warn!(authid=%authnid, "AUTH FAILED: no such user '{}'", authnid);
2022-03-15 17:52:47 +01:00
}
Err(SessionError::AuthenticationFailure)
2022-03-15 17:52:47 +01:00
}
_ => {
tracing::error!(?validation, "Unimplemented validation requested");
Err(SessionError::no_validate(validation))
2022-05-05 15:50:44 +02:00
}
2022-03-15 17:52:47 +01:00
}
2022-03-13 22:50:37 +01:00
}
}
2022-03-12 01:27:58 +01:00
struct Inner {
rsasl: SASL,
}
impl Inner {
pub fn new(rsasl: SASL) -> Self {
Self { rsasl }
}
}
2022-03-10 20:52:34 +01:00
2022-03-12 01:27:58 +01:00
#[derive(Clone)]
2022-03-12 17:31:53 +01:00
pub struct AuthenticationHandle {
2022-03-12 01:27:58 +01:00
inner: Arc<Inner>,
2022-03-10 20:52:34 +01:00
}
2022-03-12 17:31:53 +01:00
impl AuthenticationHandle {
2022-03-13 22:50:37 +01:00
pub fn new(userdb: Users) -> Self {
2022-03-16 19:29:36 +01:00
let span = tracing::debug_span!("authentication");
let _guard = span.enter();
2022-03-13 22:50:37 +01:00
let mut rsasl = SASL::new();
rsasl.install_callback(Arc::new(Callback::new(userdb)));
2022-03-16 19:29:36 +01:00
2022-05-05 15:50:44 +02:00
let mechs: Vec<&'static str> = rsasl
.server_mech_list()
.into_iter()
2022-03-16 19:29:36 +01:00
.map(|m| m.mechanism.as_str())
.collect();
2022-05-05 15:50:44 +02:00
tracing::info!(available_mechs = mechs.len(), "initialized sasl backend");
2022-03-16 19:29:36 +01:00
tracing::debug!(?mechs, "available mechs");
2022-03-15 17:52:47 +01:00
Self {
inner: Arc::new(Inner::new(rsasl)),
}
2022-03-12 01:27:58 +01:00
}
2022-03-10 20:52:34 +01:00
2022-06-02 17:46:26 +02:00
pub fn start(&self, mechanism: &Mechname) -> miette::Result<Session> {
Ok(self
.inner
.rsasl
.server_start(mechanism)
.into_diagnostic()
.wrap_err("Failed to start a SASL authentication with the given mechanism")?)
2022-03-12 17:31:53 +01:00
}
2022-03-15 17:52:47 +01:00
pub fn list_available_mechs(&self) -> impl IntoIterator<Item = &Mechname> {
self.inner
.rsasl
.server_mech_list()
.into_iter()
.map(|m| m.mechanism)
2022-03-12 01:27:58 +01:00
}
2022-03-15 17:52:47 +01:00
}