Feature request: add the `keyMatch5` built-in matcher function
還沒有人認領這個 Issue。
評估
- 難度
- 3/5
- 預估耗時
- 半天
- 新手友好度
- 74/100
- Issue 類型
- 功能
- 描述清晰度
- 描述清楚
- 活躍度
- 活躍
- 技術堆疊
- cpp
研究方向
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.
由索引模型根據 Issue 內容生成。
描述
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.
- 主要語言
- C++
- 星號
- 257
- 分支
- 67
- PR 合併指標
- 30 天內沒有已合併 PR
環境準備
- 沒有 Dockerfile 或 Docker Compose 檔案
- 沒有 Pull Request 範本
- 閱讀貢獻指南
從這裡開始
- 先讀完整個 Issue,再讀專案的貢獻指南。
- 在 Issue 下留言說明你要接手 —— 這能避免兩個人做同樣的事。
- Fork 儲存庫,在一個分支上完成修改。
- 送出 Pull Request,並在描述裡引用這個 Issue 編號。
apache/casbin-cpp 的其他 Issue
-
難度 2/5 1-3 小時 新手友好度 92/100
apache/casbin-cpp#277 ·
-
難度 1/5 1-3 小時 新手友好度 88/100
apache/casbin-cpp#276 ·
-
Quoted fields in CSV policy files keep their quote characters, so quoted policy rules never match未關閉
難度 2/5 1-3 小時 新手友好度 85/100
apache/casbin-cpp#274 ·
-
ci: automated PR performance benchmark comparison可能重新可做 @knyk-dev 於 296 天前認領,目前沒有進行中的 PR。 未關閉enhancement
apache/casbin-cpp#266 · 已指派 1 人 ·
-
Porting Casbin-CPP to Real-Time Operating Systems (RTOS)可能重新可做 @hsluoyz 於 1274 天前認領,目前沒有進行中的 PR。 未關閉enhancement
apache/casbin-cpp#229 · 1 則留言 · 已指派 1 人 ·
查看 apache/casbin-cpp 的全部 Issue
相似的 Issue
-
難度 2/5 1-3 小時 新手友好度 65/100
scp-fs2open/fs2open.github.com#7965 ·
維護者通常 1 天內回覆
-
[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 TMEM可能已有人在做 關聯的 PR 仍在進行中或已合併。 未關閉
難度 2/5 1-3 小時 新手友好度 78/100
維護者通常 4 天內回覆
-
難度 2/5 1-3 小時 新手友好度 72/100
elf-alchemist/elfbsp#113 ·
維護者通常 1 天內回覆
-
難度 2/5 1-3 小時 新手友好度 75/100
patrick-hudson/put.gd-desktop#979 · 1 則留言 ·
維護者通常 1 天內回覆
-
難度 2/5 1-3 小時 新手友好度 76/100
Dao-AILab/flash-attention#3097 ·
維護者通常 3 天內回覆