From 05a0e04bfb5a65b3309c5865254ed440a3c42182 Mon Sep 17 00:00:00 2001 From: Sagilio Date: Sat, 30 Jan 2021 19:29:14 +0800 Subject: [PATCH] Support build Incremental role links Signed-off-by: Sagilio --- Casbin.NET.sln | 6 ++ Casbin.Samples/Casbin.Samples.csproj | 25 +++++ Casbin.Samples/Examples/rbac_model.conf | 14 +++ Casbin.Samples/Examples/rbac_policy.csv | 5 + Casbin.Samples/Program.cs | 23 +++++ NetCasbin/InternalEnforcer.cs | 103 ++++++++++++++++----- NetCasbin/Model/Assertion.cs | 118 +++++++++++++++++++----- NetCasbin/Model/Policy.cs | 59 +++++++++++- NetCasbin/PolicyOperation.cs | 8 ++ 9 files changed, 312 insertions(+), 49 deletions(-) create mode 100644 Casbin.Samples/Casbin.Samples.csproj create mode 100644 Casbin.Samples/Examples/rbac_model.conf create mode 100644 Casbin.Samples/Examples/rbac_policy.csv create mode 100644 Casbin.Samples/Program.cs create mode 100644 NetCasbin/PolicyOperation.cs 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 + } +}