mirror of
https://gitlab.com/fabinfra/fabaccess/bffh.git
synced 2024-11-22 14:57:56 +01:00
Stuff to make work
This commit is contained in:
parent
abc9126137
commit
ba7a59c3de
@ -39,4 +39,5 @@
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
, mqtt_url = "tcp://localhost:1883"
|
, mqtt_url = "tcp://localhost:1883"
|
||||||
|
, db_path = "/tmp/bffh"
|
||||||
}
|
}
|
||||||
|
42
src/api.rs
42
src/api.rs
@ -13,9 +13,11 @@ use crate::network::Network;
|
|||||||
pub mod auth;
|
pub mod auth;
|
||||||
mod machine;
|
mod machine;
|
||||||
mod machines;
|
mod machines;
|
||||||
|
|
||||||
use machines::Machines;
|
use machines::Machines;
|
||||||
|
|
||||||
|
mod users;
|
||||||
|
use users::Users;
|
||||||
|
|
||||||
// TODO Session restoration by making the Bootstrap cap a SturdyRef
|
// TODO Session restoration by making the Bootstrap cap a SturdyRef
|
||||||
pub struct Bootstrap {
|
pub struct Bootstrap {
|
||||||
session: Arc<Session>,
|
session: Arc<Session>,
|
||||||
@ -45,13 +47,6 @@ impl connection_capnp::bootstrap::Server for Bootstrap {
|
|||||||
Promise::ok(())
|
Promise::ok(())
|
||||||
}
|
}
|
||||||
|
|
||||||
fn permission_system(&mut self,
|
|
||||||
_: PermissionSystemParams,
|
|
||||||
_: PermissionSystemResults
|
|
||||||
) -> Promise<(), capnp::Error> {
|
|
||||||
Promise::ok(())
|
|
||||||
}
|
|
||||||
|
|
||||||
fn machine_system(&mut self,
|
fn machine_system(&mut self,
|
||||||
_: MachineSystemParams,
|
_: MachineSystemParams,
|
||||||
mut res: MachineSystemResults
|
mut res: MachineSystemResults
|
||||||
@ -65,6 +60,11 @@ impl connection_capnp::bootstrap::Server for Bootstrap {
|
|||||||
let perms = accessdb.collect_permrules(&user.data)
|
let perms = accessdb.collect_permrules(&user.data)
|
||||||
.map_err(|e| capnp::Error::failed(format!("AccessDB lookup failed: {}", e)))?;
|
.map_err(|e| capnp::Error::failed(format!("AccessDB lookup failed: {}", e)))?;
|
||||||
|
|
||||||
|
debug!(session.log, "Giving MachineSystem cap to user {} with perms:", user.id);
|
||||||
|
for r in perms.iter() {
|
||||||
|
debug!(session.log, " {}", r);
|
||||||
|
}
|
||||||
|
|
||||||
// TODO actual permission check and stuff
|
// TODO actual permission check and stuff
|
||||||
// Right now we only check that the user has authenticated at all.
|
// Right now we only check that the user has authenticated at all.
|
||||||
let c = capnp_rpc::new_client(Machines::new(user.id, perms, nw));
|
let c = capnp_rpc::new_client(Machines::new(user.id, perms, nw));
|
||||||
@ -78,5 +78,31 @@ impl connection_capnp::bootstrap::Server for Bootstrap {
|
|||||||
|
|
||||||
Promise::from_future(f)
|
Promise::from_future(f)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fn user_system(
|
||||||
|
&mut self,
|
||||||
|
_: UserSystemParams,
|
||||||
|
mut results: UserSystemResults
|
||||||
|
) -> Promise<(), capnp::Error> {
|
||||||
|
let session = self.session.clone();
|
||||||
|
let accessdb = self.db.access.clone();
|
||||||
|
let f = async move {
|
||||||
|
// Ensure the lock is dropped as soon as possible
|
||||||
|
if let Some(user) = { session.user.lock().await.clone() } {
|
||||||
|
let perms = accessdb.collect_permrules(&user.data)
|
||||||
|
.map_err(|e| capnp::Error::failed(format!("AccessDB lookup failed: {}", e)))?;
|
||||||
|
|
||||||
|
// TODO actual permission check and stuff
|
||||||
|
// Right now we only check that the user has authenticated at all.
|
||||||
|
let c = capnp_rpc::new_client(Users::new(perms));
|
||||||
|
results.get().set_user_system(c);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Promise is Ok either way, just the machine system may not be set, indicating as
|
||||||
|
// usual a lack of permission.
|
||||||
|
Ok(())
|
||||||
|
};
|
||||||
|
|
||||||
|
Promise::from_future(f)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
43
src/api/users.rs
Normal file
43
src/api/users.rs
Normal file
@ -0,0 +1,43 @@
|
|||||||
|
use capnp::capability::Promise;
|
||||||
|
|
||||||
|
use crate::db::access::{PermRule, Permission};
|
||||||
|
use crate::schema::usersystem_capnp::user_system;
|
||||||
|
use crate::schema::usersystem_capnp::user_system::{info, manage};
|
||||||
|
|
||||||
|
#[derive(Clone, Debug)]
|
||||||
|
pub struct Users {
|
||||||
|
perms: Vec<PermRule>,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Users {
|
||||||
|
pub fn new(perms: Vec<PermRule>) -> Self {
|
||||||
|
Self { perms }
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl user_system::Server for Users {
|
||||||
|
fn info(
|
||||||
|
&mut self,
|
||||||
|
_: user_system::InfoParams,
|
||||||
|
_: user_system::InfoResults,
|
||||||
|
) -> Promise<(), capnp::Error> {
|
||||||
|
Promise::ok(())
|
||||||
|
}
|
||||||
|
|
||||||
|
fn manage(
|
||||||
|
&mut self,
|
||||||
|
_: user_system::ManageParams,
|
||||||
|
mut results: user_system::ManageResults,
|
||||||
|
) -> Promise<(), capnp::Error> {
|
||||||
|
let perm: &Permission = Permission::new("bffh.users.manage");
|
||||||
|
if self.perms.iter().any(|rule| rule.match_perm(perm)) {
|
||||||
|
results.get().set_manage(capnp_rpc::new_client(self.clone()));
|
||||||
|
}
|
||||||
|
|
||||||
|
Promise::ok(())
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl info::Server for Users {}
|
||||||
|
|
||||||
|
impl manage::Server for Users {}
|
@ -1,5 +1,5 @@
|
|||||||
use std::default::Default;
|
use std::default::Default;
|
||||||
use std::path::Path;
|
use std::path::{Path, PathBuf};
|
||||||
use std::collections::HashMap;
|
use std::collections::HashMap;
|
||||||
|
|
||||||
use serde::{Serialize, Deserialize};
|
use serde::{Serialize, Deserialize};
|
||||||
@ -36,6 +36,8 @@ pub struct Config {
|
|||||||
|
|
||||||
pub actor_connections: Box<[(String, String)]>,
|
pub actor_connections: Box<[(String, String)]>,
|
||||||
pub init_connections: Box<[(String, String)]>,
|
pub init_connections: Box<[(String, String)]>,
|
||||||
|
|
||||||
|
pub db_path: PathBuf,
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Debug, Clone, Serialize, Deserialize)]
|
#[derive(Debug, Clone, Serialize, Deserialize)]
|
||||||
@ -83,9 +85,9 @@ impl Default for Config {
|
|||||||
port: Some(DEFAULT_PORT),
|
port: Some(DEFAULT_PORT),
|
||||||
}
|
}
|
||||||
]),
|
]),
|
||||||
machines: machines,
|
machines,
|
||||||
actors: actors,
|
actors,
|
||||||
initiators: initiators,
|
initiators,
|
||||||
mqtt_url: "tcp://localhost:1883".to_string(),
|
mqtt_url: "tcp://localhost:1883".to_string(),
|
||||||
actor_connections: Box::new([
|
actor_connections: Box::new([
|
||||||
("Testmachine".to_string(), "Actor".to_string()),
|
("Testmachine".to_string(), "Actor".to_string()),
|
||||||
@ -93,6 +95,8 @@ impl Default for Config {
|
|||||||
init_connections: Box::new([
|
init_connections: Box::new([
|
||||||
("Initiator".to_string(), "Testmachine".to_string()),
|
("Initiator".to_string(), "Testmachine".to_string()),
|
||||||
]),
|
]),
|
||||||
|
|
||||||
|
db_path: PathBuf::from("/run/bffh/database"),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -42,7 +42,7 @@ impl Databases {
|
|||||||
let env = lmdb::Environment::new()
|
let env = lmdb::Environment::new()
|
||||||
.set_flags(lmdb::EnvironmentFlags::MAP_ASYNC | lmdb::EnvironmentFlags::NO_SUB_DIR)
|
.set_flags(lmdb::EnvironmentFlags::MAP_ASYNC | lmdb::EnvironmentFlags::NO_SUB_DIR)
|
||||||
.set_max_dbs(LMDB_MAX_DB as libc::c_uint)
|
.set_max_dbs(LMDB_MAX_DB as libc::c_uint)
|
||||||
.open(&PathBuf::from_str("/tmp/a.db").unwrap())?;
|
.open(config.db_path.as_path())?;
|
||||||
|
|
||||||
// Start loading the machine database, authentication system and permission system
|
// Start loading the machine database, authentication system and permission system
|
||||||
// All of those get a custom logger so the source of a log message can be better traced and
|
// All of those get a custom logger so the source of a log message can be better traced and
|
||||||
|
@ -186,6 +186,31 @@ impl Role {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
impl fmt::Display for Role {
|
||||||
|
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
|
||||||
|
write!(f, "parents:")?;
|
||||||
|
if self.parents.is_empty() {
|
||||||
|
writeln!(f, " []")?;
|
||||||
|
} else {
|
||||||
|
writeln!(f, "")?;
|
||||||
|
for p in self.parents.iter() {
|
||||||
|
writeln!(f, " - {}", p)?;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
write!(f, "permissions:")?;
|
||||||
|
if self.permissions.is_empty() {
|
||||||
|
writeln!(f, " []")?;
|
||||||
|
} else {
|
||||||
|
writeln!(f, "")?;
|
||||||
|
for p in self.permissions.iter() {
|
||||||
|
writeln!(f, " - {}", p)?;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
type SourceID = String;
|
type SourceID = String;
|
||||||
|
|
||||||
fn split_once(s: &str, split: char) -> Option<(&str, &str)> {
|
fn split_once(s: &str, split: char) -> Option<(&str, &str)> {
|
||||||
@ -454,7 +479,7 @@ pub enum PermRule {
|
|||||||
|
|
||||||
impl PermRule {
|
impl PermRule {
|
||||||
// Does this rule match that permission
|
// Does this rule match that permission
|
||||||
pub fn match_perm<P: AsRef<Permission>>(&self, perm: &P) -> bool {
|
pub fn match_perm<P: AsRef<Permission> + ?Sized>(&self, perm: &P) -> bool {
|
||||||
match self {
|
match self {
|
||||||
PermRule::Base(ref base) => base.as_permission() == perm.as_ref(),
|
PermRule::Base(ref base) => base.as_permission() == perm.as_ref(),
|
||||||
PermRule::Children(ref parent) => parent.as_permission() > perm.as_ref() ,
|
PermRule::Children(ref parent) => parent.as_permission() > perm.as_ref() ,
|
||||||
|
@ -69,16 +69,15 @@ impl Internal {
|
|||||||
roles.insert(role_id.clone(), role);
|
roles.insert(role_id.clone(), role);
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
info!(self.log, "Did not find role {} while trying to tally", role_id);
|
warn!(self.log, "Did not find role {} while trying to tally", role_id);
|
||||||
}
|
}
|
||||||
|
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn _get_role<'txn, T: Transaction>(&self, txn: &'txn T, role_id: &RoleIdentifier) -> Result<Option<Role>> {
|
pub fn _get_role<'txn, T: Transaction>(&self, txn: &'txn T, role_id: &RoleIdentifier) -> Result<Option<Role>> {
|
||||||
let string = format!("{}", role_id);
|
debug!(self.log, "Reading role '{}'", role_id.name);
|
||||||
debug!(self.log, "Reading role '{}'", &string);
|
match txn.get(self.roledb, &role_id.name.as_bytes()) {
|
||||||
match txn.get(self.roledb, &string.as_bytes()) {
|
|
||||||
Ok(bytes) => {
|
Ok(bytes) => {
|
||||||
Ok(Some(flexbuffers::from_slice(bytes)?))
|
Ok(Some(flexbuffers::from_slice(bytes)?))
|
||||||
},
|
},
|
||||||
@ -89,8 +88,7 @@ impl Internal {
|
|||||||
|
|
||||||
fn put_role(&self, txn: &mut RwTransaction, role_id: &RoleIdentifier, role: Role) -> Result<()> {
|
fn put_role(&self, txn: &mut RwTransaction, role_id: &RoleIdentifier, role: Role) -> Result<()> {
|
||||||
let bytes = flexbuffers::to_vec(role)?;
|
let bytes = flexbuffers::to_vec(role)?;
|
||||||
let string = format!("{}", role_id);
|
txn.put(self.roledb, &role_id.name.as_bytes(), &bytes, lmdb::WriteFlags::empty())?;
|
||||||
txn.put(self.roledb, &string.as_bytes(), &bytes, lmdb::WriteFlags::empty())?;
|
|
||||||
|
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
@ -107,8 +105,8 @@ impl Internal {
|
|||||||
for r in cursor.iter_start() {
|
for r in cursor.iter_start() {
|
||||||
match r {
|
match r {
|
||||||
Ok( (k,v) ) => {
|
Ok( (k,v) ) => {
|
||||||
let role_id_str = unsafe { std::str::from_utf8_unchecked(k) };
|
let role_name_str = unsafe { std::str::from_utf8_unchecked(k) };
|
||||||
let role_id = role_id_str.parse::<RoleIdentifier>().unwrap();
|
let role_id = RoleIdentifier::local_from_str(role_name_str.to_string(), "lmdb".to_string());
|
||||||
match flexbuffers::from_slice(v) {
|
match flexbuffers::from_slice(v) {
|
||||||
Ok(role) => vec.push((role_id, role)),
|
Ok(role) => vec.push((role_id, role)),
|
||||||
Err(e) => error!(self.log, "Bad format for roleid {}: {}", role_id, e),
|
Err(e) => error!(self.log, "Bad format for roleid {}: {}", role_id, e),
|
||||||
@ -126,7 +124,7 @@ impl Internal {
|
|||||||
self.load_roles_txn(&mut txn, path.as_ref())?;
|
self.load_roles_txn(&mut txn, path.as_ref())?;
|
||||||
|
|
||||||
// In case the above didn't error, commit.
|
// In case the above didn't error, commit.
|
||||||
txn.commit();
|
txn.commit()?;
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
fn load_roles_txn(&self, txn: &mut RwTransaction, path: &Path) -> Result<()> {
|
fn load_roles_txn(&self, txn: &mut RwTransaction, path: &Path) -> Result<()> {
|
||||||
|
@ -141,8 +141,10 @@ fn maybe(matches: clap::ArgMatches, log: Arc<Logger>) -> Result<(), Error> {
|
|||||||
|
|
||||||
if matches.is_present("dump") {
|
if matches.is_present("dump") {
|
||||||
let db = db::Databases::new(&log, &config)?;
|
let db = db::Databases::new(&log, &config)?;
|
||||||
let v = db.access.dump_roles();
|
let v = db.access.dump_roles().unwrap();
|
||||||
info!(log, "Roles {:?}", v);
|
for (id, role) in v.iter() {
|
||||||
|
info!(log, "Role {}:\n{}", id, role);
|
||||||
|
}
|
||||||
Ok(())
|
Ok(())
|
||||||
} else if matches.is_present("load") {
|
} else if matches.is_present("load") {
|
||||||
let db = db::Databases::new(&log, &config)?;
|
let db = db::Databases::new(&log, &config)?;
|
||||||
|
Loading…
Reference in New Issue
Block a user