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()));
{
let user = self.session.get_user();
let user = self.session.get_user_ref();
let state = self.resource.get_state_ref();
let state = state.as_ref();
@ -113,7 +113,7 @@ impl UseServer for Machine {
let resource = self.resource.clone();
let session = self.session.clone();
Promise::from_future(async move {
let user = session.get_user();
let user = session.get_user_ref();
resource.try_update(session, Status::InUse(user)).await;
Ok(())
})
@ -127,7 +127,7 @@ impl UseServer for Machine {
let resource = self.resource.clone();
let session = self.session.clone();
Promise::from_future(async move {
let user = session.get_user();
let user = session.get_user_ref();
resource
.try_update(session, Status::Reserved(user))
.await;
@ -200,7 +200,7 @@ impl ManageServer for Machine {
mut result: manage::GetMachineInfoExtendedResults,
) -> Promise<(), ::capnp::Error> {
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_previous_user(), builder.init_last_user());
Promise::ok(())
@ -233,7 +233,7 @@ impl ManageServer for Machine {
let session = self.session.clone();
Promise::from_future(async move {
resource
.force_set(Status::InUse(session.get_user()))
.force_set(Status::InUse(session.get_user_ref()))
.await;
Ok(())
})
@ -270,7 +270,7 @@ impl ManageServer for Machine {
let session = self.session.clone();
Promise::from_future(async move {
resource
.force_set(Status::Blocked(session.get_user()))
.force_set(Status::Blocked(session.get_user_ref()))
.await;
Ok(())
})
@ -295,7 +295,7 @@ impl AdminServer for Machine {
_: admin::ForceSetStateResults,
) -> Promise<(), ::capnp::Error> {
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()) {
APIMState::Free => Status::Free,
APIMState::Blocked => Status::Blocked(user),

View File

@ -1,30 +1,55 @@
use capnp::capability::Promise;
use capnp_rpc::pry;
use crate::session::SessionHandle;
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 {
session: SessionHandle,
user: UserRef,
}
impl User {
pub fn new(session: SessionHandle) -> Self {
Self { session }
pub fn new(session: SessionHandle, user: UserRef) -> Self {
Self { session, user }
}
pub fn build_else(&self, user: Option<UserRef>, mut builder: Builder) {
if let Some(user) = user {
builder.set_username(user.get_username());
}
pub fn new_self(session: SessionHandle) -> Self {
let user = session.get_user_ref();
Self::new(session, user)
}
pub fn build_into(self, mut builder: Builder) {
let user = self.session.get_user();
builder.set_username(user.get_username());
pub fn build_else(&self, user: Option<UserRef>, builder: Builder) {
if let Some(user) = user.and_then(|u| self.session.users.get_user(u.get_username())) {
self.fill(user, builder);
}
}
pub fn build(session: SessionHandle, mut builder: Builder) {
let this = Self::new(session);
this.build_into(builder)
let this = Self::new_self(session);
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(
&mut self,
_: info::ListRolesParams,
_: info::ListRolesResults,
) -> ::capnp::capability::Promise<(), ::capnp::Error> {
::capnp::capability::Promise::err(::capnp::Error::unimplemented(
"method not implemented".to_string(),
))
mut result: info::ListRolesResults,
) -> Promise<(), ::capnp::Error> {
let user = self.session.get_user();
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 {
fn pwd(
&mut self,
_: manage::PwdParams,
_: manage::PwdResults,
) -> ::capnp::capability::Promise<(), ::capnp::Error> {
::capnp::capability::Promise::err(::capnp::Error::unimplemented(
params: manage::PwdParams,
mut results: manage::PwdResults,
) -> Promise<(), ::capnp::Error> {
Promise::err(::capnp::Error::unimplemented(
"method not implemented".to_string(),
))
}
@ -57,35 +86,55 @@ impl admin::Server for User {
&mut self,
_: admin::GetUserInfoExtendedParams,
_: admin::GetUserInfoExtendedResults,
) -> ::capnp::capability::Promise<(), ::capnp::Error> {
::capnp::capability::Promise::err(::capnp::Error::unimplemented(
) -> Promise<(), ::capnp::Error> {
Promise::err(::capnp::Error::unimplemented(
"method not implemented".to_string(),
))
}
fn add_role(
&mut self,
_: admin::AddRoleParams,
param: admin::AddRoleParams,
_: admin::AddRoleResults,
) -> ::capnp::capability::Promise<(), ::capnp::Error> {
::capnp::capability::Promise::err(::capnp::Error::unimplemented(
"method not implemented".to_string(),
))
) -> Promise<(), ::capnp::Error> {
let rolename = pry!(pry!(pry!(param.get()).get_role()).get_name());
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(
&mut self,
_: admin::RemoveRoleParams,
param: admin::RemoveRoleParams,
_: admin::RemoveRoleResults,
) -> ::capnp::capability::Promise<(), ::capnp::Error> {
::capnp::capability::Promise::err(::capnp::Error::unimplemented(
"method not implemented".to_string(),
))
) -> Promise<(), ::capnp::Error> {
let rolename = pry!(pry!(pry!(param.get()).get_role()).get_name());
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(
&mut self,
_: admin::PwdParams,
_: admin::PwdResults,
) -> ::capnp::capability::Promise<(), ::capnp::Error> {
::capnp::capability::Promise::err(::capnp::Error::unimplemented(
) -> Promise<(), ::capnp::Error> {
Promise::err(::capnp::Error::unimplemented(
"method not implemented".to_string(),
))
}

View File

@ -1,4 +1,6 @@
use capnp::capability::Promise;
use capnp_rpc::pry;
use libc::user;
use api::usersystem_capnp::user_system::{
info, manage, Server as UserSystem,
self as system,
@ -7,6 +9,7 @@ use crate::authorization::permissions::Permission;
use crate::capnp::user::User;
use crate::session::SessionHandle;
use crate::users::UserRef;
#[derive(Clone)]
pub struct Users {
@ -56,11 +59,17 @@ impl manage::Server for Users {
fn get_user_list(
&mut self,
_: manage::GetUserListParams,
_: manage::GetUserListResults,
mut result: manage::GetUserListResults,
) -> Promise<(), ::capnp::Error> {
Promise::err(::capnp::Error::unimplemented(
"method not implemented".to_string(),
))
let userdb = self.session.users.into_inner();
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(
&mut self,

View File

@ -167,7 +167,7 @@ impl Resource {
pub async fn try_update(&self, session: SessionHandle, new: Status) {
let old = self.get_state();
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
@ -224,7 +224,7 @@ impl Resource {
let s: &Archived<State> = state.as_ref();
let i: &Archived<MachineState> = &s.inner;
if let ArchivedStatus::InUse(user) = &i.state {
let current = session.get_user();
let current = session.get_user_ref();
if user == &current {
self.set_state(MachineState::free(Some(current)));
}
@ -236,7 +236,7 @@ impl Resource {
}
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 {

View File

@ -7,7 +7,7 @@ use crate::authorization::permissions::Permission;
use crate::authorization::roles::{Roles};
use crate::resources::Resource;
use crate::Users;
use crate::users::UserRef;
use crate::users::{db, UserRef};
#[derive(Clone)]
@ -40,17 +40,21 @@ impl SessionManager {
#[derive(Clone)]
pub struct SessionHandle {
users: Users,
roles: Roles,
pub users: Users,
pub roles: Roles,
user: UserRef,
}
impl SessionHandle {
pub fn get_user(&self) -> UserRef {
pub fn get_user_ref(&self) -> UserRef {
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 {
if let Some(user) = self.users.get_user(self.user.get_username()) {
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())
}
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<()> {
let f = std::fs::read(path)?;
let map: HashMap<String, UserData> = toml::from_slice(&f)?;