mirror of
https://gitlab.com/fabinfra/fabaccess/bffh.git
synced 2024-11-25 16:17:56 +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 std::sync::Arc;
|
||||||
|
|
||||||
use capnp::capability::{Promise};
|
use capnp::capability::{Promise};
|
||||||
|
use rsasl::mechname::Mechname;
|
||||||
|
use rsasl::SASL;
|
||||||
|
use auth::State;
|
||||||
|
|
||||||
use crate::schema::connection_capnp;
|
use crate::schema::connection_capnp;
|
||||||
use crate::connection::Session;
|
use crate::connection::Session;
|
||||||
@ -31,99 +34,85 @@ pub struct Bootstrap {
|
|||||||
|
|
||||||
db: Databases,
|
db: Databases,
|
||||||
nw: Arc<Network>,
|
nw: Arc<Network>,
|
||||||
|
ctx: SASL,
|
||||||
session: Rc<RefCell<Option<Session>>>,
|
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Bootstrap {
|
impl Bootstrap {
|
||||||
pub fn new(log: Logger, db: Databases, nw: Arc<Network>) -> Self {
|
pub fn new(log: Logger, db: Databases, nw: Arc<Network>) -> Self {
|
||||||
info!(log, "Created Bootstrap");
|
info!(log, "Created Bootstrap");
|
||||||
let session = Rc::new(RefCell::new(None));
|
let mut ctx = SASL::new();
|
||||||
Self { session, db, nw, log }
|
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::{API_VERSION_MAJOR, API_VERSION_MINOR, API_VERSION_PATCH};
|
||||||
use connection_capnp::bootstrap::*;
|
use connection_capnp::bootstrap::*;
|
||||||
|
use crate::api::auth::Auth;
|
||||||
use crate::RELEASE;
|
use crate::RELEASE;
|
||||||
|
|
||||||
impl connection_capnp::bootstrap::Server for Bootstrap {
|
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(
|
fn get_a_p_i_version(
|
||||||
&mut self,
|
&mut self,
|
||||||
_: GetAPIVersionParams,
|
_: GetAPIVersionParams,
|
||||||
mut results: GetAPIVersionResults
|
_: GetAPIVersionResults,
|
||||||
) -> Promise<(), capnp::Error> {
|
) -> 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);
|
|
||||||
Promise::ok(())
|
Promise::ok(())
|
||||||
}
|
}
|
||||||
|
|
||||||
fn get_server_release(
|
fn get_server_release(
|
||||||
&mut self,
|
&mut self,
|
||||||
_: GetServerReleaseParams,
|
_: GetServerReleaseParams,
|
||||||
mut results: GetServerReleaseResults
|
mut result: GetServerReleaseResults,
|
||||||
) -> Promise<(), capnp::Error> {
|
) -> Promise<(), ::capnp::Error> {
|
||||||
let mut builder = results.get();
|
let mut builder = result.get();
|
||||||
builder.set_name("bffh");
|
builder.set_name("bffhd");
|
||||||
builder.set_release(RELEASE);
|
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(())
|
Promise::ok(())
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
263
src/api/auth.rs
263
src/api/auth.rs
@ -3,32 +3,35 @@
|
|||||||
//! Authorization is over in `access.rs`
|
//! Authorization is over in `access.rs`
|
||||||
//! Authentication using SASL
|
//! Authentication using SASL
|
||||||
|
|
||||||
use std::sync::Arc;
|
|
||||||
use std::rc::Rc;
|
|
||||||
use std::cell::RefCell;
|
use std::cell::RefCell;
|
||||||
use std::io::Cursor;
|
use std::io::Cursor;
|
||||||
|
use std::rc::Rc;
|
||||||
|
use std::sync::Arc;
|
||||||
|
|
||||||
use slog::Logger;
|
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::callback::Callback;
|
||||||
use rsasl::error::SessionError;
|
use rsasl::error::SessionError;
|
||||||
use rsasl::mechname::Mechname;
|
use rsasl::mechname::Mechname;
|
||||||
use rsasl::property::{AuthId, Password};
|
use rsasl::property::{AuthId, Password};
|
||||||
use rsasl::SASL;
|
use rsasl::session::Session as RsaslSession;
|
||||||
use rsasl::session::Step;
|
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;
|
use crate::api::Session;
|
||||||
|
|
||||||
pub use crate::schema::authenticationsystem_capnp as auth_system;
|
|
||||||
use crate::db::Databases;
|
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::access::AccessControl as AccessDB;
|
||||||
|
use crate::db::user::{Internal as UserDB, User, UserId};
|
||||||
|
use crate::network::Network;
|
||||||
|
|
||||||
pub struct AppData {
|
pub struct AppData {
|
||||||
userdb: Arc<UserDB>,
|
userdb: Arc<UserDB>,
|
||||||
@ -37,7 +40,7 @@ pub struct SessionData {
|
|||||||
authz: Option<User>,
|
authz: Option<User>,
|
||||||
}
|
}
|
||||||
|
|
||||||
struct CB {
|
pub struct CB {
|
||||||
userdb: Arc<UserDB>,
|
userdb: Arc<UserDB>,
|
||||||
}
|
}
|
||||||
impl CB {
|
impl CB {
|
||||||
@ -47,168 +50,151 @@ impl CB {
|
|||||||
}
|
}
|
||||||
|
|
||||||
impl Callback for 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 {
|
let ret = match validation {
|
||||||
validations::SIMPLE => {
|
validations::SIMPLE => {
|
||||||
|
|
||||||
let authid = session
|
let authid = session
|
||||||
.get_property::<AuthId>()
|
.get_property::<AuthId>()
|
||||||
.ok_or(SessionError::no_property::<AuthId>())?;
|
.ok_or(SessionError::no_property::<AuthId>())?;
|
||||||
|
|
||||||
let pass = session.get_property::<Password>()
|
let pass = session
|
||||||
.ok_or(SessionError::no_property::<Password>())?;
|
.get_property::<Password>()
|
||||||
|
.ok_or(SessionError::no_property::<Password>())?;
|
||||||
|
|
||||||
if self.userdb.login(authid.as_ref(), pass.as_bytes()).unwrap().is_some() {
|
if self
|
||||||
return Ok(())
|
.userdb
|
||||||
|
.login(authid.as_ref(), pass.as_bytes())
|
||||||
|
.unwrap()
|
||||||
|
.is_some()
|
||||||
|
{
|
||||||
|
return Ok(());
|
||||||
}
|
}
|
||||||
|
|
||||||
SessionError::AuthenticationFailure
|
SessionError::AuthenticationFailure
|
||||||
}
|
}
|
||||||
_ => {
|
_ => SessionError::no_validate(validation),
|
||||||
SessionError::no_validate(validation)
|
|
||||||
}
|
|
||||||
};
|
};
|
||||||
Err(ret)
|
Err(ret)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub enum State {
|
||||||
|
InvalidMechanism,
|
||||||
|
Finished,
|
||||||
|
Aborted,
|
||||||
|
Running(RsaslSession),
|
||||||
|
}
|
||||||
|
|
||||||
pub struct Auth {
|
pub struct Auth {
|
||||||
pub ctx: SASL,
|
|
||||||
session: Rc<RefCell<Option<Session>>>,
|
|
||||||
userdb: Arc<UserDB>,
|
userdb: Arc<UserDB>,
|
||||||
access: Arc<AccessDB>,
|
access: Arc<AccessDB>,
|
||||||
|
state: State,
|
||||||
log: Logger,
|
log: Logger,
|
||||||
|
network: Arc<Network>,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Auth {
|
impl Auth {
|
||||||
pub fn new(log: Logger, dbs: Databases, session: Rc<RefCell<Option<Session>>>) -> Self {
|
pub fn new(log: Logger, dbs: Databases, state: State, network: Arc<Network>) -> Self {
|
||||||
let mut ctx = SASL::new();
|
Self {
|
||||||
ctx.install_callback(Arc::new(CB::new(dbs.userdb.clone())));
|
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::*;
|
use crate::schema::authenticationsystem_capnp::*;
|
||||||
impl authentication_system::Server for Auth {
|
impl authentication::Server for Auth {
|
||||||
fn mechanisms(&mut self,
|
fn step(
|
||||||
_: authentication_system::MechanismsParams,
|
&mut self,
|
||||||
mut res: authentication_system::MechanismsResults
|
params: authentication::StepParams,
|
||||||
|
mut results: authentication::StepResults,
|
||||||
) -> Promise<(), capnp::Error> {
|
) -> Promise<(), capnp::Error> {
|
||||||
/*let mechs = match self.ctx.server_mech_list() {
|
let mut builder = results.get();
|
||||||
Ok(m) => m,
|
if let State::Running(mut session) = std::mem::replace(&mut self.state, State::Aborted) {
|
||||||
Err(e) => {
|
let data: &[u8] = pry!(pry!(params.get()).get_data());
|
||||||
return Promise::err(capnp::Error {
|
let mut out = Cursor::new(Vec::new());
|
||||||
kind: capnp::ErrorKind::Failed,
|
match session.step(Some(data), &mut out) {
|
||||||
description: format!("SASL Failure: {}", e),
|
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);
|
let mut builder = builder.init_successful();
|
||||||
for (i, m) in mechvec.into_iter().enumerate() {
|
if data.is_some() {
|
||||||
res_mechs.set(i as u32, m);
|
builder.set_additional_data(out.into_inner().as_slice());
|
||||||
}*/
|
}
|
||||||
// For now, only PLAIN
|
|
||||||
let mut res_mechs = res.get().init_mechs(1);
|
let mut builder = builder.init_session();
|
||||||
res_mechs.set(0, "PLAIN");
|
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(())
|
Promise::ok(())
|
||||||
}
|
}
|
||||||
|
|
||||||
// TODO: return Outcome instead of exceptions
|
fn abort(
|
||||||
fn start(&mut self,
|
&mut self,
|
||||||
params: authentication_system::StartParams,
|
_: authentication::AbortParams,
|
||||||
mut res: authentication_system::StartResults
|
_: authentication::AbortResults,
|
||||||
) -> Promise<(), capnp::Error> {
|
) -> Promise<(), capnp::Error> {
|
||||||
let req = pry!(pry!(params.get()).get_request());
|
self.state = State::Aborted;
|
||||||
|
Promise::ok(())
|
||||||
// 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(())
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -262,11 +248,11 @@ pub struct AuthenticationData {
|
|||||||
|
|
||||||
// Authentication has two parts: Granting the authentication itself and then performing the
|
// Authentication has two parts: Granting the authentication itself and then performing the
|
||||||
// authentication.
|
// 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) 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
|
// 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
|
// 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)]
|
#[derive(Debug, Clone, PartialEq, Eq, PartialOrd, Ord, Serialize, Deserialize)]
|
||||||
pub enum AuthError {
|
pub enum AuthError {
|
||||||
@ -278,5 +264,4 @@ pub enum AuthError {
|
|||||||
MalformedAuthzid,
|
MalformedAuthzid,
|
||||||
/// User may not use that authorization id
|
/// User may not use that authorization id
|
||||||
NotAllowedAuthzid,
|
NotAllowedAuthzid,
|
||||||
|
|
||||||
}
|
}
|
||||||
|
@ -27,59 +27,6 @@ impl Machine {
|
|||||||
}
|
}
|
||||||
|
|
||||||
impl info::Server for 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(
|
fn get_reservation_list(
|
||||||
&mut self,
|
&mut self,
|
||||||
_: info::GetReservationListParams,
|
_: 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 {
|
impl manage::Server for Machine {
|
||||||
fn force_free(&mut self,
|
fn force_free(&mut self,
|
||||||
_: manage::ForceFreeParams,
|
_: manage::ForceFreeParams,
|
||||||
@ -229,6 +170,60 @@ impl manage::Server for Machine {
|
|||||||
};
|
};
|
||||||
Promise::from_future(f)
|
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 {
|
impl admin::Server for Machine {
|
||||||
@ -244,6 +239,9 @@ impl admin::Server for Machine {
|
|||||||
APIMState::InUse => MachineState::used(Some(uid)),
|
APIMState::InUse => MachineState::used(Some(uid)),
|
||||||
APIMState::Reserved => MachineState::reserved(uid),
|
APIMState::Reserved => MachineState::reserved(uid),
|
||||||
APIMState::ToCheck => MachineState::check(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 machine = self.machine.get_inner();
|
||||||
let f = async move {
|
let f = async move {
|
||||||
|
@ -125,7 +125,7 @@ impl machines::Server for Machines {
|
|||||||
let permissions = &session.as_ref().unwrap().perms;
|
let permissions = &session.as_ref().unwrap().perms;
|
||||||
|
|
||||||
if let Some(machine) = network.machines.get(&id) {
|
if let Some(machine) = network.machines.get(&id) {
|
||||||
let mut builder = results.get().init_machine();
|
let mut builder = results.get();
|
||||||
fill_machine_builder(
|
fill_machine_builder(
|
||||||
&mut builder,
|
&mut builder,
|
||||||
&machine,
|
&machine,
|
||||||
@ -171,7 +171,7 @@ impl machines::Server for Machines {
|
|||||||
let permissions = &session.as_ref().unwrap().perms;
|
let permissions = &session.as_ref().unwrap().perms;
|
||||||
|
|
||||||
if let Some(machine) = network.machines.get(&id) {
|
if let Some(machine) = network.machines.get(&id) {
|
||||||
let mut builder = results.get().init_machine();
|
let mut builder = results.get();
|
||||||
fill_machine_builder(
|
fill_machine_builder(
|
||||||
&mut builder,
|
&mut builder,
|
||||||
&machine,
|
&machine,
|
||||||
|
Loading…
Reference in New Issue
Block a user