Skip to content

Commit

Permalink
feat: Implement subject Priority in jcasbin (#306)
Browse files Browse the repository at this point in the history
Co-Authored-By: imp2002 <[email protected]>

Co-authored-by: imp2002 <[email protected]>
  • Loading branch information
Xhy-5000 and imp2002 authored Oct 22, 2022
1 parent bdf2a6c commit c61f3e4
Show file tree
Hide file tree
Showing 9 changed files with 150 additions and 1 deletion.
14 changes: 14 additions & 0 deletions examples/priority_hierachy_policy.conf
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
[request_definition]
r = sub, obj, act

[policy_definition]
p = sub, obj, act, eft

[role_definition]
g = _, _

[policy_effect]
e = subjectPriority(p.eft) || deny

[matchers]
m = g(r.sub, p.sub) && r.obj == p.obj && r.act == p.act
16 changes: 16 additions & 0 deletions examples/priority_hierachy_policy.csv
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
p, root, data1, read, deny
p, admin, data1, read, deny

p, editor, data1, read, deny
p, subscriber, data1, read, deny

p, jane, data1, read, allow
p, alice, data1, read, allow

g, admin, root

g, editor, admin
g, subscriber, admin

g, jane, editor
g, alice, subscriber
14 changes: 14 additions & 0 deletions examples/subject_priority_model_with_domain.conf
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
[request_definition]
r = sub, dom, obj, act

[policy_definition]
p = sub, dom, obj, act, eft

[role_definition]
g = _, _, _

[policy_effect]
e = subjectPriority(p.eft) || deny

[matchers]
m = g(r.sub, p.sub, r.dom) && r.dom == p.dom && r.obj == p.obj && r.act == p.act
7 changes: 7 additions & 0 deletions examples/subject_priority_policy_with_domain.csv
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
p, admin, domain1, data1, write, deny
p, alice, domain1, data1, write, allow
p, admin, domain2, data2, write, deny
p, bob, domain2, data2, write, allow

g, alice, admin, domain1
g, bob, admin, domain2
Original file line number Diff line number Diff line change
Expand Up @@ -56,7 +56,7 @@ public boolean mergeEffects(String expr, Effect[] effects, float[] results) {
break;
}
}
} else if (expr.equals("priority(p_eft) || deny")) {
} else if (expr.equals("priority(p_eft) || deny") || expr.equals("subjectPriority(p_eft) || deny")) {
result = false;
for (Effect eft : effects) {
if (eft != Effect.Indeterminate) {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -53,6 +53,7 @@ public boolean push(Effect eft, int currentIndex, int policySize) {
}
break;
case "priority(p_eft) || deny":
case "subjectPriority(p_eft) || deny":
if (eft != Effect.Indeterminate) {
this.effect = eft == Effect.Allow;
this.done = true;
Expand Down
2 changes: 2 additions & 0 deletions src/main/java/org/casbin/jcasbin/main/CoreEnforcer.java
Original file line number Diff line number Diff line change
Expand Up @@ -256,6 +256,7 @@ public void loadPolicy() {
model.clearPolicy();
adapter.loadPolicy(model);
model.sortPoliciesByPriority();
model.sortPoliciesBySubjectHieraichy();

clearRmMap();
if (Util.enableLog) {
Expand Down Expand Up @@ -285,6 +286,7 @@ public void loadFilteredPolicy(Object filter) {
e.printStackTrace();
}
model.sortPoliciesByPriority();
model.sortPoliciesBySubjectHieraichy();

initRmMap();
if (Util.enableLog) {
Expand Down
79 changes: 79 additions & 0 deletions src/main/java/org/casbin/jcasbin/model/Model.java
Original file line number Diff line number Diff line change
Expand Up @@ -17,8 +17,11 @@
import org.casbin.jcasbin.config.Config;
import org.casbin.jcasbin.util.Util;

import java.util.ArrayList;
import java.util.Collections;
import java.util.Comparator;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

import static org.casbin.jcasbin.util.Util.splitCommaDelimited;
Expand All @@ -40,6 +43,9 @@ public class Model extends Policy {

// used by CoreEnforcer to detect changes to Model
protected int modCount;
private int domainIndex = -1;
private String defaultDomain = "";
private String defaultSeparator = "::";

public Model() {
model = new HashMap<>();
Expand Down Expand Up @@ -229,6 +235,79 @@ public void sortPoliciesByPriority() {
}
}

/**
* sort policies by hieraichy map
*/
public void sortPoliciesBySubjectHieraichy() {
if (model.get("e") == null || (!"subjectPriority(p_eft) || deny".equals(model.get("e").get("e").value))) {
return;
}

for (Map.Entry<String, Assertion> entry : model.get("p").entrySet()) {
Map<String, Integer> subjectHierarchyMap = getSubjectHierarchyMap(model.get("g").get("g").policy);
Assertion assertion = entry.getValue();
domainIndex = -1;
for(int i=0; i<assertion.tokens.length; i++){
if(assertion.tokens[i].equals(assertion.key+"_dom")){
domainIndex = i;
break;
}
}
Collections.sort(assertion.policy, (o1, o2)->{
String domain1 = domainIndex!=-1 ? o1.get(domainIndex) : defaultDomain;
String domain2 = domainIndex!=-1 ? o2.get(domainIndex) : defaultDomain;
int priority1 = subjectHierarchyMap.get(getNameWithDomain(domain1, o1.get(0)));
int priority2 = subjectHierarchyMap.get(getNameWithDomain(domain2, o2.get(0)));
return priority2-priority1;
});
}

}

public Map<String, Integer> getSubjectHierarchyMap(List<List<String>> policies) {
Map<String, Integer> subjectHierarchyMap = new HashMap<>();
Map<String, String> policyMap = new HashMap<>();
String domain = defaultDomain;

for(List<String> policy:policies) {
if(policy.size()!=2) {
domain = policy.get(2);
}
String child = getNameWithDomain(domain, policy.get(0));
String parent = getNameWithDomain(domain, policy.get(1));
policyMap.put(child, parent);
if(!subjectHierarchyMap.containsKey(child)) {
subjectHierarchyMap.put(child, 0);
}
if(!subjectHierarchyMap.containsKey(parent)) {
subjectHierarchyMap.put(parent, 0);
}
subjectHierarchyMap.replace(child, 1);
}
List<String> set = new ArrayList<>();
for (String key : subjectHierarchyMap.keySet()) {
if (subjectHierarchyMap.get(key) != 0) set.add(key);
}
while (!set.isEmpty()){
String child = set.get(0);
findHierarchy(policyMap, subjectHierarchyMap, set, child);
}
return subjectHierarchyMap;
}

private void findHierarchy(Map<String, String> policyMap, Map<String, Integer> subjectHierarchyMap, List<String> set, String child) {
set.remove(child);
String parent = policyMap.get(child);
if (set.contains(parent)) {
findHierarchy(policyMap, subjectHierarchyMap, set, parent);
}
subjectHierarchyMap.replace(child, subjectHierarchyMap.get(parent)+10);
}

public String getNameWithDomain(String domain, String name) {
return domain + defaultSeparator + name;
}

public enum PolicyOperations {
POLICY_ADD,
POLICY_REMOVE
Expand Down
16 changes: 16 additions & 0 deletions src/test/java/org/casbin/jcasbin/main/ModelUnitTest.java
Original file line number Diff line number Diff line change
Expand Up @@ -421,13 +421,29 @@ public void testPriorityModel() {
testEnforce(e, "bob", "data2", "write", false);
}

@Test
public void testPriorityHierachyModel(){
Enforcer e = new Enforcer("examples/priority_hierachy_policy.conf", "examples/priority_hierachy_policy.csv");

testEnforce(e, "alice", "data1", "read", true);
testEnforce(e, "jane", "data1", "read", true);
}

@Test
public void testPriorityModelIndeterminate() {
Enforcer e = new Enforcer("examples/priority_model.conf", "examples/priority_indeterminate_policy.csv");

testEnforce(e, "alice", "data1", "read", false);
}

@Test
public void testSubjectPriorityWithDomain() {
Enforcer e = new Enforcer("examples/subject_priority_model_with_domain.conf", "examples/subject_priority_policy_with_domain.csv");

testDomainEnforce(e, "alice", "domain1", "data1", "write", true);
testDomainEnforce(e, "bob", "domain2", "data2", "write", true);
}

@Test
public void testGlobMatchModel() {
Enforcer e = new Enforcer("examples/glob_model.conf", "examples/glob_policy.csv");
Expand Down

0 comments on commit c61f3e4

Please sign in to comment.