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
{