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-jcasbin.git


The following commit(s) were added to refs/heads/master by this push:
     new a7903ab  feat: add getAllUsers/getAllNamedUsers API ported from Go
a7903ab is described below

commit a7903ab189bbf2b5c5c9afb3409158a6273b5726
Author: Yang Luo <[email protected]>
AuthorDate: Tue Jun 16 22:50:43 2026 +0800

    feat: add getAllUsers/getAllNamedUsers API ported from Go
---
 examples/basic_policy.csv                          |  2 +-
 .../casbin/jcasbin/main/ManagementEnforcer.java    | 24 +++++++++++++++
 .../org/casbin/jcasbin/main/SyncedEnforcer.java    | 23 ++++++++++++++
 src/main/java/org/casbin/jcasbin/util/Util.java    | 15 ++++++++++
 .../casbin/jcasbin/main/ManagementAPIUnitTest.java | 35 ++++++++++++++++++++++
 5 files changed, 98 insertions(+), 1 deletion(-)

diff --git a/examples/basic_policy.csv b/examples/basic_policy.csv
index 57aaa97..371911b 100644
--- a/examples/basic_policy.csv
+++ b/examples/basic_policy.csv
@@ -1,2 +1,2 @@
-p, alice, data1, read
+p, alice, data1, read
 p, bob, data2, write
\ No newline at end of file
diff --git a/src/main/java/org/casbin/jcasbin/main/ManagementEnforcer.java 
b/src/main/java/org/casbin/jcasbin/main/ManagementEnforcer.java
index 1a21dde..7f9b6f4 100644
--- a/src/main/java/org/casbin/jcasbin/main/ManagementEnforcer.java
+++ b/src/main/java/org/casbin/jcasbin/main/ManagementEnforcer.java
@@ -125,6 +125,30 @@ public class ManagementEnforcer extends InternalEnforcer {
         return model.getValuesForFieldInPolicy("g", ptype, 1);
     }
 
+    /**
+     * getAllUsers gets the list of users that show up in the current policy.
+     * Users are subjects that are not roles (i.e., subjects that do not appear
+     * as the second element in any grouping policy).
+     *
+     * @return all users in "p" policy rules, excluding roles defined in "g" 
rules.
+     */
+    public List<String> getAllUsers() {
+        return getAllNamedUsers("p");
+    }
+
+    /**
+     * getAllNamedUsers gets the list of users that show up in the named 
policy.
+     * Users are subjects that are not roles.
+     *
+     * @param ptype the policy type, e.g., "p", "p2".
+     * @return all users in the named policy, excluding roles defined in "g" 
rules.
+     */
+    public List<String> getAllNamedUsers(String ptype) {
+        List<String> subjects = getAllNamedSubjects(ptype);
+        List<String> roles = getAllRoles();
+        return Util.setSubtract(subjects, roles);
+    }
+
     /**
      * getPolicy gets all the authorization rules in the policy.
      *
diff --git a/src/main/java/org/casbin/jcasbin/main/SyncedEnforcer.java 
b/src/main/java/org/casbin/jcasbin/main/SyncedEnforcer.java
index c59871d..37aabe0 100644
--- a/src/main/java/org/casbin/jcasbin/main/SyncedEnforcer.java
+++ b/src/main/java/org/casbin/jcasbin/main/SyncedEnforcer.java
@@ -405,6 +405,29 @@ public class SyncedEnforcer extends Enforcer {
         return runSynchronized(() -> super.getAllNamedRoles(ptype), 
getReadWriteLock().readLock());
     }
 
+    /**
+     * getAllUsers gets the list of users that show up in the current policy.
+     * Users are subjects that are not roles.
+     *
+     * @return all users in "p" policy rules, excluding roles.
+     */
+    @Override
+    public List<String> getAllUsers() {
+        return runSynchronized(super::getAllUsers, 
getReadWriteLock().readLock());
+    }
+
+    /**
+     * getAllNamedUsers gets the list of users that show up in the named 
policy.
+     * Users are subjects that are not roles.
+     *
+     * @param ptype the policy type, e.g., "p", "p2".
+     * @return all users in the named policy, excluding roles.
+     */
+    @Override
+    public List<String> getAllNamedUsers(String ptype) {
+        return runSynchronized(() -> super.getAllNamedUsers(ptype), 
getReadWriteLock().readLock());
+    }
+
     /**
      * getPolicy gets all the authorization rules in the policy.
      *
diff --git a/src/main/java/org/casbin/jcasbin/util/Util.java 
b/src/main/java/org/casbin/jcasbin/util/Util.java
index 4912993..4f4efc3 100644
--- a/src/main/java/org/casbin/jcasbin/util/Util.java
+++ b/src/main/java/org/casbin/jcasbin/util/Util.java
@@ -388,4 +388,19 @@ public class Util {
             return false;
         }
     }
+
+    /**
+     * setSubtract returns the elements in {@code a} that aren't in {@code b}.
+     * Preserves order from {@code a}.
+     */
+    public static List<String> setSubtract(List<String> a, List<String> b) {
+        Set<String> bSet = new HashSet<>(b);
+        List<String> result = new ArrayList<>();
+        for (String item : a) {
+            if (!bSet.contains(item)) {
+                result.add(item);
+            }
+        }
+        return result;
+    }
 }
diff --git a/src/test/java/org/casbin/jcasbin/main/ManagementAPIUnitTest.java 
b/src/test/java/org/casbin/jcasbin/main/ManagementAPIUnitTest.java
index 54c0aad..a9f7708 100644
--- a/src/test/java/org/casbin/jcasbin/main/ManagementAPIUnitTest.java
+++ b/src/test/java/org/casbin/jcasbin/main/ManagementAPIUnitTest.java
@@ -16,6 +16,7 @@ package org.casbin.jcasbin.main;
 
 import com.googlecode.aviator.AviatorEvaluator;
 import com.googlecode.aviator.AviatorEvaluatorInstance;
+import org.casbin.jcasbin.util.Util;
 import org.testng.Assert;
 import org.testng.annotations.Test;
 
@@ -298,4 +299,38 @@ public class ManagementAPIUnitTest {
         assertEquals(enforcer.getAviatorEval(), instance);
     }
 
+    @Test
+    public void testGetAllUsers() {
+        // Basic RBAC: alice and bob are users, data2_admin is a role
+        Enforcer e = new Enforcer("examples/rbac_model.conf", 
"examples/rbac_policy.csv");
+        assertUserSet(e.getAllSubjects(), asList("alice", "bob", 
"data2_admin"));
+        assertUserSet(e.getAllRoles(), asList("data2_admin"));
+        assertUserSet(e.getAllUsers(), asList("alice", "bob"));
+
+        // Add a regular user who only appears in policy, not as a role target
+        e.addPolicy("eve", "data3", "read");
+        assertUserSet(e.getAllUsers(), asList("alice", "bob", "eve"));
+        e.removePolicy("eve", "data3", "read");
+
+        // A subject who is also a role target: admin is in p AND assigned to 
role "root" via g
+        // getAllUsers = subjects(p) - roles(g col 1); admin is not in g col 
1, so it is a user
+        e.addPolicy("admin", "data1", "read");
+        e.addGroupingPolicy("admin", "root");
+        assertUserSet(e.getAllUsers(), asList("alice", "bob", "admin"));
+        e.removePolicy("admin", "data1", "read");
+        e.removeGroupingPolicy("admin", "root");
+
+        // After clearing all policies, everything should be empty
+        e.clearPolicy();
+        assertUserSet(e.getAllSubjects(), asList());
+        assertUserSet(e.getAllRoles(), asList());
+        assertUserSet(e.getAllUsers(), asList());
+    }
+
+    private void assertUserSet(List<String> actual, List<String> expected) {
+        if (!Util.setEquals(expected, actual)) {
+            Assert.fail("Expected: " + expected + ", got: " + actual);
+        }
+    }
+
 }


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

Reply via email to