Files
TinfoilVibeServer/TinfoilVibeServerTest/Tests/BasicAuthMiddlewareTests.cs
T
ecenshu 995e4aa518 Allow for cancelling downloads from filesystem
Rebuild request orignally will use setting for constructing the url
Rebuild request from client via no-cache will use httppcontext to get runtime pathing to generate url
Escape the url generated
2025-11-07 16:13:48 +10:30

116 lines
3.6 KiB
C#

using System;
using System.Collections.Generic;
using System.IO;
using System.Net;
using System.Text;
using System.Threading.Tasks;
using Microsoft.AspNetCore.Http;
using Microsoft.Extensions.Logging;
using Moq;
using NUnit.Framework;
using TinfoilVibeServer.Authentication;
using TinfoilVibeServer.Middleware;
namespace TinfoilVibeServerTest.Tests
{
[TestFixture]
public class BasicAuthMiddlewareTests
{
private Mock<ILogger<BasicAuthMiddleware>> _loggerMock;
private Mock<IAuthStore> _authMock;
private BasicAuthMiddleware _middleware;
private RequestDelegate _next;
[SetUp]
public void SetUp()
{
_loggerMock = new Mock<ILogger<BasicAuthMiddleware>>();
_authMock = new Mock<IAuthStore>();
_next = (HttpContext ctx) => Task.CompletedTask;
_middleware = new BasicAuthMiddleware(_next);
}
private HttpContext CreateContext(string authHeader = "", string ip = "127.0.0.1", int? uid = null)
{
var ctx = new DefaultHttpContext();
ctx.Connection.RemoteIpAddress = IPAddress.Parse(ip);
if (!string.IsNullOrEmpty(authHeader))
{
ctx.Request.Headers["Authorization"] = authHeader;
}
if (uid!= null)
{
ctx.Request.Headers["UID"] = uid.ToString();
}
return ctx;
}
[Test]
public async Task InvokeAsync_NoAuthHeader_ShouldReturn401()
{
// Arrange
var ctx = CreateContext();
// Act
await _middleware.InvokeAsync(ctx, _authMock.Object, _loggerMock.Object);
// Assert
Assert.That(ctx.Response.StatusCode, Is.EqualTo(StatusCodes.Status401Unauthorized));
_loggerMock.Verify(l => l.Log(
LogLevel.Warning,
It.IsAny<EventId>(),
It.Is<It.IsAnyType>((v, t) => v.ToString().Contains("Missing Authorization header")),
null,
It.IsAny<Func<It.IsAnyType, Exception, string>>()), Times.Once);
}
[Test]
public async Task InvokeAsync_BlacklistedIP_ShouldReturn403()
{
// Arrange
var ctx = CreateContext("Basic dXNlcjpwYXNz");
_authMock.Setup(a => a.IsIPBlacklisted("127.0.0.1")).Returns(true);
// Act
await _middleware.InvokeAsync(ctx, _authMock.Object, _loggerMock.Object);
// Assert
Assert.That(ctx.Response.StatusCode, Is.EqualTo(StatusCodes.Status403Forbidden));
}
[Test]
public async Task InvokeAsync_ValidCredentials_ShouldCallNext()
{
// Arrange
var user = "alice";
var pw = "secret";
var uid = 1234;
var header = $"Basic {Convert.ToBase64String(Encoding.ASCII.GetBytes($"{user}:{pw}"))}";
var ip = "127.0.0.1";
var ctx = CreateContext(header,ip, uid);
string? error;
_authMock.Setup(a =>
a.TryValidate(user, pw, uid, ip, out error))
.Returns(true);
bool nextCalled = false;
_next = (HttpContext _) => { nextCalled = true; return Task.CompletedTask; };
_middleware = new BasicAuthMiddleware(_next);
// Act
await _middleware.InvokeAsync(ctx, _authMock.Object, _loggerMock.Object);
// Assert
Assert.That(nextCalled, Is.True);
Assert.That(ctx.Response.StatusCode, Is.EqualTo(StatusCodes.Status200OK));
}
}
}