< Summary

Information
Class: ProjectTemplate.Web.Authentication.Options.ApplicationAuthenticationOptionsValidator
Assembly: ProjectTemplate.Web
File(s): /home/runner/work/NetCoreApplicationTemplate/NetCoreApplicationTemplate/src/ProjectTemplate.Web/Authentication/Options/ApplicationAuthenticationOptionsValidator.cs
Line coverage
100%
Covered lines: 76
Uncovered lines: 0
Coverable lines: 76
Total lines: 154
Line coverage: 100%
Branch coverage
100%
Covered branches: 12
Total branches: 12
Branch coverage: 100%
Method coverage

Feature is only available for sponsors

Upgrade to PRO version

Metrics

MethodBranch coverage Crap Score Cyclomatic complexity Line coverage
Validate(...)100%22100%
ValidateApplicationAuthentication(...)100%22100%
ValidateOpenIdConnectProvider(...)100%22100%
ValidateSaml2Provider(...)100%22100%
ValidateExternalProvider(...)100%22100%
RequireProviderValue(...)100%11100%
Require(...)100%22100%

File(s)

/home/runner/work/NetCoreApplicationTemplate/NetCoreApplicationTemplate/src/ProjectTemplate.Web/Authentication/Options/ApplicationAuthenticationOptionsValidator.cs

#LineLine coverage
 1using Microsoft.Extensions.Options;
 2using ProjectTemplate.Web.Authentication.Providers.OpenIdConnect;
 3using ProjectTemplate.Web.Authentication.Providers.Saml2;
 4
 5namespace ProjectTemplate.Web.Authentication.Options;
 6
 7/// <summary>
 8/// Validates application authentication configuration during application startup.
 9/// </summary>
 10public sealed class ApplicationAuthenticationOptionsValidator : IValidateOptions<ApplicationAuthenticationOptions>
 11{
 12    /// <inheritdoc />
 13    public ValidateOptionsResult Validate(string? name, ApplicationAuthenticationOptions options)
 14    {
 29815        ArgumentNullException.ThrowIfNull(options);
 16
 29817        List<string> failures = [];
 18
 29819        ValidateApplicationAuthentication(options, failures);
 29820        ValidateOpenIdConnectProvider(options.Providers.OpenIdConnect, failures);
 29821        ValidateSaml2Provider(options.Providers.Saml2, failures);
 29822        ValidateExternalProvider("Microsoft", options.Providers.Microsoft, failures);
 29823        ValidateExternalProvider("Google", options.Providers.Google, failures);
 29824        ValidateExternalProvider("GitHub", options.Providers.GitHub, failures);
 25
 29826        return failures.Count == 0
 29827            ? ValidateOptionsResult.Success
 29828            : ValidateOptionsResult.Fail(failures);
 29    }
 30
 31    private static void ValidateApplicationAuthentication(
 32        ApplicationAuthenticationOptions options,
 33        ICollection<string> failures)
 34    {
 29835        Require(
 29836            !string.IsNullOrWhiteSpace(options.DefaultScheme),
 29837            "ProjectTemplate:Authentication:DefaultScheme is required.",
 29838            failures);
 39
 29840        Require(
 29841            !string.IsNullOrWhiteSpace(options.DefaultChallengeScheme),
 29842            "ProjectTemplate:Authentication:DefaultChallengeScheme is required.",
 29843            failures);
 44
 29845        Require(
 29846            !string.IsNullOrWhiteSpace(options.DefaultSignInScheme),
 29847            "ProjectTemplate:Authentication:DefaultSignInScheme is required.",
 29848            failures);
 49
 29850        if (!options.Enabled)
 51        {
 652            return;
 53        }
 54
 29255        Require(
 29256            options.Cookie.Enabled,
 29257            "ProjectTemplate:Authentication:Cookie:Enabled must be true when application authentication is enabled.",
 29258            failures);
 59
 29260        Require(
 29261            !string.IsNullOrWhiteSpace(options.Cookie.Scheme),
 29262            "ProjectTemplate:Authentication:Cookie:Scheme is required when application authentication is enabled.",
 29263            failures);
 64
 29265        Require(
 29266            options.Cookie.ExpireMinutes > 0,
 29267            "ProjectTemplate:Authentication:Cookie:ExpireMinutes must be greater than zero when application authenticati
 29268            failures);
 29269    }
 70
 71    private static void ValidateOpenIdConnectProvider(
 72        OpenIdConnectAuthenticationOptions options,
 73        ICollection<string> failures)
 74    {
 29875        if (!options.Enabled)
 76        {
 28877            return;
 78        }
 79
 80        const string prefix = "ProjectTemplate:Authentication:Providers:OpenIdConnect";
 81
 1082        RequireProviderValue(prefix, nameof(options.Scheme), options.Scheme, failures);
 1083        RequireProviderValue(prefix, nameof(options.DisplayName), options.DisplayName, failures);
 1084        RequireProviderValue(prefix, nameof(options.Authority), options.Authority, failures);
 1085        RequireProviderValue(prefix, nameof(options.ClientId), options.ClientId, failures);
 1086        RequireProviderValue(prefix, nameof(options.CallbackPath), options.CallbackPath, failures);
 1087        RequireProviderValue(prefix, nameof(options.ResponseType), options.ResponseType, failures);
 88
 1089        Require(
 1090            options.Scopes.Any(scope => !string.IsNullOrWhiteSpace(scope)),
 1091            $"{prefix}:Scopes must contain at least one non-empty value when the OpenID Connect provider is enabled.",
 1092            failures);
 1093    }
 94
 95    private static void ValidateSaml2Provider(
 96        Saml2AuthenticationOptions options,
 97        ICollection<string> failures)
 98    {
 29899        if (!options.Enabled)
 100        {
 288101            return;
 102        }
 103
 104        const string prefix = "ProjectTemplate:Authentication:Providers:Saml2";
 105
 10106        RequireProviderValue(prefix, nameof(options.Scheme), options.Scheme, failures);
 10107        RequireProviderValue(prefix, nameof(options.DisplayName), options.DisplayName, failures);
 10108        RequireProviderValue(prefix, nameof(options.EntityId), options.EntityId, failures);
 10109        RequireProviderValue(prefix, nameof(options.MetadataUrl), options.MetadataUrl, failures);
 10110        RequireProviderValue(prefix, nameof(options.ModulePath), options.ModulePath, failures);
 10111    }
 112
 113    private static void ValidateExternalProvider(
 114        string providerName,
 115        ApplicationExternalAuthenticationProviderOptions options,
 116        ICollection<string> failures)
 117    {
 894118        if (!options.Enabled)
 119        {
 860120            return;
 121        }
 122
 34123        string prefix = $"ProjectTemplate:Authentication:Providers:{providerName}";
 124
 34125        RequireProviderValue(prefix, nameof(options.Scheme), options.Scheme, failures);
 34126        RequireProviderValue(prefix, nameof(options.DisplayName), options.DisplayName, failures);
 34127        RequireProviderValue(prefix, nameof(options.ClientId), options.ClientId, failures);
 34128        RequireProviderValue(prefix, nameof(options.ClientSecret), options.ClientSecret, failures);
 34129        RequireProviderValue(prefix, nameof(options.CallbackPath), options.CallbackPath, failures);
 34130    }
 131
 132    private static void RequireProviderValue(
 133        string prefix,
 134        string key,
 135        string? value,
 136        ICollection<string> failures)
 137    {
 280138        Require(
 280139            !string.IsNullOrWhiteSpace(value),
 280140            $"{prefix}:{key} is required when the provider is enabled.",
 280141            failures);
 280142    }
 143
 144    private static void Require(
 145        bool condition,
 146        string failureMessage,
 147        ICollection<string> failures)
 148    {
 2060149        if (!condition)
 150        {
 14151            failures.Add(failureMessage);
 152        }
 2060153    }
 154}