Skip to content

Commit

Permalink
feat: add enforce_ex api (#366)
Browse files Browse the repository at this point in the history
* feat: add enforce_explain api

* feat: rename enforce_explain to enforce_ex

* feat: add enforce_ex test case
  • Loading branch information
liulifox233 authored Feb 2, 2025
1 parent 43f856e commit 369d2e4
Show file tree
Hide file tree
Showing 4 changed files with 265 additions and 0 deletions.
26 changes: 26 additions & 0 deletions src/cached_enforcer.rs
Original file line number Diff line number Diff line change
Expand Up @@ -281,6 +281,32 @@ impl CoreApi for CachedEnforcer {
self.enforce(rvals)
}

#[cfg(feature = "explain")]
fn enforce_ex<ARGS: EnforceArgs>(
&self,
rvals: ARGS,
) -> Result<(bool, Vec<Vec<String>>)> {
let cache_key = rvals.cache_key();
let rvals = rvals.try_into_vec()?;
#[allow(unused_variables)]
let (authorized, cached, indices) =
self.private_enforce(&rvals, cache_key)?;

let rules = match indices {
Some(indices) => {
let all_rules = get_or_err!(self, "p", ModelError::P, "policy")
.get_policy();

indices
.into_iter()
.filter_map(|y| all_rules.iter().nth(y).cloned())
.collect::<Vec<_>>()
}
None => vec![],
};
Ok((authorized, rules))
}

#[inline]
fn build_role_links(&mut self) -> Result<()> {
self.enforcer.build_role_links()
Expand Down
7 changes: 7 additions & 0 deletions src/core_api.rs
Original file line number Diff line number Diff line change
Expand Up @@ -70,6 +70,13 @@ pub trait CoreApi: Send + Sync {
where
Self: Sized;
fn enforce_mut<ARGS: EnforceArgs>(&mut self, rvals: ARGS) -> Result<bool>
where
Self: Sized;
#[cfg(feature = "explain")]
fn enforce_ex<ARGS: EnforceArgs>(
&self,
rvals: ARGS,
) -> Result<(bool, Vec<Vec<String>>)>
where
Self: Sized;
fn build_role_links(&mut self) -> Result<()>;
Expand Down
2 changes: 2 additions & 0 deletions src/effector.rs
Original file line number Diff line number Diff line change
Expand Up @@ -108,6 +108,8 @@ impl EffectorStream for DefaultEffectStream {
self.res = eft == EffectKind::Allow;

self.done = true;

push_index_if_explain!(self)
}

if self.idx + 1 == self.cap {
Expand Down
230 changes: 230 additions & 0 deletions src/enforcer.rs
Original file line number Diff line number Diff line change
Expand Up @@ -669,6 +669,31 @@ impl CoreApi for Enforcer {
self.enforce(rvals)
}

#[cfg(feature = "explain")]
fn enforce_ex<ARGS: EnforceArgs>(
&self,
rvals: ARGS,
) -> Result<(bool, Vec<Vec<String>>)> {
let rvals = rvals.try_into_vec()?;
#[allow(unused_variables)]
let (authorized, indices) = self.private_enforce(&rvals)?;

let rules = match indices {
Some(indices) => {
let all_rules = get_or_err!(self, "p", ModelError::P, "policy")
.get_policy();

indices
.into_iter()
.filter_map(|y| all_rules.iter().nth(y).cloned())
.collect::<Vec<_>>()
}
None => vec![],
};

Ok((authorized, rules))
}

fn build_role_links(&mut self) -> Result<()> {
self.rm.write().clear();
self.model.build_role_links(Arc::clone(&self.rm))?;
Expand Down Expand Up @@ -1582,4 +1607,209 @@ mod tests {
true
);
}

#[cfg(feature = "explain")]
#[cfg(not(target_arch = "wasm32"))]
#[cfg_attr(
all(feature = "runtime-async-std", not(target_arch = "wasm32")),
async_std::test
)]
#[cfg_attr(
all(feature = "runtime-tokio", not(target_arch = "wasm32")),
tokio::test
)]
async fn test_enforce_ex() {
use crate::adapter;

let model = DefaultModel::from_file("examples/basic_model.conf")
.await
.unwrap();

let adapter = adapter::FileAdapter::new("examples/basic_policy.csv");

let e = Enforcer::new(model, adapter).await.unwrap();

assert_eq!(
e.enforce_ex(("alice", "data1", "read")).unwrap(),
(
true,
vec![vec![
"alice".to_string(),
"data1".to_string(),
"read".to_string()
]]
)
);
assert_eq!(
e.enforce_ex(("alice", "data1", "write")).unwrap(),
(false, vec![])
);
assert_eq!(
e.enforce_ex(("alice", "data2", "read")).unwrap(),
(false, vec![])
);
assert_eq!(
e.enforce_ex(("alice", "data2", "write")).unwrap(),
(false, vec![])
);
assert_eq!(
e.enforce_ex(("bob", "data1", "read")).unwrap(),
(false, vec![])
);
assert_eq!(
e.enforce_ex(("bob", "data1", "write")).unwrap(),
(false, vec![])
);
assert_eq!(
e.enforce_ex(("bob", "data2", "read")).unwrap(),
(false, vec![])
);
assert_eq!(
e.enforce_ex(("bob", "data2", "write")).unwrap(),
(
true,
vec![vec![
"bob".to_string(),
"data2".to_string(),
"write".to_string()
]]
)
);

let e = Enforcer::new(
"examples/rbac_model.conf",
"examples/rbac_policy.csv",
)
.await
.unwrap();

assert_eq!(
e.enforce_ex(("alice", "data1", "read")).unwrap(),
(
true,
vec![vec![
"alice".to_string(),
"data1".to_string(),
"read".to_string()
]]
)
);
assert_eq!(
e.enforce_ex(("alice", "data1", "write")).unwrap(),
(false, vec![])
);
assert_eq!(
e.enforce_ex(("alice", "data2", "read")).unwrap(),
(
true,
vec![vec![
"data2_admin".to_string(),
"data2".to_string(),
"read".to_string()
]]
)
);
assert_eq!(
e.enforce_ex(("alice", "data2", "write")).unwrap(),
(
true,
vec![vec![
"data2_admin".to_string(),
"data2".to_string(),
"write".to_string()
]]
)
);
assert_eq!(
e.enforce_ex(("bob", "data1", "read")).unwrap(),
(false, vec![])
);
assert_eq!(
e.enforce_ex(("bob", "data1", "write")).unwrap(),
(false, vec![])
);
assert_eq!(
e.enforce_ex(("bob", "data2", "read")).unwrap(),
(false, vec![])
);
assert_eq!(
e.enforce_ex(("bob", "data2", "write")).unwrap(),
(
true,
vec![vec![
"bob".to_string(),
"data2".to_string(),
"write".to_string()
]]
)
);

let e = Enforcer::new(
"examples/priority_model.conf",
"examples/priority_policy.csv",
)
.await
.unwrap();

assert_eq!(
e.enforce_ex(("alice", "data1", "read")).unwrap(),
(
true,
vec![vec![
"alice".to_string(),
"data1".to_string(),
"read".to_string(),
"allow".to_string()
]]
)
);
assert_eq!(
e.enforce_ex(("alice", "data1", "write")).unwrap(),
(
false,
vec![vec![
"data1_deny_group".to_string(),
"data1".to_string(),
"write".to_string(),
"deny".to_string()
]]
)
);
assert_eq!(
e.enforce_ex(("alice", "data2", "read")).unwrap(),
(false, vec![])
);
assert_eq!(
e.enforce_ex(("alice", "data2", "write")).unwrap(),
(false, vec![])
);
assert_eq!(
e.enforce_ex(("bob", "data1", "write")).unwrap(),
(false, vec![])
);
assert_eq!(
e.enforce_ex(("bob", "data2", "read")).unwrap(),
(
true,
vec![vec![
"data2_allow_group".to_string(),
"data2".to_string(),
"read".to_string(),
"allow".to_string()
]]
)
);
assert_eq!(
e.enforce_ex(("bob", "data2", "write")).unwrap(),
(
false,
vec![vec![
"bob".to_string(),
"data2".to_string(),
"write".to_string(),
"deny".to_string()
]]
)
);
}
}

0 comments on commit 369d2e4

Please sign in to comment.