This is an automated email from the ASF dual-hosted git repository.
hsluoyz pushed a commit to branch master
in repository https://gitbox.apache.org/repos/asf/casbin-rs.git
The following commit(s) were added to refs/heads/master by this push:
new a6318a5 fix: stop empty policy sets from failing open
a6318a5 is described below
commit a6318a54c163673c02a4445548a19e135c68fb3a
Author: Yang Luo <[email protected]>
AuthorDate: Fri Oct 9 22:07:25 2026 +0800
fix: stop empty policy sets from failing open
---
src/adapter/string_adapter.rs | 70 ++++++++++++++++++++++++++++++-------------
src/enforcer.rs | 14 ++++++---
src/model/default_model.rs | 69 ++++++++++++++++++++++++++++++++++++++++++
3 files changed, 129 insertions(+), 24 deletions(-)
diff --git a/src/adapter/string_adapter.rs b/src/adapter/string_adapter.rs
index 4287fcd..168459a 100644
--- a/src/adapter/string_adapter.rs
+++ b/src/adapter/string_adapter.rs
@@ -77,30 +77,27 @@ impl Adapter for StringAdapter {
m: &mut dyn Model,
f: Filter<'a>,
) -> Result<()> {
+ self.is_filtered = false;
let policies = self.policy.split("\n");
for line in policies {
if let Some(tokens) = parse_csv_line(line) {
- let sec = &tokens[0];
- let ptype = &tokens[1];
- let rule = tokens[1..].to_vec().clone();
- let mut is_filtered = false;
-
- if sec == "p" {
- for (i, r) in f.p.iter().enumerate() {
- if !r.is_empty() && r != &rule[i + 1] {
- is_filtered = true;
- }
- }
- }
- if sec == "g" {
- for (i, r) in f.g.iter().enumerate() {
- if !r.is_empty() && r != &rule[i + 1] {
- is_filtered = true;
- }
- }
- }
+ let ptype = &tokens[0];
+ let sec = match ptype.chars().next() {
+ Some(c) => c.to_string(),
+ None => continue,
+ };
+ let rule = tokens[1..].to_vec();
+ let filter = match sec.as_str() {
+ "p" => &f.p,
+ "g" => &f.g,
+ _ => continue,
+ };
+ let is_filtered = filter.iter().enumerate().any(|(i, r)| {
+ !r.is_empty() && rule.get(i).map(String::as_str) !=
Some(*r)
+ });
+
if !is_filtered {
- if let Some(ast_map) = m.get_mut_model().get_mut(sec) {
+ if let Some(ast_map) = m.get_mut_model().get_mut(&sec) {
if let Some(ast) = ast_map.get_mut(ptype) {
ast.get_mut_policy().insert(rule);
}
@@ -346,4 +343,37 @@ mod tests {
assert!(adapter.is_filtered());
}
+
+ #[cfg_attr(
+ all(not(target_arch = "wasm32"), feature = "runtime-async-std"),
+ async_std::test
+ )]
+ #[cfg_attr(
+ all(not(target_arch = "wasm32"), feature = "runtime-tokio"),
+ tokio::test
+ )]
+ #[cfg_attr(target_arch = "wasm32", wasm_bindgen_test)]
+ async fn test_load_filtered_policy() {
+ let policy = "p, alice, data1, read\np, bob, data2, write";
+ let mut adapter = StringAdapter::new(policy);
+ let mut model = DefaultModel::from_str(include_str!(
+ "../../examples/rbac_model.conf"
+ ))
+ .await
+ .unwrap();
+
+ let filter = Filter {
+ p: vec!["alice"],
+ g: vec![],
+ };
+
+ adapter
+ .load_filtered_policy(&mut model, filter)
+ .await
+ .unwrap();
+ let enforcer = Enforcer::new(model, adapter).await.unwrap();
+
+ assert!(enforcer.enforce(("alice", "data1", "read")).unwrap());
+ assert!(!enforcer.enforce(("bob", "data2", "write")).unwrap());
+ }
}
diff --git a/src/enforcer.rs b/src/enforcer.rs
index 40efb5e..b4f8afd 100644
--- a/src/enforcer.rs
+++ b/src/enforcer.rs
@@ -168,13 +168,16 @@ impl Enforcer {
};
if policy_len == 0 {
+ // No policy rows: bind policy tokens to unit so that only the
+ // parts of the matcher that do not depend on a policy can allow.
for token in p_ast.tokens.iter() {
- scope.push_constant(token, String::new());
+ scope.push_constant(token, ());
}
let eval_result = self
.engine
- .eval_ast_with_scope::<bool>(&mut scope, m_ast_compiled)?;
+ .eval_ast_with_scope::<bool>(&mut scope, m_ast_compiled)
+ .unwrap_or(false);
let eft = if eval_result {
EffectKind::Allow
} else {
@@ -313,13 +316,16 @@ impl Enforcer {
};
if policy_len == 0 {
+ // No policy rows: bind policy tokens to unit so that only the
+ // parts of the matcher that do not depend on a policy can allow.
for token in p_ast.tokens.iter() {
- scope.push_constant(token, String::new());
+ scope.push_constant(token, ());
}
let eval_result = self
.engine
- .eval_ast_with_scope::<bool>(&mut scope, m_ast_compiled)?;
+ .eval_ast_with_scope::<bool>(&mut scope, m_ast_compiled)
+ .unwrap_or(false);
let eft = if eval_result {
EffectKind::Allow
} else {
diff --git a/src/model/default_model.rs b/src/model/default_model.rs
index 90dfb06..166d526 100644
--- a/src/model/default_model.rs
+++ b/src/model/default_model.rs
@@ -554,6 +554,75 @@ mod tests {
assert!(!e.enforce(("bob", "data2", "write")).unwrap());
}
+ #[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_no_policy_does_not_match_empty_values() {
+ let m = DefaultModel::from_str(
+ r#"
+[request_definition]
+r = sub, obj, act
+
+[policy_definition]
+p = sub, obj, act
+
+[policy_effect]
+e = some(where (p.eft == allow))
+
+[matchers]
+m = r.sub == p.sub && r.obj == p.obj && regexMatch(r.act, p.act)
+"#,
+ )
+ .await
+ .unwrap();
+
+ let adapter = MemoryAdapter::default();
+ let e = Enforcer::new(m, adapter).await.unwrap();
+
+ assert!(!e.enforce(("", "", "")).unwrap());
+ assert!(!e.enforce(("", "", "DELETE")).unwrap());
+ }
+
+ #[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_no_policy_function_on_policy_value() {
+ let m = DefaultModel::from_str(
+ r#"
+[request_definition]
+r = sub, obj, act
+
+[policy_definition]
+p = sub, obj, act
+
+[policy_effect]
+e = some(where (p.eft == allow))
+
+[matchers]
+m = regexMatch(r.act, p.act) && r.sub == p.sub && r.obj == p.obj
+"#,
+ )
+ .await
+ .unwrap();
+
+ let adapter = MemoryAdapter::default();
+ let e = Enforcer::new(m, adapter).await.unwrap();
+
+ assert!(!e.enforce(("", "", "DELETE")).unwrap());
+ }
+
#[cfg(not(target_arch = "wasm32"))]
#[cfg_attr(
all(feature = "runtime-async-std", not(target_arch = "wasm32")),
---------------------------------------------------------------------
To unsubscribe, e-mail: [email protected]
For additional commands, e-mail: [email protected]