Move 50 auth/accounts/permissions/JWT/NKey test files from NATS.Server.Tests into a dedicated NATS.Server.Auth.Tests project. Update namespaces, replace private GetFreePort/ReadUntilAsync helpers with TestUtilities calls, replace Task.Delay with TaskCompletionSource in test doubles, and add InternalsVisibleTo. 690 tests pass.
166 lines
6.9 KiB
C#
166 lines
6.9 KiB
C#
// Tests for user NKey revocation on Account.
|
|
// Go reference: accounts_test.go TestJWTUserRevocation, checkUserRevoked (~line 3202),
|
|
// isRevoked with jwt.All global key (~line 2929).
|
|
|
|
using NATS.Server.Auth;
|
|
|
|
namespace NATS.Server.Auth.Tests.Auth;
|
|
|
|
public class NKeyRevocationTests
|
|
{
|
|
// ── 1 ──────────────────────────────────────────────────────────────────────
|
|
[Fact]
|
|
public void RevokeUser_AddsToRevokedList()
|
|
{
|
|
var account = new Account("A");
|
|
|
|
account.RevokeUser("UNKEY1", 100L);
|
|
|
|
account.RevokedUserCount.ShouldBe(1);
|
|
}
|
|
|
|
// ── 2 ──────────────────────────────────────────────────────────────────────
|
|
[Fact]
|
|
public void IsUserRevoked_Revoked_ReturnsTrue()
|
|
{
|
|
// A JWT issued at t=50 revoked when the revocation timestamp is 100
|
|
// means issuedAt (50) <= revokedAt (100) → revoked.
|
|
// Go reference: accounts.go isRevoked — t < issuedAt ⇒ NOT revoked (inverted).
|
|
var account = new Account("A");
|
|
account.RevokeUser("UNKEY1", 100L);
|
|
|
|
account.IsUserRevoked("UNKEY1", 50L).ShouldBeTrue();
|
|
}
|
|
|
|
// ── 3 ──────────────────────────────────────────────────────────────────────
|
|
[Fact]
|
|
public void IsUserRevoked_NotRevoked_ReturnsFalse()
|
|
{
|
|
// A JWT issued at t=200 with revocation timestamp 100 means
|
|
// issuedAt (200) > revokedAt (100) → NOT revoked.
|
|
var account = new Account("A");
|
|
account.RevokeUser("UNKEY1", 100L);
|
|
|
|
account.IsUserRevoked("UNKEY1", 200L).ShouldBeFalse();
|
|
}
|
|
|
|
// ── 4 ──────────────────────────────────────────────────────────────────────
|
|
[Fact]
|
|
public void RevokedUserCount_MatchesRevocations()
|
|
{
|
|
var account = new Account("A");
|
|
|
|
account.RevokedUserCount.ShouldBe(0);
|
|
|
|
account.RevokeUser("UNKEY1", 1L);
|
|
account.RevokedUserCount.ShouldBe(1);
|
|
|
|
account.RevokeUser("UNKEY2", 2L);
|
|
account.RevokedUserCount.ShouldBe(2);
|
|
|
|
// Revoking the same key again does not increase count.
|
|
account.RevokeUser("UNKEY1", 99L);
|
|
account.RevokedUserCount.ShouldBe(2);
|
|
}
|
|
|
|
// ── 5 ──────────────────────────────────────────────────────────────────────
|
|
[Fact]
|
|
public void GetRevokedUsers_ReturnsAllKeys()
|
|
{
|
|
var account = new Account("A");
|
|
account.RevokeUser("UNKEY1", 1L);
|
|
account.RevokeUser("UNKEY2", 2L);
|
|
account.RevokeUser("UNKEY3", 3L);
|
|
|
|
var keys = account.GetRevokedUsers();
|
|
|
|
keys.Count.ShouldBe(3);
|
|
keys.ShouldContain("UNKEY1");
|
|
keys.ShouldContain("UNKEY2");
|
|
keys.ShouldContain("UNKEY3");
|
|
}
|
|
|
|
// ── 6 ──────────────────────────────────────────────────────────────────────
|
|
[Fact]
|
|
public void UnrevokeUser_RemovesRevocation()
|
|
{
|
|
var account = new Account("A");
|
|
account.RevokeUser("UNKEY1", 100L);
|
|
account.RevokedUserCount.ShouldBe(1);
|
|
|
|
var removed = account.UnrevokeUser("UNKEY1");
|
|
|
|
removed.ShouldBeTrue();
|
|
account.RevokedUserCount.ShouldBe(0);
|
|
account.IsUserRevoked("UNKEY1", 50L).ShouldBeFalse();
|
|
}
|
|
|
|
// ── 7 ──────────────────────────────────────────────────────────────────────
|
|
[Fact]
|
|
public void UnrevokeUser_NonExistent_ReturnsFalse()
|
|
{
|
|
var account = new Account("A");
|
|
|
|
var removed = account.UnrevokeUser("DOES_NOT_EXIST");
|
|
|
|
removed.ShouldBeFalse();
|
|
account.RevokedUserCount.ShouldBe(0);
|
|
}
|
|
|
|
// ── 8 ──────────────────────────────────────────────────────────────────────
|
|
[Fact]
|
|
public void ClearAllRevocations_EmptiesList()
|
|
{
|
|
var account = new Account("A");
|
|
account.RevokeUser("UNKEY1", 1L);
|
|
account.RevokeUser("UNKEY2", 2L);
|
|
account.RevokeAllUsers(999L);
|
|
account.RevokedUserCount.ShouldBe(3);
|
|
|
|
account.ClearAllRevocations();
|
|
|
|
account.RevokedUserCount.ShouldBe(0);
|
|
account.GetRevokedUsers().ShouldBeEmpty();
|
|
account.IsGlobalRevocation().ShouldBeFalse();
|
|
}
|
|
|
|
// ── 9 ──────────────────────────────────────────────────────────────────────
|
|
[Fact]
|
|
public void RevokeAllUsers_SetsGlobalRevocation()
|
|
{
|
|
// Go reference: accounts.go — Revocations[jwt.All] used in isRevoked (~line 2934).
|
|
// The "*" key causes any user whose issuedAt <= timestamp to be revoked.
|
|
var account = new Account("A");
|
|
|
|
account.RevokeAllUsers(500L);
|
|
|
|
account.IsGlobalRevocation().ShouldBeTrue();
|
|
// User issued at 500 is revoked (≤ 500).
|
|
account.IsUserRevoked("ANY_USER", 500L).ShouldBeTrue();
|
|
// User issued at 499 is also revoked.
|
|
account.IsUserRevoked("ANY_USER", 499L).ShouldBeTrue();
|
|
// User issued at 501 is NOT revoked (> 500).
|
|
account.IsUserRevoked("ANY_USER", 501L).ShouldBeFalse();
|
|
}
|
|
|
|
// ── 10 ─────────────────────────────────────────────────────────────────────
|
|
[Fact]
|
|
public void GetRevocationInfo_ReturnsComplete()
|
|
{
|
|
var account = new Account("A");
|
|
account.RevokeUser("UNKEY1", 10L);
|
|
account.RevokeUser("UNKEY2", 20L);
|
|
account.RevokeAllUsers(999L);
|
|
|
|
var info = account.GetRevocationInfo();
|
|
|
|
// Two per-user keys + one global "*" key = 3 total.
|
|
info.RevokedCount.ShouldBe(3);
|
|
info.HasGlobalRevocation.ShouldBeTrue();
|
|
info.RevokedNKeys.Count.ShouldBe(3);
|
|
info.RevokedNKeys.ShouldContain("UNKEY1");
|
|
info.RevokedNKeys.ShouldContain("UNKEY2");
|
|
info.RevokedNKeys.ShouldContain("*");
|
|
}
|
|
}
|