Only update security stamp once per request (#15562)
* Add item in requestcache when security stamp is already updated in request * Propagate constructur obsoletion to implementing services and fix unit tests --------- Co-authored-by: kjac <kja@umbraco.dk>
This commit is contained in:
@@ -6,6 +6,7 @@ using Microsoft.Extensions.DependencyInjection;
|
||||
using Microsoft.Extensions.Logging;
|
||||
using Microsoft.Extensions.Options;
|
||||
using Umbraco.Cms.Core;
|
||||
using Umbraco.Cms.Core.Cache;
|
||||
using Umbraco.Cms.Core.Configuration.Models;
|
||||
using Umbraco.Cms.Core.DependencyInjection;
|
||||
using Umbraco.Cms.Core.Events;
|
||||
@@ -37,8 +38,9 @@ public class BackOfficeSignInManager : UmbracoSignInManager<BackOfficeIdentityUs
|
||||
IAuthenticationSchemeProvider schemes,
|
||||
IUserConfirmation<BackOfficeIdentityUser> confirmation,
|
||||
IEventAggregator eventAggregator,
|
||||
IOptions<SecuritySettings> securitySettings)
|
||||
: base(userManager, contextAccessor, claimsFactory, optionsAccessor, logger, schemes, confirmation, securitySettings)
|
||||
IOptions<SecuritySettings> securitySettings,
|
||||
IRequestCache requestCache)
|
||||
: base(userManager, contextAccessor, claimsFactory, optionsAccessor, logger, schemes, confirmation, securitySettings, requestCache)
|
||||
{
|
||||
_userManager = userManager;
|
||||
_externalLogins = externalLogins;
|
||||
@@ -46,6 +48,35 @@ public class BackOfficeSignInManager : UmbracoSignInManager<BackOfficeIdentityUs
|
||||
_globalSettings = globalSettings.Value;
|
||||
}
|
||||
|
||||
[Obsolete("Use non-obsolete constructor. This is scheduled for removal in V15.")]
|
||||
public BackOfficeSignInManager(
|
||||
BackOfficeUserManager userManager,
|
||||
IHttpContextAccessor contextAccessor,
|
||||
IBackOfficeExternalLoginProviders externalLogins,
|
||||
IUserClaimsPrincipalFactory<BackOfficeIdentityUser> claimsFactory,
|
||||
IOptions<IdentityOptions> optionsAccessor,
|
||||
IOptions<GlobalSettings> globalSettings,
|
||||
ILogger<SignInManager<BackOfficeIdentityUser>> logger,
|
||||
IAuthenticationSchemeProvider schemes,
|
||||
IUserConfirmation<BackOfficeIdentityUser> confirmation,
|
||||
IEventAggregator eventAggregator,
|
||||
IOptions<SecuritySettings> securitySettings)
|
||||
: this(
|
||||
userManager,
|
||||
contextAccessor,
|
||||
externalLogins,
|
||||
claimsFactory,
|
||||
optionsAccessor,
|
||||
globalSettings,
|
||||
logger,
|
||||
schemes,
|
||||
confirmation,
|
||||
eventAggregator,
|
||||
securitySettings,
|
||||
StaticServiceProvider.Instance.GetRequiredService<IRequestCache>())
|
||||
{
|
||||
}
|
||||
|
||||
[Obsolete("Use non-obsolete constructor. This is scheduled for removal in V14.")]
|
||||
public BackOfficeSignInManager(
|
||||
BackOfficeUserManager userManager,
|
||||
|
||||
@@ -5,6 +5,7 @@ using Microsoft.AspNetCore.Identity;
|
||||
using Microsoft.Extensions.DependencyInjection;
|
||||
using Microsoft.Extensions.Logging;
|
||||
using Microsoft.Extensions.Options;
|
||||
using Umbraco.Cms.Core.Cache;
|
||||
using Umbraco.Cms.Core.Configuration.Models;
|
||||
using Umbraco.Cms.Core.DependencyInjection;
|
||||
using Umbraco.Cms.Core.Events;
|
||||
@@ -32,13 +33,41 @@ public class MemberSignInManager : UmbracoSignInManager<MemberIdentityUser>, IMe
|
||||
IUserConfirmation<MemberIdentityUser> confirmation,
|
||||
IMemberExternalLoginProviders memberExternalLoginProviders,
|
||||
IEventAggregator eventAggregator,
|
||||
IOptions<SecuritySettings> securitySettings)
|
||||
: base(memberManager, contextAccessor, claimsFactory, optionsAccessor, logger, schemes, confirmation, securitySettings)
|
||||
IOptions<SecuritySettings> securitySettings,
|
||||
IRequestCache requestCache)
|
||||
: base(memberManager, contextAccessor, claimsFactory, optionsAccessor, logger, schemes, confirmation, securitySettings, requestCache)
|
||||
{
|
||||
_memberExternalLoginProviders = memberExternalLoginProviders;
|
||||
_eventAggregator = eventAggregator;
|
||||
}
|
||||
|
||||
[Obsolete("Use non-obsolete constructor. This is scheduled for removal in V15.")]
|
||||
public MemberSignInManager(
|
||||
UserManager<MemberIdentityUser> memberManager,
|
||||
IHttpContextAccessor contextAccessor,
|
||||
IUserClaimsPrincipalFactory<MemberIdentityUser> claimsFactory,
|
||||
IOptions<IdentityOptions> optionsAccessor,
|
||||
ILogger<SignInManager<MemberIdentityUser>> logger,
|
||||
IAuthenticationSchemeProvider schemes,
|
||||
IUserConfirmation<MemberIdentityUser> confirmation,
|
||||
IMemberExternalLoginProviders memberExternalLoginProviders,
|
||||
IEventAggregator eventAggregator,
|
||||
IOptions<SecuritySettings> securitySettings)
|
||||
: this(
|
||||
memberManager,
|
||||
contextAccessor,
|
||||
claimsFactory,
|
||||
optionsAccessor,
|
||||
logger,
|
||||
schemes,
|
||||
confirmation,
|
||||
memberExternalLoginProviders,
|
||||
eventAggregator,
|
||||
securitySettings,
|
||||
StaticServiceProvider.Instance.GetRequiredService<IRequestCache>())
|
||||
{
|
||||
}
|
||||
|
||||
[Obsolete("Use non-obsolete constructor. This is scheduled for removal in V14.")]
|
||||
public MemberSignInManager(
|
||||
UserManager<MemberIdentityUser> memberManager,
|
||||
|
||||
@@ -5,6 +5,7 @@ using Microsoft.AspNetCore.Identity;
|
||||
using Microsoft.Extensions.DependencyInjection;
|
||||
using Microsoft.Extensions.Logging;
|
||||
using Microsoft.Extensions.Options;
|
||||
using Umbraco.Cms.Core.Cache;
|
||||
using Umbraco.Cms.Core.Configuration.Models;
|
||||
using Umbraco.Cms.Core.DependencyInjection;
|
||||
using Umbraco.Cms.Core.Security;
|
||||
@@ -19,6 +20,7 @@ namespace Umbraco.Cms.Web.Common.Security;
|
||||
public abstract class UmbracoSignInManager<TUser> : SignInManager<TUser>
|
||||
where TUser : UmbracoIdentityUser
|
||||
{
|
||||
private readonly IRequestCache _requestCache;
|
||||
private SecuritySettings _securitySettings;
|
||||
|
||||
// borrowed from https://github.com/dotnet/aspnetcore/blob/master/src/Identity/Core/src/SignInManager.cs
|
||||
@@ -44,7 +46,31 @@ public abstract class UmbracoSignInManager<TUser> : SignInManager<TUser>
|
||||
logger,
|
||||
schemes,
|
||||
confirmation,
|
||||
StaticServiceProvider.Instance.GetRequiredService<IOptions<SecuritySettings>>())
|
||||
StaticServiceProvider.Instance.GetRequiredService<IOptions<SecuritySettings>>(),
|
||||
StaticServiceProvider.Instance.GetRequiredService<IRequestCache>())
|
||||
{
|
||||
}
|
||||
|
||||
[Obsolete("Use non-obsolete constructor. This is scheduled for removal in V15.")]
|
||||
public UmbracoSignInManager(
|
||||
UserManager<TUser> userManager,
|
||||
IHttpContextAccessor contextAccessor,
|
||||
IUserClaimsPrincipalFactory<TUser> claimsFactory,
|
||||
IOptions<IdentityOptions> optionsAccessor,
|
||||
ILogger<SignInManager<TUser>> logger,
|
||||
IAuthenticationSchemeProvider schemes,
|
||||
IUserConfirmation<TUser> confirmation,
|
||||
IOptions<SecuritySettings> securitySettingsOptions)
|
||||
: this(
|
||||
userManager,
|
||||
contextAccessor,
|
||||
claimsFactory,
|
||||
optionsAccessor,
|
||||
logger,
|
||||
schemes,
|
||||
confirmation,
|
||||
securitySettingsOptions,
|
||||
StaticServiceProvider.Instance.GetRequiredService<IRequestCache>())
|
||||
{
|
||||
}
|
||||
|
||||
@@ -56,9 +82,11 @@ public abstract class UmbracoSignInManager<TUser> : SignInManager<TUser>
|
||||
ILogger<SignInManager<TUser>> logger,
|
||||
IAuthenticationSchemeProvider schemes,
|
||||
IUserConfirmation<TUser> confirmation,
|
||||
IOptions<SecuritySettings> securitySettingsOptions)
|
||||
IOptions<SecuritySettings> securitySettingsOptions,
|
||||
IRequestCache requestCache)
|
||||
: base(userManager, contextAccessor, claimsFactory, optionsAccessor, logger, schemes, confirmation)
|
||||
{
|
||||
_requestCache = requestCache;
|
||||
_securitySettings = securitySettingsOptions.Value;
|
||||
}
|
||||
|
||||
@@ -370,7 +398,13 @@ public abstract class UmbracoSignInManager<TUser> : SignInManager<TUser>
|
||||
|
||||
if (_securitySettings.AllowConcurrentLogins is false)
|
||||
{
|
||||
await UserManager.UpdateSecurityStampAsync(user);
|
||||
|
||||
if (_requestCache.Get("SecurityStampUpdated") is null)
|
||||
{
|
||||
await UserManager.UpdateSecurityStampAsync(user);
|
||||
_requestCache.Set("SecurityStampUpdated", true);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
Logger.LogInformation("User: {UserName} logged in from IP address {IpAddress}", username, Context.Connection.RemoteIpAddress);
|
||||
|
||||
@@ -10,6 +10,7 @@ using Microsoft.Extensions.Logging;
|
||||
using Microsoft.Extensions.Options;
|
||||
using Moq;
|
||||
using NUnit.Framework;
|
||||
using Umbraco.Cms.Core.Cache;
|
||||
using Umbraco.Cms.Core.Configuration.Models;
|
||||
using Umbraco.Cms.Core.Events;
|
||||
using Umbraco.Cms.Core.Net;
|
||||
@@ -71,7 +72,8 @@ public class MemberSignInManagerTests
|
||||
Mock.Of<IUserConfirmation<MemberIdentityUser>>(),
|
||||
Mock.Of<IMemberExternalLoginProviders>(),
|
||||
Mock.Of<IEventAggregator>(),
|
||||
Mock.Of<IOptions<SecuritySettings>>(x => x.Value == new SecuritySettings()));
|
||||
Mock.Of<IOptions<SecuritySettings>>(x => x.Value == new SecuritySettings()),
|
||||
new DictionaryAppCache());
|
||||
}
|
||||
|
||||
private static Mock<MemberManager> MockMemberManager()
|
||||
|
||||
Reference in New Issue
Block a user