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;
|
|
|
|
|
2020-09-11 09:57:03 +02:00
|
|
|
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-11 09:57:03 +02:00
|
|
|
|
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
|
|
|
}
|