diff --git a/src/db/access.rs b/src/db/access.rs index c670fff..7c747ab 100644 --- a/src/db/access.rs +++ b/src/db/access.rs @@ -33,8 +33,8 @@ pub trait RoleDB { /// /// Default implementation which adapter may overwrite with more efficient specialized /// implementations. - fn check(&self, user: &User, permID: &PermIdentifier) -> Result { - self.check_roles(&user.roles, permID) + fn check>(&self, user: &User, perm: &P) -> Result { + self.check_roles(&user.roles, perm) } /// Check if a given permission is granted by any of the given roles or their respective @@ -42,7 +42,7 @@ pub trait RoleDB { /// /// A Default implementation exists which adapter may overwrite with more efficient specialized /// implementations. - fn check_roles(&self, roles: &[RoleIdentifier], permID: &PermIdentifier) -> Result { + fn check_roles>(&self, roles: &[RoleIdentifier], perm: &P) -> Result { // Tally all roles. Makes dependent roles easier let mut roleset = HashSet::new(); for roleID in roles { @@ -51,8 +51,8 @@ pub trait RoleDB { // Iter all unique role->permissions we've found and early return on match. for role in roleset.iter() { - for perm in role.permissions.iter() { - if permID == perm { + for perm_rule in role.permissions.iter() { + if perm_rule.match_perm(perm) { return Ok(true); } } @@ -104,7 +104,7 @@ pub struct Role { /// level of access sets the lower levels of access as parent, inheriting their permission; if /// you are allowed to manage a machine you are then also allowed to use it and so on parents: Vec, - permissions: Vec, + permissions: Vec, } type SourceID = String; @@ -186,16 +186,17 @@ fn is_sep_char(c: char) -> bool { c == '.' } +#[derive(Debug, Clone, Eq, PartialEq, Serialize, Deserialize)] /// A set of privileges to a thing pub struct PrivilegesBuf { /// Which permission is required to know about the existance of this thing - disclose: PermissionBuf, + pub disclose: PermissionBuf, /// Which permission is required to read this thing - read: PermissionBuf, + pub read: PermissionBuf, /// Which permission is required to write parts of this thing - write: PermissionBuf, + pub write: PermissionBuf, /// Which permission is required to manage all parts of this thing - manage: PermissionBuf + pub manage: PermissionBuf } #[derive(Debug, Clone, PartialEq, Eq, Hash, Serialize, Deserialize)] @@ -341,11 +342,11 @@ pub enum PermRule { impl PermRule { // Does this rule match that permission - fn match_perm>(rule: &PermRule, perm: P) -> bool { - match rule { - PermRule::Base(base) => base.as_permission() == perm.as_ref(), - PermRule::Children(parent) => parent.as_permission() > perm.as_ref() , - PermRule::Subtree(parent) => parent.as_permission() >= perm.as_ref(), + fn match_perm>(&self, perm: &P) -> bool { + match self { + PermRule::Base(ref base) => base.as_permission() == perm.as_ref(), + PermRule::Children(ref parent) => parent.as_permission() > perm.as_ref() , + PermRule::Subtree(ref parent) => parent.as_permission() >= perm.as_ref(), } } } @@ -372,4 +373,21 @@ mod tests { assert!(PermissionBuf::from_string("bffh.perm".to_string()) > PermissionBuf::from_string("bffh.perm.sub".to_string())); } + + #[test] + fn permission_simple_check_test() { + let perm = PermissionBuf::from_string("test.perm".to_string()); + let rule = PermRule::Base(perm.clone()); + + assert!(rule.match_perm(&perm)); + } + + #[test] + #[should_panic] + fn permission_children_checks_only_children() { + let perm = PermissionBuf::from_string("test.perm".to_string()); + let rule = PermRule::Children(perm.clone()); + + assert!(rule.match_perm(&perm)); + } } diff --git a/src/db/access/internal.rs b/src/db/access/internal.rs index 806a12b..03d839c 100644 --- a/src/db/access/internal.rs +++ b/src/db/access/internal.rs @@ -16,7 +16,7 @@ use lmdb::{Environment, Transaction, RwTransaction, Cursor}; use crate::config::Settings; use crate::error::Result; -use crate::db::access::{PermIdentifier, Role, RoleIdentifier, RoleDB}; +use crate::db::access::{Permission, Role, RoleIdentifier, RoleDB}; use crate::db::user::{UserIdentifier, User}; #[derive(Clone, Debug)] @@ -34,7 +34,9 @@ impl Internal { /// Check if a given user has the given permission #[allow(unused)] - pub fn _check(&self, txn: &T, user: &User, permID: &PermIdentifier) -> Result { + pub fn _check>(&self, txn: &T, user: &User, perm: &P) + -> Result + { // Tally all roles. Makes dependent roles easier let mut roles = HashSet::new(); for roleID in user.roles.iter() { @@ -44,8 +46,8 @@ impl Internal { // Iter all unique role->permissions we've found and early return on match. // TODO: Change this for negative permissions? for role in roles.iter() { - for perm in role.permissions.iter() { - if permID == perm { + for perm_rule in role.permissions.iter() { + if perm_rule.match_perm(perm) { return Ok(true); } } @@ -201,9 +203,9 @@ impl Internal { } impl RoleDB for Internal { - fn check(&self, user: &User, permID: &PermIdentifier) -> Result { + fn check>(&self, user: &User, perm: &P) -> Result { let txn = self.env.begin_ro_txn()?; - self._check(&txn, user, permID) + self._check(&txn, user, perm) } fn get_role(&self, roleID: &RoleIdentifier) -> Result> { diff --git a/src/machine.rs b/src/machine.rs index cdfb64d..9a9cf77 100644 --- a/src/machine.rs +++ b/src/machine.rs @@ -1,3 +1,5 @@ +use serde::{Serialize, Deserialize}; + use futures_signals::signal::Signal; use futures_signals::signal::SignalExt; use futures_signals::signal::Mutable; @@ -17,14 +19,8 @@ use crate::db::machine::{MachineIdentifier, Status, MachineState}; /// machine, checking that the user who wants the machine (de)activated has the required /// permissions. pub struct Machine { - /// Computer-readable identifier for this machine - id: MachineIdentifier, - - /// The human-readable name of the machine. Does not need to be unique - name: String, - - /// The required permissions to use this machine. - perm: access::PermIdentifier, + /// Descriptor of the machine + desc: MachineDescription, /// The state of the machine as bffh thinks the machine *should* be in. /// @@ -34,11 +30,9 @@ pub struct Machine { } impl Machine { - pub fn new(id: Uuid, name: String, perm: access::PermIdentifier) -> Machine { + pub fn new(desc: MachineDescription, perm: access::PermIdentifier) -> Machine { Machine { - id: id, - name: name, - perm: perm, + desc: desc, state: Mutable::new(MachineState { state: Status::Free}), } } @@ -64,7 +58,8 @@ impl Machine { , who: &User ) -> Result { - if pp.check(who, &self.perm)? { + // TODO: Check different levels + if pp.check(who, &self.desc.privs.write)? { self.state.set(MachineState { state: Status::InUse(who.id.clone()) }); return Ok(true); } else { @@ -76,3 +71,20 @@ impl Machine { self.state.set(MachineState { state }) } } + +#[derive(Debug, Clone, Serialize, Deserialize)] +/// A description of a machine +/// +/// This is the struct that a machine is serialized to/from. +/// Combining this with the actual state of the system will return a machine +pub struct MachineDescription { + /// The main machine identifier. This must be unique. + id: MachineIdentifier, + /// The name of the machine. Doesn't need to be unique but is what humans will be presented. + name: String, + /// An optional description of the Machine. + description: Option, + + /// The permission required + privs: access::PrivilegesBuf, +}