fix(app): harden account and workflow state
This commit is contained in:
@@ -57,6 +57,51 @@ public sealed class UsersControllerTests
|
||||
users.Verify(x => x.RemoveFromRolesAsync(admin, It.IsAny<IEnumerable<string>>()), Times.Once);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public async Task SetRoles_revokes_existing_sessions_and_trusted_devices_when_roles_change()
|
||||
{
|
||||
await using var connection = new SqliteConnection("Data Source=:memory:");
|
||||
await connection.OpenAsync();
|
||||
var currentUser = new Mock<ICurrentUserService>();
|
||||
currentUser.SetupGet(service => service.UserId).Returns("admin-1");
|
||||
var options = new DbContextOptionsBuilder<JobTrackerContext>()
|
||||
.UseSqlite(connection)
|
||||
.Options;
|
||||
await using var db = new JobTrackerContext(options, currentUser.Object);
|
||||
await db.Database.EnsureCreatedAsync();
|
||||
|
||||
var member = User("user-1");
|
||||
db.Users.Add(member);
|
||||
db.UserSessions.Add(new UserSession
|
||||
{
|
||||
Id = "member-session",
|
||||
UserId = member.Id,
|
||||
CreatedAtUtc = DateTimeOffset.UtcNow,
|
||||
LastSeenAtUtc = DateTimeOffset.UtcNow,
|
||||
ExpiresAtUtc = DateTimeOffset.UtcNow.AddDays(1)
|
||||
});
|
||||
db.TrustedDevices.Add(new TrustedDevice
|
||||
{
|
||||
UserId = member.Id,
|
||||
TokenHash = "device-hash",
|
||||
CreatedAtUtc = DateTimeOffset.UtcNow,
|
||||
ExpiresAtUtc = DateTimeOffset.UtcNow.AddDays(30)
|
||||
});
|
||||
await db.SaveChangesAsync();
|
||||
|
||||
var users = TestHostFactory.CreateUserManager(member);
|
||||
users.Setup(x => x.GetRolesAsync(member)).ReturnsAsync([]);
|
||||
users.Setup(x => x.AddToRoleAsync(member, "Admin")).ReturnsAsync(IdentityResult.Success);
|
||||
var controller = CreateController(users, "admin-1", db);
|
||||
|
||||
var result = await controller.SetRoles(member.Id, new UsersController.SetRolesRequest(["Admin"]), CancellationToken.None);
|
||||
|
||||
Assert.IsType<NoContentResult>(result);
|
||||
var session = await db.UserSessions.IgnoreQueryFilters().SingleAsync(x => x.Id == "member-session");
|
||||
Assert.NotNull(session.RevokedAtUtc);
|
||||
Assert.Empty(await db.TrustedDevices.IgnoreQueryFilters().Where(x => x.UserId == member.Id).ToListAsync());
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public async Task Delete_rejects_deleting_the_final_administrator()
|
||||
{
|
||||
@@ -159,6 +204,7 @@ public sealed class UsersControllerTests
|
||||
new UpperInvariantLookupNormalizer(),
|
||||
new IdentityErrorDescriber(),
|
||||
new NullLogger<RoleManager<IdentityRole>>());
|
||||
roles.Setup(manager => manager.RoleExistsAsync(It.IsAny<string>())).ReturnsAsync(true);
|
||||
|
||||
var controller = new UsersController(
|
||||
users.Object,
|
||||
|
||||
Reference in New Issue
Block a user