Better user

This commit is contained in:
Nadja Reitzenstein 2021-09-19 22:53:43 +02:00
parent 2fe6aa41c1
commit 006ae0af68
8 changed files with 75 additions and 48 deletions

View File

@ -15,6 +15,7 @@ mod machine;
mod machines; mod machines;
use machines::Machines; use machines::Machines;
mod user;
mod users; mod users;
use users::Users; use users::Users;

27
src/api/user.rs Normal file
View File

@ -0,0 +1,27 @@
use crate::db::access::PermRule;
use crate::db::user as db;
use crate::schema::user_capnp::user::*;
#[derive(Clone)]
pub struct User {
user: db::User,
perms: Vec<PermRule>,
}
impl User {
pub fn new(user: db::User, perms: Vec<PermRule>) -> Self {
Self { user, perms }
}
pub fn fill(&self, builder: &mut Builder) {
builder.set_username(&self.user.id.uid);
if let Some(ref realm) = &self.user.id.realm {
let mut space = builder.reborrow().init_space();
space.set_name(&realm);
}
}
}
impl info::Server for User {}
impl manage::Server for User {}
impl admin::Server for User {}

View File

@ -19,8 +19,9 @@ impl user_system::Server for Users {
fn info( fn info(
&mut self, &mut self,
_: user_system::InfoParams, _: user_system::InfoParams,
_: user_system::InfoResults, mut results: user_system::InfoResults,
) -> Promise<(), capnp::Error> { ) -> Promise<(), capnp::Error> {
results.get().set_info(capnp_rpc::new_client(self.clone()));
Promise::ok(()) Promise::ok(())
} }
@ -31,13 +32,23 @@ impl user_system::Server for Users {
) -> Promise<(), capnp::Error> { ) -> Promise<(), capnp::Error> {
let perm: &Permission = Permission::new("bffh.users.manage"); let perm: &Permission = Permission::new("bffh.users.manage");
if self.perms.iter().any(|rule| rule.match_perm(perm)) { if self.perms.iter().any(|rule| rule.match_perm(perm)) {
results.get().set_manage(capnp_rpc::new_client(self.clone())); results
.get()
.set_manage(capnp_rpc::new_client(self.clone()));
} }
Promise::ok(()) Promise::ok(())
} }
} }
impl info::Server for Users {} impl info::Server for Users {
fn get_user_self(
&mut self,
_: info::GetUserSelfParams,
mut results: info::GetUserSelfResults,
) -> Promise<(), capnp::Error> {
Promise::ok(())
}
}
impl manage::Server for Users {} impl manage::Server for Users {}

View File

@ -38,6 +38,14 @@ pub struct Config {
pub init_connections: Box<[(String, String)]>, pub init_connections: Box<[(String, String)]>,
pub db_path: PathBuf, pub db_path: PathBuf,
pub roles: HashMap<String, RoleConfig>,
}
#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct RoleConfig {
parents: Vec<String>,
permissions: Vec<PermRule>,
} }
#[derive(Debug, Clone, Serialize, Deserialize)] #[derive(Debug, Clone, Serialize, Deserialize)]
@ -97,6 +105,7 @@ impl Default for Config {
]), ]),
db_path: PathBuf::from("/run/bffh/database"), db_path: PathBuf::from("/run/bffh/database"),
roles: HashMap::new(),
} }
} }
} }

View File

@ -35,15 +35,6 @@ impl Session {
Session { log, user, accessdb } Session { log, user, accessdb }
} }
/// Check if the current session has a certain permission
pub async fn check_permission<P: AsRef<Permission>>(&self, perm: &P) -> Result<bool> {
if let Some(user) = self.user.lock().await.as_ref() {
self.accessdb.check(&user.data, perm).await
} else {
Ok(false)
}
}
} }
pub struct ConnectionHandler { pub struct ConnectionHandler {

View File

@ -34,24 +34,6 @@ impl AccessControl {
} }
} }
pub async fn check<P: AsRef<Permission>>(&self, user: &UserData, perm: &P) -> Result<bool> {
if self.internal.check(user, perm.as_ref())? {
return Ok(true);
}
return Ok(false);
}
pub async fn check_roles<P: AsRef<Permission>>(&self, roles: &[RoleIdentifier], perm: &P)
-> Result<bool>
{
if self.internal.check_roles(roles, perm.as_ref())? {
return Ok(true);
}
return Ok(false);
}
pub fn collect_permrules(&self, user: &UserData) -> Result<Vec<PermRule>> { pub fn collect_permrules(&self, user: &UserData) -> Result<Vec<PermRule>> {
self.internal.collect_permrules(user) self.internal.collect_permrules(user)
} }
@ -59,10 +41,6 @@ impl AccessControl {
pub fn dump_roles(&self) -> Result<Vec<(RoleIdentifier, Role)>> { pub fn dump_roles(&self) -> Result<Vec<(RoleIdentifier, Role)>> {
self.internal.dump_roles() self.internal.dump_roles()
} }
pub fn get_role(&self, role_id: &RoleIdentifier) -> Result<Option<Role>> {
self.internal.get_role(role_id)
}
} }
impl fmt::Debug for AccessControl { impl fmt::Debug for AccessControl {

View File

@ -40,18 +40,18 @@ impl User {
/// method or source /// method or source
pub struct UserId { pub struct UserId {
/// Main User ID. Generally an user name or similar. Locally unique /// Main User ID. Generally an user name or similar. Locally unique
uid: String, pub uid: String,
/// Sub user ID. /// Sub user ID.
/// ///
/// Can change scopes for permissions, e.g. having a +admin account with more permissions than /// Can change scopes for permissions, e.g. having a +admin account with more permissions than
/// the default account and +dashboard et.al. accounts that have restricted permissions for /// the default account and +dashboard et.al. accounts that have restricted permissions for
/// their applications /// their applications
subuid: Option<String>, pub subuid: Option<String>,
/// Realm this account originates. /// Realm this account originates.
/// ///
/// The Realm is usually described by a domain name but local policy may dictate an unrelated /// The Realm is usually described by a domain name but local policy may dictate an unrelated
/// mapping /// mapping
realm: Option<String>, pub realm: Option<String>,
} }
impl UserId { impl UserId {

View File

@ -123,24 +123,34 @@ impl Machine {
-> BoxFuture<'static, Result<ReturnToken>> -> BoxFuture<'static, Result<ReturnToken>>
{ {
let this = self.clone(); let this = self.clone();
let udata: Option<UserData> = who.map(|u| u.data.clone()); let perms: Vec<access::PermRule> = who
.map(|u| self.access.collect_permrules(&u.data))
.and_then(|result| result.ok())
.unwrap_or(vec![]);
let write: bool = perms.iter().any(|rule| rule.match_perm(&self.desc.privs.write));
let manage: bool = perms.iter().any(|rule| rule.match_perm(&self.desc.privs.manage));
let f = async move { let f = async move {
if let Some(udata) = udata { match &new_state.state {
if this.access.check(&udata, &this.desc.privs.write).await? { Status::Free => {
let mut guard = this.inner.lock().await;
guard.do_state_change(new_state);
return Ok(ReturnToken::new(this.inner.clone()))
}
} else {
if new_state == MachineState::free() {
let mut guard = this.inner.lock().await; let mut guard = this.inner.lock().await;
guard.do_state_change(new_state); guard.do_state_change(new_state);
return Ok(ReturnToken::new(this.inner.clone())); return Ok(ReturnToken::new(this.inner.clone()));
},
Status::InUse(_) | Status::ToCheck(_) if manage || write => {
let mut guard = this.inner.lock().await;
guard.do_state_change(new_state);
return Ok(ReturnToken::new(this.inner.clone()))
},
Status::Blocked(_) | Status::Disabled | Status::Reserved(_) if manage => {
let mut guard = this.inner.lock().await;
guard.do_state_change(new_state);
return Ok(ReturnToken::new(this.inner.clone()))
},
_ => {
return Err(Error::Denied);
} }
} }
return Err(Error::Denied);
}; };
Box::pin(f) Box::pin(f)