mirror of
https://gitlab.com/fabinfra/fabaccess/bffh.git
synced 2024-12-22 11:43:49 +01:00
Let's try to get this as the next v0.3
This commit is contained in:
parent
487dc2270d
commit
4f36eedf6a
1
Cargo.lock
generated
1
Cargo.lock
generated
@ -734,6 +734,7 @@ dependencies = [
|
||||
"clap",
|
||||
"erased-serde",
|
||||
"executor",
|
||||
"futures-lite",
|
||||
"futures-rustls",
|
||||
"futures-signals",
|
||||
"futures-test",
|
||||
|
@ -29,6 +29,7 @@ uuid = { version = "0.8.2", features = ["serde", "v4"] }
|
||||
async-trait = "0.1.51"
|
||||
pin-utils = "0.1.0"
|
||||
futures-util = "0.3"
|
||||
futures-lite = "1.12.0"
|
||||
|
||||
# Runtime
|
||||
executor = { path = "runtime/executor" }
|
||||
|
@ -4,7 +4,7 @@ use std::pin::Pin;
|
||||
use std::task::{Context, Poll};
|
||||
use futures_signals::signal::{MutableSignalRef, ReadOnlyMutable, Signal};
|
||||
use futures_util::future::BoxFuture;
|
||||
use crate::resource::state::State;
|
||||
use crate::resources::state::State;
|
||||
|
||||
pub trait Actor {
|
||||
fn apply(&mut self, state: State) -> BoxFuture<'static, ()>;
|
||||
|
@ -1,3 +1,11 @@
|
||||
|
||||
|
||||
pub mod db;
|
||||
pub mod db;
|
||||
|
||||
pub struct AuthenticationHandler {
|
||||
|
||||
}
|
||||
|
||||
impl AuthenticationHandler {
|
||||
|
||||
}
|
@ -0,0 +1,3 @@
|
||||
|
||||
pub mod permissions;
|
||||
pub mod roles;
|
@ -5,149 +5,6 @@ use std::fmt;
|
||||
use std::cmp::Ordering;
|
||||
use std::convert::{TryFrom, Into};
|
||||
|
||||
/// A "Role" from the Authorization perspective
|
||||
///
|
||||
/// You can think of a role as a bundle of permissions relating to other roles. In most cases a
|
||||
/// role represents a real-world education or apprenticeship, which gives a person the education
|
||||
/// necessary to use a machine safely.
|
||||
/// Roles are assigned permissions which in most cases evaluate to granting a person the right to
|
||||
/// use certain (potentially) dangerous machines.
|
||||
/// Using this indirection makes administration easier in certain ways; instead of maintaining
|
||||
/// permissions on users directly the user is given a role after having been educated on the safety
|
||||
/// of a machine; if later on a similar enough machine is put to use the administrator can just add
|
||||
/// the permission for that machine to an already existing role instead of manually having to
|
||||
/// assign to all users.
|
||||
#[derive(Debug, Clone, PartialEq, Eq, Hash, serde::Serialize, serde::Deserialize)]
|
||||
pub struct Role {
|
||||
// If a role doesn't define parents, default to an empty Vec.
|
||||
#[serde(default, skip_serializing_if = "Vec::is_empty")]
|
||||
/// A Role can have parents, inheriting all permissions
|
||||
///
|
||||
/// This makes situations where different levels of access are required easier: Each higher
|
||||
/// level of access sets the lower levels of access as parent, inheriting their permission; if
|
||||
/// you are allowed to manage a machine you are then also allowed to use it and so on
|
||||
parents: Vec<RoleIdentifier>,
|
||||
|
||||
// If a role doesn't define permissions, default to an empty Vec.
|
||||
#[serde(default, skip_serializing_if = "Vec::is_empty")]
|
||||
permissions: Vec<PermRule>,
|
||||
}
|
||||
|
||||
impl Role {
|
||||
pub fn new(parents: Vec<RoleIdentifier>, permissions: Vec<PermRule>) -> Self {
|
||||
Self { parents, permissions }
|
||||
}
|
||||
}
|
||||
|
||||
impl fmt::Display for Role {
|
||||
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
|
||||
write!(f, "parents:")?;
|
||||
if self.parents.is_empty() {
|
||||
writeln!(f, " []")?;
|
||||
} else {
|
||||
writeln!(f, "")?;
|
||||
for p in self.parents.iter() {
|
||||
writeln!(f, " - {}", p)?;
|
||||
}
|
||||
}
|
||||
write!(f, "permissions:")?;
|
||||
if self.permissions.is_empty() {
|
||||
writeln!(f, " []")?;
|
||||
} else {
|
||||
writeln!(f, "")?;
|
||||
for p in self.permissions.iter() {
|
||||
writeln!(f, " - {}", p)?;
|
||||
}
|
||||
}
|
||||
|
||||
Ok(())
|
||||
}
|
||||
}
|
||||
|
||||
type SourceID = String;
|
||||
|
||||
fn split_once(s: &str, split: char) -> Option<(&str, &str)> {
|
||||
s
|
||||
.find(split)
|
||||
.map(|idx| (&s[..idx], &s[(idx+1)..]))
|
||||
}
|
||||
|
||||
#[derive(Debug, Clone, PartialEq, Eq, Hash, serde::Serialize, serde::Deserialize)]
|
||||
#[serde(try_from = "String")]
|
||||
#[serde(into = "String")]
|
||||
/// Universal (relative) id of a role
|
||||
pub struct RoleIdentifier {
|
||||
/// Locally unique name for the role. No other role at this instance no matter the source
|
||||
/// may have the same name
|
||||
name: String,
|
||||
/// Role Source, i.e. the database the role comes from
|
||||
source: SourceID,
|
||||
}
|
||||
|
||||
impl RoleIdentifier {
|
||||
pub fn new<>(name: &str, source: &str) -> Self {
|
||||
Self { name: name.to_string(), source: source.to_string() }
|
||||
}
|
||||
pub fn from_strings(name: String, source: String) -> Self {
|
||||
Self { name, source }
|
||||
}
|
||||
}
|
||||
|
||||
impl fmt::Display for RoleIdentifier {
|
||||
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
|
||||
if self.source != "" {
|
||||
write!(f, "{}/{}", self.name, self.source)
|
||||
} else {
|
||||
write!(f, "{}", self.name)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl std::str::FromStr for RoleIdentifier {
|
||||
type Err = RoleFromStrError;
|
||||
|
||||
fn from_str(s: &str) -> std::result::Result<Self, Self::Err> {
|
||||
if let Some((name, source)) = split_once(s, '/') {
|
||||
Ok(RoleIdentifier { name: name.to_string(), source: source.to_string() })
|
||||
} else {
|
||||
Ok(RoleIdentifier { name: s.to_string(), source: String::new() })
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl TryFrom<String> for RoleIdentifier {
|
||||
type Error = RoleFromStrError;
|
||||
|
||||
fn try_from(s: String) -> std::result::Result<Self, Self::Error> {
|
||||
<RoleIdentifier as std::str::FromStr>::from_str(&s)
|
||||
}
|
||||
}
|
||||
impl Into<String> for RoleIdentifier {
|
||||
fn into(self) -> String {
|
||||
format!("{}", self)
|
||||
}
|
||||
}
|
||||
|
||||
impl RoleIdentifier {
|
||||
pub fn local_from_str(source: String, name: String) -> Self {
|
||||
RoleIdentifier { name, source }
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Debug, Copy, Clone, PartialEq, Eq, PartialOrd, Ord)]
|
||||
pub enum RoleFromStrError {
|
||||
/// No '@' or '%' found. That's strange, huh?
|
||||
Invalid
|
||||
}
|
||||
|
||||
impl fmt::Display for RoleFromStrError {
|
||||
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
|
||||
match self {
|
||||
RoleFromStrError::Invalid
|
||||
=> write!(f, "Rolename are of form 'name%source' or 'name@realm'."),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
fn is_sep_char(c: char) -> bool {
|
||||
c == '.'
|
||||
|
@ -0,0 +1,146 @@
|
||||
use std::fmt;
|
||||
use crate::authorization::permissions::PermRule;
|
||||
|
||||
/// A "Role" from the Authorization perspective
|
||||
///
|
||||
/// You can think of a role as a bundle of permissions relating to other roles. In most cases a
|
||||
/// role represents a real-world education or apprenticeship, which gives a person the education
|
||||
/// necessary to use a machine safely.
|
||||
/// Roles are assigned permissions which in most cases evaluate to granting a person the right to
|
||||
/// use certain (potentially) dangerous machines.
|
||||
/// Using this indirection makes administration easier in certain ways; instead of maintaining
|
||||
/// permissions on users directly the user is given a role after having been educated on the safety
|
||||
/// of a machine; if later on a similar enough machine is put to use the administrator can just add
|
||||
/// the permission for that machine to an already existing role instead of manually having to
|
||||
/// assign to all users.
|
||||
#[derive(Debug, Clone, PartialEq, Eq, Hash, serde::Serialize, serde::Deserialize)]
|
||||
pub struct Role {
|
||||
// If a role doesn't define parents, default to an empty Vec.
|
||||
#[serde(default, skip_serializing_if = "Vec::is_empty")]
|
||||
/// A Role can have parents, inheriting all permissions
|
||||
///
|
||||
/// This makes situations where different levels of access are required easier: Each higher
|
||||
/// level of access sets the lower levels of access as parent, inheriting their permission; if
|
||||
/// you are allowed to manage a machine you are then also allowed to use it and so on
|
||||
parents: Vec<RoleIdentifier>,
|
||||
|
||||
// If a role doesn't define permissions, default to an empty Vec.
|
||||
#[serde(default, skip_serializing_if = "Vec::is_empty")]
|
||||
permissions: Vec<PermRule>,
|
||||
}
|
||||
|
||||
impl Role {
|
||||
pub fn new(parents: Vec<RoleIdentifier>, permissions: Vec<PermRule>) -> Self {
|
||||
Self { parents, permissions }
|
||||
}
|
||||
}
|
||||
|
||||
impl fmt::Display for Role {
|
||||
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
|
||||
write!(f, "parents:")?;
|
||||
if self.parents.is_empty() {
|
||||
writeln!(f, " []")?;
|
||||
} else {
|
||||
writeln!(f, "")?;
|
||||
for p in self.parents.iter() {
|
||||
writeln!(f, " - {}", p)?;
|
||||
}
|
||||
}
|
||||
write!(f, "permissions:")?;
|
||||
if self.permissions.is_empty() {
|
||||
writeln!(f, " []")?;
|
||||
} else {
|
||||
writeln!(f, "")?;
|
||||
for p in self.permissions.iter() {
|
||||
writeln!(f, " - {}", p)?;
|
||||
}
|
||||
}
|
||||
|
||||
Ok(())
|
||||
}
|
||||
}
|
||||
|
||||
type SourceID = String;
|
||||
|
||||
fn split_once(s: &str, split: char) -> Option<(&str, &str)> {
|
||||
s
|
||||
.find(split)
|
||||
.map(|idx| (&s[..idx], &s[(idx+1)..]))
|
||||
}
|
||||
|
||||
#[derive(Debug, Clone, PartialEq, Eq, Hash, serde::Serialize, serde::Deserialize)]
|
||||
#[serde(try_from = "String")]
|
||||
#[serde(into = "String")]
|
||||
/// Universal (relative) id of a role
|
||||
pub struct RoleIdentifier {
|
||||
/// Locally unique name for the role. No other role at this instance no matter the source
|
||||
/// may have the same name
|
||||
name: String,
|
||||
/// Role Source, i.e. the database the role comes from
|
||||
source: SourceID,
|
||||
}
|
||||
|
||||
impl RoleIdentifier {
|
||||
pub fn new<>(name: &str, source: &str) -> Self {
|
||||
Self { name: name.to_string(), source: source.to_string() }
|
||||
}
|
||||
pub fn from_strings(name: String, source: String) -> Self {
|
||||
Self { name, source }
|
||||
}
|
||||
}
|
||||
|
||||
impl fmt::Display for RoleIdentifier {
|
||||
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
|
||||
if self.source != "" {
|
||||
write!(f, "{}/{}", self.name, self.source)
|
||||
} else {
|
||||
write!(f, "{}", self.name)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl std::str::FromStr for RoleIdentifier {
|
||||
type Err = RoleFromStrError;
|
||||
|
||||
fn from_str(s: &str) -> std::result::Result<Self, Self::Err> {
|
||||
if let Some((name, source)) = split_once(s, '/') {
|
||||
Ok(RoleIdentifier { name: name.to_string(), source: source.to_string() })
|
||||
} else {
|
||||
Ok(RoleIdentifier { name: s.to_string(), source: String::new() })
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl TryFrom<String> for RoleIdentifier {
|
||||
type Error = RoleFromStrError;
|
||||
|
||||
fn try_from(s: String) -> std::result::Result<Self, Self::Error> {
|
||||
<RoleIdentifier as std::str::FromStr>::from_str(&s)
|
||||
}
|
||||
}
|
||||
impl Into<String> for RoleIdentifier {
|
||||
fn into(self) -> String {
|
||||
format!("{}", self)
|
||||
}
|
||||
}
|
||||
|
||||
impl RoleIdentifier {
|
||||
pub fn local_from_str(source: String, name: String) -> Self {
|
||||
RoleIdentifier { name, source }
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Debug, Copy, Clone, PartialEq, Eq, PartialOrd, Ord)]
|
||||
pub enum RoleFromStrError {
|
||||
/// No '@' or '%' found. That's strange, huh?
|
||||
Invalid
|
||||
}
|
||||
|
||||
impl fmt::Display for RoleFromStrError {
|
||||
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
|
||||
match self {
|
||||
RoleFromStrError::Invalid
|
||||
=> write!(f, "Rolename are of form 'name%source' or 'name@realm'."),
|
||||
}
|
||||
}
|
||||
}
|
@ -1,12 +1,17 @@
|
||||
use std::future::Future;
|
||||
use capnp::capability::Promise;
|
||||
use capnp::Error;
|
||||
use capnp_rpc::rpc_twoparty_capnp::Side;
|
||||
use capnp_rpc::RpcSystem;
|
||||
use capnp_rpc::twoparty::VatNetwork;
|
||||
use futures_lite::StreamExt;
|
||||
use futures_rustls::server::TlsStream;
|
||||
use futures_util::{AsyncRead, AsyncWrite};
|
||||
use futures_util::{AsyncRead, AsyncWrite, FutureExt};
|
||||
|
||||
use crate::error::Result;
|
||||
|
||||
use api::bootstrap::{
|
||||
Client,
|
||||
Server,
|
||||
MechanismsParams,
|
||||
MechanismsResults,
|
||||
@ -14,10 +19,13 @@ use api::bootstrap::{
|
||||
CreateSessionResults
|
||||
};
|
||||
|
||||
mod authentication;
|
||||
mod session;
|
||||
mod authenticationsystem;
|
||||
mod machine;
|
||||
mod machinesystem;
|
||||
mod permissionsystem;
|
||||
mod user;
|
||||
mod users;
|
||||
mod resources;
|
||||
mod session;
|
||||
|
||||
#[derive(Debug)]
|
||||
pub struct APIHandler {
|
||||
@ -28,8 +36,15 @@ impl APIHandler {
|
||||
pub fn handle<IO: 'static + Unpin + AsyncRead + AsyncWrite>(&mut self, stream: TlsStream<IO>)
|
||||
-> impl Future<Output = Result<()>>
|
||||
{
|
||||
unimplemented!();
|
||||
futures_util::future::ready(Ok(()))
|
||||
let (rx, tx) = futures_lite::io::split(stream);
|
||||
let vat = VatNetwork::new(rx, tx, Side::Server, Default::default());
|
||||
let bootstrap: Client = capnp_rpc::new_client(ApiSystem::new());
|
||||
|
||||
RpcSystem::new(Box::new(vat), Some(bootstrap.client))
|
||||
.map(|res| match res {
|
||||
Ok(()) => Ok(()),
|
||||
Err(e) => Err(e.into())
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
@ -39,6 +54,11 @@ struct ApiSystem {
|
||||
|
||||
}
|
||||
|
||||
impl ApiSystem {
|
||||
pub fn new() -> Self {
|
||||
Self {}
|
||||
}
|
||||
}
|
||||
|
||||
impl Server for ApiSystem {
|
||||
fn mechanisms(
|
||||
|
@ -1,5 +1,5 @@
|
||||
use api::session::Builder;
|
||||
use crate::capnp::resources::Resources;
|
||||
use crate::capnp::machinesystem::Resources;
|
||||
use crate::capnp::users::Users;
|
||||
|
||||
#[derive(Debug, Clone)]
|
||||
|
@ -1,4 +1,16 @@
|
||||
use api::users::Server;
|
||||
use capnp::capability::Promise;
|
||||
use capnp::Error;
|
||||
use capnp_rpc::pry;
|
||||
|
||||
use api::users::Server as UsersServer;
|
||||
|
||||
use api::user::{
|
||||
info,
|
||||
manage,
|
||||
admin,
|
||||
passwd,
|
||||
};
|
||||
|
||||
|
||||
#[derive(Debug, Clone)]
|
||||
pub struct Users {
|
||||
@ -13,6 +25,47 @@ impl Users {
|
||||
}
|
||||
}
|
||||
|
||||
impl Server for Users {
|
||||
impl UsersServer for Users {
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
struct User {
|
||||
|
||||
}
|
||||
|
||||
impl info::Server for User {
|
||||
fn list_roles(
|
||||
&mut self,
|
||||
_params: info::ListRolesParams,
|
||||
mut results: info::ListRolesResults
|
||||
) -> Promise<(), Error>
|
||||
{
|
||||
unimplemented!()
|
||||
}
|
||||
}
|
||||
|
||||
impl manage::Server for User {
|
||||
fn add_role(
|
||||
&mut self,
|
||||
params: manage::AddRoleParams,
|
||||
_: manage::AddRoleResults
|
||||
) -> Promise<(), Error> {
|
||||
unimplemented!()
|
||||
}
|
||||
|
||||
fn remove_role(
|
||||
&mut self,
|
||||
params: manage::RemoveRoleParams,
|
||||
_: manage::RemoveRoleResults
|
||||
) -> Promise<(), Error> {
|
||||
unimplemented!()
|
||||
}
|
||||
}
|
||||
|
||||
impl admin::Server for User {
|
||||
|
||||
}
|
||||
|
||||
impl passwd::Server for User {
|
||||
|
||||
}
|
||||
|
@ -0,0 +1,30 @@
|
||||
use std::sync::atomic::{AtomicU64, Ordering};
|
||||
|
||||
#[derive(Debug)]
|
||||
/// Unique ID Allocator
|
||||
///
|
||||
/// Helper to allocate numerical ids in shared contexts
|
||||
pub struct IdAllocator {
|
||||
next_id: AtomicU64,
|
||||
}
|
||||
|
||||
impl IdAllocator {
|
||||
pub fn new(next_id: u64) -> Self {
|
||||
Self { next_id: AtomicU64::new(next_id) }
|
||||
}
|
||||
|
||||
/// Return a new unused ID using an atomic fetch-add
|
||||
pub fn get_next_id(&self) -> u64 {
|
||||
self.next_id.fetch_add(1, Ordering::Release)
|
||||
}
|
||||
}
|
||||
|
||||
pub struct IdSegments {
|
||||
segments: Vec<(u64, u64)>,
|
||||
}
|
||||
|
||||
impl IdSegments {
|
||||
pub fn new(segments: Vec<(u64, u64)>) -> Self {
|
||||
Self { segments }
|
||||
}
|
||||
}
|
@ -34,6 +34,8 @@ pub use hash::{
|
||||
};
|
||||
|
||||
mod fix;
|
||||
|
||||
pub mod index;
|
||||
pub use fix::LMDBorrow;
|
||||
|
||||
use lmdb::Error;
|
||||
@ -43,13 +45,13 @@ use std::sync::Arc;
|
||||
use std::path::Path;
|
||||
use crate::users::{User, UserDB};
|
||||
use std::collections::HashMap;
|
||||
use crate::resource::state::{OwnedEntry, State, db::StateDB};
|
||||
use crate::resources::state::{OwnedEntry, State, db::StateDB};
|
||||
use std::iter::FromIterator;
|
||||
use std::ops::Deref;
|
||||
use crate::authentication::db::PassDB;
|
||||
use crate::resource::db::ResourceDB;
|
||||
use crate::resources::db::ResourceDB;
|
||||
use crate::utils::oid::{ArchivedObjectIdentifier, ObjectIdentifier};
|
||||
use crate::resource::state::value::SerializeValue;
|
||||
use crate::resources::state::value::SerializeValue;
|
||||
|
||||
#[derive(Debug)]
|
||||
pub enum DBError {
|
||||
|
@ -5,9 +5,9 @@ use async_channel as channel;
|
||||
use async_oneshot as oneshot;
|
||||
use futures_signals::signal::Signal;
|
||||
use futures_util::future::BoxFuture;
|
||||
use crate::resource::{Error, Update};
|
||||
use crate::resource::claim::{ResourceID, UserID};
|
||||
use crate::resource::state::State;
|
||||
use crate::resources::{Error, Update};
|
||||
use crate::resources::claim::{ResourceID, UserID};
|
||||
use crate::resources::state::State;
|
||||
|
||||
pub enum UpdateError {
|
||||
/// We're not connected to anything anymore. You can't do anything about this error and the
|
||||
@ -65,7 +65,7 @@ impl UpdateSink {
|
||||
|
||||
struct Resource;
|
||||
pub struct InitiatorDriver<S, I: Initiator> {
|
||||
// TODO: make this a static reference to the resource because it's much easier and we don't
|
||||
// TODO: make this a static reference to the resources because it's much easier and we don't
|
||||
// need to replace resources at runtime at the moment.
|
||||
resource_signal: S,
|
||||
resource: Option<channel::Sender<Update>>,
|
||||
@ -122,8 +122,8 @@ impl<S: Signal<Item=ResourceSink> + Unpin, I: Initiator + Unpin> Future for Init
|
||||
// do while there is work to do
|
||||
while {
|
||||
// First things first:
|
||||
// If we've send an update to the resource in question we have error channel set, so
|
||||
// we poll that first to determine if the resource has acted on it yet.
|
||||
// If we've send an update to the resources in question we have error channel set, so
|
||||
// we poll that first to determine if the resources has acted on it yet.
|
||||
if let Some(ref mut errchan) = self.error_channel {
|
||||
match Pin::new(errchan).poll(cx) {
|
||||
// In case there's an ongoing
|
||||
|
@ -1,4 +1,4 @@
|
||||
#![forbid(unused_imports, unused_import_braces)]
|
||||
#![warn(unused_imports, unused_import_braces)]
|
||||
#![warn(missing_debug_implementations)]
|
||||
#![warn(missing_docs)]
|
||||
#![warn(missing_crate_level_docs)]
|
||||
@ -14,14 +14,11 @@ pub mod db;
|
||||
/// Shared error type
|
||||
pub mod error;
|
||||
|
||||
/// Policy decision engine
|
||||
pub mod permissions;
|
||||
|
||||
pub mod users;
|
||||
pub mod authentication;
|
||||
pub mod authorization;
|
||||
|
||||
/// Resources
|
||||
pub mod resource;
|
||||
pub mod resources;
|
||||
|
||||
pub mod actors;
|
||||
|
@ -1,7 +1,7 @@
|
||||
use std::sync::Arc;
|
||||
use async_channel::Sender;
|
||||
use lmdb::Environment;
|
||||
use crate::resource::Update;
|
||||
use crate::resources::Update;
|
||||
|
||||
#[derive(Clone, Debug)]
|
||||
/// Database of currently valid claims, interests and notify, as far as applicable
|
||||
@ -24,16 +24,16 @@ enum Level {
|
||||
}
|
||||
|
||||
#[derive(Debug)]
|
||||
/// A claim on a resource grants permission to update state
|
||||
/// A claim on a resources grants permission to update state
|
||||
///
|
||||
/// This permission is not necessarily exclusive, depending on the resource in question.
|
||||
/// This permission is not necessarily exclusive, depending on the resources in question.
|
||||
pub struct Claim {
|
||||
/// Sending end that can be used to send state updates to a resource.
|
||||
/// Sending end that can be used to send state updates to a resources.
|
||||
pub tx: Sender<Update>,
|
||||
}
|
||||
|
||||
#[derive(Debug)]
|
||||
/// An interest on a resource indicates that an user wants a resource to be in a specific state
|
||||
/// An interest on a resources indicates that an user wants a resources to be in a specific state
|
||||
pub struct Interest {
|
||||
|
||||
}
|
||||
|
@ -13,12 +13,12 @@ pub mod claim;
|
||||
pub mod db;
|
||||
|
||||
|
||||
/// A resource in BFFH has to contain several different parts;
|
||||
/// A resources in BFFH has to contain several different parts;
|
||||
/// - Currently set state
|
||||
/// - Execution state of attached actors (⇒ BFFH's job)
|
||||
/// - Output of interal logic of a resource
|
||||
/// - Output of interal logic of a resources
|
||||
/// ⇒ Resource logic gets read access to set state and write access to output state.
|
||||
/// ⇒ state `update` happens via resource logic. This logic should do access control. If the update
|
||||
/// ⇒ state `update` happens via resources logic. This logic should do access control. If the update
|
||||
/// succeeds then BFFH stores those input parameters ("set" state) and results / output state.
|
||||
/// Storing input parameters is relevant so that BFFH can know that an "update" is a no-op
|
||||
/// without having to run the module code.
|
||||
@ -42,7 +42,7 @@ pub mod db;
|
||||
/// - Check authorization of updates i.e. is this user allowed to do that
|
||||
#[async_trait]
|
||||
pub trait ResourceModel: Debug {
|
||||
/// Run whatever internal logic this resource has for the given State update, and return the
|
||||
/// Run whatever internal logic this resources has for the given State update, and return the
|
||||
/// new output state that this update produces.
|
||||
async fn on_update(&mut self, input: &State) -> Result<State, Error>;
|
||||
async fn shutdown(&mut self);
|
||||
@ -59,7 +59,7 @@ impl ResourceModel for Passthrough {
|
||||
async fn shutdown(&mut self) {}
|
||||
}
|
||||
|
||||
/// Error type a resource implementation can produce
|
||||
/// Error type a resources implementation can produce
|
||||
#[derive(Debug)]
|
||||
pub enum Error {
|
||||
Internal(Box<dyn std::error::Error + Send>),
|
||||
@ -99,9 +99,9 @@ impl ResourceDriver {
|
||||
// the DB is not necessarily fatal, but it means that BFFH is now in an
|
||||
// inconsistent state until a future update succeeds with writing to the DB.
|
||||
// Not applying the new state isn't correct either since we don't know what the
|
||||
// internal logic of the resource has done to make this happen.
|
||||
// internal logic of the resources has done to make this happen.
|
||||
// Another half right solution is to unwrap and recreate everything.
|
||||
// "Best" solution would be to tell the resource to rollback their interal
|
||||
// "Best" solution would be to tell the resources to rollback their interal
|
||||
// changes on a fatal failure and then notify the Claimant, while simply trying
|
||||
// again for temporary failures.
|
||||
let _ = self.db.set(&state, &outstate);
|
||||
|
@ -24,7 +24,7 @@ use crate::db::{
|
||||
LMDBorrow,
|
||||
};
|
||||
|
||||
use crate::resource::state::State;
|
||||
use crate::resources::state::State;
|
||||
|
||||
type StateAdapter = AllocAdapter<State>;
|
||||
|
||||
@ -37,7 +37,7 @@ pub struct StateDB {
|
||||
input: DB<StateAdapter>,
|
||||
output: DB<StateAdapter>,
|
||||
|
||||
// TODO: Index resource name/id/uuid -> u64
|
||||
// TODO: Index resources name/id/uuid -> u64
|
||||
}
|
||||
|
||||
impl StateDB {
|
||||
|
@ -23,7 +23,7 @@ use serde::ser::SerializeMap;
|
||||
use value::{RegisteredImpl, SerializeValue};
|
||||
|
||||
use crate::utils::oid::ObjectIdentifier;
|
||||
use crate::resource::state::value::{DynOwnedVal, DynVal, TypeOid, };
|
||||
use crate::resources::state::value::{DynOwnedVal, DynVal, TypeOid, };
|
||||
|
||||
pub mod value;
|
||||
pub mod db;
|
||||
@ -32,10 +32,10 @@ pub mod db;
|
||||
#[derive(Archive, Serialize, Deserialize)]
|
||||
#[derive(Clone, PartialEq)]
|
||||
#[archive_attr(derive(Debug))]
|
||||
/// State object of a resource
|
||||
/// State object of a resources
|
||||
///
|
||||
/// This object serves three functions:
|
||||
/// 1. it is constructed by modification via Claims or via internal resource logic
|
||||
/// 1. it is constructed by modification via Claims or via internal resources logic
|
||||
/// 2. it is serializable and storable in the database
|
||||
/// 3. it is sendable and forwarded to all Actors and Notifys
|
||||
pub struct State {
|
||||
|
@ -14,18 +14,9 @@
|
||||
* along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
use rkyv::{Archive, Serialize, Deserialize};
|
||||
|
||||
use capnp::capability::Promise;
|
||||
use capnp::Error;
|
||||
use capnp_rpc::pry;
|
||||
|
||||
use api::user::{
|
||||
info,
|
||||
manage,
|
||||
admin,
|
||||
passwd,
|
||||
};
|
||||
use std::ops::Deref;
|
||||
use std::sync::Arc;
|
||||
use rkyv::{Archive, Serialize, Deserialize, Infallible};
|
||||
|
||||
mod db;
|
||||
|
||||
@ -33,7 +24,6 @@ pub use db::UserDB;
|
||||
pub use crate::authentication::db::PassDB;
|
||||
|
||||
#[derive(Debug, Clone, Archive, Serialize, Deserialize, serde::Serialize, serde::Deserialize)]
|
||||
/// User API endpoint
|
||||
pub struct User {
|
||||
id: u128,
|
||||
username: String,
|
||||
@ -44,55 +34,4 @@ impl User {
|
||||
pub fn new(id: u128, username: String, roles: Vec<String>) -> Self {
|
||||
User { id, username, roles }
|
||||
}
|
||||
}
|
||||
|
||||
impl info::Server for User {
|
||||
fn list_roles(
|
||||
&mut self,
|
||||
_params: info::ListRolesParams,
|
||||
mut results: info::ListRolesResults
|
||||
) -> Promise<(), Error>
|
||||
{
|
||||
let results = results.get();
|
||||
let mut roles = results.init_roles(self.roles.len() as u32);
|
||||
|
||||
for (i, role) in self.roles.iter().enumerate() {
|
||||
let mut role_builder = roles.reborrow().get(i as u32);
|
||||
role_builder.set_name(role);
|
||||
}
|
||||
|
||||
Promise::ok(())
|
||||
}
|
||||
}
|
||||
|
||||
impl manage::Server for User {
|
||||
fn add_role(
|
||||
&mut self,
|
||||
params: manage::AddRoleParams,
|
||||
_: manage::AddRoleResults
|
||||
) -> Promise<(), Error> {
|
||||
let params = pry!(params.get());
|
||||
let name = pry!(params.get_name()).to_string();
|
||||
self.roles.push(name);
|
||||
Promise::ok(())
|
||||
}
|
||||
|
||||
fn remove_role(
|
||||
&mut self,
|
||||
params: manage::RemoveRoleParams,
|
||||
_: manage::RemoveRoleResults
|
||||
) -> Promise<(), Error> {
|
||||
let params = pry!(params.get());
|
||||
let name = pry!(params.get_name());
|
||||
self.roles.retain(|role| role != name);
|
||||
Promise::ok(())
|
||||
}
|
||||
}
|
||||
|
||||
impl admin::Server for User {
|
||||
|
||||
}
|
||||
|
||||
impl passwd::Server for User {
|
||||
|
||||
}
|
@ -7,8 +7,9 @@ use serde::{Serialize, Deserialize, Deserializer, Serializer};
|
||||
use std::fmt::Formatter;
|
||||
use std::net::{SocketAddr, IpAddr, ToSocketAddrs};
|
||||
use std::str::FromStr;
|
||||
use diflouroborane::permissions::{PermRule, RoleIdentifier};
|
||||
use serde::de::Error;
|
||||
use diflouroborane::authorization::permissions::PermRule;
|
||||
use diflouroborane::authorization::roles::RoleIdentifier;
|
||||
|
||||
type Result<T> = std::result::Result<T, serde_dhall::Error>;
|
||||
|
||||
|
6
runtime/executor/src/manage.rs
Normal file
6
runtime/executor/src/manage.rs
Normal file
@ -0,0 +1,6 @@
|
||||
|
||||
|
||||
/// View and Manage the current processes of this executor
|
||||
pub struct Manager {
|
||||
|
||||
}
|
Loading…
Reference in New Issue
Block a user