diff --git a/README.md b/README.md
index a3d3d9f..f3dee59 100644
--- a/README.md
+++ b/README.md
@@ -24,6 +24,7 @@ mvn clean install
| `-p, --policy` | The path of the policy file or policy text | y | Please wrap it with `""` and separate each line with `\|` |
| `-e, --enforce` | Check permissions | n | Please wrap it with `""` |
| `-ex, --enforceEx` | Check permissions and get which policy it is | n | Please wrap it with `""` |
+| `-AF, --addFuntion` | Add custom funtion | n | Please wrap it with `""` and separate each line with `\|` |
| `-ap, --addPolicy` | Add a policy rule to the policy file | n | Please wrap it with `""` |
| `-rp, --removePolicy` | Remove a policy rule from the policy file | n | Please wrap it with `""` |
@@ -32,32 +33,32 @@ mvn clean install
- Check whether Alice has read permission on data1
```shell
- java -jar target/casbin-java-cli.jar -m "examples/rbac_model.conf" -p "examples/rbac_policy.csv" -e "alice, data1, read"
+ ./casbin enforce -m "examples/rbac_model.conf" -p "examples/rbac_policy.csv" "alice" "data1" "read"
```
- > Allow
+ > {"allow":true,"explain":null}
```shell
- java -jar target/casbin-java-cli.jar -m "[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" -p "p, alice, data1, read|p, bob, data2, write|p, data2_admin, data2, read|p, data2_admin, data2, write|g, alice, data2_admin" -e "alice, data1, read"
+ ./casbin enforce -m "[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" -p "p, alice, data1, read|p, bob, data2, write|p, data2_admin, data2, read|p, data2_admin, data2, write|g, alice, data2_admin" "alice" "data1" "read"
```
- > Allow
+ > {"allow":true,"explain":null}
- Check whether Alice has write permission for data2. If so, display the effective policy.
```shell
- java -jar target/casbin-java-cli.jar -m "examples/rbac_model.conf" -p "examples/rbac_policy.csv" -ex "alice, data2, write"
+ ./casbin enforceEx -m "examples/rbac_model.conf" -p "examples/rbac_policy.csv" "alice" "data2" "write"
```
- > true Reason: [alice, data2, write]
+ > {"allow":true,"explain":["data2_admin","data2","write"]}
- Add a policy to the policy file
```shell
- java -jar target/casbin-java-cli.jar -m "examples/rbac_model.conf" -p "examples/rbac_policy.csv" -ap "alice, data2, write"
+ ./casbin addPolicy -m "examples/rbac_model.conf" -p "examples/rbac_policy.csv" "alice" "data2" "write"
```
- > Add Success
+ > {"allow":true,"explain":null}
- Delete a policy from the policy file
```shell
- java -jar target/casbin-java-cli.jar -m "examples/rbac_model.conf" -p "examples/rbac_policy.csv" -rp "alice,data1,read"
+ ./casbin removePolicy -m "examples/rbac_model.conf" -p "examples/rbac_policy.csv" "alice" "data2" "write"
```
- > Remove Success
+ > {"allow":true,"explain":null}
diff --git a/casbin b/casbin
new file mode 100755
index 0000000..00c2157
--- /dev/null
+++ b/casbin
@@ -0,0 +1,2 @@
+#!/bin/sh
+java -jar target/casbin-java-cli.jar "$@"
\ No newline at end of file
diff --git a/casbin.cmd b/casbin.cmd
new file mode 100644
index 0000000..70124d9
--- /dev/null
+++ b/casbin.cmd
@@ -0,0 +1,5 @@
+@echo off
+setlocal
+set JAR_PATH=target\casbin-java-cli.jar
+java -jar "%JAR_PATH%" %*
+endlocal
\ No newline at end of file
diff --git a/examples/abac_rule_with_domains_policy.csv b/examples/abac_rule_with_domains_policy.csv
index 095bebf..beb1ef8 100644
--- a/examples/abac_rule_with_domains_policy.csv
+++ b/examples/abac_rule_with_domains_policy.csv
@@ -3,4 +3,4 @@ p, r.domain == 'domain1', admin, domain1, data1, write
p, r.domain == 'domain2', admin, domain2, data2, read
p, r.domain == 'domain2', admin, domain2, data2, write
g, alice, admin, domain1
-g, bob, admin, domain2
+g, bob, admin, domain2
\ No newline at end of file
diff --git a/examples/basic_model.conf b/examples/basic_model.conf
new file mode 100644
index 0000000..dc6da81
--- /dev/null
+++ b/examples/basic_model.conf
@@ -0,0 +1,11 @@
+[request_definition]
+r = sub, obj, act
+
+[policy_definition]
+p = sub, obj, act
+
+[policy_effect]
+e = some(where (p.eft == allow))
+
+[matchers]
+m = r.sub == p.sub && r.obj == p.obj && r.act == p.act
\ No newline at end of file
diff --git a/examples/basic_policy.csv b/examples/basic_policy.csv
new file mode 100644
index 0000000..57aaa97
--- /dev/null
+++ b/examples/basic_policy.csv
@@ -0,0 +1,2 @@
+p, alice, data1, read
+p, bob, data2, write
\ No newline at end of file
diff --git a/examples/keymatch_policy.csv b/examples/keymatch_policy.csv
new file mode 100644
index 0000000..39c5966
--- /dev/null
+++ b/examples/keymatch_policy.csv
@@ -0,0 +1,5 @@
+p, alice, /alice_data/*, GET
+p, alice, /alice_data/resource1, POST
+p, bob, /alice_data/resource2, GET
+p, bob, /bob_data/*, POST
+p, cathy, /cathy_data, (GET)|(POST)
\ No newline at end of file
diff --git a/pom.xml b/pom.xml
index 0dad7f2..c1c7c7f 100644
--- a/pom.xml
+++ b/pom.xml
@@ -8,12 +8,6 @@
jar
-
-
-
-
-
-
UTF-8
diff --git a/src/main/java/org/casbin/Client.java b/src/main/java/org/casbin/Client.java
index d91d53e..54773a6 100644
--- a/src/main/java/org/casbin/Client.java
+++ b/src/main/java/org/casbin/Client.java
@@ -1,89 +1,80 @@
package org.casbin;
+
import org.apache.commons.cli.*;
-import org.casbin.jcasbin.exception.CasbinEffectorException;
-import org.casbin.jcasbin.main.EnforceResult;
+import org.casbin.generate.DynamicClassGenerator;
+import org.casbin.jcasbin.util.function.CustomFunction;
+import org.casbin.util.Util;
+import java.util.*;
-public class Client {
- private static void configureOptions(Options options) {
- Option[] cliOptions = {
- addOption("m", "model", true, "the path of the model file"),
- addOption("p", "policy", true, "the path of the policy file"),
- addOption("e", "enforce", true, "enforce"),
- addOption("ex", "enforceEx", true, "enforceEx"),
- addOption("ap", "addPolicy", true, "Add a policy rule to the storage"),
- addOption("rp", "removePolicy", true, "Remove a policy rule from the storage")
- };
- for (Option option : cliOptions) {
- options.addOption(option);
- }
- }
- private static Option addOption(String shortOpt, String longOpt, boolean hasArg, String description) {
- return new Option(shortOpt, longOpt, hasArg, description);
- }
- public static Object run(String[] args) throws ParseException {
- Options options = new Options();
- configureOptions(options);
+public class Client {
- CommandLineParser parser = new DefaultParser();
- CommandLine cmd = parser.parse(options, args);
+ public static String run(String... args) {
+ String result = "";
- String model = cmd.getOptionValue("model");
- String policy = cmd.getOptionValue("policy");
- NewEnforcer enforcer = null;
try {
- enforcer = new NewEnforcer(model, policy);
- } catch (NullPointerException | CasbinEffectorException | UnsupportedOperationException e) {
- System.out.println("unsupported effect:" + e.getMessage());
- System.exit(0);
- } catch (Exception e) {
- System.out.println(e.getMessage());
- System.exit(0);
- }
+ if(args == null || args.length == 0) {
+ printUsageMessageAndExit("");
+ }
- try {
- if(cmd.hasOption("enforce")) {
- String enforceArgs = cmd.getOptionValue("enforce").replace(" ","");
- boolean result = enforcer.enforce(enforceArgs.split(","));
- System.out.println(result ? "Allow" : "Ban");
- return result;
- } else if (cmd.hasOption("enforceEx")) {
- String enforceArgs = cmd.getOptionValue("enforceEx").replace(" ","");
- EnforceResult enforceResult = enforcer.enforceEx(enforceArgs.split(","));
- boolean allow = enforceResult.isAllow();
- if(allow) {
- System.out.printf("%s Reason: %s", allow, enforceResult.getExplain());
- } else {
- System.out.println(allow);
- }
- return allow;
- }else if (cmd.hasOption("addPolicy")){
- String policyArgs = cmd.getOptionValue("addPolicy").replace(" ","");
- boolean result = enforcer.addPolicy(policyArgs.split(","));
- System.out.println(result ? "Add Success" : "Add Failed");
- enforcer.savePolicy();
- return result;
- }else if (cmd.hasOption("removePolicy")){
- String policyArgs = cmd.getOptionValue("removePolicy").replace(" ","");
- boolean result = enforcer.removePolicy(policyArgs.split(","));
- System.out.println(result ? "Remove Success" : "Remove Failed");
- enforcer.savePolicy();
- return result;
- }else {
- System.out.println("Command Error");
- return null;
+ String commandName = args[0];
+
+ CommandLine cmd = getCmd(Arrays.copyOfRange(args, 1, args.length));
+ String model = cmd.getOptionValue("model");
+ String policy = cmd.getOptionValue("policy");
+ NewEnforcer enforcer = new NewEnforcer(model, policy);
+
+
+ if(cmd.hasOption("AF")) {
+ String codes = cmd.getOptionValue("AF");
+ String methodName = Util.getMethodName(codes);
+ CustomFunction customFunction = DynamicClassGenerator.generateClass(methodName, codes);
+ enforcer.addFunction(methodName, customFunction);
}
+ CommandExecutor commandExecutor = new CommandExecutor(enforcer, commandName, cmd.getArgs());
+ Object o = commandExecutor.outputResult();
+ System.out.println(o);
+ return o.toString();
+
} catch (Exception e) {
- System.out.println("unsupported effect:" + e.getMessage());
- System.exit(0);
+ e.printStackTrace();
+ System.exit(1);
}
- return null;
+ return result;
+ }
+
+
+ private static void printUsageMessageAndExit(String commandName) throws Exception {
+ if (commandName.isEmpty()) {
+ System.out.println("Error: " + commandName + " not recognised");
+ }
+// new HelpCommand().run();
+ System.exit(1);
}
public static void main(String[] args) throws ParseException {
- Client cli = new Client();
- Object run = run(args);
+ run(args);
+ }
+
+ private static CommandLine getCmd(String[] args) throws ParseException {
+ Options options = new Options();
+
+ Option option = new Option("AF", "AddFunction", true, "add function");
+ option.setArgs(1);
+ option.setRequired(false);
+ options.addOption(option);
+
+ option = new Option("m", "model", true, "the path of the model file or model text");
+ option.hasArg();
+ options.addOption(option);
+
+ option = new Option("p", "policy", true, "the path of the policy file or policy text");
+ option.hasArg();
+ options.addOption(option);
+
+ CommandLineParser parser = new DefaultParser();
+ return parser.parse(options, args);
}
}
diff --git a/src/main/java/org/casbin/CommandExecutor.java b/src/main/java/org/casbin/CommandExecutor.java
new file mode 100644
index 0000000..fa5bd81
--- /dev/null
+++ b/src/main/java/org/casbin/CommandExecutor.java
@@ -0,0 +1,94 @@
+package org.casbin;
+
+import com.fasterxml.jackson.core.JsonProcessingException;
+import com.fasterxml.jackson.databind.ObjectMapper;
+import org.casbin.jcasbin.main.EnforceResult;
+import org.casbin.jcasbin.main.Enforcer;
+import org.casbin.resp.ResponseBody;
+
+import java.lang.reflect.InvocationTargetException;
+import java.lang.reflect.Method;
+import java.lang.reflect.Type;
+import java.util.*;
+
+public class CommandExecutor {
+
+ private NewEnforcer enforcer;
+
+ private String inputMethodName;
+
+ private String[] inputVal;
+
+ public CommandExecutor(NewEnforcer enforcer, String inputMethodName, String[] inputVal) {
+ this.enforcer = enforcer;
+ this.inputMethodName = inputMethodName;
+ this.inputVal = inputVal;
+ }
+
+ public String outputResult() throws InvocationTargetException, IllegalAccessException, JsonProcessingException {
+ Class extends Enforcer> clazz = enforcer.getClass();
+ Method[] methods = clazz.getMethods();
+
+ ResponseBody responseBody = new ResponseBody(null, null);
+ for (Method method : methods) {
+ String methodName = method.getName();
+ if(methodName.equals(inputMethodName)) {
+ Type[] genericParameterTypes = method.getGenericParameterTypes();
+ Object[] convertedParams = new Object[genericParameterTypes.length];
+ Class> returnType = method.getReturnType();
+
+ if(genericParameterTypes.length == 3 && genericParameterTypes[0] == String.class && genericParameterTypes[1].getTypeName().equals("java.util.List") && genericParameterTypes[2].getTypeName().equals("java.util.List")) {
+ convertedParams[0] = inputVal[0];
+ convertedParams[1] = Arrays.asList(inputVal[1].split(","));
+ convertedParams[2] = Arrays.asList(inputVal[2].split(","));
+ } else if(genericParameterTypes.length == 2 && genericParameterTypes[0].getTypeName().equals("java.util.List") && genericParameterTypes[1].getTypeName().equals("java.util.List")) {
+ convertedParams[0] = Arrays.asList(inputVal[0].split(","));
+ convertedParams[1] = Arrays.asList(inputVal[1].split(","));
+ } else {
+ for (int i = 0; i < genericParameterTypes.length; i++) {
+ if(genericParameterTypes[i] == int.class) {
+ convertedParams[i] = Integer.valueOf(inputVal[i]);
+ } else if(genericParameterTypes[i] == String.class) {
+ convertedParams[i] = inputVal[i];
+ } else if(genericParameterTypes[i] == Object[].class || genericParameterTypes[i] == String[].class) {
+ convertedParams[i] = Arrays.copyOfRange(inputVal, i, inputVal.length);
+ } else if (genericParameterTypes[i] == String[][].class) {
+ String[] arr = Arrays.copyOfRange(inputVal, i, inputVal.length);
+ String[][] res = new String[arr.length][];
+ for (int i1 = 0; i1 < res.length; i1++) {
+ res[i1] = arr[i1].split(",");
+ }
+ convertedParams[i] = res;
+ } else if (genericParameterTypes[i].getTypeName().equals("java.util.List")) {
+ String[] arr = Arrays.copyOfRange(inputVal, i, inputVal.length);
+ convertedParams[i] = Arrays.asList(arr);
+ } else if (genericParameterTypes[i].getTypeName().equals("java.util.List>")) {
+ List> res = new ArrayList<>();
+ String[] arr = Arrays.copyOfRange(inputVal, i, inputVal.length);
+ for (String s : arr) {
+ List ans = new ArrayList<>();
+ Collections.addAll(ans, s.split(","));
+ res.add(ans);
+ }
+ convertedParams[i] = res;
+ }
+ }
+ }
+
+ Object invoke = method.invoke(enforcer, convertedParams);
+ if(returnType == boolean.class) {
+ responseBody.setAllow((Boolean) invoke);
+ } else if (returnType == List.class) {
+ responseBody.setExplain((ArrayList>) invoke);
+ } else if (returnType == EnforceResult.class) {
+ responseBody.setAllow(((EnforceResult) invoke).isAllow());
+ responseBody.setExplain((ArrayList>) ((EnforceResult) invoke).getExplain());
+ }
+ enforcer.savePolicy();
+ break;
+ }
+ }
+ ObjectMapper mapper = new ObjectMapper();
+ return mapper.writeValueAsString(responseBody);
+ }
+}
diff --git a/src/main/java/org/casbin/NewEnforcer.java b/src/main/java/org/casbin/NewEnforcer.java
index ebb94e9..31736f1 100644
--- a/src/main/java/org/casbin/NewEnforcer.java
+++ b/src/main/java/org/casbin/NewEnforcer.java
@@ -1,6 +1,7 @@
package org.casbin;
import org.casbin.jcasbin.main.Enforcer;
+import org.casbin.jcasbin.util.function.CustomFunction;
import java.io.BufferedWriter;
import java.io.File;
diff --git a/src/main/java/org/casbin/generate/CustomClassLoader.java b/src/main/java/org/casbin/generate/CustomClassLoader.java
new file mode 100644
index 0000000..f21f21d
--- /dev/null
+++ b/src/main/java/org/casbin/generate/CustomClassLoader.java
@@ -0,0 +1,7 @@
+package org.casbin.generate;
+
+public class CustomClassLoader extends ClassLoader {
+ public Class> defineClass(String name, byte[] b) {
+ return super.defineClass(name, b, 0, b.length);
+ }
+}
diff --git a/src/main/java/org/casbin/generate/DynamicClassGenerator.java b/src/main/java/org/casbin/generate/DynamicClassGenerator.java
new file mode 100644
index 0000000..8f18670
--- /dev/null
+++ b/src/main/java/org/casbin/generate/DynamicClassGenerator.java
@@ -0,0 +1,126 @@
+package org.casbin.generate;
+
+
+import org.casbin.jcasbin.util.function.CustomFunction;
+
+import javax.tools.*;
+import java.io.*;
+import java.net.URI;
+import java.util.*;
+
+
+import static org.casbin.util.Util.*;
+
+public class DynamicClassGenerator {
+
+ public static CustomFunction generateClass(String methodName, String methodCodes) {
+ String className = "CustomFunc";
+ int argsNum = getArgsNum(methodCodes);
+ StringBuilder sb = new StringBuilder();
+
+ String codeSnippetOne = "import com.googlecode.aviator.runtime.type.AviatorBoolean;\n" +
+ "import com.googlecode.aviator.runtime.type.AviatorObject;\n" +
+ "import org.casbin.jcasbin.util.function.CustomFunction;\n" +
+ "import java.util.Map;\n" +
+ "import java.util.regex.Pattern;" +
+ "\n" +
+ " public class " + className + " extends CustomFunction {\n" +
+ " @Override\n" +
+ " public AviatorObject call(Map env, ";
+
+ sb.append(codeSnippetOne);
+ for (int i = 0; i < argsNum; i++) {
+ if(i == argsNum - 1) {
+ sb.append("AviatorObject arg").append(i + 1);
+ } else {
+ sb.append("AviatorObject arg").append(i + 1).append(",");
+ }
+ }
+ sb.append(") {");
+
+ for (int i = 0; i < argsNum; i++) {
+ sb.append("String obj").append(i + 1).append("=getStringValue(arg").append(i + 1).append(", env);\n");
+ }
+
+ StringBuilder args = new StringBuilder();
+ for (int i = 0; i < argsNum; i++) {
+ if(i == argsNum - 1) {
+ args.append("obj").append(i + 1);
+ } else {
+ args.append("obj").append(i + 1).append(",");
+ }
+
+ }
+ sb.append("return AviatorBoolean.valueOf(").append(methodName).append("(").append(args).append("));}\n");
+ sb.append("@Override\n" + "public String getName() {\n" + " return \"").append(methodName).append("\";\n").append("}\n");
+
+ sb.append("public static final String getStringValue(final AviatorObject arg,\n" +
+ " final Map env) {\n" +
+ " String result = null;\n" +
+ " final Object value = arg.getValue(env);\n" +
+ " if (value instanceof Character) {\n" +
+ " result = value.toString();\n" +
+ " } else {\n" +
+ " result = (String) value;\n" +
+ " }\n" +
+ " return result;\n" +
+ " }\n");
+
+ sb.append(methodCodes);
+ sb.append("}");
+ try {
+ JavaCompiler compiler = ToolProvider.getSystemJavaCompiler();
+ DiagnosticCollector diagnostics = new DiagnosticCollector<>();
+ StandardJavaFileManager fileManager = compiler.getStandardFileManager(null, null, null);
+
+ InMemoryJavaFileManager customFileManager = new InMemoryJavaFileManager(fileManager);
+
+ JavaFileObject sourceFile = new JavaSourceFromString(className, sb.toString());
+ Iterable extends JavaFileObject> compilationUnits = Collections.singletonList(sourceFile);
+
+ JavaCompiler.CompilationTask task = compiler.getTask(null, customFileManager, diagnostics, null, null, compilationUnits);
+ boolean success = task.call();
+ if(success) {
+ byte[] classBytes = customFileManager.getClassBytes(className);
+ if(classBytes != null) {
+ CustomClassLoader loader = new CustomClassLoader();
+ Class> loadedClass = loader.defineClass(className, classBytes);
+ CustomFunction customFunction = (CustomFunction) loadedClass.getDeclaredConstructor().newInstance();
+ return customFunction;
+ }
+ }
+ return null;
+
+ } catch (Exception e) {
+ e.printStackTrace();
+ }
+ return null;
+ }
+
+ static class InMemoryJavaFileManager extends ForwardingJavaFileManager {
+ private final Map classBytesMap = new HashMap<>();
+
+ InMemoryJavaFileManager(StandardJavaFileManager fileManager) {
+ super(fileManager);
+ }
+
+ @Override
+ public JavaFileObject getJavaFileForOutput(Location location, String className, JavaFileObject.Kind kind, FileObject sibling) {
+ ByteArrayOutputStream outputStream = new ByteArrayOutputStream();
+ classBytesMap.put(className, outputStream);
+ return new SimpleJavaFileObject(URI.create("string:///" + className.replace('.', '/') + kind.extension), kind) {
+ @Override
+ public OutputStream openOutputStream() {
+ return outputStream;
+ }
+ };
+ }
+
+ public byte[] getClassBytes(String className) {
+ ByteArrayOutputStream outputStream = classBytesMap.get(className);
+ return outputStream != null ? outputStream.toByteArray() : null;
+ }
+ }
+}
+
+
diff --git a/src/main/java/org/casbin/generate/JavaSourceFromString.java b/src/main/java/org/casbin/generate/JavaSourceFromString.java
new file mode 100644
index 0000000..cc5b327
--- /dev/null
+++ b/src/main/java/org/casbin/generate/JavaSourceFromString.java
@@ -0,0 +1,18 @@
+package org.casbin.generate;
+
+import javax.tools.SimpleJavaFileObject;
+import java.net.URI;
+
+public class JavaSourceFromString extends SimpleJavaFileObject {
+ private final String code;
+
+ JavaSourceFromString(String name, String code) {
+ super(URI.create("string:///" + name.replace('.', '/') + Kind.SOURCE.extension), Kind.SOURCE);
+ this.code = code;
+ }
+
+ @Override
+ public CharSequence getCharContent(boolean ignoreEncodingErrors) {
+ return code;
+ }
+}
\ No newline at end of file
diff --git a/src/main/java/org/casbin/resp/ResponseBody.java b/src/main/java/org/casbin/resp/ResponseBody.java
new file mode 100644
index 0000000..a9c3a8e
--- /dev/null
+++ b/src/main/java/org/casbin/resp/ResponseBody.java
@@ -0,0 +1,43 @@
+package org.casbin.resp;
+
+import java.util.ArrayList;
+
+public class ResponseBody {
+
+ private Boolean allow;
+
+ private ArrayList> explain;
+
+ public ResponseBody() {
+
+ }
+
+ public ResponseBody(Boolean allow, ArrayList> explain) {
+ this.allow = allow;
+ this.explain = explain;
+ }
+
+ public Boolean getAllow() {
+ return allow;
+ }
+
+ public void setAllow(Boolean allow) {
+ this.allow = allow;
+ }
+
+ public ArrayList> getExplain() {
+ return explain;
+ }
+
+ public void setExplain(ArrayList> explain) {
+ this.explain = explain;
+ }
+
+ @Override
+ public String toString() {
+ return "ResponseBody{" +
+ "allow=" + allow +
+ ", explain=" + explain +
+ '}';
+ }
+}
diff --git a/src/main/java/org/casbin/util/Util.java b/src/main/java/org/casbin/util/Util.java
new file mode 100644
index 0000000..56f0ce4
--- /dev/null
+++ b/src/main/java/org/casbin/util/Util.java
@@ -0,0 +1,29 @@
+package org.casbin.util;
+
+import java.util.ArrayList;
+import java.util.Arrays;
+import java.util.List;
+import java.util.regex.Matcher;
+import java.util.regex.Pattern;
+
+public class Util {
+
+ public static String getMethodName(String methodCodes) {
+ String regex = "\\b(\\w+)\\s*\\(";
+ Pattern pattern = Pattern.compile(regex);
+ Matcher matcher = pattern.matcher(methodCodes);
+ return matcher.find() ? matcher.group(1) : null;
+ }
+
+ public static int getArgsNum(String methodCodes) {
+ String regex = "\\(([^)]*)\\)";
+ Pattern pattern = Pattern.compile(regex);
+ Matcher matcher = pattern.matcher(methodCodes);
+ if (matcher.find()) {
+ String args = matcher.group(1);
+ String[] argList = args.split(",");
+ return argList.length;
+ }
+ return 0;
+ }
+}
diff --git a/src/test/java/org/casbin/ClientTest.java b/src/test/java/org/casbin/ClientTest.java
index f275b66..4557a30 100644
--- a/src/test/java/org/casbin/ClientTest.java
+++ b/src/test/java/org/casbin/ClientTest.java
@@ -1,58 +1,44 @@
package org.casbin;
import org.apache.commons.cli.ParseException;
-import org.casbin.jcasbin.main.Enforcer;
import org.junit.Test;
import static org.junit.Assert.assertEquals;
-import static org.junit.Assert.assertTrue;
public class ClientTest {
@Test
public void testRBAC() throws ParseException {
- assertEquals(Client.run(new String[]{"-m","examples/rbac_model.conf","-p","examples/rbac_policy.csv","-e","alice,data1,read"}), true);
- assertEquals(Client.run(new String[]{"-m","examples/rbac_model.conf","-p","examples/rbac_policy.csv","-e","alice,data1,write"}), false);
- assertEquals(Client.run(new String[]{"-m","examples/rbac_model.conf","-p","examples/rbac_policy.csv","-e","alice,data2,read"}), true);
- assertEquals(Client.run(new String[]{"-m","examples/rbac_model.conf","-p","examples/rbac_policy.csv","-e","alice,data2,write"}), true);
- assertEquals(Client.run(new String[]{"-m","examples/rbac_model.conf","-p","examples/rbac_policy.csv","-e","bob,data1,read"}), false);
- assertEquals(Client.run(new String[]{"-m","examples/rbac_model.conf","-p","examples/rbac_policy.csv","-e","bob,data1,write"}), false);
- assertEquals(Client.run(new String[]{"-m","examples/rbac_model.conf","-p","examples/rbac_policy.csv","-e","bob,data2,read"}), false);
- assertEquals(Client.run(new String[]{"-m","examples/rbac_model.conf","-p","examples/rbac_policy.csv","-e","bob,data2,write"}), true);
+ assertEquals(Client.run(new String[]{"enforce","-m","examples/rbac_model.conf","-p","examples/rbac_policy.csv", "alice", "data1", "read"}), "{\"allow\":true,\"explain\":null}");
+ assertEquals(Client.run(new String[]{"enforce","-m","examples/rbac_model.conf","-p","examples/rbac_policy.csv", "alice", "data1", "write"}), "{\"allow\":false,\"explain\":null}");
+ assertEquals(Client.run(new String[]{"enforce","-m","examples/rbac_model.conf","-p","examples/rbac_policy.csv", "alice", "data2", "read"}), "{\"allow\":true,\"explain\":null}");
+ assertEquals(Client.run(new String[]{"enforce","-m","examples/rbac_model.conf","-p","examples/rbac_policy.csv", "alice", "data2", "write"}), "{\"allow\":true,\"explain\":null}");
+ assertEquals(Client.run(new String[]{"enforce","-m","examples/rbac_model.conf","-p","examples/rbac_policy.csv", "bob", "data1", "read"}), "{\"allow\":false,\"explain\":null}");
+ assertEquals(Client.run(new String[]{"enforce","-m","examples/rbac_model.conf","-p","examples/rbac_policy.csv", "bob", "data1", "write"}), "{\"allow\":false,\"explain\":null}");
+ assertEquals(Client.run(new String[]{"enforce","-m","examples/rbac_model.conf","-p","examples/rbac_policy.csv", "bob", "data2", "read"}), "{\"allow\":false,\"explain\":null}");
+ assertEquals(Client.run(new String[]{"enforce","-m","examples/rbac_model.conf","-p","examples/rbac_policy.csv", "bob", "data2", "write"}), "{\"allow\":true,\"explain\":null}");
}
@Test
public void testABAC() throws ParseException {
- assertEquals(Client.run(new String[]{"-m","examples/abac_rule_with_domains_model.conf","-p","examples/abac_rule_with_domains_policy.csv","-e","alice,domain1,data1,read"}), true);
- assertEquals(Client.run(new String[]{"-m","examples/abac_rule_with_domains_model.conf","-p","examples/abac_rule_with_domains_policy.csv","-e","alice,domain1,data1,write"}), true);
- assertEquals(Client.run(new String[]{"-m","examples/abac_rule_with_domains_model.conf","-p","examples/abac_rule_with_domains_policy.csv","-e","alice,domain2,data1,read"}), false);
- assertEquals(Client.run(new String[]{"-m","examples/abac_rule_with_domains_model.conf","-p","examples/abac_rule_with_domains_policy.csv","-e","alice,domain2,data1,write"}), false);
- assertEquals(Client.run(new String[]{"-m","examples/abac_rule_with_domains_model.conf","-p","examples/abac_rule_with_domains_policy.csv","-e","bob,domain1,data2,read"}), false);
- assertEquals(Client.run(new String[]{"-m","examples/abac_rule_with_domains_model.conf","-p","examples/abac_rule_with_domains_policy.csv","-e","bob,domain1,data2,write"}), false);
- assertEquals(Client.run(new String[]{"-m","examples/abac_rule_with_domains_model.conf","-p","examples/abac_rule_with_domains_policy.csv","-e","bob,domain2,data2,read"}), true);
- assertEquals(Client.run(new String[]{"-m","examples/abac_rule_with_domains_model.conf","-p","examples/abac_rule_with_domains_policy.csv","-e","bob,domain2,data2,read"}), true);
- }
+ assertEquals(Client.run(new String[]{"enforce","-m","examples/abac_rule_with_domains_model.conf","-p","examples/abac_rule_with_domains_policy.csv", "alice", "domain1", "data1", "read"}), "{\"allow\":true,\"explain\":null}");
+ assertEquals(Client.run(new String[]{"enforce","-m","examples/abac_rule_with_domains_model.conf","-p","examples/abac_rule_with_domains_policy.csv", "alice","domain1", "data1", "write"}), "{\"allow\":true,\"explain\":null}");
+ assertEquals(Client.run(new String[]{"enforce","-m","examples/abac_rule_with_domains_model.conf","-p","examples/abac_rule_with_domains_policy.csv", "alice", "domain2", "data1", "read"}), "{\"allow\":false,\"explain\":null}");
+ assertEquals(Client.run(new String[]{"enforce","-m","examples/abac_rule_with_domains_model.conf","-p","examples/abac_rule_with_domains_policy.csv", "alice", "domain2", "data1", "write"}), "{\"allow\":false,\"explain\":null}");
+ assertEquals(Client.run(new String[]{"enforce","-m","examples/abac_rule_with_domains_model.conf","-p","examples/abac_rule_with_domains_policy.csv", "bob", "domain1", "data2", "read"}), "{\"allow\":false,\"explain\":null}");
+ assertEquals(Client.run(new String[]{"enforce","-m","examples/abac_rule_with_domains_model.conf","-p","examples/abac_rule_with_domains_policy.csv", "bob", "domain1", "data2", "write"}), "{\"allow\":false,\"explain\":null}");
+ assertEquals(Client.run(new String[]{"enforce","-m","examples/abac_rule_with_domains_model.conf","-p","examples/abac_rule_with_domains_policy.csv", "bob", "domain2", "data2", "read"}), "{\"allow\":true,\"explain\":null}");
+ assertEquals(Client.run(new String[]{"enforce","-m","examples/abac_rule_with_domains_model.conf","-p","examples/abac_rule_with_domains_policy.csv", "bob", "domain2", "data2", "read"}), "{\"allow\":true,\"explain\":null}");
- @Test
- public void testAddPolicy() throws ParseException {
- String modelPath = "examples/rbac_model.conf";
- String policyPath = "examples/rbac_policy.csv";
- Enforcer enforcer = new Enforcer(modelPath, policyPath);
- String policy = "aliceTest,data,read";
- assertEquals(Client.run(new String[]{"-m",modelPath,"-p",policyPath,"-ap",policy}), true);
- enforcer.removePolicy(policy.split(","));
- enforcer.savePolicy();
}
@Test
- public void testRemovePolicy() throws ParseException {
- String modelPath = "examples/rbac_model.conf";
- String policyPath = "examples/rbac_policy.csv";
- Enforcer enforcer = new Enforcer(modelPath, policyPath);
- String policy = "alice,data1,read";
- assertEquals(Client.run(new String[]{"-m",modelPath,"-p",policyPath,"-rp",policy}), true);
- enforcer.addPolicy(policy.split(","));
- enforcer.savePolicy();
+ public void testAddAndRemovePolicy() throws ParseException {
+ assertEquals(Client.run(new String[]{"addPolicy","-m","examples/abac_rule_with_domains_model.conf","-p","examples/abac_rule_with_domains_policy.csv", "alice", "domain1", "data1", "read"}), "{\"allow\":true,\"explain\":null}");
+ assertEquals(Client.run(new String[]{"removePolicy","-m","examples/abac_rule_with_domains_model.conf","-p","examples/abac_rule_with_domains_policy.csv", "alice", "domain1", "data1", "read"}), "{\"allow\":true,\"explain\":null}");
+
+ assertEquals(Client.run(new String[]{"addPolicy","-m","examples/rbac_model.conf","-p","examples/rbac_policy.csv", "alice", "data2", "write"}), "{\"allow\":true,\"explain\":null}");
+ assertEquals(Client.run(new String[]{"removePolicy","-m","examples/rbac_model.conf","-p","examples/rbac_policy.csv", "alice", "data2", "write"}), "{\"allow\":true,\"explain\":null}");
}
@Test
@@ -76,8 +62,177 @@ public void testParseString() {
"p, data2_admin, data2, read\n" +
"p, data2_admin, data2, write\n" +
"g, alice, data2_admin";
- NewEnforcer enforce = new NewEnforcer(model, policy);
- assertTrue(enforce.enforce("alice", "data1", "read"));
+ assertEquals(Client.run(new String[]{"enforce", "-m", model, "-p", policy, "alice", "data1", "read"}), "{\"allow\":true,\"explain\":null}");
+ }
+
+ @Test
+ public void testCustomFunction() throws ParseException {
+ String methodName = "keyMatchTest";
+ String model = "[request_definition]\n" +
+ "r = sub, obj, act\n" +
+ "\n" +
+ "[policy_definition]\n" +
+ "p = sub, obj, act\n" +
+ "\n" +
+ "[policy_effect]\n" +
+ "e = some(where (p.eft == allow))\n" +
+ "\n" +
+ "[matchers]\n" +
+ "m = r.sub == p.sub && "+methodName+"(r.obj, p.obj) && regexMatch(r.act, p.act)\n";
+ String func = "public static boolean "+methodName+"(String key1, String key2) {\n" +
+ " int i = key2.indexOf('*');\n" +
+ " if (i == -1) {\n" +
+ " return key1.equals(key2);\n" +
+ " }\n" +
+ "\n" +
+ " if (key1.length() > i) {\n" +
+ " return key1.substring(0, i).equals(key2.substring(0, i));\n" +
+ " }\n" +
+ " return key1.equals(key2.substring(0, i));\n" +
+ " }";
+ assertEquals(Client.run(new String[]{"enforce", "-m", model, "-p", "examples/keymatch_policy.csv", "-AF", func, "alice", "/alice_data/resource1", "GET"}), "{\"allow\":true,\"explain\":null}");
+ assertEquals(Client.run(new String[]{"enforce", "-m", model, "-p", "examples/keymatch_policy.csv", "-AF", func, "alice", "/alice_data/resource1", "POST"}), "{\"allow\":true,\"explain\":null}");
+ assertEquals(Client.run(new String[]{"enforce", "-m", model, "-p", "examples/keymatch_policy.csv", "-AF", func, "alice", "/alice_data/resource2", "GET"}), "{\"allow\":true,\"explain\":null}");
+ assertEquals(Client.run(new String[]{"enforce", "-m", model, "-p", "examples/keymatch_policy.csv", "-AF", func, "alice", "/alice_data/resource2", "POST"}), "{\"allow\":false,\"explain\":null}");
+ assertEquals(Client.run(new String[]{"enforce", "-m", model, "-p", "examples/keymatch_policy.csv", "-AF", func, "alice", "/bob_data/resource1", "GET"}), "{\"allow\":false,\"explain\":null}");
+ assertEquals(Client.run(new String[]{"enforce", "-m", model, "-p", "examples/keymatch_policy.csv", "-AF", func, "alice", "/bob_data/resource1", "POST"}), "{\"allow\":false,\"explain\":null}");
+ assertEquals(Client.run(new String[]{"enforce", "-m", model, "-p", "examples/keymatch_policy.csv", "-AF", func, "alice", "/bob_data/resource2", "GET"}), "{\"allow\":false,\"explain\":null}");
+ assertEquals(Client.run(new String[]{"enforce", "-m", model, "-p", "examples/keymatch_policy.csv", "-AF", func, "alice", "/bob_data/resource2", "POST"}), "{\"allow\":false,\"explain\":null}");
+
+ assertEquals(Client.run(new String[]{"enforce", "-m", model, "-p", "examples/keymatch_policy.csv", "-AF", func, "bob", "/alice_data/resource1", "GET"}), "{\"allow\":false,\"explain\":null}");
+ assertEquals(Client.run(new String[]{"enforce", "-m", model, "-p", "examples/keymatch_policy.csv", "-AF", func, "bob", "/alice_data/resource1", "POST"}), "{\"allow\":false,\"explain\":null}");
+ assertEquals(Client.run(new String[]{"enforce", "-m", model, "-p", "examples/keymatch_policy.csv", "-AF", func, "bob", "/alice_data/resource2", "GET"}), "{\"allow\":true,\"explain\":null}");
+ assertEquals(Client.run(new String[]{"enforce", "-m", model, "-p", "examples/keymatch_policy.csv", "-AF", func, "bob", "/alice_data/resource2", "POST"}), "{\"allow\":false,\"explain\":null}");
+ assertEquals(Client.run(new String[]{"enforce", "-m", model, "-p", "examples/keymatch_policy.csv", "-AF", func, "bob", "/bob_data/resource1", "GET"}), "{\"allow\":false,\"explain\":null}");
+ assertEquals(Client.run(new String[]{"enforce", "-m", model, "-p", "examples/keymatch_policy.csv", "-AF", func, "bob", "/bob_data/resource1", "POST"}), "{\"allow\":true,\"explain\":null}");
+ assertEquals(Client.run(new String[]{"enforce", "-m", model, "-p", "examples/keymatch_policy.csv", "-AF", func, "bob", "/bob_data/resource2", "GET"}), "{\"allow\":false,\"explain\":null}");
+ assertEquals(Client.run(new String[]{"enforce", "-m", model, "-p", "examples/keymatch_policy.csv", "-AF", func, "bob", "/bob_data/resource2", "POST"}), "{\"allow\":true,\"explain\":null}");
+
+ assertEquals(Client.run(new String[]{"enforce", "-m", model, "-p", "examples/keymatch_policy.csv", "-AF", func, "cathy", "/cathy_data", "GET"}), "{\"allow\":true,\"explain\":null}");
+ assertEquals(Client.run(new String[]{"enforce", "-m", model, "-p", "examples/keymatch_policy.csv", "-AF", func, "cathy", "/cathy_data", "POST"}), "{\"allow\":true,\"explain\":null}");
+ assertEquals(Client.run(new String[]{"enforce", "-m", model, "-p", "examples/keymatch_policy.csv", "-AF", func, "cathy", "/cathy_data", "DELETE"}), "{\"allow\":false,\"explain\":null}");
+
+ }
+
+ @Test
+ public void testEnforce() {
+ assertEquals(Client.run(new String[]{"enforce", "-m", "examples/rbac_model.conf", "-p", "examples/rbac_policy.csv", "alice", "data1", "read"}), "{\"allow\":true,\"explain\":null}");
+ }
+
+ @Test
+ public void testManagementApi() {
+ assertEquals(Client.run(new String[]{"enforce","-m","examples/rbac_model.conf","-p","examples/rbac_policy.csv", "alice", "data1", "read"}), "{\"allow\":true,\"explain\":null}");
+
+ String matcher = "m = r.sub == 'root' || r.sub == p.sub && r.obj == p.obj && r.act == p.act";
+ assertEquals(Client.run(new String[]{"enforceWithMatcher","-m","examples/basic_model.conf", "-p", "examples/basic_policy.csv", matcher, "alice", "data1", "read"}), "{\"allow\":true,\"explain\":null}");
+
+ assertEquals(Client.run(new String[]{"enforceEx", "-m", "examples/rbac_model.conf", "-p", "examples/rbac_policy.csv", "alice", "data1", "read"}), "{\"allow\":true,\"explain\":[\"alice\",\"data1\",\"read\"]}");
+
+ assertEquals(Client.run(new String[]{"enforceExWithMatcher", "-m", "examples/basic_model.conf", "-p", "examples/basic_policy.csv", matcher, "alice", "data1", "read"}), "{\"allow\":true,\"explain\":[\"alice\",\"data1\",\"read\"]}");
+
+ assertEquals(Client.run(new String[]{"batchEnforce", "-m", "examples/basic_model.conf", "-p", "examples/basic_policy.csv", "alice,data1,read", "bob,data2,write", "jack,data3,read"}), "{\"allow\":null,\"explain\":[true,true,false]}");
+
+ assertEquals(Client.run(new String[]{"getAllSubjects", "-m", "examples/rbac_model.conf", "-p", "examples/rbac_policy.csv", "alice", "data1", "read"}), "{\"allow\":null,\"explain\":[\"alice\",\"bob\",\"data2_admin\"]}");
+
+ assertEquals(Client.run(new String[]{"getAllObjects", "-m", "examples/rbac_model.conf", "-p", "examples/rbac_policy.csv", "alice", "data1", "read"}), "{\"allow\":null,\"explain\":[\"data1\",\"data2\"]}");
+
+ assertEquals(Client.run(new String[]{"getAllNamedSubjects", "-m", "examples/abac_rule_with_domains_model.conf", "-p", "examples/abac_rule_with_domains_policy.csv", "p"}), "{\"allow\":null,\"explain\":[\"r.domain == 'domain1'\",\"r.domain == 'domain2'\"]}");
+
+ assertEquals(Client.run(new String[]{"getAllNamedObjects", "-m", "examples/abac_rule_with_domains_model.conf", "-p", "examples/abac_rule_with_domains_policy.csv", "p"}), "{\"allow\":null,\"explain\":[\"admin\"]}");
+
+ assertEquals(Client.run(new String[]{"getAllActions", "-m", "examples/rbac_model.conf", "-p", "examples/rbac_policy.csv"}), "{\"allow\":null,\"explain\":[\"read\",\"write\"]}");
+
+ assertEquals(Client.run(new String[]{"getAllNamedActions", "-m", "examples/rbac_model.conf", "-p", "examples/rbac_policy.csv", "p"}), "{\"allow\":null,\"explain\":[\"read\",\"write\"]}");
+
+ assertEquals(Client.run(new String[]{"getAllRoles", "-m", "examples/rbac_model.conf", "-p", "examples/rbac_policy.csv"}), "{\"allow\":null,\"explain\":[\"data2_admin\"]}");
+
+ assertEquals(Client.run(new String[]{"getAllNamedRoles", "-m", "examples/rbac_model.conf", "-p", "examples/rbac_policy.csv", "g"}), "{\"allow\":null,\"explain\":[\"data2_admin\"]}");
+
+ assertEquals(Client.run(new String[]{"getPolicy", "-m", "examples/rbac_model.conf", "-p", "examples/rbac_policy.csv"}), "{\"allow\":null,\"explain\":[[\"alice\",\"data1\",\"read\"],[\"bob\",\"data2\",\"write\"],[\"data2_admin\",\"data2\",\"read\"],[\"data2_admin\",\"data2\",\"write\"]]}");
+
+ assertEquals(Client.run(new String[]{"getFilteredPolicy", "-m", "examples/rbac_model.conf", "-p", "examples/rbac_policy.csv", "0", "alice"}), "{\"allow\":null,\"explain\":[[\"alice\",\"data1\",\"read\"]]}");
+
+ assertEquals(Client.run(new String[]{"getNamedPolicy", "-m", "examples/rbac_model.conf", "-p", "examples/rbac_policy.csv", "p"}), "{\"allow\":null,\"explain\":[[\"alice\",\"data1\",\"read\"],[\"bob\",\"data2\",\"write\"],[\"data2_admin\",\"data2\",\"read\"],[\"data2_admin\",\"data2\",\"write\"]]}");
+
+ assertEquals(Client.run(new String[]{"getFilteredNamedPolicy", "-m", "examples/rbac_model.conf", "-p", "examples/rbac_policy.csv", "p", "0", "bob"}), "{\"allow\":null,\"explain\":[[\"bob\",\"data2\",\"write\"]]}");
+
+ assertEquals(Client.run(new String[]{"getGroupingPolicy", "-m", "examples/rbac_model.conf", "-p", "examples/rbac_policy.csv"}), "{\"allow\":null,\"explain\":[[\"alice\",\"data2_admin\"]]}");
+
+ assertEquals(Client.run(new String[]{"getFilteredGroupingPolicy", "-m", "examples/rbac_model.conf", "-p", "examples/rbac_policy.csv", "0", "alice"}), "{\"allow\":null,\"explain\":[[\"alice\",\"data2_admin\"]]}");
+
+ assertEquals(Client.run(new String[]{"getNamedGroupingPolicy", "-m", "examples/rbac_model.conf", "-p", "examples/rbac_policy.csv", "g"}), "{\"allow\":null,\"explain\":[[\"alice\",\"data2_admin\"]]}");
+
+ assertEquals(Client.run(new String[]{"getFilteredNamedGroupingPolicy", "-m", "examples/rbac_model.conf", "-p", "examples/rbac_policy.csv", "g", "0", "alice"}), "{\"allow\":null,\"explain\":[[\"alice\",\"data2_admin\"]]}");
+
+ assertEquals(Client.run(new String[]{"hasPolicy", "-m", "examples/rbac_model.conf", "-p", "examples/rbac_policy.csv", "alice", "data1", "read"}), "{\"allow\":true,\"explain\":null}");
+
+ assertEquals(Client.run(new String[]{"hasNamedPolicy", "-m", "examples/rbac_model.conf", "-p", "examples/rbac_policy.csv", "p", "alice", "data1", "read"}), "{\"allow\":true,\"explain\":null}");
+
+ assertEquals(Client.run(new String[]{"addPolicy", "-m", "examples/rbac_model.conf", "-p", "examples/rbac_policy.csv", "eve", "data3", "read"}), "{\"allow\":true,\"explain\":null}");
+
+ assertEquals(Client.run(new String[]{"removePolicy", "-m", "examples/rbac_model.conf", "-p", "examples/rbac_policy.csv", "eve", "data3", "read"}), "{\"allow\":true,\"explain\":null}");
+
+ assertEquals(Client.run(new String[]{"addPolicies", "-m", "examples/rbac_model.conf", "-p", "examples/rbac_policy.csv", "jack,data4,read","katy,data4,write"}), "{\"allow\":true,\"explain\":null}");
+
+ assertEquals(Client.run(new String[]{"removePolicies", "-m", "examples/rbac_model.conf", "-p", "examples/rbac_policy.csv", "jack,data4,read","katy,data4,write"}), "{\"allow\":true,\"explain\":null}");
+
+ assertEquals(Client.run(new String[]{"addNamedPolicy", "-m", "examples/rbac_model.conf", "-p", "examples/rbac_policy.csv", "p", "eve", "data3", "read"}), "{\"allow\":true,\"explain\":null}");
+
+ assertEquals(Client.run(new String[]{"removeNamedPolicy", "-m", "examples/rbac_model.conf", "-p", "examples/rbac_policy.csv", "p", "eve", "data3", "read"}), "{\"allow\":true,\"explain\":null}");
+
+ assertEquals(Client.run(new String[]{"addNamedPolicies", "-m", "examples/rbac_model.conf", "-p", "examples/rbac_policy.csv", "p", "jack,data4,read","katy,data4,write"}), "{\"allow\":true,\"explain\":null}");
+
+ assertEquals(Client.run(new String[]{"hasGroupingPolicy", "-m", "examples/rbac_model.conf", "-p", "examples/rbac_policy.csv", "alice", "data2_admin"}), "{\"allow\":true,\"explain\":null}");
+
+ assertEquals(Client.run(new String[]{"hasNamedGroupingPolicy", "-m", "examples/rbac_model.conf", "-p", "examples/rbac_policy.csv", "g", "alice", "data2_admin"}), "{\"allow\":true,\"explain\":null}");
+
+ assertEquals(Client.run(new String[]{"addGroupingPolicy", "-m", "examples/rbac_model.conf", "-p", "examples/rbac_policy.csv", "group1", "data2_admin"}), "{\"allow\":true,\"explain\":null}");
+
+ assertEquals(Client.run(new String[]{"updateGroupingPolicy", "-m", "examples/rbac_model.conf", "-p", "examples/rbac_policy.csv", "group1,data2_admin","group2,data3_admin"}), "{\"allow\":true,\"explain\":null}");
+
+ assertEquals(Client.run(new String[]{"removeGroupingPolicy", "-m", "examples/rbac_model.conf", "-p", "examples/rbac_policy.csv", "group2", "data3_admin"}), "{\"allow\":true,\"explain\":null}");
+
+ assertEquals(Client.run(new String[]{"addGroupingPolicies", "-m", "examples/rbac_model.conf", "-p", "examples/rbac_policy.csv", "ham,data4_admin","jack,data5_admin"}), "{\"allow\":true,\"explain\":null}");
+
+ assertEquals(Client.run(new String[]{"removeGroupingPolicies", "-m", "examples/rbac_model.conf", "-p", "examples/rbac_policy.csv", "ham,data4_admin","jack,data5_admin"}), "{\"allow\":true,\"explain\":null}");
+
+ assertEquals(Client.run(new String[]{"addNamedGroupingPolicy", "-m", "examples/rbac_model.conf", "-p", "examples/rbac_policy.csv", "g", "group2", "data2_admin"}), "{\"allow\":true,\"explain\":null}");
+
+ assertEquals(Client.run(new String[]{"removeNamedGroupingPolicy", "-m", "examples/rbac_model.conf", "-p", "examples/rbac_policy.csv", "g", "group2", "data2_admin"}), "{\"allow\":true,\"explain\":null}");
+
+ assertEquals(Client.run(new String[]{"addNamedGroupingPolicies", "-m", "examples/rbac_model.conf", "-p", "examples/rbac_policy.csv", "g", "ham,data4_admin","jack,data5_admin"}), "{\"allow\":true,\"explain\":null}");
+
+ assertEquals(Client.run(new String[]{"removeNamedGroupingPolicies", "-m", "examples/rbac_model.conf", "-p", "examples/rbac_policy.csv", "g", "ham,data4_admin","jack,data5_admin"}), "{\"allow\":true,\"explain\":null}");
+
+ assertEquals(Client.run(new String[]{"removeFilteredGroupingPolicy", "-m", "examples/rbac_model.conf", "-p", "examples/rbac_policy.csv", "0", "alice"}), "{\"allow\":true,\"explain\":null}");
+
+ assertEquals(Client.run(new String[]{"addNamedGroupingPolicy", "-m", "examples/rbac_model.conf", "-p", "examples/rbac_policy.csv", "g", "alice", "data2_admin"}), "{\"allow\":true,\"explain\":null}");
+
+ assertEquals(Client.run(new String[]{"removeFilteredNamedGroupingPolicy", "-m", "examples/rbac_model.conf", "-p", "examples/rbac_policy.csv", "g", "0", "alice"}), "{\"allow\":true,\"explain\":null}");
+
+ assertEquals(Client.run(new String[]{"addNamedGroupingPolicy", "-m", "examples/rbac_model.conf", "-p", "examples/rbac_policy.csv", "g", "alice", "data2_admin"}), "{\"allow\":true,\"explain\":null}");
+
+ assertEquals(Client.run(new String[]{"updatePolicy", "-m", "examples/rbac_model.conf", "-p", "examples/rbac_policy.csv", "alice,data1,read","alice,data1,write"}), "{\"allow\":true,\"explain\":null}");
+
+ assertEquals(Client.run(new String[]{"updatePolicy", "-m", "examples/rbac_model.conf", "-p", "examples/rbac_policy.csv", "alice,data1,write","alice,data1,read"}), "{\"allow\":true,\"explain\":null}");
+
+
+ assertEquals(Client.run(new String[]{"updateNamedGroupingPolicy", "-m", "examples/rbac_model.conf", "-p", "examples/rbac_policy.csv", "g", "alice,data2_admin","admin,data4_admin"}), "{\"allow\":true,\"explain\":null}");
+
+ assertEquals(Client.run(new String[]{"updateNamedGroupingPolicy", "-m", "examples/rbac_model.conf", "-p", "examples/rbac_policy.csv", "g", "admin,data4_admin","alice,data2_admin"}), "{\"allow\":true,\"explain\":null}");
+
+ assertEquals(Client.run(new String[]{"removeNamedPolicies", "-m", "examples/rbac_model.conf", "-p", "examples/rbac_policy.csv", "p", "jack,data4,read","katy,data4,write"}), "{\"allow\":true,\"explain\":null}");
+
+ assertEquals(Client.run(new String[]{"removeFilteredPolicy", "-m", "examples/rbac_model.conf", "-p", "examples/rbac_policy.csv", "0", "alice", "data1", "read"}), "{\"allow\":true,\"explain\":null}");
+
+ assertEquals(Client.run(new String[]{"removeFilteredNamedPolicy", "-m", "examples/rbac_model.conf", "-p", "examples/rbac_policy.csv", "p", "0", "bob"}), "{\"allow\":true,\"explain\":null}");
+
+ assertEquals(Client.run(new String[]{"removePolicy","-m","examples/rbac_model.conf","-p","examples/rbac_policy.csv", "data2_admin", "data2", "read"}), "{\"allow\":true,\"explain\":null}");
+
+ assertEquals(Client.run(new String[]{"removePolicy","-m","examples/rbac_model.conf","-p","examples/rbac_policy.csv", "data2_admin", "data2", "write"}), "{\"allow\":true,\"explain\":null}");
+
+ assertEquals(Client.run(new String[]{"addPolicies", "-m", "examples/rbac_model.conf", "-p", "examples/rbac_policy.csv","alice,data1,read","bob,data2,write","data2_admin,data2,read","data2_admin,data2,write"}), "{\"allow\":true,\"explain\":null}");
+
}
}