Skip to content

Commit

Permalink
feat: support rbac-with-conditions for jcasbin (#392)
Browse files Browse the repository at this point in the history
  • Loading branch information
LMay001 committed Mar 27, 2024
1 parent c7d1c21 commit 536d194
Show file tree
Hide file tree
Showing 14 changed files with 843 additions and 28 deletions.
14 changes: 14 additions & 0 deletions examples/rbac_with_domain_temporal_roles_model.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

[role_definition]
g = _, _, _, (_, _)

[policy_effect]
e = some(where (p.eft == allow))

[matchers]
m = g(r.sub, p.sub, r.dom) && r.dom == p.dom && r.obj == p.obj && r.act == p.act
24 changes: 24 additions & 0 deletions examples/rbac_with_domain_temporal_roles_policy.csv
Original file line number Diff line number Diff line change
@@ -0,0 +1,24 @@
p, alice, domain1, data1, read
p, alice, domain1, data1, write
p, data2_admin, domain2, data2, read
p, data2_admin, domain2, data2, write
p, data3_admin, domain3, data3, read
p, data3_admin, domain3, data3, write
p, data4_admin, domain4, data4, read
p, data4_admin, domain4, data4, write
p, data5_admin, domain5, data5, read
p, data5_admin, domain5, data5, write
p, data6_admin, domain6, data6, read
p, data6_admin, domain6, data6, write
p, data7_admin, domain7, data7, read
p, data7_admin, domain7, data7, write
p, data8_admin, domain8, data8, read
p, data8_admin, domain8, data8, write

g, alice, data2_admin, domain2, 0000-01-01 00:00:00, 0000-01-02 00:00:00
g, alice, data3_admin, domain3, 0000-01-01 00:00:00, 9999-12-30 00:00:00
g, alice, data4_admin, domain4, _, _
g, alice, data5_admin, domain5, _, 9999-12-30 00:00:00
g, alice, data6_admin, domain6, _, 0000-01-02 00:00:00
g, alice, data7_admin, domain7, 0000-01-01 00:00:00, _
g, alice, data8_admin, domain8, 9999-12-30 00:00:00, _
14 changes: 14 additions & 0 deletions examples/rbac_with_temporal_roles_model.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

[role_definition]
g = _, _, (_, _)

[policy_effect]
e = some(where (p.eft == allow))

[matchers]
m = g(r.sub, p.sub) && r.obj == p.obj && r.act == p.act
24 changes: 24 additions & 0 deletions examples/rbac_with_temporal_roles_policy.csv
Original file line number Diff line number Diff line change
@@ -0,0 +1,24 @@
p, alice, data1, read
p, alice, data1, write
p, data2_admin, data2, read
p, data2_admin, data2, write
p, data3_admin, data3, read
p, data3_admin, data3, write
p, data4_admin, data4, read
p, data4_admin, data4, write
p, data5_admin, data5, read
p, data5_admin, data5, write
p, data6_admin, data6, read
p, data6_admin, data6, write
p, data7_admin, data7, read
p, data7_admin, data7, write
p, data8_admin, data8, read
p, data8_admin, data8, write

g, alice, data2_admin, 0000-01-01 00:00:00, 0000-01-02 00:00:00
g, alice, data3_admin, 0000-01-01 00:00:00, 9999-12-30 00:00:00
g, alice, data4_admin, _, _
g, alice, data5_admin, _, 9999-12-30 00:00:00
g, alice, data6_admin, _, 0000-01-02 00:00:00
g, alice, data7_admin, 0000-01-01 00:00:00, _
g, alice, data8_admin, 9999-12-30 00:00:00, _
128 changes: 114 additions & 14 deletions src/main/java/org/casbin/jcasbin/main/CoreEnforcer.java
Original file line number Diff line number Diff line change
Expand Up @@ -33,14 +33,14 @@
import org.casbin.jcasbin.model.Model;
import org.casbin.jcasbin.persist.*;
import org.casbin.jcasbin.persist.file_adapter.FileAdapter;
import org.casbin.jcasbin.rbac.DomainManager;
import org.casbin.jcasbin.rbac.RoleManager;
import org.casbin.jcasbin.rbac.*;
import org.casbin.jcasbin.util.BuiltInFunctions;
import org.casbin.jcasbin.util.EnforceContext;
import org.casbin.jcasbin.util.Util;

import java.util.*;
import java.util.function.BiPredicate;
import java.util.function.Function;

/**
* CoreEnforcer defines the core functionality of an enforcer.
Expand All @@ -55,6 +55,7 @@ public class CoreEnforcer {
Watcher watcher;
Dispatcher dispatcher;
Map<String, RoleManager> rmMap;
Map<String, ConditionalRoleManager> condRmMap;

private boolean enabled;
boolean autoSave;
Expand All @@ -67,6 +68,7 @@ public class CoreEnforcer {

void initialize() {
rmMap = new HashMap<>();
condRmMap = new HashMap<>();
eft = new DefaultEffector();
watcher = null;

Expand Down Expand Up @@ -287,6 +289,7 @@ public void loadPolicy() {
}
if (autoBuildRoleLinks) {
buildRoleLinks();
buildConditionalRoleLinks();
}
}

Expand Down Expand Up @@ -317,6 +320,7 @@ public void loadFilteredPolicy(Object filter) {
}
if (autoBuildRoleLinks) {
buildRoleLinks();
buildConditionalRoleLinks();
}
}

Expand Down Expand Up @@ -372,8 +376,31 @@ private void initRmMap() {
for (String ptype : model.model.get("g").keySet()) {
if (rmMap.containsKey(ptype)) {
rmMap.get(ptype).clear();
} else {
addOrUpdateDomainManagerMatching(ptype);
continue;
}
Assertion assertion = model.model.get("g").get(ptype);
int token_length = (assertion.tokens != null ? assertion.tokens.length : 0);
int paramsToken_length = (assertion.paramsTokens != null ? assertion.paramsTokens.length : 0);
if (token_length <= 2 && paramsToken_length == 0) {
assertion.rm = new DomainManager(10);
rmMap.put(ptype, assertion.rm);
}
if (token_length <= 2 && paramsToken_length != 0) {
assertion.condRM =new ConditionalRoleManager(10);
condRmMap.put(ptype, assertion.condRM);
}
if (token_length > 2) {
if (paramsToken_length == 0) {
assertion.rm = new DomainManager(10);
rmMap.put(ptype, assertion.rm);
} else {
assertion.condRM = new ConditionalRoleManager(10);
condRmMap.put(ptype, assertion.condRM);
}
String matchFun = "keyMatch(r_dom, p_dom)";
if (model.model.get("m").get("m").value.contains(matchFun)) {
addNamedDomainMatchingFunc(ptype, "g", BuiltInFunctions::keyMatch);
}
}
}
}
Expand Down Expand Up @@ -409,7 +436,9 @@ private void clearRmMap() {
}

for (String ptype : model.model.get("g").keySet()) {
rmMap.get(ptype).clear();
if (rmMap.get(ptype) != null) {
rmMap.get(ptype).clear();
}
}
}

Expand Down Expand Up @@ -466,10 +495,21 @@ public void enableAcceptJsonRequest(boolean acceptJsonRequest) {
* role inheritance relations.
*/
public void buildRoleLinks() {
for (RoleManager rm : rmMap.values()) {
rm.clear();
if (!rmMap.isEmpty()) {
for (RoleManager rm : rmMap.values()) {
rm.clear();
}
model.buildRoleLinks(rmMap);
}
}

public void buildConditionalRoleLinks(){
if (!condRmMap.isEmpty()) {
for (ConditionalRoleManager condRm : condRmMap.values()) {
condRm.clear();
}
model.buildConditionalRoleLinks(condRmMap);
}
model.buildRoleLinks(rmMap);
}

/**
Expand Down Expand Up @@ -499,8 +539,17 @@ private EnforceResult enforce(String matcher, Object... rvals) {
Assertion ast = entry.getValue();

RoleManager rm = ast.rm;
AviatorFunction aviatorFunction = BuiltInFunctions.GenerateGFunctionClass.generateGFunction(key, rm);
gFunctions.put(key, aviatorFunction);
if (rm != null){
AviatorFunction aviatorFunction = BuiltInFunctions.GenerateGFunctionClass.generateGFunction(key, rm);
gFunctions.put(key, aviatorFunction);
}

ConditionalRoleManager condRM = ast.condRM;
if (condRM != null){
AviatorFunction aviatorFunction = BuiltInFunctions.GenerateConditionalGFunctionClass.generateConditionalGFunction(key, condRM);
gFunctions.put(key, aviatorFunction);
}

}
}
for (AviatorFunction f : gFunctions.values()) {
Expand Down Expand Up @@ -736,10 +785,10 @@ public boolean addNamedMatchingFunc(String ptype, String name, BiPredicate<Strin
if (rmMap.containsKey(ptype)) {
DomainManager rm = (DomainManager) rmMap.get(ptype);
rm.addMatchingFunc(name, fn);
clearRmMap();
if (autoBuildRoleLinks) {
buildRoleLinks();
}
// clearRmMap();
// if (autoBuildRoleLinks) {
// buildRoleLinks();
// }
return true;
}
return false;
Expand All @@ -761,6 +810,57 @@ public boolean addNamedDomainMatchingFunc(String ptype, String name, BiPredicate
return false;
}

/**
* addNamedLinkConditionFunc Add condition function fn for Link userName->roleName,
* when fn returns true, Link is valid, otherwise invalid
*/
public boolean addNamedLinkConditionFunc(String ptype, String user, String role, Function<String[], Boolean> fn){
if (condRmMap.containsKey(ptype)){
ConditionalRoleManager condRm = condRmMap.get(ptype);
condRm.addLinkConditionFunc(user, role, fn);
return true;
}
return false;
}

/**
* addNamedDomainLinkConditionFunc Add condition function fn for Link userName-> {roleName, domain},
* when fn returns true, Link is valid, otherwise invalid
*/
public boolean addNamedDomainLinkConditionFunc(String ptype, String user, String role, String domain, Function<String[], Boolean> fn) {
if (condRmMap.containsKey(ptype)){
ConditionalRoleManager condRm = condRmMap.get(ptype);
condRm.addDomainLinkConditionFunc(user, role, domain, fn);
return true;
}
return false;
}

/**
* setNamedLinkConditionFuncParams Sets the parameters of the condition function fn for Link userName->roleName
*/
public boolean setNamedLinkConditionFuncParams(String ptype, String user, String role, String... params){
if (condRmMap.containsKey(ptype)){
ConditionalRoleManager condRm = condRmMap.get(ptype);
condRm.setLinkConditionFuncParams(user, role, params);
return true;
}
return false;
}

/**
* setNamedDomainLinkConditionFuncParams Sets the parameters of the condition function fn
* for Link userName->{roleName, domain}
*/
public boolean setNamedDomainLinkConditionFuncParams(String ptype, String user, String role, String domain, String... params){
if (condRmMap.containsKey(ptype)){
ConditionalRoleManager condRm = condRmMap.get(ptype);
condRm.setDomainLinkConditionFuncParams(user, role, domain, params);
return true;
}
return false;
}

private void getRTokens(Map<String, Object> parameters, String rType, Object... rvals) {
String[] requestTokens = model.model.get("r").get(rType).tokens;
if(requestTokens.length != rvals.length) {
Expand Down
Loading

0 comments on commit 536d194

Please sign in to comment.