File: BrowserSecurityHeadersMiddlewareTests.cs
Web Access
Project: src\tests\Aspire.Dashboard.Tests\Aspire.Dashboard.Tests.csproj (Aspire.Dashboard.Tests)
// Licensed to the .NET Foundation under one or more agreements.
// The .NET Foundation licenses this file to you under the MIT license.
 
using Aspire.Dashboard.Authentication.Connection;
using Aspire.Dashboard.Model;
using Microsoft.AspNetCore.Http;
using Microsoft.AspNetCore.InternalTesting;
using Microsoft.Extensions.FileProviders;
using Microsoft.Extensions.Hosting;
using Microsoft.Extensions.Primitives;
using Xunit;
 
namespace Aspire.Dashboard.Tests;
 
public class BrowserSecurityHeadersMiddlewareTests
{
    [Fact]
    public async Task InvokeAsync_Development_AllowExternalFetch()
    {
        // Arrange
        var middleware = CreateMiddleware(environmentName: "Development");
        var httpContext = new DefaultHttpContext();
 
        // Act
        await middleware.InvokeAsync(httpContext).DefaultTimeout();
 
        // Assert
        Assert.NotEqual(StringValues.Empty, httpContext.Response.Headers.ContentSecurityPolicy);
        Assert.DoesNotContain("default-src", httpContext.Response.Headers.ContentSecurityPolicy.ToString());
    }
 
    [Fact]
    public async Task InvokeAsync_Production_DenyExternalFetch()
    {
        // Arrange
        var middleware = CreateMiddleware(environmentName: "Production");
        var httpContext = new DefaultHttpContext();
 
        // Act
        await middleware.InvokeAsync(httpContext).DefaultTimeout();
 
        // Assert
        Assert.NotEqual(StringValues.Empty, httpContext.Response.Headers.ContentSecurityPolicy);
        Assert.Contains("default-src", httpContext.Response.Headers.ContentSecurityPolicy.ToString());
    }
 
    [Theory]
    [InlineData("https", "img-src data: https:;")]
    [InlineData("http", "img-src data: http: https:;")]
    public async Task InvokeAsync_Scheme_ImageSourceChangesOnScheme(string scheme, string expectedContent)
    {
        // Arrange
        var middleware = CreateMiddleware(environmentName: "Production");
        var httpContext = new DefaultHttpContext();
        httpContext.Request.Scheme = scheme;
 
        // Act
        await middleware.InvokeAsync(httpContext).DefaultTimeout();
 
        // Assert
        Assert.NotEqual(StringValues.Empty, httpContext.Response.Headers.ContentSecurityPolicy);
        Assert.Contains(expectedContent, httpContext.Response.Headers.ContentSecurityPolicy.ToString());
    }
 
    [Fact]
    public async Task InvokeAsync_Otlp_NotAdded()
    {
        // Arrange
        var middleware = CreateMiddleware(environmentName: "Production");
        var httpContext = new DefaultHttpContext();
        httpContext.Features.Set<IConnectionTypeFeature>(new TestConnectionTypeFeature { ConnectionTypes = [ConnectionType.Otlp] });
 
        // Act
        await middleware.InvokeAsync(httpContext).DefaultTimeout();
 
        // Assert
        Assert.Equal(StringValues.Empty, httpContext.Response.Headers.ContentSecurityPolicy);
    }
 
    private sealed class TestConnectionTypeFeature : IConnectionTypeFeature
    {
        public required List<ConnectionType> ConnectionTypes { get; init; }
    }
 
    private static BrowserSecurityHeadersMiddleware CreateMiddleware(string environmentName) =>
        new BrowserSecurityHeadersMiddleware(c => Task.CompletedTask, new TestHostEnvironment { EnvironmentName = environmentName });
 
    private sealed class TestHostEnvironment : IHostEnvironment
    {
        public string ApplicationName { get; set; } = "ApplicationName";
        public IFileProvider ContentRootFileProvider { get; set; } = default!;
        public string ContentRootPath { get; set; } = "ContentRootPath";
        public string EnvironmentName { get; set; } = "Development";
    }
}