Skip to content

Commit

Permalink
Merge pull request #30 from GopherJ/filtered-adapter
Browse files Browse the repository at this point in the history
Filtered adapter
  • Loading branch information
GopherJ authored Apr 18, 2020
2 parents 1ef3511 + c338379 commit ac1d2fd
Show file tree
Hide file tree
Showing 5 changed files with 135 additions and 5 deletions.
4 changes: 2 additions & 2 deletions Cargo.toml
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
[package]
name = "diesel-adapter"
version = "0.5.0"
version = "0.6.0"
authors = ["Cheng JIANG <[email protected]>"]
edition = "2018"
license = "Apache-2.0"
Expand All @@ -9,7 +9,7 @@ homepage="https://github.com/casbin-rs/diesel-adapter"
readme="README.md"

[dependencies]
casbin = { version = "0.5.1" }
casbin = { version = "0.6.0" }
diesel = { version = "1.4.4", features = ["r2d2"] }
async-trait = "0.1.30"

Expand Down
2 changes: 1 addition & 1 deletion examples/rbac_policy.csv
Original file line number Diff line number Diff line change
Expand Up @@ -2,4 +2,4 @@ p, alice, data1, read
p, bob, data2, write
p, data2_admin, data2, read
p, data2_admin, data2, write
g, alice, data2_admin
g, alice, data2_admin
14 changes: 14 additions & 0 deletions examples/rbac_with_domains_model.conf
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
[request_definition]
r = sub, dom, obj, act

[policy_definition]
p = sub, dom, obj, act

[role_definition]
g = _, _, _

[policy_effect]
e = some(where (p.eft == allow))

[matchers]
m = g(r.sub, p.sub, r.dom) && r.dom == p.dom && r.obj == p.obj && r.act == p.act
6 changes: 6 additions & 0 deletions examples/rbac_with_domains_policy.csv
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
p, admin,domain1,data1,read
p, admin,domain1,data1,write
p, admin,domain2,data2,read
p, admin,domain2,data2,write
g, alice,admin,domain1
g, bob,admin,domain2
114 changes: 112 additions & 2 deletions src/adapter.rs
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
use async_trait::async_trait;
use casbin::{error::AdapterError, Adapter, Error as CasbinError, Model, Result};
use casbin::{error::AdapterError, Adapter, Error as CasbinError, Filter, Model, Result};
use diesel::{
self,
r2d2::{ConnectionManager, Pool},
Expand All @@ -11,6 +11,7 @@ use std::time::Duration;

pub struct DieselAdapter {
pool: Pool<ConnectionManager<adapter::Connection>>,
is_filtered: bool,
}

pub const TABLE_NAME: &str = "casbin_rules";
Expand All @@ -27,7 +28,10 @@ impl<'a> DieselAdapter {
.get()
.map_err(|err| CasbinError::from(AdapterError(Box::new(Error::PoolError(err)))));

adapter::new(conn).map(|_| Self { pool })
adapter::new(conn).map(|_| Self {
pool,
is_filtered: false,
})
}

pub(crate) fn save_policy_line(
Expand Down Expand Up @@ -82,6 +86,39 @@ impl<'a> DieselAdapter {
None
}

pub(crate) fn load_filtered_policy_line(
&self,
casbin_rule: &CasbinRule,
f: &Filter,
) -> Option<Vec<String>> {
if let Some(sec) = casbin_rule.ptype.chars().next() {
if let Some(policy) = self.normalize_policy(casbin_rule) {
let mut is_filtered = false;
if sec == 'p' {
for (i, rule) in f.p.iter().enumerate() {
if !rule.is_empty() && rule != &policy[i] {
is_filtered = true
}
}
} else if sec == 'g' {
for (i, rule) in f.g.iter().enumerate() {
if !rule.is_empty() && rule != &policy[i] {
is_filtered = true
}
}
} else {
return None;
}

if !is_filtered {
return Some(policy);
}
}
}

None
}

fn normalize_policy(&self, casbin_rule: &CasbinRule) -> Option<Vec<String>> {
let mut result = vec![
&casbin_rule.v0,
Expand Down Expand Up @@ -135,6 +172,33 @@ impl Adapter for DieselAdapter {
Ok(())
}

async fn load_filtered_policy(&mut self, m: &mut dyn Model, f: Filter) -> Result<()> {
let conn = self
.pool
.get()
.map_err(|err| CasbinError::from(AdapterError(Box::new(Error::PoolError(err)))))?;

let rules = adapter::load_policy(conn)?;

for casbin_rule in &rules {
let rule = self.load_filtered_policy_line(casbin_rule, &f);

if let Some(rule) = rule {
if let Some(ref sec) = casbin_rule.ptype.chars().next().map(|x| x.to_string()) {
if let Some(t1) = m.get_mut_model().get_mut(sec) {
if let Some(t2) = t1.get_mut(&casbin_rule.ptype) {
t2.get_mut_policy().insert(rule);
}
}
}
} else {
self.is_filtered = true;
}
}

Ok(())
}

async fn save_policy(&mut self, m: &mut dyn Model) -> Result<()> {
let conn = self
.pool
Expand Down Expand Up @@ -241,6 +305,10 @@ impl Adapter for DieselAdapter {
Ok(false)
}
}

fn is_filtered(&self) -> bool {
self.is_filtered
}
}

#[cfg(test)]
Expand Down Expand Up @@ -411,5 +479,47 @@ mod tests {
)
.await
.is_ok());

// shadow the previous enforcer
let mut e = Enforcer::new(
"examples/rbac_with_domains_model.conf",
"examples/rbac_with_domains_policy.csv",
)
.await
.unwrap();

assert!(adapter.save_policy(e.get_mut_model()).await.is_ok());
e.set_adapter(adapter).await.unwrap();

let filter = Filter {
p: vec!["", "domain1"],
g: vec!["", "", "domain1"],
};

e.load_filtered_policy(filter).await.unwrap();
assert!(e
.enforce(&["alice", "domain1", "data1", "read"])
.await
.unwrap());
assert!(e
.enforce(&["alice", "domain1", "data1", "write"])
.await
.unwrap());
assert!(!e
.enforce(&["alice", "domain1", "data2", "read"])
.await
.unwrap());
assert!(!e
.enforce(&["alice", "domain1", "data2", "write"])
.await
.unwrap());
assert!(!e
.enforce(&["bob", "domain2", "data2", "read"])
.await
.unwrap());
assert!(!e
.enforce(&["bob", "domain2", "data2", "write"])
.await
.unwrap());
}
}

0 comments on commit ac1d2fd

Please sign in to comment.