Do a validate

This commit is contained in:
Nadja Reitzenstein 2022-11-16 13:36:37 +01:00
parent b419527c83
commit 964293f653
8 changed files with 139 additions and 54 deletions

View File

@ -2,7 +2,7 @@ mod server;
pub use server::FabFire; pub use server::FabFire;
use rsasl::mechname::Mechname; use rsasl::mechname::Mechname;
use rsasl::registry::{Mechanism, MECHANISMS, Side}; use rsasl::registry::{Mechanism, Side, MECHANISMS};
const MECHNAME: &'static Mechname = &Mechname::const_new_unchecked(b"X-FABFIRE"); const MECHNAME: &'static Mechname = &Mechname::const_new_unchecked(b"X-FABFIRE");
@ -10,8 +10,8 @@ const MECHNAME: &'static Mechname = &Mechname::const_new_unchecked(b"X-FABFIRE")
pub static FABFIRE: Mechanism = pub static FABFIRE: Mechanism =
Mechanism::build(MECHNAME, 300, None, Some(FabFire::new_server), Side::Client); Mechanism::build(MECHNAME, 300, None, Some(FabFire::new_server), Side::Client);
use std::marker::PhantomData;
use rsasl::property::SizedProperty; use rsasl::property::SizedProperty;
use std::marker::PhantomData;
// All Property types must implement Debug. // All Property types must implement Debug.
#[derive(Debug)] #[derive(Debug)]

View File

@ -3,7 +3,10 @@ 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::callback::SessionData; use rsasl::callback::SessionData;
use rsasl::mechanism::{Authentication, MechanismData, MechanismError, MechanismErrorKind, State, ThisProvider}; use rsasl::mechanism::{
Authentication, Demand, DemandReply, MechanismData, MechanismError, MechanismErrorKind,
Provider, State, ThisProvider,
};
use rsasl::prelude::{MessageSent, SASLConfig, SASLError, SessionError}; use rsasl::prelude::{MessageSent, SASLConfig, SASLError, SessionError};
use rsasl::property::AuthId; use rsasl::property::AuthId;
use serde::{Deserialize, Serialize}; use serde::{Deserialize, Serialize};
@ -62,9 +65,7 @@ impl Display for FabFireError {
} }
} }
impl std::error::Error for FabFireError { impl std::error::Error for FabFireError {}
}
impl MechanismError for FabFireError { impl MechanismError for FabFireError {
fn kind(&self) -> MechanismErrorKind { fn kind(&self) -> MechanismErrorKind {
@ -92,6 +93,7 @@ struct CardInfo {
} }
struct KeyInfo { struct KeyInfo {
authid: String,
key_id: u8, key_id: u8,
key: Box<[u8]>, key: Box<[u8]>,
} }
@ -493,11 +495,19 @@ impl Authentication for FabFire {
Ok(_) => { Ok(_) => {
match apdu_response.body { match apdu_response.body {
Some(data) => { Some(data) => {
let token = String::from_utf8(data).unwrap(); let authid = String::from_utf8(data).unwrap();
let prov = let prov = ThisProvider::<AuthId>::with(
ThisProvider::<AuthId>::with(token.trim_matches(char::from(0))); authid.trim_matches(char::from(0)),
let key = session.need_with::<FabFireCardKey, _, _>(&prov, |key| Ok(Box::from(key.as_slice())))?; );
self.key_info = Some(KeyInfo { key_id: 0x01, key }); let key = session
.need_with::<FabFireCardKey, _, _>(&prov, |key| {
Ok(Box::from(key.as_slice()))
})?;
self.key_info = Some(KeyInfo {
authid,
key_id: 0x01,
key,
});
} }
None => { None => {
tracing::error!("No data in response"); tracing::error!("No data in response");
@ -679,6 +689,25 @@ 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 })?;
struct Prov<'a> {
authid: &'a str,
}
impl<'a> Provider<'a> for Prov<'a> {
fn provide(
&self,
req: &mut Demand<'a>,
) -> DemandReply<()>
{
req.provide_ref::<AuthId>(self.authid)?
.done()
}
}
let prov = Prov {
authid: &self.key_info.as_ref().unwrap().authid,
};
session.validate(&prov)?;
return Ok(State::Finished(MessageSent::Yes)); return Ok(State::Finished(MessageSent::Yes));
} }
Err(e) => { Err(e) => {

View File

@ -2,11 +2,10 @@ mod server;
pub use server::FabFire; pub use server::FabFire;
use rsasl::mechname::Mechname; use rsasl::mechname::Mechname;
use rsasl::registry::{Mechanism, MECHANISMS, Side}; use rsasl::registry::{Mechanism, Side, MECHANISMS};
const MECHNAME: &'static Mechname = &Mechname::const_new_unchecked(b"X-FABFIRE-BIN"); const MECHNAME: &'static Mechname = &Mechname::const_new_unchecked(b"X-FABFIRE-BIN");
#[linkme::distributed_slice(MECHANISMS)] #[linkme::distributed_slice(MECHANISMS)]
pub static FABFIRE: Mechanism = pub static FABFIRE: Mechanism =
Mechanism::build(MECHNAME, 300, None, Some(FabFire::new_server), Side::Client); Mechanism::build(MECHNAME, 300, None, Some(FabFire::new_server), Side::Client);

View File

@ -3,7 +3,10 @@ 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::callback::SessionData; use rsasl::callback::SessionData;
use rsasl::mechanism::{Authentication, MechanismData, MechanismError, MechanismErrorKind, State, ThisProvider}; use rsasl::mechanism::{
Authentication, Demand, DemandReply, MechanismData, MechanismError, MechanismErrorKind,
Provider, State, ThisProvider,
};
use rsasl::prelude::{MessageSent, SASLConfig, SASLError, SessionError}; use rsasl::prelude::{MessageSent, SASLConfig, SASLError, SessionError};
use rsasl::property::AuthId; use rsasl::property::AuthId;
use serde::{Deserialize, Serialize}; use serde::{Deserialize, Serialize};
@ -62,9 +65,7 @@ impl Display for FabFireError {
} }
} }
impl std::error::Error for FabFireError { impl std::error::Error for FabFireError {}
}
impl MechanismError for FabFireError { impl MechanismError for FabFireError {
fn kind(&self) -> MechanismErrorKind { fn kind(&self) -> MechanismErrorKind {
@ -92,6 +93,7 @@ struct CardInfo {
} }
struct KeyInfo { struct KeyInfo {
authid: String,
key_id: u8, key_id: u8,
key: Box<[u8]>, key: Box<[u8]>,
} }
@ -165,7 +167,7 @@ impl Authentication for FabFire {
.write_all(&data) .write_all(&data)
.map_err(|e| SessionError::Io { source: e })?; .map_err(|e| SessionError::Io { source: e })?;
Ok(State::Running) Ok(State::Running)
}, }
Err(e) => { Err(e) => {
tracing::error!( tracing::error!(
"Failed to convert APDUCommand to Vec<u8>: {:?}", "Failed to convert APDUCommand to Vec<u8>: {:?}",
@ -209,7 +211,7 @@ impl Authentication for FabFire {
.write_all(&data) .write_all(&data)
.map_err(|e| SessionError::Io { source: e })?; .map_err(|e| SessionError::Io { source: e })?;
Ok(State::Running) Ok(State::Running)
}, }
Err(e) => { Err(e) => {
tracing::error!("Failed to convert APDUCommand to Vec<u8>: {:?}", e); tracing::error!("Failed to convert APDUCommand to Vec<u8>: {:?}", e);
return Err(FabFireError::SerializationError.into()); return Err(FabFireError::SerializationError.into());
@ -266,7 +268,7 @@ impl Authentication for FabFire {
.write_all(&data) .write_all(&data)
.map_err(|e| SessionError::Io { source: e })?; .map_err(|e| SessionError::Io { source: e })?;
Ok(State::Running) Ok(State::Running)
}, }
Err(e) => { Err(e) => {
tracing::error!("Failed to convert APDUCommand to Vec<u8>: {:?}", e); tracing::error!("Failed to convert APDUCommand to Vec<u8>: {:?}", e);
return Err(FabFireError::SerializationError.into()); return Err(FabFireError::SerializationError.into());
@ -327,7 +329,7 @@ impl Authentication for FabFire {
.write_all(&data) .write_all(&data)
.map_err(|e| SessionError::Io { source: e })?; .map_err(|e| SessionError::Io { source: e })?;
Ok(State::Running) Ok(State::Running)
}, }
Err(e) => { Err(e) => {
tracing::error!("Failed to convert APDUCommand to Vec<u8>: {:?}", e); tracing::error!("Failed to convert APDUCommand to Vec<u8>: {:?}", e);
return Err(FabFireError::SerializationError.into()); return Err(FabFireError::SerializationError.into());
@ -351,11 +353,19 @@ impl Authentication for FabFire {
Ok(_) => { Ok(_) => {
match apdu_response.body { match apdu_response.body {
Some(data) => { Some(data) => {
let token = String::from_utf8(data).unwrap(); let authid = String::from_utf8(data).unwrap();
let prov = let prov = ThisProvider::<AuthId>::with(
ThisProvider::<AuthId>::with(token.trim_matches(char::from(0))); authid.trim_matches(char::from(0)),
let key = session.need_with::<FabFireCardKey, _, _>(&prov, |key| Ok(Box::from(key.as_slice())))?; );
self.key_info = Some(KeyInfo { key_id: 0x01, key }); let key = session
.need_with::<FabFireCardKey, _, _>(&prov, |key| {
Ok(Box::from(key.as_slice()))
})?;
self.key_info = Some(KeyInfo {
authid,
key_id: 0x01,
key,
});
} }
None => { None => {
tracing::error!("No data in response"); tracing::error!("No data in response");
@ -380,7 +390,7 @@ impl Authentication for FabFire {
.write_all(&data) .write_all(&data)
.map_err(|e| SessionError::Io { source: e })?; .map_err(|e| SessionError::Io { source: e })?;
Ok(State::Running) Ok(State::Running)
}, }
Err(e) => { Err(e) => {
tracing::error!("Failed to convert to Vec<u8>: {:?}", e); tracing::error!("Failed to convert to Vec<u8>: {:?}", e);
return Err(FabFireError::SerializationError.into()); return Err(FabFireError::SerializationError.into());
@ -429,7 +439,7 @@ impl Authentication for FabFire {
.write_all(&data) .write_all(&data)
.map_err(|e| SessionError::Io { source: e })?; .map_err(|e| SessionError::Io { source: e })?;
Ok(State::Running) Ok(State::Running)
}, }
Err(e) => { Err(e) => {
tracing::error!("Failed to convert to Vec<u8>: {:?}", e); tracing::error!("Failed to convert to Vec<u8>: {:?}", e);
return Err(FabFireError::SerializationError.into()); return Err(FabFireError::SerializationError.into());
@ -446,7 +456,7 @@ impl Authentication for FabFire {
tracing::error!("Failed to check response: {:?}", e); tracing::error!("Failed to check response: {:?}", e);
Err(FabFireError::ParseError.into()) Err(FabFireError::ParseError.into())
} }
} };
} }
Step::Authenticate2 => { Step::Authenticate2 => {
// println!("Step: Authenticate2"); // println!("Step: Authenticate2");
@ -474,9 +484,25 @@ impl Authentication for FabFire {
) )
.is_ok() .is_ok()
{ {
struct Prov<'a> {
authid: &'a str,
}
impl<'a> Provider<'a> for Prov<'a> {
fn provide(
&self,
req: &mut Demand<'a>,
) -> DemandReply<()>
{
req.provide_ref::<AuthId>(self.authid)?.done()
}
}
let prov = Prov {
authid: &self.key_info.as_ref().unwrap().authid,
};
session.validate(&prov)?;
return Ok(State::Finished(MessageSent::Yes)); return Ok(State::Finished(MessageSent::Yes));
} }
}, }
}, },
None => { None => {
tracing::error!("got empty response"); tracing::error!("got empty response");

View File

@ -1,11 +1,11 @@
use crate::users::Users; use crate::users::Users;
use miette::{IntoDiagnostic, WrapErr}; use miette::{IntoDiagnostic, WrapErr};
use std::sync::Arc; use rsasl::callback::{CallbackError, Context, Request, SessionCallback, SessionData};
use rsasl::callback::{CallbackError, Request, SessionCallback, SessionData, Context};
use rsasl::mechanism::SessionError; use rsasl::mechanism::SessionError;
use rsasl::prelude::{Mechname, SASLConfig, SASLServer, Session, Validation}; use rsasl::prelude::{Mechname, SASLConfig, SASLServer, Session, Validation};
use rsasl::property::{AuthId, AuthzId, Password}; use rsasl::property::{AuthId, AuthzId, Password};
use rsasl::validate::{Validate, ValidationError}; use rsasl::validate::{Validate, ValidationError};
use std::sync::Arc;
use crate::authentication::fabfire::FabFireCardKey; use crate::authentication::fabfire::FabFireCardKey;
use crate::users::db::User; use crate::users::db::User;
@ -24,30 +24,46 @@ impl Callback {
} }
} }
impl SessionCallback for Callback { impl SessionCallback for Callback {
fn callback(&self, session_data: &SessionData, context: &Context, request: &mut Request) -> Result<(), SessionError> { fn callback(
&self,
session_data: &SessionData,
context: &Context,
request: &mut Request,
) -> Result<(), SessionError> {
if let Some(authid) = context.get_ref::<AuthId>() { if let Some(authid) = context.get_ref::<AuthId>() {
request.satisfy_with::<FabFireCardKey, _>(|| { request.satisfy_with::<FabFireCardKey, _>(|| {
let user = self.users.get_user(authid).ok_or(CallbackError::NoValue)?; let user = self.users.get_user(authid).ok_or(CallbackError::NoValue)?;
let kv = user.userdata.kv.get("cardkey").ok_or(CallbackError::NoValue)?; let kv = user
let card_key = <[u8; 16]>::try_from( .userdata
hex::decode(kv).map_err(|_| CallbackError::NoValue)?, .kv
).map_err(|_| CallbackError::NoValue)?; .get("cardkey")
.ok_or(CallbackError::NoValue)?;
let card_key =
<[u8; 16]>::try_from(hex::decode(kv).map_err(|_| CallbackError::NoValue)?)
.map_err(|_| CallbackError::NoValue)?;
Ok(card_key) Ok(card_key)
})?; })?;
} }
Ok(()) Ok(())
} }
fn validate(&self, session_data: &SessionData, context: &Context, validate: &mut Validate<'_>) -> Result<(), ValidationError> { fn validate(
&self,
session_data: &SessionData,
context: &Context,
validate: &mut Validate<'_>,
) -> Result<(), ValidationError> {
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();
if validate.is::<V>() { if validate.is::<V>() {
match session_data.mechanism().mechanism.as_str() { match session_data.mechanism().mechanism.as_str() {
"PLAIN" => { "PLAIN" => {
let authcid = context.get_ref::<AuthId>() let authcid = context
.get_ref::<AuthId>()
.ok_or(ValidationError::MissingRequiredProperty)?; .ok_or(ValidationError::MissingRequiredProperty)?;
let authzid = context.get_ref::<AuthzId>(); let authzid = context.get_ref::<AuthzId>();
let password = context.get_ref::<Password>() let password = context
.get_ref::<Password>()
.ok_or(ValidationError::MissingRequiredProperty)?; .ok_or(ValidationError::MissingRequiredProperty)?;
// if authzid.is_some() { // if authzid.is_some() {
@ -56,9 +72,7 @@ impl SessionCallback for Callback {
if let Some(user) = self.users.get_user(authcid) { if let Some(user) = self.users.get_user(authcid) {
match user.check_password(password) { match user.check_password(password) {
Ok(true) => { Ok(true) => validate.finalize::<V>(user),
validate.finalize::<V>(user)
}
Ok(false) => { Ok(false) => {
tracing::warn!(authid=%authcid, "AUTH FAILED: bad password"); tracing::warn!(authid=%authcid, "AUTH FAILED: bad password");
} }
@ -70,6 +84,14 @@ impl SessionCallback for Callback {
tracing::warn!(authid=%authcid, "AUTH FAILED: no such user"); tracing::warn!(authid=%authcid, "AUTH FAILED: no such user");
} }
} }
"X-FABFIRE" | "X-FABFIRE-BIN" => {
let authcid = context
.get_ref::<AuthId>()
.ok_or(ValidationError::MissingRequiredProperty)?;
if let Some(user) = self.users.get_user(authcid) {
validate.finalize::<V>(user)
}
}
_ => {} _ => {}
} }
} }

View File

@ -2,21 +2,21 @@ use capnp::capability::Promise;
use capnp::Error; use capnp::Error;
use capnp_rpc::pry; use capnp_rpc::pry;
use rsasl::mechname::Mechname; use rsasl::mechname::Mechname;
use rsasl::prelude::State as SaslState;
use rsasl::prelude::{MessageSent, Session};
use rsasl::property::AuthId; use rsasl::property::AuthId;
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::authentication::V;
use crate::capnp::session::APISession; use crate::capnp::session::APISession;
use crate::session::SessionManager; use crate::session::SessionManager;
use api::authenticationsystem_capnp::authentication::{ 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";

View File

@ -1,5 +1,6 @@
use super::Initiator; use super::Initiator;
use super::InitiatorCallbacks; use super::InitiatorCallbacks;
use crate::resources::modules::fabaccess::Status;
use crate::resources::state::State; use crate::resources::state::State;
use crate::utils::linebuffer::LineBuffer; use crate::utils::linebuffer::LineBuffer;
use async_process::{Child, ChildStderr, ChildStdout, Command, Stdio}; use async_process::{Child, ChildStderr, ChildStdout, Command, Stdio};
@ -11,7 +12,6 @@ use std::future::Future;
use std::io; use std::io;
use std::pin::Pin; use std::pin::Pin;
use std::task::{Context, Poll}; use std::task::{Context, Poll};
use crate::resources::modules::fabaccess::Status;
#[derive(Debug, Serialize, Deserialize)] #[derive(Debug, Serialize, Deserialize)]
pub enum InputMessage { pub enum InputMessage {
@ -63,7 +63,12 @@ struct ProcessState {
impl ProcessState { impl ProcessState {
pub fn new(stdout: ChildStdout, stderr: ChildStderr, child: Child) -> Self { pub fn new(stdout: ChildStdout, stderr: ChildStderr, child: Child) -> Self {
Self { stdout, stderr, stderr_closed: false, child } Self {
stdout,
stderr,
stderr_closed: false,
child,
}
} }
fn try_process(&mut self, buffer: &[u8], callbacks: &mut InitiatorCallbacks) -> usize { fn try_process(&mut self, buffer: &[u8], callbacks: &mut InitiatorCallbacks) -> usize {
@ -100,7 +105,9 @@ impl ProcessState {
let InputMessage::SetState(status) = state; let InputMessage::SetState(status) = state;
callbacks.set_status(status); callbacks.set_status(status);
} }
Err(error) => tracing::warn!(%error, "process initiator did not send a valid line"), Err(error) => {
tracing::warn!(%error, "process initiator did not send a valid line")
}
} }
} }
} }

View File

@ -1,10 +1,10 @@
use crate::authorization::permissions::Permission; use crate::authorization::permissions::Permission;
use crate::authorization::roles::Roles; use crate::authorization::roles::Roles;
use crate::resources::Resource; use crate::resources::Resource;
use crate::users::db::User;
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 {
@ -18,7 +18,9 @@ impl SessionManager {
} }
pub fn try_open(&self, parent: &Span, uid: impl AsRef<str>) -> Option<SessionHandle> { 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)) self.users
.get_user(uid.as_ref())
.map(|user| self.open(parent, user))
} }
// TODO: make infallible // TODO: make infallible