mirror of
https://gitlab.com/fabinfra/fabaccess/bffh.git
synced 2024-11-22 06:47:56 +01:00
Now it *actually* compiles again
This commit is contained in:
parent
f6f0f14081
commit
7525fe49f6
@ -28,8 +28,6 @@ capnp-rpc = "0.12"
|
|||||||
toml = "0.5"
|
toml = "0.5"
|
||||||
serde = { version = "1.0", features = ["derive"] }
|
serde = { version = "1.0", features = ["derive"] }
|
||||||
|
|
||||||
casbin = "0.2"
|
|
||||||
|
|
||||||
uuid = { version = "0.8", features = ["serde", "v4"] }
|
uuid = { version = "0.8", features = ["serde", "v4"] }
|
||||||
|
|
||||||
clap = "2.33"
|
clap = "2.33"
|
||||||
|
3
build.rs
3
build.rs
@ -1,3 +1,4 @@
|
|||||||
fn main() {
|
fn main() {
|
||||||
::capnpc::CompilerCommand::new().file("schema/api.capnp").run().unwrap()
|
::capnpc::CompilerCommand::new().file("schema/api.capnp").run().unwrap();
|
||||||
|
::capnpc::CompilerCommand::new().file("schema/auth.capnp").run().unwrap();
|
||||||
}
|
}
|
||||||
|
@ -3,64 +3,20 @@
|
|||||||
|
|
||||||
use slog::Logger;
|
use slog::Logger;
|
||||||
|
|
||||||
use casbin::prelude::*;
|
|
||||||
|
|
||||||
use crate::config::Config;
|
use crate::config::Config;
|
||||||
use crate::auth::Authentication;
|
|
||||||
use crate::error::Result;
|
|
||||||
|
|
||||||
use std::rc::Rc;
|
|
||||||
use async_std::sync::{Arc, RwLock};
|
|
||||||
|
|
||||||
use std::ops::Deref;
|
|
||||||
|
|
||||||
pub struct PermissionsProvider {
|
pub struct PermissionsProvider {
|
||||||
log: Logger,
|
log: Logger,
|
||||||
pdb: Enforcer,
|
|
||||||
}
|
}
|
||||||
|
|
||||||
impl PermissionsProvider {
|
impl PermissionsProvider {
|
||||||
pub fn new(log: Logger, pdb: Enforcer) -> Self {
|
pub fn new(log: Logger) -> Self {
|
||||||
Self { log, pdb }
|
Self { log }
|
||||||
}
|
|
||||||
|
|
||||||
pub fn enforce(&self, actor: &str, object: &str, action: &str) -> Result<bool> {
|
|
||||||
let b = self.pdb.enforce(vec![actor, object, action])?;
|
|
||||||
if b {
|
|
||||||
trace!(self.log, "Granted {} on {} for {}", action, object, actor);
|
|
||||||
} else {
|
|
||||||
trace!(self.log, "Denied {} on {} for {}", action, object, actor);
|
|
||||||
}
|
|
||||||
Ok(b)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
#[derive(Clone)]
|
|
||||||
pub struct Permissions {
|
|
||||||
inner: Arc<RwLock<PermissionsProvider>>,
|
|
||||||
auth: Rc<Authentication>,
|
|
||||||
}
|
|
||||||
|
|
||||||
impl Permissions {
|
|
||||||
pub fn new(inner: Arc<RwLock<PermissionsProvider>>, auth: Rc<Authentication>) -> Self {
|
|
||||||
Self { inner, auth }
|
|
||||||
}
|
|
||||||
|
|
||||||
pub async fn enforce(&self, object: &str, action: &str) -> Result<bool> {
|
|
||||||
if let Some(actor) = self.auth.state.read().await.deref() {
|
|
||||||
self.inner.read().await.enforce(&actor, object, action)
|
|
||||||
} else {
|
|
||||||
Ok(false)
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/// This line documents init
|
/// This line documents init
|
||||||
pub async fn init(log: Logger, config: &Config) -> std::result::Result<PermissionsProvider, Box<dyn std::error::Error>> {
|
pub async fn init(log: Logger, config: &Config) -> std::result::Result<PermissionsProvider, Box<dyn std::error::Error>> {
|
||||||
let model = Model::from_file(config.access.model.clone()).await?;
|
return Ok(PermissionsProvider::new(log));
|
||||||
let adapter = Box::new(FileAdapter::new(config.access.policy.clone()));
|
|
||||||
|
|
||||||
let e = Enforcer::new(model, adapter).await?;
|
|
||||||
|
|
||||||
return Ok(PermissionsProvider::new(log, e));
|
|
||||||
}
|
}
|
||||||
|
24
src/api.rs
24
src/api.rs
@ -4,32 +4,12 @@ pub mod gen {
|
|||||||
include!(concat!(env!("OUT_DIR"), "/schema/api_capnp.rs"));
|
include!(concat!(env!("OUT_DIR"), "/schema/api_capnp.rs"));
|
||||||
}
|
}
|
||||||
|
|
||||||
use std::default::Default;
|
|
||||||
use async_std::net::TcpStream;
|
use async_std::net::TcpStream;
|
||||||
|
|
||||||
use futures::task::Spawn;
|
|
||||||
use futures::FutureExt;
|
|
||||||
use futures_signals::signal::Mutable;
|
|
||||||
use casbin::Enforcer;
|
|
||||||
use casbin::MgmtApi;
|
|
||||||
|
|
||||||
use slog::Logger;
|
use slog::Logger;
|
||||||
|
|
||||||
use std::rc::Rc;
|
use crate::error::Result;
|
||||||
use async_std::sync::{Arc, RwLock};
|
|
||||||
|
|
||||||
use crate::machine::{MachinesProvider, Machines};
|
pub async fn handle_connection(log: Logger, socket: TcpStream) -> Result<()> {
|
||||||
use crate::auth::{AuthenticationProvider, Authentication};
|
|
||||||
use crate::access::{PermissionsProvider, Permissions};
|
|
||||||
|
|
||||||
use capnp::{Error};
|
|
||||||
use capnp::capability::Promise;
|
|
||||||
use capnp_rpc::RpcSystem;
|
|
||||||
use capnp_rpc::twoparty::VatNetwork;
|
|
||||||
use capnp_rpc::rpc_twoparty_capnp::Side;
|
|
||||||
|
|
||||||
use std::ops::Deref;
|
|
||||||
|
|
||||||
pub async fn handle_connection(log: Logger, socket: TcpStream) -> Result<(), Error> {
|
|
||||||
unimplemented!()
|
unimplemented!()
|
||||||
}
|
}
|
||||||
|
160
src/auth.rs
160
src/auth.rs
@ -3,147 +3,43 @@
|
|||||||
//! Authorization is over in `access.rs`
|
//! Authorization is over in `access.rs`
|
||||||
//! Authentication using SASL
|
//! Authentication using SASL
|
||||||
|
|
||||||
use std::collections::HashMap;
|
|
||||||
use std::fmt;
|
|
||||||
use std::error::Error;
|
|
||||||
use std::path::Path;
|
|
||||||
use std::fs::File;
|
|
||||||
use std::io::{Read, Write};
|
|
||||||
use std::ops::Deref;
|
|
||||||
|
|
||||||
use async_std::sync::{Arc, RwLock};
|
|
||||||
use capnp::capability::Promise;
|
|
||||||
|
|
||||||
use futures_signals::signal::Mutable;
|
|
||||||
use casbin::{Enforcer, Model, FileAdapter};
|
|
||||||
|
|
||||||
use slog::Logger;
|
use slog::Logger;
|
||||||
|
|
||||||
|
use rsasl::{SASL, Property, Step, Session, ReturnCode};
|
||||||
|
use rsasl::sys::{Gsasl, Gsasl_session};
|
||||||
|
|
||||||
use crate::error::Result;
|
use crate::error::Result;
|
||||||
use crate::config::Config;
|
use crate::config::Config;
|
||||||
|
|
||||||
pub async fn init(log: Logger, config: Config) -> Result<AuthenticationProvider> {
|
pub mod gen {
|
||||||
let passdb = open_passdb(&config.passdb).unwrap();
|
include!(concat!(env!("OUT_DIR"), "/schema/auth_capnp.rs"));
|
||||||
|
|
||||||
let m = Model::from_file(&config.access.model).await?;
|
|
||||||
let a = FileAdapter::new(config.access.policy);
|
|
||||||
let enforcer = Enforcer::new(m, Box::new(a)).await?;
|
|
||||||
|
|
||||||
Ok(AuthenticationProvider::new(passdb, enforcer))
|
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Debug)]
|
extern "C" fn callback(ctx: *mut Gsasl, sctx: *mut Gsasl_session, prop: Property) -> i32 {
|
||||||
pub enum SASLError {
|
let sasl = SASL::from_ptr(ctx);
|
||||||
/// Expected UTF-8, got something else
|
let mut session = Session::from_ptr(sctx);
|
||||||
UTF8,
|
|
||||||
/// A bad Challenge was provided
|
|
||||||
BadChallenge,
|
|
||||||
/// Enforcer Failure
|
|
||||||
Enforcer,
|
|
||||||
}
|
|
||||||
impl fmt::Display for SASLError {
|
|
||||||
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
|
|
||||||
write!(f, "Bad SASL Exchange")
|
|
||||||
}
|
|
||||||
}
|
|
||||||
impl Error for SASLError {}
|
|
||||||
|
|
||||||
type PassDB = HashMap<String, String>;
|
let rc = match prop {
|
||||||
pub fn open_passdb(path: &Path) -> Option<PassDB> {
|
_ => { ReturnCode::GSASL_NO_CALLBACK }
|
||||||
if path.is_file() {
|
};
|
||||||
let mut fp = File::open(path).unwrap();
|
|
||||||
let mut content = String::new();
|
rc as i32
|
||||||
fp.read_to_string(&mut content).unwrap();
|
}
|
||||||
let map = toml::from_str(&content).ok()?;
|
|
||||||
return Some(map);
|
pub struct Auth {
|
||||||
} else {
|
ctx: SASL,
|
||||||
let mut map = HashMap::new();
|
}
|
||||||
map.insert("Testuser".to_string(), "Testpass".to_string());
|
|
||||||
let mut fp = File::create(&path).unwrap();
|
impl Auth {
|
||||||
let toml = toml::to_string(&map).unwrap();
|
pub fn new() -> Self {
|
||||||
fp.write_all(&toml.as_bytes()).unwrap();
|
let mut ctx = SASL::new().unwrap();
|
||||||
return Some(map);
|
|
||||||
|
ctx.install_callback(Some(callback));
|
||||||
|
|
||||||
|
Self { ctx }
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub struct Plain {
|
pub async fn init(log: Logger, config: Config) -> Result<Auth> {
|
||||||
// FIXME: I don't want to store passwords.
|
Ok(Auth::new())
|
||||||
passdb: PassDB,
|
|
||||||
enforcer: Enforcer,
|
|
||||||
}
|
|
||||||
|
|
||||||
impl Plain {
|
|
||||||
pub fn step<'a>(&self, data: &'a [u8]) -> Result<(bool, &'a str)> {
|
|
||||||
let data = std::str::from_utf8(data).map_err(|_| SASLError::UTF8)?;
|
|
||||||
if let Some((authzid, authcid, passwd)) = split_nul(data) {
|
|
||||||
|
|
||||||
// Check if we know about that user
|
|
||||||
if let Some(pwd) = self.passdb.get(authcid) {
|
|
||||||
// Check the provided password
|
|
||||||
// FIXME: At least use hashes
|
|
||||||
if pwd == passwd {
|
|
||||||
// authzid is the Identity the user wants to act as.
|
|
||||||
// If that is unset, shortcut to Success
|
|
||||||
if authzid == "" || authzid == authcid {
|
|
||||||
return Ok((true, authcid));
|
|
||||||
}
|
|
||||||
|
|
||||||
if let Ok(b) = self.enforcer.enforce(vec![authcid, authzid, "su"]) {
|
|
||||||
if b {
|
|
||||||
return Ok((true, authzid));
|
|
||||||
} else {
|
|
||||||
return Ok((false, authzid));
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
return Err(SASLError::Enforcer.into());
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
||||||
}
|
|
||||||
Ok((false, authzid))
|
|
||||||
} else {
|
|
||||||
return Err(SASLError::BadChallenge.into())
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn split_nul(string: &str) -> Option<(&str, &str, &str)> {
|
|
||||||
let mut i = string.split(|b| b == '\0');
|
|
||||||
|
|
||||||
let a = i.next()?;
|
|
||||||
let b = i.next()?;
|
|
||||||
let c = i.next()?;
|
|
||||||
|
|
||||||
Some((a,b,c))
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
pub struct AuthenticationProvider {
|
|
||||||
pub plain: Plain,
|
|
||||||
}
|
|
||||||
|
|
||||||
impl AuthenticationProvider {
|
|
||||||
pub fn new(passdb: PassDB, enforcer: Enforcer) -> Self {
|
|
||||||
Self {
|
|
||||||
plain: Plain { passdb, enforcer }
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn mechs(&self) -> Vec<&'static str> {
|
|
||||||
vec!["PLAIN"]
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
#[derive(Clone)]
|
|
||||||
pub struct Authentication {
|
|
||||||
pub state: Arc<RwLock<Option<String>>>,
|
|
||||||
provider: Arc<RwLock<AuthenticationProvider>>,
|
|
||||||
}
|
|
||||||
impl Authentication {
|
|
||||||
pub fn new(provider: Arc<RwLock<AuthenticationProvider>>) -> Self {
|
|
||||||
Self {
|
|
||||||
state: Arc::new(RwLock::new(None)),
|
|
||||||
provider: provider,
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
31
src/error.rs
31
src/error.rs
@ -1,19 +1,42 @@
|
|||||||
use std::io;
|
use std::io;
|
||||||
|
use std::fmt;
|
||||||
use toml;
|
use toml;
|
||||||
|
|
||||||
use crate::auth::SASLError;
|
use rsasl::SaslError;
|
||||||
|
|
||||||
#[derive(Debug)]
|
#[derive(Debug)]
|
||||||
pub enum Error {
|
pub enum Error {
|
||||||
TomlDe(toml::de::Error),
|
TomlDe(toml::de::Error),
|
||||||
TomlSer(toml::ser::Error),
|
TomlSer(toml::ser::Error),
|
||||||
SASL(SASLError),
|
SASL(SaslError),
|
||||||
IO(io::Error),
|
IO(io::Error),
|
||||||
Boxed(Box<dyn std::error::Error>),
|
Boxed(Box<dyn std::error::Error>),
|
||||||
}
|
}
|
||||||
|
|
||||||
impl From<SASLError> for Error {
|
impl fmt::Display for Error {
|
||||||
fn from(e: SASLError) -> Error {
|
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
|
||||||
|
match self {
|
||||||
|
Error::TomlDe(e) => {
|
||||||
|
write!(f, "TOML Decoding error: {}", e)
|
||||||
|
},
|
||||||
|
Error::TomlSer(e) => {
|
||||||
|
write!(f, "TOML Serialization error: {}", e)
|
||||||
|
},
|
||||||
|
Error::SASL(e) => {
|
||||||
|
write!(f, "SASL Error: {}", e)
|
||||||
|
},
|
||||||
|
Error::IO(e) => {
|
||||||
|
write!(f, "IO Error: {}", e)
|
||||||
|
},
|
||||||
|
Error::Boxed(e) => {
|
||||||
|
write!(f, "{}", e)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl From<SaslError> for Error {
|
||||||
|
fn from(e: SaslError) -> Error {
|
||||||
Error::SASL(e)
|
Error::SASL(e)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -10,7 +10,6 @@ use toml;
|
|||||||
|
|
||||||
use crate::error::Result;
|
use crate::error::Result;
|
||||||
use crate::config::Config;
|
use crate::config::Config;
|
||||||
use crate::access::Permissions;
|
|
||||||
|
|
||||||
use std::rc::Rc;
|
use std::rc::Rc;
|
||||||
use async_std::sync::{Arc, RwLock};
|
use async_std::sync::{Arc, RwLock};
|
||||||
@ -90,11 +89,10 @@ impl MachinesProvider {
|
|||||||
#[derive(Clone)]
|
#[derive(Clone)]
|
||||||
pub struct Machines {
|
pub struct Machines {
|
||||||
inner: Arc<RwLock<MachinesProvider>>,
|
inner: Arc<RwLock<MachinesProvider>>,
|
||||||
perm: Rc<Permissions>,
|
|
||||||
}
|
}
|
||||||
impl Machines {
|
impl Machines {
|
||||||
pub fn new(inner: Arc<RwLock<MachinesProvider>>, perm: Rc<Permissions>) -> Self {
|
pub fn new(inner: Arc<RwLock<MachinesProvider>>) -> Self {
|
||||||
Self { inner, perm }
|
Self { inner }
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -17,8 +17,6 @@ use signal_hook::iterator::Signals;
|
|||||||
|
|
||||||
use clap::{App, Arg};
|
use clap::{App, Arg};
|
||||||
|
|
||||||
use api::gen as api_capnp;
|
|
||||||
|
|
||||||
use futures::prelude::*;
|
use futures::prelude::*;
|
||||||
use futures::executor::{LocalPool, ThreadPool};
|
use futures::executor::{LocalPool, ThreadPool};
|
||||||
use futures::compat::Stream01CompatExt;
|
use futures::compat::Stream01CompatExt;
|
||||||
@ -40,6 +38,12 @@ use std::sync::Arc;
|
|||||||
|
|
||||||
use error::Error;
|
use error::Error;
|
||||||
|
|
||||||
|
// Re-Export generated capnp code.
|
||||||
|
// This is necessary because the Rust generator expects types to be found in the
|
||||||
|
// `crate::<file>_capnp` hierarchy.
|
||||||
|
use api::gen as api_capnp;
|
||||||
|
use auth::gen as auth_capnp;
|
||||||
|
|
||||||
// Returning a `Result` from `main` allows us to use the `?` shorthand.
|
// Returning a `Result` from `main` allows us to use the `?` shorthand.
|
||||||
// In the case of an Err it will be printed using `fmt::Debug`
|
// In the case of an Err it will be printed using `fmt::Debug`
|
||||||
fn main() -> Result<(), Error> {
|
fn main() -> Result<(), Error> {
|
||||||
|
Loading…
Reference in New Issue
Block a user