From 594b0bb6287cb67e69bd0c7d9eafbf6491ef8d90 Mon Sep 17 00:00:00 2001 From: maliming Date: Fri, 16 Jan 2026 11:36:07 +0800 Subject: [PATCH] Add tests for shared user validation across tenants --- .../AbpIdentityUserValidator_Tests.cs | 118 +++++++++++++++++- 1 file changed, 117 insertions(+), 1 deletion(-) diff --git a/modules/identity/test/Volo.Abp.Identity.AspNetCore.Tests/Volo/Abp/Identity/AspNetCore/AbpIdentityUserValidator_Tests.cs b/modules/identity/test/Volo.Abp.Identity.AspNetCore.Tests/Volo/Abp/Identity/AspNetCore/AbpIdentityUserValidator_Tests.cs index 38f0aaa9a3..752bc3496a 100644 --- a/modules/identity/test/Volo.Abp.Identity.AspNetCore.Tests/Volo/Abp/Identity/AspNetCore/AbpIdentityUserValidator_Tests.cs +++ b/modules/identity/test/Volo.Abp.Identity.AspNetCore.Tests/Volo/Abp/Identity/AspNetCore/AbpIdentityUserValidator_Tests.cs @@ -64,7 +64,7 @@ public class AbpIdentityUserValidator_Tests : AbpIdentityAspNetCoreTestBase } } -public class SharedTenantUserSharingStrategy_AbpIdentityUserValidator_Tests : AbpIdentityUserValidator_Tests +public class AbpIdentityUserValidator_SharedUser_Compatible_Tests : AbpIdentityUserValidator_Tests { protected override void ConfigureServices(HostBuilderContext context, IServiceCollection services) { @@ -75,3 +75,119 @@ public class SharedTenantUserSharingStrategy_AbpIdentityUserValidator_Tests : Ab }); } } + +public class AbpIdentityUserValidator_SharedUser_Tests : AbpIdentityAspNetCoreTestBase +{ + private readonly IdentityUserManager _identityUserManager; + private readonly ICurrentTenant _currentTenant; + + public AbpIdentityUserValidator_SharedUser_Tests() + { + _identityUserManager = GetRequiredService(); + _currentTenant = GetRequiredService(); + } + + protected override void ConfigureServices(HostBuilderContext context, IServiceCollection services) + { + services.Configure(options => + { + options.IsEnabled = true; + options.UserSharingStrategy = TenantUserSharingStrategy.Shared; + }); + } + + [Fact] + public async Task Should_Reject_Duplicate_UserName_Across_Tenants() + { + var tenant1Id = Guid.NewGuid(); + var tenant2Id = Guid.NewGuid(); + + using (_currentTenant.Change(tenant1Id)) + { + var user1 = new IdentityUser(Guid.NewGuid(), "shared-user", "shared-user-1@volosoft.com"); + (await _identityUserManager.CreateAsync(user1)).Succeeded.ShouldBeTrue(); + } + + using (_currentTenant.Change(tenant2Id)) + { + var user2 = new IdentityUser(Guid.NewGuid(), "shared-user", "shared-user-2@volosoft.com"); + var result = await _identityUserManager.CreateAsync(user2); + + result.Succeeded.ShouldBeFalse(); + result.Errors.Count().ShouldBe(1); + result.Errors.First().Code.ShouldBe("DuplicateUserName"); + } + } + + [Fact] + public async Task Should_Reject_Duplicate_Email_Across_Tenants() + { + var tenant1Id = Guid.NewGuid(); + var tenant2Id = Guid.NewGuid(); + const string sharedEmail = "shared-email@volosoft.com"; + + using (_currentTenant.Change(tenant1Id)) + { + var user1 = new IdentityUser(Guid.NewGuid(), "shared-email-user-1", sharedEmail); + (await _identityUserManager.CreateAsync(user1)).Succeeded.ShouldBeTrue(); + } + + using (_currentTenant.Change(tenant2Id)) + { + var user2 = new IdentityUser(Guid.NewGuid(), "shared-email-user-2", sharedEmail); + var result = await _identityUserManager.CreateAsync(user2); + + result.Succeeded.ShouldBeFalse(); + result.Errors.Count().ShouldBe(1); + result.Errors.First().Code.ShouldBe("DuplicateEmail"); + } + } + + [Fact] + public async Task Should_Reject_UserName_That_Matches_Another_Users_Email_Across_Tenants() + { + var tenant1Id = Guid.NewGuid(); + var tenant2Id = Guid.NewGuid(); + const string sharedValue = "conflict@volosoft.com"; + + using (_currentTenant.Change(tenant1Id)) + { + var user1 = new IdentityUser(Guid.NewGuid(), "unique-user", sharedValue); + (await _identityUserManager.CreateAsync(user1)).Succeeded.ShouldBeTrue(); + } + + using (_currentTenant.Change(tenant2Id)) + { + var user2 = new IdentityUser(Guid.NewGuid(), sharedValue, "another@volosoft.com"); + var result = await _identityUserManager.CreateAsync(user2); + + result.Succeeded.ShouldBeFalse(); + result.Errors.Count().ShouldBe(1); + result.Errors.First().Code.ShouldBe("InvalidUserName"); + } + } + + [Fact] + public async Task Should_Reject_Email_That_Matches_Another_Users_UserName_Across_Tenants() + { + var tenant1Id = Guid.NewGuid(); + var tenant2Id = Guid.NewGuid(); + const string sharedValue = "conflict-user"; + + using (_currentTenant.Change(tenant1Id)) + { + var user1 = new IdentityUser(Guid.NewGuid(), sharedValue, "conflict-user-1@volosoft.com"); + (await _identityUserManager.CreateAsync(user1)).Succeeded.ShouldBeTrue(); + } + + using (_currentTenant.Change(tenant2Id)) + { + var user2 = new IdentityUser(Guid.NewGuid(), "another-user", sharedValue); + var result = await _identityUserManager.CreateAsync(user2); + + result.Succeeded.ShouldBeFalse(); + result.Errors.Count().ShouldBe(1); + result.Errors.First().Code.ShouldBe("InvalidEmail"); + } + } +}