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.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(scope.ServiceProvider); var result = await bootstrapper.BootstrapAsync(new PlatformAdminBootstrapOptions( "admin@example.com", TemporaryPassword, "Initial Administrator")); var context = scope.ServiceProvider.GetRequiredService(); var user = await context.Users.SingleAsync(item => item.Id == result.UserId); Assert.True(user.ForcePasswordChange); Assert.False(user.TwoFactorEnabled); 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>(); 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(scope.ServiceProvider); await bootstrapper.BootstrapAsync(new PlatformAdminBootstrapOptions("first@example.com", TemporaryPassword)); var exception = await Assert.ThrowsAsync(() => bootstrapper.BootstrapAsync(new PlatformAdminBootstrapOptions("second@example.com", TemporaryPassword))); Assert.Equal("platform_admin_already_exists", exception.Code); var context = scope.ServiceProvider.GetRequiredService(); 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>(); var createResult = await userManager.CreateAsync(new User { Email = "existing@example.com", UserName = "existing@example.com" }, TemporaryPassword); Assert.True(createResult.Succeeded); var bootstrapper = ActivatorUtilities.CreateInstance(scope.ServiceProvider); var exception = await Assert.ThrowsAsync(() => bootstrapper.BootstrapAsync(new PlatformAdminBootstrapOptions("existing@example.com", TemporaryPassword))); Assert.Equal("bootstrap_user_already_exists", exception.Code); } private static ServiceProvider CreateProvider() { var services = new ServiceCollection(); services.AddLogging(); services.AddDbContext(options => options.UseInMemoryDatabase(Guid.NewGuid().ToString())); services.AddIdentityCore(options => { options.Password.RequiredLength = 10; options.Password.RequireDigit = true; options.Password.RequireLowercase = true; options.Password.RequireUppercase = false; options.Password.RequireNonAlphanumeric = false; }) .AddEntityFrameworkStores() .AddDefaultTokenProviders(); services.AddDataProtection().UseEphemeralDataProtectionProvider(); return services.BuildServiceProvider(); } }