fabaccess-bffh/bffhd/capnp/authenticationsystem.rs
Nadja Reitzenstein c0b311e14c Cargo fix
2022-03-15 20:00:43 +01:00

104 lines
3.3 KiB
Rust

use capnp::capability::Promise;
use capnp::Error;
use capnp_rpc::pry;
use rsasl::property::AuthId;
use rsasl::session::{Session, Step};
use std::io::Cursor;
use crate::capnp::session::APISession;
use crate::session::SessionManager;
use api::authenticationsystem_capnp::authentication::{
AbortParams, AbortResults, Server as AuthenticationSystem, StepParams, StepResults,
};
use api::authenticationsystem_capnp::{response, response::Error as ErrorCode};
pub struct Authentication {
state: State,
}
impl Authentication {
pub fn new(session: Session, sessionmanager: SessionManager) -> Self {
Self {
state: State::Running(session, sessionmanager),
}
}
pub fn invalid_mechanism() -> Self {
Self {
state: State::InvalidMechanism,
}
}
fn build_error(&self, response: response::Builder) {
if let State::Running(_, _) = self.state {
return;
}
let mut builder = response.init_failed();
match self.state {
State::InvalidMechanism => builder.set_code(ErrorCode::BadMechanism),
State::Finished => builder.set_code(ErrorCode::Aborted),
State::Aborted => builder.set_code(ErrorCode::Aborted),
_ => unreachable!(),
}
}
}
enum State {
InvalidMechanism,
Finished,
Aborted,
Running(Session, SessionManager),
}
impl AuthenticationSystem for Authentication {
fn step(&mut self, params: StepParams, mut results: StepResults) -> Promise<(), Error> {
let span = tracing::trace_span!("step");
let _guard = span.enter();
let mut builder = results.get();
if let State::Running(mut session, manager) =
std::mem::replace(&mut self.state, State::Aborted)
{
let data: &[u8] = pry!(pry!(params.get()).get_data());
let mut out = Cursor::new(Vec::new());
match session.step(Some(data), &mut out) {
Ok(Step::Done(data)) => {
self.state = State::Finished;
let uid = pry!(session.get_property::<AuthId>().ok_or(capnp::Error::failed(
"Authentication didn't provide an authid as required".to_string()
)));
let session = pry!(manager.open(uid.as_ref()).ok_or(capnp::Error::failed(
"Failed to lookup the given user".to_string()
)));
let mut builder = builder.init_successful();
if data.is_some() {
builder.set_additional_data(out.into_inner().as_slice());
}
APISession::build(session, builder)
}
Ok(Step::NeedsMore(_)) => {
self.state = State::Running(session, manager);
builder.set_challenge(out.into_inner().as_slice());
}
Err(_) => {
self.state = State::Aborted;
self.build_error(builder);
}
}
} else {
self.build_error(builder);
}
Promise::ok(())
}
fn abort(&mut self, _: AbortParams, _: AbortResults) -> Promise<(), Error> {
self.state = State::Aborted;
Promise::ok(())
}
}