mirror of
https://gitlab.com/fabinfra/fabaccess/bffh.git
synced 2024-12-22 19:53:49 +01:00
More work on the API implementation
This commit is contained in:
parent
87102b9f5d
commit
f997c93c23
@ -36,7 +36,8 @@ uuid = { version = "0.8", features = ["serde", "v4"] }
|
||||
clap = "2.33"
|
||||
|
||||
# TODO update this if bindgen breaks (again)
|
||||
rsasl = "0.2.2"
|
||||
#rsasl = "0.2.3"
|
||||
rsasl = { path = "../../rsasl" }
|
||||
|
||||
# rumqtt needs tokio which I'm trying to get away from
|
||||
paho-mqtt = { git = "https://github.com/dequbed/paho.mqtt.rust.git", branch = "master", features = ["build_bindgen"] }
|
||||
|
2
schema
2
schema
@ -1 +1 @@
|
||||
Subproject commit 95fa6c5eabc8fded8b69ce8e3e87bc5d9c37c027
|
||||
Subproject commit 25effe262629c6f92773d4e6762f404b858fb09a
|
@ -136,8 +136,8 @@ impl PermissionsProvider {
|
||||
error!(self.log, "Failed to create 'roles' directory: {}, skipping!", e);
|
||||
return Ok(())
|
||||
} else {
|
||||
// Rust's stdlib considers the last element the file name so we have to put a dummy here for
|
||||
// .set_filename() to work correctly
|
||||
// Rust's stdlib considers the last element the file name even when it's a directory so
|
||||
// we have to put a dummy here for .set_filename() to work correctly
|
||||
path.push("dummy");
|
||||
self.dump_roles(txn, path.clone())?;
|
||||
path.pop();
|
||||
@ -157,8 +157,8 @@ impl PermissionsProvider {
|
||||
error!(self.log, "Failed to create 'perms' directory: {}, skipping!", e);
|
||||
return Ok(())
|
||||
} else {
|
||||
// Rust's stdlib considers the last element the file name so we have to put a dummy here for
|
||||
// .set_filename() to work correctly
|
||||
// Rust's stdlib considers the last element the file name even when it's a directory so
|
||||
// we have to put a dummy here for .set_filename() to work correctly
|
||||
path.push("dummy");
|
||||
self.dump_perms(txn, path.clone())?;
|
||||
path.pop();
|
||||
@ -178,8 +178,8 @@ impl PermissionsProvider {
|
||||
error!(self.log, "Failed to create 'users' directory: {}, skipping!", e);
|
||||
return Ok(())
|
||||
} else {
|
||||
// Rust's stdlib considers the last element the file name so we have to put a dummy here for
|
||||
// .set_filename() to work correctly
|
||||
// Rust's stdlib considers the last element the file name even when it's a directory so
|
||||
// we have to put a dummy here for .set_filename() to work correctly
|
||||
path.push("dummy");
|
||||
self.dump_users(txn, path.clone())?;
|
||||
path.pop();
|
||||
|
14
src/api.rs
14
src/api.rs
@ -14,19 +14,7 @@ use capnp_rpc::rpc_twoparty_capnp::Side;
|
||||
use capnp::capability::FromServer;
|
||||
|
||||
pub async fn handle_connection(log: Logger, socket: TcpStream) -> Result<()> {
|
||||
let mut message = capnp::message::Builder::new_default();
|
||||
let mut outer = message.init_root::<crate::connection::connection_capnp::message::Builder>();
|
||||
let mut api = outer.init_api();
|
||||
|
||||
let mapi = MachinesAPI {};
|
||||
api.set_machines(capnp_rpc::new_client(mapi));
|
||||
|
||||
let network = VatNetwork::new(socket.clone(), socket, Side::Server, Default::default());
|
||||
let rpc = RpcSystem::new(Box::new(network), None).map(|_| ());
|
||||
|
||||
rpc.await;
|
||||
|
||||
Ok(())
|
||||
unimplemented!()
|
||||
}
|
||||
|
||||
pub struct MachinesAPI;
|
||||
|
@ -8,131 +8,43 @@ use crate::api;
|
||||
|
||||
pub use crate::schema::connection_capnp;
|
||||
|
||||
pub async fn handle_connection(log: Logger, mut stream: TcpStream) -> Result<()> {
|
||||
let host = "localhost";
|
||||
let program = "Difluoroborane-0.1.0";
|
||||
let version = (0u32,1u32);
|
||||
use capnp::capability::{Params, Results, Promise, FromServer};
|
||||
|
||||
|
||||
let receive_options = capnp::message::ReaderOptions::default();
|
||||
{
|
||||
let message = capnp_futures::serialize::read_message(&mut stream, receive_options).await.unwrap().unwrap();
|
||||
let m = message.get_root::<connection_capnp::message::Reader>().unwrap();
|
||||
|
||||
if m.has_greet() {
|
||||
match m.which() {
|
||||
Ok(connection_capnp::message::Which::Greet(Ok(r))) => {
|
||||
println!("Host {} with program {} is saying hello. They speak API version {}.{}.",
|
||||
r.get_host().unwrap(),
|
||||
r.get_program().unwrap(),
|
||||
r.get_major(),
|
||||
r.get_minor())
|
||||
},
|
||||
_ => {
|
||||
// We *JUST* checked that it's a greeting. This can not happen
|
||||
unreachable!()
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
{
|
||||
let mut message = capnp::message::Builder::new_default();
|
||||
let greet_outer = message.init_root::<connection_capnp::message::Builder>();
|
||||
let mut greeting = greet_outer.init_greet();
|
||||
greeting.set_host(host);
|
||||
greeting.set_program(program);
|
||||
greeting.set_major(version.0);
|
||||
greeting.set_minor(version.1);
|
||||
|
||||
capnp_futures::serialize::write_message(&mut stream, message).await?;
|
||||
}
|
||||
{
|
||||
let mut message = capnp::message::Builder::new_default();
|
||||
let outer = message.init_root::<connection_capnp::message::Builder>();
|
||||
let mut mechs = outer.init_auth().init_mechanisms(1);
|
||||
mechs.set(0, "PLAIN");
|
||||
|
||||
capnp_futures::serialize::write_message(&mut stream, message).await?;
|
||||
}
|
||||
|
||||
{
|
||||
let message = capnp_futures::serialize::read_message(&mut stream, receive_options).await.unwrap().unwrap();
|
||||
let m = message.get_root::<connection_capnp::message::Reader>().unwrap();
|
||||
|
||||
let mut auth_success = false;
|
||||
|
||||
match m.which() {
|
||||
Ok(connection_capnp::message::Which::Auth(Ok(r))) => {
|
||||
if let Ok(w) = r.which() {
|
||||
use crate::auth::auth_capnp::auth_message::*;
|
||||
match w {
|
||||
Request(Ok(r)) => {
|
||||
let m = r.get_mechanism().unwrap();
|
||||
println!("Client wants to AUTH using {:?}", &m);
|
||||
let mut sasl = auth::Auth::new();
|
||||
let mut sess = sasl.ctx.server_start(&m).unwrap();
|
||||
|
||||
use crate::auth::auth_capnp::request::initial_response::*;
|
||||
match r.get_initial_response().which() {
|
||||
Ok(Initial(Ok(r))) => {
|
||||
debug!(log, "Client Auth with initial data");
|
||||
let mut message = capnp::message::Builder::new_default();
|
||||
let mut outer = message.init_root::<connection_capnp::message::Builder>().init_auth();
|
||||
|
||||
match sess.step(r) {
|
||||
Ok(rsasl::Step::Done(b)) => {
|
||||
auth_success = true;
|
||||
debug!(log, "Authentication successful");
|
||||
let mut outcome= outer.init_outcome();
|
||||
|
||||
outcome.set_result(auth::auth_capnp::outcome::Result::Successful);
|
||||
if !b.is_empty() {
|
||||
let mut add_data = outcome.init_additional_data();
|
||||
add_data.set_additional(&b);
|
||||
}
|
||||
},
|
||||
Ok(rsasl::Step::NeedsMore(b)) => {
|
||||
debug!(log, "Authentication needs more data");
|
||||
outer.set_response(&b);
|
||||
}
|
||||
Err(e) => {
|
||||
warn!(log, "Authentication error: {}", e);
|
||||
let mut outcome = outer.init_outcome();
|
||||
|
||||
// TODO: Distinguish errors
|
||||
outcome.set_result(auth::auth_capnp::outcome::Result::Failed);
|
||||
outcome.set_action(auth::auth_capnp::outcome::Action::Retry);
|
||||
outcome.set_help_text(&format!("{}", e));
|
||||
}
|
||||
}
|
||||
|
||||
capnp_futures::serialize::write_message(&mut stream, message).await?;
|
||||
}
|
||||
_ => {
|
||||
}
|
||||
}
|
||||
},
|
||||
_ => {
|
||||
}
|
||||
}
|
||||
} else {
|
||||
println!("Got unexpected message");
|
||||
}
|
||||
},
|
||||
Ok(_) => {
|
||||
println!("Got unexpected message");
|
||||
}
|
||||
Err(e) => {
|
||||
println!("Got error {:?}", e);
|
||||
}
|
||||
}
|
||||
|
||||
if auth_success {
|
||||
info!(log, "Handing off to API connection handler");
|
||||
api::handle_connection(log, stream).await;
|
||||
}
|
||||
}
|
||||
|
||||
Ok(())
|
||||
/// Connection context
|
||||
struct Connection {
|
||||
stream: TcpStream,
|
||||
user: Option<auth::User>,
|
||||
}
|
||||
|
||||
|
||||
use connection_capnp::bootstrap::*;
|
||||
impl connection_capnp::bootstrap::Server for Connection {
|
||||
fn auth(&mut self,
|
||||
_: Params<auth_params::Owned>,
|
||||
mut res: Results<auth_results::Owned>
|
||||
) -> Promise<(), capnp::Error> {
|
||||
// Forbid mutltiple authentication for now
|
||||
// TODO: When should we allow multiple auth and how do me make sure that does not leak
|
||||
// priviledges (e.g. due to previously issues caps)?
|
||||
if self.user.is_none() {
|
||||
res.get().set_auth(capnp_rpc::new_client(auth::Auth::new()))
|
||||
}
|
||||
|
||||
Promise::ok(())
|
||||
}
|
||||
|
||||
fn permissions(&mut self,
|
||||
_: Params<permissions_params::Owned>,
|
||||
mut res: Results<permissions_results::Owned>
|
||||
) -> Promise<(), capnp::Error> {
|
||||
if let Some(user) = self.user {
|
||||
|
||||
}
|
||||
|
||||
Promise::ok(())
|
||||
}
|
||||
}
|
||||
|
||||
pub async fn handle_connection(log: Logger, mut stream: TcpStream) -> Result<()> {
|
||||
unimplemented!()
|
||||
}
|
||||
|
@ -302,8 +302,6 @@ fn main() -> Result<(), Error> {
|
||||
});
|
||||
|
||||
// Check each signal as it arrives
|
||||
// signals is a futures-0.1 stream, compat() makes it a futures-0.3 (which we use) stream
|
||||
// Now actually check if a connection was opened or a signal recv'd
|
||||
let handle_signals = signal.map(|r| { r.unwrap() }).into_stream();
|
||||
|
||||
let mut combined = stream::select(handle_signals, handle_sockets);
|
||||
|
Loading…
Reference in New Issue
Block a user