Merge branch 'feature/rsasl-update' into development

* feature/rsasl-update:
  Update to latest rsasl
  Port rsasl
This commit is contained in:
Nadja Reitzenstein 2022-11-01 10:48:14 +01:00
commit 1971515601
10 changed files with 556 additions and 575 deletions

773
Cargo.lock generated

File diff suppressed because it is too large Load Diff

View File

@ -84,7 +84,9 @@ capnp = "0.14"
capnp-rpc = "0.14.1" capnp-rpc = "0.14.1"
# API Authentication # API Authentication
desfire = "0.2.0-alpha1" #desfire = "0.2.0-alpha1"
desfire = { path = "../nfc_rs" }
hex = { version = "0.4.3", features = ["serde"] } hex = { version = "0.4.3", features = ["serde"] }
futures-signals = "0.3.22" futures-signals = "0.3.22"
@ -112,10 +114,9 @@ rustls-native-certs = "0.6.1"
shadow-rs = "0.11" shadow-rs = "0.11"
[dependencies.rsasl] [dependencies.rsasl]
git = "https://github.com/dequbed/rsasl.git" version = "2.0.0-rc.3"
rev = "0b5012d0"
default_features = false default_features = false
features = ["unstable_custom_mechanism", "provider", "registry_static", "plain"] features = ["unstable_custom_mechanism", "provider", "registry_static", "config_builder", "plain"]
[dev-dependencies] [dev-dependencies]
futures-test = "0.3.16" futures-test = "0.3.16"
@ -126,3 +127,6 @@ shadow-rs = "0.11"
[workspace] [workspace]
members = ["runtime/*", "modules/*", "api"] members = ["runtime/*", "modules/*", "api"]
[patch.crates-io]
desfire = { path = "../nfc_rs" }

View File

@ -2,43 +2,23 @@ mod server;
pub use server::FabFire; pub use server::FabFire;
use rsasl::mechname::Mechname; use rsasl::mechname::Mechname;
use rsasl::registry::{Mechanism, MECHANISMS}; use rsasl::registry::{Mechanism, MECHANISMS, Side};
use rsasl::session::Side;
const MECHNAME: &'static Mechname = &Mechname::const_new_unchecked(b"X-FABFIRE"); const MECHNAME: &'static Mechname = &Mechname::const_new_unchecked(b"X-FABFIRE");
#[linkme::distributed_slice(MECHANISMS)] #[linkme::distributed_slice(MECHANISMS)]
pub static FABFIRE: Mechanism = Mechanism { pub static FABFIRE: Mechanism =
mechanism: MECHNAME, Mechanism::build(MECHNAME, 300, None, Some(FabFire::new_server), Side::Client);
priority: 300,
// In this situation there's one struct for both sides, however you can just as well use
// different types than then have different `impl Authentication` instead of checking a value
// in self.
client: None,
server: Some(FabFire::new_server),
first: Side::Client,
};
use rsasl::property::{Property, PropertyDefinition, PropertyQ};
use std::marker::PhantomData; use std::marker::PhantomData;
use rsasl::property::SizedProperty;
// All Property types must implement Debug. // All Property types must implement Debug.
#[derive(Debug)] #[derive(Debug)]
// The `PhantomData` in the constructor is only used so external crates can't construct this type. // The `PhantomData` in the constructor is only used so external crates can't construct this type.
pub struct FabFireCardKey(PhantomData<()>); pub struct FabFireCardKey(PhantomData<()>);
impl PropertyQ for FabFireCardKey {
// This is the type stored for this property. This could also be the struct itself if you impl SizedProperty<'_> for FabFireCardKey {
// so choose type Value = [u8; 16];
type Item = [u8; 16]; const DESCRIPTION: &'static str = "A AES128 key for a FabFire card";
// You need to return the constant you define below here for things to work properly
fn property() -> Property {
FABFIRECARDKEY
} }
}
// This const is used by your mechanism to query and by your users to set your property. It
// thus needs to be exported from your crate
pub const FABFIRECARDKEY: Property = Property::new(&PropertyDefinition::new(
// Short name, used in `Debug` output
"FabFireCardKey",
// A longer user-facing name used in `Display` output
"A AES128 key for a FabFire card",
));

View File

@ -2,11 +2,10 @@ use desfire::desfire::desfire::MAX_BYTES_PER_TRANSACTION;
use desfire::desfire::Desfire; use desfire::desfire::Desfire;
use desfire::error::Error as DesfireError; use desfire::error::Error as DesfireError;
use desfire::iso7816_4::apduresponse::APDUResponse; use desfire::iso7816_4::apduresponse::APDUResponse;
use rsasl::error::{MechanismError, MechanismErrorKind, SASLError, SessionError}; use rsasl::callback::SessionData;
use rsasl::mechanism::Authentication; use rsasl::mechanism::{Authentication, MechanismData, MechanismError, MechanismErrorKind, State, ThisProvider};
use rsasl::prelude::{MessageSent, SASLConfig, SASLError, SessionError};
use rsasl::property::AuthId; use rsasl::property::AuthId;
use rsasl::session::{SessionData, StepResult};
use rsasl::SASL;
use serde::{Deserialize, Serialize}; use serde::{Deserialize, Serialize};
use std::convert::TryFrom; use std::convert::TryFrom;
use std::fmt::{Debug, Display, Formatter}; use std::fmt::{Debug, Display, Formatter};
@ -63,6 +62,10 @@ impl Display for FabFireError {
} }
} }
impl std::error::Error for FabFireError {
}
impl MechanismError for FabFireError { impl MechanismError for FabFireError {
fn kind(&self) -> MechanismErrorKind { fn kind(&self) -> MechanismErrorKind {
match self { match self {
@ -154,7 +157,7 @@ pub struct FabFire {
const MAGIC: &'static str = "FABACCESS\0DESFIRE\01.0\0"; const MAGIC: &'static str = "FABACCESS\0DESFIRE\01.0\0";
impl FabFire { impl FabFire {
pub fn new_server(_sasl: &SASL) -> Result<Box<dyn Authentication>, SASLError> { pub fn new_server(_sasl: &SASLConfig) -> Result<Box<dyn Authentication>, SASLError> {
Ok(Box::new(Self { Ok(Box::new(Self {
step: Step::New, step: Step::New,
card_info: None, card_info: None,
@ -174,10 +177,10 @@ impl FabFire {
impl Authentication for FabFire { impl Authentication for FabFire {
fn step( fn step(
&mut self, &mut self,
session: &mut SessionData, session: &mut MechanismData<'_>,
input: Option<&[u8]>, input: Option<&[u8]>,
writer: &mut dyn Write, writer: &mut dyn Write,
) -> StepResult { ) -> Result<State, SessionError> {
match self.step { match self.step {
Step::New => { Step::New => {
tracing::trace!("Step: New"); tracing::trace!("Step: New");
@ -216,7 +219,7 @@ impl Authentication for FabFire {
writer writer
.write_all(&send_buf) .write_all(&send_buf)
.map_err(|e| SessionError::Io { source: e })?; .map_err(|e| SessionError::Io { source: e })?;
Ok(rsasl::session::Step::NeedsMore(Some(send_buf.len()))) Ok(State::Running)
} }
Err(e) => { Err(e) => {
tracing::error!("Failed to serialize APDUCommand: {:?}", e); tracing::error!("Failed to serialize APDUCommand: {:?}", e);
@ -282,7 +285,7 @@ impl Authentication for FabFire {
writer writer
.write_all(&send_buf) .write_all(&send_buf)
.map_err(|e| SessionError::Io { source: e })?; .map_err(|e| SessionError::Io { source: e })?;
Ok(rsasl::session::Step::NeedsMore(Some(send_buf.len()))) Ok(State::Running)
} }
Err(e) => { Err(e) => {
tracing::error!("Failed to serialize APDUCommand: {:?}", e); tracing::error!("Failed to serialize APDUCommand: {:?}", e);
@ -365,7 +368,7 @@ impl Authentication for FabFire {
writer writer
.write_all(&send_buf) .write_all(&send_buf)
.map_err(|e| SessionError::Io { source: e })?; .map_err(|e| SessionError::Io { source: e })?;
Ok(rsasl::session::Step::NeedsMore(Some(send_buf.len()))) Ok(State::Running)
} }
Err(e) => { Err(e) => {
tracing::error!("Failed to serialize APDUCommand: {:?}", e); tracing::error!("Failed to serialize APDUCommand: {:?}", e);
@ -452,7 +455,7 @@ impl Authentication for FabFire {
writer writer
.write_all(&send_buf) .write_all(&send_buf)
.map_err(|e| SessionError::Io { source: e })?; .map_err(|e| SessionError::Io { source: e })?;
Ok(rsasl::session::Step::NeedsMore(Some(send_buf.len()))) Ok(State::Running)
} }
Err(e) => { Err(e) => {
tracing::error!("Failed to serialize APDUCommand: {:?}", e); tracing::error!("Failed to serialize APDUCommand: {:?}", e);
@ -491,24 +494,9 @@ impl Authentication for FabFire {
match apdu_response.body { match apdu_response.body {
Some(data) => { Some(data) => {
let token = String::from_utf8(data).unwrap(); let token = String::from_utf8(data).unwrap();
session.set_property::<AuthId>(Arc::new( let prov =
token.trim_matches(char::from(0)).to_string(), ThisProvider::<AuthId>::with(token.trim_matches(char::from(0)));
)); let key = session.need_with::<FabFireCardKey, _, _>(&prov, |key| Ok(Box::from(key.as_slice())))?;
let key = match session.get_property_or_callback::<FabFireCardKey>()
{
Ok(Some(key)) => Box::from(key.as_slice()),
Ok(None) => {
tracing::error!("No keys on file for token");
return Err(FabFireError::InvalidCredentials(
"No keys on file for token".to_string(),
)
.into());
}
Err(e) => {
tracing::error!("Failed to get key: {:?}", e);
return Err(FabFireError::Session(e).into());
}
};
self.key_info = Some(KeyInfo { key_id: 0x01, key }); self.key_info = Some(KeyInfo { key_id: 0x01, key });
} }
None => { None => {
@ -546,7 +534,7 @@ impl Authentication for FabFire {
writer writer
.write_all(&send_buf) .write_all(&send_buf)
.map_err(|e| SessionError::Io { source: e })?; .map_err(|e| SessionError::Io { source: e })?;
Ok(rsasl::session::Step::NeedsMore(Some(send_buf.len()))) Ok(State::Running)
} }
Err(e) => { Err(e) => {
tracing::error!("Failed to serialize command: {:?}", e); tracing::error!("Failed to serialize command: {:?}", e);
@ -616,7 +604,7 @@ impl Authentication for FabFire {
writer writer
.write_all(&send_buf) .write_all(&send_buf)
.map_err(|e| SessionError::Io { source: e })?; .map_err(|e| SessionError::Io { source: e })?;
Ok(rsasl::session::Step::NeedsMore(Some(send_buf.len()))) Ok(State::Running)
} }
Err(e) => { Err(e) => {
tracing::error!("Failed to serialize command: {:?}", e); tracing::error!("Failed to serialize command: {:?}", e);
@ -691,9 +679,7 @@ impl Authentication for FabFire {
writer writer
.write_all(&send_buf) .write_all(&send_buf)
.map_err(|e| SessionError::Io { source: e })?; .map_err(|e| SessionError::Io { source: e })?;
return Ok(rsasl::session::Step::Done(Some( return Ok(State::Finished(MessageSent::Yes));
send_buf.len(),
)));
} }
Err(e) => { Err(e) => {
tracing::error!( tracing::error!(
@ -722,6 +708,6 @@ impl Authentication for FabFire {
} }
} }
return Ok(rsasl::session::Step::Done(None)); return Ok(State::Finished(MessageSent::No));
} }
} }

View File

@ -1,14 +1,14 @@
use crate::users::Users; use crate::users::Users;
use miette::{Context, IntoDiagnostic}; use miette::{IntoDiagnostic, WrapErr};
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 std::sync::Arc;
use rsasl::callback::{CallbackError, Request, SessionCallback, SessionData, Context};
use rsasl::mechanism::SessionError;
use rsasl::prelude::{Mechname, SASLConfig, SASLServer, Session, Validation};
use rsasl::property::{AuthId, AuthzId, Password};
use rsasl::validate::{Validate, ValidationError};
use crate::authentication::fabfire::FabFireCardKey; use crate::authentication::fabfire::FabFireCardKey;
use crate::users::db::User;
mod fabfire; mod fabfire;
@ -22,89 +22,78 @@ impl Callback {
Self { users, span } Self { users, span }
} }
} }
impl rsasl::callback::Callback for Callback { impl SessionCallback for Callback {
fn provide_prop( fn callback(&self, session_data: &SessionData, context: &Context, request: &mut Request) -> Result<(), SessionError> {
&self, if let Some(authid) = context.get_ref::<AuthId>() {
session: &mut rsasl::session::SessionData, request.satisfy_with::<FabFireCardKey, _>(|| {
property: Property, let user = self.users.get_user(authid).ok_or(CallbackError::NoValue)?;
) -> Result<(), SessionError> { let kv = user.userdata.kv.get("cardkey").ok_or(CallbackError::NoValue)?;
match property {
fabfire::FABFIRECARDKEY => {
let authcid = session.get_property_or_callback::<AuthId>()?;
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( let card_key = <[u8; 16]>::try_from(
hex::decode(kv).map_err(|_| SessionError::AuthenticationFailure)?, hex::decode(kv).map_err(|_| CallbackError::NoValue)?,
) ).map_err(|_| CallbackError::NoValue)?;
.map_err(|_| SessionError::AuthenticationFailure)?; Ok(card_key)
session.set_property::<FabFireCardKey>(Arc::new(card_key)); })?;
}
Ok(()) Ok(())
} }
_ => Err(SessionError::NoProperty { property }),
}
}
fn validate( fn validate(&self, session_data: &SessionData, context: &Context, validate: &mut Validate<'_>) -> Result<(), ValidationError> {
&self,
session: &mut SessionData,
validation: Validation,
_mechanism: &Mechname,
) -> Result<(), SessionError> {
let span = tracing::info_span!(parent: &self.span, "validate"); let span = tracing::info_span!(parent: &self.span, "validate");
let _guard = span.enter(); let _guard = span.enter();
match validation { if validate.is::<V>() {
validations::SIMPLE => { match session_data.mechanism().mechanism.as_str() {
let authnid = session "PLAIN" => {
.get_property::<AuthId>() let authcid = context.get_ref::<AuthId>()
.ok_or(SessionError::no_property::<AuthId>())?; .ok_or(ValidationError::MissingRequiredProperty)?;
tracing::debug!(authid=%authnid, "SIMPLE validation requested"); let authzid = context.get_ref::<AuthzId>();
let password = context.get_ref::<Password>()
.ok_or(ValidationError::MissingRequiredProperty)?;
if let Some(user) = self.users.get_user(authnid.as_str()) { if authzid.is_some() {
let passwd = session return Ok(())
.get_property::<Password>() }
.ok_or(SessionError::no_property::<Password>())?;
if user if let Some(user) = self.users.get_user(authcid) {
.check_password(passwd.as_bytes()) match user.check_password(password) {
.map_err(|_e| SessionError::AuthenticationFailure)? Ok(true) => {
{ validate.finalize::<V>(user)
return Ok(()); }
} else { Ok(false) => {
tracing::warn!(authid=%authnid, "AUTH FAILED: bad password"); tracing::warn!(authid=%authcid, "AUTH FAILED: bad password");
}
Err(error) => {
tracing::warn!(authid=%authcid, "Bad DB entry: {}", error);
}
} }
} else { } else {
tracing::warn!(authid=%authnid, "AUTH FAILED: no such user '{}'", authnid); tracing::warn!(authid=%authcid, "AUTH FAILED: no such user");
}
Err(SessionError::AuthenticationFailure)
}
_ => {
tracing::error!(?validation, "Unimplemented validation requested");
Err(SessionError::no_validate(validation))
} }
} }
_ => {}
}
}
Ok(())
} }
} }
pub struct V;
impl Validation for V {
type Value = User;
}
#[derive(Clone)]
struct Inner { struct Inner {
rsasl: SASL, rsasl: Arc<SASLConfig>,
} }
impl Inner { impl Inner {
pub fn new(rsasl: SASL) -> Self { pub fn new(rsasl: Arc<SASLConfig>) -> Self {
Self { rsasl } Self { rsasl }
} }
} }
#[derive(Clone)] #[derive(Clone)]
pub struct AuthenticationHandle { pub struct AuthenticationHandle {
inner: Arc<Inner>, inner: Inner,
} }
impl AuthenticationHandle { impl AuthenticationHandle {
@ -112,11 +101,13 @@ impl AuthenticationHandle {
let span = tracing::debug_span!("authentication"); let span = tracing::debug_span!("authentication");
let _guard = span.enter(); let _guard = span.enter();
let mut rsasl = SASL::new(); let config = SASLConfig::builder()
rsasl.install_callback(Arc::new(Callback::new(userdb))); .with_defaults()
.with_callback(Callback::new(userdb))
.unwrap();
let mechs: Vec<&'static str> = rsasl let mechs: Vec<&'static str> = SASLServer::<V>::new(config.clone())
.server_mech_list() .get_available()
.into_iter() .into_iter()
.map(|m| m.mechanism.as_str()) .map(|m| m.mechanism.as_str())
.collect(); .collect();
@ -124,24 +115,18 @@ impl AuthenticationHandle {
tracing::debug!(?mechs, "available mechs"); tracing::debug!(?mechs, "available mechs");
Self { Self {
inner: Arc::new(Inner::new(rsasl)), inner: Inner::new(config),
} }
} }
pub fn start(&self, mechanism: &Mechname) -> miette::Result<Session> { pub fn start(&self, mechanism: &Mechname) -> miette::Result<Session<V>> {
Ok(self Ok(SASLServer::new(self.inner.rsasl.clone())
.inner .start_suggested(mechanism)
.rsasl
.server_start(mechanism)
.into_diagnostic() .into_diagnostic()
.wrap_err("Failed to start a SASL authentication with the given mechanism")?) .wrap_err("Failed to start a SASL authentication with the given mechanism")?)
} }
pub fn list_available_mechs(&self) -> impl IntoIterator<Item = &Mechname> { pub fn sess(&self) -> SASLServer<V> {
self.inner SASLServer::new(self.inner.rsasl.clone())
.rsasl
.server_mech_list()
.into_iter()
.map(|m| m.mechanism)
} }
} }

View File

@ -3,10 +3,11 @@ use capnp::Error;
use capnp_rpc::pry; use capnp_rpc::pry;
use rsasl::mechname::Mechname; use rsasl::mechname::Mechname;
use rsasl::property::AuthId; use rsasl::property::AuthId;
use rsasl::session::{Session, Step};
use std::fmt; use std::fmt;
use std::fmt::{Formatter, Write}; use std::fmt::{Formatter, Write};
use std::io::Cursor; use std::io::Cursor;
use rsasl::prelude::{MessageSent, Session};
use rsasl::prelude::State as SaslState;
use tracing::Span; use tracing::Span;
use crate::capnp::session::APISession; use crate::capnp::session::APISession;
@ -15,6 +16,7 @@ use api::authenticationsystem_capnp::authentication::{
AbortParams, AbortResults, Server as AuthenticationSystem, StepParams, StepResults, AbortParams, AbortResults, Server as AuthenticationSystem, StepParams, StepResults,
}; };
use api::authenticationsystem_capnp::{response, response::Error as ErrorCode}; use api::authenticationsystem_capnp::{response, response::Error as ErrorCode};
use crate::authentication::V;
const TARGET: &str = "bffh::api::authenticationsystem"; const TARGET: &str = "bffh::api::authenticationsystem";
@ -27,7 +29,7 @@ impl Authentication {
pub fn new( pub fn new(
parent: &Span, parent: &Span,
mechanism: &Mechname, /* TODO: this is stored in session as well, get it out of there. */ mechanism: &Mechname, /* TODO: this is stored in session as well, get it out of there. */
session: Session, session: Session<V>,
sessionmanager: SessionManager, sessionmanager: SessionManager,
) -> Self { ) -> Self {
let span = tracing::info_span!( let span = tracing::info_span!(
@ -92,7 +94,7 @@ enum State {
InvalidMechanism, InvalidMechanism,
Finished, Finished,
Aborted, Aborted,
Running(Session, SessionManager), Running(Session<V>, SessionManager),
} }
impl AuthenticationSystem for Authentication { impl AuthenticationSystem for Authentication {
@ -121,36 +123,35 @@ impl AuthenticationSystem for Authentication {
{ {
let data: &[u8] = pry!(pry!(params.get()).get_data()); let data: &[u8] = pry!(pry!(params.get()).get_data());
let mut out = Cursor::new(Vec::new()); let mut out = Vec::new();
match session.step(Some(data), &mut out) { match session.step(Some(data), &mut out) {
Ok(Step::Done(data)) => { Ok(SaslState::Finished(sent)) => {
self.state = State::Finished; self.state = State::Finished;
let uid = pry!(session.get_property::<AuthId>().ok_or_else(|| { if let Some(user) = session.validation() {
tracing::warn!("Authentication didn't provide an authid as required."); let session = manager.open(&self.span, user);
capnp::Error::failed(
"Authentication didn't provide an authid as required".to_string(),
)
}));
let session = pry!(manager.open(&self.span, uid.as_ref()).ok_or_else(|| {
tracing::warn!(uid = uid.as_str(), "Failed to lookup the given user");
capnp::Error::failed("Failed to lookup the given user".to_string())
}));
response = Response { response = Response {
union_field: "successful", union_field: "successful",
}; };
let mut builder = builder.init_successful(); let mut builder = builder.init_successful();
if data.is_some() { if sent == MessageSent::Yes {
builder.set_additional_data(out.into_inner().as_slice()); builder.set_additional_data(out.as_slice());
} }
APISession::build(session, builder) APISession::build(session, builder)
} else {
let mut builder = builder.init_failed();
builder.set_code(ErrorCode::InvalidCredentials);
response = Response {
union_field: "error",
};
} }
Ok(Step::NeedsMore(_)) => { }
Ok(SaslState::Running) => {
self.state = State::Running(session, manager); self.state = State::Running(session, manager);
builder.set_challenge(out.into_inner().as_slice()); builder.set_challenge(out.as_slice());
response = Response { response = Response {
union_field: "challenge", union_field: "challenge",

View File

@ -95,9 +95,10 @@ impl bootstrap::Server for BootCap {
let builder = result.get(); let builder = result.get();
let mechs: Vec<_> = self let mechs: Vec<_> = self
.authentication .authentication
.list_available_mechs() .sess()
.get_available()
.into_iter() .into_iter()
.map(|m| m.as_str()) .map(|m| m.mechanism.as_str())
.collect(); .collect();
let mut mechbuilder = builder.init_mechs(mechs.len() as u32); let mut mechbuilder = builder.init_mechs(mechs.len() as u32);
for (i, m) in mechs.iter().enumerate() { for (i, m) in mechs.iter().enumerate() {
@ -146,7 +147,7 @@ impl bootstrap::Server for BootCap {
tracing::trace!(params.mechanism = mechanism, "method call"); tracing::trace!(params.mechanism = mechanism, "method call");
let mechname = Mechname::new(mechanism.as_bytes()); let mechname = Mechname::parse(mechanism.as_bytes());
let auth = if let Ok(mechname) = mechname { let auth = if let Ok(mechname) = mechname {
if let Ok(session) = self.authentication.start(mechname) { if let Ok(session) = self.authentication.start(mechname) {
Authentication::new(&self.span, mechname, session, self.sessionmanager.clone()) Authentication::new(&self.span, mechname, session, self.sessionmanager.clone())

View File

@ -56,7 +56,7 @@ impl InitiatorCallbacks {
} }
pub fn open_session(&self, uid: &str) -> Option<SessionHandle> { pub fn open_session(&self, uid: &str) -> Option<SessionHandle> {
self.sessions.open(&self.span, uid) self.sessions.try_open(&self.span, uid)
} }
} }

View File

@ -4,6 +4,7 @@ use crate::resources::Resource;
use crate::users::{db, UserRef}; use crate::users::{db, UserRef};
use crate::Users; use crate::Users;
use tracing::Span; use tracing::Span;
use crate::users::db::User;
#[derive(Clone)] #[derive(Clone)]
pub struct SessionManager { pub struct SessionManager {
@ -16,25 +17,25 @@ impl SessionManager {
Self { users, roles } Self { users, roles }
} }
pub fn try_open(&self, parent: &Span, uid: impl AsRef<str>) -> Option<SessionHandle> {
self.users.get_user(uid.as_ref()).map(|user| self.open(parent, user))
}
// TODO: make infallible // TODO: make infallible
pub fn open(&self, parent: &Span, uid: impl AsRef<str>) -> Option<SessionHandle> { pub fn open(&self, parent: &Span, user: User) -> SessionHandle {
let uid = uid.as_ref(); let uid = user.id.as_str();
if let Some(user) = self.users.get_user(uid) {
let span = tracing::info_span!( let span = tracing::info_span!(
target: "bffh::api", target: "bffh::api",
parent: parent, parent: parent,
"session", "session",
uid = uid, uid,
); );
tracing::trace!(parent: &span, uid, ?user, "opening session"); tracing::trace!(parent: &span, uid, ?user, "opening session");
Some(SessionHandle { SessionHandle {
span, span,
users: self.users.clone(), users: self.users.clone(),
roles: self.roles.clone(), roles: self.roles.clone(),
user: UserRef::new(user.id), user: UserRef::new(user.id),
})
} else {
None
} }
} }
} }

View File

@ -34,11 +34,9 @@ fn hash_pw(pw: &[u8]) -> argon2::Result<String> {
} }
impl User { impl User {
pub fn check_password(&self, pwd: &[u8]) -> miette::Result<bool> { pub fn check_password(&self, pwd: &[u8]) -> Result<bool, argon2::Error> {
if let Some(ref encoded) = self.userdata.passwd { if let Some(ref encoded) = self.userdata.passwd {
argon2::verify_encoded(encoded, pwd) argon2::verify_encoded(encoded, pwd)
.into_diagnostic()
.wrap_err("Stored password is an invalid string")
} else { } else {
Ok(false) Ok(false)
} }