Skip to content

Commit

Permalink
feat: use reflection and support Management API (#18)
Browse files Browse the repository at this point in the history
  • Loading branch information
liewstar authored Oct 24, 2024
1 parent 49b01e1 commit c0a9668
Show file tree
Hide file tree
Showing 18 changed files with 365 additions and 699 deletions.
18 changes: 9 additions & 9 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -24,7 +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 `\|` |
| `-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 `""` |

Expand All @@ -35,30 +35,30 @@ mvn clean install
```shell
./casbin enforce -m "examples/rbac_model.conf" -p "examples/rbac_policy.csv" "alice" "data1" "read"
```
> Allowed
> {"allow":true,"explain":null}
```shell
./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"
```
> Allowed
> {"allow":true,"explain":null}

- Check whether Alice has write permission for data2. If so, display the effective policy.

```shell
./casbin -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
./casbin -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
./casbin -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}

11 changes: 11 additions & 0 deletions examples/basic_model.conf
Original file line number Diff line number Diff line change
@@ -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
2 changes: 2 additions & 0 deletions examples/basic_policy.csv
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
p, alice, data1, read
p, bob, data2, write
6 changes: 6 additions & 0 deletions pom.xml
Original file line number Diff line number Diff line change
Expand Up @@ -25,6 +25,12 @@
<version>1.4</version>
</dependency>

<dependency>
<groupId>com.fasterxml.jackson.core</groupId>
<artifactId>jackson-databind</artifactId>
<version>2.13.4.2</version>
</dependency>

<dependency>
<groupId>junit</groupId>
<artifactId>junit</artifactId>
Expand Down
116 changes: 37 additions & 79 deletions src/main/java/org/casbin/Client.java
Original file line number Diff line number Diff line change
Expand Up @@ -2,37 +2,15 @@


import org.apache.commons.cli.*;
import org.casbin.command.*;
import org.casbin.generate.DynamicClassGenerator;
import org.casbin.jcasbin.util.function.CustomFunction;
import org.casbin.util.Util;


import java.util.Arrays;
import java.util.HashMap;
import java.util.Map;
import java.util.*;


public class Client {

private static final String RBAC_COMMAND = "rbac";
private static final String RBAC_WITH_CONDITION_COMMAND = "rbac_with_condition";
private static final String RBAC_WITH_DOMAINS_COMMAND = "rbac_with_domains";
private static final String ROLEMANAGER_COMMAND = "role_manager";
private static final String MANAGEMENT_COMMAND = "management";
private static final String ENFORCE_COMMAND = "enforce";

private static final Map<String, AbstractCommand> COMMANDS = new HashMap<>();

static {
COMMANDS.put(RBAC_COMMAND, new RBACCommand());
COMMANDS.put(RBAC_WITH_CONDITION_COMMAND, new RBACWithConditionsCommand());
COMMANDS.put(RBAC_WITH_DOMAINS_COMMAND, new RBACWithDomainsCommand());
COMMANDS.put(ROLEMANAGER_COMMAND, new RoleManagerCommand());
COMMANDS.put(MANAGEMENT_COMMAND, new ManagementCommand());
COMMANDS.put(ENFORCE_COMMAND, new EnforceCommand());
}

public static String run(String... args) {
String result = "";

Expand All @@ -41,64 +19,25 @@ public static String run(String... args) {
printUsageMessageAndExit("");
}

Options options = new Options();
Option option = new Option("m", "model", true, "the path of the model file or model text");
options.addOption(option);
option = new Option("p", "policy", true, "the path of the policy file or policy text");
options.addOption(option);
option = new Option("af", "addFunction", true, "add custom function");
option.setRequired(false);
options.addOption(option);

boolean hasAddFuntion = false;
for (String arg : args) {
if(arg.equals("-af") || arg.equals("-addFunction")) {
hasAddFuntion = true;
break;
}
}
String commandName = args[0];

CommandLineParser parser = new DefaultParser();
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);

CommandLine cmd = null;
if(hasAddFuntion) {
cmd = parser.parse(options, Arrays.stream(args).limit(7).toArray(String[]::new));
} else {
cmd = parser.parse(options, Arrays.stream(args).limit(5).toArray(String[]::new));
}

if(cmd.hasOption("model") && cmd.hasOption("policy")) {
String model = cmd.getOptionValue("model");
String policy = cmd.getOptionValue("policy");
NewEnforcer enforcer = new NewEnforcer(model, policy);

if (hasAddFuntion) {
String codes = cmd.getOptionValue("addFunction");
String methodName = Util.getMethodName(codes);
CustomFunction customFunction = DynamicClassGenerator.generateClass(methodName, codes);
enforcer.addFunction(methodName, customFunction);
}

String commandName = args[0];
AbstractCommand command = COMMANDS.get(commandName);



if(command != null) {
if(hasAddFuntion) {
result = command.run(enforcer, Arrays.copyOfRange(args, 7, args.length));
} else {
result = command.run(enforcer, Arrays.copyOfRange(args, 5, args.length));
}
// System.exit(0);
} else {
printUsageMessageAndExit(commandName);
}

} else {
new HelpCommand().run();
System.exit(1);
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) {
e.printStackTrace();
System.exit(1);
Expand All @@ -111,12 +50,31 @@ private static void printUsageMessageAndExit(String commandName) throws Exceptio
if (commandName.isEmpty()) {
System.out.println("Error: " + commandName + " not recognised");
}

new HelpCommand().run();
// new HelpCommand().run();
System.exit(1);
}

public static void main(String[] args) throws ParseException {
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);
}
}
94 changes: 94 additions & 0 deletions src/main/java/org/casbin/CommandExecutor.java
Original file line number Diff line number Diff line change
@@ -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<java.lang.String>") && genericParameterTypes[2].getTypeName().equals("java.util.List<java.lang.String>")) {
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<java.lang.String>") && genericParameterTypes[1].getTypeName().equals("java.util.List<java.lang.String>")) {
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<java.lang.String>")) {
String[] arr = Arrays.copyOfRange(inputVal, i, inputVal.length);
convertedParams[i] = Arrays.asList(arr);
} else if (genericParameterTypes[i].getTypeName().equals("java.util.List<java.util.List<java.lang.String>>")) {
List<List<String>> res = new ArrayList<>();
String[] arr = Arrays.copyOfRange(inputVal, i, inputVal.length);
for (String s : arr) {
List<String> 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);
}
}
12 changes: 0 additions & 12 deletions src/main/java/org/casbin/command/AbstractCommand.java

This file was deleted.

15 changes: 0 additions & 15 deletions src/main/java/org/casbin/command/EnforceCommand.java

This file was deleted.

8 changes: 0 additions & 8 deletions src/main/java/org/casbin/command/HelpCommand.java

This file was deleted.

Loading

0 comments on commit c0a9668

Please sign in to comment.