Skip to content

Commit e840a0c

Browse files
Do not convert calculated lockedOutUntil time to UTC (#17007)
* Do not convert calculated lockedOutUntil time to UTC * Handle conversion to UTC when we know we have server time values in IdentityMapDefinition for members. --------- Co-authored-by: Andy Butland <[email protected]>
1 parent c9d5c7f commit e840a0c

File tree

1 file changed

+36
-7
lines changed

1 file changed

+36
-7
lines changed

src/Umbraco.Infrastructure/Security/IdentityMapDefinition.cs

Lines changed: 36 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -129,7 +129,7 @@ private void Map(IUser source, BackOfficeIdentityUser target)
129129
target.IsApproved = source.IsApproved;
130130
target.SecurityStamp = source.SecurityStamp;
131131
DateTime? lockedOutUntil = source.LastLockoutDate?.AddMinutes(_securitySettings.UserDefaultLockoutTimeInMinutes);
132-
target.LockoutEnd = source.IsLockedOut ? (lockedOutUntil ?? DateTime.MaxValue).ToUniversalTime() : null;
132+
target.LockoutEnd = source.IsLockedOut ? lockedOutUntil ?? DateTime.MaxValue : null;
133133
}
134134

135135
// Umbraco.Code.MapAll -Id -LockoutEnabled -PhoneNumber -PhoneNumberConfirmed -ConcurrencyStamp -NormalizedEmail -NormalizedUserName -Roles
@@ -146,17 +146,46 @@ private void Map(IMember source, MemberIdentityUser target)
146146
target.PasswordConfig = source.PasswordConfiguration;
147147
target.IsApproved = source.IsApproved;
148148
target.SecurityStamp = source.SecurityStamp;
149-
DateTime? lockedOutUntil = source.LastLockoutDate?.AddMinutes(_securitySettings.MemberDefaultLockoutTimeInMinutes);
150-
target.LockoutEnd = source.IsLockedOut ? (lockedOutUntil ?? DateTime.MaxValue).ToUniversalTime() : null;
149+
target.LockoutEnd = GetLockoutEnd(source);
150+
target.LastLockoutDateUtc = GetLastLockoutDateUtc(source);
151151
target.Comments = source.Comments;
152-
target.LastLockoutDateUtc = source.LastLockoutDate == DateTime.MinValue
153-
? null
154-
: source.LastLockoutDate?.ToUniversalTime();
155-
target.CreatedDateUtc = source.CreateDate.ToUniversalTime();
152+
target.CreatedDateUtc = EnsureUtcWithServerTime(source.CreateDate);
156153
target.Key = source.Key;
157154
target.MemberTypeAlias = source.ContentTypeAlias;
158155
target.TwoFactorEnabled = _twoFactorLoginService.IsTwoFactorEnabledAsync(source.Key).GetAwaiter().GetResult();
159156

160157
// NB: same comments re AutoMapper as per BackOfficeUser
161158
}
159+
160+
private DateTimeOffset? GetLockoutEnd(IMember source)
161+
{
162+
if (source.IsLockedOut is false)
163+
{
164+
return null;
165+
}
166+
167+
DateTime? lockedOutUntil = source.LastLockoutDate?.AddMinutes(_securitySettings.MemberDefaultLockoutTimeInMinutes);
168+
if (lockedOutUntil.HasValue is false)
169+
{
170+
return DateTime.MaxValue;
171+
}
172+
173+
return EnsureUtcWithServerTime(lockedOutUntil.Value);
174+
}
175+
176+
private static DateTime? GetLastLockoutDateUtc(IMember source)
177+
{
178+
if (source.LastLockoutDate is null || source.LastLockoutDate == DateTime.MinValue)
179+
{
180+
return null;
181+
}
182+
183+
return EnsureUtcWithServerTime(source.LastLockoutDate.Value);
184+
}
185+
186+
private static DateTime EnsureUtcWithServerTime(DateTime date) =>
187+
188+
// We have a server time value here, but the the Kind is UTC, so we can't use .ToUniversalTime() to convert to the UTC
189+
// value that the LockoutEnd property expects. We need to create a DateTimeOffset with the correct offset.
190+
DateTime.SpecifyKind(date, DateTimeKind.Local).ToUniversalTime();
162191
}

0 commit comments

Comments
 (0)