diff --git a/src/OrchardCoreContrib.HealthChecks/HealthChecksAccessOptions.cs b/src/OrchardCoreContrib.HealthChecks/HealthChecksAccessOptions.cs new file mode 100644 index 0000000..025d8b2 --- /dev/null +++ b/src/OrchardCoreContrib.HealthChecks/HealthChecksAccessOptions.cs @@ -0,0 +1,6 @@ +namespace OrchardCoreContrib.HealthChecks; + +public class HealthChecksAccessOptions +{ + public HashSet AllowedIPs { get; set; } = []; +} diff --git a/src/OrchardCoreContrib.HealthChecks/HealthChecksIPRestrictionMiddleware.cs b/src/OrchardCoreContrib.HealthChecks/HealthChecksIPRestrictionMiddleware.cs index a10280f..5b74ae2 100644 --- a/src/OrchardCoreContrib.HealthChecks/HealthChecksIPRestrictionMiddleware.cs +++ b/src/OrchardCoreContrib.HealthChecks/HealthChecksIPRestrictionMiddleware.cs @@ -1,28 +1,23 @@ using Microsoft.AspNetCore.Http; -using Microsoft.Extensions.Configuration; using Microsoft.Extensions.Logging; using Microsoft.Extensions.Options; -using OrchardCore.Environment.Shell.Configuration; namespace OrchardCoreContrib.HealthChecks; public class HealthChecksIPRestrictionMiddleware( RequestDelegate next, - IShellConfiguration shellConfiguration, IOptions healthChecksOptions, + IOptions healthChecksAccessOptions, ILogger logger) { private readonly HealthChecksOptions _healthChecksOptions = healthChecksOptions.Value; - private readonly HashSet _allowedIPs = - shellConfiguration.GetSection($"{Constants.ConfigurationKey}:AllowedIPs").Get()?.ToHashSet(StringComparer.OrdinalIgnoreCase) - ?? []; public async Task InvokeAsync(HttpContext context) { if (context.Request.Path.Equals(_healthChecksOptions.Url)) { var remoteIP = context.Connection.RemoteIpAddress?.ToString(); - if (!_allowedIPs.Contains(remoteIP)) + if (!healthChecksAccessOptions.Value.AllowedIPs.Contains(remoteIP)) { logger.LogWarning("Unauthorized IP {IP} tried to access {HealthCheckEndpoint}.", remoteIP, _healthChecksOptions.Url); diff --git a/src/OrchardCoreContrib.HealthChecks/Manifest.cs b/src/OrchardCoreContrib.HealthChecks/Manifest.cs index bad963e..867738e 100644 --- a/src/OrchardCoreContrib.HealthChecks/Manifest.cs +++ b/src/OrchardCoreContrib.HealthChecks/Manifest.cs @@ -18,20 +18,20 @@ [assembly: Feature( Id = "OrchardCoreContrib.HealthChecks.IPRestriction", Name = "Health Checks IP Restriction", - Description = "Restricts access to health check endpoints by IP address.", + Description = "Restricts access to health checks endpoints by IP address.", Dependencies = [ "OrchardCoreContrib.HealthChecks" ] )] [assembly: Feature( Id = "OrchardCoreContrib.HealthChecks.RateLimiting", Name = "Health Checks Rate Limiting", - Description = "Limits requests to health check endpoints to prevent DOS attacks.", + Description = "Limits requests to health checks endpoints to prevent DOS attacks.", Dependencies = ["OrchardCoreContrib.HealthChecks"] )] [assembly: Feature( Id = "OrchardCoreContrib.HealthChecks.BlockingRateLimiting", Name = "Health Checks Blocking Rate Limiting", - Description = "Adds blocking behavior to the health check rate limiter. Clients exceeding the limit are temporarily blocked to prevent DoS attacks.", + Description = "Adds blocking behavior to the health checks rate limiter. Clients exceeding the limit are temporarily blocked to prevent DoS attacks.", Dependencies = new[] { "OrchardCoreContrib.HealthChecks.RateLimiting" } )] diff --git a/src/OrchardCoreContrib.HealthChecks/Startup.cs b/src/OrchardCoreContrib.HealthChecks/Startup.cs index 6872829..4d1f89b 100644 --- a/src/OrchardCoreContrib.HealthChecks/Startup.cs +++ b/src/OrchardCoreContrib.HealthChecks/Startup.cs @@ -69,10 +69,13 @@ private static async Task WriteResponse(HttpContext context, HealthReport report } [Feature("OrchardCoreContrib.HealthChecks.IPRestriction")] -public class IPRestrictionStartup : StartupBase +public class IPRestrictionStartup(IShellConfiguration shellConfiguration) : StartupBase { public override int Order => 10; + public override void ConfigureServices(IServiceCollection services) + => services.Configure(shellConfiguration.GetSection($"{Constants.ConfigurationKey}:Access")); + public override void Configure(IApplicationBuilder app, IEndpointRouteBuilder routes, IServiceProvider serviceProvider) => app.UseMiddleware(); } @@ -83,9 +86,7 @@ public class RateLimitingStartup(IShellConfiguration shellConfiguration) : Start public override int Order => 30; public override void ConfigureServices(IServiceCollection services) - { - services.Configure(shellConfiguration.GetSection($"{Constants.ConfigurationKey}:RateLimiting")); - } + => services.Configure(shellConfiguration.GetSection($"{Constants.ConfigurationKey}:RateLimiting")); public override void Configure(IApplicationBuilder app, IEndpointRouteBuilder routes, IServiceProvider serviceProvider) => app.UseMiddleware(); diff --git a/src/OrchardCoreContrib.Modules.Web/appsettings.json b/src/OrchardCoreContrib.Modules.Web/appsettings.json index f4d05fb..d82396f 100644 --- a/src/OrchardCoreContrib.Modules.Web/appsettings.json +++ b/src/OrchardCoreContrib.Modules.Web/appsettings.json @@ -45,7 +45,9 @@ "OrchardCoreContrib_HealthChecks": { "Url": "/health", "ShowDetails": true, - "AllowedIPs": [ "127.0.0.1", "::1" ], + "Access": { + "AllowedIPs": [ "127.0.0.1", "::1" ] + }, "RateLimiting": { "PermitLimit": 5, "Window": "00:00:10", diff --git a/test/OrchardCoreContrib.HealthChecks.Tests/OrchardCoreStartup.cs b/test/OrchardCoreContrib.HealthChecks.Tests/OrchardCoreStartup.cs index 1c9ca89..4e7a79d 100644 --- a/test/OrchardCoreContrib.HealthChecks.Tests/OrchardCoreStartup.cs +++ b/test/OrchardCoreContrib.HealthChecks.Tests/OrchardCoreStartup.cs @@ -49,8 +49,8 @@ private IConfigurationRoot AddHealthChecksConfiguration() var newConfiguration = new Dictionary { { $"{Constants.ConfigurationKey}:{nameof(HealthChecksOptions.Url)}", "/health" }, - { $"{Constants.ConfigurationKey}:AllowedIPs:0", "127.0.0.1" }, - { $"{Constants.ConfigurationKey}:AllowedIPs:1", "::1" } + { $"{Constants.ConfigurationKey}:Access:AllowedIPs:0", "127.0.0.1" }, + { $"{Constants.ConfigurationKey}:Access:AllowedIPs:1", "::1" } }; return new ConfigurationBuilder()