Feature request: add the `keyMatch5` built-in matcher function
Nessuno ha ancora preso questa issue.
Valutazione
- Difficoltà
- 3/5
- Tempo stimato
- Mezza giornata
- Idoneità per principianti
- 74/100
- Tipo di issue
- Funzionalità
- Chiarezza
- Specificata chiaramente
- Stato di attività
- Attiva
- Stack tecnologico
- cpp
- Ambito
- authorization
Direzione di ricerca
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.
Scritto dal modello di indicizzazione a partire dal testo della issue.
Descrizione
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.
- Lingua principale
- C++
- Stelle
- 257
- Fork
- 67
- Merge medio
- 10h 23m
- PR unite (30g)
- 1
Preparare l'ambiente
- Nessun Dockerfile né file Docker Compose
- Nessun modello di pull request
- Leggi la guida per i contributori
Come iniziare
- Leggi tutta la issue e poi la guida ai contributi del progetto.
- Commenta sulla issue per dire che te ne occupi tu — evita che due persone facciano lo stesso lavoro.
- Fai un fork del repository e lavora su un branch.
- Apri una pull request che faccia riferimento al numero della issue.
Altre issue di apache/casbin-cpp
-
ci: automated PR performance benchmark comparisonForse di nuovo libera @knyk-dev l’ha presa 299 giorni fa e non c’è nessuna pull request aperta. Apertaenhancement
apache/casbin-cpp#266 · 1 assegnatario ·
-
Porting Casbin-CPP to Real-Time Operating Systems (RTOS)Forse di nuovo libera @hsluoyz l’ha presa 1278 giorni fa e non c’è nessuna pull request aperta. Apertaenhancement
apache/casbin-cpp#229 · 1 commento · 1 assegnatario ·
-
Use the same performance benchmark tests for all languagesForse di nuovo libera @hsluoyz l’ha presa 1576 giorni fa e non c’è nessuna pull request aperta. Apertaenhancement
apache/casbin-cpp#207 · 3 commenti · 1 assegnatario ·
-
Benchmarking pycasbin's performance to compare it with Python's casbin implementationForse di nuovo libera @hsluoyz l’ha presa 1748 giorni fa e non c’è nessuna pull request aperta. Apertaenhancement
apache/casbin-cpp#181 · 1 commento · 1 assegnatario ·
-
Make an authorization middleware for Envoy based on CasbinForse di nuovo libera @hsluoyz l’ha presa 1952 giorni fa e non c’è nessuna pull request aperta. Apertaenhancement
apache/casbin-cpp#115 · 1 commento · 1 assegnatario ·
Tutte le issue di apache/casbin-cpp
Issue simili
-
Difficoltà 2/5 1-3 ore Idoneità per principianti 65/100
NVIDIA-RTX/NRI#307 · 1 commento ·
I maintainer di solito rispondono entro 1 giorno
-
Difficoltà 2/5 1-3 ore Idoneità per principianti 80/100
-
Difficoltà 1/5 Meno di un'ora Idoneità per principianti 82/100
-
Difficoltà 2/5 1-3 ore Idoneità per principianti 72/100
eclipse-score/lifecycle#929 ·
I maintainer di solito rispondono entro 1 giorno
-
Difficoltà 2/5 1-3 ore Idoneità per principianti 62/100
I maintainer di solito rispondono entro 1 giorno