blob: 578c2c6157da22f5788471908bd4a693f5f08263 [file] [log] [blame]
using System.Collections.Generic;
using System.IO;
using System.Threading.Tasks;
using Casbin.Model;
using Casbin.Persist;
using Casbin.Persist.Adapter.File;
using Casbin.Persist.Adapter.Stream;
using Casbin.Rbac;
using Casbin.UnitTests.Fixtures;
using Casbin.UnitTests.Mock;
using Xunit;
using Xunit.Abstractions;
using static Casbin.UnitTests.Util.TestUtil;
namespace Casbin.UnitTests.ModelTests;
[Collection("Model collection")]
public class EnforcerTest
{
private readonly ITestOutputHelper _testOutputHelper;
public EnforcerTest(ITestOutputHelper testOutputHelper)
{
_testOutputHelper = testOutputHelper;
}
[Fact]
public void TestEnforceWithMultipleRoleManager()
{
Enforcer e = new(TestModelFixture.GetNewTestModel(
TestModelFixture.RbacMultipleModelText,
TestModelFixture.RbacMultiplePolicyText));
DefaultRoleManager roleManager = new(5);
roleManager.AddMatchingFunc((arg1, arg2) => arg1.Equals(arg2));
e.SetRoleManager(roleManager);
bool result = e.Enforce("@adm-user", "org::customer1", "cust1", "manage");
Assert.True(result);
roleManager.AddMatchingFunc((arg1, arg2) => !arg1.Equals(arg2));
e.SetRoleManager(roleManager);
result = e.Enforce("@adm-user", "org::customer1", "cust1", "manage");
Assert.False(result);
}
[Fact]
public void TestEnforceWithMultipleEval()
{
Enforcer e = new(TestModelFixture.GetNewTestModel(
TestModelFixture.RbacMultipleEvalModelText,
TestModelFixture.RbacMultipleEvalPolicyText));
bool result = e.Enforce(
"domain1",
new { Role = "admin" },
new { Name = "admin_panel" },
"view");
Assert.True(result);
}
[Fact]
public void TestEnforceWithoutAutoLoadPolicy()
{
IModel m = DefaultModel.Create();
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)");
FileAdapter a = new("Examples/keymatch_policy.csv");
IEnforcer e = new Enforcer(m, a, new EnforcerOptions { AutoLoadPolicy = false });
Assert.Empty(e.GetPolicy());
e = new Enforcer(m, a);
Assert.NotEmpty(e.GetPolicy());
}
[Fact]
public void TestEnforceSubjectPriority()
{
Enforcer e = new(TestModelFixture.GetNewTestModel(
TestModelFixture.SubjectPriorityModelText,
TestModelFixture.SubjectPriorityPolicyText));
Assert.True(e.Enforce("jane", "data1", "read"));
Assert.True(e.Enforce("alice", "data1", "read"));
}
[Fact]
public void TestEnforceSubjectPriorityWithDomain()
{
Enforcer e = new(
Path.Combine("Examples", "subject_priority_model_with_domain.conf"),
Path.Combine("Examples", "subject_priority_policy_with_domain.csv"));
Assert.True(e.Enforce("alice", "data1", "domain1", "write"));
Assert.True(e.Enforce("bob", "data2", "domain2", "write"));
}
#region In memory model
[Fact]
public void TestKeyMatchModelInMemory()
{
IModel m = DefaultModel.Create();
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)");
FileAdapter a = new("Examples/keymatch_policy.csv");
Enforcer e = new(m, a);
Assert.True(e.Enforce("alice", "/alice_data/resource1", "GET"));
Assert.True(e.Enforce("alice", "/alice_data/resource1", "POST"));
Assert.True(e.Enforce("alice", "/alice_data/resource2", "GET"));
Assert.False(e.Enforce("alice", "/alice_data/resource2", "POST"));
Assert.False(e.Enforce("alice", "/bob_data/resource1", "GET"));
Assert.False(e.Enforce("alice", "/bob_data/resource1", "POST"));
Assert.False(e.Enforce("alice", "/bob_data/resource2", "GET"));
Assert.False(e.Enforce("alice", "/bob_data/resource2", "POST"));
Assert.False(e.Enforce("bob", "/alice_data/resource1", "GET"));
Assert.False(e.Enforce("bob", "/alice_data/resource1", "POST"));
Assert.True(e.Enforce("bob", "/alice_data/resource2", "GET"));
Assert.False(e.Enforce("bob", "/alice_data/resource2", "POST"));
Assert.False(e.Enforce("bob", "/bob_data/resource1", "GET"));
Assert.True(e.Enforce("bob", "/bob_data/resource1", "POST"));
Assert.True(e.Enforce("cathy", "/cathy_data", "GET"));
Assert.True(e.Enforce("cathy", "/cathy_data", "POST"));
Assert.False(e.Enforce("cathy", "/cathy_data", "DELETE"));
e = new Enforcer(m);
a.LoadPolicy(e.Model);
Assert.True(e.Enforce("alice", "/alice_data/resource1", "GET"));
Assert.True(e.Enforce("alice", "/alice_data/resource1", "POST"));
Assert.True(e.Enforce("alice", "/alice_data/resource2", "GET"));
Assert.False(e.Enforce("alice", "/alice_data/resource2", "POST"));
Assert.False(e.Enforce("alice", "/bob_data/resource1", "GET"));
Assert.False(e.Enforce("alice", "/bob_data/resource1", "POST"));
Assert.False(e.Enforce("alice", "/bob_data/resource2", "GET"));
Assert.False(e.Enforce("alice", "/bob_data/resource2", "POST"));
Assert.False(e.Enforce("bob", "/alice_data/resource1", "GET"));
Assert.False(e.Enforce("bob", "/alice_data/resource1", "POST"));
Assert.True(e.Enforce("bob", "/alice_data/resource2", "GET"));
Assert.False(e.Enforce("bob", "/alice_data/resource2", "POST"));
Assert.False(e.Enforce("bob", "/bob_data/resource1", "GET"));
Assert.True(e.Enforce("bob", "/bob_data/resource1", "POST"));
Assert.False(e.Enforce("bob", "/bob_data/resource2", "GET"));
Assert.True(e.Enforce("bob", "/bob_data/resource2", "POST"));
Assert.True(e.Enforce("cathy", "/cathy_data", "GET"));
Assert.True(e.Enforce("cathy", "/cathy_data", "POST"));
Assert.False(e.Enforce("cathy", "/cathy_data", "DELETE"));
}
[Fact]
public async Task TestKeyMatchModelInMemoryAsync()
{
IModel m = DefaultModel.Create();
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)");
FileAdapter a = new("Examples/keymatch_policy.csv");
Enforcer e = new(m, a);
Assert.True(await e.EnforceAsync("alice", "/alice_data/resource1", "GET"));
Assert.True(await e.EnforceAsync("alice", "/alice_data/resource1", "POST"));
Assert.True(await e.EnforceAsync("alice", "/alice_data/resource2", "GET"));
Assert.False(await e.EnforceAsync("alice", "/alice_data/resource2", "POST"));
Assert.False(await e.EnforceAsync("alice", "/bob_data/resource1", "GET"));
Assert.False(await e.EnforceAsync("alice", "/bob_data/resource1", "POST"));
Assert.False(await e.EnforceAsync("alice", "/bob_data/resource2", "GET"));
Assert.False(await e.EnforceAsync("alice", "/bob_data/resource2", "POST"));
Assert.False(await e.EnforceAsync("bob", "/alice_data/resource1", "GET"));
Assert.False(await e.EnforceAsync("bob", "/alice_data/resource1", "POST"));
Assert.True(await e.EnforceAsync("bob", "/alice_data/resource2", "GET"));
Assert.False(await e.EnforceAsync("bob", "/alice_data/resource2", "POST"));
Assert.False(await e.EnforceAsync("bob", "/bob_data/resource1", "GET"));
Assert.True(await e.EnforceAsync("bob", "/bob_data/resource1", "POST"));
Assert.True(await e.EnforceAsync("cathy", "/cathy_data", "GET"));
Assert.True(await e.EnforceAsync("cathy", "/cathy_data", "POST"));
Assert.False(await e.EnforceAsync("cathy", "/cathy_data", "DELETE"));
e = new Enforcer(m);
await a.LoadPolicyAsync(e.Model);
Assert.True(await e.EnforceAsync("alice", "/alice_data/resource1", "GET"));
Assert.True(await e.EnforceAsync("alice", "/alice_data/resource1", "POST"));
Assert.True(await e.EnforceAsync("alice", "/alice_data/resource2", "GET"));
Assert.False(await e.EnforceAsync("alice", "/alice_data/resource2", "POST"));
Assert.False(await e.EnforceAsync("alice", "/bob_data/resource1", "GET"));
Assert.False(await e.EnforceAsync("alice", "/bob_data/resource1", "POST"));
Assert.False(await e.EnforceAsync("alice", "/bob_data/resource2", "GET"));
Assert.False(await e.EnforceAsync("alice", "/bob_data/resource2", "POST"));
Assert.False(await e.EnforceAsync("bob", "/alice_data/resource1", "GET"));
Assert.False(await e.EnforceAsync("bob", "/alice_data/resource1", "POST"));
Assert.True(await e.EnforceAsync("bob", "/alice_data/resource2", "GET"));
Assert.False(await e.EnforceAsync("bob", "/alice_data/resource2", "POST"));
Assert.False(await e.EnforceAsync("bob", "/bob_data/resource1", "GET"));
Assert.True(await e.EnforceAsync("bob", "/bob_data/resource1", "POST"));
Assert.False(await e.EnforceAsync("bob", "/bob_data/resource2", "GET"));
Assert.True(await e.EnforceAsync("bob", "/bob_data/resource2", "POST"));
Assert.True(await e.EnforceAsync("cathy", "/cathy_data", "GET"));
Assert.True(await e.EnforceAsync("cathy", "/cathy_data", "POST"));
Assert.False(await e.EnforceAsync("cathy", "/cathy_data", "DELETE"));
}
[Fact]
public void TestKeyMatchModelInMemoryDeny()
{
IModel m = DefaultModel.Create();
m.AddDef("r", "r", "sub, obj, act");
m.AddDef("p", "p", "sub, obj, act");
m.AddDef("e", "e", "!some(where (p.eft == deny))");
m.AddDef("m", "m", "r.sub == p.sub && keyMatch(r.obj, p.obj) && regexMatch(r.act, p.act)");
FileAdapter a = new("Examples/keymatch_policy.csv");
Enforcer e = new(m, a);
Assert.True(e.Enforce("alice", "/alice_data/resource2", "POST"));
}
[Fact]
public void TestInOperator()
{
Enforcer e = new(TestModelFixture.GetNewTestModel(
TestModelFixture.RbacInOperatorModelText,
TestModelFixture.RbacInOperatorPolicyText));
Assert.True(e.Enforce(
new { Name = "Alice", Amount = 5100, Roles = new[] { "Manager", "DepartmentDirector" } },
"authorization", "grant"));
Assert.False(e.Enforce(
new { Name = "Alice", Amount = 5100, Roles = new[] { "DepartmentDirector" } },
"authorization", "grant"));
}
[Fact]
public void TestRbacModelInMemoryIndeterminate()
{
IModel m = DefaultModel.Create();
m.AddDef("r", "r", "sub, obj, act");
m.AddDef("p", "p", "sub, obj, act");
m.AddDef("g", "g", "_, _");
m.AddDef("e", "e", "some(where (p.eft == allow))");
m.AddDef("m", "m", "g(r.sub, p.sub) && r.obj == p.obj && r.act == p.act");
Enforcer e = new(m);
e.AddPermissionForUser("alice", "data1", "invalid");
Assert.False(e.Enforce("alice", "data1", "read"));
}
[Fact]
public async Task TestRbacModelInMemoryIndeterminateAsync()
{
IModel m = DefaultModel.Create();
m.AddDef("r", "r", "sub, obj, act");
m.AddDef("p", "p", "sub, obj, act");
m.AddDef("g", "g", "_, _");
m.AddDef("e", "e", "some(where (p.eft == allow))");
m.AddDef("m", "m", "g(r.sub, p.sub) && r.obj == p.obj && r.act == p.act");
Enforcer e = new(m);
await e.AddPermissionForUserAsync("alice", "data1", "invalid");
Assert.False(await e.EnforceAsync("alice", "data1", "read"));
}
[Fact]
public void TestRbacModelInMemory()
{
IModel m = DefaultModel.Create();
m.AddDef("r", "r", "sub, obj, act");
m.AddDef("p", "p", "sub, obj, act");
m.AddDef("g", "g", "_, _");
m.AddDef("e", "e", "some(where (p.eft == allow))");
m.AddDef("m", "m", "g(r.sub, p.sub) && r.obj == p.obj && r.act == p.act");
Enforcer e = new(m);
e.AddPermissionForUser("alice", "data1", "read");
e.AddPermissionForUser("bob", "data2", "write");
e.AddPermissionForUser("data2_admin", "data2", "read");
e.AddPermissionForUser("data2_admin", "data2", "write");
e.AddRoleForUser("alice", "data2_admin");
Assert.True(e.Enforce("alice", "data1", "read"));
Assert.False(e.Enforce("alice", "data1", "write"));
Assert.True(e.Enforce("alice", "data2", "read"));
Assert.True(e.Enforce("alice", "data2", "write"));
Assert.False(e.Enforce("bob", "data1", "read"));
Assert.False(e.Enforce("bob", "data1", "write"));
Assert.False(e.Enforce("bob", "data2", "read"));
Assert.True(e.Enforce("bob", "data2", "write"));
}
[Fact]
public async Task TestRbacModelInMemoryAsync()
{
IModel m = DefaultModel.Create();
m.AddDef("r", "r", "sub, obj, act");
m.AddDef("p", "p", "sub, obj, act");
m.AddDef("g", "g", "_, _");
m.AddDef("e", "e", "some(where (p.eft == allow))");
m.AddDef("m", "m", "g(r.sub, p.sub) && r.obj == p.obj && r.act == p.act");
Enforcer e = new(m);
await e.AddPermissionForUserAsync("alice", "data1", "read");
await e.AddPermissionForUserAsync("bob", "data2", "write");
await e.AddPermissionForUserAsync("data2_admin", "data2", "read");
await e.AddPermissionForUserAsync("data2_admin", "data2", "write");
await e.AddRoleForUserAsync("alice", "data2_admin");
Assert.True(await e.EnforceAsync("alice", "data1", "read"));
Assert.False(await e.EnforceAsync("alice", "data1", "write"));
Assert.True(await e.EnforceAsync("alice", "data2", "read"));
Assert.True(await e.EnforceAsync("alice", "data2", "write"));
Assert.False(await e.EnforceAsync("bob", "data1", "read"));
Assert.False(await e.EnforceAsync("bob", "data1", "write"));
Assert.False(await e.EnforceAsync("bob", "data2", "read"));
Assert.True(await e.EnforceAsync("bob", "data2", "write"));
}
[Fact]
public void TestRbacBatchEnforceInMemory()
{
IModel m = DefaultModel.Create();
m.AddDef("r", "r", "sub, obj, act");
m.AddDef("p", "p", "sub, obj, act");
m.AddDef("g", "g", "_, _");
m.AddDef("e", "e", "some(where (p.eft == allow))");
m.AddDef("m", "m", "g(r.sub, p.sub) && r.obj == p.obj && r.act == p.act");
Enforcer e = new(m);
e.AddPermissionForUser("alice", "data1", "read");
e.AddPermissionForUser("bob", "data2", "write");
e.AddPermissionForUser("data2_admin", "data2", "read");
e.AddPermissionForUser("data2_admin", "data2", "write");
e.AddRoleForUser("alice", "data2_admin");
IEnumerable<(RequestValues<string, string, string>, bool)> testCases =
[
(Request.CreateValues("alice", "data1", "read"), true),
(Request.CreateValues("alice", "data1", "write"), false),
(Request.CreateValues("alice", "data2", "read"), true),
(Request.CreateValues("alice", "data2", "write"), true),
(Request.CreateValues("bob", "data1", "read"), false),
(Request.CreateValues("bob", "data1", "write"), false),
(Request.CreateValues("bob", "data2", "read"), false),
(Request.CreateValues("bob", "data2", "write"), true)
];
e.TestBatchEnforce(testCases);
}
[Fact]
public void TestRbacParallelBatchEnforceInMemory()
{
IModel m = DefaultModel.Create();
m.AddDef("r", "r", "sub, obj, act");
m.AddDef("p", "p", "sub, obj, act");
m.AddDef("g", "g", "_, _");
m.AddDef("e", "e", "some(where (p.eft == allow))");
m.AddDef("m", "m", "g(r.sub, p.sub) && r.obj == p.obj && r.act == p.act");
Enforcer e = new(m);
e.AddPermissionForUser("alice", "data1", "read");
e.AddPermissionForUser("bob", "data2", "write");
e.AddPermissionForUser("data2_admin", "data2", "read");
e.AddPermissionForUser("data2_admin", "data2", "write");
e.AddRoleForUser("alice", "data2_admin");
IEnumerable<(RequestValues<string, string, string>, bool)> testCases =
[
(Request.CreateValues("alice", "data1", "read"), true),
(Request.CreateValues("alice", "data1", "write"), false),
(Request.CreateValues("alice", "data2", "read"), true),
(Request.CreateValues("alice", "data2", "write"), true),
(Request.CreateValues("bob", "data1", "read"), false),
(Request.CreateValues("bob", "data1", "write"), false),
(Request.CreateValues("bob", "data2", "read"), false),
(Request.CreateValues("bob", "data2", "write"), true)
];
TestParallelBatchEnforce(e, testCases);
}
[Fact]
public void TestRbacBatchEnforceInMemoryAsync()
{
IModel m = DefaultModel.Create();
m.AddDef("r", "r", "sub, obj, act");
m.AddDef("p", "p", "sub, obj, act");
m.AddDef("g", "g", "_, _");
m.AddDef("e", "e", "some(where (p.eft == allow))");
m.AddDef("m", "m", "g(r.sub, p.sub) && r.obj == p.obj && r.act == p.act");
Enforcer e = new(m);
e.AddPermissionForUserAsync("alice", "data1", "read");
e.AddPermissionForUserAsync("bob", "data2", "write");
e.AddPermissionForUserAsync("data2_admin", "data2", "read");
e.AddPermissionForUserAsync("data2_admin", "data2", "write");
e.AddRoleForUserAsync("alice", "data2_admin");
IEnumerable<(RequestValues<string, string, string>, bool)> testCases =
[
(Request.CreateValues("alice", "data1", "read"), true),
(Request.CreateValues("alice", "data1", "write"), false),
(Request.CreateValues("alice", "data2", "read"), true),
(Request.CreateValues("alice", "data2", "write"), true),
(Request.CreateValues("bob", "data1", "read"), false),
(Request.CreateValues("bob", "data1", "write"), false),
(Request.CreateValues("bob", "data2", "read"), false),
(Request.CreateValues("bob", "data2", "write"), true)
];
TestBatchEnforceAsync(e, testCases);
}
[Fact]
public void TestRbacModelInMemory2()
{
string text =
"[request_definition]\n"
+ "r = sub, obj, act\n"
+ "\n"
+ "[policy_definition]\n"
+ "p = sub, obj, act\n"
+ "\n"
+ "[role_definition]\n"
+ "g = _, _\n"
+ "\n"
+ "[policy_effect]\n"
+ "e = some(where (p.eft == allow))\n"
+ "\n"
+ "[matchers]\n"
+ "m = g(r.sub, p.sub) && r.obj == p.obj && r.act == p.act\n";
IModel m = DefaultModel.CreateFromText(text);
Enforcer e = new(m);
e.AddPermissionForUser("alice", "data1", "read");
e.AddPermissionForUser("bob", "data2", "write");
e.AddPermissionForUser("data2_admin", "data2", "read");
e.AddPermissionForUser("data2_admin", "data2", "write");
e.AddRoleForUser("alice", "data2_admin");
Assert.True(e.Enforce("alice", "data1", "read"));
Assert.False(e.Enforce("alice", "data1", "write"));
Assert.True(e.Enforce("alice", "data2", "read"));
Assert.True(e.Enforce("alice", "data2", "write"));
Assert.False(e.Enforce("bob", "data1", "read"));
Assert.False(e.Enforce("bob", "data1", "write"));
Assert.False(e.Enforce("bob", "data2", "read"));
Assert.True(e.Enforce("bob", "data2", "write"));
}
[Fact]
public async Task TestRbacModelInMemory2Async()
{
string text =
"[request_definition]\n"
+ "r = sub, obj, act\n"
+ "\n"
+ "[policy_definition]\n"
+ "p = sub, obj, act\n"
+ "\n"
+ "[role_definition]\n"
+ "g = _, _\n"
+ "\n"
+ "[policy_effect]\n"
+ "e = some(where (p.eft == allow))\n"
+ "\n"
+ "[matchers]\n"
+ "m = g(r.sub, p.sub) && r.obj == p.obj && r.act == p.act\n";
IModel m = DefaultModel.CreateFromText(text);
Enforcer e = new(m);
await e.AddPermissionForUserAsync("alice", "data1", "read");
await e.AddPermissionForUserAsync("bob", "data2", "write");
await e.AddPermissionForUserAsync("data2_admin", "data2", "read");
await e.AddPermissionForUserAsync("data2_admin", "data2", "write");
await e.AddRoleForUserAsync("alice", "data2_admin");
Assert.True(await e.EnforceAsync("alice", "data1", "read"));
Assert.False(await e.EnforceAsync("alice", "data1", "write"));
Assert.True(await e.EnforceAsync("alice", "data2", "read"));
Assert.True(await e.EnforceAsync("alice", "data2", "write"));
Assert.False(await e.EnforceAsync("bob", "data1", "read"));
Assert.False(await e.EnforceAsync("bob", "data1", "write"));
Assert.False(await e.EnforceAsync("bob", "data2", "read"));
Assert.True(await e.EnforceAsync("bob", "data2", "write"));
}
[Fact]
public void TestNotUsedRbacModelInMemory()
{
IModel m = DefaultModel.Create();
m.AddDef("r", "r", "sub, obj, act");
m.AddDef("p", "p", "sub, obj, act");
m.AddDef("g", "g", "_, _");
m.AddDef("e", "e", "some(where (p.eft == allow))");
m.AddDef("m", "m", "g(r.sub, p.sub) && r.obj == p.obj && r.act == p.act");
Enforcer e = new(m);
e.AddPermissionForUser("alice", "data1", "read");
e.AddPermissionForUser("bob", "data2", "write");
Assert.True(e.Enforce("alice", "data1", "read"));
Assert.False(e.Enforce("alice", "data1", "write"));
Assert.False(e.Enforce("alice", "data2", "read"));
Assert.False(e.Enforce("alice", "data2", "write"));
Assert.False(e.Enforce("bob", "data1", "read"));
Assert.False(e.Enforce("bob", "data1", "write"));
Assert.False(e.Enforce("bob", "data2", "read"));
Assert.True(e.Enforce("bob", "data2", "write"));
}
[Fact]
public async Task TestNotUsedRbacModelInMemoryAsync()
{
IModel m = DefaultModel.Create();
m.AddDef("r", "r", "sub, obj, act");
m.AddDef("p", "p", "sub, obj, act");
m.AddDef("g", "g", "_, _");
m.AddDef("e", "e", "some(where (p.eft == allow))");
m.AddDef("m", "m", "g(r.sub, p.sub) && r.obj == p.obj && r.act == p.act");
Enforcer e = new(m);
await e.AddPermissionForUserAsync("alice", "data1", "read");
await e.AddPermissionForUserAsync("bob", "data2", "write");
Assert.True(await e.EnforceAsync("alice", "data1", "read"));
Assert.False(await e.EnforceAsync("alice", "data1", "write"));
Assert.False(await e.EnforceAsync("alice", "data2", "read"));
Assert.False(await e.EnforceAsync("alice", "data2", "write"));
Assert.False(await e.EnforceAsync("bob", "data1", "read"));
Assert.False(await e.EnforceAsync("bob", "data1", "write"));
Assert.False(await e.EnforceAsync("bob", "data2", "read"));
Assert.True(await e.EnforceAsync("bob", "data2", "write"));
}
[Fact]
public void TestMultipleGroupTypeModelInMemory()
{
IModel m = DefaultModel.Create();
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");
Enforcer e = new(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 TestNonGNamedMultipleGroupTypeModelInMemoryAsync()
{
IModel m = DefaultModel.Create();
m.AddDef("r", "r", "sub, obj, act");
m.AddDef("p", "p", "sub, obj, act");
m.AddDef("g", "firstGroup", "_, _");
m.AddDef("g", "secondGroup", "_, _");
m.AddDef("e", "e", "some(where (p.eft == allow))");
m.AddDef("m", "m", "firstGroup(r.sub, p.sub) && secondGroup(r.obj, p.obj) && r.act == p.act");
Enforcer e = new(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("firstGroup", "alice", "data_group_admin");
await e.AddNamedGroupingPolicyAsync("secondGroup", "data1", "data_group");
await e.AddNamedGroupingPolicyAsync("secondGroup", "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"));
}
[Fact]
public async Task TestMultipleGroupTypeModelInMemoryAsync()
{
IModel m = DefaultModel.Create();
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");
Enforcer e = new(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()
{
Enforcer e = new();
IModel m = DefaultModel.Create();
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)");
FileAdapter a = new("Examples/keymatch_policy.csv");
e.SetModel(m);
e.SetAdapter(a);
e.LoadPolicy();
Assert.True(e.Enforce("alice", "/alice_data/resource1", "GET"));
}
[Fact]
public async Task TestInitEmptyAsync()
{
Enforcer e = new();
IModel m = DefaultModel.Create();
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)");
FileAdapter a = new("Examples/keymatch_policy.csv");
e.SetModel(m);
e.SetAdapter(a);
await e.LoadPolicyAsync();
Assert.True(await e.EnforceAsync("alice", "/alice_data/resource1", "GET"));
}
[Fact]
public void TestInitEmptyByInputStream()
{
Enforcer e = new();
IModel m = DefaultModel.Create();
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 (FileStream fs = new("Examples/keymatch_policy.csv", FileMode.Open, FileAccess.Read,
FileShare.ReadWrite))
{
StreamAdapter a = new(fs);
e.SetModel(m);
e.SetAdapter(a);
e.LoadPolicy();
Assert.True(e.Enforce("alice", "/alice_data/resource1", "GET"));
}
}
[Fact]
public async Task TestInitEmptyByInputStreamAsync()
{
Enforcer e = new();
IModel m = DefaultModel.Create();
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 (FileStream fs = new("Examples/keymatch_policy.csv", FileMode.Open, FileAccess.Read,
FileShare.ReadWrite))
{
StreamAdapter a = new(fs);
e.SetModel(m);
e.SetAdapter(a);
await e.LoadPolicyAsync();
Assert.True(await e.EnforceAsync("alice", "/alice_data/resource1", "GET"));
}
}
#endregion
#region Store management
[Fact]
public void TestReloadPolicy()
{
Enforcer e = new("Examples/rbac_model.conf", "Examples/rbac_policy.csv");
e.LoadPolicy();
e.TestGetPolicy(
[
["alice", "data1", "read"],
["bob", "data2", "write"],
["data2_admin", "data2", "read"],
["data2_admin", "data2", "write"]
]
);
}
[Fact]
public async Task TestReloadPolicyAsync()
{
Enforcer e = new("Examples/rbac_model.conf", "Examples/rbac_policy.csv");
await e.LoadPolicyAsync();
e.TestGetPolicy(
[
["alice", "data1", "read"],
["bob", "data2", "write"],
["data2_admin", "data2", "read"],
["data2_admin", "data2", "write"]
]
);
}
[Fact]
public void TestSavePolicy()
{
Enforcer e = new("Examples/rbac_model.conf", "Examples/rbac_policy.csv");
e.SavePolicy();
}
[Fact]
public async Task TestSavePolicyAsync()
{
Enforcer e = new("Examples/rbac_model.conf", "Examples/rbac_policy.csv");
await e.SavePolicyAsync();
}
[Fact]
public void TestSavePolicyWithoutBasicModel()
{
Enforcer e = new("Examples/basic_model.conf", "Examples/basic_policy.csv");
e.SavePolicy();
}
[Fact]
public async Task TestSavePolicyWithoutBasicModelAsync()
{
Enforcer e = new("Examples/basic_model.conf", "Examples/basic_policy.csv");
await e.SavePolicyAsync();
}
[Fact]
public void TestClearPolicy()
{
Enforcer e = new("Examples/rbac_model.conf", "Examples/rbac_policy.csv");
e.ClearPolicy();
}
#endregion
#region Extension features
[Fact]
public void TestEnableEnforce()
{
Enforcer e = new("Examples/basic_model.conf", "Examples/basic_policy.csv");
e.EnableEnforce(false);
Assert.True(e.Enforce("alice", "data1", "read"));
Assert.True(e.Enforce("alice", "data1", "write"));
Assert.True(e.Enforce("alice", "data2", "read"));
Assert.True(e.Enforce("alice", "data2", "write"));
Assert.True(e.Enforce("bob", "data1", "read"));
Assert.True(e.Enforce("bob", "data1", "write"));
Assert.True(e.Enforce("bob", "data2", "read"));
Assert.True(e.Enforce("bob", "data2", "write"));
e.EnableEnforce(true);
Assert.True(e.Enforce("alice", "data1", "read"));
Assert.False(e.Enforce("alice", "data1", "write"));
Assert.False(e.Enforce("alice", "data2", "read"));
Assert.False(e.Enforce("alice", "data2", "write"));
Assert.False(e.Enforce("bob", "data1", "read"));
Assert.False(e.Enforce("bob", "data1", "write"));
Assert.False(e.Enforce("bob", "data2", "read"));
Assert.True(e.Enforce("bob", "data2", "write"));
}
#if !NET452
[Fact]
public void TestEnableLog()
{
Enforcer e = new("Examples/basic_model.conf", "Examples/basic_policy.csv")
{
Logger = new MockLogger<Enforcer>(_testOutputHelper)
};
Assert.True(e.Enforce("alice", "data1", "read"));
Assert.False(e.Enforce("alice", "data1", "write"));
Assert.False(e.Enforce("alice", "data2", "read"));
Assert.False(e.Enforce("alice", "data2", "write"));
Assert.False(e.Enforce("bob", "data1", "read"));
Assert.False(e.Enforce("bob", "data1", "write"));
Assert.False(e.Enforce("bob", "data2", "read"));
Assert.True(e.Enforce("bob", "data2", "write"));
e.Logger = null;
Assert.True(e.Enforce("alice", "data1", "read"));
Assert.False(e.Enforce("alice", "data1", "write"));
Assert.False(e.Enforce("alice", "data2", "read"));
Assert.False(e.Enforce("alice", "data2", "write"));
Assert.False(e.Enforce("bob", "data1", "read"));
Assert.False(e.Enforce("bob", "data1", "write"));
Assert.False(e.Enforce("bob", "data2", "read"));
Assert.True(e.Enforce("bob", "data2", "write"));
}
#endif
[Fact]
public void TestEnableAutoSave()
{
Enforcer e = new("Examples/basic_model.conf", "Examples/basic_policy.csv");
e.EnableAutoSave(false);
// Because AutoSave is disabled, the policy change only affects the policy in Casbin enforcer,
// it doesn't affect the policy in the storage.
e.RemovePolicy("alice", "data1", "read");
// Reload the policy from the storage to see the effect.
e.LoadPolicy();
Assert.True(e.Enforce("alice", "data1", "read"));
Assert.False(e.Enforce("alice", "data1", "write"));
Assert.False(e.Enforce("alice", "data2", "read"));
Assert.False(e.Enforce("alice", "data2", "write"));
Assert.False(e.Enforce("bob", "data1", "read"));
Assert.False(e.Enforce("bob", "data1", "write"));
Assert.False(e.Enforce("bob", "data2", "read"));
Assert.True(e.Enforce("bob", "data2", "write"));
e.EnableAutoSave(true);
// Because AutoSave is enabled, the policy change not only affects the policy in Casbin enforcer,
// but also affects the policy in the storage.
e.RemovePolicy("alice", "data1", "read");
// However, the file adapter doesn't implement the AutoSave feature, so enabling it has no effect at all here.
// Reload the policy from the storage to see the effect.
e.LoadPolicy();
Assert.True(e.Enforce("alice", "data1", "read")); // Will not be false here.
Assert.False(e.Enforce("alice", "data1", "write"));
Assert.False(e.Enforce("alice", "data2", "read"));
Assert.False(e.Enforce("alice", "data2", "write"));
Assert.False(e.Enforce("bob", "data1", "read"));
Assert.False(e.Enforce("bob", "data1", "write"));
Assert.False(e.Enforce("bob", "data2", "read"));
Assert.True(e.Enforce("bob", "data2", "write"));
}
[Fact]
public async Task TestEnableAutoSaveAsync()
{
Enforcer e = new("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,
// it doesn't affect the policy in the storage.
await e.RemovePolicyAsync("alice", "data1", "read");
// Reload the policy from the storage to see the effect.
await e.LoadPolicyAsync();
Assert.True(await e.EnforceAsync("alice", "data1", "read"));
Assert.False(await e.EnforceAsync("alice", "data1", "write"));
Assert.False(await e.EnforceAsync("alice", "data2", "read"));
Assert.False(await e.EnforceAsync("alice", "data2", "write"));
Assert.False(await e.EnforceAsync("bob", "data1", "read"));
Assert.False(await e.EnforceAsync("bob", "data1", "write"));
Assert.False(await e.EnforceAsync("bob", "data2", "read"));
Assert.True(await e.EnforceAsync("bob", "data2", "write"));
e.EnableAutoSave(true);
// Because AutoSave is enabled, the policy change not only affects the policy in Casbin enforcer,
// but also affects the policy in the storage.
await e.RemovePolicyAsync("alice", "data1", "read");
// However, the file adapter doesn't implement the AutoSave feature, so enabling it has no effect at all here.
// Reload the policy from the storage to see the effect.
await e.LoadPolicyAsync();
Assert.True(await e.EnforceAsync("alice", "data1", "read")); // Will not be false here.
Assert.False(await e.EnforceAsync("alice", "data1", "write"));
Assert.False(await e.EnforceAsync("alice", "data2", "read"));
Assert.False(await e.EnforceAsync("alice", "data2", "write"));
Assert.False(await e.EnforceAsync("bob", "data1", "read"));
Assert.False(await e.EnforceAsync("bob", "data1", "write"));
Assert.False(await e.EnforceAsync("bob", "data2", "read"));
Assert.True(await e.EnforceAsync("bob", "data2", "write"));
}
[Fact]
public void TestAutoSaveGroupingPolicy()
{
// This test verifies that AddGroupingPolicy() respects the AutoSave flag.
// When AutoSave is disabled, grouping policy changes should not be saved to the adapter.
MockSingleAdapter adapter = new("Examples/rbac_policy.csv");
Enforcer e = new("Examples/rbac_model.conf", adapter);
// Verify initial state: alice has data2_admin role
Assert.True(e.HasGroupingPolicy("alice", "data2_admin"));
Assert.False(e.HasGroupingPolicy("bob", "data2_admin"));
adapter.ClearSavedPolicies();
e.EnableAutoSave(false);
// Because AutoSave is disabled, the grouping policy change should only affect
// the policy in Casbin enforcer, it should NOT call the adapter.
e.AddGroupingPolicy("bob", "data2_admin");
// Verify the change is in memory
Assert.True(e.HasGroupingPolicy("bob", "data2_admin"));
// Verify the adapter was NOT called because AutoSave is disabled
Assert.Empty(adapter.SavedPolicies);
}
[Fact]
public async Task TestAutoSaveGroupingPolicyAsync()
{
// This test verifies that AddGroupingPolicyAsync() respects the AutoSave flag.
// When AutoSave is disabled, grouping policy changes should not be saved to the adapter.
MockSingleAdapter adapter = new("Examples/rbac_policy.csv");
Enforcer e = new("Examples/rbac_model.conf", adapter);
// Verify initial state
Assert.True(e.HasGroupingPolicy("alice", "data2_admin"));
Assert.False(e.HasGroupingPolicy("bob", "data2_admin"));
adapter.ClearSavedPolicies();
e.EnableAutoSave(false);
// Add grouping policy with AutoSave disabled
await e.AddGroupingPolicyAsync("bob", "data2_admin");
// Verify the change is in memory
Assert.True(e.HasGroupingPolicy("bob", "data2_admin"));
// Verify the adapter was NOT called because AutoSave is disabled
Assert.Empty(adapter.SavedPolicies);
}
[Fact]
public void TestInitWithAdapter()
{
FileAdapter adapter = new("Examples/basic_policy.csv");
Enforcer e = new("Examples/basic_model.conf", adapter);
Assert.True(e.Enforce("alice", "data1", "read"));
Assert.False(e.Enforce("alice", "data1", "write"));
Assert.False(e.Enforce("alice", "data2", "read"));
Assert.False(e.Enforce("alice", "data2", "write"));
Assert.False(e.Enforce("bob", "data1", "read"));
Assert.False(e.Enforce("bob", "data1", "write"));
Assert.False(e.Enforce("bob", "data2", "read"));
Assert.True(e.Enforce("bob", "data2", "write"));
}
[Fact]
public void TestRoleLinks()
{
Enforcer e = new("Examples/rbac_model.conf");
e.EnableAutoBuildRoleLinks(false);
e.BuildRoleLinks();
e.Enforce("user501", "data9", "read");
}
[Fact]
public void TestGetAndSetModel()
{
Enforcer e = new("Examples/basic_model.conf", "Examples/basic_policy.csv");
Enforcer e2 = new("Examples/basic_with_root_model.conf", "Examples/basic_policy.csv");
Assert.False(e.Enforce("root", "data1", "read"));
e.SetModel(e2.Model);
Assert.True(e.Enforce("root", "data1", "read"));
}
[Fact]
public void TestGetAndSetAdapterInMem()
{
Enforcer e = new("Examples/basic_model.conf", "Examples/basic_policy.csv");
Enforcer e2 = new("Examples/basic_model.conf", "Examples/basic_inverse_policy.csv");
Assert.True(e.Enforce("alice", "data1", "read"));
Assert.False(e.Enforce("alice", "data1", "write"));
IReadOnlyAdapter a2 = e2.Adapter;
e.SetAdapter(a2);
e.LoadPolicy();
Assert.False(e.Enforce("alice", "data1", "read"));
Assert.True(e.Enforce("alice", "data1", "write"));
}
[Fact]
public async Task TestGetAndSetAdapterInMemAsync()
{
Enforcer e = new("Examples/basic_model.conf", "Examples/basic_policy_for_async_adapter_test.csv");
Enforcer e2 = new("Examples/basic_model.conf", "Examples/basic_inverse_policy.csv");
Assert.True(await e.EnforceAsync("alice", "data1", "read"));
Assert.False(await e.EnforceAsync("alice", "data1", "write"));
IReadOnlyAdapter a2 = e2.Adapter;
e.SetAdapter(a2);
await e.LoadPolicyAsync();
Assert.False(await e.EnforceAsync("alice", "data1", "read"));
Assert.True(await e.EnforceAsync("alice", "data1", "write"));
}
[Fact]
public void TestEnforceExApi()
{
Enforcer e = new(TestModelFixture.GetBasicTestModel());
e.TestEnforceEx("alice", "data1", "read", ["alice", "data1", "read"]);
e.TestEnforceEx("alice", "data1", "write", []);
e.TestEnforceEx("alice", "data2", "read", []);
e.TestEnforceEx("alice", "data2", "write", []);
e.TestEnforceEx("bob", "data1", "read", []);
e.TestEnforceEx("bob", "data1", "write", []);
e.TestEnforceEx("bob", "data2", "read", []);
e.TestEnforceEx("bob", "data2", "write", ["bob", "data2", "write"]);
e = new Enforcer(TestModelFixture.GetNewRbacTestModel());
e.TestEnforceEx("alice", "data1", "read", ["alice", "data1", "read"]);
e.TestEnforceEx("alice", "data1", "write", []);
// e.TestEnforceEx("alice", "data2", "read", ["data2_admin", "data2", "read"]); TODO: should be fixed
// e.TestEnforceEx("alice", "data2", "write", ["data2_admin", "data2", "write"]); TODO: should be fixed
e.TestEnforceEx("bob", "data1", "read", []);
e.TestEnforceEx("bob", "data1", "write", []);
e.TestEnforceEx("bob", "data2", "read", []);
e.TestEnforceEx("bob", "data2", "write", ["bob", "data2", "write"]);
e = new Enforcer(TestModelFixture.GetNewPriorityTestModel());
e.BuildRoleLinks();
e.TestEnforceEx("alice", "data1", "read", ["alice", "data1", "read", "allow"]);
e.TestEnforceEx("alice", "data1", "write", ["data1_deny_group", "data1", "write", "deny"]);
e.TestEnforceEx("alice", "data2", "read", []);
e.TestEnforceEx("alice", "data2", "write", []);
e.TestEnforceEx("bob", "data1", "write", []);
e.TestEnforceEx("bob", "data2", "read", ["data2_allow_group", "data2", "read", "allow"]);
e.TestEnforceEx("bob", "data2", "write", ["bob", "data2", "write", "deny"]);
}
[Fact]
public async Task TestEnforceExApiAsync()
{
Enforcer e = new(TestModelFixture.GetBasicTestModel());
await e.TestEnforceExAsync("alice", "data1", "read", new List<string> { "alice", "data1", "read" });
await e.TestEnforceExAsync("alice", "data1", "write", new List<string>());
await e.TestEnforceExAsync("alice", "data2", "read", new List<string>());
await e.TestEnforceExAsync("alice", "data2", "write", new List<string>());
await e.TestEnforceExAsync("bob", "data1", "read", new List<string>());
await e.TestEnforceExAsync("bob", "data1", "write", new List<string>());
await e.TestEnforceExAsync("bob", "data2", "read", new List<string>());
await e.TestEnforceExAsync("bob", "data2", "write", new List<string> { "bob", "data2", "write" });
e = new Enforcer(TestModelFixture.GetNewRbacTestModel());
await e.TestEnforceExAsync("alice", "data1", "read", new List<string> { "alice", "data1", "read" });
await e.TestEnforceExAsync("alice", "data1", "write", new List<string>());
// await e.TestEnforceExAsync("alice", "data2", "read", new List<string> { "data2_admin", "data2", "read" }); TODO: should be fixed
// await e.TestEnforceExAsync("alice", "data2", "write", new List<string> { "data2_admin", "data2", "write" }); TODO: should be fixed
await e.TestEnforceExAsync("bob", "data1", "read", new List<string>());
await e.TestEnforceExAsync("bob", "data1", "write", new List<string>());
await e.TestEnforceExAsync("bob", "data2", "read", new List<string>());
await e.TestEnforceExAsync("bob", "data2", "write", new List<string> { "bob", "data2", "write" });
e = new Enforcer(TestModelFixture.GetNewPriorityTestModel());
e.BuildRoleLinks();
await e.TestEnforceExAsync("alice", "data1", "read", new List<string> { "alice", "data1", "read", "allow" });
await e.TestEnforceExAsync("alice", "data1", "write",
new List<string> { "data1_deny_group", "data1", "write", "deny" });
await e.TestEnforceExAsync("alice", "data2", "read", new List<string>());
await e.TestEnforceExAsync("alice", "data2", "write", new List<string>());
await e.TestEnforceExAsync("bob", "data1", "write", new List<string>());
await e.TestEnforceExAsync("bob", "data2", "read",
new List<string> { "data2_allow_group", "data2", "read", "allow" });
await e.TestEnforceExAsync("bob", "data2", "write", new List<string> { "bob", "data2", "write", "deny" });
}
#if !NET452
[Fact]
public void TestEnforceExApiLog()
{
Enforcer e = new(TestModelFixture.GetBasicTestModel()) { Logger = new MockLogger<Enforcer>(_testOutputHelper) };
e.TestEnforceEx("alice", "data1", "read", new List<string> { "alice", "data1", "read" });
e.TestEnforceEx("alice", "data1", "write", new List<string>());
e.TestEnforceEx("alice", "data2", "read", new List<string>());
e.TestEnforceEx("alice", "data2", "write", new List<string>());
e.TestEnforceEx("bob", "data1", "read", new List<string>());
e.TestEnforceEx("bob", "data1", "write", new List<string>());
e.TestEnforceEx("bob", "data2", "read", new List<string>());
e.TestEnforceEx("bob", "data2", "write", new List<string> { "bob", "data2", "write" });
e.Logger = null;
}
#endif
#endregion
#region EnforceWithMatcher and EnforceExWithMatcher API
[Fact]
public void TestEnforceWithMatcherApi()
{
Enforcer e = new(TestModelFixture.GetBasicTestModel());
string matcher = "r.sub != p.sub && r.obj == p.obj && r.act == p.act";
Assert.False(e.EnforceWithMatcher(matcher, "alice", "data1", "read"));
Assert.False(e.EnforceWithMatcher(matcher, "alice", "data1", "write"));
Assert.False(e.EnforceWithMatcher(matcher, "alice", "data2", "read"));
Assert.True(e.EnforceWithMatcher(matcher, "alice", "data2", "write"));
Assert.True(e.EnforceWithMatcher(matcher, "bob", "data1", "read"));
Assert.False(e.EnforceWithMatcher(matcher, "bob", "data1", "write"));
Assert.False(e.EnforceWithMatcher(matcher, "bob", "data2", "read"));
Assert.False(e.EnforceWithMatcher(matcher, "bob", "data2", "write"));
}
[Fact]
public async Task TestEnforceWithMatcherAsync()
{
Enforcer e = new(TestModelFixture.GetBasicTestModel());
string matcher = "r.sub != p.sub && r.obj == p.obj && r.act == p.act";
Assert.False(await e.EnforceWithMatcherAsync(matcher, "alice", "data1", "read"));
Assert.False(await e.EnforceWithMatcherAsync(matcher, "alice", "data1", "write"));
Assert.False(await e.EnforceWithMatcherAsync(matcher, "alice", "data2", "read"));
Assert.True(await e.EnforceWithMatcherAsync(matcher, "alice", "data2", "write"));
Assert.True(await e.EnforceWithMatcherAsync(matcher, "bob", "data1", "read"));
Assert.False(await e.EnforceWithMatcherAsync(matcher, "bob", "data1", "write"));
Assert.False(await e.EnforceWithMatcherAsync(matcher, "bob", "data2", "read"));
Assert.False(await e.EnforceWithMatcherAsync(matcher, "bob", "data2", "write"));
}
[Fact]
public void TestBatchEnforceWithMatcherApi()
{
Enforcer e = new(TestModelFixture.GetBasicTestModel());
string matcher = "r.sub != p.sub && r.obj == p.obj && r.act == p.act";
IEnumerable<(RequestValues<string, string, string>, bool)> testCases =
[
(Request.CreateValues("alice", "data1", "read"), false),
(Request.CreateValues("alice", "data1", "write"), false),
(Request.CreateValues("alice", "data2", "read"), false),
(Request.CreateValues("alice", "data2", "write"), true),
(Request.CreateValues("bob", "data1", "read"), true),
(Request.CreateValues("bob", "data1", "write"), false),
(Request.CreateValues("bob", "data2", "read"), false),
(Request.CreateValues("bob", "data2", "write"), false)
];
e.TestBatchEnforceWithMatcher(matcher, testCases);
}
[Fact]
public void TestBatchEnforceWithMatcherParallel()
{
Enforcer e = new(TestModelFixture.GetBasicTestModel());
string matcher = "r.sub != p.sub && r.obj == p.obj && r.act == p.act";
IEnumerable<(RequestValues<string, string, string>, bool)> testCases =
[
(Request.CreateValues("alice", "data1", "read"), false),
(Request.CreateValues("alice", "data1", "write"), false),
(Request.CreateValues("alice", "data2", "read"), false),
(Request.CreateValues("alice", "data2", "write"), true),
(Request.CreateValues("bob", "data1", "read"), true),
(Request.CreateValues("bob", "data1", "write"), false),
(Request.CreateValues("bob", "data2", "read"), false),
(Request.CreateValues("bob", "data2", "write"), false)
];
e.TestBatchEnforceWithMatcherParallel(matcher, testCases);
}
[Fact]
public void TestBatchEnforceWithMatcherApiAsync()
{
Enforcer e = new(TestModelFixture.GetBasicTestModel());
string matcher = "r.sub != p.sub && r.obj == p.obj && r.act == p.act";
IEnumerable<(RequestValues<string, string, string>, bool)> testCases =
[
(Request.CreateValues("alice", "data1", "read"), false),
(Request.CreateValues("alice", "data1", "write"), false),
(Request.CreateValues("alice", "data2", "read"), false),
(Request.CreateValues("alice", "data2", "write"), true),
(Request.CreateValues("bob", "data1", "read"), true),
(Request.CreateValues("bob", "data1", "write"), false),
(Request.CreateValues("bob", "data2", "read"), false),
(Request.CreateValues("bob", "data2", "write"), false)
];
TestBatchEnforceWithMatcherAsync(e, matcher, testCases);
}
[Fact]
public void TestEnforceExWithMatcherApi()
{
Enforcer e = new(TestModelFixture.GetBasicTestModel());
string matcher = "r.sub != p.sub && r.obj == p.obj && r.act == p.act";
e.TestEnforceExWithMatcher(matcher, "alice", "data1", "read", []);
e.TestEnforceExWithMatcher(matcher, "alice", "data1", "write", []);
e.TestEnforceExWithMatcher(matcher, "alice", "data2", "read", []);
e.TestEnforceExWithMatcher(matcher, "alice", "data2", "write", ["bob", "data2", "write"]);
e.TestEnforceExWithMatcher(matcher, "bob", "data1", "read", ["alice", "data1", "read"]);
e.TestEnforceExWithMatcher(matcher, "bob", "data1", "write", []);
e.TestEnforceExWithMatcher(matcher, "bob", "data2", "read", []);
e.TestEnforceExWithMatcher(matcher, "bob", "data2", "write", []);
}
[Fact]
public async Task TestEnforceExWithMatcherAsync()
{
Enforcer e = new(TestModelFixture.GetBasicTestModel());
string matcher = "r.sub != p.sub && r.obj == p.obj && r.act == p.act";
await e.TestEnforceExWithMatcherAsync(matcher, "alice", "data1", "read", []);
await e.TestEnforceExWithMatcherAsync(matcher, "alice", "data1", "write", []);
await e.TestEnforceExWithMatcherAsync(matcher, "alice", "data2", "read", []);
await e.TestEnforceExWithMatcherAsync(matcher, "alice", "data2", "write", ["bob", "data2", "write"]);
await e.TestEnforceExWithMatcherAsync(matcher, "bob", "data1", "read", ["alice", "data1", "read"]);
await e.TestEnforceExWithMatcherAsync(matcher, "bob", "data1", "write", []);
await e.TestEnforceExWithMatcherAsync(matcher, "bob", "data2", "read", []);
await e.TestEnforceExWithMatcherAsync(matcher, "bob", "data2", "write", []);
}
#endregion
#if !NET452
#region ExpressionHandler Tests
[Fact]
public void TestExpressionHandlerSingleQuoteReplacement()
{
Enforcer e = new(TestModelFixture.GetBasicTestModel());
// Single quotes should be replaced with double quotes to handle DynamicExpresso limitations
string matcherWithSingleQuotes = "r.sub == 'alice' && r.obj == p.obj && r.act == p.act";
Assert.True(e.EnforceWithMatcher(matcherWithSingleQuotes, "alice", "data1", "read"));
Assert.False(e.EnforceWithMatcher(matcherWithSingleQuotes, "alice", "data1", "write"));
Assert.False(e.EnforceWithMatcher(matcherWithSingleQuotes, "bob", "data1", "read"));
}
[Fact]
public void TestExpressionHandlerLogsWarningOnInvalidExpression()
{
var logger = new MockLogger<Enforcer>(_testOutputHelper);
Enforcer e = new(TestModelFixture.GetBasicTestModel()) { Logger = logger };
// An invalid expression should return false and log a warning
Assert.False(e.EnforceWithMatcher("this_is_not_valid!!!", "alice", "data1", "read"));
Assert.Contains(logger.Logs, log => log.Level == Microsoft.Extensions.Logging.LogLevel.Warning);
}
#endregion
#endif
}