From 89d670372d8e310c7644dae98c7191c6b1506b15 Mon Sep 17 00:00:00 2001 From: Nikolaj Geisle <70372949+Zeegaan@users.noreply.github.com> Date: Mon, 12 Jun 2023 09:56:04 +0200 Subject: [PATCH] Update security stamps on logout (#14362) Co-authored-by: Zeegaan --- .../UmbracoBuilder.MembersIdentity.cs | 1 + .../Security/ConfigureMemberCookieOptions.cs | 9 +++++++ .../Security/MemberSecurityStampValidator.cs | 26 +++++++++++++++++++ .../MemberSecurityStampValidatorOptions.cs | 7 +++++ .../Security/UmbracoSignInManager.cs | 8 ++++++ 5 files changed, 51 insertions(+) create mode 100644 src/Umbraco.Web.Common/Security/MemberSecurityStampValidator.cs create mode 100644 src/Umbraco.Web.Common/Security/MemberSecurityStampValidatorOptions.cs diff --git a/src/Umbraco.Web.Common/DependencyInjection/UmbracoBuilder.MembersIdentity.cs b/src/Umbraco.Web.Common/DependencyInjection/UmbracoBuilder.MembersIdentity.cs index 79c60bc230..09ff520766 100644 --- a/src/Umbraco.Web.Common/DependencyInjection/UmbracoBuilder.MembersIdentity.cs +++ b/src/Umbraco.Web.Common/DependencyInjection/UmbracoBuilder.MembersIdentity.cs @@ -65,6 +65,7 @@ public static partial class UmbracoBuilderExtensions services.ConfigureOptions(); services.ConfigureOptions(); + services.AddScoped(); services.AddUnique(); diff --git a/src/Umbraco.Web.Common/Security/ConfigureMemberCookieOptions.cs b/src/Umbraco.Web.Common/Security/ConfigureMemberCookieOptions.cs index 9aa073483a..66714be9e6 100644 --- a/src/Umbraco.Web.Common/Security/ConfigureMemberCookieOptions.cs +++ b/src/Umbraco.Web.Common/Security/ConfigureMemberCookieOptions.cs @@ -1,6 +1,7 @@ using Microsoft.AspNetCore.Authentication.Cookies; using Microsoft.AspNetCore.Http; using Microsoft.AspNetCore.Identity; +using Microsoft.Extensions.DependencyInjection; using Microsoft.Extensions.Options; using Umbraco.Cms.Core.Routing; using Umbraco.Cms.Core.Services; @@ -47,6 +48,14 @@ public sealed class ConfigureMemberCookieOptions : IConfigureNamedOptions + { + // We need to resolve the BackOfficeSecurityStampValidator per request as a requirement (even in aspnetcore they do this) + MemberSecurityStampValidator securityStampValidator = + ctx.HttpContext.RequestServices.GetRequiredService(); + + await securityStampValidator.ValidateAsync(ctx); + }, OnRedirectToAccessDenied = ctx => { ctx.Response.StatusCode = StatusCodes.Status403Forbidden; diff --git a/src/Umbraco.Web.Common/Security/MemberSecurityStampValidator.cs b/src/Umbraco.Web.Common/Security/MemberSecurityStampValidator.cs new file mode 100644 index 0000000000..3623626112 --- /dev/null +++ b/src/Umbraco.Web.Common/Security/MemberSecurityStampValidator.cs @@ -0,0 +1,26 @@ +using Microsoft.AspNetCore.Authentication; +using Microsoft.AspNetCore.Authentication.Cookies; +using Microsoft.AspNetCore.Identity; +using Microsoft.Extensions.Logging; +using Microsoft.Extensions.Options; +using Umbraco.Cms.Core.Security; + +namespace Umbraco.Cms.Web.Common.Security; + +/// +/// A security stamp validator for the back office +/// +public class MemberSecurityStampValidator : SecurityStampValidator +{ + public MemberSecurityStampValidator( + IOptions options, + MemberSignInManager signInManager, ISystemClock clock, ILoggerFactory logger) + : base(options, signInManager, clock, logger) + { + } + + public override Task ValidateAsync(CookieValidatePrincipalContext context) + { + return base.ValidateAsync(context); + } +} diff --git a/src/Umbraco.Web.Common/Security/MemberSecurityStampValidatorOptions.cs b/src/Umbraco.Web.Common/Security/MemberSecurityStampValidatorOptions.cs new file mode 100644 index 0000000000..38189b2d6a --- /dev/null +++ b/src/Umbraco.Web.Common/Security/MemberSecurityStampValidatorOptions.cs @@ -0,0 +1,7 @@ +using Microsoft.AspNetCore.Identity; + +namespace Umbraco.Cms.Web.Common.Security; + +public class MemberSecurityStampValidatorOptions : SecurityStampValidatorOptions +{ +} diff --git a/src/Umbraco.Web.Common/Security/UmbracoSignInManager.cs b/src/Umbraco.Web.Common/Security/UmbracoSignInManager.cs index 63defed2de..bdcd723020 100644 --- a/src/Umbraco.Web.Common/Security/UmbracoSignInManager.cs +++ b/src/Umbraco.Web.Common/Security/UmbracoSignInManager.cs @@ -238,6 +238,14 @@ public abstract class UmbracoSignInManager : SignInManager /// public override async Task SignOutAsync() { + // Update the security stamp to sign out everywhere. + TUser? user = await UserManager.GetUserAsync(Context.User); + + if (user is not null) + { + await UserManager.UpdateSecurityStampAsync(user); + } + // override to replace IdentityConstants.ApplicationScheme with custom auth types // code taken from aspnetcore: https://github.com/dotnet/aspnetcore/blob/master/src/Identity/Core/src/SignInManager.cs await Context.SignOutAsync(AuthenticationType);