mirror of
https://github.com/MindWorkAI/AI-Studio.git
synced 2026-11-03 19:47:21 +00:00
119 lines
4.6 KiB
C#
119 lines
4.6 KiB
C#
using AIStudio.Tools.Security;
|
|
|
|
using Microsoft.AspNetCore.Http;
|
|
using Microsoft.Extensions.Logging.Abstractions;
|
|
|
|
namespace AIStudio.Tests.Tools.AppAccess;
|
|
|
|
/// <summary>
|
|
/// Checks which requests the app server lets through to the app.
|
|
/// </summary>
|
|
/// <remarks>
|
|
/// Only the app window has the session cookie, so every request without it gets refused, whatever
|
|
/// it asks for: pages, static files, the Blazor hub, the local files, and the preview of a visual
|
|
/// briefing alike. A request which a script sends also carries the origin of its page. Only the
|
|
/// pages of the app may send such requests: a page from anywhere else, and a sandboxed iframe with
|
|
/// its origin "null", get refused even with the cookie.
|
|
/// </remarks>
|
|
[TestFixture]
|
|
public sealed class AppAccessMiddlewareTests
|
|
{
|
|
private const int APP_PORT = 61153;
|
|
|
|
private const string UI_TOKEN = "0123456789abcdef0123456789abcdef0123456789abcdef0123456789abcdef";
|
|
|
|
/// <summary>
|
|
/// The status a request gets when it passes the middleware.
|
|
/// </summary>
|
|
private const int PASSED = StatusCodes.Status204NoContent;
|
|
|
|
private static readonly string[] PATHS =
|
|
[
|
|
"/",
|
|
"/chat",
|
|
"/_blazor/negotiate",
|
|
"/_blazor",
|
|
"/_framework/blazor.web.js",
|
|
"/local/file",
|
|
"/visual-briefing/preview/0b6c1c43-6d2e-4f0b-9a35-6f6f3c1f2a10/6a4e7d6e-2a8c-4bb0-8c55-7a2b7b3c9e01",
|
|
"/system/MudBlazor/MudBlazor.min.css",
|
|
"/app.css",
|
|
"/changelog/v26.10.1.md",
|
|
"/does-not-exist"
|
|
];
|
|
|
|
private static async Task<int> SendAsync(string path, string? sessionCookie, params string[] origins)
|
|
{
|
|
var middleware = new AppAccessMiddleware(Pass, new AppAccessPolicy(APP_PORT, UI_TOKEN), NullLogger<AppAccessMiddleware>.Instance);
|
|
var context = new DefaultHttpContext { Request = { Method = HttpMethods.Get, Path = path } };
|
|
if (sessionCookie is not null)
|
|
context.Request.Headers.Cookie = $"{AppAccessPolicy.SESSION_COOKIE_NAME}={sessionCookie}";
|
|
|
|
if (origins.Length > 0)
|
|
context.Request.Headers.Origin = origins;
|
|
|
|
await middleware.InvokeAsync(context);
|
|
return context.Response.StatusCode;
|
|
}
|
|
|
|
private static Task Pass(HttpContext context)
|
|
{
|
|
context.Response.StatusCode = PASSED;
|
|
return Task.CompletedTask;
|
|
}
|
|
|
|
[TestCaseSource(nameof(PATHS))]
|
|
public async Task ARequestWithTheSessionCookiePasses(string path)
|
|
{
|
|
Assert.That(await SendAsync(path, UI_TOKEN), Is.EqualTo(PASSED));
|
|
}
|
|
|
|
[TestCaseSource(nameof(PATHS))]
|
|
public async Task ARequestWithoutTheSessionCookieIsRefused(string path)
|
|
{
|
|
Assert.That(await SendAsync(path, null), Is.EqualTo(StatusCodes.Status403Forbidden));
|
|
}
|
|
|
|
[TestCase("0123456789abcdef0123456789abcdef0123456789abcdef0123456789abcdee")]
|
|
[TestCase("0123456789abcdef")]
|
|
[TestCase("0123456789abcdef0123456789abcdef0123456789abcdef0123456789abcdef0")]
|
|
[TestCase("")]
|
|
public async Task ARequestWithAWrongSessionCookieIsRefused(string sessionCookie)
|
|
{
|
|
Assert.That(await SendAsync("/", sessionCookie), Is.EqualTo(StatusCodes.Status403Forbidden));
|
|
}
|
|
|
|
[Test]
|
|
public async Task TheTokenUnderAnotherCookieNameIsRefused()
|
|
{
|
|
var middleware = new AppAccessMiddleware(Pass, new AppAccessPolicy(APP_PORT, UI_TOKEN), NullLogger<AppAccessMiddleware>.Instance);
|
|
var context = new DefaultHttpContext { Request = { Method = HttpMethods.Get, Path = "/", Headers = { Cookie = $"session={UI_TOKEN}" } } };
|
|
|
|
await middleware.InvokeAsync(context);
|
|
Assert.That(context.Response.StatusCode, Is.EqualTo(StatusCodes.Status403Forbidden));
|
|
}
|
|
|
|
[TestCase("http://127.0.0.1:61153")]
|
|
[TestCase("http://localhost:61153")]
|
|
[TestCase("http://[::1]:61153")]
|
|
public async Task ARequestFromTheAppPasses(string origin)
|
|
{
|
|
Assert.That(await SendAsync("/_blazor/negotiate", UI_TOKEN, origin), Is.EqualTo(PASSED));
|
|
}
|
|
|
|
[TestCase("http://rebind.example:61153")]
|
|
[TestCase("null")]
|
|
[TestCase("http://127.0.0.1:61154")]
|
|
[TestCase("https://127.0.0.1:61153")]
|
|
[TestCase("http://127.0.0.1")]
|
|
public async Task ARequestFromAnotherOriginIsRefusedEvenWithTheSessionCookie(string origin)
|
|
{
|
|
Assert.That(await SendAsync("/_blazor/negotiate", UI_TOKEN, origin), Is.EqualTo(StatusCodes.Status403Forbidden));
|
|
}
|
|
|
|
[Test]
|
|
public async Task ARequestWithSeveralOriginsIsRefused()
|
|
{
|
|
Assert.That(await SendAsync("/_blazor/negotiate", UI_TOKEN, "http://127.0.0.1:61153", "http://rebind.example:61153"), Is.EqualTo(StatusCodes.Status403Forbidden));
|
|
}
|
|
} |