< Summary

Information
Class: Elsa.ExternalAuthentication.Options.PermissionGrantOptions
Assembly: Elsa.ExternalAuthentication
File(s): /home/runner/work/elsa-core/elsa-core/src/modules/Elsa.ExternalAuthentication/Options/ExternalAuthenticationOptions.cs
Line coverage
100%
Covered lines: 2
Uncovered lines: 0
Coverable lines: 2
Total lines: 258
Line coverage: 100%
Branch coverage
N/A
Covered branches: 0
Total branches: 0
Branch coverage: N/A
Method coverage

Feature is only available for sponsors

Upgrade to PRO version

Metrics

MethodBranch coverage Crap Score Cyclomatic complexity Line coverage
get_AllowedPermissions()100%11100%
get_DeniedPermissions()100%11100%

File(s)

/home/runner/work/elsa-core/elsa-core/src/modules/Elsa.ExternalAuthentication/Options/ExternalAuthenticationOptions.cs

#LineLine coverage
 1using Elsa.ExternalAuthentication.Models;
 2using Elsa.Authorization;
 3using Elsa.ExternalAuthentication.Permissions;
 4using Microsoft.Extensions.Configuration;
 5
 6namespace Elsa.ExternalAuthentication.Options;
 7
 8/// <summary>
 9/// Configures deployment-owned External Authentication behavior.
 10/// </summary>
 11public class ExternalAuthenticationOptions
 12{
 13    /// <summary>Deployment-owned broker clients. Configuration key: <c>AuthenticationClients</c>.</summary>
 14    [ConfigurationKeyName("AuthenticationClients")]
 15    public ICollection<AuthenticationClient> Clients { get; set; } = new List<AuthenticationClient>();
 16
 17    /// <summary>Controls brokered Elsa username/password login as a normal login method.</summary>
 18    public LocalLoginMethodOptions LocalLogin { get; set; } = new();
 19
 20    /// <summary>Immutable configuration-owned connections. Configuration key: <c>Connections</c>.</summary>
 21    [ConfigurationKeyName("Connections")]
 22    public ICollection<IdentityProviderConnection> ConfigurationConnections { get; set; } = new List<IdentityProviderCon
 23
 24    /// <summary>Enables the optional database connection source and persisted management surface.</summary>
 25    public bool EnableDatabaseConnections { get; set; } = true;
 26
 27    /// <summary>Allows a database-owned host connection to explicitly supersede a configuration-owned connection with t
 28    public bool AllowConfigurationConnectionOverrides { get; set; }
 29
 30    /// <summary>Adapter types permitted by this deployment. An empty collection permits every installed adapter.</summa
 31    public ICollection<string> AllowedAdapterTypes { get; set; } = new List<string>();
 32
 33    /// <summary>Unlinked identity policy types permitted by this deployment.</summary>
 34    public ICollection<string> AllowedUnlinkedIdentityPolicyTypes { get; set; } = ["reject", "create-user"];
 35
 36    /// <summary>External user matcher types permitted by this deployment.</summary>
 37    public ICollection<string> AllowedExternalUserMatcherTypes { get; set; } = new List<string>();
 38
 39    /// <summary>Permission grant source types permitted by this deployment.</summary>
 40    public ICollection<string> AllowedPermissionGrantSourceTypes { get; set; } = ["elsa-roles", "claim-mapping", "group-
 41
 42    /// <summary>Controls the deployment default and database override boundary for unlinked identities.</summary>
 43    public UnlinkedIdentityPolicyOptions UnlinkedIdentityPolicy { get; set; } = new();
 44
 45    /// <summary>Defines deployment-wide Elsa permission allow and deny boundaries.</summary>
 46    public PermissionGrantOptions PermissionGrants { get; set; } = new();
 47
 48    /// <summary>Configures transaction, code, preview, and session lifetimes.</summary>
 49    public ExternalAuthenticationLifetimesOptions Lifetimes { get; set; } = new();
 50
 51    /// <summary>Defines default projected-claim size limits.</summary>
 52    public ExternalAuthenticationClaimsOptions Claims { get; set; } = new();
 53
 54    /// <summary>Configures anonymous broker endpoint rate limits.</summary>
 55    public ExternalAuthenticationRateLimitOptions RateLimits { get; set; } = new();
 56
 57    /// <summary>Controls provider HTTP destinations, redirects, timeouts, and response limits.</summary>
 58    public ProviderEgressOptions ProviderEgress { get; set; } = new();
 59
 60    /// <summary>Controls callback, return-path, and broker-client PKCE validation.</summary>
 61    public RedirectValidationOptions Redirects { get; set; } = new();
 62
 63    /// <summary>Reserved broker-side description of WebAssembly persistence; Studio enforces its host-local setting.</s
 64    public WebAssemblyCredentialPersistenceOptions WebAssemblyPersistence { get; set; } = new();
 65
 66    /// <summary>Defines the deployment default for upstream provider logout.</summary>
 67    public ExternalAuthenticationLogoutOptions Logout { get; set; } = new();
 68
 69    /// <summary>Prevents management changes from removing the last normal login path without recovery.</summary>
 70    public FinalLoginPathGuardOptions FinalLoginPathGuard { get; set; } = new();
 71
 72    /// <summary>Configures optional operational surfaces.</summary>
 73    public ExternalAuthenticationOperationsOptions Operations { get; set; } = new();
 74
 75    /// <summary>Configures stable keyed hashing for persisted opaque handles and external subjects.</summary>
 76    public ExternalAuthenticationHandleHashingOptions HandleHashing { get; set; } = new();
 77}
 78
 79/// <summary>Deployment-owned availability and presentation settings for broker-local credential sign-in.</summary>
 80public class LocalLoginMethodOptions
 81{
 82    /// <summary>Whether brokered local credentials appear as a normal login method.</summary>
 83    public bool IsEnabled { get; set; } = true;
 84    /// <summary>Text shown by login method discovery.</summary>
 85    public string DisplayName { get; set; } = "Elsa account";
 86    /// <summary>Trusted server-hosted icon identifier.</summary>
 87    public string IconId { get; set; } = "elsa";
 88    /// <summary>Deterministic chooser order.</summary>
 89    public int DisplayOrder { get; set; }
 90    /// <summary>Whether local login is the preferred sign-in method for its scope; this never causes automatic redirect
 91    public bool IsPreferred { get; set; }
 92}
 93
 94/// <summary>Configures the deployment-owned default unlinked identity policy.</summary>
 95public class UnlinkedIdentityPolicyOptions
 96{
 97    /// <summary>Default registered policy type. The safe default rejects unlinked identities.</summary>
 98    public string DefaultType { get; set; } = "reject";
 99    /// <summary>Whether a database-owned connection may select another deployment-allowed policy.</summary>
 100    public bool AllowDatabaseConnectionOverride { get; set; }
 101}
 102
 103/// <summary>Defines deployment-level boundaries applied after grant sources resolve candidate permissions.</summary>
 104public class PermissionGrantOptions
 105{
 106    /// <summary>When empty, all syntactically valid permission names are eligible unless denied.</summary>
 361107    public ICollection<string> AllowedPermissions { get; set; } = new List<string>();
 108    /// <summary>Exact permission names denied regardless of grant source.</summary>
 397109    public ICollection<string> DeniedPermissions { get; set; } = new List<string>();
 110}
 111
 112/// <summary>Configures bounded authentication flow and session lifetimes.</summary>
 113public class ExternalAuthenticationLifetimesOptions
 114{
 115    /// <summary>Maximum age of a broker or provider correlation transaction.</summary>
 116    public TimeSpan BrokerTransactionLifetime { get; set; } = TimeSpan.FromMinutes(10);
 117    /// <summary>Maximum age of a single-use broker completion code.</summary>
 118    public TimeSpan CompletionCodeLifetime { get; set; } = TimeSpan.FromMinutes(1);
 119    /// <summary>Maximum age of preview state and its one-time result.</summary>
 120    public TimeSpan PreviewLifetime { get; set; } = TimeSpan.FromMinutes(10);
 121    /// <summary>Absolute maximum external authentication session age.</summary>
 122    public TimeSpan MaximumSessionAge { get; set; } = TimeSpan.FromHours(8);
 123}
 124
 125/// <summary>Defines default bounds for normalized projected external claims.</summary>
 126public class ExternalAuthenticationClaimsOptions
 127{
 128    /// <summary>Maximum number of projected claims.</summary>
 129    public int MaximumClaimCount { get; set; } = 64;
 130    /// <summary>Maximum length of one projected string value.</summary>
 131    public int MaximumValueLength { get; set; } = 1_024;
 132    /// <summary>Maximum aggregate UTF-8 size of projected claims.</summary>
 133    public int MaximumTotalBytes { get; set; } = 16 * 1_024;
 134}
 135
 136public class ExternalAuthenticationRateLimitOptions
 137{
 138    /// <summary>
 139    /// Selects the partition key used by the broker's named rate-limit policies.
 140    /// Remote IP is the secure default because it cannot be bypassed by a caller-supplied client identifier.
 141    /// </summary>
 142    public ExternalAuthenticationRateLimitPartitionStrategy PartitionStrategy { get; set; } = ExternalAuthenticationRate
 143    /// <summary>Login method discovery rate limit.</summary>
 144    public RateLimitRule Discovery { get; set; } = new(60, TimeSpan.FromMinutes(1));
 145    /// <summary>External provider initiation rate limit.</summary>
 146    public RateLimitRule ExternalInitiation { get; set; } = new(20, TimeSpan.FromMinutes(1));
 147    /// <summary>Broker-local credential initiation rate limit.</summary>
 148    public RateLimitRule LocalInitiation { get; set; } = new(10, TimeSpan.FromMinutes(1));
 149    /// <summary>Provider callback rate limit.</summary>
 150    public RateLimitRule ProviderCallback { get; set; } = new(60, TimeSpan.FromMinutes(1));
 151    /// <summary>Authorization-code and refresh-token exchange rate limit.</summary>
 152    public RateLimitRule TokenExchange { get; set; } = new(30, TimeSpan.FromMinutes(1));
 153}
 154
 155/// <summary>Selects the server-derived value used to partition anonymous broker rate limits.</summary>
 156public enum ExternalAuthenticationRateLimitPartitionStrategy
 157{
 158    /// <summary>Partition by remote IP address.</summary>
 159    RemoteIp,
 160    /// <summary>Partition by registered client identifier and remote IP address.</summary>
 161    ClientIdAndRemoteIp
 162}
 163
 164/// <summary>A fixed-window permit limit.</summary>
 165public sealed record RateLimitRule(int PermitLimit, TimeSpan Window);
 166
 167/// <summary>Controls outbound traffic to identity providers.</summary>
 168public class ProviderEgressOptions
 169{
 170    /// <summary>Reject non-HTTPS provider endpoints.</summary>
 171    public bool RequireHttps { get; set; } = true;
 172    /// <summary>Allow resolved private, loopback, link-local, or otherwise non-public destinations.</summary>
 173    public bool AllowPrivateNetworkDestinations { get; set; }
 174    /// <summary>Maximum redirects followed after validating every destination.</summary>
 175    public int MaximumRedirects { get; set; } = 3;
 176    /// <summary>Maximum outbound connection establishment time.</summary>
 177    public TimeSpan ConnectTimeout { get; set; } = TimeSpan.FromSeconds(10);
 178    /// <summary>Maximum complete provider request time.</summary>
 179    public TimeSpan RequestTimeout { get; set; } = TimeSpan.FromSeconds(10);
 180    /// <summary>Maximum discovery document size.</summary>
 181    public long MaximumDiscoveryResponseBytes { get; set; } = 1 * 1_024 * 1_024;
 182    /// <summary>Maximum token endpoint response size.</summary>
 183    public long MaximumTokenResponseBytes { get; set; } = 256 * 1_024;
 184    /// <summary>Maximum UserInfo response size.</summary>
 185    public long MaximumUserInfoResponseBytes { get; set; } = 256 * 1_024;
 186    /// <summary>Optional exact host allowlist. An empty collection does not add a host restriction.</summary>
 187    public ICollection<string> AllowedHosts { get; set; } = new List<string>();
 188    /// <summary>Optional deployment-approved HTTP(S) proxy without embedded credentials.</summary>
 189    public Uri? ProxyUri { get; set; }
 190}
 191
 192/// <summary>Controls broker-client callback and return-path validation.</summary>
 193public class RedirectValidationOptions
 194{
 195    /// <summary>Deployment-owned public base URI used to derive upstream provider callbacks.</summary>
 196    public Uri? ExternalCallbackBaseUri { get; set; }
 197    /// <summary>Reserved compatibility preference; the broker currently always requires S256 PKCE.</summary>
 198    public bool RequirePkceS256 { get; set; } = true;
 199    /// <summary>Allow explicit HTTP loopback callback registrations for development.</summary>
 200    public bool AllowDevelopmentLoopbackCallbacks { get; set; }
 201    /// <summary>Reserved configurable limit; the current validator enforces a fixed 2,048-character maximum.</summary>
 202    public int MaximumReturnPathLength { get; set; } = 2_048;
 203}
 204
 205/// <summary>Describes a broker-side WebAssembly persistence preference; the Studio host owns enforcement.</summary>
 206public class WebAssemblyCredentialPersistenceOptions
 207{
 208    /// <summary>Selected credential persistence mode.</summary>
 209    public BrowserCredentialPersistence Persistence { get; set; } = BrowserCredentialPersistence.Memory;
 210    /// <summary>Require a deployment-visible warning for persistent browser storage.</summary>
 211    public bool RequireExplicitPersistentStorageWarning { get; set; } = true;
 212}
 213
 214/// <summary>Configures the default upstream sign-out behavior.</summary>
 215public class ExternalAuthenticationLogoutOptions
 216{
 217    /// <summary>Reserved deployment preference; current connections default directly to <see cref="UpstreamLogoutMode.D
 218    public UpstreamLogoutMode DefaultUpstreamLogoutMode { get; set; } = UpstreamLogoutMode.Disabled;
 219}
 220
 221/// <summary>Protects deployment access when a connection mutation removes a normal login method.</summary>
 222public class FinalLoginPathGuardOptions
 223{
 224    /// <summary>Enables the guard.</summary>
 225    public bool IsEnabled { get; set; } = true;
 226    /// <summary>Require another normal method, local login, break glass, or privileged confirmation.</summary>
 227    public bool RequireRecoveryMethod { get; set; } = true;
 228    /// <summary>Permission required for a confirmed final-login-path override.</summary>
 229    public string PrivilegedOverridePermission { get; set; } = $"{ExternalAuthenticationResourcePermissions.ProviderTrus
 230    /// <summary>Set by deployment configuration when a separately hosted break-glass method remains available.</summary
 231    public bool HasBreakGlassAuthentication { get; set; }
 232}
 233
 234/// <summary>Enables optional operational surfaces without making them readiness dependencies.</summary>
 235public class ExternalAuthenticationOperationsOptions
 236{
 237    /// <summary>Expose permission-guarded external session list and revoke endpoints.</summary>
 238    public bool EnableSessionAdministration { get; set; } = true;
 239    /// <summary>Reserved host preference; register the check explicitly with <c>AddExternalAuthenticationHealthCheck</c
 240    public bool EnableHealthCheck { get; set; }
 241    /// <summary>Reserved preferred check name for host integration.</summary>
 242    public string HealthCheckName { get; set; } = "external-authentication";
 243    /// <summary>Reserved preferred check tags for host integration.</summary>
 244    public ICollection<string> HealthCheckTags { get; set; } = ["external-authentication", "optional"];
 245}
 246
 247/// <summary>
 248/// Configures the keyed hashes used for opaque broker handles, external subjects, and secret generations.
 249/// </summary>
 250public class ExternalAuthenticationHandleHashingOptions
 251{
 252    /// <summary>
 253    /// A base64-encoded key containing at least 256 bits of entropy. All nodes that share External
 254    /// Authentication persistence must use the same value. When omitted, a process-local key is
 255    /// generated for single-node development.
 256    /// </summary>
 257    public string? SharedKeyBase64 { get; set; }
 258}