Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

How to define new matcher function? #10

Closed
M-Razavi opened this issue Jan 23, 2019 · 13 comments
Closed

How to define new matcher function? #10

M-Razavi opened this issue Jan 23, 2019 · 13 comments
Assignees
Labels

Comments

@M-Razavi
Copy link
Contributor

M-Razavi commented Jan 23, 2019

I've written a function but now how should add it to function map?

public class InCollectionFunc extends AbstractFunction {
    public InCollectionFunc() {
    }

    public AviatorObject call(Map<String, Object> env, AviatorObject arg1, AviatorObject arg2, AviatorObject arg3) {
        String value = FunctionUtils.getStringValue(arg1, env);
        String collection = FunctionUtils.getStringValue(arg3, env);
        return AviatorBoolean.valueOf(isInCollection(value, collection));
    }

    private boolean isInCollection(String value,String collection) {
        System.out.println("value:" + value + " isIn collection:" + collection);
        return true;
    }

    public String getName() {
        return getNameStatic();
    }

    public static String getNameStatic() {
        return "isIn";
    }
}
enforcer = new Enforcer("erole.conf", "policy.csv");
enforcer.addFunction(InCollectionFunc.getNameStatic(),new InCollectionFunc());
@hsluoyz
Copy link
Member

hsluoyz commented Jan 23, 2019

What you did now is correct, just call Enforcer.addFunction():

/**
* addFunction adds a customized function.
*
* @param name the name of the new function.
* @param function the function.
*/
public void addFunction(String name, AviatorFunction function) {
fm.addFunction(name, function);
}
}

It's very similar to Golang's Casbin, which is documented here: https://casbin.org/docs/en/syntax-for-models#how-to-add-a-customized-function

@hsluoyz hsluoyz self-assigned this Jan 23, 2019
@M-Razavi
Copy link
Contributor Author

I've used enforcer.addFunction() but got an error:
com.googlecode.aviator.exception.ExpressionSyntaxErrorException: Syntax error:Unexpect token 'isIn' at 32, current token: [type='variable',lexeme='isIn',index=32]. Parsing expression: r_act == "View" && r_obj.branch isIn^^

@hsluoyz
Copy link
Member

hsluoyz commented Jan 23, 2019

Can you paste all your code here? including Enforcer setup, enforce() call, model text, policy text.

@M-Razavi
Copy link
Contributor Author

M-Razavi commented Jan 23, 2019

This is set up and call :

enforcer = new Enforcer("role.conf", "policy.csv");
enforcer.addFunction(InCollectionFunc.getNameStatic(),new InCollectionFunc());
enforcer.addFunction(TimeValidityFunc.getNameStatic(),new TimeValidityFunc());
if (enforcer.enforce("cathy", "order1", "view")) {
        System.out.println("ok");
}

And this is model:

[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 = r.act == "View" && r.obj.branch isIn(r.sub.branch) || g(r.sub, "Manager") && r.act == "View" ||  isValidTimeForUser(r.sub) || g(r.sub, "Manager") && (r.act == "Confirm" || r.act == "Reject")  || g(r.sub, "Operator") && (r.act == "Create" || r.act == "Edit") || g(r.sub, "Reviewer") && r.obj.status== "confirmed"

Policy file is empty.

@M-Razavi
Copy link
Contributor Author

M-Razavi commented Jan 23, 2019

Time function:

import com.googlecode.aviator.runtime.function.AbstractFunction;
import com.googlecode.aviator.runtime.function.FunctionUtils;
import com.googlecode.aviator.runtime.type.AviatorBoolean;
import com.googlecode.aviator.runtime.type.AviatorObject;

import java.time.LocalTime;
import java.util.Map;

/**
 * Created by Mahdi Razavi on 1/22/19-4:06 PM
 */
public class TimeValidityFunc extends AbstractFunction {

    public TimeValidityFunc() {
    }

    public AviatorObject call(Map<String, Object> env, AviatorObject arg1, AviatorObject arg2, AviatorObject arg3) {
        String actionTime = FunctionUtils.getStringValue(arg1, env);
        String validityTimeStart = FunctionUtils.getStringValue(arg2, env);
        String validityTimeEnd = FunctionUtils.getStringValue(arg3, env);
        return AviatorBoolean.valueOf(isTimeMatch(actionTime, validityTimeStart, validityTimeEnd));
//        return AviatorBoolean.valueOf(BuiltInFunctions.keyMatch(key1, key2));
    }


    private boolean isTimeMatch(String actionTime, String validityTimeStart, String validityTimeEnd) {
        LocalTime actTime = LocalTime.parse(actionTime);
        LocalTime tStart = LocalTime.parse(validityTimeStart);
        LocalTime tEnd = LocalTime.parse(validityTimeEnd);

        return actTime.compareTo(tStart) >= 0 && actTime.compareTo(tEnd) <= 0;

    }

    private boolean isValidTimeForUser(String userName) {
        System.out.println("User:" + userName + " wants to do action");

        return true;
    }

    public String getName() {
        return getNameStatic();
    }

    public static String getNameStatic() {
        return "isValidTimeForUser";
    }
}

and isIn function

import com.googlecode.aviator.runtime.function.AbstractFunction;
import com.googlecode.aviator.runtime.function.FunctionUtils;
import com.googlecode.aviator.runtime.type.AviatorBoolean;
import com.googlecode.aviator.runtime.type.AviatorObject;

import java.time.LocalTime;
import java.util.Map;

/**
 * Created by Mahdi Razavi on 1/22/19-4:06 PM
 */
public class InCollectionFunc extends AbstractFunction {

    public InCollectionFunc() {
    }

    public AviatorObject call(Map<String, Object> env, AviatorObject arg1, AviatorObject arg2, AviatorObject arg3) {
        String value = FunctionUtils.getStringValue(arg1, env);
        String collection = FunctionUtils.getStringValue(arg3, env);
        return AviatorBoolean.valueOf(isInCollection(value, collection));
    }



    private boolean isInCollection(String value,String collection) {
        System.out.println("value:" + value + " isIn collection:" + collection);

        return true;
    }

    public String getName() {
        return getNameStatic();
    }

    public static String getNameStatic() {
        return "isIn";
    }


}

@hsluoyz
Copy link
Member

hsluoyz commented Jan 23, 2019

Your matcher is not correct. From your function's code, it has three arguments: AviatorObject arg1, AviatorObject arg2, AviatorObject arg3. BTW, I didn't see you are using the 2nd arg.

So your matcher should be: isIn(arg1, arg2, arg3) instead of r.obj.branch isIn(r.sub.branch).

@M-Razavi
Copy link
Contributor Author

@hsluoyz Many Thanks

@M-Razavi
Copy link
Contributor Author

M-Razavi commented Jan 23, 2019

I got this error:
Could not find variable r_obj.branch
@hsluoyz How should I set the field of request variable?

@M-Razavi M-Razavi reopened this Jan 23, 2019
@M-Razavi
Copy link
Contributor Author

I think this is a bug in aviator which I fixed it
killme2008/aviatorscript#106

@hsluoyz
Copy link
Member

hsluoyz commented Jan 23, 2019

What does that PR mean? I'm not a Java expert and didn't quite understand it.

BTW, I already asked Aviator's author to review your PR :)

@M-Razavi
Copy link
Contributor Author

It seems that recent commit merged in Aviator and it needed to use the latest version of it in JCasbin dependency.

@hsluoyz
Copy link
Member

hsluoyz commented Jan 24, 2019

@M-Razavi Aviator needs to release a new version before jCasbin can import it. You can ask its author to release one and I will release a new version jCasbin based on it.

@hsluoyz
Copy link
Member

hsluoyz commented Oct 19, 2019

@M-Razavi jCasbin 1.2.0 has been released to Maven, may need some time for cache: https://mvnrepository.com/artifact/org.casbin/jcasbin

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
Projects
None yet
Development

No branches or pull requests

2 participants