diff --git a/Casbin.NET.sln b/Casbin.NET.sln
index f4355cd7..c066a7ec 100644
--- a/Casbin.NET.sln
+++ b/Casbin.NET.sln
@@ -23,6 +23,8 @@ Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "Solution Items", "Solution
EndProject
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Casbin.Benchmark", "Casbin.Benchmark\Casbin.Benchmark.csproj", "{1DBC2931-4981-4DB5-A30B-FF6EB8622B04}"
EndProject
+Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Casbin.Samples", "Casbin.Samples\Casbin.Samples.csproj", "{BE93FBFB-0D11-4647-BD4A-48FDDF3DACB1}"
+EndProject
Global
GlobalSection(SolutionConfigurationPlatforms) = preSolution
Debug|Any CPU = Debug|Any CPU
@@ -41,6 +43,10 @@ Global
{1DBC2931-4981-4DB5-A30B-FF6EB8622B04}.Debug|Any CPU.Build.0 = Debug|Any CPU
{1DBC2931-4981-4DB5-A30B-FF6EB8622B04}.Release|Any CPU.ActiveCfg = Release|Any CPU
{1DBC2931-4981-4DB5-A30B-FF6EB8622B04}.Release|Any CPU.Build.0 = Release|Any CPU
+ {BE93FBFB-0D11-4647-BD4A-48FDDF3DACB1}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
+ {BE93FBFB-0D11-4647-BD4A-48FDDF3DACB1}.Debug|Any CPU.Build.0 = Debug|Any CPU
+ {BE93FBFB-0D11-4647-BD4A-48FDDF3DACB1}.Release|Any CPU.ActiveCfg = Release|Any CPU
+ {BE93FBFB-0D11-4647-BD4A-48FDDF3DACB1}.Release|Any CPU.Build.0 = Release|Any CPU
EndGlobalSection
GlobalSection(SolutionProperties) = preSolution
HideSolutionNode = FALSE
diff --git a/Casbin.Samples/Casbin.Samples.csproj b/Casbin.Samples/Casbin.Samples.csproj
new file mode 100644
index 00000000..56f17f43
--- /dev/null
+++ b/Casbin.Samples/Casbin.Samples.csproj
@@ -0,0 +1,25 @@
+
+
+
+ Exe
+ net5.0
+
+
+
+
+
+
+
+
+
+
+
+
+ PreserveNewest
+
+
+ PreserveNewest
+
+
+
+
diff --git a/Casbin.Samples/Examples/rbac_model.conf b/Casbin.Samples/Examples/rbac_model.conf
new file mode 100644
index 00000000..9ca4b928
--- /dev/null
+++ b/Casbin.Samples/Examples/rbac_model.conf
@@ -0,0 +1,14 @@
+[request_definition]
+r = sub, obj, act
+
+[policy_definition]
+p = sub, obj, act
+
+[role_definition]
+g = _, _
+
+[policy_effect]
+e = some(where (p.eft == allow))
+
+[matchers]
+m = g(r.sub, p.sub) && r.obj == p.obj && r.act == p.act
diff --git a/Casbin.Samples/Examples/rbac_policy.csv b/Casbin.Samples/Examples/rbac_policy.csv
new file mode 100644
index 00000000..f93d6df8
--- /dev/null
+++ b/Casbin.Samples/Examples/rbac_policy.csv
@@ -0,0 +1,5 @@
+p, alice, data1, read
+p, bob, data2, write
+p, data2_admin, data2, read
+p, data2_admin, data2, write
+g, alice, data2_admin
\ No newline at end of file
diff --git a/Casbin.Samples/Program.cs b/Casbin.Samples/Program.cs
new file mode 100644
index 00000000..56b39ba8
--- /dev/null
+++ b/Casbin.Samples/Program.cs
@@ -0,0 +1,23 @@
+using System;
+using Microsoft.Extensions.DependencyInjection;
+using Microsoft.Extensions.Logging;
+using NetCasbin;
+
+namespace Casbin.Samples
+{
+ class Program
+ {
+ static void Main(string[] args)
+ {
+ Enforcer enforcer = new (
+ "Examples/rbac_model.conf",
+ "Examples/rbac_policy.csv");
+
+ //var provider = new ServiceCollection()
+ // .AddLogging(builder => builder.AddConsole())
+ // .BuildServiceProvider();
+
+ Console.ReadKey();
+ }
+ }
+}
diff --git a/NetCasbin/InternalEnforcer.cs b/NetCasbin/InternalEnforcer.cs
index 56f105c9..added60e 100644
--- a/NetCasbin/InternalEnforcer.cs
+++ b/NetCasbin/InternalEnforcer.cs
@@ -1,6 +1,7 @@
using System;
using System.Collections.Generic;
using System.Linq;
+using System.Security;
using System.Threading.Tasks;
using NetCasbin.Model;
@@ -44,7 +45,14 @@ protected bool InternalAddPolicy(string sec, string ptype, List rule)
return false;
}
- NoticePolicyChanged(sec);
+ if (sec.Equals(PermConstants.Section.RoleSection))
+ {
+ model.BuildIncrementalRoleLink(roleManager, PolicyOperation.PolicyAdd,
+ sec, ptype, rule);
+ ExpressionHandler.SetGFunctions();
+ }
+
+ NotifyPolicyChanged();
return true;
}
@@ -81,7 +89,14 @@ protected async Task InternalAddPolicyAsync(string sec, string ptype, List
return false;
}
- await NoticePolicyChangedAsync(sec);
+ if (sec.Equals(PermConstants.Section.RoleSection))
+ {
+ model.BuildIncrementalRoleLink(roleManager, PolicyOperation.PolicyAdd,
+ sec, ptype, rule);
+ ExpressionHandler.SetGFunctions();
+ }
+
+ await NotifyPolicyChangedAsync();
return true;
}
@@ -120,7 +135,14 @@ protected bool InternalAddPolicies(string sec, string ptype, IEnumerable InternalAddPoliciesAsync(string sec, string ptype, IE
return false;
}
- await NoticePolicyChangedAsync(sec);
+ if (sec.Equals(PermConstants.Section.RoleSection))
+ {
+ model.BuildIncrementalRoleLinks(roleManager, PolicyOperation.PolicyAdd,
+ sec, ptype, ruleArray);
+ ExpressionHandler.SetGFunctions();
+ }
+
+ await NotifyPolicyChangedAsync();
return true;
}
@@ -197,7 +226,14 @@ protected bool InternalRemovePolicy(string sec, string ptype, List rule)
return false;
}
- NoticePolicyChanged(sec);
+ if (sec.Equals(PermConstants.Section.RoleSection))
+ {
+ model.BuildIncrementalRoleLink(roleManager, PolicyOperation.PolicyRemove,
+ sec, ptype, rule);
+ ExpressionHandler.SetGFunctions();
+ }
+
+ NotifyPolicyChanged();
return true;
}
@@ -234,7 +270,14 @@ protected async Task InternalRemovePolicyAsync(string sec, string ptype, L
return false;
}
- await NoticePolicyChangedAsync(sec);
+ if (sec.Equals(PermConstants.Section.RoleSection))
+ {
+ model.BuildIncrementalRoleLink(roleManager, PolicyOperation.PolicyRemove,
+ sec, ptype, rule);
+ ExpressionHandler.SetGFunctions();
+ }
+
+ await NotifyPolicyChangedAsync();
return true;
}
@@ -273,7 +316,14 @@ protected bool InternalRemovePolicies(string sec, string ptype, IEnumerable InternalRemovePoliciesAsync(string sec, string ptype,
return false;
}
- await NoticePolicyChangedAsync(sec);
+ if (sec.Equals(PermConstants.Section.RoleSection))
+ {
+ model.BuildIncrementalRoleLinks(roleManager, PolicyOperation.PolicyRemove,
+ sec, ptype, ruleArray);
+ ExpressionHandler.SetGFunctions();
+ }
+
+ await NotifyPolicyChangedAsync();
return true;
}
@@ -345,7 +402,13 @@ protected bool InternalRemoveFilteredPolicy(string sec, string ptype, int fieldI
return false;
}
- NoticePolicyChanged(sec);
+ if (sec.Equals(PermConstants.Section.RoleSection))
+ {
+ BuildRoleLinks();
+ ExpressionHandler.SetGFunctions();
+ }
+
+ NotifyPolicyChanged();
return true;
}
@@ -378,32 +441,26 @@ protected async Task InternalRemoveFilteredPolicyAsync(string sec, string
return false;
}
- await NoticePolicyChangedAsync(sec);
- return true;
- }
-
- private void NoticePolicyChanged(string section)
- {
- if (autoBuildRoleLinks && section.Equals(PermConstants.Section.RoleSection))
+ if (sec.Equals(PermConstants.Section.RoleSection))
{
BuildRoleLinks();
ExpressionHandler.SetGFunctions();
}
+ await NotifyPolicyChangedAsync();
+ return true;
+ }
+
+ private void NotifyPolicyChanged()
+ {
if (autoNotifyWatcher)
{
watcher?.Update();
}
}
- private async Task NoticePolicyChangedAsync(string section)
+ private async Task NotifyPolicyChangedAsync()
{
- if (autoBuildRoleLinks && section.Equals(PermConstants.Section.RoleSection))
- {
- BuildRoleLinks();
- ExpressionHandler.SetGFunctions();
- }
-
if (autoNotifyWatcher && watcher is not null)
{
await watcher.UpdateAsync();
diff --git a/NetCasbin/Model/Assertion.cs b/NetCasbin/Model/Assertion.cs
index 23ebef3e..6c802600 100644
--- a/NetCasbin/Model/Assertion.cs
+++ b/NetCasbin/Model/Assertion.cs
@@ -40,34 +40,110 @@ public void RefreshPolicyStringSet()
}
}
+ internal void BuildIncrementalRoleLink(IRoleManager roleManager,
+ PolicyOperation policyOperation, IEnumerable rule)
+ {
+ RoleManager = roleManager;
+ int count = Value.Count(c => c is '_');
+ if (count < 2)
+ {
+ throw new InvalidOperationException("the number of \"_\" in role definition should be at least 2.");
+ }
+
+ BuildRoleLink(roleManager, count, policyOperation, rule);
+ }
+
+ internal void BuildIncrementalRoleLinks(IRoleManager roleManager,
+ PolicyOperation policyOperation, IEnumerable> rules)
+ {
+ RoleManager = roleManager;
+ int count = Value.Count(c => c is '_');
+ if (count < 2)
+ {
+ throw new InvalidOperationException("the number of \"_\" in role definition should be at least 2.");
+ }
+
+ foreach (var rule in rules)
+ {
+ BuildRoleLink(roleManager, count, policyOperation, rule);
+ }
+ }
+
public void BuildRoleLinks(IRoleManager roleManager)
{
RoleManager = roleManager;
- int count = Value.ToCharArray().Count(x => x == '_');
+ int count = Value.Count(c => c is '_');
+ if (count < 2)
+ {
+ throw new InvalidOperationException("the number of \"_\" in role definition should be at least 2.");
+ }
+
foreach (var rule in Policy)
{
- if (count < 2)
- {
- throw new Exception("the number of \"_\" in role definition should be at least 2");
- }
- if (rule.Count < count)
- {
- throw new Exception("grouping policy elements do not meet role definition");
- }
+ BuildRoleLink(roleManager, count, PolicyOperation.PolicyAdd, rule);
+ }
+ }
- if (count == 2)
- {
- roleManager.AddLink(rule[0], rule[1]);
- }
- else if (count == 3)
- {
- roleManager.AddLink(rule[0], rule[1], rule[2]);
- }
- else if (count == 4)
- {
- roleManager.AddLink(rule[0], rule[1], rule[2], rule[3]);
- }
+ private static void BuildRoleLink(IRoleManager roleManager, int groupPolicyCount,
+ PolicyOperation policyOperation, IEnumerable rule)
+ {
+ List ruleEnum = rule as List ?? rule.ToList();
+ int ruleCount = ruleEnum.Count;
+
+ if (ruleCount < groupPolicyCount)
+ {
+ throw new InvalidOperationException("Grouping policy elements do not meet role definition.");
+ }
+
+ if (ruleCount > groupPolicyCount)
+ {
+ ruleEnum = ruleEnum.GetRange(0, groupPolicyCount);
}
+
+ switch (policyOperation)
+ {
+ case PolicyOperation.PolicyAdd:
+ switch (groupPolicyCount)
+ {
+ case 2:
+ roleManager.AddLink(ruleEnum[0], ruleEnum[1]);
+ break;
+ case 3:
+ roleManager.AddLink(ruleEnum[0], ruleEnum[1], ruleEnum[2]);
+ break;
+ case 4:
+ roleManager.AddLink(ruleEnum[0], ruleEnum[1],
+ ruleEnum[2], ruleEnum[3]);
+ break;
+ default:
+ roleManager.AddLink(ruleEnum[0], ruleEnum[1],
+ ruleEnum.GetRange(2, groupPolicyCount - 2).ToArray());
+ break;
+ }
+ break;
+ case PolicyOperation.PolicyRemove:
+ switch (groupPolicyCount)
+ {
+ case 2:
+ roleManager.DeleteLink(ruleEnum[0], ruleEnum[1]);
+ break;
+ case 3:
+ roleManager.DeleteLink(ruleEnum[0], ruleEnum[1], ruleEnum[2]);
+ break;
+ case 4:
+ roleManager.DeleteLink(ruleEnum[0], ruleEnum[1],
+ ruleEnum[2], ruleEnum[3]);
+ break;
+ default:
+ roleManager.DeleteLink(ruleEnum[0], ruleEnum[1],
+ ruleEnum.GetRange(2, groupPolicyCount - 2).ToArray());
+ break;
+ }
+ break;
+ default:
+ throw new ArgumentOutOfRangeException(nameof(policyOperation), policyOperation, null);
+ }
+
}
internal bool Contains(IEnumerable rule)
diff --git a/NetCasbin/Model/Policy.cs b/NetCasbin/Model/Policy.cs
index 37db4ba9..1e79e0e0 100644
--- a/NetCasbin/Model/Policy.cs
+++ b/NetCasbin/Model/Policy.cs
@@ -15,14 +15,63 @@ protected Policy()
Model = new Dictionary>();
}
+
+
+ ///
+ /// Provides incremental build the role inheritance relation.
+ ///
+ ///
+ ///
+ ///
+ ///
+ ///
+ public void BuildIncrementalRoleLink(IRoleManager roleManager, PolicyOperation policyOperation,
+ string section, string policyType, IEnumerable rule)
+ {
+ if (Model.ContainsKey(PermConstants.Section.RoleSection) is false)
+ {
+ return;
+ }
+
+ Assertion assertion = GetExistAssertion(section, policyType);
+ assertion.BuildIncrementalRoleLink(roleManager, policyOperation, rule);
+ }
+
+ ///
+ /// Provides incremental build the role inheritance relations.
+ ///
+ ///
+ ///
+ ///
+ ///
+ ///
+ public void BuildIncrementalRoleLinks(IRoleManager roleManager, PolicyOperation policyOperation,
+ string section, string policyType, IEnumerable> rules)
+ {
+ if (Model.ContainsKey(PermConstants.Section.RoleSection) is false)
+ {
+ return;
+ }
+
+ Assertion assertion = GetExistAssertion(section, policyType);
+ assertion.BuildIncrementalRoleLinks(roleManager, policyOperation, rules);
+ }
+
+
+ ///
+ /// Initializes the roles in RBAC.
+ ///
+ ///
public void BuildRoleLinks(IRoleManager roleManager)
{
- if (Model.ContainsKey(PermConstants.Section.RoleSection))
+ if (Model.ContainsKey(PermConstants.Section.RoleSection) is false)
{
- foreach (Assertion assertion in Model[PermConstants.Section.RoleSection].Values)
- {
- assertion.BuildRoleLinks(roleManager);
- }
+ return;
+ }
+
+ foreach (Assertion assertion in Model[PermConstants.Section.RoleSection].Values)
+ {
+ assertion.BuildRoleLinks(roleManager);
}
}
diff --git a/NetCasbin/PolicyOperation.cs b/NetCasbin/PolicyOperation.cs
new file mode 100644
index 00000000..4c2b95b6
--- /dev/null
+++ b/NetCasbin/PolicyOperation.cs
@@ -0,0 +1,8 @@
+namespace NetCasbin
+{
+ public enum PolicyOperation
+ {
+ PolicyAdd,
+ PolicyRemove
+ }
+}