Feature request: add the `keyMatch5` built-in matcher function
Nadie ha tomado este issue todavía.
Evaluación
- Dificultad
- 3/5
- Tiempo estimado
- Medio día
- Aptitud para principiantes
- 74/100
- Tipo de issue
- Nueva funcionalidad
- Claridad
- Bien especificado
- Estado de actividad
- Activo
- Stack tecnológico
- cpp
- Área
- authorization
Línea de trabajo
Start at casbin/model/evaluator.cpp LoadFunctions; follow KeyMatch4 through include/casbin/model/exprtk_config.h, casbin/util/built_in_functions.cpp and include/casbin/util/built_in_functions.h. Add KeyMatch5 by stripping key1 at the first ?, then using KeyMatch3-style wildcard/placeholder matching, and register it in the factory and LoadFunctions. Add a TestKeyMatch5 beside TestKeyMatch4 in tests/built_in_functions_test.cpp; run the gtest suite, and done is the new matcher registered as keyMatch5 with the test passing.
Escrito por el modelo de indexación a partir del texto del issue.
Descripción
Location (apache/casbin-cpp @ default branch 0ad64a7):
casbin/model/evaluator.cpp:81-91—ExprtkEvaluator::LoadFunctions
void ExprtkEvaluator::LoadFunctions() {
AddFunction("keyMatch", ExprtkFunctionFactory::GetExprtkFunction(ExprtkFunctionType::KeyMatch, 2));
AddFunction("keyMatch2", ExprtkFunctionFactory::GetExprtkFunction(ExprtkFunctionType::KeyMatch2, 2));
AddFunction("keyMatch3", ExprtkFunctionFactory::GetExprtkFunction(ExprtkFunctionType::KeyMatch3, 2));
AddFunction("keyMatch4", ExprtkFunctionFactory::GetExprtkFunction(ExprtkFunctionType::KeyMatch4, 2));
AddFunction("regexMatch", ExprtkFunctionFactory::GetExprtkFunction(ExprtkFunctionType::RegexMatch, 2));
AddFunction("ipMatch", ExprtkFunctionFactory::GetExprtkFunction(ExprtkFunctionType::IpMatch, 2));
AddFunction("keyGet", ExprtkFunctionFactory::GetExprtkFunction(ExprtkFunctionType::KeyGet, 2));
AddFunction("keyGet2", ExprtkFunctionFactory::GetExprtkFunction(ExprtkFunctionType::KeyGet2, 3));
AddFunction("keyGet3", ExprtkFunctionFactory::GetExprtkFunction(ExprtkFunctionType::KeyGet3, 3));
}
Problem
Casbin's function reference lists keyMatch5: arg1 is "a URL path like /alice_data/123/?status=1", arg2 is "a URL path, a {} or * pattern like /alice_data/{id}/*". The query string of the request path is ignored when matching. casbin-cpp registers keyMatch … keyMatch4, regexMatch, ipMatch and keyGet* as built-ins, but not keyMatch5, so a model that uses it in other Casbin implementations, e.g.
[matchers]
m = r.sub == p.sub && keyMatch5(r.obj, p.obj) && r.act == p.act
with p, alice, /parent/child, GET, can't be used unchanged with casbin-cpp. Users have to strip the query string themselves or register their own function (AddFunction) in each application.
This is a feature request, not a bug: an unknown function is already an error, not an allow.
Reproduction
With the matcher above, the first Enforce call throws, and gtest reports:
unknown file: Failure
Unknown C++ exception thrown in the test body.
Environment: master 0ad64a7.
Already implemented in apache/casbin-node-casbin
PR: https://github.com/apache/casbin-node-casbin/pull/359 — "feat: #357 Support keyMatch5" (merged 2022-04-15T01:43:23Z, merge commit e6a6d8ab253). It adds keyMatch5 to node-casbin's built-in function map, matching after dropping the query string from the request path. node-casbin's version compares the remaining path exactly; the reference implementation (apache/casbin KeyMatch5) additionally supports {name} and /* in the pattern, which is the behaviour the docs describe.
How node-casbin implemented it:
--- a/src/model/functionMap.ts
+++ b/src/model/functionMap.ts
@@ -37,6 +37,7 @@ export class FunctionMap {
fm.addFunction('keyGet2', util.keyGet2Func);
fm.addFunction('keyMatch3', util.keyMatch3Func);
fm.addFunction('keyMatch4', util.keyMatch4Func);
+ fm.addFunction('keyMatch5', util.keyMatch5Func);
fm.addFunction('regexMatch', util.regexMatchFunc);
fm.addFunction('ipMatch', util.ipMatchFunc);
fm.addFunction('globMatch', util.globMatch);
--- a/src/util/builtinOperators.ts
+++ b/src/util/builtinOperators.ts
@@ -233,6 +233,26 @@ function keyMatch4Func(...args: any[]): boolean {
return keyMatch4(name1, name2);
}
+// KeyMatch determines whether key1 matches the pattern of key2 and ignores the parameters in key2.
+// For example, "/foo/bar?status=1&type=2" matches "/foo/bar"
+function KeyMatch5(key1: string, key2: string): boolean {
+ const i: number = key1.indexOf('?');
+ if (i === -1) {
+ return key1 === key2;
+ }
+
+ return key1.slice(0, i) === key2;
+}
+
+// keyMatch5Func is the wrapper for KeyMatch5.
+function keyMatch5Func(...args: any[]): boolean {
+ const [arg0, arg1] = args;
+ const name1: string = (arg0 || '').toString();
+ const name2: string = (arg1 || '').toString();
+
+ return KeyMatch5(name1, name2);
+}
+
// regexMatchFunc is the wrapper for regexMatch.
function regexMatchFunc(...args: any[]): boolean {
const [arg0, arg1] = args;
Suggested fix
Add KeyMatch5 next to KeyMatch4 (drop everything from the first ? in key1, then match like keyMatch3: /* is a wildcard and {name} matches one path segment), add it to the exprtk function factory, and register it as keyMatch5 in LoadFunctions:
diff --git a/casbin/model/evaluator.cpp b/casbin/model/evaluator.cpp
--- a/casbin/model/evaluator.cpp
+++ b/casbin/model/evaluator.cpp
@@ -83,6 +83,7 @@ void ExprtkEvaluator::LoadFunctions() {
AddFunction("keyMatch2", ExprtkFunctionFactory::GetExprtkFunction(ExprtkFunctionType::KeyMatch2, 2));
AddFunction("keyMatch3", ExprtkFunctionFactory::GetExprtkFunction(ExprtkFunctionType::KeyMatch3, 2));
AddFunction("keyMatch4", ExprtkFunctionFactory::GetExprtkFunction(ExprtkFunctionType::KeyMatch4, 2));
+ AddFunction("keyMatch5", ExprtkFunctionFactory::GetExprtkFunction(ExprtkFunctionType::KeyMatch5, 2));
AddFunction("regexMatch", ExprtkFunctionFactory::GetExprtkFunction(ExprtkFunctionType::RegexMatch, 2));
AddFunction("ipMatch", ExprtkFunctionFactory::GetExprtkFunction(ExprtkFunctionType::IpMatch, 2));
AddFunction("keyGet", ExprtkFunctionFactory::GetExprtkFunction(ExprtkFunctionType::KeyGet, 2));
diff --git a/casbin/util/built_in_functions.cpp b/casbin/util/built_in_functions.cpp
--- a/casbin/util/built_in_functions.cpp
+++ b/casbin/util/built_in_functions.cpp
@@ -204,6 +204,18 @@ bool KeyMatch4(const std::string& key1, const std::string& key2) {
return true;
}
+// KeyMatch5 determines whether key1 matches the pattern of key2 (similar to RESTful path), key2 can contain a *.
+// The query string of key1 (everything from the first "?") is ignored.
+// For example, "/foo/bar?status=1&type=2" matches "/foo/bar", "/parent/child1" matches "/parent/*" and "/parent/{id}"
+bool KeyMatch5(const std::string& key1, const std::string& key2) {
+ std::string k1 = key1.substr(0, key1.find('?'));
+ std::string k2 = PrepareWildCardMatching(key2);
+ k2 = std::regex_replace(k2, enclosedPlaceHolderRegex, "$1[^/]+$2");
+ k2 = EscapeCurlyBraces(k2);
+
+ return RegexMatch(k1, "^" + k2 + "$");
+}
+
// RegexMatch determines whether key1 matches the pattern of key2 in regular expression.
bool RegexMatch(const std::string& key1, const std::string& key2) {
std::regex regex_s(key2);
diff --git a/include/casbin/model/exprtk_config.h b/include/casbin/model/exprtk_config.h
--- a/include/casbin/model/exprtk_config.h
+++ b/include/casbin/model/exprtk_config.h
@@ -234,6 +234,7 @@ enum class ExprtkFunctionType {
KeyMatch2,
KeyMatch3,
KeyMatch4,
+ KeyMatch5,
RegexMatch,
IpMatch,
KeyGet,
@@ -276,6 +277,9 @@ public:
case ExprtkFunctionType::KeyMatch4:
func = std::make_shared<ExprtkMatchFunction>(idenfier, KeyMatch4);
break;
+ case ExprtkFunctionType::KeyMatch5:
+ func = std::make_shared<ExprtkMatchFunction>(idenfier, KeyMatch5);
+ break;
case ExprtkFunctionType::IpMatch:
func = std::make_shared<ExprtkMatchFunction>(idenfier, IPMatch);
break;
diff --git a/include/casbin/util/built_in_functions.h b/include/casbin/util/built_in_functions.h
--- a/include/casbin/util/built_in_functions.h
+++ b/include/casbin/util/built_in_functions.h
@@ -53,6 +53,11 @@ std::string KeyGet3(const std::string& key1, const std::string& key2, const std:
// But KeyMatch3 will match both.
bool KeyMatch4(const std::string& key1, const std::string& key2);
+// KeyMatch5 determines whether key1 matches the pattern of key2 (similar to RESTful path), key2 can contain a *.
+// The query string of key1 (everything from the first "?") is ignored.
+// For example, "/foo/bar?status=1&type=2" matches "/foo/bar", "/parent/child1" matches "/parent/*" and "/parent/{id}"
+bool KeyMatch5(const std::string& key1, const std::string& key2);
+
// RegexMatch determines whether key1 matches the pattern of key2 in regular expression.
bool RegexMatch(const std::string& key1, const std::string& key2);
Verified on 0ad64a7 (GCC 11.4.0, GoogleTest 1.14.0): with the example above added as a TestKeyMatch5 unit test in tests/built_in_functions_test.cpp (via the exprtk evaluator, like TestKeyMatch4), the test does not compile without this patch and passes with it; no other test results change.
I can submit a PR for this.
Related: no issue/PR mentions keyMatch5; #209 / #212 added the then-missing keyGet* / keyMatch4 built-ins in the same way.
- Lenguaje dominante
- C++
- Estrellas
- 257
- Forks
- 67
- Métricas de merge de PR
- Sin PR fusionados en 30 d
Preparar el entorno
- Sin Dockerfile ni archivo de Docker Compose
- Sin plantilla de pull request
- Leer la guía de contribución
Primeros pasos
- Lee el issue completo y luego la guía de contribución del proyecto.
- Comenta en el issue que vas a ocuparte — evita que dos personas hagan lo mismo.
- Haz un fork del repositorio y trabaja en una rama.
- Abre un pull request que haga referencia al número del issue.
Más de apache/casbin-cpp
-
Dificultad 2/5 1-3 horas Aptitud para principiantes 92/100
apache/casbin-cpp#277 ·
-
Dificultad 1/5 1-3 horas Aptitud para principiantes 88/100
apache/casbin-cpp#276 ·
-
Quoted fields in CSV policy files keep their quote characters, so quoted policy rules never matchAbierto
Dificultad 2/5 1-3 horas Aptitud para principiantes 85/100
apache/casbin-cpp#274 ·
-
ci: automated PR performance benchmark comparisonQuizá libre de nuevo @knyk-dev la tomó hace 296 días y no hay ningún pull request abierto. Abiertoenhancement
apache/casbin-cpp#266 · 1 asignado ·
-
Porting Casbin-CPP to Real-Time Operating Systems (RTOS)Quizá libre de nuevo @hsluoyz la tomó hace 1275 días y no hay ningún pull request abierto. Abiertoenhancement
apache/casbin-cpp#229 · 1 comentario · 1 asignado ·
Todos los issues de apache/casbin-cpp
Issues similares
-
Dificultad 2/5 1-3 horas Aptitud para principiantes 65/100
scp-fs2open/fs2open.github.com#7965 ·
Los mantenedores suelen responder en 1 día
-
[Bug][CuTeDSL][Fuzz] `utils.gemm.sm100.epilogue` releases the accumulator before `tcgen05.ld` completes: no `tcgen05.wait::ld` before the arrive that lets the next MMA overwrite TMEMPosiblemente ocupada Un pull request vinculado a esta issue está abierto o ya se fusionó. Abierto
Dificultad 2/5 1-3 horas Aptitud para principiantes 78/100
Los mantenedores suelen responder en 4 días
-
Dificultad 2/5 1-3 horas Aptitud para principiantes 72/100
elf-alchemist/elfbsp#113 ·
Los mantenedores suelen responder en 1 día
-
Dificultad 2/5 1-3 horas Aptitud para principiantes 75/100
patrick-hudson/put.gd-desktop#979 · 1 comentario ·
Los mantenedores suelen responder en 1 día
-
Dificultad 2/5 1-3 horas Aptitud para principiantes 76/100
Dao-AILab/flash-attention#3097 ·
Los mantenedores suelen responder en 3 días