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;

Check notice on line 1 in src/Umbraco.Infrastructure/Security/BackOfficeUserStore.cs

View check run for this annotation

CodeScene Delta Analysis / CodeScene Cloud Delta Analysis (v15/dev)

✅ Getting better: Primitive Obsession

The ratio of primitive types in function arguments decreases from 40.24% to 39.76%, threshold = 30.0%. The functions in this file have too many primitive types (e.g. int, double, float) in their function argument lists. Using many primitive types lead to the code smell Primitive Obsession. Avoid adding more primitive arguments.
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 @@
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 @@
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
@@ -1,8 +1,7 @@
using System.Data;

Check notice on line 1 in src/Umbraco.Infrastructure/Security/MemberUserStore.cs

View check run for this annotation

CodeScene Delta Analysis / CodeScene Cloud Delta Analysis (v15/dev)

✅ Getting better: Overall Code Complexity

The mean cyclomatic complexity decreases from 5.40 to 5.31, threshold = 4. This file has many conditional statements (e.g. if, for, while) across its implementation, leading to lower code health. Avoid adding more conditionals.
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 @@
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 @@
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