diff --git a/NetCasbin.UnitTest/EnforcerTest.cs b/NetCasbin.UnitTest/EnforcerTest.cs index 37ea2ccb..7ff76884 100644 --- a/NetCasbin.UnitTest/EnforcerTest.cs +++ b/NetCasbin.UnitTest/EnforcerTest.cs @@ -23,6 +23,7 @@ public EnforcerTest(ITestOutputHelper testOutputHelper, TestModelFixture testMod _testModelFixture = testModelFixture; } + #region In memory model [Fact] public void TestKeyMatchModelInMemory() { @@ -379,6 +380,144 @@ public async Task TestNotUsedRbacModelInMemoryAsync() await TestEnforceAsync(e, "bob", "data2", "write", true); } + [Fact] + public void TestMultipleGroupTypeModelInMemory() + { + var m = Model.Model.CreateDefault(); + m.AddDef("r", "r", "sub, obj, act"); + m.AddDef("p", "p", "sub, obj, act"); + m.AddDef("g", "g", "_, _"); + m.AddDef("g", "g2", "_, _"); + m.AddDef("e", "e", "some(where (p.eft == allow))"); + m.AddDef("m", "m", "g(r.sub, p.sub) && g2(r.obj, p.obj) && r.act == p.act"); + + var e = new Enforcer(m); + e.AddPolicy("alice", "data1", "read"); + e.AddPolicy("bob", "data2", "write"); + e.AddPolicy("data_group_admin", "data_group", "write"); + e.AddNamedGroupingPolicy("g", "alice", "data_group_admin"); + e.AddNamedGroupingPolicy("g2", "data1", "data_group"); + e.AddNamedGroupingPolicy("g2", "data2", "data_group"); + + Assert.True(e.Enforce("alice", "data1", "read")); + Assert.True(e.Enforce("alice", "data1", "write")); + Assert.False(e.Enforce("alice", "data2", "read")); + Assert.True(e.Enforce("alice", "data2", "write")); + } + + [Fact] + public async Task TestMultipleGroupTypeModelInMemoryAsync() + { + var m = Model.Model.CreateDefault(); + m.AddDef("r", "r", "sub, obj, act"); + m.AddDef("p", "p", "sub, obj, act"); + m.AddDef("g", "g", "_, _"); + m.AddDef("g", "g2", "_, _"); + m.AddDef("e", "e", "some(where (p.eft == allow))"); + m.AddDef("m", "m", "g(r.sub, p.sub) && g2(r.obj, p.obj) && r.act == p.act"); + + var e = new Enforcer(m); + await e.AddPolicyAsync("alice", "data1", "read"); + await e.AddPolicyAsync("bob", "data2", "write"); + await e.AddPolicyAsync("data_group_admin", "data_group", "write"); + await e.AddNamedGroupingPolicyAsync("g", "alice", "data_group_admin"); + await e.AddNamedGroupingPolicyAsync("g2", "data1", "data_group"); + await e.AddNamedGroupingPolicyAsync("g2", "data2", "data_group"); + + Assert.True(await e.EnforceAsync("alice", "data1", "read")); + Assert.True(await e.EnforceAsync("alice", "data1", "write")); + Assert.False(await e.EnforceAsync("alice", "data2", "read")); + Assert.True(await e.EnforceAsync("alice", "data2", "write")); + } + #endregion + + #region Init enmpty + [Fact] + public void TestInitEmpty() + { + var e = new Enforcer(); + + var m = Model.Model.CreateDefault(); + m.AddDef("r", "r", "sub, obj, act"); + m.AddDef("p", "p", "sub, obj, act"); + m.AddDef("e", "e", "some(where (p.eft == allow))"); + m.AddDef("m", "m", "r.sub == p.sub && keyMatch(r.obj, p.obj) && regexMatch(r.act, p.act)"); + + IAdapter a = new DefaultFileAdapter("examples/keymatch_policy.csv"); + + e.SetModel(m); + e.SetAdapter(a); + e.LoadPolicy(); + + TestEnforce(e, "alice", "/alice_data/resource1", "GET", true); + } + + [Fact] + public async Task TestInitEmptyAsync() + { + var e = new Enforcer(); + + var m = Model.Model.CreateDefault(); + m.AddDef("r", "r", "sub, obj, act"); + m.AddDef("p", "p", "sub, obj, act"); + m.AddDef("e", "e", "some(where (p.eft == allow))"); + m.AddDef("m", "m", "r.sub == p.sub && keyMatch(r.obj, p.obj) && regexMatch(r.act, p.act)"); + + IAdapter a = new DefaultFileAdapter("examples/keymatch_policy.csv"); + + e.SetModel(m); + e.SetAdapter(a); + await e.LoadPolicyAsync(); + + await TestEnforceAsync(e, "alice", "/alice_data/resource1", "GET", true); + } + + [Fact] + public void TestInitEmptyByInputStream() + { + var e = new Enforcer(); + + var m = Model.Model.CreateDefault(); + m.AddDef("r", "r", "sub, obj, act"); + m.AddDef("p", "p", "sub, obj, act"); + m.AddDef("e", "e", "some(where (p.eft == allow))"); + m.AddDef("m", "m", "r.sub == p.sub && keyMatch(r.obj, p.obj) && regexMatch(r.act, p.act)"); + + using (var fs = new FileStream("examples/keymatch_policy.csv", FileMode.Open, FileAccess.Read, FileShare.ReadWrite)) + { + IAdapter a = new DefaultFileAdapter(fs); + e.SetModel(m); + e.SetAdapter(a); + e.LoadPolicy(); + + TestEnforce(e, "alice", "/alice_data/resource1", "GET", true); + } + } + + [Fact] + public async Task TestInitEmptyByInputStreamAsync() + { + var e = new Enforcer(); + + var m = Model.Model.CreateDefault(); + m.AddDef("r", "r", "sub, obj, act"); + m.AddDef("p", "p", "sub, obj, act"); + m.AddDef("e", "e", "some(where (p.eft == allow))"); + m.AddDef("m", "m", "r.sub == p.sub && keyMatch(r.obj, p.obj) && regexMatch(r.act, p.act)"); + + using (var fs = new FileStream("examples/keymatch_policy.csv", FileMode.Open, FileAccess.Read, FileShare.ReadWrite)) + { + IAdapter a = new DefaultFileAdapter(fs); + e.SetModel(m); + e.SetAdapter(a); + await e.LoadPolicyAsync(); + + await TestEnforceAsync(e, "alice", "/alice_data/resource1", "GET", true); + } + } + #endregion + + #region Policy management [Fact] public void TestReloadPolicy() { @@ -436,7 +575,9 @@ public void TestClearPolicy() e.ClearPolicy(); } + #endregion + #region Extension features [Fact] public void TestEnableEnforce() { @@ -671,90 +812,9 @@ public async Task TestSetAdapterFromFileAsync() await TestEnforceAsync(e, "alice", "data1", "read", true); } - [Fact] - public void TestInitEmpty() - { - var e = new Enforcer(); - - var m = Model.Model.CreateDefault(); - m.AddDef("r", "r", "sub, obj, act"); - m.AddDef("p", "p", "sub, obj, act"); - m.AddDef("e", "e", "some(where (p.eft == allow))"); - m.AddDef("m", "m", "r.sub == p.sub && keyMatch(r.obj, p.obj) && regexMatch(r.act, p.act)"); - - IAdapter a = new DefaultFileAdapter("examples/keymatch_policy.csv"); - - e.SetModel(m); - e.SetAdapter(a); - e.LoadPolicy(); - - TestEnforce(e, "alice", "/alice_data/resource1", "GET", true); - } - - [Fact] - public async Task TestInitEmptyAsync() - { - var e = new Enforcer(); - - var m = Model.Model.CreateDefault(); - m.AddDef("r", "r", "sub, obj, act"); - m.AddDef("p", "p", "sub, obj, act"); - m.AddDef("e", "e", "some(where (p.eft == allow))"); - m.AddDef("m", "m", "r.sub == p.sub && keyMatch(r.obj, p.obj) && regexMatch(r.act, p.act)"); - - IAdapter a = new DefaultFileAdapter("examples/keymatch_policy.csv"); - - e.SetModel(m); - e.SetAdapter(a); - await e.LoadPolicyAsync(); - - await TestEnforceAsync(e, "alice", "/alice_data/resource1", "GET", true); - } - - [Fact] - public void TestInitEmptyByInputStream() - { - var e = new Enforcer(); - - var m = Model.Model.CreateDefault(); - m.AddDef("r", "r", "sub, obj, act"); - m.AddDef("p", "p", "sub, obj, act"); - m.AddDef("e", "e", "some(where (p.eft == allow))"); - m.AddDef("m", "m", "r.sub == p.sub && keyMatch(r.obj, p.obj) && regexMatch(r.act, p.act)"); - - using (var fs = new FileStream("examples/keymatch_policy.csv", FileMode.Open, FileAccess.Read, FileShare.ReadWrite)) - { - IAdapter a = new DefaultFileAdapter(fs); - e.SetModel(m); - e.SetAdapter(a); - e.LoadPolicy(); - - TestEnforce(e, "alice", "/alice_data/resource1", "GET", true); - } - } - - [Fact] - public async Task TestInitEmptyByInputStreamAsync() - { - var e = new Enforcer(); - - var m = Model.Model.CreateDefault(); - m.AddDef("r", "r", "sub, obj, act"); - m.AddDef("p", "p", "sub, obj, act"); - m.AddDef("e", "e", "some(where (p.eft == allow))"); - m.AddDef("m", "m", "r.sub == p.sub && keyMatch(r.obj, p.obj) && regexMatch(r.act, p.act)"); - - using (var fs = new FileStream("examples/keymatch_policy.csv", FileMode.Open, FileAccess.Read, FileShare.ReadWrite)) - { - IAdapter a = new DefaultFileAdapter(fs); - e.SetModel(m); - e.SetAdapter(a); - await e.LoadPolicyAsync(); - - await TestEnforceAsync(e, "alice", "/alice_data/resource1", "GET", true); - } - } + #endregion + #region EnforceEx API [Fact] public void TestEnforceExApi() { @@ -854,5 +914,6 @@ public void TestEnforceExApiLog() e.Logger = null; } #endif + #endregion } } diff --git a/NetCasbin/ManagementEnforcer.cs b/NetCasbin/ManagementEnforcer.cs index cc95e0a6..631c816f 100644 --- a/NetCasbin/ManagementEnforcer.cs +++ b/NetCasbin/ManagementEnforcer.cs @@ -740,6 +740,19 @@ public bool AddNamedGroupingPolicy(string ptype, params string[] parameters) return AddNamedGroupingPolicy(ptype, parameters.ToList()); } + /// + /// Adds a named role inheritance rule to the current + /// policy. If the rule already exists, the function returns false and the rule + /// will not be added. Otherwise the function returns true by adding the new rule. + /// + /// The policy type, can be "g", "g2", "g3", .. + /// The "g" policy rule. + /// Succeeds or not. + public Task AddNamedGroupingPolicyAsync(string ptype, params string[] parameters) + { + return AddNamedGroupingPolicyAsync(ptype, parameters.ToList()); + } + /// /// Adds roles inheritance rule to the current policy. If the /// rule already exists, the function returns false and the rule will not be diff --git a/NetCasbin/Model/Model.cs b/NetCasbin/Model/Model.cs index ac2f36c5..a45db7bd 100644 --- a/NetCasbin/Model/Model.cs +++ b/NetCasbin/Model/Model.cs @@ -74,6 +74,13 @@ public void LoadModelFromText(string text) LoadModel(Config.Config.NewConfigFromText(text)); } + /// + /// Adds an assertion to the model. + /// + /// + /// Key of the assertion, it is same to "policyType" when section is "p" or "g". + /// Value of the assertion. + /// public bool AddDef(string section, string key, string value) { if (string.IsNullOrWhiteSpace(value)) @@ -90,7 +97,7 @@ public bool AddDef(string section, string key, string value) if (section.Equals(PermConstants.Section.RequestSection) || section.Equals(PermConstants.Section.PolicySection)) { - var tokens = assertion.Value + string[] tokens = assertion.Value .Split(PermConstants.PolicySeparatorChar) .Select(t => t.Trim()).ToArray(); @@ -108,7 +115,7 @@ public bool AddDef(string section, string key, string value) assertion.Value = Utility.RemoveComments(Utility.EscapeAssertion(assertion.Value)); } - if (!Model.ContainsKey(section)) + if (Model.ContainsKey(section) is false) { var assertionMap = new Dictionary {