mirror of
https://gitlab.com/fabinfra/fabaccess/bffh.git
synced 2024-11-21 22:47:55 +01:00
Pushes code around until example loading compiles
This commit is contained in:
parent
5d9c1d5a64
commit
3b63e654e5
14
examples/machines.toml
Normal file
14
examples/machines.toml
Normal file
@ -0,0 +1,14 @@
|
||||
[e5408099-d3e5-440b-a92b-3aabf7683d6b]
|
||||
name = "Somemachine"
|
||||
disclose = "lab.some.disclose"
|
||||
read = "lab.some.read"
|
||||
write = "lab.some.write"
|
||||
manage = "lab.some.admin"
|
||||
|
||||
[eaabebae-34d1-4a3a-912a-967b495d3d6e]
|
||||
name = "Testmachine"
|
||||
description = "An optional description"
|
||||
disclose = "lab.test.read"
|
||||
read = "lab.test.read"
|
||||
write = "lab.test.write"
|
||||
manage = "lab.test.admin"
|
20
examples/roles.toml
Normal file
20
examples/roles.toml
Normal file
@ -0,0 +1,20 @@
|
||||
[testrole]
|
||||
name = "Testrole"
|
||||
permissions = [
|
||||
"lab.test.*"
|
||||
]
|
||||
|
||||
[somerole]
|
||||
name = "Somerole"
|
||||
parents = ["testparent%lmdb"]
|
||||
permissions = [
|
||||
"lab.some.admin"
|
||||
]
|
||||
|
||||
[testparent]
|
||||
name = "Testparent"
|
||||
permissions = [
|
||||
"lab.some.write",
|
||||
"lab.some.read",
|
||||
"lab.some.disclose",
|
||||
]
|
@ -1,5 +1,7 @@
|
||||
use std::sync::Arc;
|
||||
|
||||
use slog::Logger;
|
||||
|
||||
use capnp::capability::{Params, Results, Promise};
|
||||
|
||||
use crate::schema::connection_capnp;
|
||||
@ -17,6 +19,7 @@ pub struct Bootstrap {
|
||||
|
||||
impl Bootstrap {
|
||||
pub fn new(session: Arc<Session>) -> Self {
|
||||
info!(session.log, "Created Bootstrap");
|
||||
Self { session }
|
||||
}
|
||||
}
|
||||
@ -31,7 +34,7 @@ impl connection_capnp::bootstrap::Server for Bootstrap {
|
||||
// TODO: When should we allow multiple auth and how do me make sure that does not leak
|
||||
// priviledges (e.g. due to previously issues caps)?
|
||||
if self.session.user.is_none() {
|
||||
res.get().set_auth(capnp_rpc::new_client(auth::Auth::new()))
|
||||
res.get().set_auth(capnp_rpc::new_client(auth::Auth::new(self.session.clone())))
|
||||
}
|
||||
|
||||
Promise::ok(())
|
||||
|
@ -3,23 +3,29 @@
|
||||
//! Authorization is over in `access.rs`
|
||||
//! Authentication using SASL
|
||||
|
||||
use std::sync::Arc;
|
||||
|
||||
use slog::Logger;
|
||||
|
||||
use rsasl::{
|
||||
SASL,
|
||||
Property,
|
||||
Session,
|
||||
Session as SaslSession,
|
||||
ReturnCode,
|
||||
Callback,
|
||||
SaslCtx,
|
||||
Step,
|
||||
};
|
||||
|
||||
use serde::{Serialize, Deserialize};
|
||||
|
||||
use capnp::capability::{Params, Results, Promise};
|
||||
|
||||
use crate::error::Result;
|
||||
use crate::config::Settings;
|
||||
|
||||
use crate::api::Session;
|
||||
|
||||
pub use crate::schema::auth_capnp;
|
||||
|
||||
pub struct AppData;
|
||||
@ -27,7 +33,7 @@ pub struct SessionData;
|
||||
|
||||
struct CB;
|
||||
impl Callback<AppData, SessionData> for CB {
|
||||
fn callback(sasl: SaslCtx<AppData, SessionData>, session: Session<SessionData>, prop: Property) -> libc::c_int {
|
||||
fn callback(sasl: SaslCtx<AppData, SessionData>, session: SaslSession<SessionData>, prop: Property) -> libc::c_int {
|
||||
let ret = match prop {
|
||||
Property::GSASL_VALIDATE_SIMPLE => {
|
||||
let authid = session.get_property(Property::GSASL_AUTHID).unwrap().to_string_lossy();
|
||||
@ -50,10 +56,11 @@ impl Callback<AppData, SessionData> for CB {
|
||||
|
||||
pub struct Auth {
|
||||
pub ctx: SASL<AppData, SessionData>,
|
||||
session: Arc<Session>,
|
||||
}
|
||||
|
||||
impl Auth {
|
||||
pub fn new() -> Self {
|
||||
pub fn new(session: Arc<Session>) -> Self {
|
||||
let mut ctx = SASL::new().unwrap();
|
||||
|
||||
let mut appdata = Box::new(AppData);
|
||||
@ -62,7 +69,9 @@ impl Auth {
|
||||
|
||||
ctx.install_callback::<CB>();
|
||||
|
||||
Self { ctx }
|
||||
info!(session.log, "Auth created");
|
||||
|
||||
Self { ctx, session }
|
||||
}
|
||||
}
|
||||
|
||||
@ -156,20 +165,19 @@ impl auth_capnp::authentication::Server for Auth {
|
||||
}
|
||||
}
|
||||
|
||||
pub async fn init(log: Logger, config: Settings) -> Result<Auth> {
|
||||
Ok(Auth::new())
|
||||
}
|
||||
|
||||
// Use the newtype pattern here to make the type system work for us; even though AuthCId is for all
|
||||
// intents and purposes just a String the compiler will still complain if you return or more
|
||||
// importantly pass a String intead of a AuthCId. This prevents bugs where you get an object from
|
||||
// somewhere and pass it somewhere else and in between don't check if it's the right type and
|
||||
// accidentally pass the authzid where the authcid should have gone.
|
||||
|
||||
#[derive(Debug, Clone, PartialEq, Eq, PartialOrd, Ord, Serialize, Deserialize)]
|
||||
/// Authentication Identity
|
||||
///
|
||||
/// Under the hood a string because the form depends heavily on the method
|
||||
struct AuthCId(String);
|
||||
|
||||
#[derive(Debug, Clone, PartialEq, Eq, PartialOrd, Ord, Serialize, Deserialize)]
|
||||
/// Authorization Identity
|
||||
///
|
||||
/// This identity is internal to FabAccess and completely independent from the authentication
|
||||
@ -191,6 +199,7 @@ struct AuthZId {
|
||||
}
|
||||
|
||||
// What is a man?! A miserable little pile of secrets!
|
||||
#[derive(Debug, Clone, PartialEq, Eq, PartialOrd, Ord, Serialize, Deserialize)]
|
||||
/// Authentication/Authorization user object.
|
||||
///
|
||||
/// This struct contains the user as is passed to the actual authentication/authorization
|
||||
@ -218,7 +227,7 @@ pub struct User {
|
||||
/// Contains the authentication method used
|
||||
///
|
||||
/// For the most part this is the SASL method
|
||||
authMethod: String,
|
||||
auth_method: String,
|
||||
|
||||
/// Method-specific key-value pairs
|
||||
///
|
||||
@ -236,6 +245,7 @@ pub struct User {
|
||||
// b) the given authcid may authenticate as the given authzid. E.g. if a given client certificate
|
||||
// has been configured for that user, if a GSSAPI user maps to a given user,
|
||||
|
||||
#[derive(Debug, Clone, PartialEq, Eq, PartialOrd, Ord, Serialize, Deserialize)]
|
||||
pub enum AuthError {
|
||||
/// Authentication ID is bad/unknown/..
|
||||
BadAuthcid,
|
||||
@ -247,7 +257,3 @@ pub enum AuthError {
|
||||
NotAllowedAuthzid,
|
||||
|
||||
}
|
||||
|
||||
fn grant_auth(user: User) -> std::result::Result<(), AuthError> {
|
||||
unimplemented!()
|
||||
}
|
||||
|
@ -1,5 +1,7 @@
|
||||
use std::sync::Arc;
|
||||
|
||||
use slog::Logger;
|
||||
|
||||
use capnp::capability::Promise;
|
||||
use capnp::Error;
|
||||
|
||||
@ -15,6 +17,7 @@ pub struct Machines {
|
||||
|
||||
impl Machines {
|
||||
pub fn new(session: Arc<Session>) -> Self {
|
||||
info!(session.log, "Machines created");
|
||||
Self { session }
|
||||
}
|
||||
}
|
||||
|
@ -15,7 +15,7 @@ use crate::schema::connection_capnp;
|
||||
/// Connection context
|
||||
// TODO this should track over several connections
|
||||
pub struct Session {
|
||||
log: Logger,
|
||||
pub log: Logger,
|
||||
pub user: Option<auth::User>,
|
||||
}
|
||||
|
||||
@ -57,6 +57,7 @@ async fn handshake(log: &Logger, stream: &mut TcpStream) -> Result<()> {
|
||||
pub async fn handle_connection(log: Logger, stream: TcpStream) -> Result<()> {
|
||||
//handshake(&log, &mut stream).await?;
|
||||
|
||||
info!(log, "New connection from on {:?}", stream);
|
||||
let session = Arc::new(Session::new(log));
|
||||
let boots = Bootstrap::new(session);
|
||||
let rpc: connection_capnp::bootstrap::Client = capnp_rpc::new_client(boots);
|
||||
|
156
src/db/access.rs
156
src/db/access.rs
@ -4,16 +4,22 @@
|
||||
use std::fmt;
|
||||
use std::collections::HashSet;
|
||||
use std::cmp::Ordering;
|
||||
|
||||
use std::convert::TryInto;
|
||||
|
||||
use std::path::{Path, PathBuf};
|
||||
use std::fs;
|
||||
use std::io::Write;
|
||||
use std::sync::Arc;
|
||||
use std::collections::HashMap;
|
||||
use std::iter::FromIterator;
|
||||
use std::convert::{TryFrom, Into};
|
||||
|
||||
use flexbuffers;
|
||||
use serde::{Serialize, Deserialize};
|
||||
use serde::{
|
||||
Serialize,
|
||||
Serializer,
|
||||
|
||||
Deserialize,
|
||||
Deserializer,
|
||||
};
|
||||
|
||||
use slog::Logger;
|
||||
use lmdb::{Environment, Transaction, RwTransaction, Cursor};
|
||||
@ -98,15 +104,31 @@ pub trait RoleDB {
|
||||
pub struct Role {
|
||||
name: String,
|
||||
|
||||
// If a role doesn't define parents, default to an empty Vec.
|
||||
#[serde(default, skip_serializing_if = "Vec::is_empty")]
|
||||
/// 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>,
|
||||
|
||||
// If a role doesn't define permissions, default to an empty Vec.
|
||||
#[serde(default, skip_serializing_if = "Vec::is_empty")]
|
||||
permissions: Vec<PermRule>,
|
||||
}
|
||||
|
||||
impl Role {
|
||||
fn load_file<P: AsRef<Path>>(path: P) -> Result<HashMap<RoleIdentifier, Role>> {
|
||||
let content = fs::read(path)?;
|
||||
let file_roles: HashMap<String, Role> = toml::from_slice(&content[..])?;
|
||||
|
||||
Ok(HashMap::from_iter(file_roles.into_iter().map(|(key, value)| {
|
||||
(RoleIdentifier::local_from_str("lmdb".to_string(), key), value)
|
||||
})))
|
||||
}
|
||||
}
|
||||
|
||||
type SourceID = String;
|
||||
|
||||
fn split_once(s: &str, split: char) -> Option<(&str, &str)> {
|
||||
@ -116,6 +138,7 @@ fn split_once(s: &str, split: char) -> Option<(&str, &str)> {
|
||||
}
|
||||
|
||||
#[derive(Debug, Clone, PartialEq, Eq, Hash, Serialize, Deserialize)]
|
||||
#[serde(try_from = "String")]
|
||||
/// Universal (relative) id of a role
|
||||
pub enum RoleIdentifier {
|
||||
/// The role comes from this instance
|
||||
@ -135,6 +158,16 @@ pub enum RoleIdentifier {
|
||||
location: String,
|
||||
}
|
||||
}
|
||||
|
||||
impl fmt::Display for RoleIdentifier {
|
||||
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
|
||||
match self {
|
||||
RoleIdentifier::Local {name, source} => write!(f, "{}/{}@local", name, source),
|
||||
RoleIdentifier::Remote {name, location} => write!(f, "{}@{}", name, location),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl std::str::FromStr for RoleIdentifier {
|
||||
type Err = RoleFromStrError;
|
||||
|
||||
@ -148,21 +181,42 @@ impl std::str::FromStr for RoleIdentifier {
|
||||
}
|
||||
}
|
||||
}
|
||||
impl fmt::Display for RoleIdentifier {
|
||||
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
|
||||
match self {
|
||||
RoleIdentifier::Local {name, source} => write!(f, "{}/{}@local", name, source),
|
||||
RoleIdentifier::Remote {name, location} => write!(f, "{}@{}", name, location),
|
||||
|
||||
impl TryFrom<String> for RoleIdentifier {
|
||||
type Error = RoleFromStrError;
|
||||
|
||||
fn try_from(s: String) -> std::result::Result<Self, Self::Error> {
|
||||
if let Some((name, location)) = split_once(&s, '@') {
|
||||
Ok(RoleIdentifier::Remote { name: name.to_string(), location: location.to_string() })
|
||||
} else if let Some((name, source)) = split_once(&s, '%') {
|
||||
Ok(RoleIdentifier::Local { name: name.to_string(), source: source.to_string() })
|
||||
} else {
|
||||
Err(RoleFromStrError::Invalid)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl RoleIdentifier {
|
||||
pub fn local_from_str(source: String, name: String) -> Self {
|
||||
RoleIdentifier::Local { name, source }
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Debug, Copy, Clone, PartialEq, Eq, PartialOrd, Ord)]
|
||||
pub enum RoleFromStrError {
|
||||
/// No '@' or '%' found. That's strange, huh?
|
||||
Invalid
|
||||
}
|
||||
|
||||
impl fmt::Display for RoleFromStrError {
|
||||
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
|
||||
match self {
|
||||
RoleFromStrError::Invalid
|
||||
=> write!(f, "Rolename are of form 'name%source' or 'name@realm'."),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Debug, Clone, PartialEq, Eq, Hash, Serialize, Deserialize)]
|
||||
/// An identifier for a permission
|
||||
// XXX: Does remote permissions ever make sense?
|
||||
@ -201,6 +255,7 @@ pub struct PrivilegesBuf {
|
||||
|
||||
#[derive(Debug, Clone, PartialEq, Eq, Hash, Serialize, Deserialize)]
|
||||
#[repr(transparent)]
|
||||
#[serde(transparent)]
|
||||
/// An owned permission string
|
||||
///
|
||||
/// This is under the hood just a fancy std::String.
|
||||
@ -242,6 +297,10 @@ impl PermissionBuf {
|
||||
pub fn from_string(inner: String) -> Self {
|
||||
Self { inner }
|
||||
}
|
||||
|
||||
pub fn into_string(self) -> String {
|
||||
self.inner
|
||||
}
|
||||
}
|
||||
impl AsRef<str> for PermissionBuf {
|
||||
#[inline(always)]
|
||||
@ -317,8 +376,16 @@ impl PartialOrd for Permission {
|
||||
}
|
||||
}
|
||||
|
||||
impl AsRef<Permission> for Permission {
|
||||
#[inline]
|
||||
fn as_ref(&self) -> &Permission {
|
||||
self
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Clone, Debug, PartialEq, Eq, Hash, Serialize, Deserialize)]
|
||||
#[serde(try_from = "String")]
|
||||
#[serde(into = "String")]
|
||||
pub enum PermRule {
|
||||
/// The permission is precise,
|
||||
///
|
||||
@ -364,6 +431,46 @@ impl fmt::Display for PermRule {
|
||||
}
|
||||
}
|
||||
|
||||
impl Into<String> for PermRule {
|
||||
fn into(self) -> String {
|
||||
match self {
|
||||
PermRule::Base(perm) => perm.into_string(),
|
||||
PermRule::Children(mut perm) => {
|
||||
perm.push(Permission::new("+"));
|
||||
perm.into_string()
|
||||
},
|
||||
PermRule::Subtree(mut perm) => {
|
||||
perm.push(Permission::new("+"));
|
||||
perm.into_string()
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl TryFrom<String> for PermRule {
|
||||
type Error = &'static str;
|
||||
|
||||
fn try_from(mut input: String) -> std::result::Result<Self, Self::Error> {
|
||||
// Check out specifically the last two chars
|
||||
let len = input.len();
|
||||
if len <= 2 {
|
||||
Err("Input string for PermRule is too short")
|
||||
} else {
|
||||
match &input[len-2..len] {
|
||||
".+" => {
|
||||
input.truncate(len-2);
|
||||
Ok(PermRule::Children(PermissionBuf::from_string(input)))
|
||||
},
|
||||
".*" => {
|
||||
input.truncate(len-2);
|
||||
Ok(PermRule::Subtree(PermissionBuf::from_string(input)))
|
||||
},
|
||||
_ => Ok(PermRule::Base(PermissionBuf::from_string(input))),
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
mod tests {
|
||||
use super::*;
|
||||
@ -390,4 +497,35 @@ mod tests {
|
||||
|
||||
assert!(rule.match_perm(&perm));
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn load_examples_roles_test() {
|
||||
let roles = Role::load_file("examples/roles.toml")
|
||||
.expect("Couldn't load the example role defs. Does `examples/roles.toml` exist?");
|
||||
|
||||
|
||||
assert!(true)
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn rules_from_string_test() {
|
||||
assert_eq!(
|
||||
PermRule::Base(PermissionBuf::from_string("bffh.perm".to_string())),
|
||||
PermRule::try_from("bffh.perm".to_string()).unwrap()
|
||||
);
|
||||
assert_eq!(
|
||||
PermRule::Children(PermissionBuf::from_string("bffh.perm".to_string())),
|
||||
PermRule::try_from("bffh.perm.+".to_string()).unwrap()
|
||||
);
|
||||
assert_eq!(
|
||||
PermRule::Subtree(PermissionBuf::from_string("bffh.perm".to_string())),
|
||||
PermRule::try_from("bffh.perm.*".to_string()).unwrap()
|
||||
);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn rules_from_string_edgecases_test() {
|
||||
assert!(PermRule::try_from("*".to_string()).is_err());
|
||||
assert!(PermRule::try_from("+".to_string()).is_err());
|
||||
}
|
||||
}
|
||||
|
@ -1,3 +1,7 @@
|
||||
use std::path::Path;
|
||||
use std::collections::HashMap;
|
||||
use std::fs;
|
||||
|
||||
use serde::{Serialize, Deserialize};
|
||||
|
||||
use futures_signals::signal::Signal;
|
||||
@ -19,6 +23,9 @@ use crate::db::machine::{MachineIdentifier, Status, MachineState};
|
||||
/// machine, checking that the user who wants the machine (de)activated has the required
|
||||
/// permissions.
|
||||
pub struct Machine {
|
||||
/// Globally unique machine readable identifier
|
||||
id: MachineIdentifier,
|
||||
|
||||
/// Descriptor of the machine
|
||||
desc: MachineDescription,
|
||||
|
||||
@ -30,8 +37,9 @@ pub struct Machine {
|
||||
}
|
||||
|
||||
impl Machine {
|
||||
pub fn new(desc: MachineDescription, perm: access::PermIdentifier) -> Machine {
|
||||
pub fn new(id: MachineIdentifier, desc: MachineDescription, perm: access::PermIdentifier) -> Machine {
|
||||
Machine {
|
||||
id: id,
|
||||
desc: desc,
|
||||
state: Mutable::new(MachineState { state: Status::Free}),
|
||||
}
|
||||
@ -72,19 +80,70 @@ impl Machine {
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Debug, Clone, Serialize, Deserialize)]
|
||||
#[derive(Debug, Clone, PartialEq, Eq, 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
|
||||
#[serde(flatten)]
|
||||
privs: access::PrivilegesBuf,
|
||||
}
|
||||
|
||||
impl MachineDescription {
|
||||
fn load_file<P: AsRef<Path>>(path: P) -> Result<HashMap<MachineIdentifier, MachineDescription>> {
|
||||
let content = fs::read(path)?;
|
||||
Ok(toml::from_slice(&content[..])?)
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
mod tests {
|
||||
use super::*;
|
||||
use std::iter::FromIterator;
|
||||
|
||||
use crate::db::access::{PermissionBuf, PrivilegesBuf};
|
||||
|
||||
#[test]
|
||||
fn load_examples_descriptions_test() {
|
||||
let machines = MachineDescription::load_file("examples/machines.toml")
|
||||
.expect("Couldn't load the example machine defs. Does `examples/machines.toml` exist?");
|
||||
|
||||
let expected: HashMap<MachineIdentifier, MachineDescription>
|
||||
= HashMap::from_iter(vec![
|
||||
(Uuid::parse_str("e5408099-d3e5-440b-a92b-3aabf7683d6b").unwrap(),
|
||||
MachineDescription {
|
||||
name: "Somemachine".to_string(),
|
||||
description: None,
|
||||
privs: PrivilegesBuf {
|
||||
disclose: PermissionBuf::from_string("lab.some.disclose".to_string()),
|
||||
read: PermissionBuf::from_string("lab.some.read".to_string()),
|
||||
write: PermissionBuf::from_string("lab.some.write".to_string()),
|
||||
manage: PermissionBuf::from_string("lab.some.admin".to_string()),
|
||||
},
|
||||
}),
|
||||
(Uuid::parse_str("eaabebae-34d1-4a3a-912a-967b495d3d6e").unwrap(),
|
||||
MachineDescription {
|
||||
name: "Testmachine".to_string(),
|
||||
description: Some("An optional description".to_string()),
|
||||
privs: PrivilegesBuf {
|
||||
disclose: PermissionBuf::from_string("lab.test.read".to_string()),
|
||||
read: PermissionBuf::from_string("lab.test.read".to_string()),
|
||||
write: PermissionBuf::from_string("lab.test.write".to_string()),
|
||||
manage: PermissionBuf::from_string("lab.test.admin".to_string()),
|
||||
},
|
||||
}),
|
||||
].into_iter());
|
||||
|
||||
for u in ["e5408099-d3e5-440b-a92b-3aabf7683d6b", "eaabebae-34d1-4a3a-912a-967b495d3d6e"].iter() {
|
||||
let uuid = Uuid::parse_str(u).unwrap();
|
||||
assert_eq!(machines[&uuid], expected[&uuid]);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -143,7 +143,6 @@ fn main() -> Result<(), Error> {
|
||||
let env = Arc::new(env);
|
||||
let mdb = db::machine::init(log.new(o!("system" => "machines")), &config, env.clone());
|
||||
let pdb = db::access::init(log.new(o!("system" => "permissions")), &config, env.clone());
|
||||
let authentication_f = api::auth::init(log.new(o!("system" => "authentication")), config.clone());
|
||||
|
||||
// If --load or --dump is given we can stop at this point and load/dump the database and then
|
||||
// exit.
|
||||
|
Loading…
Reference in New Issue
Block a user