Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions src/main/java/org/casbin/jcasbin/model/FunctionMap.java
Original file line number Diff line number Diff line change
Expand Up @@ -84,6 +84,7 @@ public static FunctionMap loadFunctionMap() {
fm.addFunction("keyMatch5", new KeyMatch5Func());
fm.addFunction("keyGet", new KeyGetFunc());
fm.addFunction("keyGet2", new KeyGet2Func());
fm.addFunction("keyGet3", new KeyGet3Func());
fm.addFunction("regexMatch", new RegexMatchFunc());
fm.addFunction("ipMatch", new IPMatchFunc());
fm.addFunction("eval", new EvalFunc());
Expand Down
41 changes: 41 additions & 0 deletions src/main/java/org/casbin/jcasbin/util/BuiltInFunctions.java
Original file line number Diff line number Diff line change
Expand Up @@ -275,6 +275,47 @@ public static String keyGet2Func(String key1, String key2, String pathVar) {
return "";
}

/**
* KeyGet3 returns value matched pattern. For example, "/resource1" matches "/{resource}", if the pathVar == "resource", then "resource1" will be returned.
* This is similar with KeyGet2(), except using "/proxy/{id}" instead of "/proxy/:id".
*
* @param key1 the first argument.
* @param key2 the second argument.
* @param pathVar the name of the variable to retrieve from the matched pattern.
* @return the matched part.
*/
public static String keyGet3Func(String key1, String key2, String pathVar) {
key2 = key2.replace("/*", "/.*");
String regexp = "\\{[^/]+?\\}";
Pattern re = Pattern.compile(regexp);
Matcher keys = re.matcher(key2);
List<String> keysList = new ArrayList<>();
while (keys.find()) {
keysList.add(keys.group());
}
key2 = re.matcher(key2).replaceAll("([^/]+?)");
// Escape { and } for Java regex compatibility since { is treated as repetition quantifier
key2 = key2.replace("{", "\\{").replace("}", "\\}");
key2 = "^" + key2 + "$";
Pattern re2 = Pattern.compile(key2);
Matcher values = re2.matcher(key1);
List<String> valuesList = new ArrayList<>();
while (values.find()) {
for (int i = 0; i <= values.groupCount(); i++) {
valuesList.add(values.group(i));
}
}
if (valuesList.isEmpty()) {
return "";
}
for (int i = 0; i < keysList.size(); i++) {
if (pathVar.equals(keysList.get(i).substring(1, keysList.get(i).length() - 1))) {
return valuesList.get(i + 1);
}
}
return "";
}

/**
* regexMatch determines whether key1 matches the pattern of key2 in regular expression.
*
Expand Down
47 changes: 47 additions & 0 deletions src/main/java/org/casbin/jcasbin/util/function/KeyGet3Func.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,47 @@
/*
* Copyright 2021 The casbin Authors. All Rights Reserved.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/

package org.casbin.jcasbin.util.function;

import com.googlecode.aviator.runtime.function.AbstractFunction;
import com.googlecode.aviator.runtime.function.FunctionUtils;
import com.googlecode.aviator.runtime.type.AviatorObject;
import com.googlecode.aviator.runtime.type.AviatorString;
import org.casbin.jcasbin.util.BuiltInFunctions;

import java.util.Map;

/**
* KeyGet3Func is the wrapper for keyGet3.
*
* @author yanglif
* @since 2021/02/09
*/
public class KeyGet3Func extends AbstractFunction {
@Override
public AviatorObject call(Map<String, Object> env, AviatorObject arg1, AviatorObject arg2, AviatorObject arg3) {
String key1 = FunctionUtils.getStringValue(arg1, env);
String key2 = FunctionUtils.getStringValue(arg2, env);
String pathVar = FunctionUtils.getStringValue(arg3, env);

return new AviatorString(BuiltInFunctions.keyGet3Func(key1, key2, pathVar));
}

@Override
public String getName() {
return "keyGet3";
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -214,6 +214,46 @@ public void TestKeyGet2() {
testKeyGet2("/alice/all", "/:/all", "", "");
}

@Test
public void testKeyGet3Func() {
// KeyGet3() is similar with KeyGet2(), except using "/proxy/{id}" instead of "/proxy/:id".
testKeyGet3("/foo", "/foo", "id", "");
testKeyGet3("/foo", "/foo*", "id", "");
testKeyGet3("/foo", "/foo/*", "id", "");
testKeyGet3("/foo/bar", "/foo", "id", "");
testKeyGet3("/foo/bar", "/foo*", "id", "");
testKeyGet3("/foo/bar", "/foo/*", "id", "");
testKeyGet3("/foobar", "/foo", "id", "");
testKeyGet3("/foobar", "/foo*", "id", "");
testKeyGet3("/foobar", "/foo/*", "id", "");

testKeyGet3("/", "/{resource}", "resource", "");
testKeyGet3("/resource1", "/{resource}", "resource", "resource1");
testKeyGet3("/myid", "/{id}/using/{resId}", "id", "");
testKeyGet3("/myid/using/myresid", "/{id}/using/{resId}", "id", "myid");
testKeyGet3("/myid/using/myresid", "/{id}/using/{resId}", "resId", "myresid");

testKeyGet3("/proxy/myid", "/proxy/{id}/*", "id", "");
testKeyGet3("/proxy/myid/", "/proxy/{id}/*", "id", "myid");
testKeyGet3("/proxy/myid/res", "/proxy/{id}/*", "id", "myid");
testKeyGet3("/proxy/myid/res/res2", "/proxy/{id}/*", "id", "myid");
testKeyGet3("/proxy/myid/res/res2/res3", "/proxy/{id}/*", "id", "myid");
testKeyGet3("/proxy/", "/proxy/{id}/*", "id", "");

testKeyGet3("/api/group1_group_name/project1_admin/info", "/api/{proj}_admin/info", "proj", "");
testKeyGet3("/{id/using/myresid", "/{id/using/{resId}", "resId", "myresid");
testKeyGet3("/{id/using/myresid/status}", "/{id/using/{resId}/status}", "resId", "myresid");

testKeyGet3("/proxy/myid/res/res2/res3", "/proxy/{id}/*/{res}", "res", "res3");
testKeyGet3("/api/project1_admin/info", "/api/{proj}_admin/info", "proj", "project1");
testKeyGet3("/api/group1_group_name/project1_admin/info", "/api/{g}_{gn}/{proj}_admin/info",
"g", "group1");
testKeyGet3("/api/group1_group_name/project1_admin/info", "/api/{g}_{gn}/{proj}_admin/info",
"gn", "group_name");
testKeyGet3("/api/group1_group_name/project1_admin/info", "/api/{g}_{gn}/{proj}_admin/info",
"proj", "project1");
}

@Test
public void testRegexMatchFunc() {
testRegexMatch("/topic/create", "/topic/create", true);
Expand Down
4 changes: 4 additions & 0 deletions src/test/java/org/casbin/jcasbin/main/TestUtil.java
Original file line number Diff line number Diff line change
Expand Up @@ -273,6 +273,10 @@ static void testKeyGet2(String key1, String key2, String pathVar, String res) {
assertEquals(res, BuiltInFunctions.keyGet2Func(key1, key2, pathVar));
}

static void testKeyGet3(String key1, String key2, String pathVar, String res) {
assertEquals(res, BuiltInFunctions.keyGet3Func(key1, key2, pathVar));
}

static void testEval(String eval, Map<String, Object> env, AviatorEvaluatorInstance aviatorEval, boolean res) {
assertEquals(res, BuiltInFunctions.eval(eval, env, aviatorEval));
}
Expand Down
Loading