This commit is contained in:
Nadja Reitzenstein 2021-12-05 23:38:05 +01:00
parent 6d3e08955a
commit 6e91295cc0
5 changed files with 174 additions and 162 deletions

View File

@ -22,10 +22,10 @@
{ cmd = "./examples/fail-actor.sh" { cmd = "./examples/fail-actor.sh"
}} }}
} }
--, init_connections = [] : List { machine : Text, initiator : Text } , init_connections = [] : List { machine : Text, initiator : Text }
, init_connections = [{ machine = "Testmachine", initiator = "Initiator" }] --, init_connections = [{ machine = "Testmachine", initiator = "Initiator" }]
, initiators = --{=} , initiators = {=}
{ Initiator = { module = "Dummy", params = {=} } } --{ Initiator = { module = "Dummy", params = {=} } }
, listens = , listens =
[ { address = "127.0.0.1", port = Some 59661 } [ { address = "127.0.0.1", port = Some 59661 }
, { address = "::1", port = Some 59661 } , { address = "::1", port = Some 59661 }

View File

@ -8,13 +8,14 @@ use capnp::Error;
use crate::db::machine::Status; use crate::db::machine::Status;
use crate::api::machine::*; use crate::api::machine::*;
use crate::schema::machine_capnp::machine::MachineState; use crate::schema::machine_capnp::machine::{MachineState, Builder as MachineBuilder};
use crate::schema::machinesystem_capnp::machine_system; use crate::schema::machinesystem_capnp::machine_system;
use crate::schema::machinesystem_capnp::machine_system::info as machines; use crate::schema::machinesystem_capnp::machine_system::info as machines;
use crate::network::Network; use crate::network::Network;
use crate::db::user::UserId; use crate::db::user::UserId;
use crate::db::access::{PermRule, admin_perm}; use crate::db::access::{PermRule, admin_perm, Permission};
use crate::connection::Session; use crate::connection::Session;
use crate::machine::Machine as NwMachine;
/// An implementation of the `Machines` API /// An implementation of the `Machines` API
#[derive(Clone)] #[derive(Clone)]
@ -70,54 +71,15 @@ impl machines::Server for Machines {
let permissions = &session.as_ref().unwrap().perms; let permissions = &session.as_ref().unwrap().perms;
let mut machines = results.get().init_machine_list(v.len() as u32); let mut machines = results.get().init_machine_list(v.len() as u32);
for (i, (name, machine)) in v.into_iter().enumerate() { for (i, (id, machine)) in v.into_iter().enumerate() {
let perms = Perms::get_for(&machine.desc.privs, permissions.iter());
let mut builder = machines.reborrow().get(i as u32); let mut builder = machines.reborrow().get(i as u32);
builder.set_id(&name); fill_machine_builder(
builder.set_name(&machine.desc.name); &mut builder,
if let Some(ref desc) = machine.desc.description { &machine,
builder.set_description(desc); &permissions[..],
} &id,
if let Some(ref wiki) = machine.desc.wiki { user,
builder.set_wiki(wiki); ).await
}
builder.set_urn(&format!("urn:fabaccess:resource:{}", &name));
let machineapi = Machine::new(user.clone(), perms, machine.clone());
let state = machine.get_status().await;
let s = match state {
Status::Free => MachineState::Free,
Status::Disabled => MachineState::Disabled,
Status::Blocked(_) => MachineState::Blocked,
Status::InUse(ref u) => {
if let Some(owner) = u.as_ref() {
if owner == user {
builder.set_inuse(capnp_rpc::new_client(machineapi.clone()));
}
}
MachineState::InUse
},
Status::Reserved(_) => MachineState::Reserved,
Status::ToCheck(_) => MachineState::ToCheck,
};
builder.set_state(s);
if perms.write && state == Status::Free {
builder.set_use(capnp_rpc::new_client(machineapi.clone()));
}
if perms.manage {
//builder.set_transfer(capnp_rpc::new_client(machineapi.clone()));
//builder.set_check(capnp_rpc::new_client(machineapi.clone()));
builder.set_manage(capnp_rpc::new_client(machineapi.clone()));
}
if permissions.iter().any(|r| r.match_perm(&admin_perm())) {
builder.set_admin(capnp_rpc::new_client(machineapi.clone()));
}
builder.set_info(capnp_rpc::new_client(machineapi));
} }
Ok(()) Ok(())
@ -148,50 +110,14 @@ impl machines::Server for Machines {
if let Some(machine) = network.machines.get(&id) { if let Some(machine) = network.machines.get(&id) {
let mut builder = results.get().init_machine(); let mut builder = results.get().init_machine();
let perms = Perms::get_for(&machine.desc.privs, permissions.iter()); fill_machine_builder(
builder.set_id(&id); &mut builder,
builder.set_name(&machine.desc.name); &machine,
if let Some(ref desc) = machine.desc.description { &permissions[..],
builder.set_description(desc); &id,
} user,
if let Some(ref wiki) = machine.desc.wiki { ).await
builder.set_wiki(wiki);
}
builder.set_urn(&format!("urn:fabaccess:resource:{}", &id));
let machineapi = Machine::new(user.clone(), perms, machine.clone());
let state = machine.get_status().await;
if perms.write && state == Status::Free {
builder.set_use(capnp_rpc::new_client(machineapi.clone()));
}
if perms.manage {
//builder.set_transfer(capnp_rpc::new_client(machineapi.clone()));
//builder.set_check(capnp_rpc::new_client(machineapi.clone()));
builder.set_manage(capnp_rpc::new_client(machineapi.clone()));
}
if permissions.iter().any(|r| r.match_perm(&admin_perm())) {
builder.set_admin(capnp_rpc::new_client(machineapi.clone()));
}
let s = match machine.get_status().await {
Status::Free => MachineState::Free,
Status::Disabled => MachineState::Disabled,
Status::Blocked(_) => MachineState::Blocked,
Status::InUse(u) => {
if let Some(owner) = u.as_ref() {
if owner == user {
builder.set_inuse(capnp_rpc::new_client(machineapi.clone()));
}
}
MachineState::InUse
},
Status::Reserved(_) => MachineState::Reserved,
Status::ToCheck(_) => MachineState::ToCheck,
};
builder.set_state(s);
builder.set_info(capnp_rpc::new_client(machineapi));
}; };
Ok(()) Ok(())
@ -209,72 +135,34 @@ impl machines::Server for Machines {
) -> Promise<(), capnp::Error> { ) -> Promise<(), capnp::Error> {
let rc = Rc::clone(&self.session); let rc = Rc::clone(&self.session);
if self.session.borrow().is_some() { if self.session.borrow().is_some() {
let urn = { let id: Option<String> = {
let params = pry!(params.get()); let urn = pry!(pry!(params.get()).get_urn());
pry!(params.get_urn()) let mut parts = urn.split_terminator(':');
let part_urn = parts.next().map(|u| u == "urn").unwrap_or(false);
let part_fabaccess = parts.next().map(|f| f == "fabaccess").unwrap_or(false);
let part_resource = parts.next().map(|r| r == "resource").unwrap_or(false);
if !(part_urn && part_fabaccess && part_resource) {
return Promise::ok(())
}
parts.next().map(|s| s.to_string())
}; };
let mut parts = urn.split_terminator(':'); if let Some(id) = id {
let part_urn = parts.next().map(|u| u == "urn").unwrap_or(false);
let part_fabaccess = parts.next().map(|f| f == "fabaccess").unwrap_or(false);
let part_resource = parts.next().map(|r| r == "resource").unwrap_or(false);
if !(part_urn && part_fabaccess && part_resource) {
return Promise::ok(())
}
if let Some(name) = parts.next() {
let name = name.to_string();
let network = self.network.clone(); let network = self.network.clone();
let f = async move { let f = async move {
let session = rc.borrow(); let session = rc.borrow();
let user = &session.as_ref().unwrap().authzid; let user = &session.as_ref().unwrap().authzid;
let permissions = &session.as_ref().unwrap().perms; let permissions = &session.as_ref().unwrap().perms;
if let Some(machine) = network.machines.get(&name) { if let Some(machine) = network.machines.get(&id) {
let mut builder = results.get().init_machine(); let mut builder = results.get().init_machine();
let perms = Perms::get_for(&machine.desc.privs, permissions.iter()); fill_machine_builder(
builder.set_name(&name); &mut builder,
if let Some(ref desc) = machine.desc.description { &machine,
builder.set_description(desc); &permissions[..],
} id,
if let Some(ref wiki) = machine.desc.wiki { user,
builder.set_wiki(wiki); ).await
}
builder.set_urn(&format!("urn:fabaccess:resource:{}", &name));
let machineapi = Machine::new(user.clone(), perms, machine.clone());
let state = machine.get_status().await;
if perms.write && state == Status::Free {
builder.set_use(capnp_rpc::new_client(machineapi.clone()));
}
if perms.manage {
//builder.set_transfer(capnp_rpc::new_client(machineapi.clone()));
//builder.set_check(capnp_rpc::new_client(machineapi.clone()));
builder.set_manage(capnp_rpc::new_client(machineapi.clone()));
}
if permissions.iter().any(|r| r.match_perm(&admin_perm())) {
builder.set_admin(capnp_rpc::new_client(machineapi.clone()));
}
let s = match machine.get_status().await {
Status::Free => MachineState::Free,
Status::Disabled => MachineState::Disabled,
Status::Blocked(_) => MachineState::Blocked,
Status::InUse(u) => {
if let Some(owner) = u.as_ref() {
if owner == user {
builder.set_inuse(capnp_rpc::new_client(machineapi.clone()));
}
}
MachineState::InUse
},
Status::Reserved(_) => MachineState::Reserved,
Status::ToCheck(_) => MachineState::ToCheck,
};
builder.set_state(s);
builder.set_info(capnp_rpc::new_client(machineapi));
}; };
Ok(()) Ok(())
@ -288,3 +176,57 @@ impl machines::Server for Machines {
} }
} }
} }
async fn fill_machine_builder(
builder: &mut MachineBuilder<'_>,
machine: &NwMachine,
permissions: &[PermRule],
id: impl AsRef<str>,
user: &UserId,
) {
let name = &machine.desc.name;
let perms = Perms::get_for(&machine.desc.privs, permissions.iter());
builder.set_id(id.as_ref());
builder.set_name(name);
if let Some(ref desc) = machine.desc.description {
builder.set_description(desc);
}
if let Some(ref wiki) = machine.desc.wiki {
builder.set_wiki(wiki);
}
builder.set_urn(&format!("urn:fabaccess:resource:{}", id.as_ref()));
let machineapi = Machine::new(user.clone(), perms, machine.clone());
let state = machine.get_status().await;
if perms.write && state == Status::Free {
builder.set_use(capnp_rpc::new_client(machineapi.clone()));
}
if perms.manage {
//builder.set_transfer(capnp_rpc::new_client(machineapi.clone()));
//builder.set_check(capnp_rpc::new_client(machineapi.clone()));
builder.set_manage(capnp_rpc::new_client(machineapi.clone()));
}
if permissions.iter().any(|r| r.match_perm(&admin_perm())) {
builder.set_admin(capnp_rpc::new_client(machineapi.clone()));
}
let s = match machine.get_status().await {
Status::Free => MachineState::Free,
Status::Disabled => MachineState::Disabled,
Status::Blocked(_) => MachineState::Blocked,
Status::InUse(u) => {
if let Some(owner) = u.as_ref() {
if owner == user {
builder.set_inuse(capnp_rpc::new_client(machineapi.clone()));
}
}
MachineState::InUse
},
Status::Reserved(_) => MachineState::Reserved,
Status::ToCheck(_) => MachineState::ToCheck,
};
builder.set_state(s);
builder.set_info(capnp_rpc::new_client(machineapi));
}

View File

@ -5,7 +5,7 @@ use slog::Logger;
use std::sync::Arc; use std::sync::Arc;
use std::fmt; use std::fmt;
use std::collections::HashMap; use std::collections::{HashMap, HashSet};
use std::cmp::Ordering; use std::cmp::Ordering;
use std::path::Path; use std::path::Path;
use std::fs; use std::fs;
@ -106,6 +106,43 @@ pub trait RoleDB {
return Ok(output); return Ok(output);
} }
fn permitted_tally(&self,
roles: &mut HashSet<RoleIdentifier>,
role_id: &RoleIdentifier,
perm: &Permission
) -> Result<bool> {
if let Some(role) = self.get_role(role_id)? {
// Only check and tally parents of a role at the role itself if it's the first time we
// see it
if !roles.contains(&role_id) {
for perm_rule in role.permissions.iter() {
if perm_rule.match_perm(perm) {
return Ok(true);
}
}
for parent in role.parents.iter() {
if self.permitted_tally(roles, parent, perm)? {
return Ok(true);
}
}
roles.insert(role_id.clone());
}
}
Ok(false)
}
fn is_permitted(&self, user: &UserData, perm: impl AsRef<Permission>) -> Result<bool> {
let mut seen = HashSet::new();
for role_id in user.roles.iter() {
if self.permitted_tally(&mut seen, role_id, perm.as_ref())? {
return Ok(true);
}
}
Ok(false)
}
} }
impl RoleDB for HashMap<RoleIdentifier, Role> { impl RoleDB for HashMap<RoleIdentifier, Role> {

View File

@ -117,8 +117,7 @@ impl Future for Initiator {
debug!(this.log, "Sensor returned a new state"); debug!(this.log, "Sensor returned a new state");
this.future.take(); this.future.take();
let f = this.machine.as_mut().map(|machine| { let f = this.machine.as_mut().map(|machine| {
unimplemented!() machine.request_state_change(user.as_ref(), state)
//machine.request_state_change(user.as_ref(), state)
}); });
this.state_change_fut = f; this.state_change_fut = f;
} }

View File

@ -24,6 +24,7 @@ use slog::Logger;
use crate::error::{Result, Error}; use crate::error::{Result, Error};
use crate::db::{access, Databases, MachineDB}; use crate::db::{access, Databases, MachineDB};
use crate::db::access::AccessControl;
use crate::db::machine::{MachineIdentifier, MachineState, Status}; use crate::db::machine::{MachineIdentifier, MachineState, Status};
use crate::db::user::{User, UserData, UserId}; use crate::db::user::{User, UserData, UserId};
@ -62,15 +63,24 @@ pub struct Machine {
pub id: MachineIdentifier, pub id: MachineIdentifier,
pub desc: MachineDescription, pub desc: MachineDescription,
access_control: Arc<AccessControl>,
inner: Arc<Mutex<Inner>>, inner: Arc<Mutex<Inner>>,
} }
impl Machine { impl Machine {
pub fn new(inner: Inner, id: MachineIdentifier, desc: MachineDescription) -> Self { pub fn new(
inner: Inner,
id: MachineIdentifier,
desc: MachineDescription,
access_control: Arc<AccessControl>
) -> Self
{
Self { Self {
id, id,
inner: Arc::new(Mutex::new(inner)), inner: Arc::new(Mutex::new(inner)),
desc, desc,
access_control,
} }
} }
@ -79,9 +89,10 @@ impl Machine {
desc: MachineDescription, desc: MachineDescription,
state: MachineState, state: MachineState,
db: Arc<MachineDB>, db: Arc<MachineDB>,
) -> Machine access_control: Arc<AccessControl>,
) -> Machine
{ {
Self::new(Inner::new(id.clone(), state, db), id, desc) Self::new(Inner::new(id.clone(), state, db), id, desc, access_control)
} }
pub fn do_state_change(&self, new_state: MachineState) pub fn do_state_change(&self, new_state: MachineState)
@ -98,6 +109,15 @@ impl Machine {
Box::pin(f) Box::pin(f)
} }
pub fn request_state_change(&mut self, user: Option<&User>, new_state: MachineState)
-> BoxFuture<'static, Result<ReturnToken>>
{
let inner = self.inner.clone();
Box::pin(async move {
Ok(ReturnToken::new(inner))
})
}
pub async fn get_status(&self) -> Status { pub async fn get_status(&self) -> Status {
let guard = self.inner.lock().await; let guard = self.inner.lock().await;
guard.state.get_cloned().state guard.state.get_cloned().state
@ -140,7 +160,6 @@ pub struct Inner {
reset: Option<MachineState>, reset: Option<MachineState>,
previous: Option<UserId>, previous: Option<UserId>,
db: Arc<MachineDB>, db: Arc<MachineDB>,
} }
@ -277,6 +296,7 @@ pub fn load(config: &crate::config::Config, db: Databases, log: &Logger)
-> Result<MachineMap> -> Result<MachineMap>
{ {
let mut map = config.machines.clone(); let mut map = config.machines.clone();
let access_control = db.access;
let db = db.machine; let db = db.machine;
let it = map.drain() let it = map.drain()
@ -284,10 +304,24 @@ pub fn load(config: &crate::config::Config, db: Databases, log: &Logger)
// TODO: Read state from the state db // TODO: Read state from the state db
if let Some(state) = db.get(&k).unwrap() { if let Some(state) = db.get(&k).unwrap() {
debug!(log, "Loading old state from db for {}: {:?}", &k, &state); debug!(log, "Loading old state from db for {}: {:?}", &k, &state);
(k.clone(), Machine::construct(k, v, state, db.clone())) (k.clone(),
Machine::construct(
k,
v,
state,
db.clone(),
access_control.clone()
))
} else { } else {
debug!(log, "No old state found in db for {}, creating new.", &k); debug!(log, "No old state found in db for {}, creating new.", &k);
(k.clone(), Machine::construct(k, v, MachineState::new(), db.clone())) (k.clone(),
Machine::construct(
k,
v,
MachineState::new(),
db.clone(),
access_control.clone(),
))
} }
}); });