Remove duplicate source files from old ApiKeys/, Authentication/, and Authorization/ folders that were already migrated to Common/Security/. Update test namespace usings to match. Pin EFC Relational 10.0.5 to resolve MSB3277 version conflict with Npgsql's transitive dependency. Add LangVersion and TreatWarningsAsErrors to AppHost and ServiceDefaults.
104 lines
3.1 KiB
C#
Executable File
104 lines
3.1 KiB
C#
Executable File
using System.IdentityModel.Tokens.Jwt;
|
|
using MicCheck.Api.Common.Security.Authorization;
|
|
using MicCheck.Api.Organizations;
|
|
using MicCheck.Api.Users;
|
|
using Microsoft.Extensions.Configuration;
|
|
using NUnit.Framework;
|
|
|
|
namespace MicCheck.Api.Tests.Unit.Authorization;
|
|
|
|
[TestFixture]
|
|
public class TokenServiceTests
|
|
{
|
|
private IConfiguration _configuration = null!;
|
|
private TokenService _tokenService = null!;
|
|
|
|
[SetUp]
|
|
public void SetUp()
|
|
{
|
|
_configuration = new ConfigurationBuilder()
|
|
.AddInMemoryCollection(new Dictionary<string, string?>
|
|
{
|
|
["Jwt:SecretKey"] = "test-secret-key-that-is-long-enough-32c",
|
|
["Jwt:Issuer"] = "MicCheck",
|
|
["Jwt:Audience"] = "MicCheck",
|
|
["Jwt:ExpiryMinutes"] = "60",
|
|
})
|
|
.Build();
|
|
|
|
_tokenService = new TokenService(_configuration);
|
|
}
|
|
|
|
private static User BuildUser(int id = 1, string email = "alice@example.com") =>
|
|
new()
|
|
{
|
|
Email = email,
|
|
FirstName = "Alice",
|
|
LastName = "Smith",
|
|
PasswordHash = "hashed",
|
|
IsActive = true,
|
|
CreatedAt = DateTimeOffset.UtcNow
|
|
};
|
|
|
|
[Test]
|
|
public void WhenAUserIsProvided_ThenATokenIsReturned()
|
|
{
|
|
var result = _tokenService.GenerateToken(BuildUser());
|
|
|
|
Assert.That(result.Token, Is.Not.Null.And.Not.Empty);
|
|
}
|
|
|
|
[Test]
|
|
public void WhenATokenIsGenerated_ThenItContainsTheUserEmailClaim()
|
|
{
|
|
var user = BuildUser(email: "bob@example.com");
|
|
|
|
var result = _tokenService.GenerateToken(user);
|
|
|
|
var handler = new JwtSecurityTokenHandler();
|
|
var jwt = handler.ReadJwtToken(result.Token);
|
|
|
|
Assert.That(jwt.Claims.Any(c => c.Type == JwtRegisteredClaimNames.Email && c.Value == "bob@example.com"),
|
|
Is.True);
|
|
}
|
|
|
|
[Test]
|
|
public void WhenATokenIsGenerated_ThenItHasAFutureExpiry()
|
|
{
|
|
var result = _tokenService.GenerateToken(BuildUser());
|
|
|
|
Assert.That(result.ExpiresAt, Is.GreaterThan(DateTime.UtcNow));
|
|
}
|
|
|
|
[Test]
|
|
public void WhenATokenIsGenerated_ThenItHasTheConfiguredIssuer()
|
|
{
|
|
var result = _tokenService.GenerateToken(BuildUser());
|
|
|
|
var handler = new JwtSecurityTokenHandler();
|
|
var jwt = handler.ReadJwtToken(result.Token);
|
|
|
|
Assert.That(jwt.Issuer, Is.EqualTo("MicCheck"));
|
|
}
|
|
|
|
[Test]
|
|
public void WhenUserBelongsToOrganizations_ThenTokenContainsOrganizationClaims()
|
|
{
|
|
var user = BuildUser();
|
|
user.Organizations.Add(new OrganizationUser
|
|
{
|
|
OrganizationId = 42,
|
|
UserId = user.Id,
|
|
Role = OrganizationRole.Admin
|
|
});
|
|
|
|
var result = _tokenService.GenerateToken(user);
|
|
|
|
var handler = new JwtSecurityTokenHandler();
|
|
var jwt = handler.ReadJwtToken(result.Token);
|
|
|
|
Assert.That(jwt.Claims.Any(c => c.Type == "OrganizationId" && c.Value == "42"), Is.True);
|
|
Assert.That(jwt.Claims.Any(c => c.Type == "OrganizationRole" && c.Value == "Admin"), Is.True);
|
|
}
|
|
}
|