using System.IdentityModel.Tokens.Jwt; using System.Security.Claims; using System.Text; using FluentAssertions; using Microsoft.IdentityModel.Tokens; using SatelliteProvider.Tests.TestUtilities; namespace SatelliteProvider.Tests.Authentication; public class JwtTokenFactoryTests { private const string Secret = "factory-secret-that-is-longer-than-thirty-two-bytes-bytes"; [Fact] public void Create_ProducesTokenValidatedByMatchingParameters() { // Arrange — disable inbound claim remapping so the test asserts // the factory's actual output ("sub", "email", ...) rather than // the framework's ClaimTypes.* aliases. var token = JwtTokenFactory.Create(Secret, subject: "alice"); var parameters = BuildParameters(Secret); var handler = new JwtSecurityTokenHandler { MapInboundClaims = false }; // Act var principal = handler.ValidateToken(token, parameters, out var validatedToken); // Assert principal.Identity!.IsAuthenticated.Should().BeTrue(); principal.FindFirst(JwtRegisteredClaimNames.Sub)!.Value.Should().Be("alice"); validatedToken.Should().BeOfType(); } [Fact] public void Create_WithExtraClaims_PropagatesClaimsThroughValidation() { // Arrange var claims = new[] { new Claim("email", "alice@example.com"), new Claim("role", "operator"), new Claim("permissions", "GPS"), new Claim("permissions", "FL") }; var token = JwtTokenFactory.Create(Secret, extraClaims: claims); var handler = new JwtSecurityTokenHandler { MapInboundClaims = false }; // Act var principal = handler.ValidateToken(token, BuildParameters(Secret), out _); // Assert principal.FindAll("permissions").Select(c => c.Value).Should().BeEquivalentTo(new[] { "GPS", "FL" }); principal.FindFirst("email")!.Value.Should().Be("alice@example.com"); } [Fact] public void CreateExpired_TokenFailsValidationWithLifetimeException() { // Arrange var token = JwtTokenFactory.CreateExpired(Secret); var handler = new JwtSecurityTokenHandler(); // Act var act = () => handler.ValidateToken(token, BuildParameters(Secret), out _); // Assert act.Should().Throw(); } [Fact] public void TamperSignature_TokenFailsValidationWithSignatureException() { // Arrange var token = JwtTokenFactory.Create(Secret); var tampered = JwtTokenFactory.TamperSignature(token); var handler = new JwtSecurityTokenHandler(); // Act var act = () => handler.ValidateToken(tampered, BuildParameters(Secret), out _); // Assert act.Should().Throw(); } private static TokenValidationParameters BuildParameters(string secret) => new() { ValidateIssuerSigningKey = true, IssuerSigningKey = new SymmetricSecurityKey(Encoding.UTF8.GetBytes(secret)), ValidateLifetime = true, ClockSkew = TimeSpan.FromSeconds(30), ValidateIssuer = false, ValidateAudience = false, RequireSignedTokens = true, RequireExpirationTime = true }; }