From 15bc5060c6893987d14cbbda7c238c159036b191 Mon Sep 17 00:00:00 2001 From: Brandon Treston Date: Thu, 7 Nov 2024 14:10:00 -0500 Subject: [PATCH] [PM-11409] prevent managed user from leaving managing organization (#4995) * prevent managed user from leaving managing organization * fix org check to be specific to single org * simplify logic --- .../Controllers/OrganizationsController.cs | 6 ++++ .../OrganizationsControllerTests.cs | 36 +++++++++++++++++-- 2 files changed, 40 insertions(+), 2 deletions(-) diff --git a/src/Api/AdminConsole/Controllers/OrganizationsController.cs b/src/Api/AdminConsole/Controllers/OrganizationsController.cs index 0b3811618..e134adc04 100644 --- a/src/Api/AdminConsole/Controllers/OrganizationsController.cs +++ b/src/Api/AdminConsole/Controllers/OrganizationsController.cs @@ -252,6 +252,12 @@ public class OrganizationsController : Controller throw new BadRequestException("Your organization's Single Sign-On settings prevent you from leaving."); } + if (_featureService.IsEnabled(FeatureFlagKeys.AccountDeprovisioning) + && (await _userService.GetOrganizationsManagingUserAsync(user.Id)).Any(x => x.Id == id)) + { + throw new BadRequestException("Managed user account cannot leave managing organization. Contact your organization administrator for additional details."); + } + await _removeOrganizationUserCommand.RemoveUserAsync(id, user.Id); } diff --git a/test/Api.Test/AdminConsole/Controllers/OrganizationsControllerTests.cs b/test/Api.Test/AdminConsole/Controllers/OrganizationsControllerTests.cs index 25227fec7..13826888d 100644 --- a/test/Api.Test/AdminConsole/Controllers/OrganizationsControllerTests.cs +++ b/test/Api.Test/AdminConsole/Controllers/OrganizationsControllerTests.cs @@ -51,7 +51,6 @@ public class OrganizationsControllerTests : IDisposable private readonly IProviderBillingService _providerBillingService; private readonly IDataProtectorTokenFactory _orgDeleteTokenDataFactory; private readonly IRemoveOrganizationUserCommand _removeOrganizationUserCommand; - private readonly OrganizationsController _sut; public OrganizationsControllerTests() @@ -123,7 +122,8 @@ public class OrganizationsControllerTests : IDisposable _currentContext.OrganizationUser(orgId).Returns(true); _ssoConfigRepository.GetByOrganizationIdAsync(orgId).Returns(ssoConfig); _userService.GetUserByPrincipalAsync(Arg.Any()).Returns(user); - + _featureService.IsEnabled(FeatureFlagKeys.AccountDeprovisioning).Returns(true); + _userService.GetOrganizationsManagingUserAsync(user.Id).Returns(new List { null }); var exception = await Assert.ThrowsAsync(() => _sut.Leave(orgId)); Assert.Contains("Your organization's Single Sign-On settings prevent you from leaving.", @@ -132,6 +132,36 @@ public class OrganizationsControllerTests : IDisposable await _removeOrganizationUserCommand.DidNotReceiveWithAnyArgs().RemoveUserAsync(default, default); } + [Theory, AutoData] + public async Task OrganizationsController_UserCannotLeaveOrganizationThatManagesUser( + Guid orgId, User user) + { + var ssoConfig = new SsoConfig + { + Id = default, + Data = new SsoConfigurationData + { + MemberDecryptionType = MemberDecryptionType.KeyConnector + }.Serialize(), + Enabled = true, + OrganizationId = orgId, + }; + var foundOrg = new Organization(); + foundOrg.Id = orgId; + + _currentContext.OrganizationUser(orgId).Returns(true); + _ssoConfigRepository.GetByOrganizationIdAsync(orgId).Returns(ssoConfig); + _userService.GetUserByPrincipalAsync(Arg.Any()).Returns(user); + _featureService.IsEnabled(FeatureFlagKeys.AccountDeprovisioning).Returns(true); + _userService.GetOrganizationsManagingUserAsync(user.Id).Returns(new List { { foundOrg } }); + var exception = await Assert.ThrowsAsync(() => _sut.Leave(orgId)); + + Assert.Contains("Managed user account cannot leave managing organization. Contact your organization administrator for additional details.", + exception.Message); + + await _removeOrganizationUserCommand.DidNotReceiveWithAnyArgs().RemoveUserAsync(default, default); + } + [Theory] [InlineAutoData(true, false)] [InlineAutoData(false, true)] @@ -157,6 +187,8 @@ public class OrganizationsControllerTests : IDisposable _currentContext.OrganizationUser(orgId).Returns(true); _ssoConfigRepository.GetByOrganizationIdAsync(orgId).Returns(ssoConfig); _userService.GetUserByPrincipalAsync(Arg.Any()).Returns(user); + _featureService.IsEnabled(FeatureFlagKeys.AccountDeprovisioning).Returns(true); + _userService.GetOrganizationsManagingUserAsync(user.Id).Returns(new List()); await _sut.Leave(orgId);