Skip to content

Commit c2a60b7

Browse files
committed
fix: respect AutoSave flag for grouping policy operations
The EnableAutoSave(false) setting was not being respected for RBAC/grouping policy operations. When AutoSave was disabled, policy operations (AddPolicy, RemovePolicy, UpdatePolicy) correctly skipped adapter saving, but grouping policy operations (AddGroupingPolicy, RemoveGroupingPolicy, etc.) still saved to the adapter. Root Cause: The SetAutoSave() method only iterated through policy assertions (section "p") to set the AutoSave flag. It never set the flag for role assertions (section "g"), even though RoleAssertion has its own PolicyManager with an AutoSave property. Solution: Modified SetAutoSave() to also configure the AutoSave flag for role/grouping assertions, with a safety check for models without role definitions. Changes: - Casbin/Extensions/Model/ModelExtension.cs: Updated SetAutoSave() to handle both policy and role assertions - Casbin.UnitTests/ModelTests/EnforcerTest.cs: Added comprehensive tests for sync and async grouping policy operations - Casbin.UnitTests/Mock/MockSingleAdapter.cs: Created test helper to track adapter save operations All 363 unit tests pass with no regressions.
1 parent 67dd0a4 commit c2a60b7

File tree

3 files changed

+129
-0
lines changed

3 files changed

+129
-0
lines changed
Lines changed: 66 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,66 @@
1+
using System.Collections.Generic;
2+
using System.Threading.Tasks;
3+
using Casbin.Model;
4+
using Casbin.Persist;
5+
using Casbin.Persist.Adapter.File;
6+
7+
namespace Casbin.UnitTests.Mock;
8+
9+
public class MockSingleAdapter : FileAdapter, ISingleAdapter
10+
{
11+
public List<string> SavedPolicies { get; } = new();
12+
13+
public MockSingleAdapter(string filePath) : base(filePath)
14+
{
15+
}
16+
17+
public void AddPolicy(string section, string policyType, IPolicyValues rule)
18+
{
19+
SavedPolicies.Add($"AddPolicy: {section}.{policyType} {rule.ToText()}");
20+
}
21+
22+
public Task AddPolicyAsync(string section, string policyType, IPolicyValues rule)
23+
{
24+
SavedPolicies.Add($"AddPolicyAsync: {section}.{policyType} {rule.ToText()}");
25+
#if NET452
26+
return Task.FromResult(0);
27+
#else
28+
return Task.CompletedTask;
29+
#endif
30+
}
31+
32+
public void UpdatePolicy(string section, string policyType, IPolicyValues oldRule, IPolicyValues newRule)
33+
{
34+
SavedPolicies.Add($"UpdatePolicy: {section}.{policyType} {oldRule.ToText()} -> {newRule.ToText()}");
35+
}
36+
37+
public Task UpdatePolicyAsync(string section, string policyType, IPolicyValues oldRules, IPolicyValues newRules)
38+
{
39+
SavedPolicies.Add($"UpdatePolicyAsync: {section}.{policyType} {oldRules.ToText()} -> {newRules.ToText()}");
40+
#if NET452
41+
return Task.FromResult(0);
42+
#else
43+
return Task.CompletedTask;
44+
#endif
45+
}
46+
47+
public void RemovePolicy(string section, string policyType, IPolicyValues rule)
48+
{
49+
SavedPolicies.Add($"RemovePolicy: {section}.{policyType} {rule.ToText()}");
50+
}
51+
52+
public Task RemovePolicyAsync(string section, string policyType, IPolicyValues rule)
53+
{
54+
SavedPolicies.Add($"RemovePolicyAsync: {section}.{policyType} {rule.ToText()}");
55+
#if NET452
56+
return Task.FromResult(0);
57+
#else
58+
return Task.CompletedTask;
59+
#endif
60+
}
61+
62+
public void ClearSavedPolicies()
63+
{
64+
SavedPolicies.Clear();
65+
}
66+
}

Casbin.UnitTests/ModelTests/EnforcerTest.cs

Lines changed: 53 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -939,6 +939,59 @@ public async Task TestEnableAutoSaveAsync()
939939
Assert.True(await e.EnforceAsync("bob", "data2", "write"));
940940
}
941941

942+
[Fact]
943+
public void TestAutoSaveGroupingPolicy()
944+
{
945+
// This test verifies that AddGroupingPolicy() respects the AutoSave flag.
946+
// When AutoSave is disabled, grouping policy changes should not be saved to the adapter.
947+
948+
MockSingleAdapter adapter = new("Examples/rbac_policy.csv");
949+
Enforcer e = new("Examples/rbac_model.conf", adapter);
950+
951+
// Verify initial state: alice has data2_admin role
952+
Assert.True(e.HasGroupingPolicy("alice", "data2_admin"));
953+
Assert.False(e.HasGroupingPolicy("bob", "data2_admin"));
954+
955+
adapter.ClearSavedPolicies();
956+
e.EnableAutoSave(false);
957+
958+
// Because AutoSave is disabled, the grouping policy change should only affect
959+
// the policy in Casbin enforcer, it should NOT call the adapter.
960+
e.AddGroupingPolicy("bob", "data2_admin");
961+
962+
// Verify the change is in memory
963+
Assert.True(e.HasGroupingPolicy("bob", "data2_admin"));
964+
965+
// Verify the adapter was NOT called because AutoSave is disabled
966+
Assert.Empty(adapter.SavedPolicies);
967+
}
968+
969+
[Fact]
970+
public async Task TestAutoSaveGroupingPolicyAsync()
971+
{
972+
// This test verifies that AddGroupingPolicyAsync() respects the AutoSave flag.
973+
// When AutoSave is disabled, grouping policy changes should not be saved to the adapter.
974+
975+
MockSingleAdapter adapter = new("Examples/rbac_policy.csv");
976+
Enforcer e = new("Examples/rbac_model.conf", adapter);
977+
978+
// Verify initial state
979+
Assert.True(e.HasGroupingPolicy("alice", "data2_admin"));
980+
Assert.False(e.HasGroupingPolicy("bob", "data2_admin"));
981+
982+
adapter.ClearSavedPolicies();
983+
e.EnableAutoSave(false);
984+
985+
// Add grouping policy with AutoSave disabled
986+
await e.AddGroupingPolicyAsync("bob", "data2_admin");
987+
988+
// Verify the change is in memory
989+
Assert.True(e.HasGroupingPolicy("bob", "data2_admin"));
990+
991+
// Verify the adapter was NOT called because AutoSave is disabled
992+
Assert.Empty(adapter.SavedPolicies);
993+
}
994+
942995
[Fact]
943996
public void TestInitWithAdapter()
944997
{

Casbin/Extensions/Model/ModelExtension.cs

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -228,10 +228,20 @@ public static async Task<bool> SavePolicyAsync(this IModel model)
228228

229229
public static void SetAutoSave(this IModel model, bool autoSave)
230230
{
231+
// Set AutoSave for policy assertions (section "p")
231232
foreach (KeyValuePair<string, PolicyAssertion> pair in model.Sections.GetPolicyAssertions())
232233
{
233234
pair.Value.PolicyManager.AutoSave = autoSave;
234235
}
236+
237+
// Set AutoSave for role/grouping assertions (section "g") if they exist
238+
if (model.Sections.ContainsSection(PermConstants.Section.RoleSection))
239+
{
240+
foreach (KeyValuePair<string, RoleAssertion> pair in model.Sections.GetRoleAssertions())
241+
{
242+
pair.Value.PolicyManager.AutoSave = autoSave;
243+
}
244+
}
235245
}
236246

237247
public static IPolicyManager GetPolicyManager(this IModel model, string section,

0 commit comments

Comments
 (0)