mirror of
https://gitlab.com/fabinfra/fabaccess/bffh.git
synced 2024-11-23 15:17:57 +01:00
Initial commit
This commit is contained in:
commit
d5f92e41d1
2
.gitignore
vendored
Normal file
2
.gitignore
vendored
Normal file
@ -0,0 +1,2 @@
|
|||||||
|
/target
|
||||||
|
**/*.rs.bk
|
32
Cargo.toml
Normal file
32
Cargo.toml
Normal file
@ -0,0 +1,32 @@
|
|||||||
|
[package]
|
||||||
|
name = "bffh"
|
||||||
|
version = "0.1.0"
|
||||||
|
authors = ["Gregor Reitzenstein <me@dequbed.space>"]
|
||||||
|
edition = "2018"
|
||||||
|
|
||||||
|
# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html
|
||||||
|
|
||||||
|
[dependencies]
|
||||||
|
# TODO: reduce the feature groups for faster compilation
|
||||||
|
#tokio = { version = "0.2", features = ["full"] }
|
||||||
|
|
||||||
|
async-std = "1.5"
|
||||||
|
futures = "0.3"
|
||||||
|
futures-util = "0.3"
|
||||||
|
futures-signals = "0.3"
|
||||||
|
|
||||||
|
slog = "2.5"
|
||||||
|
slog-term = "2.5"
|
||||||
|
slog-async = "2.4"
|
||||||
|
|
||||||
|
capnp = "0.12"
|
||||||
|
capnp-rpc = "0.12"
|
||||||
|
|
||||||
|
toml = "0.5"
|
||||||
|
serde = "1"
|
||||||
|
serde_derive = "1"
|
||||||
|
|
||||||
|
casbin = "0.2"
|
||||||
|
|
||||||
|
[build-dependencies]
|
||||||
|
capnpc = "0.12"
|
3
build.rs
Normal file
3
build.rs
Normal file
@ -0,0 +1,3 @@
|
|||||||
|
fn main() {
|
||||||
|
::capnpc::CompilerCommand::new().file("schema/api.capnp").run().unwrap()
|
||||||
|
}
|
10
schema/api.capnp
Normal file
10
schema/api.capnp
Normal file
@ -0,0 +1,10 @@
|
|||||||
|
@0xfd92ce9be2369b8e;
|
||||||
|
|
||||||
|
interface BffhAdmin {
|
||||||
|
getAllSubjects @0 () -> (subjects :List(Subject));
|
||||||
|
|
||||||
|
struct Subject {
|
||||||
|
id @0 :Text;
|
||||||
|
domain @1 :Text;
|
||||||
|
}
|
||||||
|
}
|
15
src/access.rs
Normal file
15
src/access.rs
Normal file
@ -0,0 +1,15 @@
|
|||||||
|
//! Access control logic
|
||||||
|
//!
|
||||||
|
|
||||||
|
use casbin::prelude::*;
|
||||||
|
|
||||||
|
use super::config::Config;
|
||||||
|
|
||||||
|
pub async fn init(config: &Config) -> Result<Enforcer, Box<dyn std::error::Error>> {
|
||||||
|
let model = Model::from_file(config.access.model.clone()).await?;
|
||||||
|
let adapter = Box::new(FileAdapter::new(config.access.policy.clone()));
|
||||||
|
|
||||||
|
let e = Enforcer::new(model, adapter).await?;
|
||||||
|
|
||||||
|
return Ok(e);
|
||||||
|
}
|
48
src/api.rs
Normal file
48
src/api.rs
Normal file
@ -0,0 +1,48 @@
|
|||||||
|
// module needs to be top level for generated functions to be in scope:
|
||||||
|
// https://github.com/capnproto/capnproto-rust/issues/16
|
||||||
|
pub(crate) mod api_capnp {
|
||||||
|
include!(concat!(env!("OUT_DIR"), "/schema/api_capnp.rs"));
|
||||||
|
}
|
||||||
|
|
||||||
|
use std::default::Default;
|
||||||
|
use async_std::net::TcpStream;
|
||||||
|
|
||||||
|
use futures_signals::signal::Mutable;
|
||||||
|
use casbin::Enforcer;
|
||||||
|
use casbin::MgmtApi;
|
||||||
|
|
||||||
|
pub fn init() {
|
||||||
|
}
|
||||||
|
|
||||||
|
pub async fn process_socket(enforcer: Mutable<Enforcer>, socket: TcpStream) -> Result<(), capnp::Error> {
|
||||||
|
let api = Api { e: enforcer };
|
||||||
|
let a = api_capnp::bffh_admin::ToClient::new(api).into_client::<::capnp_rpc::Server>();
|
||||||
|
let netw = capnp_rpc::twoparty::VatNetwork::new(socket.clone(), socket,
|
||||||
|
capnp_rpc::rpc_twoparty_capnp::Side::Server, Default::default());
|
||||||
|
let rpc = capnp_rpc::RpcSystem::new(Box::new(netw), Some(a.clone().client));
|
||||||
|
rpc.await
|
||||||
|
}
|
||||||
|
|
||||||
|
struct Api {
|
||||||
|
e: Mutable<Enforcer>,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl api_capnp::bffh_admin::Server for Api {
|
||||||
|
fn get_all_subjects(&mut self,
|
||||||
|
_params: api_capnp::bffh_admin::GetAllSubjectsParams,
|
||||||
|
mut results: api_capnp::bffh_admin::GetAllSubjectsResults)
|
||||||
|
-> ::capnp::capability::Promise<(), ::capnp::Error>
|
||||||
|
{
|
||||||
|
let subjs = self.e.lock_ref().get_all_subjects();
|
||||||
|
let mut b = results.get()
|
||||||
|
.init_subjects(subjs.len() as u32);
|
||||||
|
for (i, s) in subjs.into_iter().enumerate() {
|
||||||
|
let bldr = b.reborrow();
|
||||||
|
let mut sub = bldr.get(i as u32);
|
||||||
|
sub.set_id(&s);
|
||||||
|
sub.set_domain("");
|
||||||
|
}
|
||||||
|
|
||||||
|
::capnp::capability::Promise::ok(())
|
||||||
|
}
|
||||||
|
}
|
25
src/config.rs
Normal file
25
src/config.rs
Normal file
@ -0,0 +1,25 @@
|
|||||||
|
use std::str::FromStr;
|
||||||
|
use std::path::PathBuf;
|
||||||
|
use serde_derive::Deserialize;
|
||||||
|
|
||||||
|
use crate::error::Result;
|
||||||
|
|
||||||
|
pub fn read() -> Result<Config> {
|
||||||
|
Ok(Config {
|
||||||
|
access: Access {
|
||||||
|
model: PathBuf::from_str("/tmp/model.conf").unwrap(),
|
||||||
|
policy: PathBuf::from_str("/tmp/policy.csv").unwrap(),
|
||||||
|
}
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(Deserialize)]
|
||||||
|
pub struct Config {
|
||||||
|
pub(crate) access: Access
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(Deserialize)]
|
||||||
|
pub struct Access {
|
||||||
|
pub(crate) model: PathBuf,
|
||||||
|
pub(crate) policy: PathBuf
|
||||||
|
}
|
8
src/error.rs
Normal file
8
src/error.rs
Normal file
@ -0,0 +1,8 @@
|
|||||||
|
use std::io;
|
||||||
|
|
||||||
|
#[derive(Debug)]
|
||||||
|
pub enum Error {
|
||||||
|
IO(io::Error)
|
||||||
|
}
|
||||||
|
|
||||||
|
pub type Result<T> = std::result::Result<T, Error>;
|
11
src/log.rs
Normal file
11
src/log.rs
Normal file
@ -0,0 +1,11 @@
|
|||||||
|
use slog::{Drain, Logger};
|
||||||
|
use slog_async;
|
||||||
|
use slog_term::{TermDecorator, FullFormat};
|
||||||
|
|
||||||
|
pub fn init() -> Logger {
|
||||||
|
let decorator = TermDecorator::new().build();
|
||||||
|
let drain = FullFormat::new(decorator).build().fuse();
|
||||||
|
let drain = slog_async::Async::new(drain).build().fuse();
|
||||||
|
|
||||||
|
return slog::Logger::root(drain, o!());
|
||||||
|
}
|
58
src/main.rs
Normal file
58
src/main.rs
Normal file
@ -0,0 +1,58 @@
|
|||||||
|
#[macro_use]
|
||||||
|
extern crate slog;
|
||||||
|
|
||||||
|
mod access;
|
||||||
|
mod modules;
|
||||||
|
mod log;
|
||||||
|
mod api;
|
||||||
|
mod config;
|
||||||
|
mod error;
|
||||||
|
|
||||||
|
use api::api_capnp;
|
||||||
|
|
||||||
|
use futures::prelude::*;
|
||||||
|
use futures_signals::signal::Mutable;
|
||||||
|
use futures::task::LocalSpawn;
|
||||||
|
|
||||||
|
fn main() {
|
||||||
|
let log = log::init();
|
||||||
|
info!(log, "Starting");
|
||||||
|
|
||||||
|
let config = config::read().unwrap();
|
||||||
|
|
||||||
|
modules::init(log.new(o!()));
|
||||||
|
api::init();
|
||||||
|
|
||||||
|
let mut exec = futures::executor::LocalPool::new();
|
||||||
|
|
||||||
|
let enf = exec.run_until(async {
|
||||||
|
let e = access::init(&config).await.unwrap();
|
||||||
|
Mutable::new(e)
|
||||||
|
});
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
use std::net::ToSocketAddrs;
|
||||||
|
let args: Vec<String> = ::std::env::args().collect();
|
||||||
|
if args.len() != 2 {
|
||||||
|
println!("usage: {} ADDRESS[:PORT]", args[0]);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
let addr = args[1].to_socket_addrs().unwrap().next().expect("could not parse address");
|
||||||
|
|
||||||
|
|
||||||
|
let spawner = exec.spawner();
|
||||||
|
let result: Result<(), Box<dyn std::error::Error>> = exec.run_until(async move {
|
||||||
|
let listener = async_std::net::TcpListener::bind(&addr).await?;
|
||||||
|
let mut incoming = listener.incoming();
|
||||||
|
while let Some(socket) = incoming.next().await {
|
||||||
|
let socket = socket?;
|
||||||
|
let rpc_system = api::process_socket(enf.clone(), socket);
|
||||||
|
spawner.spawn_local_obj(
|
||||||
|
Box::pin(rpc_system.map_err(|e| println!("error: {:?}", e)).map(|_|())).into()).expect("spawn")
|
||||||
|
}
|
||||||
|
Ok(())
|
||||||
|
});
|
||||||
|
result.expect("main");
|
||||||
|
}
|
16
src/modules.rs
Normal file
16
src/modules.rs
Normal file
@ -0,0 +1,16 @@
|
|||||||
|
//! Indpendent Communication modules
|
||||||
|
//!
|
||||||
|
//! This is where dynamic modules are implemented later on using libloading / abi_stable_crates et
|
||||||
|
//! al.
|
||||||
|
//! Additionally, FFI modules to other languages (Python/Lua/...) make the most sense in here as
|
||||||
|
//! well.
|
||||||
|
|
||||||
|
mod mqtt;
|
||||||
|
|
||||||
|
use slog::Logger;
|
||||||
|
|
||||||
|
pub fn init(log: Logger) {
|
||||||
|
info!(log, "Initializing submodules");
|
||||||
|
mqtt::init(log.new(o!()));
|
||||||
|
info!(log, "Finished initializing submodules");
|
||||||
|
}
|
9
src/modules/mqtt.rs
Normal file
9
src/modules/mqtt.rs
Normal file
@ -0,0 +1,9 @@
|
|||||||
|
//! Mock impl of MQTT as transport.
|
||||||
|
//!
|
||||||
|
//! Specific Protocol implementations (Sonoff/Card2Go/...) would be located here
|
||||||
|
|
||||||
|
use slog::Logger;
|
||||||
|
|
||||||
|
pub fn init(log: Logger) {
|
||||||
|
info!(log, "MQTT Module initialized.")
|
||||||
|
}
|
Loading…
Reference in New Issue
Block a user