fabaccess-bffh/bffhd/authentication/mod.rs

147 lines
4.5 KiB
Rust
Raw Normal View History

2022-03-15 17:52:47 +01:00
use crate::users::Users;
2022-11-01 10:47:51 +01:00
use miette::{IntoDiagnostic, WrapErr};
use rsasl::callback::{CallbackError, Context, Request, SessionCallback, SessionData};
2022-10-05 17:28:47 +02:00
use rsasl::mechanism::SessionError;
2022-11-01 10:47:51 +01:00
use rsasl::prelude::{Mechname, SASLConfig, SASLServer, Session, Validation};
use rsasl::property::{AuthId, AuthzId, Password};
use rsasl::validate::{Validate, ValidationError};
use std::sync::Arc;
2022-04-26 23:21:43 +02:00
use crate::authentication::fabfire::FabFireCardKey;
2022-11-01 10:47:51 +01:00
use crate::users::db::User;
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
}
}
2022-10-05 17:28:47 +02:00
impl SessionCallback for Callback {
fn callback(
&self,
session_data: &SessionData,
context: &Context,
request: &mut Request,
) -> Result<(), SessionError> {
2022-10-05 17:28:47 +02:00
if let Some(authid) = context.get_ref::<AuthId>() {
request.satisfy_with::<FabFireCardKey, _>(|| {
let user = self.users.get_user(authid).ok_or(CallbackError::NoValue)?;
let kv = user
.userdata
.kv
.get("cardkey")
.ok_or(CallbackError::NoValue)?;
let card_key =
<[u8; 16]>::try_from(hex::decode(kv).map_err(|_| CallbackError::NoValue)?)
.map_err(|_| CallbackError::NoValue)?;
2022-10-05 17:28:47 +02:00
Ok(card_key)
})?;
}
2022-10-05 17:28:47 +02:00
Ok(())
}
fn validate(
&self,
session_data: &SessionData,
context: &Context,
validate: &mut Validate<'_>,
) -> Result<(), ValidationError> {
let span = tracing::info_span!(parent: &self.span, "validate");
let _guard = span.enter();
2022-11-01 10:47:51 +01:00
if validate.is::<V>() {
match session_data.mechanism().mechanism.as_str() {
"PLAIN" => {
let authcid = context
.get_ref::<AuthId>()
2022-11-01 10:47:51 +01:00
.ok_or(ValidationError::MissingRequiredProperty)?;
let authzid = context.get_ref::<AuthzId>();
let password = context
.get_ref::<Password>()
2022-11-01 10:47:51 +01:00
.ok_or(ValidationError::MissingRequiredProperty)?;
2022-11-01 10:47:51 +01:00
if authzid.is_some() {
return Ok(());
2022-11-01 10:47:51 +01:00
}
2022-03-15 17:52:47 +01:00
2022-11-01 10:47:51 +01:00
if let Some(user) = self.users.get_user(authcid) {
match user.check_password(password) {
Ok(true) => validate.finalize::<V>(user),
2022-11-01 10:47:51 +01:00
Ok(false) => {
tracing::warn!(authid=%authcid, "AUTH FAILED: bad password");
}
Err(error) => {
tracing::warn!(authid=%authcid, "Bad DB entry: {}", error);
}
}
} else {
2022-11-01 10:47:51 +01:00
tracing::warn!(authid=%authcid, "AUTH FAILED: no such user");
}
2022-03-15 17:52:47 +01:00
}
2022-11-01 10:47:51 +01:00
_ => {}
2022-05-05 15:50:44 +02:00
}
2022-03-15 17:52:47 +01:00
}
2022-11-01 10:47:51 +01:00
Ok(())
}
2022-03-13 22:50:37 +01:00
}
2022-11-01 10:47:51 +01:00
pub struct V;
impl Validation for V {
type Value = User;
}
#[derive(Clone)]
2022-03-12 01:27:58 +01:00
struct Inner {
2022-10-05 17:28:47 +02:00
rsasl: Arc<SASLConfig>,
2022-03-12 01:27:58 +01:00
}
impl Inner {
2022-10-05 17:28:47 +02:00
pub fn new(rsasl: Arc<SASLConfig>) -> Self {
2022-03-12 01:27:58 +01:00
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-10-05 17:28:47 +02:00
inner: 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-10-05 17:28:47 +02:00
let config = SASLConfig::builder()
.with_defaults()
.with_callback(Callback::new(userdb))
.unwrap();
2022-03-16 19:29:36 +01:00
2022-11-01 10:47:51 +01:00
let mechs: Vec<&'static str> = SASLServer::<V>::new(config.clone())
2022-10-05 17:28:47 +02:00
.get_available()
2022-05-05 15:50:44 +02:00
.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 {
2022-10-05 17:28:47 +02:00
inner: Inner::new(config),
2022-03-15 17:52:47 +01:00
}
2022-03-12 01:27:58 +01:00
}
2022-03-10 20:52:34 +01:00
2022-11-01 10:47:51 +01:00
pub fn start(&self, mechanism: &Mechname) -> miette::Result<Session<V>> {
2022-10-05 17:28:47 +02:00
Ok(SASLServer::new(self.inner.rsasl.clone())
.start_suggested(mechanism)
2022-06-02 17:46:26 +02:00
.into_diagnostic()
.wrap_err("Failed to start a SASL authentication with the given mechanism")?)
2022-03-12 17:31:53 +01:00
}
2022-11-01 10:47:51 +01:00
pub fn sess(&self) -> SASLServer<V> {
2022-10-05 17:28:47 +02:00
SASLServer::new(self.inner.rsasl.clone())
2022-03-12 01:27:58 +01:00
}
2022-03-15 17:52:47 +01:00
}