mirror of
https://gitlab.com/fabinfra/fabaccess/bffh.git
synced 2024-11-22 14:57:56 +01:00
Session initialization
This commit is contained in:
parent
2e9c7fbc19
commit
5c9b72c37d
@ -1,11 +1,12 @@
|
|||||||
use std::sync::Arc;
|
|
||||||
use rsasl::error::{SASLError, SessionError};
|
|
||||||
use rsasl::mechname::Mechname;
|
|
||||||
use rsasl::{Property, SASL};
|
|
||||||
use rsasl::session::{Session, SessionData};
|
|
||||||
use rsasl::validate::Validation;
|
|
||||||
use crate::users::db::UserDB;
|
use crate::users::db::UserDB;
|
||||||
use crate::users::Users;
|
use crate::users::Users;
|
||||||
|
use rsasl::error::{SASLError, SessionError};
|
||||||
|
use rsasl::mechname::Mechname;
|
||||||
|
use rsasl::property::{AuthId, Password};
|
||||||
|
use rsasl::session::{Session, SessionData};
|
||||||
|
use rsasl::validate::{validations, Validation};
|
||||||
|
use rsasl::{Property, SASL};
|
||||||
|
use std::sync::Arc;
|
||||||
|
|
||||||
pub mod db;
|
pub mod db;
|
||||||
|
|
||||||
@ -14,12 +15,40 @@ struct Callback {
|
|||||||
}
|
}
|
||||||
impl Callback {
|
impl Callback {
|
||||||
pub fn new(users: Users) -> Self {
|
pub fn new(users: Users) -> Self {
|
||||||
Self { users, }
|
Self { users }
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
impl rsasl::callback::Callback for Callback {
|
impl rsasl::callback::Callback for Callback {
|
||||||
fn validate(&self, session: &mut SessionData, validation: Validation, mechanism: &Mechname) -> Result<(), SessionError> {
|
fn validate(
|
||||||
todo!()
|
&self,
|
||||||
|
session: &mut SessionData,
|
||||||
|
validation: Validation,
|
||||||
|
mechanism: &Mechname,
|
||||||
|
) -> Result<(), SessionError> {
|
||||||
|
match validation {
|
||||||
|
validations::SIMPLE => {
|
||||||
|
let authnid = session
|
||||||
|
.get_property::<AuthId>()
|
||||||
|
.ok_or(SessionError::no_property::<AuthId>())?;
|
||||||
|
let user = self
|
||||||
|
.users
|
||||||
|
.get_user(authnid.as_str())
|
||||||
|
.ok_or(SessionError::AuthenticationFailure)?;
|
||||||
|
let passwd = session
|
||||||
|
.get_property::<Password>()
|
||||||
|
.ok_or(SessionError::no_property::<Password>())?;
|
||||||
|
|
||||||
|
if user
|
||||||
|
.check_password(passwd.as_bytes())
|
||||||
|
.map_err(|e| SessionError::AuthenticationFailure)?
|
||||||
|
{
|
||||||
|
Ok(())
|
||||||
|
} else {
|
||||||
|
Err(SessionError::AuthenticationFailure)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
_ => Err(SessionError::no_validate(validation)),
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -41,14 +70,20 @@ impl AuthenticationHandle {
|
|||||||
pub fn new(userdb: Users) -> Self {
|
pub fn new(userdb: Users) -> Self {
|
||||||
let mut rsasl = SASL::new();
|
let mut rsasl = SASL::new();
|
||||||
rsasl.install_callback(Arc::new(Callback::new(userdb)));
|
rsasl.install_callback(Arc::new(Callback::new(userdb)));
|
||||||
Self { inner: Arc::new(Inner::new(rsasl)) }
|
Self {
|
||||||
|
inner: Arc::new(Inner::new(rsasl)),
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn start(&self, mechanism: &Mechname) -> anyhow::Result<Session> {
|
pub fn start(&self, mechanism: &Mechname) -> anyhow::Result<Session> {
|
||||||
Ok(self.inner.rsasl.server_start(mechanism)?)
|
Ok(self.inner.rsasl.server_start(mechanism)?)
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn list_available_mechs(&self) -> impl IntoIterator<Item=&Mechname> {
|
pub fn list_available_mechs(&self) -> impl IntoIterator<Item = &Mechname> {
|
||||||
self.inner.rsasl.server_mech_list().into_iter().map(|m| m.mechanism)
|
self.inner
|
||||||
|
.rsasl
|
||||||
|
.server_mech_list()
|
||||||
|
.into_iter()
|
||||||
|
.map(|m| m.mechanism)
|
||||||
}
|
}
|
||||||
}
|
}
|
@ -1,34 +1,26 @@
|
|||||||
use std::sync::Arc;
|
use std::sync::Arc;
|
||||||
use crate::authorization::permissions::Permission;
|
use crate::authorization::permissions::Permission;
|
||||||
use crate::authorization::roles::Role;
|
use crate::authorization::roles::{Role, Roles};
|
||||||
use crate::Users;
|
use crate::Users;
|
||||||
use crate::users::User;
|
use crate::users::UserRef;
|
||||||
|
|
||||||
pub mod permissions;
|
pub mod permissions;
|
||||||
pub mod roles;
|
pub mod roles;
|
||||||
|
|
||||||
struct Inner {
|
|
||||||
users: Users,
|
|
||||||
}
|
|
||||||
impl Inner {
|
|
||||||
pub fn new(users: Users) -> Self {
|
|
||||||
Self { users }
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
#[derive(Clone)]
|
#[derive(Clone)]
|
||||||
pub struct AuthorizationHandle {
|
pub struct AuthorizationHandle {
|
||||||
users: Users,
|
users: Users,
|
||||||
|
roles: Roles,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl AuthorizationHandle {
|
impl AuthorizationHandle {
|
||||||
pub fn new(users: Users) -> Self {
|
pub fn new(users: Users, roles: Roles) -> Self {
|
||||||
Self { users }
|
Self { users, roles }
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn get_user_roles(&self, uid: impl AsRef<str>) -> Option<impl IntoIterator<Item=Role>> {
|
pub fn get_user_roles(&self, uid: impl AsRef<str>) -> Option<Vec<String>> {
|
||||||
let user = self.users.get_user(uid.as_ref())?;
|
let user = self.users.get_user(uid.as_ref())?;
|
||||||
Some([])
|
Some(user.userdata.roles.clone())
|
||||||
}
|
}
|
||||||
|
|
||||||
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 {
|
||||||
|
@ -1,6 +1,32 @@
|
|||||||
|
use std::collections::HashMap;
|
||||||
use std::fmt;
|
use std::fmt;
|
||||||
|
use once_cell::sync::OnceCell;
|
||||||
use crate::authorization::permissions::PermRule;
|
use crate::authorization::permissions::PermRule;
|
||||||
|
|
||||||
|
static ROLES: OnceCell<HashMap<String, Role>> = OnceCell::new();
|
||||||
|
|
||||||
|
#[derive(Copy, Clone)]
|
||||||
|
pub struct Roles {
|
||||||
|
roles: &'static HashMap<String, Role>,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Roles {
|
||||||
|
pub fn new(roles: HashMap<String, Role>) -> Self {
|
||||||
|
let span = tracing::debug_span!("roles", "Creating Roles handle");
|
||||||
|
let _guard = span.enter();
|
||||||
|
|
||||||
|
let this = ROLES.get_or_init(|| {
|
||||||
|
tracing::debug!("Initializing global roles…");
|
||||||
|
roles
|
||||||
|
});
|
||||||
|
Self { roles: this }
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn get(self, roleid: &str) -> Option<&Role> {
|
||||||
|
self.roles.get(roleid)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
/// A "Role" from the Authorization perspective
|
/// 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
|
/// You can think of a role as a bundle of permissions relating to other roles. In most cases a
|
||||||
@ -22,7 +48,7 @@ pub struct Role {
|
|||||||
/// This makes situations where different levels of access are required easier: Each higher
|
/// 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
|
/// 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
|
/// you are allowed to manage a machine you are then also allowed to use it and so on
|
||||||
parents: Vec<RoleIdentifier>,
|
parents: Vec<String>,
|
||||||
|
|
||||||
// If a role doesn't define permissions, default to an empty Vec.
|
// If a role doesn't define permissions, default to an empty Vec.
|
||||||
#[serde(default, skip_serializing_if = "Vec::is_empty")]
|
#[serde(default, skip_serializing_if = "Vec::is_empty")]
|
||||||
@ -30,7 +56,7 @@ pub struct Role {
|
|||||||
}
|
}
|
||||||
|
|
||||||
impl Role {
|
impl Role {
|
||||||
pub fn new(parents: Vec<RoleIdentifier>, permissions: Vec<PermRule>) -> Self {
|
pub fn new(parents: Vec<String>, permissions: Vec<PermRule>) -> Self {
|
||||||
Self { parents, permissions }
|
Self { parents, permissions }
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -59,88 +85,3 @@ impl fmt::Display for Role {
|
|||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
type SourceID = String;
|
|
||||||
|
|
||||||
fn split_once(s: &str, split: char) -> Option<(&str, &str)> {
|
|
||||||
s
|
|
||||||
.find(split)
|
|
||||||
.map(|idx| (&s[..idx], &s[(idx+1)..]))
|
|
||||||
}
|
|
||||||
|
|
||||||
#[derive(Debug, Clone, PartialEq, Eq, Hash, serde::Serialize, serde::Deserialize)]
|
|
||||||
#[serde(try_from = "String")]
|
|
||||||
#[serde(into = "String")]
|
|
||||||
/// Universal (relative) id of a role
|
|
||||||
pub struct RoleIdentifier {
|
|
||||||
/// 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,
|
|
||||||
}
|
|
||||||
|
|
||||||
impl RoleIdentifier {
|
|
||||||
pub fn new<>(name: &str, source: &str) -> Self {
|
|
||||||
Self { name: name.to_string(), source: source.to_string() }
|
|
||||||
}
|
|
||||||
pub fn from_strings(name: String, source: String) -> Self {
|
|
||||||
Self { name, source }
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
impl fmt::Display for RoleIdentifier {
|
|
||||||
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
|
|
||||||
if self.source != "" {
|
|
||||||
write!(f, "{}/{}", self.name, self.source)
|
|
||||||
} else {
|
|
||||||
write!(f, "{}", self.name)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
impl std::str::FromStr for RoleIdentifier {
|
|
||||||
type Err = RoleFromStrError;
|
|
||||||
|
|
||||||
fn from_str(s: &str) -> std::result::Result<Self, Self::Err> {
|
|
||||||
if let Some((name, source)) = split_once(s, '/') {
|
|
||||||
Ok(RoleIdentifier { name: name.to_string(), source: source.to_string() })
|
|
||||||
} else {
|
|
||||||
Ok(RoleIdentifier { name: s.to_string(), source: String::new() })
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
impl TryFrom<String> for RoleIdentifier {
|
|
||||||
type Error = RoleFromStrError;
|
|
||||||
|
|
||||||
fn try_from(s: String) -> std::result::Result<Self, Self::Error> {
|
|
||||||
<RoleIdentifier as std::str::FromStr>::from_str(&s)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
impl Into<String> for RoleIdentifier {
|
|
||||||
fn into(self) -> String {
|
|
||||||
format!("{}", self)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
impl RoleIdentifier {
|
|
||||||
pub fn local_from_str(source: String, name: String) -> Self {
|
|
||||||
RoleIdentifier { 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'."),
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
@ -5,7 +5,7 @@ use crate::capnp::machinesystem::Machines;
|
|||||||
use crate::capnp::permissionsystem::Permissions;
|
use crate::capnp::permissionsystem::Permissions;
|
||||||
use crate::capnp::user_system::Users;
|
use crate::capnp::user_system::Users;
|
||||||
use crate::session::{SessionHandle, SessionManager};
|
use crate::session::{SessionHandle, SessionManager};
|
||||||
use crate::users::User;
|
use crate::users::UserRef;
|
||||||
|
|
||||||
#[derive(Debug, Clone)]
|
#[derive(Debug, Clone)]
|
||||||
pub struct APISession;
|
pub struct APISession;
|
||||||
|
@ -9,7 +9,6 @@ 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::RoleIdentifier;
|
|
||||||
|
|
||||||
type Result<T> = std::result::Result<T, serde_dhall::Error>;
|
type Result<T> = std::result::Result<T, serde_dhall::Error>;
|
||||||
|
|
||||||
@ -66,7 +65,7 @@ pub struct Config {
|
|||||||
pub db_path: PathBuf,
|
pub db_path: PathBuf,
|
||||||
pub auditlog_path: PathBuf,
|
pub auditlog_path: PathBuf,
|
||||||
|
|
||||||
pub roles: HashMap<RoleIdentifier, RoleConfig>,
|
pub roles: HashMap<String, RoleConfig>,
|
||||||
|
|
||||||
#[serde(flatten)]
|
#[serde(flatten)]
|
||||||
pub tlsconfig: TlsListen,
|
pub tlsconfig: TlsListen,
|
||||||
@ -90,7 +89,7 @@ impl Config {
|
|||||||
#[derive(Debug, Clone, Serialize, Deserialize)]
|
#[derive(Debug, Clone, Serialize, Deserialize)]
|
||||||
pub struct RoleConfig {
|
pub struct RoleConfig {
|
||||||
#[serde(default = "Vec::new")]
|
#[serde(default = "Vec::new")]
|
||||||
pub parents: Vec<RoleIdentifier>,
|
pub parents: Vec<String>,
|
||||||
#[serde(default = "Vec::new")]
|
#[serde(default = "Vec::new")]
|
||||||
pub permissions: Vec<PermRule>,
|
pub permissions: Vec<PermRule>,
|
||||||
}
|
}
|
||||||
|
@ -119,7 +119,7 @@ impl Diflouroborane {
|
|||||||
let tlsconfig = TlsConfig::new(config.tlskeylog.as_ref(), !config.is_quiet())?;
|
let tlsconfig = TlsConfig::new(config.tlskeylog.as_ref(), !config.is_quiet())?;
|
||||||
let acceptor = tlsconfig.make_tls_acceptor(&config.tlsconfig)?;
|
let acceptor = tlsconfig.make_tls_acceptor(&config.tlsconfig)?;
|
||||||
|
|
||||||
let sessionmanager = SessionManager::new();
|
let sessionmanager = SessionManager::new(userdb.clone());
|
||||||
let authentication = AuthenticationHandle::new(userdb.clone());
|
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))?;
|
||||||
|
@ -9,7 +9,7 @@ use crate::resources::modules::fabaccess::{MachineState, Status};
|
|||||||
use crate::resources::state::db::StateDB;
|
use crate::resources::state::db::StateDB;
|
||||||
use crate::resources::state::State;
|
use crate::resources::state::State;
|
||||||
use crate::session::SessionHandle;
|
use crate::session::SessionHandle;
|
||||||
use crate::users::User;
|
use crate::users::UserRef;
|
||||||
|
|
||||||
pub mod claim;
|
pub mod claim;
|
||||||
pub mod db;
|
pub mod db;
|
||||||
@ -173,7 +173,7 @@ impl Resource {
|
|||||||
session.has_disclose(self) || self.is_owned_by(session.get_user())
|
session.has_disclose(self) || self.is_owned_by(session.get_user())
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn is_owned_by(&self, owner: User) -> bool {
|
pub fn is_owned_by(&self, owner: UserRef) -> bool {
|
||||||
match self.get_state().state {
|
match self.get_state().state {
|
||||||
Status::Free | Status::Disabled => false,
|
Status::Free | Status::Disabled => false,
|
||||||
|
|
||||||
|
@ -9,7 +9,7 @@ use crate::oidvalue;
|
|||||||
use crate::resources::state::{State};
|
use crate::resources::state::{State};
|
||||||
use crate::resources::state::value::Value;
|
use crate::resources::state::value::Value;
|
||||||
use crate::session::SessionHandle;
|
use crate::session::SessionHandle;
|
||||||
use crate::users::User;
|
use crate::users::UserRef;
|
||||||
|
|
||||||
/// Status of a Machine
|
/// Status of a Machine
|
||||||
#[derive(
|
#[derive(
|
||||||
@ -28,15 +28,15 @@ pub enum Status {
|
|||||||
/// Not currently used by anybody
|
/// Not currently used by anybody
|
||||||
Free,
|
Free,
|
||||||
/// Used by somebody
|
/// Used by somebody
|
||||||
InUse(User),
|
InUse(UserRef),
|
||||||
/// Was used by somebody and now needs to be checked for cleanliness
|
/// Was used by somebody and now needs to be checked for cleanliness
|
||||||
ToCheck(User),
|
ToCheck(UserRef),
|
||||||
/// Not used by anybody but also can not be used. E.g. down for maintenance
|
/// Not used by anybody but also can not be used. E.g. down for maintenance
|
||||||
Blocked(User),
|
Blocked(UserRef),
|
||||||
/// Disabled for some other reason
|
/// Disabled for some other reason
|
||||||
Disabled,
|
Disabled,
|
||||||
/// Reserved
|
/// Reserved
|
||||||
Reserved(User),
|
Reserved(UserRef),
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(
|
#[derive(
|
||||||
@ -54,7 +54,7 @@ pub enum Status {
|
|||||||
/// The status of the machine
|
/// The status of the machine
|
||||||
pub struct MachineState {
|
pub struct MachineState {
|
||||||
pub state: Status,
|
pub state: Status,
|
||||||
pub previous: Option<User>,
|
pub previous: Option<UserRef>,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl MachineState {
|
impl MachineState {
|
||||||
@ -76,42 +76,42 @@ impl MachineState {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn free(previous: Option<User>) -> Self {
|
pub fn free(previous: Option<UserRef>) -> Self {
|
||||||
Self {
|
Self {
|
||||||
state: Status::Free,
|
state: Status::Free,
|
||||||
previous,
|
previous,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn used(user: User, previous: Option<User>) -> Self {
|
pub fn used(user: UserRef, previous: Option<UserRef>) -> Self {
|
||||||
Self {
|
Self {
|
||||||
state: Status::InUse(user),
|
state: Status::InUse(user),
|
||||||
previous,
|
previous,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn blocked(user: User, previous: Option<User>) -> Self {
|
pub fn blocked(user: UserRef, previous: Option<UserRef>) -> Self {
|
||||||
Self {
|
Self {
|
||||||
state: Status::Blocked(user),
|
state: Status::Blocked(user),
|
||||||
previous,
|
previous,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn disabled(previous: Option<User>) -> Self {
|
pub fn disabled(previous: Option<UserRef>) -> Self {
|
||||||
Self {
|
Self {
|
||||||
state: Status::Disabled,
|
state: Status::Disabled,
|
||||||
previous,
|
previous,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn reserved(user: User, previous: Option<User>) -> Self {
|
pub fn reserved(user: UserRef, previous: Option<UserRef>) -> Self {
|
||||||
Self {
|
Self {
|
||||||
state: Status::Reserved(user),
|
state: Status::Reserved(user),
|
||||||
previous,
|
previous,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn check(user: User) -> Self {
|
pub fn check(user: UserRef) -> Self {
|
||||||
Self {
|
Self {
|
||||||
state: Status::ToCheck(user.clone()),
|
state: Status::ToCheck(user.clone()),
|
||||||
previous: Some(user),
|
previous: Some(user),
|
||||||
|
37
bffhd/session/db.rs
Normal file
37
bffhd/session/db.rs
Normal file
@ -0,0 +1,37 @@
|
|||||||
|
use std::sync::Arc;
|
||||||
|
use lmdb::{DatabaseFlags, Environment};
|
||||||
|
|
||||||
|
use rkyv::{Archive, Serialize, Deserialize};
|
||||||
|
|
||||||
|
use crate::db::{AllocAdapter, DB, RawDB};
|
||||||
|
use crate::users::UserRef;
|
||||||
|
|
||||||
|
#[derive(Clone, Debug, PartialEq, Eq)]
|
||||||
|
#[derive(Archive, Serialize, Deserialize)]
|
||||||
|
pub struct Session {
|
||||||
|
userid: UserRef,
|
||||||
|
}
|
||||||
|
|
||||||
|
type Adapter = AllocAdapter<Session>;
|
||||||
|
pub struct SessionCache {
|
||||||
|
env: Arc<Environment>,
|
||||||
|
db: DB<Adapter>,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl SessionCache {
|
||||||
|
pub unsafe fn new(env: Arc<Environment>, db: RawDB) -> Self {
|
||||||
|
let db = DB::new_unchecked(db);
|
||||||
|
Self { env, db }
|
||||||
|
}
|
||||||
|
|
||||||
|
pub unsafe fn open(env: Arc<Environment>) -> lmdb::Result<Self> {
|
||||||
|
let db = RawDB::open(&env, Some("sessions"))?;
|
||||||
|
Ok(Self::new(env, db))
|
||||||
|
}
|
||||||
|
|
||||||
|
pub unsafe fn create(env: Arc<Environment>) -> lmdb::Result<Self> {
|
||||||
|
let flags = DatabaseFlags::empty();
|
||||||
|
let db = RawDB::create(&env, Some("sessions"), flags)?;
|
||||||
|
Ok(Self::new(env, db))
|
||||||
|
}
|
||||||
|
}
|
@ -1,38 +1,46 @@
|
|||||||
|
use std::path::PathBuf;
|
||||||
use std::sync::Arc;
|
use std::sync::Arc;
|
||||||
|
use anyhow::Context;
|
||||||
|
use lmdb::Environment;
|
||||||
|
use once_cell::sync::OnceCell;
|
||||||
use crate::authorization::roles::Role;
|
use crate::authorization::roles::Role;
|
||||||
use crate::resources::Resource;
|
use crate::resources::Resource;
|
||||||
use crate::users::User;
|
use crate::session::db::SessionCache;
|
||||||
|
use crate::Users;
|
||||||
|
use crate::users::UserRef;
|
||||||
|
|
||||||
struct Inner {
|
mod db;
|
||||||
|
|
||||||
}
|
static SESSION_CACHE: OnceCell<SessionCache> = OnceCell::new();
|
||||||
impl Inner {
|
|
||||||
pub fn new() -> Self {
|
|
||||||
Self { }
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
#[derive(Clone)]
|
#[derive(Clone)]
|
||||||
pub struct SessionManager {
|
pub struct SessionManager {
|
||||||
inner: Arc<Inner>,
|
users: Users,
|
||||||
}
|
}
|
||||||
impl SessionManager {
|
impl SessionManager {
|
||||||
pub fn new() -> Self {
|
pub fn new(users: Users) -> Self {
|
||||||
Self {
|
Self { users }
|
||||||
inner: Arc::new(Inner::new()),
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// TODO: make infallible
|
||||||
pub fn open(&self, uid: impl AsRef<str>) -> Option<SessionHandle> {
|
pub fn open(&self, uid: impl AsRef<str>) -> Option<SessionHandle> {
|
||||||
unimplemented!()
|
let uid = uid.as_ref();
|
||||||
|
if let Some(user) = self.users.get_user(uid) {
|
||||||
|
tracing::trace!(uid, "opening new session for user");
|
||||||
|
Some(SessionHandle { user: UserRef::new(user.id) })
|
||||||
|
} else {
|
||||||
|
None
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Clone, Debug)]
|
#[derive(Clone, Debug)]
|
||||||
pub struct SessionHandle {
|
pub struct SessionHandle {
|
||||||
|
user: UserRef,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl SessionHandle {
|
impl SessionHandle {
|
||||||
pub fn get_user(&self) -> User {
|
pub fn get_user(&self) -> UserRef {
|
||||||
unimplemented!()
|
unimplemented!()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -4,9 +4,9 @@ use lmdb::{RwTransaction, Transaction};
|
|||||||
use std::collections::{HashMap, HashSet};
|
use std::collections::{HashMap, HashSet};
|
||||||
use std::path::Path;
|
use std::path::Path;
|
||||||
use std::sync::Arc;
|
use std::sync::Arc;
|
||||||
|
use anyhow::Context;
|
||||||
|
|
||||||
use rkyv::{Archived, Deserialize};
|
use rkyv::{Archived, Deserialize};
|
||||||
use crate::authorization::roles::RoleIdentifier;
|
|
||||||
|
|
||||||
#[derive(
|
#[derive(
|
||||||
Clone,
|
Clone,
|
||||||
@ -24,6 +24,17 @@ pub struct User {
|
|||||||
pub userdata: UserData,
|
pub userdata: UserData,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
impl User {
|
||||||
|
pub fn check_password(&self, pwd: &[u8]) -> anyhow::Result<bool> {
|
||||||
|
if let Some(ref encoded) = self.userdata.passwd {
|
||||||
|
argon2::verify_encoded(encoded, pwd)
|
||||||
|
.context("Stored password is an invalid string")
|
||||||
|
} else {
|
||||||
|
Ok(false)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
#[derive(
|
#[derive(
|
||||||
Clone,
|
Clone,
|
||||||
PartialEq,
|
PartialEq,
|
||||||
|
@ -26,7 +26,7 @@ use std::sync::Arc;
|
|||||||
pub mod db;
|
pub mod db;
|
||||||
|
|
||||||
pub use crate::authentication::db::PassDB;
|
pub use crate::authentication::db::PassDB;
|
||||||
use crate::authorization::roles::{Role, RoleIdentifier};
|
use crate::authorization::roles::Role;
|
||||||
use crate::db::LMDBorrow;
|
use crate::db::LMDBorrow;
|
||||||
use crate::users::db::UserData;
|
use crate::users::db::UserData;
|
||||||
use crate::UserDB;
|
use crate::UserDB;
|
||||||
@ -43,13 +43,13 @@ use crate::UserDB;
|
|||||||
serde::Deserialize,
|
serde::Deserialize,
|
||||||
)]
|
)]
|
||||||
#[archive_attr(derive(Debug, PartialEq))]
|
#[archive_attr(derive(Debug, PartialEq))]
|
||||||
pub struct User {
|
pub struct UserRef {
|
||||||
id: String,
|
id: String,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl User {
|
impl UserRef {
|
||||||
pub fn new(id: String) -> Self {
|
pub fn new(id: String) -> Self {
|
||||||
User { id }
|
UserRef { id }
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn get_username(&self) -> &str {
|
pub fn get_username(&self) -> &str {
|
||||||
@ -73,7 +73,7 @@ impl Users {
|
|||||||
let userdb = USERDB
|
let userdb = USERDB
|
||||||
.get_or_try_init(|| {
|
.get_or_try_init(|| {
|
||||||
tracing::debug!("Global resource not yet initialized, initializing…");
|
tracing::debug!("Global resource not yet initialized, initializing…");
|
||||||
unsafe { UserDB::create(env.clone()) }
|
unsafe { UserDB::create(env) }
|
||||||
})
|
})
|
||||||
.context("Failed to open userdb")?;
|
.context("Failed to open userdb")?;
|
||||||
|
|
||||||
|
Loading…
Reference in New Issue
Block a user