mirror of
https://gitlab.com/fabinfra/fabaccess/bffh.git
synced 2024-11-26 00:24:55 +01:00
Fix #29
This commit is contained in:
parent
6b88191dc5
commit
a09c3d3880
@ -8,7 +8,7 @@
|
|||||||
, { machine = "Yetmore", actor = "FailBash"}
|
, { machine = "Yetmore", actor = "FailBash"}
|
||||||
]
|
]
|
||||||
, actors =
|
, actors =
|
||||||
{ Shelly_1234 = { module = "Shelly", params =
|
{ Shelly1234 = { module = "Shelly", params =
|
||||||
{ topic = "Topic1234" }}
|
{ topic = "Topic1234" }}
|
||||||
, Bash = { module = "Process", params =
|
, Bash = { module = "Process", params =
|
||||||
{ cmd = "./examples/actor.sh"
|
{ cmd = "./examples/actor.sh"
|
||||||
@ -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 = { uid = "Testuser" } } }
|
||||||
, 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 }
|
||||||
|
@ -6,46 +6,13 @@ use capnp::Error;
|
|||||||
|
|
||||||
use futures::FutureExt;
|
use futures::FutureExt;
|
||||||
|
|
||||||
use crate::db::access::{PrivilegesBuf, PermRule};
|
use crate::db::access::{PrivilegesBuf, PermRule, Perms};
|
||||||
use crate::db::user::UserId;
|
use crate::db::user::UserId;
|
||||||
use crate::db::machine::{Status, MachineState};
|
use crate::db::machine::{Status, MachineState};
|
||||||
use crate::machine::Machine as NwMachine;
|
use crate::machine::Machine as NwMachine;
|
||||||
use crate::schema::machine_capnp::machine::*;
|
use crate::schema::machine_capnp::machine::*;
|
||||||
use crate::schema::machine_capnp::machine::MachineState as APIMState;
|
use crate::schema::machine_capnp::machine::MachineState as APIMState;
|
||||||
|
|
||||||
#[derive(Clone, Copy)]
|
|
||||||
pub struct Perms {
|
|
||||||
pub disclose: bool,
|
|
||||||
pub read: bool,
|
|
||||||
pub write: bool,
|
|
||||||
pub manage: bool,
|
|
||||||
}
|
|
||||||
|
|
||||||
impl Perms {
|
|
||||||
pub fn get_for<'a, I: Iterator<Item=&'a PermRule>>(privs: &'a PrivilegesBuf, rules: I) -> Self {
|
|
||||||
let mut disclose = false;
|
|
||||||
let mut read = false;
|
|
||||||
let mut write = false;
|
|
||||||
let mut manage = false;
|
|
||||||
for rule in rules {
|
|
||||||
if rule.match_perm(&privs.disclose) {
|
|
||||||
disclose = true;
|
|
||||||
}
|
|
||||||
if rule.match_perm(&privs.read) {
|
|
||||||
read = true;
|
|
||||||
}
|
|
||||||
if rule.match_perm(&privs.write) {
|
|
||||||
write = true;
|
|
||||||
}
|
|
||||||
if rule.match_perm(&privs.manage) {
|
|
||||||
manage = true;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
Self { disclose, read, write, manage }
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
#[derive(Clone)]
|
#[derive(Clone)]
|
||||||
pub struct Machine {
|
pub struct Machine {
|
||||||
userid: UserId,
|
userid: UserId,
|
||||||
|
@ -13,7 +13,7 @@ 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, Permission};
|
use crate::db::access::{PermRule, admin_perm, Permission, Perms};
|
||||||
use crate::connection::Session;
|
use crate::connection::Session;
|
||||||
use crate::machine::Machine as NwMachine;
|
use crate::machine::Machine as NwMachine;
|
||||||
|
|
||||||
|
@ -5,9 +5,9 @@ use std::collections::HashMap;
|
|||||||
use serde::{Serialize, Deserialize};
|
use serde::{Serialize, Deserialize};
|
||||||
|
|
||||||
use crate::error::Result;
|
use crate::error::Result;
|
||||||
use crate::machine::MachineDescription;
|
|
||||||
use crate::db::machine::MachineIdentifier;
|
use crate::db::machine::MachineIdentifier;
|
||||||
use crate::db::access::*;
|
use crate::db::access::*;
|
||||||
|
use crate::machine::MachineDescription;
|
||||||
|
|
||||||
pub fn read(path: &Path) -> Result<Config> {
|
pub fn read(path: &Path) -> Result<Config> {
|
||||||
serde_dhall::from_file(path)
|
serde_dhall::from_file(path)
|
||||||
|
@ -25,12 +25,13 @@ pub mod access;
|
|||||||
pub mod machine;
|
pub mod machine;
|
||||||
|
|
||||||
pub type MachineDB = machine::internal::Internal;
|
pub type MachineDB = machine::internal::Internal;
|
||||||
|
pub type UserDB = user::Internal;
|
||||||
|
|
||||||
#[derive(Clone)]
|
#[derive(Clone)]
|
||||||
pub struct Databases {
|
pub struct Databases {
|
||||||
pub access: Arc<access::AccessControl>,
|
pub access: Arc<access::AccessControl>,
|
||||||
pub machine: Arc<MachineDB>,
|
pub machine: Arc<MachineDB>,
|
||||||
pub userdb: Arc<user::Internal>,
|
pub userdb: Arc<UserDB>,
|
||||||
}
|
}
|
||||||
|
|
||||||
const LMDB_MAX_DB: u32 = 16;
|
const LMDB_MAX_DB: u32 = 16;
|
||||||
|
@ -11,6 +11,7 @@ use std::path::Path;
|
|||||||
use std::fs;
|
use std::fs;
|
||||||
use std::iter::FromIterator;
|
use std::iter::FromIterator;
|
||||||
use std::convert::{TryFrom, Into};
|
use std::convert::{TryFrom, Into};
|
||||||
|
use std::fmt::{Display, Formatter, Write};
|
||||||
|
|
||||||
use serde::{Serialize, Deserialize};
|
use serde::{Serialize, Deserialize};
|
||||||
|
|
||||||
@ -22,6 +23,81 @@ use crate::config::Config;
|
|||||||
use crate::db::user::UserData;
|
use crate::db::user::UserData;
|
||||||
pub use internal::Internal;
|
pub use internal::Internal;
|
||||||
|
|
||||||
|
#[derive(Clone, Copy, Debug)]
|
||||||
|
pub struct Perms {
|
||||||
|
pub disclose: bool,
|
||||||
|
pub read: bool,
|
||||||
|
pub write: bool,
|
||||||
|
pub manage: bool,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Display for Perms {
|
||||||
|
fn fmt(&self, f: &mut Formatter<'_>) -> fmt::Result {
|
||||||
|
fn part(f: &mut Formatter<'_>, fst: &mut bool, n: &'static str) -> fmt::Result {
|
||||||
|
if *fst {
|
||||||
|
*fst = false;
|
||||||
|
f.write_char(' ')?;
|
||||||
|
} else {
|
||||||
|
f.write_str("| ")?;
|
||||||
|
}
|
||||||
|
f.write_str(n)?;
|
||||||
|
f.write_char(' ')
|
||||||
|
}
|
||||||
|
|
||||||
|
let mut fst = true;
|
||||||
|
f.write_char('(')?;
|
||||||
|
|
||||||
|
if self.disclose {
|
||||||
|
part(f, &mut fst, "DISCLOSE")?;
|
||||||
|
}
|
||||||
|
if self.read {
|
||||||
|
part(f, &mut fst, "READ")?;
|
||||||
|
}
|
||||||
|
if self.write {
|
||||||
|
part(f, &mut fst, "WRITE")?;
|
||||||
|
}
|
||||||
|
if self.manage {
|
||||||
|
part(f, &mut fst, "MANAGE")?;
|
||||||
|
}
|
||||||
|
|
||||||
|
f.write_char(')')
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Perms {
|
||||||
|
pub fn get_for<'a, I: Iterator<Item=&'a PermRule>>(privs: &'a PrivilegesBuf, rules: I) -> Self {
|
||||||
|
let mut disclose = false;
|
||||||
|
let mut read = false;
|
||||||
|
let mut write = false;
|
||||||
|
let mut manage = false;
|
||||||
|
for rule in rules {
|
||||||
|
if rule.match_perm(&privs.disclose) {
|
||||||
|
disclose = true;
|
||||||
|
}
|
||||||
|
if rule.match_perm(&privs.read) {
|
||||||
|
read = true;
|
||||||
|
}
|
||||||
|
if rule.match_perm(&privs.write) {
|
||||||
|
write = true;
|
||||||
|
}
|
||||||
|
if rule.match_perm(&privs.manage) {
|
||||||
|
manage = true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
Self { disclose, read, write, manage }
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn empty() -> Self {
|
||||||
|
Self {
|
||||||
|
disclose: false,
|
||||||
|
read: false,
|
||||||
|
write: false,
|
||||||
|
manage: false,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
pub struct AccessControl {
|
pub struct AccessControl {
|
||||||
internal: HashMap<RoleIdentifier, Role>,
|
internal: HashMap<RoleIdentifier, Role>,
|
||||||
}
|
}
|
||||||
@ -566,6 +642,27 @@ impl TryFrom<String> for PermRule {
|
|||||||
mod tests {
|
mod tests {
|
||||||
use super::*;
|
use super::*;
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn display_perm() {
|
||||||
|
let mut perm = Perms {
|
||||||
|
disclose: false,
|
||||||
|
read: false,
|
||||||
|
write: false,
|
||||||
|
manage: false
|
||||||
|
};
|
||||||
|
println!("{}", perm);
|
||||||
|
assert_eq!("()", format!("{}", perm));
|
||||||
|
|
||||||
|
perm.disclose = true;
|
||||||
|
println!("{}", perm);
|
||||||
|
assert_eq!("( DISCLOSE )", format!("{}", perm));
|
||||||
|
|
||||||
|
perm.read = true;
|
||||||
|
perm.write = true;
|
||||||
|
println!("{}", perm);
|
||||||
|
assert_eq!("( DISCLOSE | READ | WRITE )", format!("{}", perm));
|
||||||
|
}
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn permission_ord_test() {
|
fn permission_ord_test() {
|
||||||
assert!(PermissionBuf::from_string("bffh.perm".to_string())
|
assert!(PermissionBuf::from_string("bffh.perm".to_string())
|
||||||
|
@ -12,7 +12,7 @@ use paho_mqtt::AsyncClient;
|
|||||||
use futures::future::BoxFuture;
|
use futures::future::BoxFuture;
|
||||||
|
|
||||||
use futures_signals::signal::{Signal, Mutable, MutableSignalCloned};
|
use futures_signals::signal::{Signal, Mutable, MutableSignalCloned};
|
||||||
use crate::machine::{Machine, ReturnToken};
|
use crate::machine::Machine;
|
||||||
use crate::db::machine::MachineState;
|
use crate::db::machine::MachineState;
|
||||||
use crate::db::user::{User, UserId, UserData};
|
use crate::db::user::{User, UserId, UserData};
|
||||||
|
|
||||||
@ -22,7 +22,7 @@ use crate::error::Result;
|
|||||||
use crate::config::Config;
|
use crate::config::Config;
|
||||||
|
|
||||||
pub trait Sensor {
|
pub trait Sensor {
|
||||||
fn run_sensor(&mut self) -> BoxFuture<'static, (Option<User>, MachineState)>;
|
fn run_sensor(&mut self) -> BoxFuture<'static, (Option<UserId>, MachineState)>;
|
||||||
}
|
}
|
||||||
|
|
||||||
type BoxSensor = Box<dyn Sensor + Send>;
|
type BoxSensor = Box<dyn Sensor + Send>;
|
||||||
@ -31,10 +31,9 @@ pub struct Initiator {
|
|||||||
log: Logger,
|
log: Logger,
|
||||||
signal: MutableSignalCloned<Option<Machine>>,
|
signal: MutableSignalCloned<Option<Machine>>,
|
||||||
machine: Option<Machine>,
|
machine: Option<Machine>,
|
||||||
future: Option<BoxFuture<'static, (Option<User>, MachineState)>>,
|
future: Option<BoxFuture<'static, (Option<UserId>, MachineState)>>,
|
||||||
// TODO: Prepare the init for async state change requests.
|
// TODO: Prepare the init for async state change requests.
|
||||||
state_change_fut: Option<BoxFuture<'static, Result<ReturnToken>>>,
|
state_change_fut: Option<BoxFuture<'static, Result<()>>>,
|
||||||
token: Option<ReturnToken>,
|
|
||||||
sensor: BoxSensor,
|
sensor: BoxSensor,
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -46,7 +45,6 @@ impl Initiator {
|
|||||||
machine: None,
|
machine: None,
|
||||||
future: None,
|
future: None,
|
||||||
state_change_fut: None,
|
state_change_fut: None,
|
||||||
token: None,
|
|
||||||
sensor: sensor,
|
sensor: sensor,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -92,13 +90,11 @@ impl Future for Initiator {
|
|||||||
debug!(this.log, "State change blocked");
|
debug!(this.log, "State change blocked");
|
||||||
return Poll::Pending;
|
return Poll::Pending;
|
||||||
},
|
},
|
||||||
Poll::Ready(Ok(tok)) => {
|
Poll::Ready(Ok(rt)) => {
|
||||||
debug!(this.log, "State change returned ok");
|
debug!(this.log, "State change returned ok");
|
||||||
// Explicity drop the future
|
// Explicity drop the future
|
||||||
let _ = this.state_change_fut.take();
|
let _ = this.state_change_fut.take();
|
||||||
|
|
||||||
// Store the given return token for future use
|
|
||||||
this.token.replace(tok);
|
|
||||||
}
|
}
|
||||||
Poll::Ready(Err(e)) => {
|
Poll::Ready(Err(e)) => {
|
||||||
info!(this.log, "State change returned err: {}", e);
|
info!(this.log, "State change returned err: {}", e);
|
||||||
@ -117,7 +113,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| {
|
||||||
machine.request_state_change(user.as_ref(), state)
|
machine.request_state_change(user.as_ref(), state).unwrap()
|
||||||
});
|
});
|
||||||
this.state_change_fut = f;
|
this.state_change_fut = f;
|
||||||
}
|
}
|
||||||
@ -151,12 +147,12 @@ fn load_single(
|
|||||||
log: &Logger,
|
log: &Logger,
|
||||||
name: &String,
|
name: &String,
|
||||||
module_name: &String,
|
module_name: &String,
|
||||||
_params: &HashMap<String, String>
|
params: &HashMap<String, String>
|
||||||
) -> Option<BoxSensor>
|
) -> Option<BoxSensor>
|
||||||
{
|
{
|
||||||
match module_name.as_ref() {
|
match module_name.as_ref() {
|
||||||
"Dummy" => {
|
"Dummy" => {
|
||||||
Some(Box::new(Dummy::new(log)))
|
Some(Box::new(Dummy::new(log, params)))
|
||||||
},
|
},
|
||||||
_ => {
|
_ => {
|
||||||
error!(log, "No initiator found with name \"{}\", configured as \"{}\"",
|
error!(log, "No initiator found with name \"{}\", configured as \"{}\"",
|
||||||
@ -169,34 +165,47 @@ fn load_single(
|
|||||||
pub struct Dummy {
|
pub struct Dummy {
|
||||||
log: Logger,
|
log: Logger,
|
||||||
step: bool,
|
step: bool,
|
||||||
|
userid: Option<UserId>,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Dummy {
|
impl Dummy {
|
||||||
pub fn new(log: &Logger) -> Self {
|
pub fn new(log: &Logger, params: &HashMap<String, String>) -> Self {
|
||||||
Self { log: log.new(o!("module" => "Dummy Initiator")), step: false }
|
let userid = if let Some(uid) = params.get("uid") {
|
||||||
|
Some(UserId::new(uid.clone(),
|
||||||
|
params.get("subuid").map(String::from),
|
||||||
|
params.get("realm").map(String::from)
|
||||||
|
))
|
||||||
|
} else {
|
||||||
|
None
|
||||||
|
};
|
||||||
|
|
||||||
|
let log = log.new(o!("module" => "Dummy Initiator"));
|
||||||
|
debug!(log, "Constructed dummy initiator with params: {:?}", params);
|
||||||
|
|
||||||
|
Self { log, step: false, userid }
|
||||||
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Sensor for Dummy {
|
impl Sensor for Dummy {
|
||||||
fn run_sensor(&mut self)
|
fn run_sensor(&mut self)
|
||||||
-> BoxFuture<'static, (Option<User>, MachineState)>
|
-> BoxFuture<'static, (Option<UserId>, MachineState)>
|
||||||
{
|
{
|
||||||
let step = self.step;
|
let step = self.step;
|
||||||
self.step = !step;
|
self.step = !step;
|
||||||
|
|
||||||
info!(self.log, "Kicking off new dummy initiator state change: {}", step);
|
info!(self.log, "Kicking off new dummy initiator state change: {}, {:?}",
|
||||||
|
if step { "free" } else { "used" },
|
||||||
|
&self.userid
|
||||||
|
);
|
||||||
|
|
||||||
|
let userid = self.userid.clone();
|
||||||
let f = async move {
|
let f = async move {
|
||||||
Timer::after(std::time::Duration::from_secs(1)).await;
|
Timer::after(std::time::Duration::from_secs(1)).await;
|
||||||
if step {
|
if step {
|
||||||
return (None, MachineState::free());
|
return (userid.clone(), MachineState::free());
|
||||||
} else {
|
} else {
|
||||||
let user = User::new(
|
return (userid.clone(), MachineState::used(userid.clone()));
|
||||||
UserId::new("test".to_string(), None, None),
|
|
||||||
UserData::new(vec![crate::db::access::RoleIdentifier::local_from_str("lmdb".to_string(), "testrole".to_string())], 0),
|
|
||||||
);
|
|
||||||
let id = user.id.clone();
|
|
||||||
return (Some(user), MachineState::used(Some(id)));
|
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
179
src/machine.rs
179
src/machine.rs
@ -23,10 +23,11 @@ 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, UserDB};
|
||||||
use crate::db::access::AccessControl;
|
use crate::db::access::{AccessControl, Perms};
|
||||||
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};
|
||||||
|
use crate::Error::Denied;
|
||||||
|
|
||||||
use crate::network::MachineMap;
|
use crate::network::MachineMap;
|
||||||
use crate::space;
|
use crate::space;
|
||||||
@ -64,6 +65,8 @@ pub struct Machine {
|
|||||||
pub desc: MachineDescription,
|
pub desc: MachineDescription,
|
||||||
|
|
||||||
access_control: Arc<AccessControl>,
|
access_control: Arc<AccessControl>,
|
||||||
|
userdb: Arc<UserDB>,
|
||||||
|
log: Logger,
|
||||||
|
|
||||||
inner: Arc<Mutex<Inner>>,
|
inner: Arc<Mutex<Inner>>,
|
||||||
}
|
}
|
||||||
@ -73,7 +76,9 @@ impl Machine {
|
|||||||
inner: Inner,
|
inner: Inner,
|
||||||
id: MachineIdentifier,
|
id: MachineIdentifier,
|
||||||
desc: MachineDescription,
|
desc: MachineDescription,
|
||||||
access_control: Arc<AccessControl>
|
access_control: Arc<AccessControl>,
|
||||||
|
userdb: Arc<UserDB>,
|
||||||
|
log: Logger,
|
||||||
) -> Self
|
) -> Self
|
||||||
{
|
{
|
||||||
Self {
|
Self {
|
||||||
@ -81,6 +86,8 @@ impl Machine {
|
|||||||
inner: Arc::new(Mutex::new(inner)),
|
inner: Arc::new(Mutex::new(inner)),
|
||||||
desc,
|
desc,
|
||||||
access_control,
|
access_control,
|
||||||
|
userdb,
|
||||||
|
log,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -90,9 +97,12 @@ impl Machine {
|
|||||||
state: MachineState,
|
state: MachineState,
|
||||||
db: Arc<MachineDB>,
|
db: Arc<MachineDB>,
|
||||||
access_control: Arc<AccessControl>,
|
access_control: Arc<AccessControl>,
|
||||||
|
userdb: Arc<UserDB>,
|
||||||
|
log: &Logger,
|
||||||
) -> Machine
|
) -> Machine
|
||||||
{
|
{
|
||||||
Self::new(Inner::new(id.clone(), state, db), id, desc, access_control)
|
let log = log.new(o!("machine" => id.clone()));
|
||||||
|
Self::new(Inner::new(id.clone(), state, db), id, desc, access_control, userdb, log)
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn do_state_change(&self, new_state: MachineState)
|
pub fn do_state_change(&self, new_state: MachineState)
|
||||||
@ -109,13 +119,110 @@ impl Machine {
|
|||||||
Box::pin(f)
|
Box::pin(f)
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn request_state_change(&mut self, user: Option<&User>, new_state: MachineState)
|
pub fn request_state_change(&mut self, userid: Option<&UserId>, new_state: MachineState)
|
||||||
-> BoxFuture<'static, Result<ReturnToken>>
|
-> Result<BoxFuture<'static, Result<()>>>
|
||||||
{
|
{
|
||||||
let inner = self.inner.clone();
|
let inner = self.inner.clone();
|
||||||
Box::pin(async move {
|
let perms = if let Some(userid) = userid {
|
||||||
Ok(ReturnToken::new(inner))
|
if let Some(user) = self.userdb.get_user(&userid.uid)? {
|
||||||
})
|
let roles = self.access_control.collect_permrules(&user.data)?;
|
||||||
|
Perms::get_for(&self.desc.privs, roles.iter())
|
||||||
|
} else {
|
||||||
|
Perms::empty()
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
Perms::empty()
|
||||||
|
};
|
||||||
|
|
||||||
|
debug!(self.log, "State change requested: {:?}, {:?}, {}",
|
||||||
|
&userid,
|
||||||
|
new_state,
|
||||||
|
perms,
|
||||||
|
);
|
||||||
|
|
||||||
|
if perms.manage {
|
||||||
|
Ok(Box::pin(async move {
|
||||||
|
let mut guard = inner.lock().await;
|
||||||
|
guard.do_state_change(new_state);
|
||||||
|
Ok(())
|
||||||
|
}))
|
||||||
|
} else if perms.write {
|
||||||
|
let userid = userid.map(|u| u.clone());
|
||||||
|
let f = async move {
|
||||||
|
let mut guard = inner.lock().await;
|
||||||
|
// Match (current state, new state) for permission
|
||||||
|
if
|
||||||
|
match (guard.read_state().lock_ref().state.clone(), &new_state.state) {
|
||||||
|
// Going from available to used by the person requesting is okay.
|
||||||
|
(Status::Free, Status::InUse(who))
|
||||||
|
// Check that the person requesting does not request for somebody else.
|
||||||
|
// *That* is manage privilege.
|
||||||
|
if who.as_ref() == userid.as_ref() => true,
|
||||||
|
|
||||||
|
// Reserving things for ourself is okay.
|
||||||
|
(Status::Free, Status::Reserved(whom))
|
||||||
|
if userid.as_ref() == Some(whom) => true,
|
||||||
|
|
||||||
|
// Returning things we've been using is okay. This includes both if
|
||||||
|
// they're being freed or marked as to be checked.
|
||||||
|
(Status::InUse(who), Status::Free | Status::ToCheck(_))
|
||||||
|
if who.as_ref() == userid.as_ref() => true,
|
||||||
|
|
||||||
|
// Un-reserving things we reserved is okay
|
||||||
|
(Status::Reserved(whom), Status::Free)
|
||||||
|
if userid.as_ref() == Some(&whom) => true,
|
||||||
|
// Using things that we've reserved is okay. But the person requesting
|
||||||
|
// that has to be the person that reserved the machine. Otherwise
|
||||||
|
// somebody could make a machine reserved by a different user as used by
|
||||||
|
// that different user but use it themself.
|
||||||
|
(Status::Reserved(whom), Status::InUse(who))
|
||||||
|
if userid.as_ref() == Some(&whom)
|
||||||
|
&& who.as_ref() == Some(&whom)
|
||||||
|
=> true,
|
||||||
|
|
||||||
|
// Default is deny.
|
||||||
|
_ => false
|
||||||
|
}
|
||||||
|
{
|
||||||
|
// Permission granted
|
||||||
|
guard.do_state_change(new_state);
|
||||||
|
Ok(())
|
||||||
|
} else {
|
||||||
|
Err(Denied)
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
Ok(Box::pin(f))
|
||||||
|
} else {
|
||||||
|
let userid = userid.map(|u| u.clone());
|
||||||
|
let f = async move {
|
||||||
|
let mut guard = inner.lock().await;
|
||||||
|
// Match (current state, new state) for permission
|
||||||
|
if
|
||||||
|
match (guard.read_state().lock_ref().state.clone(), &new_state.state) {
|
||||||
|
// Returning things we've been using is okay. This includes both if
|
||||||
|
// they're being freed or marked as to be checked.
|
||||||
|
(Status::InUse(who), Status::Free | Status::ToCheck(_))
|
||||||
|
if who.as_ref() == userid.as_ref() => true,
|
||||||
|
|
||||||
|
// Un-reserving things we reserved is okay
|
||||||
|
(Status::Reserved(whom), Status::Free)
|
||||||
|
if userid.as_ref() == Some(&whom) => true,
|
||||||
|
|
||||||
|
// Default is deny.
|
||||||
|
_ => false
|
||||||
|
}
|
||||||
|
{
|
||||||
|
// Permission granted
|
||||||
|
guard.do_state_change(new_state);
|
||||||
|
Ok(())
|
||||||
|
} else {
|
||||||
|
Err(Denied)
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
Ok(Box::pin(f))
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub async fn get_status(&self) -> Status {
|
pub async fn get_status(&self) -> Status {
|
||||||
@ -244,39 +351,6 @@ impl Inner {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
//pub type ReturnToken = futures::channel::oneshot::Sender<()>;
|
|
||||||
pub struct ReturnToken {
|
|
||||||
f: Option<BoxFuture<'static, ()>>,
|
|
||||||
}
|
|
||||||
|
|
||||||
impl ReturnToken {
|
|
||||||
pub fn new(inner: Arc<Mutex<Inner>>) -> Self {
|
|
||||||
let f = async move {
|
|
||||||
let mut guard = inner.lock().await;
|
|
||||||
guard.reset_state();
|
|
||||||
};
|
|
||||||
|
|
||||||
Self { f: Some(Box::pin(f)) }
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
impl Future for ReturnToken {
|
|
||||||
type Output = (); // FIXME: This should probably be a Result<(), Error>
|
|
||||||
|
|
||||||
fn poll(mut self: Pin<&mut Self>, cx: &mut Context) -> Poll<Self::Output> {
|
|
||||||
let mut this = &mut *self;
|
|
||||||
|
|
||||||
match this.f.as_mut().map(|f| Future::poll(Pin::new(f), cx)) {
|
|
||||||
None => Poll::Ready(()), // TODO: Is it saner to return Pending here? This can only happen after the future completed
|
|
||||||
Some(Poll::Pending) => Poll::Pending,
|
|
||||||
Some(Poll::Ready(())) => {
|
|
||||||
let _ = this.f.take(); // Remove the future to not poll after completion
|
|
||||||
Poll::Ready(())
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)]
|
#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)]
|
||||||
/// A description of a machine
|
/// A description of a machine
|
||||||
///
|
///
|
||||||
@ -309,20 +383,23 @@ pub fn load(config: &crate::config::Config, db: Databases, log: &Logger)
|
|||||||
{
|
{
|
||||||
let mut map = config.machines.clone();
|
let mut map = config.machines.clone();
|
||||||
let access_control = db.access;
|
let access_control = db.access;
|
||||||
let db = db.machine;
|
let machinedb = db.machine;
|
||||||
|
let userdb = db.userdb;
|
||||||
|
|
||||||
let it = map.drain()
|
let it = map.drain()
|
||||||
.map(|(k,v)| {
|
.map(|(k,v)| {
|
||||||
// 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) = machinedb.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(),
|
(k.clone(),
|
||||||
Machine::construct(
|
Machine::construct(
|
||||||
k,
|
k,
|
||||||
v,
|
v,
|
||||||
state,
|
state,
|
||||||
db.clone(),
|
machinedb.clone(),
|
||||||
access_control.clone()
|
access_control.clone(),
|
||||||
|
userdb.clone(),
|
||||||
|
log,
|
||||||
))
|
))
|
||||||
} 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);
|
||||||
@ -331,8 +408,10 @@ pub fn load(config: &crate::config::Config, db: Databases, log: &Logger)
|
|||||||
k,
|
k,
|
||||||
v,
|
v,
|
||||||
MachineState::new(),
|
MachineState::new(),
|
||||||
db.clone(),
|
machinedb.clone(),
|
||||||
access_control.clone(),
|
access_control.clone(),
|
||||||
|
userdb.clone(),
|
||||||
|
log,
|
||||||
))
|
))
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
Loading…
Reference in New Issue
Block a user