mirror of
https://gitlab.com/fabinfra/fabaccess/bffh.git
synced 2024-12-25 13:13:48 +01:00
Port rsasl
This commit is contained in:
parent
ec1cac9443
commit
3cf152a164
768
Cargo.lock
generated
768
Cargo.lock
generated
File diff suppressed because it is too large
Load Diff
@ -113,7 +113,7 @@ shadow-rs = "0.11"
|
||||
|
||||
[dependencies.rsasl]
|
||||
git = "https://github.com/dequbed/rsasl.git"
|
||||
rev = "0b5012d0"
|
||||
branch = "development"
|
||||
default_features = false
|
||||
features = ["unstable_custom_mechanism", "provider", "registry_static", "plain"]
|
||||
|
||||
|
@ -2,43 +2,23 @@ mod server;
|
||||
pub use server::FabFire;
|
||||
|
||||
use rsasl::mechname::Mechname;
|
||||
use rsasl::registry::{Mechanism, MECHANISMS};
|
||||
use rsasl::session::Side;
|
||||
use rsasl::registry::{Mechanism, MECHANISMS, Side};
|
||||
|
||||
const MECHNAME: &'static Mechname = &Mechname::const_new_unchecked(b"X-FABFIRE");
|
||||
|
||||
#[linkme::distributed_slice(MECHANISMS)]
|
||||
pub static FABFIRE: Mechanism = Mechanism {
|
||||
mechanism: MECHNAME,
|
||||
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,
|
||||
};
|
||||
pub static FABFIRE: Mechanism =
|
||||
Mechanism::build(MECHNAME, 300, None, Some(FabFire::new_server), Side::Client);
|
||||
|
||||
use rsasl::property::{Property, PropertyDefinition, PropertyQ};
|
||||
use std::marker::PhantomData;
|
||||
use rsasl::property::SizedProperty;
|
||||
|
||||
// All Property types must implement Debug.
|
||||
#[derive(Debug)]
|
||||
// The `PhantomData` in the constructor is only used so external crates can't construct this type.
|
||||
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
|
||||
// so choose
|
||||
type Item = [u8; 16];
|
||||
// You need to return the constant you define below here for things to work properly
|
||||
fn property() -> Property {
|
||||
FABFIRECARDKEY
|
||||
}
|
||||
|
||||
impl SizedProperty<'_> for FabFireCardKey {
|
||||
type Value = [u8; 16];
|
||||
const DESCRIPTION: &'static str = "A AES128 key for a FabFire card";
|
||||
}
|
||||
// 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",
|
||||
));
|
||||
|
@ -2,11 +2,10 @@ use desfire::desfire::desfire::MAX_BYTES_PER_TRANSACTION;
|
||||
use desfire::desfire::Desfire;
|
||||
use desfire::error::Error as DesfireError;
|
||||
use desfire::iso7816_4::apduresponse::APDUResponse;
|
||||
use rsasl::error::{MechanismError, MechanismErrorKind, SASLError, SessionError};
|
||||
use rsasl::mechanism::Authentication;
|
||||
use rsasl::callback::SessionData;
|
||||
use rsasl::mechanism::{Authentication, MechanismError, MechanismErrorKind, State, ThisProvider};
|
||||
use rsasl::prelude::{MessageSent, SASLConfig, SASLError, SessionError};
|
||||
use rsasl::property::AuthId;
|
||||
use rsasl::session::{SessionData, StepResult};
|
||||
use rsasl::SASL;
|
||||
use serde::{Deserialize, Serialize};
|
||||
use std::convert::TryFrom;
|
||||
use std::fmt::{Debug, Display, Formatter};
|
||||
@ -63,6 +62,10 @@ impl Display for FabFireError {
|
||||
}
|
||||
}
|
||||
|
||||
impl std::error::Error for FabFireError {
|
||||
|
||||
}
|
||||
|
||||
impl MechanismError for FabFireError {
|
||||
fn kind(&self) -> MechanismErrorKind {
|
||||
match self {
|
||||
@ -154,7 +157,7 @@ pub struct FabFire {
|
||||
const MAGIC: &'static str = "FABACCESS\0DESFIRE\01.0\0";
|
||||
|
||||
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 {
|
||||
step: Step::New,
|
||||
card_info: None,
|
||||
@ -177,7 +180,7 @@ impl Authentication for FabFire {
|
||||
session: &mut SessionData,
|
||||
input: Option<&[u8]>,
|
||||
writer: &mut dyn Write,
|
||||
) -> StepResult {
|
||||
) -> Result<State, SessionError> {
|
||||
match self.step {
|
||||
Step::New => {
|
||||
tracing::trace!("Step: New");
|
||||
@ -216,7 +219,7 @@ impl Authentication for FabFire {
|
||||
writer
|
||||
.write_all(&send_buf)
|
||||
.map_err(|e| SessionError::Io { source: e })?;
|
||||
Ok(rsasl::session::Step::NeedsMore(Some(send_buf.len())))
|
||||
Ok(State::Running)
|
||||
}
|
||||
Err(e) => {
|
||||
tracing::error!("Failed to serialize APDUCommand: {:?}", e);
|
||||
@ -282,7 +285,7 @@ impl Authentication for FabFire {
|
||||
writer
|
||||
.write_all(&send_buf)
|
||||
.map_err(|e| SessionError::Io { source: e })?;
|
||||
Ok(rsasl::session::Step::NeedsMore(Some(send_buf.len())))
|
||||
Ok(State::Running)
|
||||
}
|
||||
Err(e) => {
|
||||
tracing::error!("Failed to serialize APDUCommand: {:?}", e);
|
||||
@ -365,7 +368,7 @@ impl Authentication for FabFire {
|
||||
writer
|
||||
.write_all(&send_buf)
|
||||
.map_err(|e| SessionError::Io { source: e })?;
|
||||
Ok(rsasl::session::Step::NeedsMore(Some(send_buf.len())))
|
||||
Ok(State::Running)
|
||||
}
|
||||
Err(e) => {
|
||||
tracing::error!("Failed to serialize APDUCommand: {:?}", e);
|
||||
@ -452,7 +455,7 @@ impl Authentication for FabFire {
|
||||
writer
|
||||
.write_all(&send_buf)
|
||||
.map_err(|e| SessionError::Io { source: e })?;
|
||||
Ok(rsasl::session::Step::NeedsMore(Some(send_buf.len())))
|
||||
Ok(State::Running)
|
||||
}
|
||||
Err(e) => {
|
||||
tracing::error!("Failed to serialize APDUCommand: {:?}", e);
|
||||
@ -491,24 +494,9 @@ impl Authentication for FabFire {
|
||||
match apdu_response.body {
|
||||
Some(data) => {
|
||||
let token = String::from_utf8(data).unwrap();
|
||||
session.set_property::<AuthId>(Arc::new(
|
||||
token.trim_matches(char::from(0)).to_string(),
|
||||
));
|
||||
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());
|
||||
}
|
||||
};
|
||||
let prov =
|
||||
ThisProvider::<AuthId>::with(token.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 });
|
||||
}
|
||||
None => {
|
||||
@ -546,7 +534,7 @@ impl Authentication for FabFire {
|
||||
writer
|
||||
.write_all(&send_buf)
|
||||
.map_err(|e| SessionError::Io { source: e })?;
|
||||
Ok(rsasl::session::Step::NeedsMore(Some(send_buf.len())))
|
||||
Ok(State::Running)
|
||||
}
|
||||
Err(e) => {
|
||||
tracing::error!("Failed to serialize command: {:?}", e);
|
||||
@ -616,7 +604,7 @@ impl Authentication for FabFire {
|
||||
writer
|
||||
.write_all(&send_buf)
|
||||
.map_err(|e| SessionError::Io { source: e })?;
|
||||
Ok(rsasl::session::Step::NeedsMore(Some(send_buf.len())))
|
||||
Ok(State::Running)
|
||||
}
|
||||
Err(e) => {
|
||||
tracing::error!("Failed to serialize command: {:?}", e);
|
||||
@ -691,9 +679,7 @@ impl Authentication for FabFire {
|
||||
writer
|
||||
.write_all(&send_buf)
|
||||
.map_err(|e| SessionError::Io { source: e })?;
|
||||
return Ok(rsasl::session::Step::Done(Some(
|
||||
send_buf.len(),
|
||||
)));
|
||||
return Ok(State::Finished(MessageSent::Yes));
|
||||
}
|
||||
Err(e) => {
|
||||
tracing::error!(
|
||||
@ -722,6 +708,6 @@ impl Authentication for FabFire {
|
||||
}
|
||||
}
|
||||
|
||||
return Ok(rsasl::session::Step::Done(None));
|
||||
return Ok(State::Finished(MessageSent::No));
|
||||
}
|
||||
}
|
||||
|
@ -1,12 +1,10 @@
|
||||
use crate::users::Users;
|
||||
use miette::{Context, IntoDiagnostic};
|
||||
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::callback::{CallbackError, Request, SessionCallback, SessionData};
|
||||
use rsasl::mechanism::SessionError;
|
||||
use rsasl::prelude::{Mechname, SASLConfig, SASLServer, Session};
|
||||
use rsasl::property::AuthId;
|
||||
|
||||
use crate::authentication::fabfire::FabFireCardKey;
|
||||
|
||||
@ -22,36 +20,22 @@ impl Callback {
|
||||
Self { users, span }
|
||||
}
|
||||
}
|
||||
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>()?;
|
||||
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)?;
|
||||
impl SessionCallback for Callback {
|
||||
fn callback(&self, session_data: &SessionData, context: &rsasl::callback::Context, request: &mut Request) -> Result<(), SessionError> {
|
||||
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(|_| SessionError::AuthenticationFailure)?,
|
||||
)
|
||||
.map_err(|_| SessionError::AuthenticationFailure)?;
|
||||
session.set_property::<FabFireCardKey>(Arc::new(card_key));
|
||||
Ok(())
|
||||
}
|
||||
_ => Err(SessionError::NoProperty { property }),
|
||||
hex::decode(kv).map_err(|_| CallbackError::NoValue)?,
|
||||
).map_err(|_| CallbackError::NoValue)?;
|
||||
Ok(card_key)
|
||||
})?;
|
||||
}
|
||||
Ok(())
|
||||
}
|
||||
|
||||
fn validate(
|
||||
/*fn validate(
|
||||
&self,
|
||||
session: &mut SessionData,
|
||||
validation: Validation,
|
||||
@ -90,21 +74,21 @@ impl rsasl::callback::Callback for Callback {
|
||||
Err(SessionError::no_validate(validation))
|
||||
}
|
||||
}
|
||||
}
|
||||
}*/
|
||||
}
|
||||
|
||||
struct Inner {
|
||||
rsasl: SASL,
|
||||
rsasl: Arc<SASLConfig>,
|
||||
}
|
||||
impl Inner {
|
||||
pub fn new(rsasl: SASL) -> Self {
|
||||
pub fn new(rsasl: Arc<SASLConfig>) -> Self {
|
||||
Self { rsasl }
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Clone)]
|
||||
pub struct AuthenticationHandle {
|
||||
inner: Arc<Inner>,
|
||||
inner: Inner,
|
||||
}
|
||||
|
||||
impl AuthenticationHandle {
|
||||
@ -112,11 +96,13 @@ impl AuthenticationHandle {
|
||||
let span = tracing::debug_span!("authentication");
|
||||
let _guard = span.enter();
|
||||
|
||||
let mut rsasl = SASL::new();
|
||||
rsasl.install_callback(Arc::new(Callback::new(userdb)));
|
||||
let config = SASLConfig::builder()
|
||||
.with_defaults()
|
||||
.with_callback(Callback::new(userdb))
|
||||
.unwrap();
|
||||
|
||||
let mechs: Vec<&'static str> = rsasl
|
||||
.server_mech_list()
|
||||
let mechs: Vec<&'static str> = SASLServer::new(config.clone())
|
||||
.get_available()
|
||||
.into_iter()
|
||||
.map(|m| m.mechanism.as_str())
|
||||
.collect();
|
||||
@ -124,23 +110,20 @@ impl AuthenticationHandle {
|
||||
tracing::debug!(?mechs, "available mechs");
|
||||
|
||||
Self {
|
||||
inner: Arc::new(Inner::new(rsasl)),
|
||||
inner: Inner::new(config),
|
||||
}
|
||||
}
|
||||
|
||||
pub fn start(&self, mechanism: &Mechname) -> miette::Result<Session> {
|
||||
Ok(self
|
||||
.inner
|
||||
.rsasl
|
||||
.server_start(mechanism)
|
||||
Ok(SASLServer::new(self.inner.rsasl.clone())
|
||||
.start_suggested(mechanism)
|
||||
.into_diagnostic()
|
||||
.wrap_err("Failed to start a SASL authentication with the given mechanism")?)
|
||||
}
|
||||
|
||||
pub fn list_available_mechs(&self) -> impl IntoIterator<Item = &Mechname> {
|
||||
self.inner
|
||||
.rsasl
|
||||
.server_mech_list()
|
||||
SASLServer::new(self.inner.rsasl.clone())
|
||||
.get_available()
|
||||
.into_iter()
|
||||
.map(|m| m.mechanism)
|
||||
}
|
||||
|
@ -3,10 +3,11 @@ use capnp::Error;
|
||||
use capnp_rpc::pry;
|
||||
use rsasl::mechname::Mechname;
|
||||
use rsasl::property::AuthId;
|
||||
use rsasl::session::{Session, Step};
|
||||
use std::fmt;
|
||||
use std::fmt::{Formatter, Write};
|
||||
use std::io::Cursor;
|
||||
use rsasl::prelude::{MessageSent, Session};
|
||||
use rsasl::prelude::State as SaslState;
|
||||
use tracing::Span;
|
||||
|
||||
use crate::capnp::session::APISession;
|
||||
@ -123,7 +124,7 @@ impl AuthenticationSystem for Authentication {
|
||||
|
||||
let mut out = Cursor::new(Vec::new());
|
||||
match session.step(Some(data), &mut out) {
|
||||
Ok(Step::Done(data)) => {
|
||||
Ok(SaslState::Finished(sent)) => {
|
||||
self.state = State::Finished;
|
||||
|
||||
let uid = pry!(session.get_property::<AuthId>().ok_or_else(|| {
|
||||
@ -142,13 +143,13 @@ impl AuthenticationSystem for Authentication {
|
||||
};
|
||||
|
||||
let mut builder = builder.init_successful();
|
||||
if data.is_some() {
|
||||
if sent == MessageSent::Yes {
|
||||
builder.set_additional_data(out.into_inner().as_slice());
|
||||
}
|
||||
|
||||
APISession::build(session, builder)
|
||||
}
|
||||
Ok(Step::NeedsMore(_)) => {
|
||||
Ok(SaslState::Running) => {
|
||||
self.state = State::Running(session, manager);
|
||||
builder.set_challenge(out.into_inner().as_slice());
|
||||
|
||||
|
Loading…
Reference in New Issue
Block a user