feat: execute full-repo remaining parity closure plan

This commit is contained in:
Joseph Doherty
2026-02-23 13:08:52 -05:00
parent cbe1fa6121
commit 2b64d762f6
75 changed files with 2325 additions and 121 deletions

View File

@@ -0,0 +1,30 @@
using NATS.Server.Auth;
using NATS.Server.Protocol;
namespace NATS.Server.Tests;
public class AuthExtensionParityTests
{
[Fact]
public void Auth_service_uses_proxy_auth_extension_when_enabled()
{
var service = AuthService.Build(new NatsOptions
{
ProxyAuth = new ProxyAuthOptions
{
Enabled = true,
UsernamePrefix = "proxy:",
},
});
service.IsAuthRequired.ShouldBeTrue();
var result = service.Authenticate(new ClientAuthContext
{
Opts = new ClientOptions { Username = "proxy:alice" },
Nonce = [],
});
result.ShouldNotBeNull();
result.Identity.ShouldBe("alice");
}
}

View File

@@ -0,0 +1,58 @@
using NATS.Server.Auth;
using NATS.Server.Protocol;
namespace NATS.Server.Tests;
public class ExternalAuthCalloutTests
{
[Fact]
public void External_callout_authenticator_can_allow_and_deny_with_timeout_and_reason_mapping()
{
var authenticator = new ExternalAuthCalloutAuthenticator(
new FakeExternalAuthClient(),
TimeSpan.FromMilliseconds(50));
var allowed = authenticator.Authenticate(new ClientAuthContext
{
Opts = new ClientOptions { Username = "u", Password = "p" },
Nonce = [],
});
allowed.ShouldNotBeNull();
allowed.Identity.ShouldBe("u");
var denied = authenticator.Authenticate(new ClientAuthContext
{
Opts = new ClientOptions { Username = "u", Password = "bad" },
Nonce = [],
});
denied.ShouldBeNull();
var timeout = new ExternalAuthCalloutAuthenticator(
new SlowExternalAuthClient(TimeSpan.FromMilliseconds(200)),
TimeSpan.FromMilliseconds(30));
timeout.Authenticate(new ClientAuthContext
{
Opts = new ClientOptions { Username = "u", Password = "p" },
Nonce = [],
}).ShouldBeNull();
}
private sealed class FakeExternalAuthClient : IExternalAuthClient
{
public Task<ExternalAuthDecision> AuthorizeAsync(ExternalAuthRequest request, CancellationToken ct)
{
if (request is { Username: "u", Password: "p" })
return Task.FromResult(new ExternalAuthDecision(true, "u", "A"));
return Task.FromResult(new ExternalAuthDecision(false, Reason: "denied"));
}
}
private sealed class SlowExternalAuthClient(TimeSpan delay) : IExternalAuthClient
{
public async Task<ExternalAuthDecision> AuthorizeAsync(ExternalAuthRequest request, CancellationToken ct)
{
await Task.Delay(delay, ct);
return new ExternalAuthDecision(true, "slow");
}
}
}

View File

@@ -0,0 +1,28 @@
using NATS.Server.Auth;
using NATS.Server.Protocol;
namespace NATS.Server.Tests;
public class ProxyAuthTests
{
[Fact]
public void Proxy_authenticator_maps_prefixed_username_to_identity()
{
var authenticator = new ProxyAuthenticator(new ProxyAuthOptions
{
Enabled = true,
UsernamePrefix = "proxy:",
Account = "A",
});
var result = authenticator.Authenticate(new ClientAuthContext
{
Opts = new ClientOptions { Username = "proxy:bob" },
Nonce = [],
});
result.ShouldNotBeNull();
result.Identity.ShouldBe("bob");
result.AccountName.ShouldBe("A");
}
}