From 28e9c24f332a4cb6db6c71401c89719faf6ed403 Mon Sep 17 00:00:00 2001 From: Vincent Salucci <26154748+vincentsalucci@users.noreply.github.com> Date: Tue, 2 Dec 2025 23:23:58 -0600 Subject: [PATCH] [PM-25584] [PM-25585] Remove feature flag - recover provider accounts (#6673) * chore: remove ff from OrganizationUsersController, refs PM-25584 * chore: update tests with reference to ff, refs PM-25584 * chore: remove ff definition, refs PM-25585 * chore: dotnet format, refs PM-25584 --- .../OrganizationUsersController.cs | 35 +--------- src/Core/Constants.cs | 1 - ...ionUsersControllerPutResetPasswordTests.cs | 9 --- .../OrganizationUsersControllerTests.cs | 64 ++----------------- 4 files changed, 6 insertions(+), 103 deletions(-) diff --git a/src/Api/AdminConsole/Controllers/OrganizationUsersController.cs b/src/Api/AdminConsole/Controllers/OrganizationUsersController.cs index 155b60ce5b..55b9caa550 100644 --- a/src/Api/AdminConsole/Controllers/OrganizationUsersController.cs +++ b/src/Api/AdminConsole/Controllers/OrganizationUsersController.cs @@ -483,43 +483,10 @@ public class OrganizationUsersController : BaseAdminConsoleController } } +#nullable enable [HttpPut("{id}/reset-password")] [Authorize] public async Task PutResetPassword(Guid orgId, Guid id, [FromBody] OrganizationUserResetPasswordRequestModel model) - { - if (_featureService.IsEnabled(FeatureFlagKeys.AccountRecoveryCommand)) - { - // TODO: remove legacy implementation after feature flag is enabled. - return await PutResetPasswordNew(orgId, id, model); - } - - // Get the users role, since provider users aren't a member of the organization we use the owner check - var orgUserType = await _currentContext.OrganizationOwner(orgId) - ? OrganizationUserType.Owner - : _currentContext.Organizations?.FirstOrDefault(o => o.Id == orgId)?.Type; - if (orgUserType == null) - { - return TypedResults.NotFound(); - } - - var result = await _userService.AdminResetPasswordAsync(orgUserType.Value, orgId, id, model.NewMasterPasswordHash, model.Key); - if (result.Succeeded) - { - return TypedResults.Ok(); - } - - foreach (var error in result.Errors) - { - ModelState.AddModelError(string.Empty, error.Description); - } - - await Task.Delay(2000); - return TypedResults.BadRequest(ModelState); - } - -#nullable enable - // TODO: make sure the route and authorize attributes are maintained when the legacy implementation is removed. - private async Task PutResetPasswordNew(Guid orgId, Guid id, [FromBody] OrganizationUserResetPasswordRequestModel model) { var targetOrganizationUser = await _organizationUserRepository.GetByIdAsync(id); if (targetOrganizationUser == null || targetOrganizationUser.OrganizationId != orgId) diff --git a/src/Core/Constants.cs b/src/Core/Constants.cs index e63d087863..0d3dd37df4 100644 --- a/src/Core/Constants.cs +++ b/src/Core/Constants.cs @@ -140,7 +140,6 @@ public static class FeatureFlagKeys public const string CreateDefaultLocation = "pm-19467-create-default-location"; public const string AutomaticConfirmUsers = "pm-19934-auto-confirm-organization-users"; public const string PM23845_VNextApplicationCache = "pm-24957-refactor-memory-application-cache"; - public const string AccountRecoveryCommand = "pm-25581-prevent-provider-account-recovery"; public const string BlockClaimedDomainAccountCreation = "pm-28297-block-uninvited-claimed-domain-registration"; public const string PolicyValidatorsRefactor = "pm-26423-refactor-policy-side-effects"; public const string IncreaseBulkReinviteLimitForCloud = "pm-28251-increase-bulk-reinvite-limit-for-cloud"; diff --git a/test/Api.IntegrationTest/AdminConsole/Controllers/OrganizationUsersControllerPutResetPasswordTests.cs b/test/Api.IntegrationTest/AdminConsole/Controllers/OrganizationUsersControllerPutResetPasswordTests.cs index 7b707fa335..38e3cac863 100644 --- a/test/Api.IntegrationTest/AdminConsole/Controllers/OrganizationUsersControllerPutResetPasswordTests.cs +++ b/test/Api.IntegrationTest/AdminConsole/Controllers/OrganizationUsersControllerPutResetPasswordTests.cs @@ -3,7 +3,6 @@ using Bit.Api.AdminConsole.Authorization; using Bit.Api.IntegrationTest.Factories; using Bit.Api.IntegrationTest.Helpers; using Bit.Api.Models.Request.Organizations; -using Bit.Core; using Bit.Core.AdminConsole.Entities; using Bit.Core.AdminConsole.Entities.Provider; using Bit.Core.AdminConsole.Enums; @@ -14,8 +13,6 @@ using Bit.Core.Entities; using Bit.Core.Enums; using Bit.Core.Models.Api; using Bit.Core.Repositories; -using Bit.Core.Services; -using NSubstitute; using Xunit; namespace Bit.Api.IntegrationTest.AdminConsole.Controllers; @@ -32,12 +29,6 @@ public class OrganizationUsersControllerPutResetPasswordTests : IClassFixture(featureService => - { - featureService - .IsEnabled(FeatureFlagKeys.AccountRecoveryCommand) - .Returns(true); - }); _client = _factory.CreateClient(); _loginHelper = new LoginHelper(_factory, _client); } diff --git a/test/Api.Test/AdminConsole/Controllers/OrganizationUsersControllerTests.cs b/test/Api.Test/AdminConsole/Controllers/OrganizationUsersControllerTests.cs index ae14001223..cb03844aa2 100644 --- a/test/Api.Test/AdminConsole/Controllers/OrganizationUsersControllerTests.cs +++ b/test/Api.Test/AdminConsole/Controllers/OrganizationUsersControllerTests.cs @@ -452,60 +452,10 @@ public class OrganizationUsersControllerTests [Theory] [BitAutoData] - public async Task PutResetPassword_WithFeatureFlagDisabled_CallsLegacyPath( + public async Task PutResetPassword_WhenOrganizationUserNotFound_ReturnsNotFound( Guid orgId, Guid orgUserId, OrganizationUserResetPasswordRequestModel model, SutProvider sutProvider) { - sutProvider.GetDependency().IsEnabled(FeatureFlagKeys.AccountRecoveryCommand).Returns(false); - sutProvider.GetDependency().OrganizationOwner(orgId).Returns(true); - sutProvider.GetDependency().AdminResetPasswordAsync(Arg.Any(), orgId, orgUserId, model.NewMasterPasswordHash, model.Key) - .Returns(Microsoft.AspNetCore.Identity.IdentityResult.Success); - - var result = await sutProvider.Sut.PutResetPassword(orgId, orgUserId, model); - - Assert.IsType(result); - await sutProvider.GetDependency().Received(1) - .AdminResetPasswordAsync(OrganizationUserType.Owner, orgId, orgUserId, model.NewMasterPasswordHash, model.Key); - } - - [Theory] - [BitAutoData] - public async Task PutResetPassword_WithFeatureFlagDisabled_WhenOrgUserTypeIsNull_ReturnsNotFound( - Guid orgId, Guid orgUserId, OrganizationUserResetPasswordRequestModel model, - SutProvider sutProvider) - { - sutProvider.GetDependency().IsEnabled(FeatureFlagKeys.AccountRecoveryCommand).Returns(false); - sutProvider.GetDependency().OrganizationOwner(orgId).Returns(false); - sutProvider.GetDependency().Organizations.Returns(new List()); - - var result = await sutProvider.Sut.PutResetPassword(orgId, orgUserId, model); - - Assert.IsType(result); - } - - [Theory] - [BitAutoData] - public async Task PutResetPassword_WithFeatureFlagDisabled_WhenAdminResetPasswordFails_ReturnsBadRequest( - Guid orgId, Guid orgUserId, OrganizationUserResetPasswordRequestModel model, - SutProvider sutProvider) - { - sutProvider.GetDependency().IsEnabled(FeatureFlagKeys.AccountRecoveryCommand).Returns(false); - sutProvider.GetDependency().OrganizationOwner(orgId).Returns(true); - sutProvider.GetDependency().AdminResetPasswordAsync(Arg.Any(), orgId, orgUserId, model.NewMasterPasswordHash, model.Key) - .Returns(Microsoft.AspNetCore.Identity.IdentityResult.Failed(new Microsoft.AspNetCore.Identity.IdentityError { Description = "Error 1" })); - - var result = await sutProvider.Sut.PutResetPassword(orgId, orgUserId, model); - - Assert.IsType>(result); - } - - [Theory] - [BitAutoData] - public async Task PutResetPassword_WithFeatureFlagEnabled_WhenOrganizationUserNotFound_ReturnsNotFound( - Guid orgId, Guid orgUserId, OrganizationUserResetPasswordRequestModel model, - SutProvider sutProvider) - { - sutProvider.GetDependency().IsEnabled(FeatureFlagKeys.AccountRecoveryCommand).Returns(true); sutProvider.GetDependency().GetByIdAsync(orgUserId).Returns((OrganizationUser)null); var result = await sutProvider.Sut.PutResetPassword(orgId, orgUserId, model); @@ -515,12 +465,11 @@ public class OrganizationUsersControllerTests [Theory] [BitAutoData] - public async Task PutResetPassword_WithFeatureFlagEnabled_WhenOrganizationIdMismatch_ReturnsNotFound( + public async Task PutResetPassword_WhenOrganizationIdMismatch_ReturnsNotFound( Guid orgId, Guid orgUserId, OrganizationUserResetPasswordRequestModel model, OrganizationUser organizationUser, SutProvider sutProvider) { organizationUser.OrganizationId = Guid.NewGuid(); - sutProvider.GetDependency().IsEnabled(FeatureFlagKeys.AccountRecoveryCommand).Returns(true); sutProvider.GetDependency().GetByIdAsync(orgUserId).Returns(organizationUser); var result = await sutProvider.Sut.PutResetPassword(orgId, orgUserId, model); @@ -530,12 +479,11 @@ public class OrganizationUsersControllerTests [Theory] [BitAutoData] - public async Task PutResetPassword_WithFeatureFlagEnabled_WhenAuthorizationFails_ReturnsBadRequest( + public async Task PutResetPassword_WhenAuthorizationFails_ReturnsBadRequest( Guid orgId, Guid orgUserId, OrganizationUserResetPasswordRequestModel model, OrganizationUser organizationUser, SutProvider sutProvider) { organizationUser.OrganizationId = orgId; - sutProvider.GetDependency().IsEnabled(FeatureFlagKeys.AccountRecoveryCommand).Returns(true); sutProvider.GetDependency().GetByIdAsync(orgUserId).Returns(organizationUser); sutProvider.GetDependency() .AuthorizeAsync( @@ -551,12 +499,11 @@ public class OrganizationUsersControllerTests [Theory] [BitAutoData] - public async Task PutResetPassword_WithFeatureFlagEnabled_WhenRecoverAccountSucceeds_ReturnsOk( + public async Task PutResetPassword_WhenRecoverAccountSucceeds_ReturnsOk( Guid orgId, Guid orgUserId, OrganizationUserResetPasswordRequestModel model, OrganizationUser organizationUser, SutProvider sutProvider) { organizationUser.OrganizationId = orgId; - sutProvider.GetDependency().IsEnabled(FeatureFlagKeys.AccountRecoveryCommand).Returns(true); sutProvider.GetDependency().GetByIdAsync(orgUserId).Returns(organizationUser); sutProvider.GetDependency() .AuthorizeAsync( @@ -577,12 +524,11 @@ public class OrganizationUsersControllerTests [Theory] [BitAutoData] - public async Task PutResetPassword_WithFeatureFlagEnabled_WhenRecoverAccountFails_ReturnsBadRequest( + public async Task PutResetPassword_WhenRecoverAccountFails_ReturnsBadRequest( Guid orgId, Guid orgUserId, OrganizationUserResetPasswordRequestModel model, OrganizationUser organizationUser, SutProvider sutProvider) { organizationUser.OrganizationId = orgId; - sutProvider.GetDependency().IsEnabled(FeatureFlagKeys.AccountRecoveryCommand).Returns(true); sutProvider.GetDependency().GetByIdAsync(orgUserId).Returns(organizationUser); sutProvider.GetDependency() .AuthorizeAsync(