This is an automated email from the ASF dual-hosted git repository.

tisonkun pushed a commit to branch fix/conditional-role-matching
in repository https://gitbox.apache.org/repos/asf/casbin-jcasbin.git

commit e4356b7083e6cdfa3f40377ff02a102ad80b3ecb
Author: tison <[email protected]>
AuthorDate: Mon Oct 26 13:58:08 2026 +0800

    fix: preserve conditional roles when registering name matching
---
 .../java/org/casbin/jcasbin/main/CoreEnforcer.java | 17 ++++----
 .../jcasbin/rbac/ConditionalRoleManager.java       | 21 +++++++---
 src/main/java/org/casbin/jcasbin/rbac/Role.java    | 14 ++-----
 .../org/casbin/jcasbin/main/ModelUnitTest.java     | 47 ++++++++++++++++++++++
 .../casbin/jcasbin/main/RoleManagerUnitTest.java   | 17 ++++++++
 5 files changed, 91 insertions(+), 25 deletions(-)

diff --git a/src/main/java/org/casbin/jcasbin/main/CoreEnforcer.java 
b/src/main/java/org/casbin/jcasbin/main/CoreEnforcer.java
index b1b16f5..119c628 100644
--- a/src/main/java/org/casbin/jcasbin/main/CoreEnforcer.java
+++ b/src/main/java/org/casbin/jcasbin/main/CoreEnforcer.java
@@ -835,16 +835,15 @@ public class CoreEnforcer {
      * @return whether the matching function was successfully added.
      */
     public boolean addNamedMatchingFunc(String ptype, String name, 
BiPredicate<String, String> fn) {
-        if (rmMap.containsKey(ptype)) {
-            DomainManager rm = (DomainManager) rmMap.get(ptype);
-            rm.addMatchingFunc(name, fn);
-//            clearRmMap();
-//            if (autoBuildRoleLinks) {
-//                buildRoleLinks();
-//            }
-            return true;
+        RoleManager rm = rmMap.get(ptype);
+        if (rm instanceof DomainManager) {
+            ((DomainManager) rm).addMatchingFunc(name, fn);
+        } else if (rm instanceof DefaultRoleManager) {
+            ((DefaultRoleManager) rm).addMatchingFunc(name, fn);
+        } else {
+            return false;
         }
-        return false;
+        return true;
     }
 
     /**
diff --git a/src/main/java/org/casbin/jcasbin/rbac/ConditionalRoleManager.java 
b/src/main/java/org/casbin/jcasbin/rbac/ConditionalRoleManager.java
index 6ab5dc3..d9fd671 100644
--- a/src/main/java/org/casbin/jcasbin/rbac/ConditionalRoleManager.java
+++ b/src/main/java/org/casbin/jcasbin/rbac/ConditionalRoleManager.java
@@ -34,12 +34,23 @@ public class ConditionalRoleManager extends 
DefaultRoleManager{
         this.domainMatchingFunc = domainMatchingFunc;
     }
 
+    @Override
+    public void addMatchingFunc(String name, BiPredicate<String, String> 
matchingFunc) {
+        Collection<Role> roles = this.allRoles.values();
+        this.matchingFunc = matchingFunc;
+        clear();
+        copyRoles(roles);
+    }
+
     void copyFrom(ConditionalRoleManager other) {
-        other.allRoles.values().forEach(user -> {
-            user.roles.keySet().forEach(roleName -> {
-                addLink(user.getName(), roleName);
-                getRole(user.getName()).copyLinkConditions(user, roleName);
-            });
+        copyRoles(other.allRoles.values());
+    }
+
+    private void copyRoles(Collection<Role> roles) {
+        roles.forEach(user -> {
+            user.roles.keySet().forEach(roleName -> addLink(user.getName(), 
roleName));
+            // Conditions can be registered before their links are added.
+            getRole(user.getName()).copyLinkConditions(user);
         });
     }
 
diff --git a/src/main/java/org/casbin/jcasbin/rbac/Role.java 
b/src/main/java/org/casbin/jcasbin/rbac/Role.java
index 9353dc2..065b138 100644
--- a/src/main/java/org/casbin/jcasbin/rbac/Role.java
+++ b/src/main/java/org/casbin/jcasbin/rbac/Role.java
@@ -173,17 +173,9 @@ class Role {
         return linkConditionFuncMap;
     }
 
-    void copyLinkConditions(Role other, String roleName) {
-        other.linkConditionFuncMap.forEach((key, fn) -> {
-            if (key.getRoleName().equals(roleName)) {
-                linkConditionFuncMap.put(key, fn);
-            }
-        });
-        other.linkConditionFuncParamsMap.forEach((key, params) -> {
-            if (key.getRoleName().equals(roleName)) {
-                linkConditionFuncParamsMap.put(key, params);
-            }
-        });
+    void copyLinkConditions(Role other) {
+        linkConditionFuncMap.putAll(other.linkConditionFuncMap);
+        linkConditionFuncParamsMap.putAll(other.linkConditionFuncParamsMap);
     }
 
     void setLinkConditionFuncParams(Role role, String domain, String... 
params){
diff --git a/src/test/java/org/casbin/jcasbin/main/ModelUnitTest.java 
b/src/test/java/org/casbin/jcasbin/main/ModelUnitTest.java
index 919a96b..5f75594 100644
--- a/src/test/java/org/casbin/jcasbin/main/ModelUnitTest.java
+++ b/src/test/java/org/casbin/jcasbin/main/ModelUnitTest.java
@@ -278,6 +278,53 @@ public class ModelUnitTest {
         assertFalse(e.enforce("alice", "tenantB", "data", "read"));
     }
 
+    @DataProvider(name = "conditionalRoleMatching")
+    public Object[][] conditionalRoleMatching() {
+        return new Object[][] {{"g", false}, {"g2", false}, {"g", true}, 
{"g2", true}};
+    }
+
+    @Test(dataProvider = "conditionalRoleMatching")
+    public void testNamedRoleMatchingPreservesConditions(String ptype, boolean 
withDomain) {
+        Model m = new Model();
+        m.addDef("r", "r", "sub, dom, obj, act");
+        m.addDef("p", "p", "sub, dom, obj, act");
+        m.addDef("g", ptype, withDomain ? "_, _, _, (_, _)" : "_, _, (_, _)");
+        m.addDef("e", "e", "some(where (p.eft == allow))");
+        m.addDef("m", "m", ptype + (withDomain ? "(r.sub, p.sub, r.dom)" : 
"(r.sub, p.sub)")
+            + " && r.dom == p.dom && r.obj == p.obj && r.act == p.act");
+        Enforcer e = new Enforcer(m);
+        e.addPolicy("admin", "tenantA", "data", "read");
+        if (withDomain) {
+            e.addNamedGroupingPolicy(ptype, "alice", "admin", "tenantA", 
"deny", "_");
+            e.addNamedGroupingPolicy(ptype, "bob*", "admin", "tenantA", "_", 
"_");
+            e.addNamedDomainLinkConditionFunc(ptype, "alice", "admin", 
"tenantA", params -> "allow".equals(params[0]));
+            e.setNamedDomainLinkConditionFuncParams(ptype, "alice", "admin", 
"tenantA", "deny", "_");
+        } else {
+            e.addNamedGroupingPolicy(ptype, "alice", "admin", "deny", "_");
+            e.addNamedGroupingPolicy(ptype, "bob*", "admin", "_", "_");
+            e.addNamedLinkConditionFunc(ptype, "alice", "admin", params -> 
"allow".equals(params[0]));
+            e.setNamedLinkConditionFuncParams(ptype, "alice", "admin", "deny", 
"_");
+        }
+        assertFalse(e.enforce("alice", "tenantA", "data", "read"));
+        assertFalse(e.enforce("bob1", "tenantA", "data", "read"));
+
+        assertTrue(e.addNamedMatchingFunc(ptype, "keyMatch", 
BuiltInFunctions::keyMatch));
+        assertFalse(e.enforce("alice", "tenantA", "data", "read"));
+        assertTrue(e.enforce("bob1", "tenantA", "data", "read"));
+        assertTrue(e.addNamedMatchingFunc(ptype, "keyMatch", 
BuiltInFunctions::keyMatch));
+        assertFalse(e.enforce("alice", "tenantA", "data", "read"));
+
+        if (withDomain) {
+            e.setNamedDomainLinkConditionFuncParams(ptype, "alice", "admin", 
"tenantA", "allow", "_");
+        } else {
+            e.setNamedLinkConditionFuncParams(ptype, "alice", "admin", 
"allow", "_");
+        }
+        assertTrue(e.enforce("alice", "tenantA", "data", "read"));
+        assertTrue(e.addNamedMatchingFunc(ptype, "exact", String::equals));
+        assertTrue(e.enforce("alice", "tenantA", "data", "read"));
+        assertFalse(e.enforce("bob1", "tenantA", "data", "read"));
+    }
+
     @Test
     public void testRBACModelWithDomainsAtRuntime() {
         Enforcer e = new Enforcer("examples/rbac_with_domains_model.conf");
diff --git a/src/test/java/org/casbin/jcasbin/main/RoleManagerUnitTest.java 
b/src/test/java/org/casbin/jcasbin/main/RoleManagerUnitTest.java
index 51809eb..ab97293 100644
--- a/src/test/java/org/casbin/jcasbin/main/RoleManagerUnitTest.java
+++ b/src/test/java/org/casbin/jcasbin/main/RoleManagerUnitTest.java
@@ -18,6 +18,7 @@
 package org.casbin.jcasbin.main;
 
 import org.casbin.jcasbin.rbac.DefaultRoleManager;
+import org.casbin.jcasbin.rbac.ConditionalRoleManager;
 import org.casbin.jcasbin.rbac.DomainManager;
 import org.casbin.jcasbin.rbac.RoleManager;
 import org.casbin.jcasbin.util.BuiltInFunctions;
@@ -30,6 +31,22 @@ import java.util.Collections;
  * @author Yixiang Zhao (@seriouszyx)
  **/
 public class RoleManagerUnitTest {
+    @Test
+    public void testMatchingPreservesConditionsRegisteredBeforeLinks() {
+        ConditionalRoleManager rm = new ConditionalRoleManager(10);
+        rm.addLinkConditionFunc("alice", "admin", params -> 
"allow".equals(params[0]));
+        rm.setLinkConditionFuncParams("alice", "admin", "deny");
+        rm.addMatchingFunc("keyMatch", BuiltInFunctions::keyMatch);
+        rm.addLink("alice", "admin");
+        TestUtil.testHasRole(rm, "alice", "admin", false);
+
+        rm.setLinkConditionFuncParams("alice", "admin", "allow");
+        TestUtil.testHasRole(rm, "alice", "admin", true);
+        rm.addMatchingFunc("exact", String::equals);
+        rm.setLinkConditionFuncParams("alice", "admin", "deny");
+        TestUtil.testHasRole(rm, "alice", "admin", false);
+    }
+
     @Test
     public void testRole() {
         RoleManager rm = new DefaultRoleManager(3);


---------------------------------------------------------------------
To unsubscribe, e-mail: [email protected]
For additional commands, e-mail: [email protected]

Reply via email to