mirror of
https://gitlab.com/fabinfra/fabaccess/bffh.git
synced 2024-11-22 23:07:56 +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"
|
clap = "2.33"
|
||||||
|
|
||||||
# TODO update this if bindgen breaks (again)
|
# 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
|
# 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"] }
|
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);
|
error!(self.log, "Failed to create 'roles' directory: {}, skipping!", e);
|
||||||
return Ok(())
|
return Ok(())
|
||||||
} else {
|
} else {
|
||||||
// Rust's stdlib considers the last element the file name so we have to put a dummy here for
|
// Rust's stdlib considers the last element the file name even when it's a directory so
|
||||||
// .set_filename() to work correctly
|
// we have to put a dummy here for .set_filename() to work correctly
|
||||||
path.push("dummy");
|
path.push("dummy");
|
||||||
self.dump_roles(txn, path.clone())?;
|
self.dump_roles(txn, path.clone())?;
|
||||||
path.pop();
|
path.pop();
|
||||||
@ -157,8 +157,8 @@ impl PermissionsProvider {
|
|||||||
error!(self.log, "Failed to create 'perms' directory: {}, skipping!", e);
|
error!(self.log, "Failed to create 'perms' directory: {}, skipping!", e);
|
||||||
return Ok(())
|
return Ok(())
|
||||||
} else {
|
} else {
|
||||||
// Rust's stdlib considers the last element the file name so we have to put a dummy here for
|
// Rust's stdlib considers the last element the file name even when it's a directory so
|
||||||
// .set_filename() to work correctly
|
// we have to put a dummy here for .set_filename() to work correctly
|
||||||
path.push("dummy");
|
path.push("dummy");
|
||||||
self.dump_perms(txn, path.clone())?;
|
self.dump_perms(txn, path.clone())?;
|
||||||
path.pop();
|
path.pop();
|
||||||
@ -178,8 +178,8 @@ impl PermissionsProvider {
|
|||||||
error!(self.log, "Failed to create 'users' directory: {}, skipping!", e);
|
error!(self.log, "Failed to create 'users' directory: {}, skipping!", e);
|
||||||
return Ok(())
|
return Ok(())
|
||||||
} else {
|
} else {
|
||||||
// Rust's stdlib considers the last element the file name so we have to put a dummy here for
|
// Rust's stdlib considers the last element the file name even when it's a directory so
|
||||||
// .set_filename() to work correctly
|
// we have to put a dummy here for .set_filename() to work correctly
|
||||||
path.push("dummy");
|
path.push("dummy");
|
||||||
self.dump_users(txn, path.clone())?;
|
self.dump_users(txn, path.clone())?;
|
||||||
path.pop();
|
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;
|
use capnp::capability::FromServer;
|
||||||
|
|
||||||
pub async fn handle_connection(log: Logger, socket: TcpStream) -> Result<()> {
|
pub async fn handle_connection(log: Logger, socket: TcpStream) -> Result<()> {
|
||||||
let mut message = capnp::message::Builder::new_default();
|
unimplemented!()
|
||||||
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(())
|
|
||||||
}
|
}
|
||||||
|
|
||||||
pub struct MachinesAPI;
|
pub struct MachinesAPI;
|
||||||
|
@ -8,131 +8,43 @@ use crate::api;
|
|||||||
|
|
||||||
pub use crate::schema::connection_capnp;
|
pub use crate::schema::connection_capnp;
|
||||||
|
|
||||||
pub async fn handle_connection(log: Logger, mut stream: TcpStream) -> Result<()> {
|
use capnp::capability::{Params, Results, Promise, FromServer};
|
||||||
let host = "localhost";
|
|
||||||
let program = "Difluoroborane-0.1.0";
|
|
||||||
let version = (0u32,1u32);
|
|
||||||
|
|
||||||
|
/// Connection context
|
||||||
let receive_options = capnp::message::ReaderOptions::default();
|
struct Connection {
|
||||||
{
|
stream: TcpStream,
|
||||||
let message = capnp_futures::serialize::read_message(&mut stream, receive_options).await.unwrap().unwrap();
|
user: Option<auth::User>,
|
||||||
let m = message.get_root::<connection_capnp::message::Reader>().unwrap();
|
}
|
||||||
|
|
||||||
if m.has_greet() {
|
|
||||||
match m.which() {
|
use connection_capnp::bootstrap::*;
|
||||||
Ok(connection_capnp::message::Which::Greet(Ok(r))) => {
|
impl connection_capnp::bootstrap::Server for Connection {
|
||||||
println!("Host {} with program {} is saying hello. They speak API version {}.{}.",
|
fn auth(&mut self,
|
||||||
r.get_host().unwrap(),
|
_: Params<auth_params::Owned>,
|
||||||
r.get_program().unwrap(),
|
mut res: Results<auth_results::Owned>
|
||||||
r.get_major(),
|
) -> Promise<(), capnp::Error> {
|
||||||
r.get_minor())
|
// 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)?
|
||||||
// We *JUST* checked that it's a greeting. This can not happen
|
if self.user.is_none() {
|
||||||
unreachable!()
|
res.get().set_auth(capnp_rpc::new_client(auth::Auth::new()))
|
||||||
}
|
}
|
||||||
}
|
|
||||||
}
|
Promise::ok(())
|
||||||
}
|
}
|
||||||
|
|
||||||
{
|
fn permissions(&mut self,
|
||||||
let mut message = capnp::message::Builder::new_default();
|
_: Params<permissions_params::Owned>,
|
||||||
let greet_outer = message.init_root::<connection_capnp::message::Builder>();
|
mut res: Results<permissions_results::Owned>
|
||||||
let mut greeting = greet_outer.init_greet();
|
) -> Promise<(), capnp::Error> {
|
||||||
greeting.set_host(host);
|
if let Some(user) = self.user {
|
||||||
greeting.set_program(program);
|
|
||||||
greeting.set_major(version.0);
|
}
|
||||||
greeting.set_minor(version.1);
|
|
||||||
|
Promise::ok(())
|
||||||
capnp_futures::serialize::write_message(&mut stream, message).await?;
|
}
|
||||||
}
|
}
|
||||||
{
|
|
||||||
let mut message = capnp::message::Builder::new_default();
|
pub async fn handle_connection(log: Logger, mut stream: TcpStream) -> Result<()> {
|
||||||
let outer = message.init_root::<connection_capnp::message::Builder>();
|
unimplemented!()
|
||||||
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(())
|
|
||||||
}
|
}
|
||||||
|
@ -302,8 +302,6 @@ fn main() -> Result<(), Error> {
|
|||||||
});
|
});
|
||||||
|
|
||||||
// Check each signal as it arrives
|
// 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 handle_signals = signal.map(|r| { r.unwrap() }).into_stream();
|
||||||
|
|
||||||
let mut combined = stream::select(handle_signals, handle_sockets);
|
let mut combined = stream::select(handle_signals, handle_sockets);
|
||||||
|
Loading…
Reference in New Issue
Block a user