< Summary

Information
Class: Elsa.Workflows.Api.Security.WorkflowDefinitionScriptAuthorizationService
Assembly: Elsa.Workflows.Api
File(s): /home/runner/work/elsa-core/elsa-core/src/modules/Elsa.Workflows.Api/Security/WorkflowDefinitionScriptAuthorizationService.cs
Line coverage
75%
Covered lines: 37
Uncovered lines: 12
Coverable lines: 49
Total lines: 106
Line coverage: 75.5%
Branch coverage
22%
Covered branches: 4
Total branches: 18
Branch coverage: 22.2%
Method coverage

Feature is only available for sponsors

Upgrade to PRO version

Metrics

MethodBranch coverage Crap Score Cyclomatic complexity Line coverage
.ctor(...)100%11100%
.cctor()100%11100%
AuthorizeAsync()50%2275%
AuthorizeAsync()50%2283.33%
AuthorizeAsync()100%11100%
AuthorizeScriptUsage(...)0%4260%
GetUsedScriptPoliciesAsync()100%11100%
IsRunActivity(...)100%11100%
HasExpression(...)50%22100%
HasPermission(...)0%2040%
get_ExpressionType()100%11100%

File(s)

/home/runner/work/elsa-core/elsa-core/src/modules/Elsa.Workflows.Api/Security/WorkflowDefinitionScriptAuthorizationService.cs

#LineLine coverage
 1using System.Security.Claims;
 2using Elsa.Expressions.Contracts;
 3using Elsa.Extensions;
 4using Elsa.Workflows.Activities;
 5using Elsa.Workflows.Management.Models;
 6
 7namespace Elsa.Workflows.Api.Security;
 8
 169internal class WorkflowDefinitionScriptAuthorizationService(
 1610    IActivityVisitor activityVisitor,
 1611    IExpressionDescriptorRegistry expressionDescriptorRegistry)
 12{
 113    private static readonly ScriptPolicy[] ScriptPolicies =
 114    [
 115        new(
 116            "CSharp",
 117            WorkflowScriptActivityTypeNames.RunCSharp,
 118            PermissionNames.ExecuteCSharpExpressions,
 119            "C# workflow expression execution is disabled by the host. Set CSharpOptions.AllowHostCodeExecution to true 
 120        new(
 121            "Python",
 122            WorkflowScriptActivityTypeNames.RunPython,
 123            PermissionNames.ExecutePythonExpressions,
 124            "Python.NET workflow expression execution is disabled by the host. Set PythonOptions.AllowHostCodeExecution 
 125    ];
 26
 27    public async Task<WorkflowDefinitionScriptAuthorizationResult> AuthorizeAsync(WorkflowDefinitionModel model, ClaimsP
 28    {
 329        if (model.Root == null)
 330            return WorkflowDefinitionScriptAuthorizationResult.Allowed();
 31
 032        return await AuthorizeAsync(model.Root, user, cancellationToken);
 333    }
 34
 35    public async Task<WorkflowDefinitionScriptAuthorizationResult> AuthorizeAsync(IActivity root, ClaimsPrincipal user, 
 36    {
 1137        var scriptUsages = await GetUsedScriptPoliciesAsync(root, cancellationToken);
 38
 1139        var failure = scriptUsages
 040            .Select(policy => AuthorizeScriptUsage(policy, user))
 1141            .FirstOrDefault(result => result is { Succeeded: false });
 42
 1143        if (failure.FailureReason.HasValue)
 044            return failure;
 45
 1146        return WorkflowDefinitionScriptAuthorizationResult.Allowed();
 1147    }
 48
 49    public async Task<WorkflowDefinitionScriptAuthorizationResult> AuthorizeAsync(Workflow workflow, ClaimsPrincipal use
 50    {
 1151        return await AuthorizeAsync((IActivity)workflow, user, cancellationToken);
 1152    }
 53
 54    private WorkflowDefinitionScriptAuthorizationResult AuthorizeScriptUsage(ScriptPolicy policy, ClaimsPrincipal user)
 55    {
 56        // Language-specific options live in optional modules. Workflows.Api observes the descriptor state projected by 
 057        if (expressionDescriptorRegistry.Find(policy.ExpressionType)?.IsBrowsable != true)
 058            return WorkflowDefinitionScriptAuthorizationResult.HostDisabled(policy.HostDisabledMessage);
 59
 060        return HasPermission(user, policy.Permission)
 061            ? WorkflowDefinitionScriptAuthorizationResult.Allowed()
 062            : WorkflowDefinitionScriptAuthorizationResult.MissingPermission();
 63    }
 64
 65    private async Task<IEnumerable<ScriptPolicy>> GetUsedScriptPoliciesAsync(IActivity root, CancellationToken cancellat
 66    {
 1167        var graph = await activityVisitor.VisitAsync(root, cancellationToken);
 1168        var nodes = new[] { graph }.Concat(graph.Descendants()).ToList();
 1169        var policies = ScriptPolicies
 11470            .Where(policy => nodes.Any(x => IsRunActivity(x.Activity, policy) || HasExpression(x.Activity, policy)))
 1171            .ToList();
 72
 1173        return policies;
 1174    }
 75
 76    private static bool IsRunActivity(IActivity activity, ScriptPolicy policy) =>
 9277        string.Equals(activity.Type, policy.RunActivityType, StringComparison.Ordinal);
 78
 79    private static bool HasExpression(IActivity activity, ScriptPolicy policy) =>
 13880        activity.GetInputs().Any(x => string.Equals(x.Expression?.Type, policy.ExpressionType, StringComparison.Ordinal)
 81
 82    private static bool HasPermission(ClaimsPrincipal user, string permission)
 83    {
 084        return user.Claims.Any(x =>
 085            x.Type == PermissionNames.ClaimType &&
 086            (string.Equals(x.Value, PermissionNames.All, StringComparison.Ordinal) ||
 087             string.Equals(x.Value, permission, StringComparison.Ordinal)));
 88    }
 89
 14090    private sealed record ScriptPolicy(string ExpressionType, string RunActivityType, string Permission, string HostDisa
 91}
 92
 93internal readonly record struct WorkflowDefinitionScriptAuthorizationResult(bool Succeeded, WorkflowDefinitionScriptAuth
 94{
 95    public static WorkflowDefinitionScriptAuthorizationResult Allowed() => new(true, null, null);
 96
 97    public static WorkflowDefinitionScriptAuthorizationResult HostDisabled(string message) => new(false, WorkflowDefinit
 98
 99    public static WorkflowDefinitionScriptAuthorizationResult MissingPermission() => new(false, WorkflowDefinitionScript
 100}
 101
 102internal enum WorkflowDefinitionScriptAuthorizationFailureReason
 103{
 104    HostDisabled,
 105    MissingPermission
 106}