Skip to content

Commit

Permalink
feat: Support eval with dynamic request value type (#360)
Browse files Browse the repository at this point in the history
Signed-off-by: Taoyuesong <[email protected]>
  • Loading branch information
Taoyuesong committed Jun 18, 2024
1 parent e133b78 commit 6d3cb37
Show file tree
Hide file tree
Showing 5 changed files with 71 additions and 3 deletions.
4 changes: 4 additions & 0 deletions Casbin.UnitTests/Fixtures/TestModelFixture.cs
Original file line number Diff line number Diff line change
Expand Up @@ -95,6 +95,10 @@ public class TestModelFixture
public static readonly string RbacWithIndexMatcherModelText = ReadTestFile("rbac_with_index_matcher_model.conf");
public static readonly string RbacWithIndexMatcherPolicyText = ReadTestFile("rbac_with_index_matcher_policy.csv");

// https://github.com/casbin/Casbin.NET/issues/354
public static readonly string AbacWithDynamicValueTypeModelText = ReadTestFile("abac_with_dynamic_value_type_model.conf");
public static readonly string AbacWithDynamicValueTypePolicyText = ReadTestFile("abac_with_dynamic_value_type_policy.csv");

public static IModel GetNewAbacModel() => GetNewTestModel(AbacModelText);

public static IModel GetNewAbacWithEvalModel() => GetNewTestModel(AbacWithEvalModelText, AbacWithEvalPolicyText);
Expand Down
19 changes: 19 additions & 0 deletions Casbin.UnitTests/ModelTests/ModelTest.cs
Original file line number Diff line number Diff line change
Expand Up @@ -752,6 +752,25 @@ public void TestRbacWithIndexMatcher()
Assert.True(e.Enforce(rule, "Admin", "/api/transactions/getTransactions", "POST"));
}

[Fact]
public void TestAbacWithDynamicValueType()
{
Enforcer e = new(TestModelFixture.GetNewTestModel(
TestModelFixture.AbacWithDynamicValueTypeModelText,
TestModelFixture.AbacWithDynamicValueTypePolicyText));
var sub = new { Name = "bob" };
var obj1 = new { Object = "/data1", Property1 = "prop-1" };
var obj2 = new { Object = "/data2", Property2 = "prop-2" };
var obj3 = new { Object = "/data2", Property3 = "prop-3" };
Assert.True(e.Enforce(sub, obj1, "read"));
Assert.True(e.Enforce(sub, obj2, "read"));
Assert.False(e.Enforce(sub, obj3, "read"));
// Request again to test the cache hit logic.
Assert.True(e.Enforce(sub, obj1, "read"));
Assert.True(e.Enforce(sub, obj2, "read"));
Assert.False(e.Enforce(sub, obj3, "read"));
}

public class TestResource
{
public TestResource(string name, string owner)
Expand Down
14 changes: 14 additions & 0 deletions Casbin.UnitTests/examples/abac_with_dynamic_value_type_model.conf
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
[request_definition]
r = sub, obj, act

[policy_definition]
p = sub, obj, act, rule

[policy_effect]
e = some(where (p.eft == allow))

[matchers]
m = r.sub.Name == p.sub && \
r.obj.Object == p.obj && \
r.act == p.act && \
eval(p.rule)
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
p, bob, /data1, read, r.obj.Property1 == "prop-1"
p, bob, /data2, read, r.obj.Property2 == "prop-2"
35 changes: 32 additions & 3 deletions Casbin/Evaluation/ExpressionHandler.cs
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,8 @@ internal class ExpressionHandler : IExpressionHandler
private Interpreter _interpreter;
#endif

private bool TryCompile { get; set; } = true;

public ExpressionHandler()
{
_interpreter = CreateInterpreter();
Expand Down Expand Up @@ -76,13 +78,23 @@ public void SetFunction(string name, Delegate function)
return func(request, policy);
}

if (_cachePool.TryGetFunc(expressionString,
out Func<TRequest, TPolicy, bool> genericFunc) is not false)
if (_cachePool.TryGetFunc(expressionString, out Func<TRequest, TPolicy, bool> genericFunc))
{
return genericFunc is not null && genericFunc(request, policy);
}

if (TryCompile is false)
{
genericFunc = CompileExpression<TRequest, TPolicy>(in context, expressionString);
_cachePool.SetFunc(expressionString, genericFunc);
return genericFunc(request, policy);
}

genericFunc = CompileExpression<TRequest, TPolicy>(in context, expressionString);
if (TryCompileExpression(in context, expressionString, out genericFunc) is false)
{
_cachePool.SetFunc(expressionString, genericFunc);
return false;
}
_cachePool.SetFunc(expressionString, genericFunc);
return genericFunc(request, policy);
}
Expand All @@ -96,6 +108,23 @@ public void SetFunction(string name, Delegate function)
context.View.RequestType, context.View.PolicyType);
}

private bool TryCompileExpression<TRequest, TPolicy>(in EnforceContext context,
string expressionString, out Func<TRequest, TPolicy, bool> func)
where TRequest : IRequestValues
where TPolicy : IPolicyValues
{
try
{
func = CompileExpression<TRequest, TPolicy>(in context, expressionString);
}
catch (Exception)
{
func = null;
return false;
}
return true;
}

private Interpreter CreateInterpreter()
{
var interpreter = new Interpreter();
Expand Down

0 comments on commit 6d3cb37

Please sign in to comment.