mirror of
https://gitlab.com/fabinfra/fabaccess/bffh.git
synced 2024-11-22 06:47:56 +01:00
User db & loading
This commit is contained in:
parent
c4dac55b23
commit
ddd8add270
1
Cargo.lock
generated
1
Cargo.lock
generated
@ -773,6 +773,7 @@ dependencies = [
|
|||||||
"signal-hook",
|
"signal-hook",
|
||||||
"signal-hook-async-std",
|
"signal-hook-async-std",
|
||||||
"tempfile",
|
"tempfile",
|
||||||
|
"toml",
|
||||||
"tracing",
|
"tracing",
|
||||||
"tracing-futures",
|
"tracing-futures",
|
||||||
"tracing-subscriber 0.2.25",
|
"tracing-subscriber 0.2.25",
|
||||||
|
@ -34,6 +34,7 @@ futures-util = "0.3"
|
|||||||
futures-lite = "1.12.0"
|
futures-lite = "1.12.0"
|
||||||
async-net = "1.6.1"
|
async-net = "1.6.1"
|
||||||
anyhow = "1.0.56"
|
anyhow = "1.0.56"
|
||||||
|
toml = "0.5.8"
|
||||||
|
|
||||||
# Runtime
|
# Runtime
|
||||||
executor = { path = "runtime/executor" }
|
executor = { path = "runtime/executor" }
|
||||||
|
@ -42,19 +42,19 @@ impl Actor for Process {
|
|||||||
Status::Free => {
|
Status::Free => {
|
||||||
command.arg("free");
|
command.arg("free");
|
||||||
}
|
}
|
||||||
Status::InUse(by) => {
|
Status::InUse(ref by) => {
|
||||||
command.arg("inuse").arg(format!("{}", by.get_username()));
|
command.arg("inuse").arg(format!("{}", by.get_username()));
|
||||||
}
|
}
|
||||||
Status::ToCheck(by) => {
|
Status::ToCheck(ref by) => {
|
||||||
command.arg("tocheck")
|
command.arg("tocheck")
|
||||||
.arg(format!("{}", by.get_username()));
|
.arg(format!("{}", by.get_username()));
|
||||||
}
|
}
|
||||||
Status::Blocked(by) => {
|
Status::Blocked(ref by) => {
|
||||||
command.arg("blocked")
|
command.arg("blocked")
|
||||||
.arg(format!("{}", by.get_username()));
|
.arg(format!("{}", by.get_username()));
|
||||||
}
|
}
|
||||||
Status::Disabled => { command.arg("disabled"); },
|
Status::Disabled => { command.arg("disabled"); },
|
||||||
Status::Reserved(by) => {
|
Status::Reserved(ref by) => {
|
||||||
command.arg("reserved")
|
command.arg("reserved")
|
||||||
.arg(format!("{}", by.get_username()));
|
.arg(format!("{}", by.get_username()));
|
||||||
}
|
}
|
||||||
|
@ -1,11 +1,28 @@
|
|||||||
use std::sync::Arc;
|
use std::sync::Arc;
|
||||||
use rsasl::error::SASLError;
|
use rsasl::error::{SASLError, SessionError};
|
||||||
use rsasl::mechname::Mechname;
|
use rsasl::mechname::Mechname;
|
||||||
use rsasl::SASL;
|
use rsasl::{Property, SASL};
|
||||||
use rsasl::session::Session;
|
use rsasl::session::{Session, SessionData};
|
||||||
|
use rsasl::validate::Validation;
|
||||||
|
use crate::users::db::UserDB;
|
||||||
|
use crate::users::Users;
|
||||||
|
|
||||||
pub mod db;
|
pub mod db;
|
||||||
|
|
||||||
|
struct Callback {
|
||||||
|
users: Users,
|
||||||
|
}
|
||||||
|
impl Callback {
|
||||||
|
pub fn new(users: Users) -> Self {
|
||||||
|
Self { users, }
|
||||||
|
}
|
||||||
|
}
|
||||||
|
impl rsasl::callback::Callback for Callback {
|
||||||
|
fn validate(&self, session: &mut SessionData, validation: Validation, mechanism: &Mechname) -> Result<(), SessionError> {
|
||||||
|
todo!()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
struct Inner {
|
struct Inner {
|
||||||
rsasl: SASL,
|
rsasl: SASL,
|
||||||
}
|
}
|
||||||
@ -21,8 +38,9 @@ pub struct AuthenticationHandle {
|
|||||||
}
|
}
|
||||||
|
|
||||||
impl AuthenticationHandle {
|
impl AuthenticationHandle {
|
||||||
pub fn new() -> Self {
|
pub fn new(userdb: Users) -> Self {
|
||||||
let rsasl = SASL::new();
|
let mut rsasl = SASL::new();
|
||||||
|
rsasl.install_callback(Arc::new(Callback::new(userdb)));
|
||||||
Self { inner: Arc::new(Inner::new(rsasl)) }
|
Self { inner: Arc::new(Inner::new(rsasl)) }
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -27,8 +27,9 @@ impl AuthorizationHandle {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn lookup_user(&self, uid: impl AsRef<str>) -> Option<User> {
|
pub fn get_user_roles(&self, uid: impl AsRef<str>) -> Option<impl IntoIterator<Item=Role>> {
|
||||||
unimplemented!()
|
unimplemented!();
|
||||||
|
Some([])
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn is_permitted<'a>(&self, roles: impl IntoIterator<Item=&'a Role>, perm: impl AsRef<Permission>) -> bool {
|
pub fn is_permitted<'a>(&self, roles: impl IntoIterator<Item=&'a Role>, perm: impl AsRef<Permission>) -> bool {
|
||||||
|
@ -240,9 +240,13 @@ impl AdminServer for Machine {
|
|||||||
"totakeover not implemented".to_string(),
|
"totakeover not implemented".to_string(),
|
||||||
)),
|
)),
|
||||||
};
|
};
|
||||||
self.resource.force_set(state);
|
let resource = self.resource.clone();
|
||||||
Promise::ok(())
|
Promise::from_future(async move {
|
||||||
|
resource.force_set(state).await;
|
||||||
|
Ok(())
|
||||||
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
fn force_set_user(
|
fn force_set_user(
|
||||||
&mut self,
|
&mut self,
|
||||||
_: admin::ForceSetUserParams,
|
_: admin::ForceSetUserParams,
|
||||||
@ -252,6 +256,7 @@ impl AdminServer for Machine {
|
|||||||
"method not implemented".to_string(),
|
"method not implemented".to_string(),
|
||||||
))
|
))
|
||||||
}
|
}
|
||||||
|
|
||||||
fn get_admin_property_list(
|
fn get_admin_property_list(
|
||||||
&mut self,
|
&mut self,
|
||||||
_: admin::GetAdminPropertyListParams,
|
_: admin::GetAdminPropertyListParams,
|
||||||
|
18
bffhd/lib.rs
18
bffhd/lib.rs
@ -62,6 +62,8 @@ use crate::resources::search::ResourcesHandle;
|
|||||||
use crate::resources::state::db::StateDB;
|
use crate::resources::state::db::StateDB;
|
||||||
use crate::session::SessionManager;
|
use crate::session::SessionManager;
|
||||||
use crate::tls::TlsConfig;
|
use crate::tls::TlsConfig;
|
||||||
|
use crate::users::db::UserDB;
|
||||||
|
use crate::users::Users;
|
||||||
|
|
||||||
pub const RELEASE_STRING: &'static str = env!("BFFHD_RELEASE_STRING");
|
pub const RELEASE_STRING: &'static str = env!("BFFHD_RELEASE_STRING");
|
||||||
|
|
||||||
@ -82,8 +84,12 @@ impl Diflouroborane {
|
|||||||
tracing::info!(version=RELEASE_STRING, "Starting");
|
tracing::info!(version=RELEASE_STRING, "Starting");
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn setup(&mut self, config: &Config) -> anyhow::Result<()> {
|
pub fn init_logging(config: &Config) {
|
||||||
logging::init(&config);
|
logging::init(&config);
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn setup(&mut self, config: &Config) -> anyhow::Result<()> {
|
||||||
|
Self::init_logging(config);
|
||||||
|
|
||||||
let span = tracing::info_span!("setup");
|
let span = tracing::info_span!("setup");
|
||||||
let _guard = span.enter();
|
let _guard = span.enter();
|
||||||
@ -96,8 +102,12 @@ impl Diflouroborane {
|
|||||||
SIGTERM,
|
SIGTERM,
|
||||||
]).context("Failed to construct signal handler")?;
|
]).context("Failed to construct signal handler")?;
|
||||||
|
|
||||||
let statedb = StateDB::create(&config.db_path).context("Failed to open state DB")?;
|
let env = StateDB::open_env(&config.db_path)?;
|
||||||
let statedb = Arc::new(statedb);
|
let statedb = Arc::new(StateDB::create_with_env(env.clone())
|
||||||
|
.context("Failed to open state DB file")?);
|
||||||
|
|
||||||
|
let userdb = Users::new(env.clone()).context("Failed to open users DB file")?;
|
||||||
|
|
||||||
let resources = ResourcesHandle::new(config.machines.iter().map(|(id, desc)| {
|
let resources = ResourcesHandle::new(config.machines.iter().map(|(id, desc)| {
|
||||||
Resource::new(Arc::new(resources::Inner::new(id.to_string(), statedb.clone(), desc.clone())))
|
Resource::new(Arc::new(resources::Inner::new(id.to_string(), statedb.clone(), desc.clone())))
|
||||||
}));
|
}));
|
||||||
@ -110,7 +120,7 @@ impl Diflouroborane {
|
|||||||
let acceptor = tlsconfig.make_tls_acceptor(&config.tlsconfig)?;
|
let acceptor = tlsconfig.make_tls_acceptor(&config.tlsconfig)?;
|
||||||
|
|
||||||
let sessionmanager = SessionManager::new();
|
let sessionmanager = SessionManager::new();
|
||||||
let authentication = AuthenticationHandle::new();
|
let authentication = AuthenticationHandle::new(userdb.clone());
|
||||||
|
|
||||||
let mut apiserver = self.executor.run(APIServer::bind(self.executor.clone(), &config.listens, acceptor, sessionmanager, authentication))?;
|
let mut apiserver = self.executor.run(APIServer::bind(self.executor.clone(), &config.listens, acceptor, sessionmanager, authentication))?;
|
||||||
|
|
||||||
|
@ -112,7 +112,7 @@ impl Resource {
|
|||||||
if session.has_manage(self) // Default allow for managers
|
if session.has_manage(self) // Default allow for managers
|
||||||
|
|
||||||
|| (session.has_write(self) // Decision tree for writers
|
|| (session.has_write(self) // Decision tree for writers
|
||||||
&& match (old.state, &new) {
|
&& match (&old.state, &new) {
|
||||||
// Going from available to used by the person requesting is okay.
|
// Going from available to used by the person requesting is okay.
|
||||||
(Status::Free, Status::InUse(who))
|
(Status::Free, Status::InUse(who))
|
||||||
// Check that the person requesting does not request for somebody else.
|
// Check that the person requesting does not request for somebody else.
|
||||||
@ -126,30 +126,30 @@ impl Resource {
|
|||||||
// Returning things we've been using is okay. This includes both if
|
// Returning things we've been using is okay. This includes both if
|
||||||
// they're being freed or marked as to be checked.
|
// they're being freed or marked as to be checked.
|
||||||
(Status::InUse(who), Status::Free | Status::ToCheck(_))
|
(Status::InUse(who), Status::Free | Status::ToCheck(_))
|
||||||
if who == user => true,
|
if who == &user => true,
|
||||||
|
|
||||||
// Un-reserving things we reserved is okay
|
// Un-reserving things we reserved is okay
|
||||||
(Status::Reserved(whom), Status::Free)
|
(Status::Reserved(whom), Status::Free)
|
||||||
if user == whom => true,
|
if whom == &user => true,
|
||||||
// Using things that we've reserved is okay. But the person requesting
|
// Using things that we've reserved is okay. But the person requesting
|
||||||
// that has to be the person that reserved the machine. Otherwise
|
// that has to be the person that reserved the machine. Otherwise
|
||||||
// somebody could make a machine reserved by a different user as used by
|
// somebody could make a machine reserved by a different user as used by
|
||||||
// that different user but use it themself.
|
// that different user but use it themself.
|
||||||
(Status::Reserved(whom), Status::InUse(who))
|
(Status::Reserved(whom), Status::InUse(who))
|
||||||
if user == whom && who == &whom => true,
|
if whom == &user && who == whom => true,
|
||||||
|
|
||||||
// Default is deny.
|
// Default is deny.
|
||||||
_ => false
|
_ => false
|
||||||
})
|
})
|
||||||
|
|
||||||
// Default permissions everybody has
|
// Default permissions everybody has
|
||||||
|| match (old.state, &new) {
|
|| match (&old.state, &new) {
|
||||||
// Returning things we've been using is okay. This includes both if
|
// Returning things we've been using is okay. This includes both if
|
||||||
// they're being freed or marked as to be checked.
|
// they're being freed or marked as to be checked.
|
||||||
(Status::InUse(who), Status::Free | Status::ToCheck(_)) if who == user => true,
|
(Status::InUse(who), Status::Free | Status::ToCheck(_)) if who == &user => true,
|
||||||
|
|
||||||
// Un-reserving things we reserved is okay
|
// Un-reserving things we reserved is okay
|
||||||
(Status::Reserved(whom), Status::Free) if user == whom => true,
|
(Status::Reserved(whom), Status::Free) if whom == &user => true,
|
||||||
|
|
||||||
// Default is deny.
|
// Default is deny.
|
||||||
_ => false,
|
_ => false,
|
||||||
|
@ -13,7 +13,6 @@ use crate::users::User;
|
|||||||
|
|
||||||
/// Status of a Machine
|
/// Status of a Machine
|
||||||
#[derive(
|
#[derive(
|
||||||
Copy,
|
|
||||||
Clone,
|
Clone,
|
||||||
PartialEq,
|
PartialEq,
|
||||||
Eq,
|
Eq,
|
||||||
@ -24,7 +23,7 @@ use crate::users::User;
|
|||||||
serde::Serialize,
|
serde::Serialize,
|
||||||
serde::Deserialize,
|
serde::Deserialize,
|
||||||
)]
|
)]
|
||||||
#[archive_attr(derive(Debug, PartialEq, serde::Serialize, serde::Deserialize))]
|
#[archive_attr(derive(Debug, PartialEq))]
|
||||||
pub enum Status {
|
pub enum Status {
|
||||||
/// Not currently used by anybody
|
/// Not currently used by anybody
|
||||||
Free,
|
Free,
|
||||||
@ -41,7 +40,6 @@ pub enum Status {
|
|||||||
}
|
}
|
||||||
|
|
||||||
#[derive(
|
#[derive(
|
||||||
Copy,
|
|
||||||
Clone,
|
Clone,
|
||||||
PartialEq,
|
PartialEq,
|
||||||
Eq,
|
Eq,
|
||||||
@ -115,7 +113,7 @@ impl MachineState {
|
|||||||
|
|
||||||
pub fn check(user: User) -> Self {
|
pub fn check(user: User) -> Self {
|
||||||
Self {
|
Self {
|
||||||
state: Status::ToCheck(user),
|
state: Status::ToCheck(user.clone()),
|
||||||
previous: Some(user),
|
previous: Some(user),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -41,7 +41,7 @@ pub struct StateDB {
|
|||||||
}
|
}
|
||||||
|
|
||||||
impl StateDB {
|
impl StateDB {
|
||||||
fn open_env<P: AsRef<Path>>(path: P) -> lmdb::Result<Environment> {
|
pub fn open_env<P: AsRef<Path>>(path: P) -> lmdb::Result<Arc<Environment>> {
|
||||||
Environment::new()
|
Environment::new()
|
||||||
.set_flags( EnvironmentFlags::WRITE_MAP
|
.set_flags( EnvironmentFlags::WRITE_MAP
|
||||||
| EnvironmentFlags::NO_SUB_DIR
|
| EnvironmentFlags::NO_SUB_DIR
|
||||||
@ -49,10 +49,11 @@ impl StateDB {
|
|||||||
| EnvironmentFlags::NO_READAHEAD)
|
| EnvironmentFlags::NO_READAHEAD)
|
||||||
.set_max_dbs(2)
|
.set_max_dbs(2)
|
||||||
.open(path.as_ref())
|
.open(path.as_ref())
|
||||||
|
.map(Arc::new)
|
||||||
}
|
}
|
||||||
|
|
||||||
fn new(env: Environment, input: DB<StateAdapter>, output: DB<StateAdapter>) -> Self {
|
fn new(env: Arc<Environment>, input: DB<StateAdapter>, output: DB<StateAdapter>) -> Self {
|
||||||
Self { env: Arc::new(env), input, output }
|
Self { env: env, input, output }
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn open<P: AsRef<Path>>(path: P) -> lmdb::Result<Self> {
|
pub fn open<P: AsRef<Path>>(path: P) -> lmdb::Result<Self> {
|
||||||
@ -63,15 +64,19 @@ impl StateDB {
|
|||||||
Ok(Self::new(env, input, output))
|
Ok(Self::new(env, input, output))
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn create<P: AsRef<Path>>(path: P) -> lmdb::Result<Self> {
|
pub fn create_with_env(env: Arc<Environment>) -> lmdb::Result<Self> {
|
||||||
let flags = DatabaseFlags::empty();
|
let flags = DatabaseFlags::empty();
|
||||||
let env = Self::open_env(path)?;
|
|
||||||
let input = unsafe { DB::create(&env, Some("input"), flags)? };
|
let input = unsafe { DB::create(&env, Some("input"), flags)? };
|
||||||
let output = unsafe { DB::create(&env, Some("output"), flags)? };
|
let output = unsafe { DB::create(&env, Some("output"), flags)? };
|
||||||
|
|
||||||
Ok(Self::new(env, input, output))
|
Ok(Self::new(env, input, output))
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub fn create<P: AsRef<Path>>(path: P) -> lmdb::Result<Self> {
|
||||||
|
let env = Self::open_env(path)?;
|
||||||
|
Self::create_with_env(env)
|
||||||
|
}
|
||||||
|
|
||||||
fn update_txn(&self, txn: &mut RwTransaction, key: impl AsRef<[u8]>, input: &State, output: &State)
|
fn update_txn(&self, txn: &mut RwTransaction, key: impl AsRef<[u8]>, input: &State, output: &State)
|
||||||
-> Result<(), DBError>
|
-> Result<(), DBError>
|
||||||
{
|
{
|
||||||
|
@ -1,10 +1,12 @@
|
|||||||
use crate::db::{AllocAdapter, Environment, RawDB, Result, DB};
|
use crate::db::{AllocAdapter, Environment, RawDB, Result, DB};
|
||||||
use crate::db::{DatabaseFlags, LMDBorrow, RoTransaction, WriteFlags};
|
use crate::db::{DatabaseFlags, LMDBorrow, RoTransaction, WriteFlags};
|
||||||
use lmdb::{RwTransaction, Transaction};
|
use lmdb::{RwTransaction, Transaction};
|
||||||
use std::collections::HashSet;
|
use std::collections::{HashMap, HashSet};
|
||||||
|
use std::path::Path;
|
||||||
use std::sync::Arc;
|
use std::sync::Arc;
|
||||||
|
|
||||||
use rkyv::{Archived, Deserialize};
|
use rkyv::{Archived, Deserialize};
|
||||||
|
use crate::authorization::roles::RoleIdentifier;
|
||||||
|
|
||||||
#[derive(
|
#[derive(
|
||||||
Clone,
|
Clone,
|
||||||
@ -18,9 +20,45 @@ use rkyv::{Archived, Deserialize};
|
|||||||
serde::Deserialize,
|
serde::Deserialize,
|
||||||
)]
|
)]
|
||||||
pub struct User {
|
pub struct User {
|
||||||
id: u128,
|
pub id: String,
|
||||||
username: String,
|
pub userdata: UserData,
|
||||||
roles: Vec<String>,
|
}
|
||||||
|
|
||||||
|
#[derive(
|
||||||
|
Clone,
|
||||||
|
PartialEq,
|
||||||
|
Eq,
|
||||||
|
Debug,
|
||||||
|
rkyv::Archive,
|
||||||
|
rkyv::Serialize,
|
||||||
|
rkyv::Deserialize,
|
||||||
|
serde::Serialize,
|
||||||
|
serde::Deserialize,
|
||||||
|
)]
|
||||||
|
/// Data on an user to base decisions on
|
||||||
|
///
|
||||||
|
/// This of course includes authorization data, i.e. that users set roles
|
||||||
|
pub struct UserData {
|
||||||
|
/// A Person has N ≥ 0 roles.
|
||||||
|
/// Persons are only ever given roles, not permissions directly
|
||||||
|
pub roles: Vec<String>,
|
||||||
|
|
||||||
|
#[serde(skip_serializing_if = "Option::is_none")]
|
||||||
|
#[serde(default)]
|
||||||
|
pub passwd: Option<String>,
|
||||||
|
|
||||||
|
/// Additional data storage
|
||||||
|
#[serde(flatten, skip_serializing_if = "HashMap::is_empty")]
|
||||||
|
kv: HashMap<String, String>,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl UserData {
|
||||||
|
pub fn new(roles: Vec<String>) -> Self {
|
||||||
|
Self { roles, kv: HashMap::new(), passwd: None }
|
||||||
|
}
|
||||||
|
pub fn new_with_kv(roles: Vec<String>, kv: HashMap<String, String>) -> Self {
|
||||||
|
Self { roles, kv, passwd: None }
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
type Adapter = AllocAdapter<User>;
|
type Adapter = AllocAdapter<User>;
|
||||||
@ -79,4 +117,4 @@ impl UserDB {
|
|||||||
|
|
||||||
Ok(out)
|
Ok(out)
|
||||||
}
|
}
|
||||||
}
|
}
|
@ -14,17 +14,22 @@
|
|||||||
* along with this program. If not, see <https://www.gnu.org/licenses/>.
|
* along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
|
use std::collections::HashMap;
|
||||||
use rkyv::{Archive, Deserialize, Infallible, Serialize};
|
use rkyv::{Archive, Deserialize, Infallible, Serialize};
|
||||||
use std::ops::Deref;
|
use std::ops::Deref;
|
||||||
|
use std::path::Path;
|
||||||
use std::sync::Arc;
|
use std::sync::Arc;
|
||||||
|
use anyhow::Context;
|
||||||
|
use lmdb::Environment;
|
||||||
|
|
||||||
pub mod db;
|
pub mod db;
|
||||||
|
|
||||||
pub use crate::authentication::db::PassDB;
|
pub use crate::authentication::db::PassDB;
|
||||||
use crate::authorization::roles::Role;
|
use crate::authorization::roles::{Role, RoleIdentifier};
|
||||||
|
use crate::UserDB;
|
||||||
|
use crate::users::db::UserData;
|
||||||
|
|
||||||
#[derive(
|
#[derive(
|
||||||
Copy,
|
|
||||||
Clone,
|
Clone,
|
||||||
PartialEq,
|
PartialEq,
|
||||||
Eq,
|
Eq,
|
||||||
@ -35,18 +40,18 @@ use crate::authorization::roles::Role;
|
|||||||
serde::Serialize,
|
serde::Serialize,
|
||||||
serde::Deserialize,
|
serde::Deserialize,
|
||||||
)]
|
)]
|
||||||
#[archive_attr(derive(Debug, PartialEq, serde::Serialize, serde::Deserialize))]
|
#[archive_attr(derive(Debug, PartialEq))]
|
||||||
pub struct User {
|
pub struct User {
|
||||||
id: u64
|
id: String,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl User {
|
impl User {
|
||||||
pub fn new(id: u64) -> Self {
|
pub fn new(id: String) -> Self {
|
||||||
User { id }
|
User { id }
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn get_username(&self) -> &str {
|
pub fn get_username(&self) -> &str {
|
||||||
unimplemented!()
|
self.id.as_str()
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn get_roles(&self) -> impl IntoIterator<Item=Role> {
|
pub fn get_roles(&self) -> impl IntoIterator<Item=Role> {
|
||||||
@ -54,3 +59,45 @@ impl User {
|
|||||||
[]
|
[]
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub struct Inner {
|
||||||
|
userdb: UserDB,
|
||||||
|
//passdb: PassDB,
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(Clone)]
|
||||||
|
pub struct Users {
|
||||||
|
inner: Arc<Inner>
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Users {
|
||||||
|
pub fn new(env: Arc<Environment>) -> anyhow::Result<Self> {
|
||||||
|
let userdb = unsafe { UserDB::create(env.clone()).unwrap() };
|
||||||
|
//let passdb = unsafe { PassDB::create(env).unwrap() };
|
||||||
|
Ok(Self { inner: Arc::new(Inner { userdb }) })
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn load_file<P: AsRef<Path>>(&self, path: P) -> anyhow::Result<()> {
|
||||||
|
let f = std::fs::read(path)?;
|
||||||
|
let mut map: HashMap<String, UserData> = toml::from_slice(&f)?;
|
||||||
|
|
||||||
|
for (uid, mut userdata) in map {
|
||||||
|
userdata.passwd = userdata.passwd.map(|pw| if !pw.starts_with("$argon2") {
|
||||||
|
let config = argon2::Config::default();
|
||||||
|
let salt: [u8; 16] = rand::random();
|
||||||
|
let hash = argon2::hash_encoded(pw.as_bytes(), &salt, &config)
|
||||||
|
.expect(&format!("Failed to hash password for {}: ", uid));
|
||||||
|
tracing::debug!("Hashed pw for {} to {}", uid, hash);
|
||||||
|
|
||||||
|
hash
|
||||||
|
} else {
|
||||||
|
pw
|
||||||
|
});
|
||||||
|
let user = db::User { id: uid.clone(), userdata };
|
||||||
|
tracing::trace!(%uid, ?user, "Storing user object");
|
||||||
|
self.inner.userdb.put(uid.as_str(), &user);
|
||||||
|
}
|
||||||
|
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
|
}
|
@ -5,8 +5,11 @@ use std::net::ToSocketAddrs;
|
|||||||
use std::os::unix::prelude::AsRawFd;
|
use std::os::unix::prelude::AsRawFd;
|
||||||
use std::str::FromStr;
|
use std::str::FromStr;
|
||||||
use std::{env, io, io::Write, path::PathBuf};
|
use std::{env, io, io::Write, path::PathBuf};
|
||||||
|
use std::sync::Arc;
|
||||||
use anyhow::Context;
|
use anyhow::Context;
|
||||||
|
use lmdb::{Environment, EnvironmentFlags};
|
||||||
use nix::NixPath;
|
use nix::NixPath;
|
||||||
|
use diflouroborane::users::Users;
|
||||||
|
|
||||||
fn main() -> anyhow::Result<()> {
|
fn main() -> anyhow::Result<()> {
|
||||||
// Argument parsing
|
// Argument parsing
|
||||||
@ -60,6 +63,7 @@ fn main() -> anyhow::Result<()> {
|
|||||||
Arg::new("load")
|
Arg::new("load")
|
||||||
.help("Load values into the internal databases")
|
.help("Load values into the internal databases")
|
||||||
.long("load")
|
.long("load")
|
||||||
|
.takes_value(true)
|
||||||
.conflicts_with("dump"),
|
.conflicts_with("dump"),
|
||||||
)
|
)
|
||||||
.arg(Arg::new("keylog")
|
.arg(Arg::new("keylog")
|
||||||
@ -103,10 +107,25 @@ fn main() -> anyhow::Result<()> {
|
|||||||
std::process::exit(-1);
|
std::process::exit(-1);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
} else if matches.is_present("dump") {
|
}
|
||||||
|
|
||||||
|
let mut config = config::read(&PathBuf::from_str(configpath).unwrap()).unwrap();
|
||||||
|
|
||||||
|
if matches.is_present("dump") {
|
||||||
unimplemented!()
|
unimplemented!()
|
||||||
} else if matches.is_present("load") {
|
} else if matches.is_present("load") {
|
||||||
unimplemented!()
|
Diflouroborane::init_logging(&config);
|
||||||
|
let env = Environment::new()
|
||||||
|
.set_flags( EnvironmentFlags::WRITE_MAP
|
||||||
|
| EnvironmentFlags::NO_SUB_DIR
|
||||||
|
| EnvironmentFlags::NO_TLS
|
||||||
|
| EnvironmentFlags::NO_READAHEAD)
|
||||||
|
.set_max_dbs(2)
|
||||||
|
.open(config.db_path.as_ref())
|
||||||
|
.map(Arc::new)?;
|
||||||
|
let userdb = Users::new(env).context("Failed to open users DB file")?;
|
||||||
|
userdb.load_file(matches.value_of("load").unwrap());
|
||||||
|
return Ok(())
|
||||||
} else {
|
} else {
|
||||||
let keylog = matches.value_of("keylog");
|
let keylog = matches.value_of("keylog");
|
||||||
// When passed an empty string (i.e no value) take the value from the env
|
// When passed an empty string (i.e no value) take the value from the env
|
||||||
@ -121,8 +140,6 @@ fn main() -> anyhow::Result<()> {
|
|||||||
keylog.map(PathBuf::from)
|
keylog.map(PathBuf::from)
|
||||||
};
|
};
|
||||||
|
|
||||||
let mut config = config::read(&PathBuf::from_str(configpath).unwrap()).unwrap();
|
|
||||||
|
|
||||||
config.tlskeylog = keylog;
|
config.tlskeylog = keylog;
|
||||||
config.verbosity = matches.occurrences_of("verbosity") as isize;
|
config.verbosity = matches.occurrences_of("verbosity") as isize;
|
||||||
if config.verbosity == 0 && matches.is_present("quiet") {
|
if config.verbosity == 0 && matches.is_present("quiet") {
|
||||||
|
Loading…
Reference in New Issue
Block a user