User admin methods

This commit is contained in:
Nadja Reitzenstein 2022-03-21 00:01:50 +01:00
parent 3eab5b8702
commit 5538dd6751
6 changed files with 120 additions and 53 deletions

View File

@ -40,7 +40,7 @@ impl Machine {
builder.set_urn(&format!("urn:fabaccess:resource:{}", self.resource.get_id())); builder.set_urn(&format!("urn:fabaccess:resource:{}", self.resource.get_id()));
{ {
let user = self.session.get_user(); let user = self.session.get_user_ref();
let state = self.resource.get_state_ref(); let state = self.resource.get_state_ref();
let state = state.as_ref(); let state = state.as_ref();
@ -113,7 +113,7 @@ impl UseServer for Machine {
let resource = self.resource.clone(); let resource = self.resource.clone();
let session = self.session.clone(); let session = self.session.clone();
Promise::from_future(async move { Promise::from_future(async move {
let user = session.get_user(); let user = session.get_user_ref();
resource.try_update(session, Status::InUse(user)).await; resource.try_update(session, Status::InUse(user)).await;
Ok(()) Ok(())
}) })
@ -127,7 +127,7 @@ impl UseServer for Machine {
let resource = self.resource.clone(); let resource = self.resource.clone();
let session = self.session.clone(); let session = self.session.clone();
Promise::from_future(async move { Promise::from_future(async move {
let user = session.get_user(); let user = session.get_user_ref();
resource resource
.try_update(session, Status::Reserved(user)) .try_update(session, Status::Reserved(user))
.await; .await;
@ -200,7 +200,7 @@ impl ManageServer for Machine {
mut result: manage::GetMachineInfoExtendedResults, mut result: manage::GetMachineInfoExtendedResults,
) -> Promise<(), ::capnp::Error> { ) -> Promise<(), ::capnp::Error> {
let mut builder = result.get(); let mut builder = result.get();
let user = User::new(self.session.clone()); let user = User::new_self(self.session.clone());
user.build_else(self.resource.get_current_user(), builder.reborrow().init_current_user()); user.build_else(self.resource.get_current_user(), builder.reborrow().init_current_user());
user.build_else(self.resource.get_previous_user(), builder.init_last_user()); user.build_else(self.resource.get_previous_user(), builder.init_last_user());
Promise::ok(()) Promise::ok(())
@ -233,7 +233,7 @@ impl ManageServer for Machine {
let session = self.session.clone(); let session = self.session.clone();
Promise::from_future(async move { Promise::from_future(async move {
resource resource
.force_set(Status::InUse(session.get_user())) .force_set(Status::InUse(session.get_user_ref()))
.await; .await;
Ok(()) Ok(())
}) })
@ -270,7 +270,7 @@ impl ManageServer for Machine {
let session = self.session.clone(); let session = self.session.clone();
Promise::from_future(async move { Promise::from_future(async move {
resource resource
.force_set(Status::Blocked(session.get_user())) .force_set(Status::Blocked(session.get_user_ref()))
.await; .await;
Ok(()) Ok(())
}) })
@ -295,7 +295,7 @@ impl AdminServer for Machine {
_: admin::ForceSetStateResults, _: admin::ForceSetStateResults,
) -> Promise<(), ::capnp::Error> { ) -> Promise<(), ::capnp::Error> {
use api::schema::machine_capnp::machine::MachineState as APIMState; use api::schema::machine_capnp::machine::MachineState as APIMState;
let user = self.session.get_user(); let user = self.session.get_user_ref();
let state = match pry!(pry!(params.get()).get_state()) { let state = match pry!(pry!(params.get()).get_state()) {
APIMState::Free => Status::Free, APIMState::Free => Status::Free,
APIMState::Blocked => Status::Blocked(user), APIMState::Blocked => Status::Blocked(user),

View File

@ -1,30 +1,55 @@
use capnp::capability::Promise;
use capnp_rpc::pry;
use crate::session::SessionHandle; use crate::session::SessionHandle;
use api::user_capnp::user::{admin, info, manage, Builder}; use api::user_capnp::user::{admin, info, manage, Builder};
use crate::users::UserRef; use crate::authorization::permissions::Permission;
use crate::users::{db, UserRef};
#[derive(Clone)]
pub struct User { pub struct User {
session: SessionHandle, session: SessionHandle,
user: UserRef,
} }
impl User { impl User {
pub fn new(session: SessionHandle) -> Self { pub fn new(session: SessionHandle, user: UserRef) -> Self {
Self { session } Self { session, user }
} }
pub fn build_else(&self, user: Option<UserRef>, mut builder: Builder) { pub fn new_self(session: SessionHandle) -> Self {
if let Some(user) = user { let user = session.get_user_ref();
builder.set_username(user.get_username()); Self::new(session, user)
}
} }
pub fn build_into(self, mut builder: Builder) { pub fn build_else(&self, user: Option<UserRef>, builder: Builder) {
let user = self.session.get_user(); if let Some(user) = user.and_then(|u| self.session.users.get_user(u.get_username())) {
builder.set_username(user.get_username()); self.fill(user, builder);
}
} }
pub fn build(session: SessionHandle, mut builder: Builder) { pub fn build(session: SessionHandle, mut builder: Builder) {
let this = Self::new(session); let this = Self::new_self(session);
this.build_into(builder) let user = this.session.get_user();
this.fill(user, builder);
}
pub fn fill(&self, user: db::User, mut builder: Builder) {
builder.set_username(user.id.as_str());
let client = Self::new(self.session.clone(), UserRef::new(user.id.clone()));
// We have permissions on ourself
let is_me = &self.session.get_user_ref().id == &user.id;
if is_me || self.session.has_perm(Permission::new("bffh.users.info")) {
builder.set_info(capnp_rpc::new_client(client.clone()));
}
if is_me {
builder.set_manage(capnp_rpc::new_client(client.clone()));
}
if self.session.has_perm(Permission::new("bffh.users.admin")) {
builder.set_admin(capnp_rpc::new_client(client.clone()));
}
} }
} }
@ -32,21 +57,25 @@ impl info::Server for User {
fn list_roles( fn list_roles(
&mut self, &mut self,
_: info::ListRolesParams, _: info::ListRolesParams,
_: info::ListRolesResults, mut result: info::ListRolesResults,
) -> ::capnp::capability::Promise<(), ::capnp::Error> { ) -> Promise<(), ::capnp::Error> {
::capnp::capability::Promise::err(::capnp::Error::unimplemented( let user = self.session.get_user();
"method not implemented".to_string(), let mut builder = result.get().init_roles(user.userdata.roles.len() as u32);
)) for (i, role) in user.userdata.roles.into_iter().enumerate() {
let mut b = builder.reborrow().get(i as u32);
b.set_name(role.as_str());
}
Promise::ok(())
} }
} }
impl manage::Server for User { impl manage::Server for User {
fn pwd( fn pwd(
&mut self, &mut self,
_: manage::PwdParams, params: manage::PwdParams,
_: manage::PwdResults, mut results: manage::PwdResults,
) -> ::capnp::capability::Promise<(), ::capnp::Error> { ) -> Promise<(), ::capnp::Error> {
::capnp::capability::Promise::err(::capnp::Error::unimplemented( Promise::err(::capnp::Error::unimplemented(
"method not implemented".to_string(), "method not implemented".to_string(),
)) ))
} }
@ -57,35 +86,55 @@ impl admin::Server for User {
&mut self, &mut self,
_: admin::GetUserInfoExtendedParams, _: admin::GetUserInfoExtendedParams,
_: admin::GetUserInfoExtendedResults, _: admin::GetUserInfoExtendedResults,
) -> ::capnp::capability::Promise<(), ::capnp::Error> { ) -> Promise<(), ::capnp::Error> {
::capnp::capability::Promise::err(::capnp::Error::unimplemented( Promise::err(::capnp::Error::unimplemented(
"method not implemented".to_string(), "method not implemented".to_string(),
)) ))
} }
fn add_role( fn add_role(
&mut self, &mut self,
_: admin::AddRoleParams, param: admin::AddRoleParams,
_: admin::AddRoleResults, _: admin::AddRoleResults,
) -> ::capnp::capability::Promise<(), ::capnp::Error> { ) -> Promise<(), ::capnp::Error> {
::capnp::capability::Promise::err(::capnp::Error::unimplemented( let rolename = pry!(pry!(pry!(param.get()).get_role()).get_name());
"method not implemented".to_string(),
)) if let Some(_role) = self.session.roles.get(rolename) {
let mut target = self.session.users.get_user(self.user.get_username()).unwrap();
// Only update if needed
if !target.userdata.roles.iter().any(|r| r.as_str() == rolename) {
target.userdata.roles.push(rolename.to_string());
self.session.users.put_user(self.user.get_username(), &target);
}
}
Promise::ok(())
} }
fn remove_role( fn remove_role(
&mut self, &mut self,
_: admin::RemoveRoleParams, param: admin::RemoveRoleParams,
_: admin::RemoveRoleResults, _: admin::RemoveRoleResults,
) -> ::capnp::capability::Promise<(), ::capnp::Error> { ) -> Promise<(), ::capnp::Error> {
::capnp::capability::Promise::err(::capnp::Error::unimplemented( let rolename = pry!(pry!(pry!(param.get()).get_role()).get_name());
"method not implemented".to_string(),
)) if let Some(_role) = self.session.roles.get(rolename) {
let mut target = self.session.users.get_user(self.user.get_username()).unwrap();
// Only update if needed
if target.userdata.roles.iter().any(|r| r.as_str() == rolename) {
target.userdata.roles.retain(|r| r.as_str() != rolename);
self.session.users.put_user(self.user.get_username(), &target);
}
}
Promise::ok(())
} }
fn pwd( fn pwd(
&mut self, &mut self,
_: admin::PwdParams, _: admin::PwdParams,
_: admin::PwdResults, _: admin::PwdResults,
) -> ::capnp::capability::Promise<(), ::capnp::Error> { ) -> Promise<(), ::capnp::Error> {
::capnp::capability::Promise::err(::capnp::Error::unimplemented( Promise::err(::capnp::Error::unimplemented(
"method not implemented".to_string(), "method not implemented".to_string(),
)) ))
} }

View File

@ -1,4 +1,6 @@
use capnp::capability::Promise; use capnp::capability::Promise;
use capnp_rpc::pry;
use libc::user;
use api::usersystem_capnp::user_system::{ use api::usersystem_capnp::user_system::{
info, manage, Server as UserSystem, info, manage, Server as UserSystem,
self as system, self as system,
@ -7,6 +9,7 @@ use crate::authorization::permissions::Permission;
use crate::capnp::user::User; use crate::capnp::user::User;
use crate::session::SessionHandle; use crate::session::SessionHandle;
use crate::users::UserRef;
#[derive(Clone)] #[derive(Clone)]
pub struct Users { pub struct Users {
@ -56,11 +59,17 @@ impl manage::Server for Users {
fn get_user_list( fn get_user_list(
&mut self, &mut self,
_: manage::GetUserListParams, _: manage::GetUserListParams,
_: manage::GetUserListResults, mut result: manage::GetUserListResults,
) -> Promise<(), ::capnp::Error> { ) -> Promise<(), ::capnp::Error> {
Promise::err(::capnp::Error::unimplemented( let userdb = self.session.users.into_inner();
"method not implemented".to_string(), let users = pry!(userdb.get_all()
)) .map_err(|e| capnp::Error::failed(format!("UserDB error: {:?}", e))));
let mut builder = result.get().init_user_list(users.len() as u32);
let me = User::new_self(self.session.clone());
for (i, (_, user)) in users.into_iter().enumerate() {
me.fill(user, builder.reborrow().get(i as u32));
}
Promise::ok(())
} }
fn add_user( fn add_user(
&mut self, &mut self,

View File

@ -167,7 +167,7 @@ impl Resource {
pub async fn try_update(&self, session: SessionHandle, new: Status) { pub async fn try_update(&self, session: SessionHandle, new: Status) {
let old = self.get_state(); let old = self.get_state();
let old: &Archived<State> = old.as_ref(); let old: &Archived<State> = old.as_ref();
let user = session.get_user(); let user = session.get_user_ref();
if session.has_manage(self) // Default allow for managers if session.has_manage(self) // Default allow for managers
@ -224,7 +224,7 @@ impl Resource {
let s: &Archived<State> = state.as_ref(); let s: &Archived<State> = state.as_ref();
let i: &Archived<MachineState> = &s.inner; let i: &Archived<MachineState> = &s.inner;
if let ArchivedStatus::InUse(user) = &i.state { if let ArchivedStatus::InUse(user) = &i.state {
let current = session.get_user(); let current = session.get_user_ref();
if user == &current { if user == &current {
self.set_state(MachineState::free(Some(current))); self.set_state(MachineState::free(Some(current)));
} }
@ -236,7 +236,7 @@ impl Resource {
} }
pub fn visible(&self, session: &SessionHandle) -> bool { pub fn visible(&self, session: &SessionHandle) -> bool {
session.has_disclose(self) || self.is_owned_by(session.get_user()) session.has_disclose(self) || self.is_owned_by(session.get_user_ref())
} }
pub fn is_owned_by(&self, owner: UserRef) -> bool { pub fn is_owned_by(&self, owner: UserRef) -> bool {

View File

@ -7,7 +7,7 @@ use crate::authorization::permissions::Permission;
use crate::authorization::roles::{Roles}; use crate::authorization::roles::{Roles};
use crate::resources::Resource; use crate::resources::Resource;
use crate::Users; use crate::Users;
use crate::users::UserRef; use crate::users::{db, UserRef};
#[derive(Clone)] #[derive(Clone)]
@ -40,17 +40,21 @@ impl SessionManager {
#[derive(Clone)] #[derive(Clone)]
pub struct SessionHandle { pub struct SessionHandle {
users: Users, pub users: Users,
roles: Roles, pub roles: Roles,
user: UserRef, user: UserRef,
} }
impl SessionHandle { impl SessionHandle {
pub fn get_user(&self) -> UserRef { pub fn get_user_ref(&self) -> UserRef {
self.user.clone() self.user.clone()
} }
pub fn get_user(&self) -> db::User {
self.users.get_user(self.user.get_username()).expect("Failed to get user self")
}
pub fn has_disclose(&self, resource: &Resource) -> bool { pub fn has_disclose(&self, resource: &Resource) -> bool {
if let Some(user) = self.users.get_user(self.user.get_username()) { if let Some(user) = self.users.get_user(self.user.get_username()) {
self.roles.is_permitted(&user.userdata, &resource.get_required_privs().disclose) self.roles.is_permitted(&user.userdata, &resource.get_required_privs().disclose)

View File

@ -93,6 +93,11 @@ impl Users {
.map(|user| Deserialize::<db::User, _>::deserialize(user.as_ref(), &mut Infallible).unwrap()) .map(|user| Deserialize::<db::User, _>::deserialize(user.as_ref(), &mut Infallible).unwrap())
} }
pub fn put_user(&self, uid: &str, user: &db::User) -> Result<(), lmdb::Error> {
tracing::trace!(uid, ?user, "Updating user");
self.userdb.put(uid, user)
}
pub fn load_file<P: AsRef<Path>>(&self, path: P) -> anyhow::Result<()> { pub fn load_file<P: AsRef<Path>>(&self, path: P) -> anyhow::Result<()> {
let f = std::fs::read(path)?; let f = std::fs::read(path)?;
let map: HashMap<String, UserData> = toml::from_slice(&f)?; let map: HashMap<String, UserData> = toml::from_slice(&f)?;