hidingmyname opened a new issue, #402: URL: https://github.com/apache/casbin-Casbin.NET/issues/402
**Location** (`apache/casbin-Casbin.NET` @ `771066d`): - [`Casbin/Extensions/Model/ModelExtension.cs:13-17`](https://github.com/apache/casbin-Casbin.NET/blob/771066d0e94df76f84e10c7fffbf648c4b926151/Casbin/Extensions/Model/ModelExtension.cs#L13-L17): `SortPolicy` always reads the `policy_effect` of the default type `e`. - [`Casbin/Model/DefaultSections.cs:91-102`](https://github.com/apache/casbin-Casbin.NET/blob/771066d0e94df76f84e10c7fffbf648c4b926151/Casbin/Model/DefaultSections.cs#L91-L102): `GetAssertion` throws `ArgumentOutOfRangeException` when the type does not exist. - [`Casbin/Enforcer.cs:60`](https://github.com/apache/casbin-Casbin.NET/blob/771066d0e94df76f84e10c7fffbf648c4b926151/Casbin/Enforcer.cs#L60): the constructor calls `model.SortPolicy()` unconditionally; [`Casbin/Extensions/Enforcer/EnforcerExtension.cs:190`](https://github.com/apache/casbin-Casbin.NET/blob/771066d0e94df76f84e10c7fffbf648c4b926151/Casbin/Extensions/Enforcer/EnforcerExtension.cs#L190) does the same in `LoadPolicy`. ```csharp public static bool SortPolicy(this IModel model) { string value = model.Sections.GetValue(PermConstants.Section.PolicyEffectSection, PermConstants.DefaultPolicyEffectType); switch (value) { ``` **Problem** Casbin.NET supports several section types through `EnforceContext` (`CreateContext("r2", "p2", "e2", "m2")`). A model that only uses such types, without the defaults `r`/`p`/`e`/`m`, cannot be used, because the enforcer cannot even be constructed: `SortPolicy` looks up the `e` policy effect with `GetValue`, which throws when `e` is missing. The same call runs from `LoadPolicy`/`LoadPolicyAsync`. Scope: - Only models without a default `e` policy effect are affected. Models that define `e` and additional types already work. - Priority sorting is still driven by the default `e` and applied to `p` only. This report is about the crash, not about sorting for `e2`. **Reproduction** ```csharp using Casbin.Model; using Xunit; namespace Casbin.UnitTests.ModelTests; public class MultipleSectionsTypeTest { private static IModel BuildModel() { IModel model = DefaultModel.Create(); model.AddDef("r", "r2", "sub, obj, act"); model.AddDef("p", "p2", "sub, obj, act"); model.AddDef("g", "g", "_, _"); model.AddDef("e", "e2", "some(where (p.eft == allow))"); model.AddDef("m", "m2", "g(r2.sub, p2.sub) && r2.obj == p2.obj && r2.act == p2.act"); return model; } [Fact] public void TestEnforceWithOnlyMultipleSectionsType() { IModel model = BuildModel(); Enforcer e = new(model); e.AddNamedPolicy(PermConstants.PolicyType2, "alice", "data1", "read"); e.AddNamedPolicy(PermConstants.PolicyType2, "bob", "data2", "write"); e.BuildRoleLinks(); EnforceContext context = e.CreateContext( PermConstants.RequestType2, PermConstants.PolicyType2, PermConstants.PolicyEffectType2, PermConstants.MatcherType2); Assert.True(e.Enforce(context, "alice", "data1", "read")); Assert.True(e.Enforce(context, "bob", "data2", "write")); } } ``` `dotnet test Casbin.UnitTests/Casbin.UnitTests.csproj -f net9.0`: ```text Failed Casbin.UnitTests.ModelTests.MultipleSectionsTypeTest.TestEnforceWithOnlyMultipleSectionsType [50 ms] Error Message: System.ArgumentOutOfRangeException : Specified argument was out of the range of valid values. (Parameter 'type') Actual value was e. Stack Trace: at Casbin.Model.DefaultSections.GetAssertion[T](String section, String type) in .../Casbin/Model/DefaultSections.cs:line 101 at Casbin.Model.SectionsExtension.GetValue(ISections sections, String section, String type) in .../Casbin/Extensions/Model/SectionsExtension.cs:line 9 at Casbin.Model.ModelExtension.SortPolicy(IModel model) in .../Casbin/Extensions/Model/ModelExtension.cs:line 15 at Casbin.Enforcer..ctor(IModel model, IReadOnlyAdapter adapter, EnforcerOptions options) in .../Casbin/Enforcer.cs:line 60 at Casbin.UnitTests.ModelTests.MultipleSectionsTypeTest.TestEnforceWithOnlyMultipleSectionsType() in .../Casbin.UnitTests/ModelTests/MultipleSectionsTypeTest.cs:line 23 Failed! - Failed: 1, Passed: 399, Skipped: 0, Total: 400, Duration: 39 s - Casbin.UnitTests.dll (net9.0) ``` Environment: - Commit: [`771066d0e94df76f84e10c7fffbf648c4b926151`](https://github.com/apache/casbin-Casbin.NET/commit/771066d0e94df76f84e10c7fffbf648c4b926151) (`master`, current HEAD) - Toolchain: .NET SDK 11.0.100-rc.2.26504.105 (selected by `global.json` roll-forward), test target net9.0, Linux x64 **Already fixed in `apache/casbin-node-casbin`** PR: https://github.com/apache/casbin-node-casbin/pull/442 ("feat: Multiple sections type", merged 2023-03-26T16:37:35Z, merge commit `48b0d8fbbf3`). It added `EnforceContext` to node-casbin, looks up the `r`/`p`/`e`/`m` assertions by the context's types, and tests an enforcer built from a model that only has `r2`/`p2`/`e2`/`m2`. The same model works in node-casbin. **How node-casbin fixed it** (relevant hunks, verbatim): ```diff --- a/src/coreEnforcer.ts +++ b/src/coreEnforcer.ts @@ -430,23 +438,23 @@ export class CoreEnforcer { functions[key] = asyncCompile ? generateGFunction(rm) : generateSyncedGFunction(rm); }); - const expString = this.model.model.get('m')?.get('m')?.value; + const expString = this.model.model.get('m')?.get(enforceContext.mType)?.value; if (!expString) { throw new Error('Unable to find matchers in model'); } - const effectExpr = this.model.model.get('e')?.get('e')?.value; + const effectExpr = this.model.model.get('e')?.get(enforceContext.eType)?.value; if (!effectExpr) { throw new Error('Unable to find policy_effect in model'); } ... ``` ```diff --- a/test/enforcer.test.ts +++ b/test/enforcer.test.ts @@ -753,3 +753,71 @@ test('TestEnforcerWithScopeFileSystem', async () => { await testEnforce(e, 'bob', 'data2', 'write', true); await testEnforce(e, 'bob', 'data2', 'read', false); }); + +test('TestEnforce Multiple policies config', async () => { + const m = newModel(); + m.addDef('r', 'r2', 'sub, obj, act'); + m.addDef('p', 'p2', 'sub, obj, act'); + m.addDef('g', 'g', '_, _'); + m.addDef('e', 'e2', 'some(where (p.eft == allow))'); + m.addDef('m', 'm2', 'g(r2.sub, p2.sub) && r2.obj == p2.obj && r2.act == p2.act'); + const a = new FileAdapter('examples/mulitple_policy.csv'); + + const e = await newEnforcer(m, a); + + //const e = await getEnforcerWithPath(m); + const enforceContext = new EnforceContext('r2', 'p2', 'e2', 'm2'); + await expect(e.enforce(enforceContext, 'alice', 'data1', 'read')).resolves.toStrictEqual(true); + await expect(e.enforce(enforceContext, 'bob', 'data2', 'write')).resolves.toStrictEqual(true); +}); ... ``` **Suggested fix** Treat a missing default `e` like any effect that needs no sorting, and return `false` instead of throwing: ```diff diff --git a/Casbin/Extensions/Model/ModelExtension.cs b/Casbin/Extensions/Model/ModelExtension.cs --- a/Casbin/Extensions/Model/ModelExtension.cs +++ b/Casbin/Extensions/Model/ModelExtension.cs @@ -12,9 +12,14 @@ namespace Casbin.Model { public static bool SortPolicy(this IModel model) { - string value = model.Sections.GetValue(PermConstants.Section.PolicyEffectSection, - PermConstants.DefaultPolicyEffectType); - switch (value) + // A model may define only non-default section types (e.g. "e2") and use them through an EnforceContext. + if (model.Sections.TryGetAssertion(PermConstants.Section.PolicyEffectSection, + PermConstants.DefaultPolicyEffectType, out PolicyEffectAssertion assertion) is false) + { + return false; + } + + switch (assertion.Value) { case PermConstants.PolicyEffect.Priority: case PermConstants.PolicyEffect.PriorityDenyOverride: ``` Verified on `771066d` (.NET SDK 11.0.100-rc.2.26504.105, net9.0): the test above fails without this patch and passes with it, and both `Enforce` calls through the `e2` context return `true`; no other test results change (399 existing tests in `Casbin.UnitTests`). I can submit a PR for this. Checked: #216 (a second matcher next to the default `m`), #329 (named role types) and #346 (`ArgumentOutOfRangeException` under concurrent writes) are different problems; searches for `SortPolicy`, `EnforceContext` and `e2 policy_effect` found nothing about models without the default section types. -- This is an automated message from the Apache Git Service. To respond to the message, please log on to GitHub and use the URL above to go to the specific comment. To unsubscribe, e-mail: [email protected] For queries about this service, please contact Infrastructure at: [email protected] --------------------------------------------------------------------- To unsubscribe, e-mail: [email protected] For additional commands, e-mail: [email protected]
