< Summary

Information
Class: Elsa.UserTasks.Services.DefaultClaimsIdentityResolver
Assembly: Elsa.UserTasks
File(s): /home/runner/work/elsa-core/elsa-core/src/modules/Elsa.UserTasks/Services/DefaultClaimsIdentityResolver.cs
Line coverage
96%
Covered lines: 29
Uncovered lines: 1
Coverable lines: 30
Total lines: 53
Line coverage: 96.6%
Branch coverage
71%
Covered branches: 10
Total branches: 14
Branch coverage: 71.4%
Method coverage

Feature is only available for sponsors

Upgrade to PRO version

Metrics

MethodBranch coverage Crap Score Cyclomatic complexity Line coverage
.ctor(...)100%11100%
ResolveAsync(...)71.42%141496.42%

File(s)

/home/runner/work/elsa-core/elsa-core/src/modules/Elsa.UserTasks/Services/DefaultClaimsIdentityResolver.cs

#LineLine coverage
 1using System.Security.Claims;
 2using Elsa.UserTasks.Contracts;
 3using Elsa.UserTasks.Models;
 4using Elsa.UserTasks.Options;
 5using Elsa.UserTasks.Permissions;
 6using Microsoft.Extensions.Options;
 7
 8namespace Elsa.UserTasks.Services;
 9
 310public sealed class DefaultClaimsIdentityResolver(IOptions<UserTasksOptions> options) : IUserTaskIdentityResolver
 11{
 12    /// <summary>An ASP.NET role, not a permission, despite reading like one. Kept for hosts that grant it.</summary>
 13    private const string ManagerRole = "user-tasks:manager";
 14
 315    private readonly UserTasksOptions _options = options.Value;
 16
 17    public ValueTask<UserTaskActor?> ResolveAsync(ClaimsPrincipal principal, CancellationToken cancellationToken = defau
 18    {
 319        var subjectId = principal.FindFirstValue(_options.SubjectClaimType)
 320                        ?? principal.FindFirstValue(ClaimTypes.NameIdentifier);
 21
 322        if (string.IsNullOrWhiteSpace(subjectId))
 023            return ValueTask.FromResult<UserTaskActor?>(null);
 24
 325        var tenantId = principal.FindFirstValue(_options.TenantClaimType) ?? _options.DefaultTenantId;
 326        var provider = principal.FindFirstValue(_options.ProviderClaimType) ?? _options.DefaultProvider;
 327        var subject = new ParticipantReference(tenantId, provider, UserTaskParticipantType.User, subjectId,
 328            principal.FindFirstValue(_options.DisplayNameClaimType) ?? principal.Identity?.Name);
 329        var groups = _options.GroupClaimTypes
 630            .SelectMany(type => principal.FindAll(type))
 231            .Select(x => x.Value)
 232            .Where(value => !string.IsNullOrWhiteSpace(value))
 333            .Distinct(StringComparer.Ordinal)
 234            .Select(id => new ParticipantReference(tenantId, provider, UserTaskParticipantType.Group, id))
 335            .ToArray();
 36        // Ordinal, matching the permission model everywhere else: folding case here would collapse two
 37        // spellings into whichever arrived first, and the survivor might be the one that no longer matches.
 338        var permissions = _options.PermissionClaimTypes
 639            .SelectMany(type => principal.FindAll(type))
 440            .Select(x => x.Value)
 441            .Where(value => !string.IsNullOrWhiteSpace(value))
 342            .ToHashSet(StringComparer.Ordinal);
 343        var actor = new UserTaskActor(subject, groups, subject.DisplayName) { Permissions = permissions };
 44
 345        return ValueTask.FromResult<UserTaskActor?>(actor with
 346        {
 347            // Asked of the actor rather than of the raw strings, so a subtree or verb wildcard confers
 348            // manager standing here exactly as it does at every other check.
 349            IsManager = principal.IsInRole(ManagerRole)
 350                        || actor.HasPermission(UserTasksResourcePermissions.UserTasks, UserTaskVerbs.Supervise)
 351        });
 52    }
 53}