| File: Integration\SetLanguageEndpointTests.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 System.Net; using Aspire.Dashboard.Utils; using Aspire.Hosting; using Microsoft.AspNetCore.InternalTesting; using Microsoft.AspNetCore.Localization; using Xunit; namespace Aspire.Dashboard.Tests.Integration; public class SetLanguageEndpointTests { private readonly ITestOutputHelper _testOutputHelper; public SetLanguageEndpointTests(ITestOutputHelper testOutputHelper) { _testOutputHelper = testOutputHelper; } [Fact] public async Task Get_SetLanguage_Http_CultureCookieIsNotSecure() { await using var app = IntegrationTestHelpers.CreateDashboardWebApplication(_testOutputHelper); await app.StartAsync().DefaultTimeout(); using var client = CreateClient(new Uri($"http://{app.FrontendSingleEndPointAccessor().EndPoint}")); var response = await client.GetAsync(DashboardUrls.SetLanguageUrl("fr", "/hi")).DefaultTimeout(); var cookie = AssertCultureCookie(response); // Browsers drop Secure cookies set over plain HTTP from non-localhost origins, which would break language selection. Assert.DoesNotContain("; secure", cookie, StringComparison.OrdinalIgnoreCase); } [Fact] public async Task Get_SetLanguage_Https_CultureCookieIsSecure() { await using var app = IntegrationTestHelpers.CreateDashboardWebApplication(_testOutputHelper, config => { config[DashboardConfigNames.DashboardFrontendUrlName.ConfigKey] = "https://127.0.0.1:0;http://127.0.0.1:0"; }); await app.StartAsync().DefaultTimeout(); var httpsEndpoint = app.FrontendEndPointsAccessor .Select(accessor => accessor()) .Single(endpoint => endpoint.IsHttps); using var client = CreateClient(new Uri(httpsEndpoint.GetResolvedAddress())); var response = await client.GetAsync(DashboardUrls.SetLanguageUrl("fr", "/hi")).DefaultTimeout(); var cookie = AssertCultureCookie(response); Assert.Contains("; secure", cookie, StringComparison.OrdinalIgnoreCase); } [Fact] public async Task Get_SetLanguage_ForwardedHttps_CultureCookieIsSecure() { await using var app = IntegrationTestHelpers.CreateDashboardWebApplication(_testOutputHelper, config => { config[DashboardConfigNames.ForwardedHeaders.ConfigKey] = bool.TrueString; }); await app.StartAsync().DefaultTimeout(); using var client = CreateClient(new Uri($"http://{app.FrontendSingleEndPointAccessor().EndPoint}")); client.DefaultRequestHeaders.Add("X-Forwarded-Proto", "https"); client.DefaultRequestHeaders.Add("X-Forwarded-Host", "localhost"); var response = await client.GetAsync(DashboardUrls.SetLanguageUrl("fr", "/hi")).DefaultTimeout(); var cookie = AssertCultureCookie(response); Assert.Contains("; secure", cookie, StringComparison.OrdinalIgnoreCase); } [Fact] public async Task Get_SetLanguage_ForwardedHttpsHeaderIgnoredWhenForwardedHeadersDisabled_CultureCookieIsNotSecure() { await using var app = IntegrationTestHelpers.CreateDashboardWebApplication(_testOutputHelper); await app.StartAsync().DefaultTimeout(); using var client = CreateClient(new Uri($"http://{app.FrontendSingleEndPointAccessor().EndPoint}")); client.DefaultRequestHeaders.Add("X-Forwarded-Proto", "https"); var response = await client.GetAsync(DashboardUrls.SetLanguageUrl("fr", "/hi")).DefaultTimeout(); var cookie = AssertCultureCookie(response); Assert.DoesNotContain("; secure", cookie, StringComparison.OrdinalIgnoreCase); } [Fact] public async Task Get_SetLanguage_UnsupportedLanguage_NoCultureCookie() { await using var app = IntegrationTestHelpers.CreateDashboardWebApplication(_testOutputHelper); await app.StartAsync().DefaultTimeout(); using var client = CreateClient(new Uri($"http://{app.FrontendSingleEndPointAccessor().EndPoint}")); var response = await client.GetAsync(DashboardUrls.SetLanguageUrl("xx", "/hi")).DefaultTimeout(); Assert.Equal(HttpStatusCode.BadRequest, response.StatusCode); Assert.False(response.Headers.Contains("Set-Cookie")); } private static HttpClient CreateClient(Uri baseAddress) { var handler = new HttpClientHandler { AllowAutoRedirect = false, ServerCertificateCustomValidationCallback = HttpClientHandler.DangerousAcceptAnyServerCertificateValidator, UseCookies = false }; return new HttpClient(handler) { BaseAddress = baseAddress }; } private static string AssertCultureCookie(HttpResponseMessage response) { Assert.Equal(HttpStatusCode.Redirect, response.StatusCode); Assert.Equal("/hi", response.Headers.Location?.OriginalString); var cookie = Assert.Single(response.Headers.GetValues("Set-Cookie")); var expectedValue = Uri.EscapeDataString(CookieRequestCultureProvider.MakeCookieValue(new RequestCulture("fr"))); Assert.StartsWith($"{CookieRequestCultureProvider.DefaultCookieName}={expectedValue};", cookie, StringComparison.Ordinal); Assert.Contains("; httponly", cookie, StringComparison.OrdinalIgnoreCase); Assert.Contains("; samesite=lax", cookie, StringComparison.OrdinalIgnoreCase); Assert.Contains("; expires=", cookie, StringComparison.OrdinalIgnoreCase); return cookie; } }