Skip to content

Commit

Permalink
feat: Support thread-safe policy management
Browse files Browse the repository at this point in the history
Signed-off-by: Sagilio <Sagilio@outlook.com>
  • Loading branch information
sagilio committed Apr 3, 2021
1 parent 782e9b9 commit 849c632
Show file tree
Hide file tree
Showing 22 changed files with 589 additions and 388 deletions.
2 changes: 1 addition & 1 deletion NetCasbin.UnitTest/EnforcerTest.cs
Original file line number Diff line number Diff line change
Expand Up @@ -537,7 +537,7 @@ public void TestEnableAutoSave()
[Fact]
public async Task TestEnableAutoSaveAsync()
{
var e = new Enforcer("examples/basic_model.conf", "examples/basic_policy_for_async_adapter_test.csv");
var e = SyncedEnforcer.Create("examples/basic_model.conf", "examples/basic_policy_for_async_adapter_test.csv");

e.EnableAutoSave(false);
// Because AutoSave is disabled, the policy change only affects the policy in Casbin enforcer,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -8,12 +8,12 @@
namespace Casbin.UnitTests
{
[Collection("Model collection")]
public class EnforcerCacheTest
public class EnforcerWithCacheTest
{
private readonly ITestOutputHelper _testOutputHelper;
private readonly TestModelFixture _testModelFixture;

public EnforcerCacheTest(ITestOutputHelper testOutputHelper, TestModelFixture testModelFixture)
public EnforcerWithCacheTest(ITestOutputHelper testOutputHelper, TestModelFixture testModelFixture)
{
_testOutputHelper = testOutputHelper;
_testModelFixture = testModelFixture;
Expand Down
3 changes: 2 additions & 1 deletion NetCasbin.UnitTest/GroupRoleManagerTest.cs
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
using Casbin.Rbac;
using Casbin.Extensions;
using Casbin.Rbac;
using Xunit;
using static Casbin.UnitTests.Util.TestUtil;

Expand Down
48 changes: 24 additions & 24 deletions NetCasbin.UnitTest/Util/TestUtil.cs
Original file line number Diff line number Diff line change
Expand Up @@ -21,13 +21,13 @@ internal static List<string> AsList(params string[] values)
return values.ToList();
}

internal static void TestEnforce(Enforcer e, object sub, object obj, string act, bool res)
internal static void TestEnforce(IEnforcer e, object sub, object obj, string act, bool res)
{
Assert.Equal(res, e.Enforce(sub, obj, act));
}

#if !NET452
internal static void TestEnforceEx(Enforcer e, object sub, object obj, string act, List<string> res)
internal static void TestEnforceEx(IEnforcer e, object sub, object obj, string act, List<string> res)
{
var myRes = e.EnforceEx(sub, obj, act).Explains.ToList();
string message = "Key: " + myRes + ", supposed to be " + res;
Expand All @@ -37,7 +37,7 @@ internal static void TestEnforceEx(Enforcer e, object sub, object obj, string ac
}
}
#else
internal static void TestEnforceEx(Enforcer e, object sub, object obj, string act, List<string> res)
internal static void TestEnforceEx(IEnforcer e, object sub, object obj, string act, List<string> res)
{
var myRes = e.EnforceEx(sub, obj, act).Item2.ToList();
string message = "Key: " + myRes + ", supposed to be " + res;
Expand All @@ -48,127 +48,127 @@ internal static void TestEnforceEx(Enforcer e, object sub, object obj, string ac
}
#endif

internal static async Task TestEnforceExAsync(Enforcer e, object sub, object obj, string act, List<string> res)
internal static async Task TestEnforceExAsync(IEnforcer e, object sub, object obj, string act, List<string> res)
{
var myRes = (await e.EnforceExAsync(sub, obj, act)).Item2.ToList();
string message = "Key: " + myRes + ", supposed to be " + res;
if (myRes.Count > 0)
if (myRes.Any())
{
Assert.True(Utility.SetEquals(res, myRes[0].ToList()), message);
}
}

internal static async Task TestEnforceAsync(Enforcer e, object sub, object obj, string act, bool res)
internal static async Task TestEnforceAsync(IEnforcer e, object sub, object obj, string act, bool res)
{
Assert.Equal(res, await e.EnforceAsync(sub, obj, act));
}

internal static void TestEnforceWithoutUsers(Enforcer e, string obj, string act, bool res)
internal static void TestEnforceWithoutUsers(IEnforcer e, string obj, string act, bool res)
{
Assert.Equal(res, e.Enforce(obj, act));
}

internal static async Task TestEnforceWithoutUsersAsync(Enforcer e, string obj, string act, bool res)
internal static async Task TestEnforceWithoutUsersAsync(IEnforcer e, string obj, string act, bool res)
{
Assert.Equal(res, await e.EnforceAsync(obj, act));
}

internal static void TestDomainEnforce(Enforcer e, string sub, string dom, string obj, string act, bool res)
internal static void TestDomainEnforce(IEnforcer e, string sub, string dom, string obj, string act, bool res)
{
Assert.Equal(res, e.Enforce(sub, dom, obj, act));
}

internal static void TestGetPolicy(Enforcer e, List<List<string>> res)
internal static void TestGetPolicy(IEnforcer e, List<List<string>> res)
{
var myRes = e.GetPolicy();
Assert.True(res.DeepEquals(myRes));
}

internal static void TestGetFilteredPolicy(Enforcer e, int fieldIndex, List<List<string>> res, params string[] fieldValues)
internal static void TestGetFilteredPolicy(IEnforcer e, int fieldIndex, List<List<string>> res, params string[] fieldValues)
{
var myRes = e.GetFilteredPolicy(fieldIndex, fieldValues);
Assert.True(res.DeepEquals(myRes));
}

internal static void TestGetGroupingPolicy(Enforcer e, List<List<string>> res)
internal static void TestGetGroupingPolicy(IEnforcer e, List<List<string>> res)
{
var myRes = e.GetGroupingPolicy();
Assert.Equal(res, myRes);
}

internal static void TestGetFilteredGroupingPolicy(Enforcer e, int fieldIndex, List<List<string>> res, params string[] fieldValues)
internal static void TestGetFilteredGroupingPolicy(IEnforcer e, int fieldIndex, List<List<string>> res, params string[] fieldValues)
{
var myRes = e.GetFilteredGroupingPolicy(fieldIndex, fieldValues);
Assert.Equal(res, myRes);
}

internal static void TestHasPolicy(Enforcer e, List<string> policy, bool res)
internal static void TestHasPolicy(IEnforcer e, List<string> policy, bool res)
{
bool myRes = e.HasPolicy(policy);
Assert.Equal(res, myRes);
}

internal static void TestHasGroupingPolicy(Enforcer e, List<string> policy, bool res)
internal static void TestHasGroupingPolicy(IEnforcer e, List<string> policy, bool res)
{
bool myRes = e.HasGroupingPolicy(policy);
Assert.Equal(res, myRes);
}

internal static void TestGetRoles(Enforcer e, string name, List<string> res, string domain = null)
internal static void TestGetRoles(IEnforcer e, string name, List<string> res, string domain = null)
{
List<string> myRes = e.GetRolesForUser(name, domain);
string message = "Roles for " + name + ": " + myRes + ", supposed to be " + res;
Assert.True(Utility.SetEquals(res, myRes), message);
}

internal static void TestGetUsers(Enforcer e, string name, List<string> res, string domain = null)
internal static void TestGetUsers(IEnforcer e, string name, List<string> res, string domain = null)
{
List<string> myRes = e.GetUsersForRole(name, domain);
string message = "Users for " + name + ": " + myRes + ", supposed to be " + res;
Assert.True(Utility.SetEquals(res, myRes), message);
}

internal static void TestHasRole(Enforcer e, string name, string role, bool res, string domain = null)
internal static void TestHasRole(IEnforcer e, string name, string role, bool res, string domain = null)
{
bool myRes = e.HasRoleForUser(name, role, domain);
Assert.Equal(res, myRes);
}

internal static void TestGetPermissions(Enforcer e, string name, List<List<string>> res, string domain = null)
internal static void TestGetPermissions(IEnforcer e, string name, List<List<string>> res, string domain = null)
{
var myRes = e.GetPermissionsForUser(name, domain);
string message = "Permissions for " + name + ": " + myRes + ", supposed to be " + res;
Assert.True(res.DeepEquals(myRes), message);
}

internal static void TestGetImplicitPermissions(Enforcer e, string name, List<List<string>> res, string domain = null)
internal static void TestGetImplicitPermissions(IEnforcer e, string name, List<List<string>> res, string domain = null)
{
var myRes = e.GetImplicitPermissionsForUser(name, domain);
string message = "Implicit permissions for " + name + ": " + myRes + ", supposed to be " + res;
Assert.True(res.DeepEquals(myRes), message);
}

internal static void TestHasPermission(Enforcer e, string name, List<string> permission, bool res)
internal static void TestHasPermission(IEnforcer e, string name, List<string> permission, bool res)
{
bool myRes = e.HasPermissionForUser(name, permission);
Assert.Equal(res, myRes);
}

internal static void TestGetRolesInDomain(Enforcer e, string name, string domain, List<string> res)
internal static void TestGetRolesInDomain(IEnforcer e, string name, string domain, List<string> res)
{
List<string> myRes = e.GetRolesForUserInDomain(name, domain);
string message = "Roles for " + name + " under " + domain + ": " + myRes + ", supposed to be " + res;
Assert.True(Utility.SetEquals(res, myRes), message);
}

internal static void TestGetImplicitRolesInDomain(Enforcer e, string name, string domain, List<string> res)
internal static void TestGetImplicitRolesInDomain(IEnforcer e, string name, string domain, List<string> res)
{
List<string> myRes = e.GetImplicitRolesForUser(name, domain);
string message = "Implicit roles in domain " + name + " under " + domain + ": " + myRes + ", supposed to be " + res;
Assert.True(Utility.SetEquals(res, myRes), message);
}

internal static void TestGetPermissionsInDomain(Enforcer e, string name, string domain, List<List<string>> res)
internal static void TestGetPermissionsInDomain(IEnforcer e, string name, string domain, List<List<string>> res)
{
var myRes = e.GetPermissionsForUserInDomain(name, domain);
Assert.True(res.DeepEquals(myRes), "Permissions for " + name + " under " + domain + ": " + myRes + ", supposed to be " + res);
Expand Down
1 change: 1 addition & 0 deletions NetCasbin.UnitTest/WatcherTest.cs
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
using System;
using System.Threading.Tasks;
using Casbin.Adapter.File;
using Casbin.Extensions;
using Casbin.Persist;
using Casbin.UnitTests.Fixtures;
using Xunit;
Expand Down
138 changes: 56 additions & 82 deletions NetCasbin/Abstractions/IEnforcer.cs
Original file line number Diff line number Diff line change
@@ -1,3 +1,5 @@
using System;
using System.Collections.Generic;
using System.Threading.Tasks;
using Casbin.Persist;
using Casbin.Rbac;
Expand All @@ -12,96 +14,30 @@ namespace Casbin
public interface IEnforcer
{
#region Options
public bool Enabled { get; }
public bool EnabledCache { get; }
public bool AutoSave { get; }
public bool AutoBuildRoleLinks { get; }
public bool AutoNotifyWatcher { get; }
public bool AutoCleanEnforceCache { get; }
public bool Enabled { get; set; }
public bool EnabledCache { get; set; }
public bool AutoSave { get; set; }
public bool AutoBuildRoleLinks { get; set; }
public bool AutoNotifyWatcher { get; set; }
public bool AutoCleanEnforceCache { get; set; }
#endregion

#region Extensions
public IEffector Effector { get; }
public IModel Model { get; }
public IPolicyManager PolicyManager { get; }
public IAdapter Adapter { get; }
public IWatcher Watcher { get; }
public IRoleManager RoleManager { get; }
public IEnforceCache EnforceCache { get; }
public IEffector Effector { get; set; }
public IModel Model { get; set; }
public IPolicyManager PolicyManager { get; set; }
public IAdapter Adapter { get; set; }
public IWatcher Watcher { get; set; }
public IRoleManager RoleManager { get; set; }
public IEnforceCache EnforceCache { get; set; }
public IExpressionHandler ExpressionHandler { get; set; }
#if !NET45
public ILogger Logger { get; set; }
#endif
#endregion

public string ModelPath { get; }
public bool IsFiltered { get; }
public IExpressionHandler ExpressionHandler { get; }

/// <summary>
/// Changes the enforcing state of Casbin, when Casbin is disabled,
/// all access will be allowed by the enforce() function.
/// </summary>
/// <param name="enable"></param>
public void EnableEnforce(bool enable);

/// <summary>
/// Controls whether to save a policy rule automatically to the
/// adapter when it is added or removed.
/// </summary>
/// <param name="autoSave"></param>
public void EnableAutoSave(bool autoSave);

/// <summary>
/// Controls whether to save a policy rule automatically
/// to the adapter when it is added or removed.
/// </summary>
/// <param name="autoBuildRoleLinks">Whether to automatically build the role links.</param>
public void EnableAutoBuildRoleLinks(bool autoBuildRoleLinks);



/// <summary>
/// Sets the current model.
/// </summary>
/// <param name="modelPath"></param>
public void SetModel(string modelPath);

/// <summary>
/// Sets the current model.
/// </summary>
/// <param name="model"></param>
public void SetModel(IModel model);

/// <summary>
/// Sets an adapter.
/// </summary>
/// <param name="adapter"></param>
public void SetAdapter(IAdapter adapter);

/// <summary>
/// Sets an watcher.
/// </summary>
/// <param name="watcher"></param>
/// <param name="useAsync">Whether use async update callback.</param>
public void SetWatcher(IWatcher watcher, bool useAsync = true);

/// <summary>
/// Sets the current role manager.
/// </summary>
/// <param name="roleManager"></param>
public void SetRoleManager(IRoleManager roleManager);

/// <summary>
/// Sets the current effector.
/// </summary>
/// <param name="effector"></param>
public void SetEffector(IEffector effector);

/// <summary>
/// Sets an enforce cache.
/// </summary>
/// <param name="enforceCache"></param>
public void SetEnforceCache(IEnforceCache enforceCache);

/// <summary>
/// LoadModel reloads the model from the model CONF file. Because the policy is
Expand Down Expand Up @@ -164,10 +100,48 @@ public interface IEnforcer
/// Decides whether a "subject" can access a "object" with the operation
/// "action", input parameters are usually: (sub, obj, act).
/// </summary>
/// <param name="rvals">The request needs to be mediated, usually an array of strings,
/// <param name="requestValues">The request needs to be mediated, usually an array of strings,
/// can be class instances if ABAC is used.</param>
/// <returns>Whether to allow the request.</returns>
public bool Enforce(params object[] requestValues);

/// <summary>
/// Decides whether a "subject" can access a "object" with the operation
/// "action", input parameters are usually: (sub, obj, act).
/// </summary>
/// <param name="requestValues">The request needs to be mediated, usually an array of strings,
/// can be class instances if ABAC is used.</param>
/// <returns>Whether to allow the request.</returns>
public bool Enforce(params object[] rvals);
public Task<bool> EnforceAsync(params object[] requestValues);

/// <summary>
/// Explains enforcement by informing matched rules
/// </summary>
/// <param name="requestValues">The request needs to be mediated, usually an array of strings,
/// can be class instances if ABAC is used.</param>
/// <returns>Whether to allow the request and explains.</returns>
#if !NET45

public (bool Result, IEnumerable<IEnumerable<string>> Explains)
EnforceEx(params object[] requestValues);
#else
public Tuple<bool, IEnumerable<IEnumerable<string>>>
EnforceEx(params object[] requestValues);
#endif

/// <summary>
/// Explains enforcement by informing matched rules
/// </summary>
/// <param name="requestValues">The request needs to be mediated, usually an array of strings,
/// can be class instances if ABAC is used.</param>
/// <returns>Whether to allow the request and explains.</returns>
#if !NET45
public Task<(bool Result, IEnumerable<IEnumerable<string>> Explains)>
EnforceExAsync(params object[] requestValues);
#else
public Task<Tuple<bool, IEnumerable<IEnumerable<string>>>>
EnforceExAsync(params object[] requestValues);
#endif
}

}
4 changes: 2 additions & 2 deletions NetCasbin/Abstractions/IModel.cs
Original file line number Diff line number Diff line change
Expand Up @@ -2,9 +2,9 @@
{
public interface IModel : IPolicy
{
public IPolicyManager PolicyManager { get; }
public string ModelPath { get; }

public void SetPolicyManager(IPolicyManager policyManager);
public IPolicyManager PolicyManager { get; set; }

public void LoadModelFromFile(string path);

Expand Down
Loading

0 comments on commit 849c632

Please # to comment.