Skip to content
This repository was archived by the owner on Mar 26, 2019. It is now read-only.
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
// <copyright file="AuthorizedHealthAuthorizationFilter.cs" company="Allan Hardy">
// Copyright (c) Allan Hardy. All rights reserved.
// </copyright>

using System.Threading;
using Microsoft.AspNetCore.Http;

namespace App.Metrics.AspNetCore.Health
{
public class AuthorizedHealthAuthorizationFilter : IHealthAuthorizationFilter
{
/// <inheritdoc />
public bool Authorized(HttpContext context, CancellationToken token = default) { return true; }
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
// <copyright file="IHealthAuthorizationFilter.cs" company="Allan Hardy">
// Copyright (c) Allan Hardy. All rights reserved.
// </copyright>

using System.Threading;
using Microsoft.AspNetCore.Http;

namespace App.Metrics.AspNetCore.Health
{
public interface IHealthAuthorizationFilter
{
bool Authorized(HttpContext context, CancellationToken token = default);
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
// <copyright file="NotAuthorizedHealthAuthorizationFilter.cs" company="Allan Hardy">
// Copyright (c) Allan Hardy. All rights reserved.
// </copyright>

using System.Threading;
using Microsoft.AspNetCore.Http;

namespace App.Metrics.AspNetCore.Health
{
public class NotAuthorizedHealthAuthorizationFilter : IHealthAuthorizationFilter
{
/// <inheritdoc />
public bool Authorized(HttpContext context, CancellationToken token = default) { return false; }
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -33,13 +33,22 @@ public static void MiddlewareExecuting<TMiddleware>(this ILogger logger)
}
}

public static void MiddlewareAuthorizationInvalid<TMiddleware>(this ILogger logger)
{
if (logger.IsEnabled(LogLevel.Trace))
{
logger.LogTrace(AppMetricsEventIds.Middleware.MiddlewareAuthorizationInvalidId, $"Invalid authorization App Metrics Health Middleware {typeof(TMiddleware).FullName}");
}
}

private static class AppMetricsEventIds
{
public static class Middleware
{
public const int MiddlewareExecutedId = 1;
public const int MiddlewareExecutingId = 2;
public const int MiddlewareErrorId = 3;
public const int MiddlewareAuthorizationInvalidId = 4;
}
}
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@
// </copyright>

using System;
using App.Metrics.AspNetCore.Health;
using App.Metrics.AspNetCore.Health.Endpoints;
using App.Metrics.AspNetCore.Health.Endpoints.Middleware;
using App.Metrics.Health;
Expand Down Expand Up @@ -112,7 +113,8 @@ private static void UseHealthMiddleware(
appBuilder =>
{
var responseWriter = HealthAspNetCoreHealthEndpointsServiceCollectionExtensions.ResolveHealthResponseWriter(app.ApplicationServices, formatter);
appBuilder.UseMiddleware<HealthCheckEndpointMiddleware>(responseWriter, endpointsOptionsAccessor.Value.Timeout);
var healthAuthorizationFilter = app.ApplicationServices.GetService<IHealthAuthorizationFilter>() ?? new AuthorizedHealthAuthorizationFilter();
appBuilder.UseMiddleware<HealthCheckEndpointMiddleware>(responseWriter, endpointsOptionsAccessor.Value.Timeout, healthAuthorizationFilter);
});
}
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,7 @@ public class HealthCheckEndpointMiddleware
{
private readonly IRunHealthChecks _healthCheckRunner;
private readonly IHealthResponseWriter _healthResponseWriter;
private readonly IHealthAuthorizationFilter _healthAuthorizationFilter;
private readonly ILogger<HealthCheckEndpointMiddleware> _logger;
private readonly TimeSpan _timeout;

Expand All @@ -28,12 +29,14 @@ public HealthCheckEndpointMiddleware(
ILoggerFactory loggerFactory,
IRunHealthChecks healthCheckRunner,
IHealthResponseWriter healthResponseWriter,
IHealthAuthorizationFilter healthAuthorizationFilter,
TimeSpan timeout)
// ReSharper restore UnusedParameter.Local
{
_healthCheckRunner = healthCheckRunner;
_logger = loggerFactory.CreateLogger<HealthCheckEndpointMiddleware>();
_healthResponseWriter = healthResponseWriter ?? throw new ArgumentNullException(nameof(healthResponseWriter));
_healthAuthorizationFilter = healthAuthorizationFilter ?? new AuthorizedHealthAuthorizationFilter();
_timeout = timeout <= TimeSpan.Zero ? TimeSpan.FromSeconds(20) : timeout;
}

Expand All @@ -49,9 +52,18 @@ public async Task Invoke(HttpContext context)
{
try
{
if (!_healthAuthorizationFilter.Authorized(context))
{
_logger.MiddlewareAuthorizationInvalid<HealthCheckEndpointMiddleware>();
context.Response.StatusCode = StatusCodes.Status401Unauthorized;
await context.Response.WriteAsync("Invalid authorization.", cancellationToken: cancellationTokenSource.Token);
}
else
{
var healthStatus = await _healthCheckRunner.ReadAsync(cancellationTokenSource.Token);

await _healthResponseWriter.WriteAsync(context, healthStatus, cancellationTokenSource.Token);
}
}
catch (OperationCanceledException e)
{
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,31 @@
// <copyright file="HealthCheckEndpointAuthorizationMiddleware.cs" company="Allan Hardy">
// Copyright (c) Allan Hardy. All rights reserved.
// </copyright>

using System.Net;
using System.Net.Http;
using System.Threading.Tasks;
using App.Metrics.AspNetCore.Health.Integration.Facts.Startup;
using FluentAssertions;
using Xunit;

namespace App.Metrics.AspNetCore.Health.Integration.Facts.Middleware
{
public class HealthCheckEndpointAuthorizationMiddleware : IClassFixture<StartupTestFixture<NotAuthorizedHealthTestStartup>>
{
public HealthCheckEndpointAuthorizationMiddleware(StartupTestFixture<NotAuthorizedHealthTestStartup> fixture)
{
Client = fixture.Client;
}

private HttpClient Client { get; }

[Fact]
public async Task Returns_correct_response_headers_not_authorized()
{
var result = await Client.GetAsync("/health");

result.StatusCode.Should().Be(HttpStatusCode.Unauthorized);
}
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,37 @@
// <copyright file="NotAuthorizedHealthTestStartup.cs" company="Allan Hardy">
// Copyright (c) Allan Hardy. All rights reserved.
// </copyright>

using App.Metrics.AspNetCore.Health.Endpoints;
using App.Metrics.Health;
using Microsoft.AspNetCore.Builder;
using Microsoft.AspNetCore.Hosting;
using Microsoft.Extensions.DependencyInjection;
using Microsoft.Extensions.Logging;

namespace App.Metrics.AspNetCore.Health.Integration.Facts.Startup
{
// ReSharper disable ClassNeverInstantiated.Global
public class NotAuthorizedHealthTestStartup : TestStartup
// ReSharper restore ClassNeverInstantiated.Global
{
public void Configure(IApplicationBuilder app, IHostingEnvironment env, ILoggerFactory loggerFactory)
{
app.UseHealthEndpoint();

SetupAppBuilder(app, env, loggerFactory);
}

public void ConfigureServices(IServiceCollection services)
{
services.AddSingleton<IHealthAuthorizationFilter, NotAuthorizedHealthAuthorizationFilter>();

var appMetricsMiddlewareHealthCheckOptions = new HealthEndpointsOptions();

SetupServices(
services,
appMetricsMiddlewareHealthCheckOptions,
healthChecks: new[] { HealthCheckResult.Healthy() });
}
}
}