Implement more API

This commit is contained in:
Nadja Reitzenstein
2022-03-12 17:31:53 +01:00
parent ee57c2b275
commit 87af5fde94
15 changed files with 341 additions and 52 deletions

View File

@ -1,33 +1,101 @@
use std::io::Cursor;
use capnp::capability::Promise;
use capnp::Error;
use capnp_rpc::pry;
use rsasl::session::{Session, Step};
use rsasl::property::AuthId;
use rsasl::session::{Session, Step, StepResult};
use std::io::Cursor;
use crate::authorization::AuthorizationHandle;
use crate::capnp::session::APISession;
use crate::session::SessionManager;
use api::authenticationsystem_capnp::authentication::{
Server as AuthenticationSystem,
StepParams, StepResults,
AbortParams, AbortResults,
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)
Running(Session, SessionManager),
}
impl AuthenticationSystem for Authentication {
fn step(&mut self, params: StepParams, mut results: StepResults) -> Promise<(), Error> {
unimplemented!();
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(())
}
}
}

View File

@ -1,15 +1,88 @@
use api::connection_capnp::bootstrap::Server as Bootstrap;
pub use api::connection_capnp::bootstrap::Client;
use api::connection_capnp::bootstrap;
use capnp::capability::Promise;
use capnp_rpc::pry;
use rsasl::mechname::Mechname;
use crate::authentication::AuthenticationHandle;
use crate::capnp::authenticationsystem::Authentication;
use crate::session::SessionManager;
#[derive(Debug)]
/// Cap'n Proto API Handler
pub struct BootCap;
pub struct BootCap {
authentication: AuthenticationHandle,
sessionmanager: SessionManager,
}
impl BootCap {
pub fn new() -> Self {
Self
pub fn new(authentication: AuthenticationHandle, sessionmanager: SessionManager) -> Self {
Self {
authentication,
sessionmanager,
}
}
}
impl Bootstrap for BootCap {
}
impl bootstrap::Server for BootCap {
fn get_a_p_i_version(
&mut self,
_: bootstrap::GetAPIVersionParams,
_: bootstrap::GetAPIVersionResults,
) -> Promise<(), ::capnp::Error> {
Promise::ok(())
}
fn get_server_release(
&mut self,
_: bootstrap::GetServerReleaseParams,
mut result: bootstrap::GetServerReleaseResults,
) -> Promise<(), ::capnp::Error> {
let mut builder = result.get();
builder.set_name("bffhd");
builder.set_release(crate::RELEASE_STRING);
Promise::ok(())
}
fn mechanisms(
&mut self,
_: bootstrap::MechanismsParams,
mut result: bootstrap::MechanismsResults,
) -> Promise<(), ::capnp::Error> {
let mut builder = result.get();
let mechs: Vec<_> = self.authentication.list_available_mechs()
.into_iter()
.map(|m| m.as_str())
.collect();
let mut mechbuilder = builder.init_mechs(mechs.len() as u32);
for (i,m) in mechs.iter().enumerate() {
mechbuilder.set(i as u32, m);
}
Promise::ok(())
}
fn create_session(
&mut self,
params: bootstrap::CreateSessionParams,
mut result: bootstrap::CreateSessionResults,
) -> Promise<(), ::capnp::Error> {
let params = pry!(params.get());
let mechanism: &str = pry!(params.get_mechanism());
let mechname = Mechname::new(mechanism.as_bytes());
let auth = if let Ok(mechname) = mechname {
if let Ok(session) = self.authentication.start(mechname) {
Authentication::new(session, self.sessionmanager.clone())
} else {
Authentication::invalid_mechanism()
}
} else {
Authentication::invalid_mechanism()
};
let mut builder = result.get();
builder.set_authentication(capnp_rpc::new_client(auth));
Promise::ok(())
}
}

View File

@ -6,8 +6,11 @@ use api::machine_capnp::machine::{
manage, manage::Server as ManageServer,
use_, use_::Server as UseServer,
};
use crate::session::SessionHandle;
pub struct Machine;
pub struct Machine {
session: SessionHandle,
}
impl InfoServer for Machine {
fn get_property_list(

View File

@ -1,19 +1,55 @@
use api::machinesystem_capnp::machine_system::Server as MachineSystem;
use crate::authorization::AuthorizationHandle;
use crate::session::SessionHandle;
use api::machinesystem_capnp::machine_system::{
info, InfoParams, InfoResults, Server as MachineSystem,
};
use capnp::capability::Promise;
#[derive(Debug, Clone)]
pub struct Machines {
session: SessionHandle,
}
impl Machines {
pub fn new() -> Self {
Self {
}
pub fn new(session: SessionHandle) -> Self {
Self { session }
}
}
impl MachineSystem for Machines {
fn info(&mut self, _: InfoParams, _: InfoResults) -> Promise<(), ::capnp::Error> {
Promise::err(::capnp::Error::unimplemented(
"method not implemented".to_string(),
))
}
}
}
impl info::Server for Machines {
fn get_machine_list(
&mut self,
_: info::GetMachineListParams,
_: info::GetMachineListResults,
) -> Promise<(), ::capnp::Error> {
Promise::err(::capnp::Error::unimplemented(
"method not implemented".to_string(),
))
}
fn get_machine(
&mut self,
_: info::GetMachineParams,
_: info::GetMachineResults,
) -> Promise<(), ::capnp::Error> {
Promise::err(::capnp::Error::unimplemented(
"method not implemented".to_string(),
))
}
fn get_machine_u_r_n(
&mut self,
_: info::GetMachineURNParams,
_: info::GetMachineURNResults,
) -> Promise<(), ::capnp::Error> {
Promise::err(::capnp::Error::unimplemented(
"method not implemented".to_string(),
))
}
}

View File

@ -17,8 +17,11 @@ use std::future::Future;
use std::io;
use std::io::BufReader;
use std::sync::Arc;
use crate::authentication::AuthenticationHandle;
use crate::authorization::AuthorizationHandle;
use crate::error::Result;
use crate::session::SessionManager;
mod authenticationsystem;
mod connection;
@ -33,6 +36,8 @@ pub struct APIServer {
executor: Executor<'static>,
sockets: Vec<TcpListener>,
acceptor: TlsAcceptor,
sessionmanager: SessionManager,
authentication: AuthenticationHandle,
}
impl APIServer {
@ -40,11 +45,15 @@ impl APIServer {
executor: Executor<'static>,
sockets: Vec<TcpListener>,
acceptor: TlsAcceptor,
sessionmanager: SessionManager,
authentication: AuthenticationHandle,
) -> Self {
Self {
executor,
sockets,
acceptor,
sessionmanager,
authentication,
}
}
@ -52,6 +61,8 @@ impl APIServer {
executor: Executor<'static>,
listens: impl IntoIterator<Item = &Listen>,
acceptor: TlsAcceptor,
sessionmanager: SessionManager,
authentication: AuthenticationHandle,
) -> anyhow::Result<Self> {
let span = tracing::info_span!("binding API listen sockets");
let _guard = span.enter();
@ -100,10 +111,10 @@ impl APIServer {
tracing::warn!("No usable listen addresses configured for the API server!");
}
Ok(Self::new(executor, sockets, acceptor))
Ok(Self::new(executor, sockets, acceptor, sessionmanager, authentication))
}
pub async fn handle_until(&mut self, stop: impl Future) {
pub async fn handle_until(self, stop: impl Future) {
stream::select_all(
self.sockets
.iter()
@ -132,7 +143,8 @@ impl APIServer {
};
let (rx, tx) = futures_lite::io::split(stream);
let vat = VatNetwork::new(rx, tx, Side::Server, Default::default());
let bootstrap: connection::Client = capnp_rpc::new_client(connection::BootCap::new());
let bootstrap: connection::Client = capnp_rpc::new_client(connection::BootCap::new(self.authentication.clone(), self.sessionmanager.clone()));
if let Err(e) = RpcSystem::new(Box::new(vat), Some(bootstrap.client)).await {
tracing::error!("Error during RPC handling: {}", e);

View File

@ -1,7 +1,15 @@
use api::permissionsystem_capnp::permission_system::Server as PermissionSystem;
use crate::authorization::AuthorizationHandle;
use crate::session::SessionHandle;
pub struct Permissions;
impl Permissions {
pub fn new(session: SessionHandle) -> Self {
Self
}
}
impl PermissionSystem for Permissions {
}

View File

@ -1,17 +1,24 @@
use api::authenticationsystem_capnp::response::successful::Builder;
use capnp::capability::Promise;
use crate::authorization::AuthorizationHandle;
use crate::capnp::machinesystem::Machines;
use crate::capnp::permissionsystem::Permissions;
use crate::capnp::user_system::Users;
use crate::session::{SessionHandle, SessionManager};
use crate::users::User;
#[derive(Debug, Clone)]
pub struct Session {
resources: Machines,
users: Users,
}
pub struct APISession;
impl Session {
impl APISession {
pub fn new() -> Self {
Session {
resources: Machines::new(),
users: Users::new(),
}
Self
}
pub fn build(session: SessionHandle, mut builder: Builder) {
let mut builder = builder.init_session();
builder.set_machine_system(capnp_rpc::new_client(Machines::new(session.clone())));
builder.set_user_system(capnp_rpc::new_client(Users::new(session.clone())));
builder.set_permission_system(capnp_rpc::new_client(Permissions::new(session)));
}
}

View File

@ -4,8 +4,11 @@ use api::user_capnp::user::{
manage,
admin,
};
use crate::session::SessionHandle;
struct User;
struct User {
session: SessionHandle,
}
impl info::Server for User {

View File

@ -7,16 +7,18 @@ use api::usersystem_capnp::user_system::{
info, info::Server as InfoServer,
manage, manage::Server as ManageServer,
};
use crate::authorization::AuthorizationHandle;
use crate::session::SessionHandle;
#[derive(Debug, Clone)]
pub struct Users {
session: SessionHandle,
}
impl Users {
pub fn new() -> Self {
pub fn new(session: SessionHandle) -> Self {
Self {
session,
}
}
}