Browse Source

Do not validate the user while deleting it

pull/25945/head
maliming 4 days ago
parent
commit
dd396d1c8e
No known key found for this signature in database GPG Key ID: A646B9CB645ECEA4
  1. 7
      modules/identity/src/Volo.Abp.Identity.Domain/Volo/Abp/Identity/IdentityUserManager.cs
  2. 144
      modules/identity/test/Volo.Abp.Identity.TestBase/Volo/Abp/Identity/IdentityUserManager_Delete_Tests.cs

7
modules/identity/src/Volo.Abp.Identity.Domain/Volo/Abp/Identity/IdentityUserManager.cs

@ -115,15 +115,14 @@ public class IdentityUserManager : UserManager<IdentityUser>, IDomainService
user.PasswordHistories.Clear();
user.Passkeys.Clear();
//UserDeletedEventHandler deletes them after the changes are saved, this keeps
//them gone for the rest of the current unit of work. They are in the host database.
//They are in the host database and deleting them here covers the current unit of work.
using (CurrentTenant.Change(null))
{
await IdentityLinkUserRepository.DeleteAsync(new IdentityLinkUserInfo(user.Id, user.TenantId), CancellationToken);
}
//Soft deleting an entity reloads its original values.
(await UpdateAsync(user)).CheckErrors();
//Soft deleting reloads the original values, the store saves the changes without validating the user.
(await Store.UpdateAsync(user, CancellationToken)).CheckErrors();
return await base.DeleteAsync(user);
}

144
modules/identity/test/Volo.Abp.Identity.TestBase/Volo/Abp/Identity/IdentityUserManager_Delete_Tests.cs

@ -4,7 +4,11 @@ using System.Threading.Tasks;
using Microsoft.AspNetCore.Identity;
using Shouldly;
using Volo.Abp.Data;
using Volo.Abp.Domain.Entities;
using Volo.Abp.Caching;
using Volo.Abp.Modularity;
using Volo.Abp.MultiTenancy;
using Volo.Abp.Security.Claims;
using Volo.Abp.Uow;
using Xunit;
@ -22,9 +26,13 @@ public abstract class IdentityUserManager_Delete_Tests<TStartupModule> : AbpIden
protected ILookupNormalizer LookupNormalizer { get; }
protected IUnitOfWorkManager UnitOfWorkManager { get; }
protected IDataFilter DataFilter { get; }
protected ICurrentTenant CurrentTenant { get; }
protected IDistributedCache<AbpDynamicClaimCacheItem> DynamicClaimCache { get; }
protected IdentityUserManager_Delete_Tests()
{
CurrentTenant = GetRequiredService<ICurrentTenant>();
DynamicClaimCache = GetRequiredService<IDistributedCache<AbpDynamicClaimCacheItem>>();
IdentityUserManager = GetRequiredService<IdentityUserManager>();
IdentityUserRepository = GetRequiredService<IIdentityUserRepository>();
OrganizationUnitRepository = GetRequiredService<IOrganizationUnitRepository>();
@ -214,4 +222,140 @@ public abstract class IdentityUserManager_Delete_Tests<TStartupModule> : AbpIden
await uow.CompleteAsync();
}
}
[Fact]
public virtual async Task Should_Delete_A_User_That_Does_Not_Pass_The_User_Validators()
{
var userId = Guid.NewGuid();
//Insert with the repository, so the user name is not validated.
using (var uow = UnitOfWorkManager.Begin())
{
var user = new IdentityUser(userId, $"invalid user name {userId:N}", $"invalid-{userId:N}@abp.io");
user.AddPasswordHistory("test");
await IdentityUserRepository.InsertAsync(user);
await uow.CompleteAsync();
}
using (var uow = UnitOfWorkManager.Begin())
{
(await IdentityUserManager.DeleteAsync(await IdentityUserRepository.GetAsync(userId))).CheckErrors();
await uow.CompleteAsync();
}
using (var uow = UnitOfWorkManager.Begin())
using (DataFilter.Disable<ISoftDelete>())
{
var deletedUser = await IdentityUserRepository.FindAsync(userId);
deletedUser.IsDeleted.ShouldBeTrue();
deletedUser.PasswordHistories.Count.ShouldBe(0);
await uow.CompleteAsync();
}
}
[Fact]
public virtual async Task Should_Remove_The_Related_Data_Of_A_Tenant_User_When_The_Unit_Of_Work_Completes_In_The_Host()
{
var tenantId = Guid.NewGuid();
var userId = Guid.NewGuid();
using (var uow = UnitOfWorkManager.Begin())
using (CurrentTenant.Change(tenantId))
{
await IdentityUserRepository.InsertAsync(
new IdentityUser(userId, $"tenant-{userId:N}", $"tenant-{userId:N}@abp.io", tenantId));
await IdentitySessionRepository.InsertAsync(new IdentitySession(
Guid.NewGuid(), $"tenant-session-{userId:N}", "Web", "Chrome", userId, tenantId, "MyApp", "127.0.0.1", DateTime.UtcNow));
await IdentityUserDelegationRepository.InsertAsync(new IdentityUserDelegation(
Guid.NewGuid(), userId, Guid.NewGuid(), DateTime.UtcNow, DateTime.UtcNow.AddDays(1), tenantId));
await uow.CompleteAsync();
}
//The event is published while the unit of work completes, the current tenant is the host then.
using (var uow = UnitOfWorkManager.Begin())
{
using (CurrentTenant.Change(tenantId))
{
await IdentityUserRepository.DeleteAsync(await IdentityUserRepository.GetAsync(userId));
}
await uow.CompleteAsync();
}
using (var uow = UnitOfWorkManager.Begin())
using (CurrentTenant.Change(tenantId))
{
(await IdentitySessionRepository.GetCountAsync(userId: userId)).ShouldBe(0);
(await IdentityUserDelegationRepository.GetListAsync(sourceUserId: userId, targetUserId: null)).ShouldBeEmpty();
await uow.CompleteAsync();
}
}
[Fact]
public virtual async Task Should_Remove_The_Dynamic_Claims_Cache_Of_A_Deleted_User()
{
var userId = Guid.NewGuid();
var cacheKey = AbpDynamicClaimCacheItem.CalculateCacheKey(userId, null);
using (var uow = UnitOfWorkManager.Begin())
{
(await IdentityUserManager.CreateAsync(
new IdentityUser(userId, $"claims-cache-{userId:N}", $"claims-cache-{userId:N}@abp.io"))).CheckErrors();
await uow.CompleteAsync();
}
await DynamicClaimCache.SetAsync(cacheKey, new AbpDynamicClaimCacheItem());
(await DynamicClaimCache.GetAsync(cacheKey)).ShouldNotBeNull();
using (var uow = UnitOfWorkManager.Begin())
{
(await IdentityUserManager.DeleteAsync(await IdentityUserRepository.GetAsync(userId))).CheckErrors();
await uow.CompleteAsync();
}
(await DynamicClaimCache.GetAsync(cacheKey)).ShouldBeNull();
}
[Fact]
public virtual async Task Deleting_A_Stale_User_Should_Throw_A_Concurrency_Exception()
{
var userId = Guid.NewGuid();
IdentityUser staleUser;
using (var uow = UnitOfWorkManager.Begin())
{
(await IdentityUserManager.CreateAsync(
new IdentityUser(userId, $"stale-{userId:N}", $"stale-{userId:N}@abp.io"))).CheckErrors();
await uow.CompleteAsync();
}
using (var uow = UnitOfWorkManager.Begin())
{
staleUser = await IdentityUserRepository.GetAsync(userId);
await uow.CompleteAsync();
}
//Change the user, so the instance loaded above has an old concurrency stamp.
using (var uow = UnitOfWorkManager.Begin())
{
var user = await IdentityUserRepository.GetAsync(userId);
user.Name = "Changed";
await IdentityUserRepository.UpdateAsync(user);
await uow.CompleteAsync();
}
using (var uow = UnitOfWorkManager.Begin())
{
await Should.ThrowAsync<AbpIdentityResultException>(
async () => await IdentityUserManager.DeleteAsync(staleUser));
}
}
}

Loading…
Cancel
Save