Skip to content

Commit faf49b0

Browse files
author
Rajesh Jinaga
committed
Ability to allow or deny registered functions execution
1 parent 70edec3 commit faf49b0

File tree

11 files changed

+165
-53
lines changed

11 files changed

+165
-53
lines changed
Lines changed: 22 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,22 @@
1+
// Copyright (c) navtech.io. All rights reserved.
2+
// See License in the project root for license information.
3+
4+
using System;
5+
6+
namespace Simpleflow.CodeGenerator
7+
{
8+
internal enum EventType
9+
{
10+
None,
11+
VisitFunctionOnAvail
12+
}
13+
internal class ParserEventPublisher
14+
{
15+
public Action<EventType, object> OnVisit;
16+
17+
public void Publish(EventType eventType, object data)
18+
{
19+
OnVisit(eventType, data);
20+
}
21+
}
22+
}

src/Simpleflow/CodeGenerator/SimpleflowCodeVisitor.VisitFunction.cs

Lines changed: 5 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -21,16 +21,19 @@ partial class SimpleflowCodeVisitor<TArg>
2121

2222
public override Expression VisitFunction([NotNull] SimpleflowParser.FunctionContext context)
2323
{
24-
var functionName = context.FunctionName().GetText();
24+
var functionName = context.FunctionName().GetText().Substring(1); // Remove $ symbol
2525

2626
// Get registered function
27-
var function = FunctionRegister.GetFunction(functionName.Substring(1)); // Remove $ symbol
27+
var function = FunctionRegister.GetFunction(functionName);
2828

2929
if (function == null)
3030
{
3131
throw new InvalidFunctionException(functionName);
3232
}
3333

34+
// Publish event once function is available to compile
35+
EventPublisher.Publish(EventType.VisitFunctionOnAvail, functionName);
36+
3437
// Get actual method meta-data info and parameters
3538
var methodInfo = function.GetMethodInfo();
3639

src/Simpleflow/CodeGenerator/SimpleflowCodeVisitor.cs

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -27,9 +27,12 @@ internal partial class SimpleflowCodeVisitor<TArg> : SimpleflowBaseVisitor<Expre
2727
protected readonly ParameterExpression Output; // script main function parameter 2
2828
protected readonly ParameterExpression ScriptHelperContext; //script main function parameter 3
2929

30-
public SimpleflowCodeVisitor(IFunctionRegister functionRegister)
30+
protected readonly ParserEventPublisher EventPublisher;
31+
32+
public SimpleflowCodeVisitor(IFunctionRegister functionRegister, ParserEventPublisher eventPublisher)
3133
{
3234
FunctionRegister = functionRegister ?? throw new ArgumentNullException(nameof(functionRegister));
35+
EventPublisher = eventPublisher;
3336

3437
/* Initialize smart variables and smart json variables */
3538
Variables = new List<ParameterExpression>();

src/Simpleflow/CodeGenerator/SimpleflowCompiler.cs

Lines changed: 5 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -15,7 +15,9 @@ namespace Simpleflow.CodeGenerator
1515
internal class SimpleflowCompiler
1616
{
1717

18-
public static Action<FlowInput<TArg>, FlowOutput, ScriptHelperContext> Compile<TArg>(string code, IFunctionRegister activityRegister)
18+
public static Action<FlowInput<TArg>, FlowOutput, ScriptHelperContext> Compile<TArg>(string code,
19+
IFunctionRegister activityRegister,
20+
ParserEventPublisher eventPublisher)
1921
{
2022
var inputStream = new AntlrInputStream(code);
2123

@@ -43,8 +45,9 @@ public static Action<FlowInput<TArg>, FlowOutput, ScriptHelperContext> Compile<T
4345
throw new SyntaxException(errorListener.GetAggregateMessages(), errorListener.Errors);
4446
}
4547

48+
4649
// Generate code
47-
var visitor = new SimpleflowCodeVisitor<TArg>(activityRegister);
50+
var visitor = new SimpleflowCodeVisitor<TArg>(activityRegister, eventPublisher);
4851
var program = visitor.Visit(programContext);
4952

5053
// Compile
Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,13 @@
1+
// Copyright (c) navtech.io. All rights reserved.
2+
// See License in the project root for license information.
3+
4+
namespace Simpleflow.Exceptions
5+
{
6+
public class AccessDeniedException : SimpleflowException
7+
{
8+
public AccessDeniedException(string message) : base(message)
9+
{
10+
11+
}
12+
}
13+
}

src/Simpleflow/FlowOptions.cs

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -15,11 +15,11 @@ public class FlowOptions : IOptions
1515
/// <summary>
1616
/// Gets or sets AllowFunctions
1717
/// </summary>
18-
public string[] AllowOnlyFunctions { get; set; }
18+
public string[] AllowFunctions { get; set; }
1919

2020
/// <summary>
2121
/// Gets or sets DenyFunctions
2222
/// </summary>
23-
public string[] DenyOnlyFunctions { get; set; }
23+
public string[] DenyFunctions { get; set; }
2424
}
2525
}

src/Simpleflow/IOptions.cs

Lines changed: 3 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -14,19 +14,14 @@ public interface IOptions
1414
bool AllowArgumentToMutate { get; }
1515

1616
/// <summary>
17-
/// Gets or sets AllowFunctions,
18-
/// if nothing is specified all configured functions will be allowed.
19-
/// Either <see cref="AllowOnlyFunctions"/> or <see cref="DenyOnlyFunctions"/>
20-
/// must be set, not both.
17+
/// Gets or sets AllowFunctions
2118
/// </summary>
22-
public string[] AllowOnlyFunctions { get; set; }
19+
public string[] AllowFunctions { get; set; }
2320

2421

2522
/// <summary>
2623
/// Gets or sets DenyFunctions.
27-
/// Either <see cref="AllowOnlyFunctions"/> or <see cref="DenyOnlyFunctions"/>
28-
/// must be set, not both.
2924
/// </summary>
30-
public string[] DenyOnlyFunctions { get; set; }
25+
public string[] DenyFunctions { get; set; }
3126
}
3227
}

src/Simpleflow/Services/CacheService.cs

Lines changed: 6 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -106,8 +106,8 @@ protected virtual string GetScriptUniqueId(string script)
106106
private string GetFlowContextOptionsId(IContextOptions options)
107107
{
108108
if (options.AllowArgumentToMutate == false
109-
&& (options.AllowOnlyFunctions == null || options.AllowOnlyFunctions.Length == 0)
110-
&& (options.DenyOnlyFunctions == null || options.DenyOnlyFunctions.Length == 0)
109+
&& (options.AllowFunctions == null || options.AllowFunctions.Length == 0)
110+
&& (options.DenyFunctions == null || options.DenyFunctions.Length == 0)
111111
)
112112
{
113113
return string.Empty;
@@ -116,16 +116,16 @@ private string GetFlowContextOptionsId(IContextOptions options)
116116
StringBuilder sb = new StringBuilder();
117117
sb.Append(string.Join(' ', options.AllowArgumentToMutate));
118118

119-
if (options.AllowOnlyFunctions != null && options.AllowOnlyFunctions.Length > 0)
119+
if (options.AllowFunctions != null && options.AllowFunctions.Length > 0)
120120
{
121121
sb.Append("Allow"); //ensure add this to avoid collisions
122-
sb.Append(string.Join(' ', options.AllowOnlyFunctions));
122+
sb.Append(string.Join(' ', options.AllowFunctions));
123123
}
124124

125-
if (options.DenyOnlyFunctions != null && options.DenyOnlyFunctions.Length > 0)
125+
if (options.DenyFunctions != null && options.DenyFunctions.Length > 0)
126126
{
127127
sb.Append("Deny"); //ensure add this to avoid collisions
128-
sb.Append(string.Join(' ', options.DenyOnlyFunctions ));
128+
sb.Append(string.Join(' ', options.DenyFunctions ));
129129
}
130130

131131
return GetScriptUniqueId(sb.ToString());

src/Simpleflow/Services/CompilerService.cs

Lines changed: 34 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,9 @@
22
// See License in the project root for license information.
33

44
using System;
5+
using System.Linq;
56
using Simpleflow.CodeGenerator;
7+
using Simpleflow.Exceptions;
68

79
namespace Simpleflow.Services
810
{
@@ -34,7 +36,10 @@ So here we don't need to run again */
3436

3537
if (context.Internals.CompiledScript == null)
3638
{
37-
context.Internals.CompiledScript = SimpleflowCompiler.Compile<TArg>(context.Script, _activityRegister);
39+
var eventPublisher = new ParserEventPublisher();
40+
CheckFunctionExecutionPermissions(context, eventPublisher);
41+
42+
context.Internals.CompiledScript = SimpleflowCompiler.Compile<TArg>(context.Script, _activityRegister, eventPublisher);
3843

3944
context.Trace.Write("Compiled");
4045
}
@@ -45,5 +50,33 @@ So here we don't need to run again */
4550

4651
next?.Invoke(context);
4752
}
53+
54+
private static void CheckFunctionExecutionPermissions<TArg>(FlowContext<TArg> context, ParserEventPublisher eventPublisher)
55+
{
56+
eventPublisher.OnVisit = (type, data) =>
57+
{
58+
if (type == EventType.VisitFunctionOnAvail
59+
&& context.Options?.DenyFunctions != null)
60+
{
61+
var functionName = data.ToString();
62+
if (context.Options.DenyFunctions.Contains(functionName, StringComparer.OrdinalIgnoreCase))
63+
{
64+
throw new AccessDeniedException($"Function '{functionName}' cannot be allowed to run in this context.");
65+
}
66+
}
67+
68+
if (type == EventType.VisitFunctionOnAvail
69+
&& context.Options?.AllowFunctions != null)
70+
{
71+
var functionName = data.ToString();
72+
if (!context.Options.AllowFunctions.Contains(functionName, StringComparer.OrdinalIgnoreCase))
73+
{
74+
throw new AccessDeniedException($"Function '{functionName}' cannot be allowed to run in this context.");
75+
}
76+
}
77+
};
78+
}
79+
80+
4881
}
4982
}

src/Simpleflow/Simpleflow.xml

Lines changed: 5 additions & 10 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

0 commit comments

Comments
 (0)