mirror of
https://gitlab.com/fabinfra/fabaccess/bffh.git
synced 2024-11-26 08:34:55 +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
|
/// Default implementation which adapter may overwrite with more efficient specialized
|
||||||
/// implementations.
|
/// implementations.
|
||||||
fn check(&self, user: &User, permID: &PermIdentifier) -> Result<bool> {
|
fn check<P: AsRef<Permission>>(&self, user: &User, perm: &P) -> Result<bool> {
|
||||||
self.check_roles(&user.roles, permID)
|
self.check_roles(&user.roles, perm)
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Check if a given permission is granted by any of the given roles or their respective
|
/// 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
|
/// A Default implementation exists which adapter may overwrite with more efficient specialized
|
||||||
/// implementations.
|
/// 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
|
// Tally all roles. Makes dependent roles easier
|
||||||
let mut roleset = HashSet::new();
|
let mut roleset = HashSet::new();
|
||||||
for roleID in roles {
|
for roleID in roles {
|
||||||
@ -51,8 +51,8 @@ pub trait RoleDB {
|
|||||||
|
|
||||||
// Iter all unique role->permissions we've found and early return on match.
|
// Iter all unique role->permissions we've found and early return on match.
|
||||||
for role in roleset.iter() {
|
for role in roleset.iter() {
|
||||||
for perm in role.permissions.iter() {
|
for perm_rule in role.permissions.iter() {
|
||||||
if permID == perm {
|
if perm_rule.match_perm(perm) {
|
||||||
return Ok(true);
|
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
|
/// 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
|
/// you are allowed to manage a machine you are then also allowed to use it and so on
|
||||||
parents: Vec<RoleIdentifier>,
|
parents: Vec<RoleIdentifier>,
|
||||||
permissions: Vec<PermIdentifier>,
|
permissions: Vec<PermRule>,
|
||||||
}
|
}
|
||||||
|
|
||||||
type SourceID = String;
|
type SourceID = String;
|
||||||
@ -186,16 +186,17 @@ fn is_sep_char(c: char) -> bool {
|
|||||||
c == '.'
|
c == '.'
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[derive(Debug, Clone, Eq, PartialEq, Serialize, Deserialize)]
|
||||||
/// A set of privileges to a thing
|
/// A set of privileges to a thing
|
||||||
pub struct PrivilegesBuf {
|
pub struct PrivilegesBuf {
|
||||||
/// Which permission is required to know about the existance of this thing
|
/// 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
|
/// Which permission is required to read this thing
|
||||||
read: PermissionBuf,
|
pub read: PermissionBuf,
|
||||||
/// Which permission is required to write parts of this thing
|
/// 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
|
/// Which permission is required to manage all parts of this thing
|
||||||
manage: PermissionBuf
|
pub manage: PermissionBuf
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Debug, Clone, PartialEq, Eq, Hash, Serialize, Deserialize)]
|
#[derive(Debug, Clone, PartialEq, Eq, Hash, Serialize, Deserialize)]
|
||||||
@ -341,11 +342,11 @@ pub enum PermRule {
|
|||||||
|
|
||||||
impl PermRule {
|
impl PermRule {
|
||||||
// Does this rule match that permission
|
// Does this rule match that permission
|
||||||
fn match_perm<P: AsRef<Permission>>(rule: &PermRule, perm: P) -> bool {
|
fn match_perm<P: AsRef<Permission>>(&self, perm: &P) -> bool {
|
||||||
match rule {
|
match self {
|
||||||
PermRule::Base(base) => base.as_permission() == perm.as_ref(),
|
PermRule::Base(ref base) => base.as_permission() == perm.as_ref(),
|
||||||
PermRule::Children(parent) => parent.as_permission() > perm.as_ref() ,
|
PermRule::Children(ref parent) => parent.as_permission() > perm.as_ref() ,
|
||||||
PermRule::Subtree(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())
|
assert!(PermissionBuf::from_string("bffh.perm".to_string())
|
||||||
> PermissionBuf::from_string("bffh.perm.sub".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::config::Settings;
|
||||||
use crate::error::Result;
|
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};
|
use crate::db::user::{UserIdentifier, User};
|
||||||
|
|
||||||
#[derive(Clone, Debug)]
|
#[derive(Clone, Debug)]
|
||||||
@ -34,7 +34,9 @@ impl Internal {
|
|||||||
|
|
||||||
/// Check if a given user has the given permission
|
/// Check if a given user has the given permission
|
||||||
#[allow(unused)]
|
#[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
|
// Tally all roles. Makes dependent roles easier
|
||||||
let mut roles = HashSet::new();
|
let mut roles = HashSet::new();
|
||||||
for roleID in user.roles.iter() {
|
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.
|
// Iter all unique role->permissions we've found and early return on match.
|
||||||
// TODO: Change this for negative permissions?
|
// TODO: Change this for negative permissions?
|
||||||
for role in roles.iter() {
|
for role in roles.iter() {
|
||||||
for perm in role.permissions.iter() {
|
for perm_rule in role.permissions.iter() {
|
||||||
if permID == perm {
|
if perm_rule.match_perm(perm) {
|
||||||
return Ok(true);
|
return Ok(true);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -201,9 +203,9 @@ impl Internal {
|
|||||||
}
|
}
|
||||||
|
|
||||||
impl RoleDB for 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()?;
|
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>> {
|
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::Signal;
|
||||||
use futures_signals::signal::SignalExt;
|
use futures_signals::signal::SignalExt;
|
||||||
use futures_signals::signal::Mutable;
|
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
|
/// machine, checking that the user who wants the machine (de)activated has the required
|
||||||
/// permissions.
|
/// permissions.
|
||||||
pub struct Machine {
|
pub struct Machine {
|
||||||
/// Computer-readable identifier for this machine
|
/// Descriptor of the machine
|
||||||
id: MachineIdentifier,
|
desc: MachineDescription,
|
||||||
|
|
||||||
/// 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,
|
|
||||||
|
|
||||||
/// The state of the machine as bffh thinks the machine *should* be in.
|
/// The state of the machine as bffh thinks the machine *should* be in.
|
||||||
///
|
///
|
||||||
@ -34,11 +30,9 @@ pub struct Machine {
|
|||||||
}
|
}
|
||||||
|
|
||||||
impl Machine {
|
impl Machine {
|
||||||
pub fn new(id: Uuid, name: String, perm: access::PermIdentifier) -> Machine {
|
pub fn new(desc: MachineDescription, perm: access::PermIdentifier) -> Machine {
|
||||||
Machine {
|
Machine {
|
||||||
id: id,
|
desc: desc,
|
||||||
name: name,
|
|
||||||
perm: perm,
|
|
||||||
state: Mutable::new(MachineState { state: Status::Free}),
|
state: Mutable::new(MachineState { state: Status::Free}),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -64,7 +58,8 @@ impl Machine {
|
|||||||
, who: &User
|
, who: &User
|
||||||
) -> Result<bool>
|
) -> 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()) });
|
self.state.set(MachineState { state: Status::InUse(who.id.clone()) });
|
||||||
return Ok(true);
|
return Ok(true);
|
||||||
} else {
|
} else {
|
||||||
@ -76,3 +71,20 @@ impl Machine {
|
|||||||
self.state.set(MachineState { state })
|
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