mirror of
https://gitlab.com/fabinfra/fabaccess/bffh.git
synced 2024-12-22 19:53:49 +01:00
Update API
This commit is contained in:
parent
0531156b9e
commit
15f31ffd7c
2
schema
2
schema
@ -1 +1 @@
|
||||
Subproject commit 18ed9c2ae6a221f57d19e255165c7ebc4508e9af
|
||||
Subproject commit c9283ebd696ed6dd428a7c3d24820889f7ab4bf3
|
131
src/api.rs
131
src/api.rs
@ -7,6 +7,9 @@ use slog::Logger;
|
||||
use std::sync::Arc;
|
||||
|
||||
use capnp::capability::{Promise};
|
||||
use rsasl::mechname::Mechname;
|
||||
use rsasl::SASL;
|
||||
use auth::State;
|
||||
|
||||
use crate::schema::connection_capnp;
|
||||
use crate::connection::Session;
|
||||
@ -31,99 +34,85 @@ pub struct Bootstrap {
|
||||
|
||||
db: Databases,
|
||||
nw: Arc<Network>,
|
||||
|
||||
session: Rc<RefCell<Option<Session>>>,
|
||||
ctx: SASL,
|
||||
}
|
||||
|
||||
impl Bootstrap {
|
||||
pub fn new(log: Logger, db: Databases, nw: Arc<Network>) -> Self {
|
||||
info!(log, "Created Bootstrap");
|
||||
let session = Rc::new(RefCell::new(None));
|
||||
Self { session, db, nw, log }
|
||||
let mut ctx = SASL::new();
|
||||
ctx.install_callback(Arc::new(auth::CB::new(db.userdb.clone())));
|
||||
Self { db, nw, log, ctx }
|
||||
}
|
||||
}
|
||||
|
||||
use connection_capnp::{API_VERSION_MAJOR, API_VERSION_MINOR, API_VERSION_PATCH};
|
||||
use connection_capnp::bootstrap::*;
|
||||
use crate::api::auth::Auth;
|
||||
use crate::RELEASE;
|
||||
|
||||
impl connection_capnp::bootstrap::Server for Bootstrap {
|
||||
fn authentication_system(&mut self,
|
||||
_: AuthenticationSystemParams,
|
||||
mut res: AuthenticationSystemResults
|
||||
) -> Promise<(), capnp::Error> {
|
||||
// TODO: Forbid mutltiple authentication for now
|
||||
// TODO: When should we allow multiple auth and how do me make sure that does not leak
|
||||
// priviledges (e.g. due to previously issues caps)?
|
||||
|
||||
// If this Rc has a strong count of 1 then there's no other cap issued yet meaning we can
|
||||
// safely transform the inner session with an auth.
|
||||
if Rc::strong_count(&self.session) == 1 {
|
||||
let session = Rc::clone(&self.session);
|
||||
let db = self.db.clone();
|
||||
res.get().set_authentication_system(capnp_rpc::new_client(
|
||||
auth::Auth::new(self.log.new(o!()), db, session))
|
||||
);
|
||||
}
|
||||
|
||||
Promise::ok(())
|
||||
}
|
||||
|
||||
fn machine_system(&mut self,
|
||||
_: MachineSystemParams,
|
||||
mut res: MachineSystemResults
|
||||
) -> Promise<(), capnp::Error> {
|
||||
if let Some(session) = self.session.borrow().deref() {
|
||||
debug!(self.log, "Giving MachineSystem cap to user {} with perms:", session.authzid);
|
||||
for r in session.perms.iter() {
|
||||
debug!(session.log, " {}", r);
|
||||
}
|
||||
|
||||
// TODO actual permission check and stuff
|
||||
// Right now we only check that the user has authenticated at all.
|
||||
let c = capnp_rpc::new_client(Machines::new(Rc::clone(&self.session), self.nw.clone()));
|
||||
res.get().set_machine_system(c);
|
||||
}
|
||||
|
||||
Promise::ok(())
|
||||
}
|
||||
|
||||
fn user_system(
|
||||
&mut self,
|
||||
_: UserSystemParams,
|
||||
mut results: UserSystemResults
|
||||
) -> Promise<(), capnp::Error> {
|
||||
if self.session.borrow().is_some() {
|
||||
// TODO actual permission check and stuff
|
||||
// Right now we only check that the user has authenticated at all.
|
||||
let c = capnp_rpc::new_client(Users::new(Rc::clone(&self.session), self.db.userdb.clone()));
|
||||
results.get().set_user_system(c);
|
||||
}
|
||||
|
||||
Promise::ok(())
|
||||
}
|
||||
|
||||
fn get_a_p_i_version(
|
||||
&mut self,
|
||||
_: GetAPIVersionParams,
|
||||
mut results: GetAPIVersionResults
|
||||
) -> Promise<(), capnp::Error> {
|
||||
let builder = results.get();
|
||||
let mut builder = builder.init_version();
|
||||
builder.set_major(API_VERSION_MAJOR);
|
||||
builder.set_minor(API_VERSION_MINOR);
|
||||
builder.set_patch(API_VERSION_PATCH);
|
||||
_: GetAPIVersionResults,
|
||||
) -> Promise<(), ::capnp::Error> {
|
||||
Promise::ok(())
|
||||
}
|
||||
|
||||
fn get_server_release(
|
||||
&mut self,
|
||||
_: GetServerReleaseParams,
|
||||
mut results: GetServerReleaseResults
|
||||
) -> Promise<(), capnp::Error> {
|
||||
let mut builder = results.get();
|
||||
builder.set_name("bffh");
|
||||
builder.set_release(RELEASE);
|
||||
mut result: GetServerReleaseResults,
|
||||
) -> Promise<(), ::capnp::Error> {
|
||||
let mut builder = result.get();
|
||||
builder.set_name("bffhd");
|
||||
builder.set_release(crate::RELEASE);
|
||||
Promise::ok(())
|
||||
}
|
||||
|
||||
fn mechanisms(
|
||||
&mut self,
|
||||
_: MechanismsParams,
|
||||
mut result: MechanismsResults,
|
||||
) -> Promise<(), ::capnp::Error> {
|
||||
let mut builder = result.get();
|
||||
let mechs: Vec<_> = self.ctx.server_mech_list()
|
||||
.into_iter()
|
||||
.map(|m| m.mechanism.as_str())
|
||||
.collect();
|
||||
let mut mechbuilder = builder.init_mechs(mechs.len() as u32);
|
||||
for (i,m) in mechs.iter().enumerate() {
|
||||
mechbuilder.set(i as u32, m);
|
||||
}
|
||||
|
||||
Promise::ok(())
|
||||
}
|
||||
|
||||
fn create_session(
|
||||
&mut self,
|
||||
params: CreateSessionParams,
|
||||
mut result: CreateSessionResults,
|
||||
) -> Promise<(), ::capnp::Error> {
|
||||
let params = pry!(params.get());
|
||||
let mechanism: &str = pry!(params.get_mechanism());
|
||||
|
||||
let mechname = mechanism.as_bytes();
|
||||
let state = if let Ok(mechname) = Mechname::new(mechname) {
|
||||
if let Ok(session) = self.ctx.server_start(mechname) {
|
||||
State::Running(session)
|
||||
} else {
|
||||
State::Aborted
|
||||
}
|
||||
} else {
|
||||
State::InvalidMechanism
|
||||
};
|
||||
|
||||
let auth = Auth::new(self.log.clone(), self.db.clone(), state, self.nw.clone());
|
||||
|
||||
let mut builder = result.get();
|
||||
builder.set_authentication(capnp_rpc::new_client(auth));
|
||||
|
||||
Promise::ok(())
|
||||
}
|
||||
}
|
||||
|
263
src/api/auth.rs
263
src/api/auth.rs
@ -3,32 +3,35 @@
|
||||
//! Authorization is over in `access.rs`
|
||||
//! Authentication using SASL
|
||||
|
||||
use std::sync::Arc;
|
||||
use std::rc::Rc;
|
||||
use std::cell::RefCell;
|
||||
use std::io::Cursor;
|
||||
|
||||
use std::rc::Rc;
|
||||
use std::sync::Arc;
|
||||
|
||||
use slog::Logger;
|
||||
|
||||
use serde::{Serialize, Deserialize};
|
||||
use serde::{Deserialize, Serialize};
|
||||
|
||||
use capnp::capability::{Promise};
|
||||
use crate::api::machines::Machines;
|
||||
use capnp::capability::Promise;
|
||||
use rsasl::callback::Callback;
|
||||
use rsasl::error::SessionError;
|
||||
use rsasl::mechname::Mechname;
|
||||
use rsasl::property::{AuthId, Password};
|
||||
use rsasl::SASL;
|
||||
use rsasl::session::Session as RsaslSession;
|
||||
use rsasl::session::Step;
|
||||
use rsasl::validate::{Validation, validations};
|
||||
use rsasl::validate::{validations, Validation};
|
||||
use rsasl::SASL;
|
||||
|
||||
use crate::api::users::Users;
|
||||
use crate::api::Session;
|
||||
|
||||
pub use crate::schema::authenticationsystem_capnp as auth_system;
|
||||
use crate::db::Databases;
|
||||
pub use crate::schema::authenticationsystem_capnp as auth_system;
|
||||
|
||||
use crate::db::user::{Internal as UserDB, User};
|
||||
use crate::db::access::AccessControl as AccessDB;
|
||||
use crate::db::user::{Internal as UserDB, User, UserId};
|
||||
use crate::network::Network;
|
||||
|
||||
pub struct AppData {
|
||||
userdb: Arc<UserDB>,
|
||||
@ -37,7 +40,7 @@ pub struct SessionData {
|
||||
authz: Option<User>,
|
||||
}
|
||||
|
||||
struct CB {
|
||||
pub struct CB {
|
||||
userdb: Arc<UserDB>,
|
||||
}
|
||||
impl CB {
|
||||
@ -47,168 +50,151 @@ impl CB {
|
||||
}
|
||||
|
||||
impl Callback for CB {
|
||||
fn validate(&self, session: &mut rsasl::session::SessionData, validation: Validation, _mechanism: &Mechname) -> Result<(), SessionError> {
|
||||
fn validate(
|
||||
&self,
|
||||
session: &mut rsasl::session::SessionData,
|
||||
validation: Validation,
|
||||
_mechanism: &Mechname,
|
||||
) -> Result<(), SessionError> {
|
||||
let ret = match validation {
|
||||
validations::SIMPLE => {
|
||||
|
||||
let authid = session
|
||||
.get_property::<AuthId>()
|
||||
.ok_or(SessionError::no_property::<AuthId>())?;
|
||||
|
||||
let pass = session.get_property::<Password>()
|
||||
.ok_or(SessionError::no_property::<Password>())?;
|
||||
let pass = session
|
||||
.get_property::<Password>()
|
||||
.ok_or(SessionError::no_property::<Password>())?;
|
||||
|
||||
if self.userdb.login(authid.as_ref(), pass.as_bytes()).unwrap().is_some() {
|
||||
return Ok(())
|
||||
if self
|
||||
.userdb
|
||||
.login(authid.as_ref(), pass.as_bytes())
|
||||
.unwrap()
|
||||
.is_some()
|
||||
{
|
||||
return Ok(());
|
||||
}
|
||||
|
||||
SessionError::AuthenticationFailure
|
||||
}
|
||||
_ => {
|
||||
SessionError::no_validate(validation)
|
||||
}
|
||||
_ => SessionError::no_validate(validation),
|
||||
};
|
||||
Err(ret)
|
||||
}
|
||||
}
|
||||
|
||||
pub enum State {
|
||||
InvalidMechanism,
|
||||
Finished,
|
||||
Aborted,
|
||||
Running(RsaslSession),
|
||||
}
|
||||
|
||||
pub struct Auth {
|
||||
pub ctx: SASL,
|
||||
session: Rc<RefCell<Option<Session>>>,
|
||||
userdb: Arc<UserDB>,
|
||||
access: Arc<AccessDB>,
|
||||
state: State,
|
||||
log: Logger,
|
||||
network: Arc<Network>,
|
||||
}
|
||||
|
||||
impl Auth {
|
||||
pub fn new(log: Logger, dbs: Databases, session: Rc<RefCell<Option<Session>>>) -> Self {
|
||||
let mut ctx = SASL::new();
|
||||
ctx.install_callback(Arc::new(CB::new(dbs.userdb.clone())));
|
||||
pub fn new(log: Logger, dbs: Databases, state: State, network: Arc<Network>) -> Self {
|
||||
Self {
|
||||
log,
|
||||
userdb: dbs.userdb.clone(),
|
||||
access: dbs.access.clone(),
|
||||
state,
|
||||
network,
|
||||
}
|
||||
}
|
||||
|
||||
Self { log, ctx, session, userdb: dbs.userdb.clone(), access: dbs.access.clone() }
|
||||
fn build_error(&self, response: response::Builder) {
|
||||
use crate::schema::authenticationsystem_capnp::response::Error as ErrorCode;
|
||||
if let State::Running(_) = self.state {
|
||||
return;
|
||||
}
|
||||
|
||||
let mut builder = response.init_failed();
|
||||
match self.state {
|
||||
State::InvalidMechanism => builder.set_code(ErrorCode::BadMechanism),
|
||||
State::Finished => builder.set_code(ErrorCode::Aborted),
|
||||
State::Aborted => builder.set_code(ErrorCode::Aborted),
|
||||
_ => unreachable!(),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
use crate::schema::authenticationsystem_capnp::*;
|
||||
impl authentication_system::Server for Auth {
|
||||
fn mechanisms(&mut self,
|
||||
_: authentication_system::MechanismsParams,
|
||||
mut res: authentication_system::MechanismsResults
|
||||
impl authentication::Server for Auth {
|
||||
fn step(
|
||||
&mut self,
|
||||
params: authentication::StepParams,
|
||||
mut results: authentication::StepResults,
|
||||
) -> Promise<(), capnp::Error> {
|
||||
/*let mechs = match self.ctx.server_mech_list() {
|
||||
Ok(m) => m,
|
||||
Err(e) => {
|
||||
return Promise::err(capnp::Error {
|
||||
kind: capnp::ErrorKind::Failed,
|
||||
description: format!("SASL Failure: {}", e),
|
||||
})
|
||||
},
|
||||
};
|
||||
let mut builder = results.get();
|
||||
if let State::Running(mut session) = std::mem::replace(&mut self.state, State::Aborted) {
|
||||
let data: &[u8] = pry!(pry!(params.get()).get_data());
|
||||
let mut out = Cursor::new(Vec::new());
|
||||
match session.step(Some(data), &mut out) {
|
||||
Ok(Step::Done(data)) => {
|
||||
self.state = State::Finished;
|
||||
|
||||
let mechvec: Vec<&str> = mechs.iter().collect();
|
||||
let uid = pry!(session.get_property::<AuthId>().ok_or(capnp::Error::failed(
|
||||
"Authentication didn't provide an authid as required".to_string()
|
||||
)));
|
||||
let user = self.userdb.get_user(uid.as_str()).unwrap()
|
||||
.expect("Just auth'ed user was not found?!");
|
||||
|
||||
let mut res_mechs = res.get().init_mechs(mechvec.len() as u32);
|
||||
for (i, m) in mechvec.into_iter().enumerate() {
|
||||
res_mechs.set(i as u32, m);
|
||||
}*/
|
||||
// For now, only PLAIN
|
||||
let mut res_mechs = res.get().init_mechs(1);
|
||||
res_mechs.set(0, "PLAIN");
|
||||
let mut builder = builder.init_successful();
|
||||
if data.is_some() {
|
||||
builder.set_additional_data(out.into_inner().as_slice());
|
||||
}
|
||||
|
||||
let mut builder = builder.init_session();
|
||||
let perms = pry!(self.access.collect_permrules(&user.data)
|
||||
.map_err(|e| capnp::Error::failed(format!("AccessDB lookup failed: {}", e))));
|
||||
|
||||
let session = Rc::new(RefCell::new(Some(Session::new(
|
||||
self.log.clone(),
|
||||
user.id,
|
||||
uid.to_string(),
|
||||
user.data.roles.into_boxed_slice(),
|
||||
perms.into_boxed_slice(),
|
||||
))));
|
||||
|
||||
builder.set_machine_system(capnp_rpc::new_client(Machines::new(
|
||||
session.clone(),
|
||||
self.network.clone(),
|
||||
)));
|
||||
builder.set_user_system(capnp_rpc::new_client(Users::new(
|
||||
session.clone(),
|
||||
self.userdb.clone(),
|
||||
)));
|
||||
}
|
||||
Ok(Step::NeedsMore(_)) => {
|
||||
self.state = State::Aborted;
|
||||
self.build_error(builder);
|
||||
}
|
||||
Err(_) => {
|
||||
self.state = State::Aborted;
|
||||
self.build_error(builder);
|
||||
}
|
||||
}
|
||||
} else {
|
||||
self.build_error(builder);
|
||||
}
|
||||
|
||||
Promise::ok(())
|
||||
}
|
||||
|
||||
// TODO: return Outcome instead of exceptions
|
||||
fn start(&mut self,
|
||||
params: authentication_system::StartParams,
|
||||
mut res: authentication_system::StartResults
|
||||
fn abort(
|
||||
&mut self,
|
||||
_: authentication::AbortParams,
|
||||
_: authentication::AbortResults,
|
||||
) -> Promise<(), capnp::Error> {
|
||||
let req = pry!(pry!(params.get()).get_request());
|
||||
|
||||
// Extract the MECHANISM the client wants to use and start a session.
|
||||
// Or fail at that and thrown an exception TODO: return Outcome
|
||||
let mech = pry!(req.get_mechanism());
|
||||
if pry!(req.get_mechanism()) != "PLAIN" {
|
||||
return Promise::err(capnp::Error {
|
||||
kind: capnp::ErrorKind::Failed,
|
||||
description: format!("Invalid SASL mech"),
|
||||
})
|
||||
}
|
||||
|
||||
let mech = Mechname::new(mech.as_bytes()).unwrap();
|
||||
|
||||
let mut session = match self.ctx.server_start(mech) {
|
||||
Ok(s) => s,
|
||||
Err(e) =>
|
||||
return Promise::err(capnp::Error {
|
||||
kind: capnp::ErrorKind::Failed,
|
||||
description: format!("SASL error: {}", e),
|
||||
}),
|
||||
};
|
||||
|
||||
let mut out = Cursor::new(Vec::new());
|
||||
|
||||
// If the client has provided initial data go use that
|
||||
use request::initial_response::Which;
|
||||
let step_res = match req.get_initial_response().which() {
|
||||
Err(capnp::NotInSchema(_)) =>
|
||||
return Promise::err(capnp::Error {
|
||||
kind: capnp::ErrorKind::Failed,
|
||||
description: "Initial data is badly formatted".to_string(),
|
||||
}),
|
||||
|
||||
Ok(Which::None(_)) => {
|
||||
// FIXME: Actually this needs to indicate NO data instead of SOME data of 0 length
|
||||
session.step(Option::<&[u8]>::None, &mut out)
|
||||
}
|
||||
Ok(Which::Initial(data)) => {
|
||||
session.step(Some(pry!(data)), &mut out)
|
||||
}
|
||||
};
|
||||
|
||||
// The step may either return an error, a success or the need for more data
|
||||
// TODO: Set the session user. Needs a lookup though <.>
|
||||
|
||||
match step_res {
|
||||
Ok(Step::Done(b)) => {
|
||||
let user = session
|
||||
.get_property::<AuthId>()
|
||||
.and_then(|data| {
|
||||
self.userdb.get_user(data.as_str()).unwrap()
|
||||
})
|
||||
.expect("Authentication returned OK but the given AuthId is invalid");
|
||||
|
||||
let perms = pry!(self.access.collect_permrules(&user.data)
|
||||
.map_err(|e| capnp::Error::failed(format!("AccessDB lookup failed: {}", e))));
|
||||
self.session.replace(Some(Session::new(
|
||||
self.log.new(o!()),
|
||||
user.id,
|
||||
"".to_string(),
|
||||
user.data.roles.into_boxed_slice(),
|
||||
perms.into_boxed_slice()
|
||||
)));
|
||||
|
||||
let mut outcome = pry!(res.get().get_response()).init_outcome();
|
||||
outcome.reborrow().set_result(response::Result::Successful);
|
||||
if b.is_some() {
|
||||
outcome.init_additional_data().set_additional(&out.get_ref());
|
||||
}
|
||||
Promise::ok(())
|
||||
},
|
||||
Ok(Step::NeedsMore(b)) => {
|
||||
if b.is_some() {
|
||||
pry!(res.get().get_response()).set_challence(&out.get_ref());
|
||||
}
|
||||
Promise::ok(())
|
||||
}
|
||||
Err(e) => {
|
||||
let mut outcome = pry!(res.get().get_response()).init_outcome();
|
||||
outcome.reborrow().set_result(response::Result::InvalidCredentials);
|
||||
let text = format!("{}", e);
|
||||
outcome.set_help_text(&text);
|
||||
Promise::ok(())
|
||||
}
|
||||
}
|
||||
self.state = State::Aborted;
|
||||
Promise::ok(())
|
||||
}
|
||||
}
|
||||
|
||||
@ -262,11 +248,11 @@ pub struct AuthenticationData {
|
||||
|
||||
// Authentication has two parts: Granting the authentication itself and then performing the
|
||||
// authentication.
|
||||
// Granting the authentication checks if
|
||||
// Granting the authentication checks if
|
||||
// a) the given authcid fits with the given (authMethod, kvs). In general a failure here indicates
|
||||
// a programming failure — the authcid come from the same source as that tuple
|
||||
// b) the given authcid may authenticate as the given authzid. E.g. if a given client certificate
|
||||
// has been configured for that user, if a GSSAPI user maps to a given user,
|
||||
// has been configured for that user, if a GSSAPI user maps to a given user,
|
||||
|
||||
#[derive(Debug, Clone, PartialEq, Eq, PartialOrd, Ord, Serialize, Deserialize)]
|
||||
pub enum AuthError {
|
||||
@ -278,5 +264,4 @@ pub enum AuthError {
|
||||
MalformedAuthzid,
|
||||
/// User may not use that authorization id
|
||||
NotAllowedAuthzid,
|
||||
|
||||
}
|
||||
|
@ -27,59 +27,6 @@ impl Machine {
|
||||
}
|
||||
|
||||
impl info::Server for Machine {
|
||||
fn get_machine_info_extended(
|
||||
&mut self,
|
||||
_: info::GetMachineInfoExtendedParams,
|
||||
mut results: info::GetMachineInfoExtendedResults,
|
||||
) -> Promise<(), capnp::Error> {
|
||||
let machine = self.machine.get_inner();
|
||||
let perms = self.perms.clone();
|
||||
let f = async move {
|
||||
if perms.manage {
|
||||
let builder = results.get();
|
||||
let mut extinfo = builder.init_machine_info_extended();
|
||||
let guard = machine.lock().await;
|
||||
|
||||
// "previous" user
|
||||
if let Some(user) = guard.get_previous() {
|
||||
let mut previous = extinfo.reborrow().init_transfer_user();
|
||||
previous.set_username(&user.uid);
|
||||
}
|
||||
|
||||
let state = guard.read_state();
|
||||
let state_lock = state.lock_ref();
|
||||
match state_lock.state {
|
||||
Status::Free => {}
|
||||
Status::InUse(ref user) => if user.is_some() {
|
||||
let user = user.as_ref().unwrap();
|
||||
let mut current = extinfo.init_current_user();
|
||||
current.set_username(&user.uid);
|
||||
}
|
||||
Status::ToCheck(ref user) => {
|
||||
let mut current = extinfo.init_current_user();
|
||||
current.set_username(&user.uid);
|
||||
}
|
||||
Status::Blocked(ref user) => {
|
||||
let mut current = extinfo.init_current_user();
|
||||
current.set_username(&user.uid);
|
||||
}
|
||||
Status::Disabled => {}
|
||||
Status::Reserved(ref user) => {
|
||||
let mut current = extinfo.init_current_user();
|
||||
current.set_username(&user.uid);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Ok(())
|
||||
};
|
||||
|
||||
let g = smol::future::race(f, smol::Timer::after(Duration::from_secs(4))
|
||||
.map(|_| Err(capnp::Error::failed("Waiting for machine lock timed out!".to_string()))));
|
||||
|
||||
Promise::from_future(g)
|
||||
}
|
||||
|
||||
fn get_reservation_list(
|
||||
&mut self,
|
||||
_: info::GetReservationListParams,
|
||||
@ -170,12 +117,6 @@ impl in_use::Server for Machine {
|
||||
}
|
||||
}
|
||||
|
||||
impl transfer::Server for Machine {
|
||||
}
|
||||
|
||||
impl check::Server for Machine {
|
||||
}
|
||||
|
||||
impl manage::Server for Machine {
|
||||
fn force_free(&mut self,
|
||||
_: manage::ForceFreeParams,
|
||||
@ -229,6 +170,60 @@ impl manage::Server for Machine {
|
||||
};
|
||||
Promise::from_future(f)
|
||||
}
|
||||
|
||||
fn get_machine_info_extended(
|
||||
&mut self,
|
||||
_: manage::GetMachineInfoExtendedParams,
|
||||
mut results: manage::GetMachineInfoExtendedResults,
|
||||
) -> Promise<(), capnp::Error> {
|
||||
let machine = self.machine.get_inner();
|
||||
let perms = self.perms.clone();
|
||||
let f = async move {
|
||||
if perms.manage {
|
||||
let builder = results.get();
|
||||
let mut extinfo = builder;
|
||||
let guard = machine.lock().await;
|
||||
|
||||
// "previous" user
|
||||
if let Some(user) = guard.get_previous() {
|
||||
let mut previous = extinfo.reborrow().init_last_user();
|
||||
previous.set_username(&user.uid);
|
||||
}
|
||||
|
||||
let state = guard.read_state();
|
||||
let state_lock = state.lock_ref();
|
||||
match state_lock.state {
|
||||
Status::Free => {}
|
||||
Status::InUse(ref user) => if user.is_some() {
|
||||
let user = user.as_ref().unwrap();
|
||||
let mut current = extinfo.init_current_user();
|
||||
current.set_username(&user.uid);
|
||||
}
|
||||
Status::ToCheck(ref user) => {
|
||||
let mut current = extinfo.init_current_user();
|
||||
current.set_username(&user.uid);
|
||||
}
|
||||
Status::Blocked(ref user) => {
|
||||
let mut current = extinfo.init_current_user();
|
||||
current.set_username(&user.uid);
|
||||
}
|
||||
Status::Disabled => {}
|
||||
Status::Reserved(ref user) => {
|
||||
let mut current = extinfo.init_current_user();
|
||||
current.set_username(&user.uid);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Ok(())
|
||||
};
|
||||
|
||||
let g = smol::future::race(f, smol::Timer::after(Duration::from_secs(4))
|
||||
.map(|_| Err(capnp::Error::failed("Waiting for machine lock timed out!".to_string()))));
|
||||
|
||||
Promise::from_future(g)
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
impl admin::Server for Machine {
|
||||
@ -244,6 +239,9 @@ impl admin::Server for Machine {
|
||||
APIMState::InUse => MachineState::used(Some(uid)),
|
||||
APIMState::Reserved => MachineState::reserved(uid),
|
||||
APIMState::ToCheck => MachineState::check(uid),
|
||||
APIMState::Totakeover => return Promise::err(::capnp::Error::unimplemented(
|
||||
"totakeover not implemented".to_string(),
|
||||
)),
|
||||
};
|
||||
let machine = self.machine.get_inner();
|
||||
let f = async move {
|
||||
|
@ -125,7 +125,7 @@ impl machines::Server for Machines {
|
||||
let permissions = &session.as_ref().unwrap().perms;
|
||||
|
||||
if let Some(machine) = network.machines.get(&id) {
|
||||
let mut builder = results.get().init_machine();
|
||||
let mut builder = results.get();
|
||||
fill_machine_builder(
|
||||
&mut builder,
|
||||
&machine,
|
||||
@ -171,7 +171,7 @@ impl machines::Server for Machines {
|
||||
let permissions = &session.as_ref().unwrap().perms;
|
||||
|
||||
if let Some(machine) = network.machines.get(&id) {
|
||||
let mut builder = results.get().init_machine();
|
||||
let mut builder = results.get();
|
||||
fill_machine_builder(
|
||||
&mut builder,
|
||||
&machine,
|
||||
|
Loading…
Reference in New Issue
Block a user