diff --git a/schema b/schema index 5b7a31b..9fb856a 160000 --- a/schema +++ b/schema @@ -1 +1 @@ -Subproject commit 5b7a31b00528d535b8858289d1db685269ec9b7b +Subproject commit 9fb856a4dbe8f1e68c77afa3dbff606a27342e7c diff --git a/src/access.rs b/src/access.rs index cef7470..10fbbac 100644 --- a/src/access.rs +++ b/src/access.rs @@ -196,7 +196,7 @@ impl PermissionsProvider { let (kbytes, _rest) = kbuf.split_at(std::mem::size_of::()); let roleID = u64::from_ne_bytes(kbytes.try_into().unwrap()); let role: Role = flexbuffers::from_slice(vbuf)?; - let filename = format!("{:x}.yml", roleID); + let filename = format!("{:x}.toml", roleID); path.set_file_name(filename); let mut fp = std::fs::File::create(&path)?; let out = toml::to_vec(&role)?; @@ -213,7 +213,7 @@ impl PermissionsProvider { let (kbytes, _rest) = kbuf.split_at(std::mem::size_of::()); let permID = u64::from_ne_bytes(kbytes.try_into().unwrap()); let perm: Perm = flexbuffers::from_slice(vbuf)?; - let filename = format!("{:x}.yml", permID); + let filename = format!("{:x}.toml", permID); path.set_file_name(filename); let mut fp = std::fs::File::create(&path)?; let out = toml::to_vec(&perm)?; @@ -230,7 +230,7 @@ impl PermissionsProvider { let (kbytes, _rest) = kbuf.split_at(std::mem::size_of::()); let userID = u64::from_ne_bytes(kbytes.try_into().unwrap()); let user: User = flexbuffers::from_slice(vbuf)?; - let filename = format!("{:x}.yml", userID); + let filename = format!("{:x}.toml", userID); path.set_file_name(filename); let mut fp = std::fs::File::create(&path)?; let out = toml::to_vec(&user)?; diff --git a/src/api.rs b/src/api.rs index 4673e55..23a8633 100644 --- a/src/api.rs +++ b/src/api.rs @@ -1,63 +1,52 @@ -// module needs to be top level for generated functions to be in scope: -// https://github.com/capnproto/capnproto-rust/issues/16 -pub mod api_capnp { - include!(concat!(env!("OUT_DIR"), "/schema/api_capnp.rs")); -} - use smol::net::TcpStream; use futures_util::FutureExt; use slog::Logger; use crate::error::Result; +pub use crate::schema::api_capnp; use capnp::capability::Promise; use capnp::Error; use capnp_rpc::RpcSystem; use capnp_rpc::twoparty::VatNetwork; use capnp_rpc::rpc_twoparty_capnp::Side; +use capnp::capability::FromServer; pub async fn handle_connection(log: Logger, socket: TcpStream) -> Result<()> { - let client = DifAPI {}; - let api: api_capnp::diflouroborane::Client = capnp_rpc::new_client(client); - let mut message = capnp::message::Builder::new_default(); let mut outer = message.init_root::(); - outer.set_api(api.clone()); + 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), Some(api.client)).map(|_| ()); + let rpc = RpcSystem::new(Box::new(network), None).map(|_| ()); rpc.await; Ok(()) } -pub struct DifAPI; - -impl api_capnp::diflouroborane::Server for DifAPI { - fn machines(&mut self, - _params: api_capnp::diflouroborane::MachinesParams, - mut results: api_capnp::diflouroborane::MachinesResults) - -> Promise<(), Error> - { - let mut b = results.get(); - let mach = capnp_rpc::new_client(MachinesAPI); - b.set_mach(mach); - Promise::ok(()) - } -} - pub struct MachinesAPI; impl api_capnp::machines::Server for MachinesAPI { - fn list(&mut self, - _params: api_capnp::machines::ListParams, - mut results: api_capnp::machines::ListResults) + fn list_machines(&mut self, + _params: api_capnp::machines::ListMachinesParams, + mut results: api_capnp::machines::ListMachinesResults) -> Promise<(), Error> { let mut l = results.get(); l.init_machines(0); Promise::ok(()) } + + fn get_machine(&mut self, + _params: api_capnp::machines::GetMachineParams, + mut results: api_capnp::machines::GetMachineResults) + -> Promise<(), Error> + { + Promise::ok(()) + } } diff --git a/src/auth.rs b/src/auth.rs index 703f566..3ef57e0 100644 --- a/src/auth.rs +++ b/src/auth.rs @@ -11,9 +11,7 @@ use rsasl::sys::{Gsasl, Gsasl_session}; use crate::error::Result; use crate::config::Settings; -pub mod auth_capnp { - include!(concat!(env!("OUT_DIR"), "/schema/auth_capnp.rs")); -} +pub use crate::schema::auth_capnp; extern "C" fn callback(ctx: *mut Gsasl, sctx: *mut Gsasl_session, prop: Property) -> i32 { let sasl = SASL::from_ptr(ctx); @@ -56,3 +54,83 @@ impl Auth { pub async fn init(log: Logger, config: Settings) -> Result { Ok(Auth::new()) } + +// Use the newtype pattern here to make the type system work for us; even though AuthCId is for all +// intents and purposes just a String the compiler will still complain if you return or more +// importantly pass a String intead of a AuthCId. This prevents bugs where you get an object from +// somewhere and pass it somewhere else and in between don't check if it's the right type and +// accidentally pass the authzid where the authcid should have gone. + +/// Authentication Identity +/// +/// Under the hood a string because the form depends heavily on the method +struct AuthCId(String); +/// Authorization Identity +/// +/// This identity is internal to FabAccess and completely independent from the authentication +/// method or source +struct AuthZId { + uid: String, + subuid: String, + domain: String, +} + +// What is a man?! A miserable little pile of secrets! +/// Authentication/Authorization user object. +/// +/// This struct contains the user as is passed to the actual authentication/authorization +/// subsystems +/// +struct User { + /// Contains the Authentication ID used + /// + /// The authentication ID is an identifier for the authentication exchange. This is different + /// than the ID of the user to be authenticated; for example when using x509 the authcid is + /// the dn of the certificate, when using GSSAPI the authcid is of form `@` + authcid: AuthCId, + + /// Contains the Authorization ID + /// + /// This is the identifier of the user to *authenticate as*. This in several cases is different + /// to the `authcid`: + /// If somebody wants to authenticate as somebody else, su-style. + /// If a person wants to authenticate as a higher-permissions account, e.g. foo may set authzid foo+admin + /// to split normal user and "admin" accounts. + /// If a method requires a specific authcid that is different from the identifier of the user + /// to authenticate as, e.g. GSSAPI, x509 client certificates, API TOKEN authentication. + authzid: AuthZId, + + /// Contains the authentication method used + /// + /// For the most part this is the SASL method + authMethod: String, + + /// Method-specific key-value pairs + /// + /// Each method can use their own key-value pairs. + /// E.g. EXTERNAL encodes the actual method used (x509 client certs, UID/GID for unix sockets, + /// ...) + kvs: Box<[(String, String)]>, +} + +// Authentication has two parts: Granting the authentication itself and then performing the +// authentication. +// Granting the authentication checks if +// a) the given authcid fits with the given (authMethod, kvs). In general a failure here indicates +// a programming failure — the authcid come from the same source as that tuple +// b) the given authcid may authenticate as the given authzid. E.g. if a given client certificate +// has been configured for that user, if a GSSAPI user maps to a given user, + +enum AuthError { + /// Authentication ID is bad/unknown/.. + BadAuthcid, + /// Authorization ID is bad/unknown/.. + BadAuthzid, + /// User may not use that authorization id + NotAllowedAuthzid, + +} + +fn grant_auth(user: User) -> std::result::Result<(), AuthError> { + unimplemented!() +} diff --git a/src/connection.rs b/src/connection.rs index a6ad9ba..0bcae6f 100644 --- a/src/connection.rs +++ b/src/connection.rs @@ -6,9 +6,7 @@ use crate::error::Result; use crate::auth; use crate::api; -pub mod connection_capnp { - include!(concat!(env!("OUT_DIR"), "/schema/connection_capnp.rs")); -} +pub use crate::schema::connection_capnp; pub async fn handle_connection(log: Logger, mut stream: TcpStream) -> Result<()> { let host = "localhost"; diff --git a/src/main.rs b/src/main.rs index 454d8b3..64744c6 100644 --- a/src/main.rs +++ b/src/main.rs @@ -18,6 +18,7 @@ mod machine; mod connection; mod registries; mod network; +mod schema; use clap::{App, Arg}; diff --git a/src/schema.rs b/src/schema.rs new file mode 100644 index 0000000..06fb286 --- /dev/null +++ b/src/schema.rs @@ -0,0 +1,11 @@ +pub mod auth_capnp { + include!(concat!(env!("OUT_DIR"), "/schema/auth_capnp.rs")); +} + +pub mod api_capnp { + include!(concat!(env!("OUT_DIR"), "/schema/api_capnp.rs")); +} + +pub mod connection_capnp { + include!(concat!(env!("OUT_DIR"), "/schema/connection_capnp.rs")); +}