diff --git a/src/Umbraco.Cms.Api.Management/Controllers/BackOfficeLoginController.cs b/src/Umbraco.Cms.Api.Management/Controllers/BackOfficeLoginController.cs index 6e11989975..aa8b711257 100644 --- a/src/Umbraco.Cms.Api.Management/Controllers/BackOfficeLoginController.cs +++ b/src/Umbraco.Cms.Api.Management/Controllers/BackOfficeLoginController.cs @@ -54,16 +54,16 @@ public class BackOfficeLoginController : Controller model.UmbracoUrl = _hostingEnvironment.ToAbsolute(_globalSettings.UmbracoPath); } - if ( Uri.TryCreate(model.ReturnUrl, UriKind.Relative, out _) is false) // Needs to test for relative and not absolute, as /whatever/ is an absolute path on linux - { - return BadRequest("ReturnUrl must be a relative path."); - } - if (string.IsNullOrEmpty(model.ReturnUrl)) { model.ReturnUrl = model.UmbracoUrl; } + if ( Uri.TryCreate(model.ReturnUrl, UriKind.Relative, out _) is false) // Needs to test for relative and not absolute, as /whatever/ is an absolute path on linux + { + return BadRequest("ReturnUrl must be a relative path."); + } + return View("/umbraco/UmbracoLogin/Index.cshtml", model); } } diff --git a/src/Umbraco.Cms.Api.Management/Controllers/Security/ResetPasswordTokenController.cs b/src/Umbraco.Cms.Api.Management/Controllers/Security/ResetPasswordTokenController.cs index 9e378b7a1e..7d55492206 100644 --- a/src/Umbraco.Cms.Api.Management/Controllers/Security/ResetPasswordTokenController.cs +++ b/src/Umbraco.Cms.Api.Management/Controllers/Security/ResetPasswordTokenController.cs @@ -2,6 +2,7 @@ using Asp.Versioning; using Microsoft.AspNetCore.Authorization; using Microsoft.AspNetCore.Http; using Microsoft.AspNetCore.Mvc; +using OpenIddict.Abstractions; using Umbraco.Cms.Api.Common.Builders; using Umbraco.Cms.Api.Management.Filters; using Umbraco.Cms.Api.Management.ViewModels.Security; @@ -10,6 +11,7 @@ using Umbraco.Cms.Core.Models; using Umbraco.Cms.Core.Services; using Umbraco.Cms.Core.Services.OperationStatus; using Umbraco.Cms.Web.Common.Authorization; +using Umbraco.Extensions; namespace Umbraco.Cms.Api.Management.Controllers.Security; @@ -18,8 +20,13 @@ namespace Umbraco.Cms.Api.Management.Controllers.Security; public class ResetPasswordTokenController : SecurityControllerBase { private readonly IUserService _userService; + private readonly IOpenIddictTokenManager _tokenManager; - public ResetPasswordTokenController(IUserService userService) => _userService = userService; + public ResetPasswordTokenController(IUserService userService, IOpenIddictTokenManager tokenManager) + { + _userService = userService; + _tokenManager = tokenManager; + } [HttpPost("forgot-password/reset")] [MapToApiVersion("1.0")] @@ -31,8 +38,13 @@ public class ResetPasswordTokenController : SecurityControllerBase { Attempt result = await _userService.ResetPasswordAsync(model.User.Id, model.ResetCode, model.Password); - return result.Success - ? NoContent() - : UserOperationStatusResult(result.Status, result.Result); + if (result.Success is false) + { + return UserOperationStatusResult(result.Status, result.Result); + } + + await _tokenManager.RevokeUmbracoUserTokens(model.User.Id); + return Ok(); + } } diff --git a/src/Umbraco.Cms.Api.Management/Controllers/User/CreateInitialPasswordUserController.cs b/src/Umbraco.Cms.Api.Management/Controllers/User/CreateInitialPasswordUserController.cs index 0afbedb4e0..3831a2b029 100644 --- a/src/Umbraco.Cms.Api.Management/Controllers/User/CreateInitialPasswordUserController.cs +++ b/src/Umbraco.Cms.Api.Management/Controllers/User/CreateInitialPasswordUserController.cs @@ -2,12 +2,14 @@ using Asp.Versioning; using Microsoft.AspNetCore.Authorization; using Microsoft.AspNetCore.Http; using Microsoft.AspNetCore.Mvc; +using OpenIddict.Abstractions; using Umbraco.Cms.Api.Management.ViewModels.User; using Umbraco.Cms.Core; using Umbraco.Cms.Core.Models; using Umbraco.Cms.Core.Services; using Umbraco.Cms.Core.Services.OperationStatus; using Umbraco.Cms.Web.Common.Authorization; +using Umbraco.Extensions; namespace Umbraco.Cms.Api.Management.Controllers.User; @@ -16,8 +18,13 @@ namespace Umbraco.Cms.Api.Management.Controllers.User; public class CreateInitialPasswordUserController : UserControllerBase { private readonly IUserService _userService; + private readonly IOpenIddictTokenManager _tokenManager; - public CreateInitialPasswordUserController(IUserService userService) => _userService = userService; + public CreateInitialPasswordUserController(IUserService userService, IOpenIddictTokenManager tokenManager) + { + _userService = userService; + _tokenManager = tokenManager; + } [AllowAnonymous] [HttpPost("invite/create-password")] @@ -31,8 +38,12 @@ public class CreateInitialPasswordUserController : UserControllerBase { Attempt response = await _userService.CreateInitialPasswordAsync(model.User.Id, model.Token, model.Password); - return response.Success - ? Ok() - : UserOperationStatusResult(response.Status, response.Result); + if (response.Success is false) + { + return UserOperationStatusResult(response.Status, response.Result); + } + + await _tokenManager.RevokeUmbracoUserTokens(model.User.Id); + return Ok(); } } diff --git a/src/Umbraco.Cms.Api.Management/Extensions/OpenIdDictTokenManagerExtensions.cs b/src/Umbraco.Cms.Api.Management/Extensions/OpenIdDictTokenManagerExtensions.cs new file mode 100644 index 0000000000..5cc47ff4dd --- /dev/null +++ b/src/Umbraco.Cms.Api.Management/Extensions/OpenIdDictTokenManagerExtensions.cs @@ -0,0 +1,16 @@ +using OpenIddict.Abstractions; + +namespace Umbraco.Extensions; + +public static class OpenIdDictTokenManagerExtensions +{ + public static async Task RevokeUmbracoUserTokens(this IOpenIddictTokenManager openIddictTokenManager, Guid userKey) + { + var tokens = await openIddictTokenManager.FindBySubjectAsync(userKey.ToString()).ToArrayAsync(); + + foreach (var token in tokens) + { + await openIddictTokenManager.DeleteAsync(token); + } + } +} diff --git a/src/Umbraco.Cms.Api.Management/Handlers/RevokeUserAuthenticationTokensNotificationHandler.cs b/src/Umbraco.Cms.Api.Management/Handlers/RevokeUserAuthenticationTokensNotificationHandler.cs index 87475e26ae..acf6cb508a 100644 --- a/src/Umbraco.Cms.Api.Management/Handlers/RevokeUserAuthenticationTokensNotificationHandler.cs +++ b/src/Umbraco.Cms.Api.Management/Handlers/RevokeUserAuthenticationTokensNotificationHandler.cs @@ -215,17 +215,9 @@ internal sealed class RevokeUserAuthenticationTokensNotificationHandler : private async Task RevokeTokensAsync(IUser user) { - var tokens = await _tokenManager.FindBySubjectAsync(user.Key.ToString()).ToArrayAsync(); - if (tokens.Length == 0) - { - return; - } + _logger.LogInformation("Revoking active tokens for user with ID {id}", user.Id); - _logger.LogInformation("Revoking {count} active tokens for user with ID {id}", tokens.Length, user.Id); - foreach (var token in tokens) - { - await _tokenManager.DeleteAsync(token); - } + await _tokenManager.RevokeUmbracoUserTokens(user.Key); } private async Task FindUserFromString(string userId)