test(infra): add GetPrincipalFromExpiredToken tests for JwtService RED
This commit is contained in:
@@ -122,6 +122,65 @@ public class JwtServiceTests : IDisposable
|
|||||||
Assert.Equal("2", parsed2.Subject);
|
Assert.Equal("2", parsed2.Subject);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// T-040: GetPrincipalFromExpiredToken
|
||||||
|
|
||||||
|
[Fact]
|
||||||
|
public void GetPrincipalFromExpiredToken_ValidSignatureExpired_ReturnsPrincipal()
|
||||||
|
{
|
||||||
|
// Generate a token that will expire in 1 second, then manually create an expired JWT
|
||||||
|
// using JwtSecurityTokenHandler directly (bypassing the service to control timestamps).
|
||||||
|
var signingKey = new RsaSecurityKey(_rsa);
|
||||||
|
var credentials = new SigningCredentials(signingKey, SecurityAlgorithms.RsaSha256);
|
||||||
|
|
||||||
|
var past = DateTime.UtcNow.AddHours(-2);
|
||||||
|
var descriptor = new SecurityTokenDescriptor
|
||||||
|
{
|
||||||
|
Subject = new System.Security.Claims.ClaimsIdentity(
|
||||||
|
[new System.Security.Claims.Claim("sub", "1")]),
|
||||||
|
Issuer = "sigcm2.api",
|
||||||
|
Audience = "sigcm2.web",
|
||||||
|
IssuedAt = past,
|
||||||
|
NotBefore = past,
|
||||||
|
Expires = past.AddMinutes(60), // expired 1h ago
|
||||||
|
SigningCredentials = credentials,
|
||||||
|
};
|
||||||
|
|
||||||
|
var handler = new JwtSecurityTokenHandler();
|
||||||
|
var token = handler.CreateToken(descriptor);
|
||||||
|
var expiredToken = handler.WriteToken(token);
|
||||||
|
|
||||||
|
// Now use the service — it must validate the signature but ignore expiry
|
||||||
|
var principal = _jwtService.GetPrincipalFromExpiredToken(expiredToken);
|
||||||
|
|
||||||
|
Assert.NotNull(principal);
|
||||||
|
// The JWT handler maps "sub" to ClaimTypes.NameIdentifier by default,
|
||||||
|
// but our JwtService uses a custom "sub" claim. Check both.
|
||||||
|
var sub = principal.FindFirst("sub")?.Value
|
||||||
|
?? principal.FindFirst(System.Security.Claims.ClaimTypes.NameIdentifier)?.Value;
|
||||||
|
Assert.Equal("1", sub);
|
||||||
|
}
|
||||||
|
|
||||||
|
[Fact]
|
||||||
|
public void GetPrincipalFromExpiredToken_InvalidSignature_Throws()
|
||||||
|
{
|
||||||
|
// Sign with a different RSA key
|
||||||
|
using var otherRsa = System.Security.Cryptography.RSA.Create(2048);
|
||||||
|
var otherOptions = new JwtOptions { Issuer = "sigcm2.api", Audience = "sigcm2.web", AccessTokenMinutes = 60 };
|
||||||
|
var otherService = new JwtService(otherRsa, otherOptions);
|
||||||
|
var tokenFromOtherKey = otherService.GenerateAccessToken(MakeUsuario());
|
||||||
|
|
||||||
|
// Validating with the correct key should throw
|
||||||
|
Assert.Throws<Microsoft.IdentityModel.Tokens.SecurityTokenSignatureKeyNotFoundException>(
|
||||||
|
() => _jwtService.GetPrincipalFromExpiredToken(tokenFromOtherKey));
|
||||||
|
}
|
||||||
|
|
||||||
|
[Fact]
|
||||||
|
public void GetPrincipalFromExpiredToken_MalformedToken_Throws()
|
||||||
|
{
|
||||||
|
Assert.ThrowsAny<Exception>(
|
||||||
|
() => _jwtService.GetPrincipalFromExpiredToken("not.a.valid.jwt"));
|
||||||
|
}
|
||||||
|
|
||||||
private static Usuario MakeUsuario(int id = 1, string username = "admin")
|
private static Usuario MakeUsuario(int id = 1, string username = "admin")
|
||||||
=> new(id, username, "$2a$12$hash", "Administrador", "Sistema", null, "admin", "[\"*\"]", true);
|
=> new(id, username, "$2a$12$hash", "Administrador", "Sistema", null, "admin", "[\"*\"]", true);
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user