Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
21 changes: 13 additions & 8 deletions src/Umbraco.Infrastructure/Security/BackOfficeUserStore.cs
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
using System.Data;
using System.Data.Common;
using System.Diagnostics.CodeAnalysis;
using System.Globalization;
using Microsoft.AspNetCore.Identity;
using Microsoft.Extensions.DependencyInjection;
Expand Down Expand Up @@ -436,8 +437,7 @@ public override Task<IdentityResult> DeleteAsync(
throw new ArgumentNullException(nameof(user));
}

IUser? found = FindUserFromString(user.Id);
if (found is not null)
if (TryFindUserFromString(user.Id, out IUser? found))
{
DisableAsync(found).GetAwaiter().GetResult();
}
Expand Down Expand Up @@ -469,31 +469,36 @@ public override Task<IdentityResult> DeleteAsync(
cancellationToken.ThrowIfCancellationRequested();
ThrowIfDisposed();

IUser? user = FindUserFromString(userId);
if (user == null)
if (TryFindUserFromString(userId, out IUser? user) is false)
{
return Task.FromResult((BackOfficeIdentityUser?)null)!;
}

return Task.FromResult(AssignLoginsCallback(_mapper.Map<BackOfficeIdentityUser>(user)))!;
}

private IUser? FindUserFromString(string userId)
private bool TryFindUserFromString(string userId, [NotNullWhen(true)] out IUser? user)
{
// We could use ResolveEntityIdFromIdentityId here, but that would require multiple DB calls, so let's not.
if (TryConvertIdentityIdToInt(userId, out var id))
{
return GetAsync(id).GetAwaiter().GetResult();
user = GetAsync(id).GetAwaiter().GetResult();
return user is not null;
}

// We couldn't directly convert the ID to an int, this is because the user logged in with external login.
// So we need to look up the user by key.
if (Guid.TryParse(userId, out Guid key))
{
return GetAsync(key).GetAwaiter().GetResult();
user = GetAsync(key).GetAwaiter().GetResult();
return user is not null;
}

throw new InvalidOperationException($"Unable to resolve user with ID {userId}");
// Maybe we have some other format of user Id from an external login flow, so don't throw but return null.
// We won't be able to find the user via this ID in a local database lookup so we'll handle the same as if they don't exist.

user = null;
return false;
}

protected override async Task<int> ResolveEntityIdFromIdentityId(string? identityId)
Expand Down
32 changes: 24 additions & 8 deletions src/Umbraco.Infrastructure/Security/MemberUserStore.cs
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,6 @@
using System.Globalization;
using Microsoft.AspNetCore.Identity;
using Microsoft.Extensions.DependencyInjection;
using Umbraco.Cms.Core.DependencyInjection;
using Umbraco.Cms.Core.Mapping;
using Umbraco.Cms.Core.Models;
using Umbraco.Cms.Core.Models.PublishedContent;
Expand Down Expand Up @@ -322,9 +321,15 @@ public override Task<IdentityResult> DeleteAsync(
throw new ArgumentNullException(nameof(userId));
}

IMember? user = Guid.TryParse(userId, out Guid key)
? _memberService.GetByKey(key)
: _memberService.GetById(ResolveEntityIdFromIdentityId(userId).GetAwaiter().GetResult());
IMember? user = null;
if (Guid.TryParse(userId, out Guid key))
{
user = _memberService.GetByKey(key);
}
else if (TryResolveEntityIdFromIdentityId(userId, out int id))
{
user = _memberService.GetById(id);
}

if (user == null)
{
Expand All @@ -334,22 +339,33 @@ public override Task<IdentityResult> DeleteAsync(
return Task.FromResult(AssignLoginsCallback(_mapper.Map<MemberIdentityUser>(user)))!;
}

protected override Task<int> ResolveEntityIdFromIdentityId(string? identityId)
private bool TryResolveEntityIdFromIdentityId(string? identityId, out int entityId)
{
if (TryConvertIdentityIdToInt(identityId, out var id))
if (TryConvertIdentityIdToInt(identityId, out entityId))
{
return Task.FromResult(id);
return true;
}

if (Guid.TryParse(identityId, out Guid key))
{
IMember? member = _memberService.GetByKey(key);
if (member is not null)
{
return Task.FromResult(member.Id);
entityId = member.Id;
return true;
}
}

return false;
}

protected override Task<int> ResolveEntityIdFromIdentityId(string? identityId)
{
if (TryResolveEntityIdFromIdentityId(identityId, out var entityId))
{
return Task.FromResult(entityId);
}

throw new InvalidOperationException($"Unable to resolve user with ID {identityId}");
}

Expand Down
17 changes: 3 additions & 14 deletions src/Umbraco.Infrastructure/Security/UmbracoUserStore.cs
Original file line number Diff line number Diff line change
Expand Up @@ -35,29 +35,18 @@ protected UmbracoUserStore(IdentityErrorDescriber describer)
[Obsolete("Use TryConvertIdentityIdToInt instead. Scheduled for removal in V15.")]
protected static int UserIdToInt(string? userId)
{
if (TryUserIdToInt(userId, out int result))
if (int.TryParse(userId, NumberStyles.Integer, CultureInfo.InvariantCulture, out var result))
{
return result;
}

throw new InvalidOperationException($"Unable to convert user ID ({userId})to int using InvariantCulture");
}

protected static bool TryUserIdToInt(string? userId, out int result)
{
if (int.TryParse(userId, NumberStyles.Integer, CultureInfo.InvariantCulture, out result))
{
return true;
}

if (Guid.TryParse(userId, out Guid key))
{
// Reverse the IntExtensions.ToGuid
result = BitConverter.ToInt32(key.ToByteArray(), 0);
return true;
return BitConverter.ToInt32(key.ToByteArray(), 0);
}

return false;
throw new InvalidOperationException($"Unable to convert user ID ({userId})to int using InvariantCulture");
}

protected abstract Task<int> ResolveEntityIdFromIdentityId(string? identityId);
Expand Down