< Summary - Kestrun — Combined Coverage

Information
Class: Kestrun.Hosting.KestrunSecurityMiddlewareExtensions
Assembly: Kestrun
File(s): /home/runner/work/Kestrun/Kestrun/src/CSharp/Kestrun/Hosting/KestrunSecurityMiddlewareExtensions.cs
Tag: Kestrun/Kestrun@2d87023b37eb91155071c91dd3d6a2eeb3004705
Line coverage
66%
Covered lines: 63
Uncovered lines: 32
Coverable lines: 95
Total lines: 259
Line coverage: 66.3%
Branch coverage
42%
Covered branches: 17
Total branches: 40
Branch coverage: 42.5%
Method coverage

Feature is only available for sponsors

Upgrade to PRO version

Coverage history

Coverage history 0 25 50 75 100 10/17/2025 - 15:48:30 Line coverage: 66.3% (63/95) Branch coverage: 42.5% (17/40) Total lines: 259 Tag: Kestrun/Kestrun@b8199aff869a847b75e185d0527ba45e04a43d86 10/17/2025 - 15:48:30 Line coverage: 66.3% (63/95) Branch coverage: 42.5% (17/40) Total lines: 259 Tag: Kestrun/Kestrun@b8199aff869a847b75e185d0527ba45e04a43d86

Metrics

MethodBranch coverage Crap Score Cyclomatic complexity Line coverage
AddRateLimiter(...)50%6677.77%
AddRateLimiter(...)16.66%7666.66%
AddAntiforgery(...)75%5457.14%
AddAntiforgery(...)16.66%12645.45%
AddCorsAllowAll(...)100%11100%
AddCors(...)0%2260%
AddCors(...)50%6680%
AddHostFiltering(...)0%2040%
AddHostFiltering(...)100%66100%

File(s)

/home/runner/work/Kestrun/Kestrun/src/CSharp/Kestrun/Hosting/KestrunSecurityMiddlewareExtensions.cs

#LineLine coverage
 1using Kestrun.Utilities;
 2using Microsoft.AspNetCore.Antiforgery;
 3using Microsoft.AspNetCore.Cors.Infrastructure;
 4using Microsoft.AspNetCore.RateLimiting;
 5using Serilog.Events;
 6using Microsoft.AspNetCore.HostFiltering;
 7
 8namespace Kestrun.Hosting;
 9
 10/// <summary>
 11/// Extension methods for adding security-related middleware to a <see cref="KestrunHost"/>.
 12/// </summary>
 13public static class KestrunSecurityMiddlewareExtensions
 14{
 15    /// <summary>
 16    /// Adds rate limiting to the application using the specified <see cref="RateLimiterOptions"/>.
 17    /// </summary>
 18    /// <param name="host">The KestrunHost instance to configure.</param>
 19    /// <param name="cfg">The configuration options for rate limiting.</param>
 20    /// <returns>The current KestrunHost instance.</returns>
 21    public static KestrunHost AddRateLimiter(this KestrunHost host, RateLimiterOptions cfg)
 22    {
 223        if (host.Logger.IsEnabled(LogEventLevel.Debug))
 24        {
 025            host.Logger.Debug("Adding rate limiter with configuration: {@Config}", cfg);
 26        }
 27
 228        if (cfg == null)
 29        {
 130            return host.AddRateLimiter();   // fall back to your “blank” overload
 31        }
 32
 133        _ = host.AddService(services =>
 134        {
 035            _ = services.AddRateLimiter(opts => opts.CopyFrom(cfg));   // ← single line!
 136        });
 37
 138        return host.Use(app => app.UseRateLimiter());
 39    }
 40
 41
 42    /// <summary>
 43    /// Adds rate limiting to the application using the specified configuration delegate.
 44    /// </summary>
 45    /// <param name="host">The KestrunHost instance to configure.</param>
 46    /// <param name="cfg">An optional delegate to configure rate limiting options.</param>
 47    /// <returns>The current KestrunHost instance.</returns>
 48    public static KestrunHost AddRateLimiter(this KestrunHost host, Action<RateLimiterOptions>? cfg = null)
 49    {
 350        if (host.Logger.IsEnabled(LogEventLevel.Debug))
 51        {
 052            host.Logger.Debug("Adding rate limiter with configuration: {HasConfig}", cfg != null);
 53        }
 54
 55        // Register the rate limiter service
 356        _ = host.AddService(services =>
 357            {
 058                _ = services.AddRateLimiter(cfg ?? (_ => { })); // Always pass a delegate
 359            });
 60
 61        // Apply the middleware
 362        return host.Use(app =>
 363        {
 064            if (host.Logger.IsEnabled(LogEventLevel.Debug))
 365            {
 066                host.Logger.Debug("Registering rate limiter middleware");
 367            }
 368
 069            _ = app.UseRateLimiter();
 370        });
 71    }
 72
 73
 74
 75    /// <summary>
 76    /// Adds antiforgery protection to the application.
 77    /// This overload allows you to specify configuration options.
 78    /// </summary>
 79    /// <param name="host">The KestrunHost instance to configure.</param>
 80    /// <param name="options">The antiforgery options to configure.</param>
 81    /// <returns>The current KestrunHost instance.</returns>
 82    public static KestrunHost AddAntiforgery(this KestrunHost host, AntiforgeryOptions? options)
 83    {
 284        if (host.Logger.IsEnabled(LogEventLevel.Debug))
 85        {
 086            host.Logger.Debug("Adding Antiforgery with configuration: {@Config}", options);
 87        }
 88
 289        if (options == null)
 90        {
 191            return host.AddAntiforgery(); // no config, use defaults
 92        }
 93
 94        // Delegate to the Action-based overload
 195        return host.AddAntiforgery(cfg =>
 196        {
 097            cfg.Cookie = options.Cookie;
 098            cfg.FormFieldName = options.FormFieldName;
 099            cfg.HeaderName = options.HeaderName;
 0100            cfg.SuppressXFrameOptionsHeader = options.SuppressXFrameOptionsHeader;
 1101#if NET9_0_OR_GREATER
 0102            cfg.SuppressReadingTokenFromFormBody = options.SuppressReadingTokenFromFormBody;
 1103#endif
 1104        });
 105    }
 106
 107    /// <summary>
 108    /// Adds antiforgery protection to the application.
 109    /// </summary>
 110    /// <param name="host">The KestrunHost instance to configure.</param>
 111    /// <param name="setupAction">An optional action to configure the antiforgery options.</param>
 112    /// <returns>The current KestrunHost instance.</returns>
 113    public static KestrunHost AddAntiforgery(this KestrunHost host, Action<AntiforgeryOptions>? setupAction = null)
 114    {
 4115        if (host.Logger.IsEnabled(LogEventLevel.Debug))
 116        {
 0117            host.Logger.Debug(
 0118                setupAction == null
 0119                    ? "Adding Antiforgery with default configuration (no custom options provided)."
 0120                    : "Adding Antiforgery with custom configuration via setupAction."
 0121            );
 122        }
 123        // Service side
 4124        _ = host.AddService(services =>
 4125        {
 0126            _ = setupAction == null ? services.AddAntiforgery() : services.AddAntiforgery(setupAction);
 4127        });
 128
 129        // Middleware side
 4130        return host.Use(app => app.UseAntiforgery());
 131    }
 132
 133
 134    /// <summary>
 135    /// Adds a CORS policy named "AllowAll" that allows any origin, method, and header.
 136    /// </summary>
 137    /// <param name="host">The KestrunHost instance to configure.</param>
 138    /// <returns>The current KestrunHost instance.</returns>
 139    public static KestrunHost AddCorsAllowAll(this KestrunHost host) =>
 1140        host.AddCors("AllowAll", b => b.AllowAnyOrigin()
 1141                                  .AllowAnyMethod()
 1142                                  .AllowAnyHeader());
 143
 144    /// <summary>
 145    /// Registers a named CORS policy that was already composed with a
 146    /// <see cref="CorsPolicyBuilder"/> and applies that policy in the pipeline.
 147    /// </summary>
 148    /// <param name="host">The KestrunHost instance to configure.</param>
 149    /// <param name="policyName">The name to store/apply the policy under.</param>
 150    /// <param name="builder">
 151    ///     A fully‑configured <see cref="CorsPolicyBuilder"/>.
 152    ///     Callers typically chain <c>.WithOrigins()</c>, <c>.WithMethods()</c>,
 153    ///     etc. before passing it here.
 154    /// </param>
 155    public static KestrunHost AddCors(this KestrunHost host, string policyName, CorsPolicyBuilder builder)
 156    {
 2157        ArgumentException.ThrowIfNullOrWhiteSpace(policyName);
 2158        ArgumentNullException.ThrowIfNull(builder);
 159
 160        // 1️⃣ Service‑time registration
 1161        _ = host.AddService(services =>
 1162        {
 0163            _ = services.AddCors(options =>
 0164            {
 0165                options.AddPolicy(policyName, builder.Build());
 0166            });
 1167        });
 168
 169        // 2️⃣ Middleware‑time application
 1170        return host.Use(app => app.UseCors(policyName));
 171    }
 172
 173    /// <summary>
 174    /// Registers a named CORS policy that was already composed with a
 175    /// <see cref="CorsPolicyBuilder"/> and applies that policy in the pipeline.
 176    /// </summary>
 177    /// <param name="host">The KestrunHost instance to configure.</param>
 178    /// <param name="policyName">The name to store/apply the policy under.</param>
 179    /// <param name="buildPolicy">An action to configure the CORS policy.</param>
 180    /// <returns>The current KestrunHost instance.</returns>
 181    /// <exception cref="ArgumentException">Thrown when the policy name is null or whitespace.</exception>
 182    public static KestrunHost AddCors(this KestrunHost host, string policyName, Action<CorsPolicyBuilder> buildPolicy)
 183    {
 5184        if (host.Logger.IsEnabled(LogEventLevel.Debug))
 185        {
 0186            host.Logger.Debug("Adding CORS policy: {PolicyName}", policyName);
 187        }
 188
 5189        if (string.IsNullOrWhiteSpace(policyName))
 190        {
 2191            throw new ArgumentException("Policy name required.", nameof(policyName));
 192        }
 193
 3194        ArgumentNullException.ThrowIfNull(buildPolicy);
 195
 2196        _ = host.AddService(s =>
 2197        {
 0198            _ = s.AddCors(o => o.AddPolicy(policyName, buildPolicy));
 2199        });
 200
 201        // apply only that policy
 2202        return host.Use(app => app.UseCors(policyName));
 203    }
 204
 205    /// <summary>
 206    /// Adds Host Filtering to the application using the specified configuration delegate.
 207    /// </summary>
 208    /// <param name="host">The KestrunHost instance to configure.</param>
 209    /// <param name="opts">The delegate for configuring host filtering options.</param>
 210    /// <returns>The updated KestrunHost instance.</returns>
 211    public static KestrunHost AddHostFiltering(this KestrunHost host, Action<HostFilteringOptions>? opts = null)
 212    {
 0213        if (host.Logger.IsEnabled(LogEventLevel.Debug))
 214        {
 0215            host.Logger.Debug("Adding host filtering with configuration: {HostFilteringOptions}", opts != null);
 216        }
 217
 218        // Register the host filtering service
 0219        _ = host.AddService(services =>
 0220            {
 0221                _ = services.AddHostFiltering(opts ?? (_ => { })); // Always pass a delegate
 0222            });
 223
 224        // Apply the middleware
 0225        return host.Use(app => app.UseHostFiltering());
 226    }
 227
 228    /// <summary>
 229    /// Adds Host Filtering to the application using the specified <see cref="HostFilteringOptions"/>.
 230    /// </summary>
 231    /// <param name="host">The KestrunHost instance to configure.</param>
 232    /// <param name="opts">The host filtering options.</param>
 233    /// <returns>The updated KestrunHost instance.</returns>
 234    public static KestrunHost AddHostFiltering(this KestrunHost host, HostFilteringOptions opts)
 235    {
 1236        if (host.Logger.IsEnabled(LogEventLevel.Debug))
 237        {
 1238            host.Logger.Debug("Adding host filtering with configuration: {HostFilteringOptions}", opts);
 239        }
 240
 241        // Register the host filtering service
 1242        _ = host.AddService(services =>
 1243        {
 1244            _ = services.AddHostFiltering(o =>
 1245            {
 1246                o.AllowedHosts.Clear();
 4247                foreach (var host in opts.AllowedHosts)
 1248                {
 1249                    o.AllowedHosts.Add(host);
 1250                }
 1251                o.AllowEmptyHosts = opts.AllowEmptyHosts;
 1252                o.IncludeFailureMessage = opts.IncludeFailureMessage;
 2253            });
 2254        });
 255
 256        // Apply the middleware
 2257        return host.Use(app => app.UseHostFiltering());
 258    }
 259}