From c5e0ef90c3f8aa88fb28bd289dd2358866ba7e07 Mon Sep 17 00:00:00 2001 From: Warren Buckley Date: Mon, 10 Feb 2020 14:27:54 +0000 Subject: [PATCH] Verify & check SecurityStamp --- src/Umbraco.Web/Editors/AuthenticationController.cs | 7 ++++--- src/Umbraco.Web/Editors/BackOfficeController.cs | 12 +++++++++++- 2 files changed, 15 insertions(+), 4 deletions(-) diff --git a/src/Umbraco.Web/Editors/AuthenticationController.cs b/src/Umbraco.Web/Editors/AuthenticationController.cs index c2c481e8e4..c7c08d1b42 100644 --- a/src/Umbraco.Web/Editors/AuthenticationController.cs +++ b/src/Umbraco.Web/Editors/AuthenticationController.cs @@ -301,7 +301,7 @@ namespace Umbraco.Web.Editors if (user != null) { var code = await UserManager.GeneratePasswordResetTokenAsync(identityUser.Id); - var callbackUrl = ConstructCallbackUrl(identityUser.Id, code); + var callbackUrl = ConstructCallbackUrl(identityUser.Id, code, identityUser.SecurityStamp.GenerateHash()); var message = Services.TextService.Localize("resetPasswordEmailCopyFormat", // Ensure the culture of the found user is used for the email! @@ -506,7 +506,7 @@ namespace Umbraco.Web.Editors return response; } - private string ConstructCallbackUrl(int userId, string code) + private string ConstructCallbackUrl(int userId, string code, string userSecurityStamp) { // Get an mvc helper to get the url var http = EnsureHttpContext(); @@ -516,7 +516,8 @@ namespace Umbraco.Web.Editors { area = GlobalSettings.GetUmbracoMvcArea(), u = userId, - r = code + r = code, + s = userSecurityStamp }); // Construct full URL using configured application URL (which will fall back to request) diff --git a/src/Umbraco.Web/Editors/BackOfficeController.cs b/src/Umbraco.Web/Editors/BackOfficeController.cs index e77a1b70f2..04c4627d85 100644 --- a/src/Umbraco.Web/Editors/BackOfficeController.cs +++ b/src/Umbraco.Web/Editors/BackOfficeController.cs @@ -296,11 +296,21 @@ namespace Umbraco.Web.Editors } [HttpGet] - public async Task ValidatePasswordResetCode([Bind(Prefix = "u")]int userId, [Bind(Prefix = "r")]string resetCode) + public async Task ValidatePasswordResetCode([Bind(Prefix = "u")]int userId, [Bind(Prefix = "r")]string resetCode, [Bind(Prefix = "s")]string stampHash) { var user = UserManager.FindById(userId); if (user != null) { + // Check security stamp that has been generated in forgotten password email link is the same we have stored for user + // ie the user has not been marked inactive or password changed by an admin etc + if(user.SecurityStamp.GenerateHash() != stampHash) + { + // Password, email or something changed to the user since the password reset email requested + // Add error and redirect for it to be displayed + TempData[ViewDataExtensions.TokenPasswordResetCode] = new[] { Services.TextService.Localize("login/resetCodeExpired") }; + return RedirectToLocal(Url.Action("Default", "BackOffice")); + } + var result = await UserManager.UserTokenProvider.ValidateAsync("ResetPassword", resetCode, UserManager, user); if (result) {