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 7b569fa fix: isolate role managers per grouping type
7b569fa is described below
commit 7b569fa588ae3d97240f5c0b8dcd6debb2e40324
Author: Yang Luo <[email protected]>
AuthorDate: Fri Oct 9 20:52:14 2026 +0800
fix: isolate role managers per grouping type
---
src/cached_enforcer.rs | 17 +++++++
src/core_api.rs | 9 ++++
src/enforcer.rs | 113 +++++++++++++++++++++++++++++++++++++++++----
src/macros.rs | 2 +-
src/model/default_model.rs | 27 ++++++-----
src/model/mod.rs | 4 +-
src/rbac_api.rs | 16 +++----
7 files changed, 155 insertions(+), 33 deletions(-)
diff --git a/src/cached_enforcer.rs b/src/cached_enforcer.rs
index 69454bd..a97d9e9 100644
--- a/src/cached_enforcer.rs
+++ b/src/cached_enforcer.rs
@@ -177,6 +177,23 @@ impl CoreApi for CachedEnforcer {
self.enforcer.set_role_manager(rm)
}
+ #[inline]
+ fn get_named_role_manager(
+ &self,
+ ptype: &str,
+ ) -> Option<Arc<RwLock<dyn RoleManager>>> {
+ self.enforcer.get_named_role_manager(ptype)
+ }
+
+ #[inline]
+ fn set_named_role_manager(
+ &mut self,
+ ptype: &str,
+ rm: Arc<RwLock<dyn RoleManager>>,
+ ) -> Result<()> {
+ self.enforcer.set_named_role_manager(ptype, rm)
+ }
+
#[inline]
async fn set_model<M: TryIntoModel>(&mut self, m: M) -> Result<()> {
self.enforcer.set_model(m).await
diff --git a/src/core_api.rs b/src/core_api.rs
index 98961f8..54dae8a 100644
--- a/src/core_api.rs
+++ b/src/core_api.rs
@@ -48,6 +48,15 @@ pub trait CoreApi: Send + Sync {
&mut self,
rm: Arc<RwLock<dyn RoleManager>>,
) -> Result<()>;
+ fn get_named_role_manager(
+ &self,
+ ptype: &str,
+ ) -> Option<Arc<RwLock<dyn RoleManager>>>;
+ fn set_named_role_manager(
+ &mut self,
+ ptype: &str,
+ rm: Arc<RwLock<dyn RoleManager>>,
+ ) -> Result<()>;
#[cfg(feature = "logging")]
fn get_logger(&self) -> &dyn Logger;
#[cfg(feature = "logging")]
diff --git a/src/enforcer.rs b/src/enforcer.rs
index fa58d50..40efb5e 100644
--- a/src/enforcer.rs
+++ b/src/enforcer.rs
@@ -62,7 +62,7 @@ pub struct Enforcer {
adapter: Box<dyn Adapter>,
fm: FunctionMap,
eft: Box<dyn Effector>,
- rm: Arc<RwLock<dyn RoleManager>>,
+ rm_map: HashMap<String, Arc<RwLock<dyn RoleManager>>>,
enabled: bool,
auto_save: bool,
auto_build_role_links: bool,
@@ -406,7 +406,21 @@ impl Enforcer {
}
}
+ fn init_rm_map(&mut self) {
+ self.rm_map.entry("g".to_owned()).or_insert_with(|| {
+ Arc::new(RwLock::new(DefaultRoleManager::new(10)))
+ });
+ if let Some(ast_map) = self.model.get_model().get("g") {
+ for ptype in ast_map.keys() {
+ self.rm_map.entry(ptype.to_owned()).or_insert_with(|| {
+ Arc::new(RwLock::new(DefaultRoleManager::new(10)))
+ });
+ }
+ }
+ }
+
pub(crate) fn register_g_functions(&mut self) -> Result<()> {
+ self.init_rm_map();
if let Some(ast_map) = self.model.get_model().get("g") {
for (fname, ast) in ast_map {
register_g_function!(self, fname, ast);
@@ -428,7 +442,6 @@ impl CoreApi for Enforcer {
let adapter = a.try_into_adapter().await?;
let fm = FunctionMap::default();
let eft = Box::new(DefaultEffector);
- let rm = Arc::new(RwLock::new(DefaultRoleManager::new(10)));
let mut engine = Engine::new_raw();
@@ -443,7 +456,7 @@ impl CoreApi for Enforcer {
adapter,
fm,
eft,
- rm,
+ rm_map: HashMap::new(),
enabled: true,
auto_save: true,
auto_build_role_links: true,
@@ -552,7 +565,7 @@ impl CoreApi for Enforcer {
#[inline]
fn get_role_manager(&self) -> Arc<RwLock<dyn RoleManager>> {
- Arc::clone(&self.rm)
+ Arc::clone(&self.rm_map["g"])
}
#[inline]
@@ -560,7 +573,23 @@ impl CoreApi for Enforcer {
&mut self,
rm: Arc<RwLock<dyn RoleManager>>,
) -> Result<()> {
- self.rm = rm;
+ self.set_named_role_manager("g", rm)
+ }
+
+ #[inline]
+ fn get_named_role_manager(
+ &self,
+ ptype: &str,
+ ) -> Option<Arc<RwLock<dyn RoleManager>>> {
+ self.rm_map.get(ptype).map(Arc::clone)
+ }
+
+ fn set_named_role_manager(
+ &mut self,
+ ptype: &str,
+ rm: Arc<RwLock<dyn RoleManager>>,
+ ) -> Result<()> {
+ self.rm_map.insert(ptype.to_owned(), rm);
if self.auto_build_role_links {
self.build_role_links()?;
}
@@ -578,6 +607,7 @@ impl CoreApi for Enforcer {
default_model.compile_matchers(&self.engine)?;
}
+ self.register_g_functions()?;
self.load_policy().await?;
Ok(())
}
@@ -748,16 +778,17 @@ impl CoreApi for Enforcer {
}
fn build_role_links(&mut self) -> Result<()> {
- self.rm.write().clear();
- self.model.build_role_links(Arc::clone(&self.rm))?;
+ for rm in self.rm_map.values() {
+ rm.write().clear();
+ }
+ self.model.build_role_links(&self.rm_map)?;
Ok(())
}
#[cfg(feature = "incremental")]
fn build_incremental_role_links(&mut self, d: EventData) -> Result<()> {
- self.model
- .build_incremental_role_links(Arc::clone(&self.rm), d)?;
+ self.model.build_incremental_role_links(&self.rm_map, d)?;
Ok(())
}
@@ -1496,6 +1527,70 @@ mod tests {
assert!(!e.enforce(("bob", "domain2", "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_grouping_role_managers_are_isolated() {
+ use crate::RbacApi;
+
+ let m = DefaultModel::from_str(
+ r#"
+[request_definition]
+r = sub, obj, act
+
+[policy_definition]
+p = sub, obj, act
+
+[role_definition]
+g = _, _
+g2 = _, _
+
+[policy_effect]
+e = some(where (p.eft == allow))
+
+[matchers]
+m = g(r.sub, p.sub) && g2(r.obj, p.obj) && r.act == p.act
+"#,
+ )
+ .await
+ .unwrap();
+ let adapter = StringAdapter::new(
+ r#"
+p, admin, data_group, write
+g, alice, admin
+g2, report1, data_group
+g2, eve, admin
+"#,
+ );
+ let mut e = Enforcer::new(m, adapter).await.unwrap();
+ e.enable_auto_save(false);
+
+ assert!(e.enforce(("alice", "report1", "write")).unwrap());
+ assert!(!e.enforce(("eve", "data_group", "write")).unwrap());
+ assert!(!e.has_role_for_user("eve", "admin", None));
+
+ e.add_named_grouping_policy(
+ "g2",
+ vec!["mallory".to_owned(), "admin".to_owned()],
+ )
+ .await
+ .unwrap();
+
+ assert!(!e.enforce(("mallory", "data_group", "write")).unwrap());
+ assert!(!e.has_role_for_user("mallory", "admin", None));
+ assert!(e
+ .get_named_role_manager("g2")
+ .unwrap()
+ .read()
+ .has_link("mallory", "admin", None));
+ }
+
#[cfg(not(target_arch = "wasm32"))]
#[cfg_attr(
all(feature = "runtime-async-std", not(target_arch = "wasm32")),
diff --git a/src/macros.rs b/src/macros.rs
index 712763a..8721655 100644
--- a/src/macros.rs
+++ b/src/macros.rs
@@ -47,7 +47,7 @@ macro_rules! get_or_err_with_context {
#[macro_export]
macro_rules! register_g_function {
($enforcer:ident, $fname:ident, $ast:ident) => {{
- let rm = Arc::clone(&$enforcer.rm);
+ let rm = Arc::clone(&$enforcer.rm_map[$fname]);
let count = $ast.value.matches('_').count();
if count == 2 {
diff --git a/src/model/default_model.rs b/src/model/default_model.rs
index afcc6d6..90dfb06 100644
--- a/src/model/default_model.rs
+++ b/src/model/default_model.rs
@@ -194,11 +194,13 @@ impl Model for DefaultModel {
fn build_role_links(
&mut self,
- rm: Arc<RwLock<dyn RoleManager>>,
+ rm_map: &HashMap<String, Arc<RwLock<dyn RoleManager>>>,
) -> Result<()> {
if let Some(asts) = self.model.get_mut("g") {
- for ast in asts.values_mut() {
- ast.build_role_links(Arc::clone(&rm))?;
+ for (ptype, ast) in asts.iter_mut() {
+ if let Some(rm) = rm_map.get(ptype) {
+ ast.build_role_links(Arc::clone(rm))?;
+ }
}
}
Ok(())
@@ -207,10 +209,10 @@ impl Model for DefaultModel {
#[cfg(feature = "incremental")]
fn build_incremental_role_links(
&mut self,
- rm: Arc<RwLock<dyn RoleManager>>,
+ rm_map: &HashMap<String, Arc<RwLock<dyn RoleManager>>>,
d: EventData,
) -> Result<()> {
- let ast = match d {
+ let (ast, rm) = match d {
EventData::AddPolicy(ref sec, ref ptype, _)
| EventData::AddPolicies(ref sec, ref ptype, _)
| EventData::RemovePolicy(ref sec, ref ptype, _)
@@ -218,15 +220,18 @@ impl Model for DefaultModel {
| EventData::RemoveFilteredPolicy(ref sec, ref ptype, _)
if sec == "g" =>
{
- self.model
- .get_mut(sec)
- .and_then(|ast_map| ast_map.get_mut(ptype))
+ (
+ self.model
+ .get_mut(sec)
+ .and_then(|ast_map| ast_map.get_mut(ptype)),
+ rm_map.get(ptype),
+ )
}
- _ => None,
+ _ => (None, None),
};
- if let Some(ast) = ast {
- ast.build_incremental_role_links(rm, d)?;
+ if let (Some(ast), Some(rm)) = (ast, rm) {
+ ast.build_incremental_role_links(Arc::clone(rm), d)?;
}
Ok(())
diff --git a/src/model/mod.rs b/src/model/mod.rs
index bc32b8b..42f4b55 100644
--- a/src/model/mod.rs
+++ b/src/model/mod.rs
@@ -21,12 +21,12 @@ pub trait Model: Send + Sync {
fn get_mut_model(&mut self) -> &mut HashMap<String, AssertionMap>;
fn build_role_links(
&mut self,
- rm: Arc<RwLock<dyn RoleManager>>,
+ rm_map: &HashMap<String, Arc<RwLock<dyn RoleManager>>>,
) -> Result<()>;
#[cfg(feature = "incremental")]
fn build_incremental_role_links(
&mut self,
- rm: Arc<RwLock<dyn RoleManager>>,
+ rm_map: &HashMap<String, Arc<RwLock<dyn RoleManager>>>,
d: EventData,
) -> Result<()>;
fn add_policy(&mut self, sec: &str, ptype: &str, rule: Vec<String>)
diff --git a/src/rbac_api.rs b/src/rbac_api.rs
index 115631c..7feecba 100644
--- a/src/rbac_api.rs
+++ b/src/rbac_api.rs
@@ -1084,7 +1084,8 @@ mod tests {
use crate::model::key_match2;
- e.get_role_manager()
+ e.get_named_role_manager("g2")
+ .unwrap()
.write()
.matching_fn(Some(key_match2), None);
@@ -1099,15 +1100,10 @@ mod tests {
assert!(e.enforce(("bob", "/pen/1", "GET")).unwrap());
assert!(e.enforce(("bob", "/pen/2", "GET")).unwrap());
- assert_eq!(
- vec!["book_group"],
- sort_unstable(e.get_implicit_roles_for_user("/book/1", None))
- );
-
- assert_eq!(
- vec!["pen_group"],
- sort_unstable(e.get_implicit_roles_for_user("/pen/1", None))
- );
+ let rm = e.get_named_role_manager("g2").unwrap();
+ assert_eq!(vec!["book_group"], rm.read().get_roles("/book/1", None));
+ assert_eq!(vec!["pen_group"], rm.read().get_roles("/pen/1", None));
+ assert!(e.get_implicit_roles_for_user("/book/1", None).is_empty());
}
#[cfg(not(target_arch = "wasm32"))]
---------------------------------------------------------------------
To unsubscribe, e-mail: [email protected]
For additional commands, e-mail: [email protected]