mirror of
https://gitlab.com/fabinfra/fabaccess/bffh.git
synced 2024-11-25 08:07:57 +01:00
Impl roles
This commit is contained in:
parent
d7467989ef
commit
a111a86266
@ -1,7 +1,8 @@
|
|||||||
use std::collections::HashMap;
|
use std::collections::{HashMap, HashSet};
|
||||||
use std::fmt;
|
use std::fmt;
|
||||||
use once_cell::sync::OnceCell;
|
use once_cell::sync::OnceCell;
|
||||||
use crate::authorization::permissions::PermRule;
|
use crate::authorization::permissions::{Permission, PermRule};
|
||||||
|
use crate::users::db::UserData;
|
||||||
|
|
||||||
static ROLES: OnceCell<HashMap<String, Role>> = OnceCell::new();
|
static ROLES: OnceCell<HashMap<String, Role>> = OnceCell::new();
|
||||||
|
|
||||||
@ -25,6 +26,78 @@ impl Roles {
|
|||||||
pub fn get(self, roleid: &str) -> Option<&Role> {
|
pub fn get(self, roleid: &str) -> Option<&Role> {
|
||||||
self.roles.get(roleid)
|
self.roles.get(roleid)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/// Tally a role dependency tree into a set
|
||||||
|
///
|
||||||
|
/// A Default implementation exists which adapter may overwrite with more efficient
|
||||||
|
/// implementations.
|
||||||
|
fn tally_role(&self, roles: &mut HashMap<String, Role>, role_id: &String) {
|
||||||
|
if let Some(role) = self.get(role_id) {
|
||||||
|
// Only check and tally parents of a role at the role itself if it's the first time we
|
||||||
|
// see it
|
||||||
|
if !roles.contains_key(role_id) {
|
||||||
|
for parent in role.parents.iter() {
|
||||||
|
self.tally_role(roles, parent);
|
||||||
|
}
|
||||||
|
|
||||||
|
roles.insert(role_id.clone(), role.clone());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fn collect_permrules(&self, user: &UserData) -> Vec<PermRule> {
|
||||||
|
let mut roleset = HashMap::new();
|
||||||
|
for role_id in user.roles.iter() {
|
||||||
|
self.tally_role(&mut roleset, role_id);
|
||||||
|
}
|
||||||
|
|
||||||
|
let mut output = Vec::new();
|
||||||
|
|
||||||
|
// Iter all unique role->permissions we've found and early return on match.
|
||||||
|
for (_roleid, role) in roleset.iter() {
|
||||||
|
output.extend(role.permissions.iter().cloned())
|
||||||
|
}
|
||||||
|
|
||||||
|
output
|
||||||
|
}
|
||||||
|
|
||||||
|
fn permitted_tally(&self,
|
||||||
|
roles: &mut HashSet<String>,
|
||||||
|
role_id: &String,
|
||||||
|
perm: &Permission
|
||||||
|
) -> bool {
|
||||||
|
if let Some(role) = self.get(role_id) {
|
||||||
|
// Only check and tally parents of a role at the role itself if it's the first time we
|
||||||
|
// see it
|
||||||
|
if !roles.contains(role_id) {
|
||||||
|
for perm_rule in role.permissions.iter() {
|
||||||
|
if perm_rule.match_perm(perm) {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
for parent in role.parents.iter() {
|
||||||
|
if self.permitted_tally(roles, parent, perm) {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
roles.insert(role_id.clone());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
false
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn is_permitted(&self, user: &UserData, perm: impl AsRef<Permission>) -> bool {
|
||||||
|
let mut seen = HashSet::new();
|
||||||
|
for role_id in user.roles.iter() {
|
||||||
|
if self.permitted_tally(&mut seen, role_id, perm.as_ref()) {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
false
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/// A "Role" from the Authorization perspective
|
/// A "Role" from the Authorization perspective
|
||||||
|
@ -10,7 +10,7 @@ use api::usersystem_capnp::user_system::{
|
|||||||
use crate::authorization::AuthorizationHandle;
|
use crate::authorization::AuthorizationHandle;
|
||||||
use crate::session::SessionHandle;
|
use crate::session::SessionHandle;
|
||||||
|
|
||||||
#[derive(Debug, Clone)]
|
#[derive(Clone)]
|
||||||
pub struct Users {
|
pub struct Users {
|
||||||
session: SessionHandle,
|
session: SessionHandle,
|
||||||
}
|
}
|
||||||
|
@ -9,6 +9,7 @@ use std::net::{SocketAddr, IpAddr, ToSocketAddrs};
|
|||||||
use std::str::FromStr;
|
use std::str::FromStr;
|
||||||
use serde::de::Error;
|
use serde::de::Error;
|
||||||
use crate::authorization::permissions::{PermRule, PrivilegesBuf};
|
use crate::authorization::permissions::{PermRule, PrivilegesBuf};
|
||||||
|
use crate::authorization::roles::Role;
|
||||||
|
|
||||||
type Result<T> = std::result::Result<T, serde_dhall::Error>;
|
type Result<T> = std::result::Result<T, serde_dhall::Error>;
|
||||||
|
|
||||||
@ -65,7 +66,7 @@ pub struct Config {
|
|||||||
pub db_path: PathBuf,
|
pub db_path: PathBuf,
|
||||||
pub auditlog_path: PathBuf,
|
pub auditlog_path: PathBuf,
|
||||||
|
|
||||||
pub roles: HashMap<String, RoleConfig>,
|
pub roles: HashMap<String, Role>,
|
||||||
|
|
||||||
#[serde(flatten)]
|
#[serde(flatten)]
|
||||||
pub tlsconfig: TlsListen,
|
pub tlsconfig: TlsListen,
|
||||||
@ -86,14 +87,6 @@ impl Config {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Debug, Clone, Serialize, Deserialize)]
|
|
||||||
pub struct RoleConfig {
|
|
||||||
#[serde(default = "Vec::new")]
|
|
||||||
pub parents: Vec<String>,
|
|
||||||
#[serde(default = "Vec::new")]
|
|
||||||
pub permissions: Vec<PermRule>,
|
|
||||||
}
|
|
||||||
|
|
||||||
#[derive(Debug, Clone, Serialize, Deserialize)]
|
#[derive(Debug, Clone, Serialize, Deserialize)]
|
||||||
pub struct ModuleConfig {
|
pub struct ModuleConfig {
|
||||||
pub module: String,
|
pub module: String,
|
||||||
|
@ -3,6 +3,7 @@ use std::sync::Arc;
|
|||||||
use futures_signals::signal::{Mutable, Signal, SignalExt};
|
use futures_signals::signal::{Mutable, Signal, SignalExt};
|
||||||
use lmdb::RoTransaction;
|
use lmdb::RoTransaction;
|
||||||
use rkyv::Archived;
|
use rkyv::Archived;
|
||||||
|
use crate::authorization::permissions::PrivilegesBuf;
|
||||||
use crate::config::MachineDescription;
|
use crate::config::MachineDescription;
|
||||||
use crate::db::LMDBorrow;
|
use crate::db::LMDBorrow;
|
||||||
use crate::resources::modules::fabaccess::{MachineState, Status};
|
use crate::resources::modules::fabaccess::{MachineState, Status};
|
||||||
@ -93,6 +94,10 @@ impl Resource {
|
|||||||
self.inner.signal()
|
self.inner.signal()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub fn get_required_privs(&self) -> &PrivilegesBuf {
|
||||||
|
&self.inner.desc.privs
|
||||||
|
}
|
||||||
|
|
||||||
fn set_state(&self, state: MachineState) {
|
fn set_state(&self, state: MachineState) {
|
||||||
self.inner.set_state(state)
|
self.inner.set_state(state)
|
||||||
}
|
}
|
||||||
|
@ -3,7 +3,7 @@ use std::sync::Arc;
|
|||||||
use anyhow::Context;
|
use anyhow::Context;
|
||||||
use lmdb::Environment;
|
use lmdb::Environment;
|
||||||
use once_cell::sync::OnceCell;
|
use once_cell::sync::OnceCell;
|
||||||
use crate::authorization::roles::Role;
|
use crate::authorization::roles::{Role, Roles};
|
||||||
use crate::resources::Resource;
|
use crate::resources::Resource;
|
||||||
use crate::session::db::SessionCache;
|
use crate::session::db::SessionCache;
|
||||||
use crate::Users;
|
use crate::Users;
|
||||||
@ -16,10 +16,13 @@ static SESSION_CACHE: OnceCell<SessionCache> = OnceCell::new();
|
|||||||
#[derive(Clone)]
|
#[derive(Clone)]
|
||||||
pub struct SessionManager {
|
pub struct SessionManager {
|
||||||
users: Users,
|
users: Users,
|
||||||
|
roles: Roles,
|
||||||
|
|
||||||
|
// cache: SessionCache // todo
|
||||||
}
|
}
|
||||||
impl SessionManager {
|
impl SessionManager {
|
||||||
pub fn new(users: Users) -> Self {
|
pub fn new(users: Users, roles: Roles) -> Self {
|
||||||
Self { users }
|
Self { users, roles }
|
||||||
}
|
}
|
||||||
|
|
||||||
// TODO: make infallible
|
// TODO: make infallible
|
||||||
@ -27,33 +30,56 @@ impl SessionManager {
|
|||||||
let uid = uid.as_ref();
|
let uid = uid.as_ref();
|
||||||
if let Some(user) = self.users.get_user(uid) {
|
if let Some(user) = self.users.get_user(uid) {
|
||||||
tracing::trace!(uid, "opening new session for user");
|
tracing::trace!(uid, "opening new session for user");
|
||||||
Some(SessionHandle { user: UserRef::new(user.id) })
|
Some(SessionHandle {
|
||||||
|
users: self.users.clone(),
|
||||||
|
roles: self.roles.clone(),
|
||||||
|
user: UserRef::new(user.id),
|
||||||
|
})
|
||||||
} else {
|
} else {
|
||||||
None
|
None
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Clone, Debug)]
|
#[derive(Clone)]
|
||||||
pub struct SessionHandle {
|
pub struct SessionHandle {
|
||||||
|
users: Users,
|
||||||
|
roles: Roles,
|
||||||
|
|
||||||
user: UserRef,
|
user: UserRef,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl SessionHandle {
|
impl SessionHandle {
|
||||||
pub fn get_user(&self) -> UserRef {
|
pub fn get_user(&self) -> UserRef {
|
||||||
unimplemented!()
|
self.user.clone()
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn has_disclose(&self, resource: &Resource) -> bool {
|
pub fn has_disclose(&self, resource: &Resource) -> bool {
|
||||||
unimplemented!()
|
if let Some(user) = self.users.get_user(self.user.get_username()) {
|
||||||
|
self.roles.is_permitted(&user.userdata, &resource.get_required_privs().disclose)
|
||||||
|
} else {
|
||||||
|
false
|
||||||
|
}
|
||||||
}
|
}
|
||||||
pub fn has_read(&self, resource: &Resource) -> bool {
|
pub fn has_read(&self, resource: &Resource) -> bool {
|
||||||
unimplemented!()
|
if let Some(user) = self.users.get_user(self.user.get_username()) {
|
||||||
|
self.roles.is_permitted(&user.userdata, &resource.get_required_privs().read)
|
||||||
|
} else {
|
||||||
|
false
|
||||||
|
}
|
||||||
}
|
}
|
||||||
pub fn has_write(&self, resource: &Resource) -> bool {
|
pub fn has_write(&self, resource: &Resource) -> bool {
|
||||||
unimplemented!()
|
if let Some(user) = self.users.get_user(self.user.get_username()) {
|
||||||
|
self.roles.is_permitted(&user.userdata, &resource.get_required_privs().write)
|
||||||
|
} else {
|
||||||
|
false
|
||||||
|
}
|
||||||
}
|
}
|
||||||
pub fn has_manage(&self, resource: &Resource) -> bool {
|
pub fn has_manage(&self, resource: &Resource) -> bool {
|
||||||
unimplemented!()
|
if let Some(user) = self.users.get_user(self.user.get_username()) {
|
||||||
|
self.roles.is_permitted(&user.userdata, &resource.get_required_privs().manage)
|
||||||
|
} else {
|
||||||
|
false
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
Loading…
Reference in New Issue
Block a user