Files
tiku-backend.net/Tiku.UnitTests/Bootstrap/PlatformAdminBootstrapperTests.cs

146 lines
6.7 KiB
C#

using Microsoft.AspNetCore.Identity;
using Microsoft.AspNetCore.DataProtection;
using Microsoft.EntityFrameworkCore;
using Microsoft.Extensions.DependencyInjection;
using Tiku.Application.Security;
using Tiku.Domain.Identity;
using Tiku.Infrastructure.Bootstrap;
using Tiku.Infrastructure.Auth;
using Tiku.Infrastructure.Persistence;
namespace Tiku.UnitTests.Bootstrap;
public sealed class PlatformAdminBootstrapperTests
{
private const string TemporaryPassword = "Temporary9Password";
[Fact]
public async Task Bootstrap_creates_forced_enrollment_super_admin_and_audit()
{
await using var provider = CreateProvider();
await using var scope = provider.CreateAsyncScope();
var bootstrapper = ActivatorUtilities.CreateInstance<PlatformAdminBootstrapper>(scope.ServiceProvider);
var result = await bootstrapper.BootstrapAsync(new PlatformAdminBootstrapOptions(
"admin@example.com",
TemporaryPassword,
"Initial Administrator"));
var context = scope.ServiceProvider.GetRequiredService<TikuDbContext>();
var user = await context.Users.SingleAsync(item => item.Id == result.UserId);
Assert.True(user.ForcePasswordChange);
Assert.True(user.EmailConfirmed);
Assert.Equal(UserStatus.Active, user.Status);
var role = await context.PlatformBackendRoles.SingleAsync(item => item.Id == result.RoleId);
Assert.Equal(PlatformAdminBootstrapper.SuperAdminRoleCode, role.Code);
Assert.True(role.IsSystem);
Assert.Equal(BackendPermissions.Platform.Count, await context.PlatformBackendRolePermissions.CountAsync());
Assert.True(await context.PlatformBackendUserRoles.AnyAsync(item => item.UserId == user.Id && item.RoleId == role.Id));
Assert.True(await context.AuditLogs.AnyAsync(item =>
item.ActorUserId == user.Id && item.Action == "platform.bootstrap_admin.created"));
var userManager = scope.ServiceProvider.GetRequiredService<UserManager<User>>();
Assert.True(await userManager.CheckPasswordAsync(user, TemporaryPassword));
}
[Fact]
public async Task Bootstrap_rejects_a_second_platform_administrator_without_mutating_data()
{
await using var provider = CreateProvider();
await using var scope = provider.CreateAsyncScope();
var bootstrapper = ActivatorUtilities.CreateInstance<PlatformAdminBootstrapper>(scope.ServiceProvider);
await bootstrapper.BootstrapAsync(new PlatformAdminBootstrapOptions("first@example.com", TemporaryPassword));
var exception = await Assert.ThrowsAsync<PlatformAdminBootstrapException>(() =>
bootstrapper.BootstrapAsync(new PlatformAdminBootstrapOptions("second@example.com", TemporaryPassword)));
Assert.Equal("platform_admin_already_exists", exception.Code);
var context = scope.ServiceProvider.GetRequiredService<TikuDbContext>();
Assert.Single(context.PlatformBackendUserRoles);
Assert.Single(context.PlatformBackendRoles);
Assert.Single(context.AuditLogs);
Assert.Single(context.Users);
}
[Fact]
public async Task Bootstrap_rejects_an_existing_user_email()
{
await using var provider = CreateProvider();
await using var scope = provider.CreateAsyncScope();
var userManager = scope.ServiceProvider.GetRequiredService<UserManager<User>>();
var createResult = await userManager.CreateAsync(new User
{
Email = "existing@example.com",
UserName = "existing@example.com"
}, TemporaryPassword);
Assert.True(createResult.Succeeded);
var bootstrapper = ActivatorUtilities.CreateInstance<PlatformAdminBootstrapper>(scope.ServiceProvider);
var exception = await Assert.ThrowsAsync<PlatformAdminBootstrapException>(() =>
bootstrapper.BootstrapAsync(new PlatformAdminBootstrapOptions("existing@example.com", TemporaryPassword)));
Assert.Equal("bootstrap_user_already_exists", exception.Code);
}
[Fact]
public async Task Development_async_seed_creates_one_forced_enrollment_administrator()
{
await using var provider = CreateProvider();
await using var scope = provider.CreateAsyncScope();
var context = scope.ServiceProvider.GetRequiredService<TikuDbContext>();
var created = await DevelopmentPlatformAdminSeeder.SeedAsync(context);
var createdAgain = await DevelopmentPlatformAdminSeeder.SeedAsync(context);
Assert.True(created);
Assert.False(createdAgain);
var user = await context.Users.SingleAsync();
Assert.Equal(DevelopmentPlatformAdminSeeder.Email, user.Email);
Assert.True(user.ForcePasswordChange);
Assert.Equal(BackendPermissions.Platform.Count, await context.PlatformBackendRolePermissions.CountAsync());
Assert.Single(context.PlatformBackendUserRoles);
Assert.Single(context.AuditLogs);
var quote = await context.PlatformBillingQuotes.SingleAsync();
Assert.Equal(quote.OriginalAmountCents - quote.DiscountAmountCents, quote.TotalAmountCents);
var order = await context.PlatformBillingOrders.SingleAsync();
Assert.Equal(order.OriginalAmountCents - order.DiscountAmountCents, order.TotalAmountCents);
}
[Fact]
public async Task Development_sync_seed_is_idempotent()
{
await using var provider = CreateProvider();
await using var scope = provider.CreateAsyncScope();
var context = scope.ServiceProvider.GetRequiredService<TikuDbContext>();
var created = DevelopmentPlatformAdminSeeder.Seed(context);
var createdAgain = DevelopmentPlatformAdminSeeder.Seed(context);
Assert.True(created);
Assert.False(createdAgain);
Assert.Single(context.Users);
Assert.Single(context.PlatformBackendUserRoles);
}
private static ServiceProvider CreateProvider()
{
var services = new ServiceCollection();
services.AddLogging();
services.AddDbContext<TikuDbContext>(options =>
options.UseInMemoryDatabase(Guid.NewGuid().ToString()));
services.AddIdentityCore<User>(options =>
{
options.Password.RequiredLength = 8;
options.Password.RequireDigit = false;
options.Password.RequireLowercase = false;
options.Password.RequireUppercase = false;
options.Password.RequireNonAlphanumeric = false;
})
.AddEntityFrameworkStores<TikuDbContext>()
.AddDefaultTokenProviders()
.AddPasswordValidator<LetterAndDigitPasswordValidator<User>>();
services.AddDataProtection().UseEphemeralDataProtectionProvider();
return services.BuildServiceProvider();
}
}