mirror of
https://gitlab.com/fabinfra/fabaccess/bffh.git
synced 2024-12-22 11:43:49 +01:00
Implement more API
This commit is contained in:
parent
ee57c2b275
commit
87af5fde94
4
Cargo.lock
generated
4
Cargo.lock
generated
@ -1885,9 +1885,7 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "rsasl"
|
||||
version = "2.0.0-preview2"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "2adcc7fb89ad42cf35d527905a11232c02fa030f7b6983b8c9880c385da2ae8e"
|
||||
version = "2.0.0-preview3"
|
||||
dependencies = [
|
||||
"base64",
|
||||
"digest 0.10.3",
|
||||
|
@ -69,7 +69,8 @@ capnp = "0.14"
|
||||
capnp-rpc = "0.14.1"
|
||||
|
||||
# API Authentication
|
||||
rsasl = "2.0.0-preview2"
|
||||
#rsasl = "2.0.0-preview3"
|
||||
rsasl = { path = "../../rsasl" }
|
||||
|
||||
futures-signals = "0.3.22"
|
||||
async-oneshot = "0.5"
|
||||
|
@ -16,16 +16,21 @@ impl Inner {
|
||||
}
|
||||
|
||||
#[derive(Clone)]
|
||||
pub struct AuthenticationHandler {
|
||||
pub struct AuthenticationHandle {
|
||||
inner: Arc<Inner>,
|
||||
}
|
||||
|
||||
impl AuthenticationHandler {
|
||||
pub fn new(rsasl: SASL) -> Self {
|
||||
impl AuthenticationHandle {
|
||||
pub fn new() -> Self {
|
||||
let rsasl = SASL::new();
|
||||
Self { inner: Arc::new(Inner::new(rsasl)) }
|
||||
}
|
||||
|
||||
pub fn start(&self, mechanism: &Mechname) -> Result<Session, SASLError> {
|
||||
self.inner.rsasl.server_start(mechanism)
|
||||
pub fn start(&self, mechanism: &Mechname) -> anyhow::Result<Session> {
|
||||
Ok(self.inner.rsasl.server_start(mechanism)?)
|
||||
}
|
||||
|
||||
pub fn list_available_mechs(&self) -> impl IntoIterator<Item=&Mechname> {
|
||||
self.inner.rsasl.server_mech_list().into_iter().map(|m| m.mechanism)
|
||||
}
|
||||
}
|
@ -1,3 +1,37 @@
|
||||
use std::sync::Arc;
|
||||
use crate::authorization::permissions::Permission;
|
||||
use crate::authorization::roles::Role;
|
||||
use crate::users::User;
|
||||
|
||||
pub mod permissions;
|
||||
pub mod roles;
|
||||
pub mod roles;
|
||||
|
||||
struct Inner {
|
||||
|
||||
}
|
||||
impl Inner {
|
||||
pub fn new() -> Self {
|
||||
Self {}
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Clone)]
|
||||
pub struct AuthorizationHandle {
|
||||
inner: Arc<Inner>,
|
||||
}
|
||||
|
||||
impl AuthorizationHandle {
|
||||
pub fn new() -> Self {
|
||||
Self {
|
||||
inner: Arc::new(Inner::new())
|
||||
}
|
||||
}
|
||||
|
||||
pub fn lookup_user(&self, uid: impl AsRef<str>) -> Option<User> {
|
||||
unimplemented!()
|
||||
}
|
||||
|
||||
pub fn is_permitted<'a>(&self, roles: impl IntoIterator<Item=&'a Role>, perm: impl AsRef<Permission>) -> bool {
|
||||
unimplemented!()
|
||||
}
|
||||
}
|
@ -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(())
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -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(())
|
||||
}
|
||||
}
|
||||
|
@ -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(
|
||||
|
@ -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(),
|
||||
))
|
||||
}
|
||||
}
|
||||
|
@ -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);
|
||||
|
@ -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 {
|
||||
|
||||
}
|
@ -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)));
|
||||
}
|
||||
}
|
@ -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 {
|
||||
|
||||
|
@ -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,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
11
bffhd/lib.rs
11
bffhd/lib.rs
@ -37,6 +37,7 @@ mod tls;
|
||||
mod keylog;
|
||||
mod logging;
|
||||
mod audit;
|
||||
mod session;
|
||||
|
||||
use std::fs::File;
|
||||
use std::io::BufReader;
|
||||
@ -49,10 +50,14 @@ use rustls::{Certificate, KeyLogFile, PrivateKey, ServerConfig};
|
||||
use rustls::server::NoClientAuth;
|
||||
use signal_hook::consts::signal::*;
|
||||
use executor::pool::Executor;
|
||||
use crate::authentication::AuthenticationHandle;
|
||||
use crate::capnp::APIServer;
|
||||
use crate::config::{Config, TlsListen};
|
||||
use crate::session::SessionManager;
|
||||
use crate::tls::TlsConfig;
|
||||
|
||||
pub const RELEASE_STRING: &'static str = env!("BFFHD_RELEASE_STRING");
|
||||
|
||||
pub struct Diflouroborane {
|
||||
executor: Executor<'static>,
|
||||
}
|
||||
@ -65,7 +70,6 @@ impl Diflouroborane {
|
||||
}
|
||||
|
||||
fn log_version_number(&self) {
|
||||
const RELEASE_STRING: &'static str = env!("BFFHD_RELEASE_STRING");
|
||||
tracing::info!(version=RELEASE_STRING, "Starting");
|
||||
}
|
||||
|
||||
@ -86,7 +90,10 @@ impl Diflouroborane {
|
||||
let tlsconfig = TlsConfig::new(config.tlskeylog.as_ref(), !config.is_quiet())?;
|
||||
let acceptor = tlsconfig.make_tls_acceptor(&config.tlsconfig)?;
|
||||
|
||||
let mut apiserver = self.executor.run(APIServer::bind(self.executor.clone(), &config.listens, acceptor))?;
|
||||
let sessionmanager = SessionManager::new();
|
||||
let authentication = AuthenticationHandle::new();
|
||||
|
||||
let mut apiserver = self.executor.run(APIServer::bind(self.executor.clone(), &config.listens, acceptor, sessionmanager, authentication))?;
|
||||
|
||||
let (mut tx, rx) = async_oneshot::oneshot();
|
||||
|
||||
|
32
bffhd/session/mod.rs
Normal file
32
bffhd/session/mod.rs
Normal file
@ -0,0 +1,32 @@
|
||||
use std::sync::Arc;
|
||||
|
||||
struct Inner {
|
||||
|
||||
}
|
||||
impl Inner {
|
||||
pub fn new() -> Self {
|
||||
Self { }
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Clone)]
|
||||
pub struct SessionManager {
|
||||
inner: Arc<Inner>,
|
||||
}
|
||||
impl SessionManager {
|
||||
pub fn new() -> Self {
|
||||
Self {
|
||||
inner: Arc::new(Inner::new()),
|
||||
}
|
||||
}
|
||||
pub fn open(&self, uid: impl AsRef<str>) -> Option<SessionHandle> {
|
||||
unimplemented!()
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Clone, Debug)]
|
||||
pub struct SessionHandle {
|
||||
}
|
||||
|
||||
impl SessionHandle {
|
||||
}
|
Loading…
Reference in New Issue
Block a user