mirror of
https://gitlab.com/fabinfra/fabaccess/bffh.git
synced 2024-12-23 20:23:49 +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