Skip to content

Commit

Permalink
feat: add ABAC & JSON related test cases (#376)
Browse files Browse the repository at this point in the history
  • Loading branch information
LMay001 authored Feb 3, 2024
1 parent 00bc8e8 commit 2c363e1
Show file tree
Hide file tree
Showing 7 changed files with 172 additions and 6 deletions.
2 changes: 1 addition & 1 deletion examples/abac_model.conf
Original file line number Diff line number Diff line change
Expand Up @@ -8,4 +8,4 @@ p = sub, obj, act
e = some(where (p.eft == allow))

[matchers]
m = r.sub == r.obj.owner
m = r.sub == r.obj.Owner
5 changes: 2 additions & 3 deletions examples/abac_rule_policy.csv
Original file line number Diff line number Diff line change
@@ -1,3 +1,2 @@
p, r.sub.not_exist_attribute_test == true, /data0, read
p, r.sub.age > 18 && r.sub.age < 25, /data1, read
p, r.sub.age < 60, /data2, write
p, r.sub.Age > 18, /data1, read
p, r.sub.Age < 60, /data2, write
6 changes: 6 additions & 0 deletions pom.xml
Original file line number Diff line number Diff line change
Expand Up @@ -229,6 +229,12 @@
<artifactId>gson</artifactId>
<version>2.9.0</version>
</dependency>
<dependency>
<groupId>com.fasterxml.jackson.core</groupId>
<artifactId>jackson-databind</artifactId>
<version>2.13.1</version>
</dependency>

</dependencies>

</project>
35 changes: 35 additions & 0 deletions src/main/java/org/casbin/jcasbin/main/CoreEnforcer.java
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,9 @@

package org.casbin.jcasbin.main;

import com.fasterxml.jackson.core.JsonProcessingException;
import com.fasterxml.jackson.core.type.TypeReference;
import com.fasterxml.jackson.databind.ObjectMapper;
import com.googlecode.aviator.AviatorEvaluator;
import com.googlecode.aviator.AviatorEvaluatorInstance;
import com.googlecode.aviator.Expression;
Expand Down Expand Up @@ -57,6 +60,7 @@ public class CoreEnforcer {
boolean autoBuildRoleLinks;
boolean autoNotifyWatcher = true;
boolean autoNotifyDispatcher = true;
boolean acceptJsonRequest = false;

private AviatorEvaluatorInstance aviatorEval;

Expand Down Expand Up @@ -447,6 +451,15 @@ public void enableAutoBuildRoleLinks(boolean autoBuildRoleLinks) {
this.autoBuildRoleLinks = autoBuildRoleLinks;
}

/**
* EnableAcceptJsonRequest controls whether to accept json as a request parameter
*
* @param acceptJsonRequest
*/
public void enableAcceptJsonRequest(boolean acceptJsonRequest) {
this.acceptJsonRequest = acceptJsonRequest;
}

/**
* buildRoleLinks manually rebuild the
* role inheritance relations.
Expand Down Expand Up @@ -516,6 +529,28 @@ private EnforceResult enforce(String matcher, Object... rvals) {
expString = Util.removeComments(Util.escapeAssertion(matcher));
}

// json process
if (acceptJsonRequest) {
try {
List<Object> parsedRvals = new ArrayList<>();
ObjectMapper objectMapper = new ObjectMapper();

for (Object rval : rvals) {
if (rval instanceof String && !((String) rval).isEmpty() && Util.isJsonString((String) rval)) {
String jsonString = (String) rval;
Map<String, Object> mapValue = objectMapper.readValue(jsonString, new TypeReference<Map<String, Object>>() {});
parsedRvals.add(mapValue);
} else {
parsedRvals.add(rval);
}
}

rvals = parsedRvals.toArray();
} catch (JsonProcessingException e) {
e.printStackTrace();
}
}

expString = Util.convertInSyntax(expString);
// Use md5 encryption as cacheKey to prevent expString from being too long
Expression expression = aviatorEval.compile(Util.md5(expString), expString, compileCached);
Expand Down
18 changes: 18 additions & 0 deletions src/main/java/org/casbin/jcasbin/util/Util.java
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,8 @@

package org.casbin.jcasbin.util;

import com.fasterxml.jackson.core.JsonProcessingException;
import com.fasterxml.jackson.databind.ObjectMapper;
import org.apache.commons.csv.CSVFormat;
import org.apache.commons.csv.CSVParser;
import org.apache.commons.csv.CSVRecord;
Expand Down Expand Up @@ -330,4 +332,20 @@ private static MessageDigest getDigest(String algorithm) {
throw new IllegalArgumentException(e);
}
}

/**
* Helper method to check if a string is a valid JSON
*
* @param str
* @return boolean
*/
public static boolean isJsonString(String str) {
try {
ObjectMapper objectMapper = new ObjectMapper();
objectMapper.readTree(str);
return true;
} catch (JsonProcessingException e) {
return false;
}
}
}
2 changes: 1 addition & 1 deletion src/test/java/org/casbin/jcasbin/main/AbacAPIUnitTest.java
Original file line number Diff line number Diff line change
Expand Up @@ -35,7 +35,7 @@ public void testEval() {
testEnforce(e, alice, "/data1", "read", true);
testEnforce(e, alice, "/data1", "write", false);
alice.setAge(25);
testEnforce(e, alice, "/data1", "read", false);
testEnforce(e, alice, "/data1", "read", true);
testEnforce(e, alice, "/data1", "write", false);
testEnforce(e, alice, "/data2", "read", false);
testEnforce(e, alice, "/data2", "write", true);
Expand Down
110 changes: 109 additions & 1 deletion src/test/java/org/casbin/jcasbin/main/ModelUnitTest.java
Original file line number Diff line number Diff line change
Expand Up @@ -17,13 +17,18 @@
import org.casbin.jcasbin.persist.file_adapter.AdapterMock;
import org.casbin.jcasbin.rbac.RoleManager;
import org.casbin.jcasbin.util.BuiltInFunctions;
import org.casbin.jcasbin.util.Util;
import org.junit.Test;

import java.util.List;
import java.util.*;

import com.fasterxml.jackson.core.JsonProcessingException;
import com.fasterxml.jackson.databind.ObjectMapper;

import static org.casbin.jcasbin.main.TestUtil.testDomainEnforce;
import static org.casbin.jcasbin.main.TestUtil.testEnforce;
import static org.casbin.jcasbin.main.TestUtil.testEnforceWithoutUsers;
import static org.junit.Assert.assertEquals;

public class ModelUnitTest {
@Test
Expand Down Expand Up @@ -416,6 +421,109 @@ public void testABACModel() {
testEnforce(e, "bob", data2, "write", true);
}

@Test
public void testABACMapRequest(){
Enforcer e = new Enforcer("examples/abac_model.conf");

Map<String, Object> data1 = new HashMap<>();
data1.put("Name", "data1");
data1.put("Owner", "alice");

Map<String, Object> data2 = new HashMap<>();
data2.put("Name", "data2");
data2.put("Owner", "bob");

testEnforce(e, "alice", data1, "read", true);
testEnforce(e, "alice", data1, "write", true);
testEnforce(e, "alice", data2, "read", false);
testEnforce(e, "alice", data2, "write", false);
testEnforce(e, "bob", data1, "read", false);
testEnforce(e, "bob", data1, "write", false);
testEnforce(e, "bob", data2, "read", true);
testEnforce(e, "bob", data2, "write", true);
}

static class StructRequest {
private List<Object> Roles;
private boolean Enabled;
private int Age;
private String Name;

// Getters and setters
public List<Object> getRoles() {
return Roles;
}

public void setRoles(List<Object> Roles) {
this.Roles = Roles;
}

public boolean isEnabled() {
return Enabled;
}

public void setEnabled(boolean Enabled) {
this.Enabled = Enabled;
}

public int getAge() {
return Age;
}

public void setAge(int Age) {
this.Age = Age;
}

public String getName() {
return Name;
}

public void setName(String Name) {
this.Name = Name;
}
}

public static void testEnforce(Enforcer e, Object sub, Object obj, String act, boolean res) {
try {
boolean myRes = e.enforce(sub, obj, act);
assertEquals(String.format("%s, %s, %s: %b, supposed to be %b", sub, obj, act, myRes, res), res, myRes);
} catch (Exception ex) {
throw new RuntimeException(String.format("Enforce Error: %s", ex.getMessage()), ex);
}
}

@Test
public void testABACTypes(){
Enforcer e = new Enforcer("examples/abac_model.conf");
String matcher = "\"moderator\" in r.sub.Roles && r.sub.Enabled == true && r.sub.Age >= 21 && r.sub.Name != \"foo\"";
e.getModel().model.get("m").get("m").value = (Util.removeComments(Util.escapeAssertion(matcher)));

// Struct request
StructRequest structRequest = new StructRequest();
structRequest.setRoles(Arrays.asList("user", "moderator"));
structRequest.setEnabled(true);
structRequest.setAge(30);
structRequest.setName("alice");
testEnforce(e, structRequest, null, "", true);

// Map request
Map<String, Object> mapRequest = new HashMap<>();
mapRequest.put("Roles", Arrays.asList("user", "moderator"));
mapRequest.put("Enabled", true);
mapRequest.put("Age", 30);
mapRequest.put("Name", "alice");
testEnforce(e, mapRequest, null, "", true);

// JSON request
e.enableAcceptJsonRequest(true);
try {
String jsonRequest = new ObjectMapper().writeValueAsString(mapRequest);
testEnforce(e, jsonRequest, "", "", true);
} catch (JsonProcessingException jsonProcessingException) {
jsonProcessingException.printStackTrace();
}
}

@Test
public void testKeyMatchModel() {
Enforcer e = new Enforcer("examples/keymatch_model.conf", "examples/keymatch_policy.csv");
Expand Down

0 comments on commit 2c363e1

Please sign in to comment.