< Summary

Information
Class: Elsa.Identity.Features.DefaultAuthenticationFeature
Assembly: Elsa.Identity
File(s): /home/runner/work/elsa-core/elsa-core/src/modules/Elsa.Identity/Features/DefaultAuthenticationFeature.cs
Line coverage
94%
Covered lines: 51
Uncovered lines: 3
Coverable lines: 54
Total lines: 173
Line coverage: 94.4%
Branch coverage
80%
Covered branches: 8
Total branches: 10
Branch coverage: 80%
Method coverage

Feature is only available for sponsors

Upgrade to PRO version

Metrics

File(s)

/home/runner/work/elsa-core/elsa-core/src/modules/Elsa.Identity/Features/DefaultAuthenticationFeature.cs

#LineLine coverage
 1using AspNetCore.Authentication.ApiKey;
 2using Elsa.Extensions;
 3using Elsa.Features.Abstractions;
 4using Elsa.Features.Attributes;
 5using Elsa.Features.Services;
 6using Elsa.Identity.Constants;
 7using Elsa.Identity.Options;
 8using Elsa.Identity.Providers;
 9using Elsa.Options;
 10using Elsa.Requirements;
 11using Microsoft.AspNetCore.Authentication;
 12using Microsoft.AspNetCore.Authentication.JwtBearer;
 13using Microsoft.AspNetCore.Authorization;
 14using Microsoft.Extensions.DependencyInjection;
 15
 16namespace Elsa.Identity.Features;
 17
 18/// <summary>
 19/// Provides an authorization feature that configures the system with JWT bearer and API key authentication.
 20/// </summary>
 21[DependsOn(typeof(IdentityFeature))]
 22public class DefaultAuthenticationFeature : FeatureBase
 23{
 24    private const string MultiScheme = "Jwt-or-ApiKey";
 825    private Func<AuthenticationBuilder, AuthenticationBuilder> _configureApiKeyAuthorization = builder => builder.AddApi
 26    private Action<AuthorizationOptions>? _configureAuthorizationOptions;
 27
 28    /// <inheritdoc />
 829    public DefaultAuthenticationFeature(IModule module) : base(module)
 30    {
 831        ConfigureAuthorizationOptions = ConfigureDefaultSecurityRootPolicy;
 832    }
 33
 34    /// <summary>
 35    /// Gets or sets the <see cref="ApiKeyProviderType"/>.
 36    /// </summary>
 1437    public Type ApiKeyProviderType { get; set; } = typeof(DefaultApiKeyProvider);
 38
 39    /// <summary>
 40    /// Gets or sets the authorization options configuration.
 41    /// </summary>
 42    public Action<AuthorizationOptions> ConfigureAuthorizationOptions
 43    {
 744        get => _configureAuthorizationOptions ?? ConfigureDefaultSecurityRootPolicy;
 1045        set => _configureAuthorizationOptions = value ?? ConfigureDefaultSecurityRootPolicy;
 46    }
 47
 48    /// <summary>
 49    /// Gets or sets whether localhost requests may satisfy the security-root permission requirement without other crede
 50    /// </summary>
 1351    public bool EnableLocalHostPermissionGrant { get; set; }
 52
 53    /// <summary>
 54    /// Configures the API key provider type.
 55    /// </summary>
 56    /// <typeparam name="T">The type of the API key provider.</typeparam>
 57    /// <returns>The current <see cref="DefaultAuthenticationFeature"/>.</returns>
 58    public DefaultAuthenticationFeature UseApiKeyAuthorization<T>() where T : class, IApiKeyProvider
 59    {
 360        ApiKeyProviderType = typeof(T);
 661        _configureApiKeyAuthorization = builder => builder.AddApiKeyInAuthorizationHeader<T>();
 362        return this;
 63    }
 64
 65    /// <summary>
 66    /// Configures the API key provider type to <see cref="AdminApiKeyProvider"/>. The provider denies all keys unless c
 67    /// </summary>
 68    /// <returns>The current <see cref="DefaultAuthenticationFeature"/>.</returns>
 369    public DefaultAuthenticationFeature UseAdminApiKey() => UseApiKeyAuthorization<AdminApiKeyProvider>();
 70
 71    /// <summary>
 72    /// Configures the admin API key provider with an explicit API key.
 73    /// </summary>
 74    /// <param name="apiKey">The API key to accept.</param>
 75    /// <returns>The current <see cref="DefaultAuthenticationFeature"/>.</returns>
 76    public DefaultAuthenticationFeature UseAdminApiKey(string apiKey)
 77    {
 478        Services.Configure<AdminApiKeyOptions>(options => options.ApiKey = apiKey);
 379        return UseAdminApiKey();
 80    }
 81
 82    /// <summary>
 83    /// Configures the admin API key provider with an explicit API key.
 84    /// </summary>
 85    /// <param name="configure">The admin API key options to configure.</param>
 86    /// <returns>The current <see cref="DefaultAuthenticationFeature"/>.</returns>
 87    public DefaultAuthenticationFeature UseAdminApiKey(Action<AdminApiKeyOptions> configure)
 88    {
 089        Services.Configure(configure);
 090        return UseAdminApiKey();
 91    }
 92
 93    /// <summary>
 94    /// Enables the all-zero development admin API key. Do not use in production.
 95    /// </summary>
 96    /// <returns>The current <see cref="DefaultAuthenticationFeature"/>.</returns>
 397    public DefaultAuthenticationFeature UseDevelopmentAdminApiKey() => UseAdminApiKey(AdminApiKeyProvider.DevelopmentApi
 98
 99    /// <summary>
 100    /// Enables the legacy localhost permission grant for the security root policy.
 101    /// </summary>
 102    public DefaultAuthenticationFeature EnableLocalHostPermissionGrantForSecurityRoot()
 103    {
 3104        EnableLocalHostPermissionGrant = true;
 3105        return this;
 106    }
 107
 108    /// <summary>
 109    /// Disables the localhost permission grant for the security root policy.
 110    /// This is useful when privileged identity bootstrap is handled through features such as <see cref="DefaultAdminUse
 111    /// </summary>
 112    public DefaultAuthenticationFeature DisableLocalHostPermissionGrantForSecurityRoot()
 113    {
 1114        EnableLocalHostPermissionGrant = false;
 1115        return this;
 116    }
 117
 118    /// <summary>
 119    /// Disables the legacy localhost permission grant for the security root policy.
 120    /// This is useful when privileged identity bootstrap is handled through features such as <see cref="DefaultAdminUse
 121    /// </summary>
 122    [Obsolete("Use DisableLocalHostPermissionGrantForSecurityRoot instead.")]
 0123    public DefaultAuthenticationFeature DisableLocalHostRequirement() => DisableLocalHostPermissionGrantForSecurityRoot(
 124
 125    /// <inheritdoc />
 126    public override void Apply()
 127    {
 3128        Services.ConfigureOptions<ConfigureJwtBearerOptions>();
 4129        Services.Configure<AdminApiKeyOptions>(_ => { });
 3130        Services.AddIdentityTokenOptionsValidation();
 3131        Services.Configure<LocalHostPermissionRequirementOptions>(options => options.EnableLocalHostPermissionGrant = En
 132
 3133        var authBuilder = Services
 3134            .AddAuthentication(MultiScheme)
 3135            .AddPolicyScheme(MultiScheme, MultiScheme, options =>
 3136            {
 1137                options.ForwardDefaultSelector = context =>
 1138                {
 590139                    return context.Request.Headers.Authorization.Any(x => x!.Contains(ApiKeyDefaults.AuthenticationSchem
 295140                        ? ApiKeyDefaults.AuthenticationScheme
 295141                        : JwtBearerDefaults.AuthenticationScheme;
 1142                };
 1143            })
 3144            .AddJwtBearer()
 3145            .AddJwtBearer(IdentityAuthenticationSchemes.RefreshToken);
 146
 3147        _configureApiKeyAuthorization(authBuilder);
 148
 3149        Services.AddScoped<IAuthorizationHandler, LocalHostRequirementHandler>();
 3150        Services.AddScoped<IAuthorizationHandler, LocalHostPermissionRequirementHandler>();
 3151        Services.AddScoped(ApiKeyProviderType);
 3152        Services.AddScoped<IApiKeyProvider>(sp => (IApiKeyProvider)sp.GetRequiredService(ApiKeyProviderType));
 3153        Services.AddAuthorization(ConfigureAuthorizationOptions);
 3154    }
 155
 156    private static void ConfigureAuthenticatedSecurityRootPolicy(AuthorizationOptions options)
 157    {
 10158        options.AddPolicy(IdentityPolicyNames.SecurityRoot, policy => policy.RequireAuthenticatedUser());
 5159    }
 160
 161    private void ConfigureDefaultSecurityRootPolicy(AuthorizationOptions options)
 162    {
 6163        if (EnableLocalHostPermissionGrant)
 1164            ConfigureLocalHostSecurityRootPolicy(options);
 165        else
 5166            ConfigureAuthenticatedSecurityRootPolicy(options);
 5167    }
 168
 169    private static void ConfigureLocalHostSecurityRootPolicy(AuthorizationOptions options)
 170    {
 2171        options.AddPolicy(IdentityPolicyNames.SecurityRoot, policy => policy.AddRequirements(new LocalHostPermissionRequ
 1172    }
 173}