diff --git a/CHANGELOG.md b/CHANGELOG.md
index d17761b4..6c1ce981 100644
--- a/CHANGELOG.md
+++ b/CHANGELOG.md
@@ -2,6 +2,13 @@
All notable changes to this project will be documented in this file.
+## [5.0.0]
+- Fixed security bug related to System.Dynamic.Linq.Core
+
+### Breaking Changes
+- As a part of security bug fix, method call for only registered types via reSettings will be allowed. This only impacts strongly typed inputs and nested types
+
+
## [4.0.0]
- RulesEngine is now available in both dotnet 6 and netstandard 2.0
- Dependency on ILogger, MemoryCache have been removed
diff --git a/benchmark/RulesEngineBenchmark/RulesEngineBenchmark.csproj b/benchmark/RulesEngineBenchmark/RulesEngineBenchmark.csproj
index 798d5fc9..ae746fb7 100644
--- a/benchmark/RulesEngineBenchmark/RulesEngineBenchmark.csproj
+++ b/benchmark/RulesEngineBenchmark/RulesEngineBenchmark.csproj
@@ -6,7 +6,7 @@
-
+
diff --git a/demo/DemoApp.EFDataExample/DemoApp.EFDataExample.csproj b/demo/DemoApp.EFDataExample/DemoApp.EFDataExample.csproj
index cd75c12b..0a588c15 100644
--- a/demo/DemoApp.EFDataExample/DemoApp.EFDataExample.csproj
+++ b/demo/DemoApp.EFDataExample/DemoApp.EFDataExample.csproj
@@ -7,8 +7,8 @@
-
-
+
+
diff --git a/src/RulesEngine/ExpressionBuilders/RuleExpressionParser.cs b/src/RulesEngine/ExpressionBuilders/RuleExpressionParser.cs
index ac43d10c..8570fdbb 100644
--- a/src/RulesEngine/ExpressionBuilders/RuleExpressionParser.cs
+++ b/src/RulesEngine/ExpressionBuilders/RuleExpressionParser.cs
@@ -37,7 +37,9 @@ private void PopulateMethodInfo()
}
public Expression Parse(string expression, ParameterExpression[] parameters, Type returnType)
{
- var config = new ParsingConfig { CustomTypeProvider = new CustomTypeProvider(_reSettings.CustomTypes) };
+ var config = new ParsingConfig {
+ CustomTypeProvider = new CustomTypeProvider(_reSettings.CustomTypes)
+ };
return new ExpressionParser(parameters, expression, new object[] { }, config).Parse(returnType);
}
diff --git a/src/RulesEngine/Extensions/EnumerableExtensions.cs b/src/RulesEngine/Extensions/EnumerableExtensions.cs
new file mode 100644
index 00000000..a3586f67
--- /dev/null
+++ b/src/RulesEngine/Extensions/EnumerableExtensions.cs
@@ -0,0 +1,19 @@
+// Copyright (c) Microsoft Corporation.
+// Licensed under the MIT License.
+
+using System;
+using System.Collections.Generic;
+using System.Linq;
+using System.Text;
+using System.Threading.Tasks;
+
+namespace RulesEngine.Extensions
+{
+ internal static class EnumerableExtensions
+ {
+ public static IEnumerable Safe(this IEnumerable enumerable)
+ {
+ return enumerable ?? Enumerable.Empty();
+ }
+ }
+}
diff --git a/src/RulesEngine/Models/ReSettings.cs b/src/RulesEngine/Models/ReSettings.cs
index 7b6d942d..8589092e 100644
--- a/src/RulesEngine/Models/ReSettings.cs
+++ b/src/RulesEngine/Models/ReSettings.cs
@@ -12,6 +12,23 @@ namespace RulesEngine.Models
[ExcludeFromCodeCoverage]
public class ReSettings
{
+
+ public ReSettings() { }
+
+ // create a copy of settings
+ internal ReSettings(ReSettings reSettings)
+ {
+ CustomTypes = reSettings.CustomTypes;
+ CustomActions = reSettings.CustomActions;
+ EnableExceptionAsErrorMessage = reSettings.EnableExceptionAsErrorMessage;
+ IgnoreException = reSettings.IgnoreException;
+ EnableFormattedErrorMessage = reSettings.EnableFormattedErrorMessage;
+ EnableScopedParams = reSettings.EnableScopedParams;
+ NestedRuleExecutionMode = reSettings.NestedRuleExecutionMode;
+ CacheConfig = reSettings.CacheConfig;
+ }
+
+
///
/// Get/Set the custom types to be used in Rule expressions
///
diff --git a/src/RulesEngine/Models/Workflow.cs b/src/RulesEngine/Models/Workflow.cs
index c264a5eb..91d6bdba 100644
--- a/src/RulesEngine/Models/Workflow.cs
+++ b/src/RulesEngine/Models/Workflow.cs
@@ -1,6 +1,8 @@
// Copyright (c) Microsoft Corporation.
// Licensed under the MIT License.
+using Newtonsoft.Json.Converters;
+using Newtonsoft.Json;
using System;
using System.Collections.Generic;
using System.Diagnostics.CodeAnalysis;
@@ -31,6 +33,8 @@ public IEnumerable WorkflowRulesToInject {
}
public IEnumerable WorkflowsToInject { get; set; }
+ public RuleExpressionType RuleExpressionType { get; set; } = RuleExpressionType.LambdaExpression;
+
///
/// Gets or Sets the global params which will be applicable to all rules
///
diff --git a/src/RulesEngine/RuleCompiler.cs b/src/RulesEngine/RuleCompiler.cs
index 2c3f33a6..d05bce88 100644
--- a/src/RulesEngine/RuleCompiler.cs
+++ b/src/RulesEngine/RuleCompiler.cs
@@ -47,7 +47,7 @@ internal RuleCompiler(RuleExpressionBuilderFactory expressionBuilderFactory, ReS
///
///
/// Compiled func delegate
- internal RuleFunc CompileRule(Rule rule, RuleParameter[] ruleParams, ScopedParam[] globalParams)
+ internal RuleFunc CompileRule(Rule rule, RuleExpressionType ruleExpressionType, RuleParameter[] ruleParams, Lazy globalParams)
{
if (rule == null)
{
@@ -56,10 +56,12 @@ internal RuleFunc CompileRule(Rule rule, RuleParameter[] rulePar
}
try
{
- var globalParamExp = GetRuleExpressionParameters(rule.RuleExpressionType,globalParams, ruleParams);
+ var globalParamExp = globalParams.Value;
var extendedRuleParams = ruleParams.Concat(globalParamExp.Select(c => new RuleParameter(c.ParameterExpression.Name,c.ParameterExpression.Type)))
.ToArray();
var ruleExpression = GetDelegateForRule(rule, extendedRuleParams);
+
+
return GetWrappedRuleFunc(rule,ruleExpression,ruleParams,globalParamExp);
}
catch (Exception ex)
@@ -100,7 +102,7 @@ private RuleFunc GetDelegateForRule(Rule rule, RuleParameter[] r
return GetWrappedRuleFunc(rule, ruleFn, ruleParams, scopedParamList);
}
- private RuleExpressionParameter[] GetRuleExpressionParameters(RuleExpressionType ruleExpressionType,IEnumerable localParams, RuleParameter[] ruleParams)
+ internal RuleExpressionParameter[] GetRuleExpressionParameters(RuleExpressionType ruleExpressionType,IEnumerable localParams, RuleParameter[] ruleParams)
{
if(!_reSettings.EnableScopedParams)
{
@@ -227,6 +229,12 @@ private RuleFunc BuildNestedRuleFunc(Rule parentRule, Expression
return (isSuccess, resultList);
}
+ internal Func
-
-
+
+
-
+
-
+
diff --git a/test/RulesEngine.UnitTest/BusinessRuleEngineTest.cs b/test/RulesEngine.UnitTest/BusinessRuleEngineTest.cs
index 48203dca..521741df 100644
--- a/test/RulesEngine.UnitTest/BusinessRuleEngineTest.cs
+++ b/test/RulesEngine.UnitTest/BusinessRuleEngineTest.cs
@@ -388,10 +388,12 @@ public async Task ExecuteRule_WithInjectedUtils_ReturnsListOfRuleResultTree(stri
[InlineData("rules6.json")]
public async Task ExecuteRule_RuleWithMethodExpression_ReturnsSucess(string ruleFileName)
{
- var re = GetRulesEngine(ruleFileName);
-
Func func = () => true;
+ var re = GetRulesEngine(ruleFileName, new ReSettings {
+ CustomTypes = new[] { typeof(Func) }
+ });
+
dynamic input1 = new ExpandoObject();
input1.Property1 = "hello";
input1.Boolean = false;
@@ -851,7 +853,7 @@ private static dynamic[] GetInputs4()
}
[ExcludeFromCodeCoverage]
- private class TestInstanceUtils
+ public class TestInstanceUtils
{
public bool CheckExists(string str)
{
diff --git a/test/RulesEngine.UnitTest/RuleCompilerTest.cs b/test/RulesEngine.UnitTest/RuleCompilerTest.cs
index 72abd678..ef9081e8 100644
--- a/test/RulesEngine.UnitTest/RuleCompilerTest.cs
+++ b/test/RulesEngine.UnitTest/RuleCompilerTest.cs
@@ -28,8 +28,8 @@ public void RuleCompiler_CompileRule_ThrowsException()
var reSettings = new ReSettings();
var parser = new RuleExpressionParser(reSettings);
var compiler = new RuleCompiler(new RuleExpressionBuilderFactory(reSettings, parser),null);
- Assert.Throws(() => compiler.CompileRule(null, null,null));
- Assert.Throws(() => compiler.CompileRule(null, new RuleParameter[] { null },null));
+ Assert.Throws(() => compiler.CompileRule(null, RuleExpressionType.LambdaExpression,null,null));
+ Assert.Throws(() => compiler.CompileRule(null, RuleExpressionType.LambdaExpression, new RuleParameter[] { null },null));
}
}
}
diff --git a/test/RulesEngine.UnitTest/RulesEngine.UnitTest.csproj b/test/RulesEngine.UnitTest/RulesEngine.UnitTest.csproj
index e969f59f..70200802 100644
--- a/test/RulesEngine.UnitTest/RulesEngine.UnitTest.csproj
+++ b/test/RulesEngine.UnitTest/RulesEngine.UnitTest.csproj
@@ -6,16 +6,16 @@
True
-
-
-
-
+
+
+
+
all
runtime; build; native; contentfiles; analyzers; buildtransitive
-
+
all
runtime; build; native; contentfiles; analyzers; buildtransitive
diff --git a/test/RulesEngine.UnitTest/ScopedParamsTest.cs b/test/RulesEngine.UnitTest/ScopedParamsTest.cs
index 5979f2b2..ebbbb345 100644
--- a/test/RulesEngine.UnitTest/ScopedParamsTest.cs
+++ b/test/RulesEngine.UnitTest/ScopedParamsTest.cs
@@ -101,6 +101,7 @@ public async Task DisabledScopedParam_ShouldReflect(string workflowName, bool[]
[Theory]
[InlineData("GlobalParamsOnly")]
[InlineData("LocalParamsOnly2")]
+ [InlineData("GlobalParamsOnlyWithComplexInput")]
public async Task ErrorInScopedParam_ShouldAppearAsErrorMessage(string workflowName)
{
var workflow = GetWorkflowList();
@@ -386,9 +387,13 @@ private Workflow[] GetWorkflowList()
new Rule {
RuleName = "TrueTest",
Expression = "globalParam1 == \"hello\""
+ },
+ new Rule {
+ RuleName = "TrueTest2",
+ Expression = "globalParam1.ToUpper() == \"HELLO\""
}
}
- },
+ }
};
}
}