fabaccess-bffh/src/db/access.rs

109 lines
3.5 KiB
Rust
Raw Normal View History

2020-02-14 12:20:17 +01:00
//! Access control logic
//!
2020-10-26 12:58:55 +01:00
use std::fmt;
2020-09-10 11:50:19 +02:00
use std::collections::HashSet;
use std::convert::TryInto;
use std::path::{Path, PathBuf};
use std::fs;
use std::io::Write;
2020-10-23 16:35:10 +02:00
use std::sync::Arc;
2020-09-10 11:50:19 +02:00
use flexbuffers;
use serde::{Serialize, Deserialize};
2020-02-17 15:07:55 +01:00
use slog::Logger;
2020-10-23 16:35:10 +02:00
use lmdb::{Environment, Transaction, RwTransaction, Cursor};
2020-02-17 15:07:55 +01:00
2020-09-15 14:31:10 +02:00
use crate::config::Settings;
2020-09-10 11:50:19 +02:00
use crate::error::Result;
2020-02-18 16:55:19 +01:00
2020-10-26 12:58:55 +01:00
mod adapter_lmdb;
use adapter_lmdb::PermissionsDB;
pub use adapter_lmdb::init;
2020-09-11 10:18:43 +02:00
// FIXME: fabinfra/fabaccess/bffh#3
2020-09-17 10:51:51 +02:00
pub type UserIdentifier = u64;
pub type RoleIdentifier = u64;
pub type PermIdentifier = u64;
2020-02-18 16:55:19 +01:00
2020-10-23 16:35:10 +02:00
#[derive(Clone, Debug)]
pub struct Permissions {
pub inner: PermissionsDB,
env: Arc<Environment>,
}
impl Permissions {
pub fn new(inner: PermissionsDB, env: Arc<Environment>) -> Permissions {
Permissions { inner, env }
}
pub fn check(&self, userID: UserIdentifier, permID: PermIdentifier) -> Result<bool> {
let txn = self.env.begin_ro_txn()?;
self.inner.check(&txn, userID, permID)
}
2020-10-26 12:58:55 +01:00
pub fn get_role(&self, roleID: RoleIdentifier) -> Result<Option<Role>> {
let txn = self.env.begin_ro_txn()?;
self.inner.get_role(&txn, roleID)
}
2020-10-23 16:35:10 +02:00
}
/// A "Role" from the Authorization perspective
///
/// You can think of a role as a bundle of permissions relating to other roles. In most cases a
/// role represents a real-world education or apprenticeship, which gives a person the education
/// necessary to use a machine safely.
/// Roles are assigned permissions which in most cases evaluate to granting a person the right to
/// use certain (potentially) dangerous machines.
/// Using this indirection makes administration easier in certain ways; instead of maintaining
/// permissions on users directly the user is given a role after having been educated on the safety
/// of a machine; if later on a similar enough machine is put to use the administrator can just add
/// the permission for that machine to an already existing role instead of manually having to
/// assign to all users.
#[derive(Debug, Clone, PartialEq, Eq, Hash, Serialize, Deserialize)]
2020-10-26 12:58:55 +01:00
pub struct Role {
2020-10-23 16:35:10 +02:00
name: String,
/// A Role can have parents, inheriting all permissions
///
/// This makes situations where different levels of access are required easier: Each higher
/// 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>,
}
2020-10-26 12:58:55 +01:00
type SourceID = String;
/// Universal (relative) id of a role
enum RoleID {
/// The role comes from this instance
Local {
/// Locally unique name for the role. No other role at this instance no matter the source
/// may have the same name
name: String,
/// Role Source, i.e. the database the role comes from
source: SourceID,
},
/// The role comes from a federated instance
Remote {
/// Name of the role. This role is unique in that instance so the tuple (name, location)
/// refers to a unique role
name: String,
/// The federated instance this role comes from
location: String,
2020-09-10 11:50:19 +02:00
}
2020-10-26 12:58:55 +01:00
}
impl fmt::Display for RoleID {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
match *self {
RoleID::Local {name, source} => write!(f, "{}/{}@local", name, source),
RoleID::Remote {name, location} => write!(f, "{}@{}", name, location),
2020-09-10 12:32:33 +02:00
}
}
2020-09-10 10:39:46 +02:00
}