mirror of
https://gitlab.com/fabinfra/fabaccess/bffh.git
synced 2024-12-22 19:53:49 +01:00
Permission checking upgrades
This commit is contained in:
parent
b7421528c6
commit
448cbbc98a
@ -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<bool> {
|
||||
self.check_roles(&user.roles, permID)
|
||||
fn check<P: AsRef<Permission>>(&self, user: &User, perm: &P) -> Result<bool> {
|
||||
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<bool> {
|
||||
fn check_roles<P: AsRef<Permission>>(&self, roles: &[RoleIdentifier], perm: &P) -> Result<bool> {
|
||||
// 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<RoleIdentifier>,
|
||||
permissions: Vec<PermIdentifier>,
|
||||
permissions: Vec<PermRule>,
|
||||
}
|
||||
|
||||
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<P: AsRef<Permission>>(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<P: AsRef<Permission>>(&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));
|
||||
}
|
||||
}
|
||||
|
@ -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<T: Transaction>(&self, txn: &T, user: &User, permID: &PermIdentifier) -> Result<bool> {
|
||||
pub fn _check<T: Transaction, P: AsRef<Permission>>(&self, txn: &T, user: &User, perm: &P)
|
||||
-> Result<bool>
|
||||
{
|
||||
// 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<bool> {
|
||||
fn check<P: AsRef<Permission>>(&self, user: &User, perm: &P) -> Result<bool> {
|
||||
let txn = self.env.begin_ro_txn()?;
|
||||
self._check(&txn, user, permID)
|
||||
self._check(&txn, user, perm)
|
||||
}
|
||||
|
||||
fn get_role(&self, roleID: &RoleIdentifier) -> Result<Option<Role>> {
|
||||
|
@ -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<bool>
|
||||
{
|
||||
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<String>,
|
||||
|
||||
/// The permission required
|
||||
privs: access::PrivilegesBuf,
|
||||
}
|
||||
|
Loading…
Reference in New Issue
Block a user