"chrono",
"chrono-tz",
"delegate",
+ "either",
"failure",
"fehler",
"flexi_logger",
chrono = "0.4"
chrono-tz = "0.5"
delegate = "0.4"
+either = "1"
failure = "0.1.8" # for pwd
fehler = "1"
flexi_logger = { version = "0.15", features = [ "specfile" ] }
panic!("xxx")
}
}
+
+//---------- acl handling ----------
+
+pub mod loaded_acl {
+ use crate::imports::*;
+
+ pub trait Perm : FromPrimitive + ToPrimitive
+ + Copy + Eq + Hash + Sync + Send { }
+
+ #[derive(Copy,Clone,Debug)]
+ pub struct PermSet<P: Perm> (u64, PhantomData<&'static P>);
+
+ #[derive(Debug,Clone)]
+ pub struct EffectiveAcl<'i, P: Perm> {
+ pub owner_account: Option<&'i str>,
+ pub acl: LoadedAcl<P>,
+ }
+
+ #[derive(Debug,Clone)]
+ pub struct LoadedAcl<P: Perm> (Vec<LoadedAclEntry<P>>);
+
+ #[derive(Debug,Clone)]
+ struct LoadedAclEntry<P: Perm> {
+ pat: glob::Pattern,
+ allow: Bitmap,
+ deny: Bitmap,
+ ptype: PhantomData<&'static P>,
+ }
+
+ #[derive(Debug)]
+ struct AclEntryRef<'r, P: Perm> {
+ pat: Either<&'r str, &'r glob::Pattern>,
+ allow: u64,
+ deny: u64,
+ ptype: PhantomData<&'static P>,
+ }
+
+ impl<P:Perm> LoadedAcl<P> {
+ fn entries(&'s self) -> impl Iterator<Item=AclEntryRef<'s>> {
+ self.owner_account.map(
+ |owner|
+ AclEntryRef { pat: Left(owner), allow: !0, deny: 0, ptype }
+ ).chain(self.entries.map(
+ |LoadedAclEntry { pat, allow, deny }|
+ AclEntryRef { pat: Left(pat), allow: allow.0, deny: deny.0 }
+ ))
+ }
+
+ #[throws(MgmtError)]
+ fn check(&self, account_name: &str, p: PermSet<P>) {
+ let mut needed = p.0;
+ assert!(needed != 0);
+ for AclEntryRef { pat, allow, deny } in self.entries() {
+ if !match pat {
+ Left(owner) => owner == account_name,
+ Right(pat) => pat.matches(account_name),
+ } { continue }
+ if needed & deny != 0 { break }
+ needed &= !allow;
+ if needed == 0 { return Ok(()) }
+ }
+ Err(ME::PermissionDenied)
+ }
+ }
+
+ impl<P:Perm> From<I> for PermSet<P> where I: IntoIterator<Item=&P> {
+ fn from(i: I) -> Self {
+ i.into_iter().fold(0, |b, i| b | i.to_u64().unwrap())
+ }
+ }
+
+ fn unpack<P:Perm>(unpacked: Bitmap) -> HashSet<P> {
+ let mut s = HashSet::new();
+ for n in 0.. {
+ let v = match FromPrimitive::from_u64(n) { Some(v) => v, None => break };
+ if unpacked & n != 0 { s.insert(v) }
+ }
+ s
+ }
+
+ impl<P:Perm> From<Acl<P>> for LoadedAcl<P> {
+ fn from(acl: Acl<P>) -> LoadedAcl<P> {
+ let ents = acl.into_iter().map(
+ |AclEntry { account_glob, allow, deny }|
+ LoadedAclEntry { account_glob, allow: allow.into(), deny: deny.into() }
+ ).collect();
+ LoadedAcl(ents)
+ }
+ }
+
+ impl<P:Perm> From<LoadedAcl<P>> for Acl<P> {
+ fn from(acl: LoadedAcl<P>) -> Acl<P> {
+ let LoadedAcl(ents) = acl;
+ ents.into_iter().map(
+ |LoadedAclEntry { account_glob, allow, deny }|
+ AclEntry { account_glob, allow: unpack(allow), deny: unpack(deny) }
+ ).collect()
+ }
+ }
+}
fn fmt(&self, f: &mut Formatter) { write!(f, "The facilitator")? }
}
+struct CommandStream<'d> {
+ euid : Result<Uid, ConnectionEuidDiscoverEerror>,
+ desc : &'d str,
+ account : Option<AccountSpecified>,
+ chan : MgmtChannel,
+ who: Who,
+}
+
+#[derive(Debug,Clone)]
+struct AccountSpecified {
+ name: ScopedName,
+ cooked: String,
+ auth: Authorisation<AccountScope>,
+}
+
// ========== management API ==========
// ---------- management command implementations
Noop => Fine,
SetAccount(wanted_account) => {
- let authorised = authorise_scope(cs, &wanted_account.scope)?;
+ let authorised = authorise_scope_direct(cs, &wanted_account.scope)?;
cs.account = Some((
wanted_account,
authorised.therefore_ok(),
},
CreateGame { game, insns } => {
- let authorised = authorise_scope(cs, &game.scope)?;
- let authorised : Authorisation<AccountName> = authorised.therefore_ok();
+ let authorised = authorise_by_account(cs, &game.scope)?;
let gs = crate::gamestate::GameState {
table_size : DEFAULT_TABLE_SIZE,
ListGames { all } => {
let (scope, auth) = if all == Some(true) {
- let auth = authorise_scope(cs, &AS::Server)?;
+ let auth = authorise_scope_direct(cs, &AS::Server)?;
(None, auth)
} else {
let (account, auth) = cs.account.as_ref()
type Insn = MgmtGameInstruction;
type Resp = MgmtGameResponse;
let who = &cs.who;
- fn readonly(_ig: &InstanceGuard, resp: Resp) -> ExecuteGameInsnResults {
+
+ fn readonly<F: FnOnce(&mut InstanceGuard) -> ExecuteGameInsnResults>(
+ cs: &CommandStream,
+ ig: &Unauthorised<InstanceGuard>,
+ p: PermSet<TablePermission>,
+ f: F) -> ExecuteGameInsnResults
+ {
+ let ig = ig.check_acl(&cs.account.as_ref()?.cooked)?;
+ let resp = f(ig);
(U{ pcs: vec![], log: vec![], raw: None }, resp)
}
// ---------- core listener implementation ----------
-struct CommandStream<'d> {
- euid : Result<Uid, ConnectionEuidDiscoverEerror>,
- desc : &'d str,
- account : Option<(AccountName, Authorisation<AccountScope>)>,
- chan : MgmtChannel,
- who: Who,
-}
-
impl CommandStream<'_> {
#[throws(CSE)]
pub fn mainloop(mut self) {
}
#[throws(MgmtError)]
-fn authorise_scope(cs: &CommandStream, wanted: &AccountScope)
- -> Authorisation<AccountScope> {
+fn authorise_scope_direct(cs: &CommandStream, wanted: &AccountScope)
+ -> Authorisation<AccountScope> {
+ // Usually, use authorise_by_account
do_authorise_scope(cs, wanted)
.map_err(|e| cs.map_auth_err(e))?
}
pub iplayers : SecondarySlotMap<PlayerId, PlayerRecord>,
pub tokens_players : TokenRegistry<PlayerId>,
pub tokens_clients : TokenRegistry<ClientId>,
+ pub acl: Acl<TablePermission>,
}
pub struct PlayerRecord {
}
}
+impl<A> Unauthorised<InstanceGuard<'_>, A> {
+ #[throws(MgmtError)]
+ pub fn check_acl(&mut self, p: PermSet<TablePermissions>)
+ -> &mut InstanceGuard {
+ let auth = {
+ let acl = self.by(Authorisation::authorise_any()).acl;
+ acl.check(p)?;
+ };
+ self.by_mut(auth);
+ }
+}
+
impl<A> Unauthorised<InstanceRef, A> {
#[throws(InstanceLockError)]
pub fn lock(&self) -> Unauthorised<InstanceGuard<'_>, A> {
pub use log::{trace,debug,info,warn,error};
pub use log::log;
-pub use num_traits::Bounded;
+pub use num_traits::{Bounded, FromPrimitive, ToPrimitive};
pub use flexi_logger::{LogSpecification};
pub use crate::shapelib;
pub use crate::tz::*;
pub use crate::accounts::*;
+pub use crate::accounts::loaded_acl::{self,LoadedAcl};
pub use zcoord::{self, ZCoord};