From 9eccb0001d9321c107edc90b7dd698c19a2088f4 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Rui=20Tom=C3=A9?= <108268980+r-tome@users.noreply.github.com> Date: Tue, 24 Feb 2026 10:54:51 +0000 Subject: [PATCH] [PM-30327] Fix SingleOrg policy not revoking non-compliant users (#7001) --- .../OrganizationUserRepository.cs | 2 +- .../Controllers/PoliciesControllerTests.cs | 43 +++++++++++++++++++ 2 files changed, 44 insertions(+), 1 deletion(-) diff --git a/src/Infrastructure.EntityFramework/AdminConsole/Repositories/OrganizationUserRepository.cs b/src/Infrastructure.EntityFramework/AdminConsole/Repositories/OrganizationUserRepository.cs index c15bd72c5b..b086b8c487 100644 --- a/src/Infrastructure.EntityFramework/AdminConsole/Repositories/OrganizationUserRepository.cs +++ b/src/Infrastructure.EntityFramework/AdminConsole/Repositories/OrganizationUserRepository.cs @@ -407,7 +407,7 @@ public class OrganizationUserRepository : Repository>(await query.ToListAsync()); } diff --git a/test/Api.IntegrationTest/AdminConsole/Controllers/PoliciesControllerTests.cs b/test/Api.IntegrationTest/AdminConsole/Controllers/PoliciesControllerTests.cs index d58538ae1c..2f749d0c85 100644 --- a/test/Api.IntegrationTest/AdminConsole/Controllers/PoliciesControllerTests.cs +++ b/test/Api.IntegrationTest/AdminConsole/Controllers/PoliciesControllerTests.cs @@ -441,4 +441,47 @@ public class PoliciesControllerTests : IClassFixture, IAs // Assert Assert.Equal(HttpStatusCode.BadRequest, response.StatusCode); } + + [Fact] + public async Task Put_SingleOrgPolicy_RevokesNonCompliantUser() + { + // Arrange + // Create a second organization (Org B) with its own owner + var orgBOwnerEmail = $"integration-test{Guid.NewGuid()}@bitwarden.com"; + await _factory.LoginWithNewAccount(orgBOwnerEmail); + var (orgB, _) = await OrganizationTestHelpers.SignUpAsync(_factory, plan: PlanType.EnterpriseAnnually, + ownerEmail: orgBOwnerEmail, passwordManagerSeats: 10, paymentMethod: PaymentMethodType.Card); + + // Create a user that belongs to both Org A and Org B + var multiOrgUserEmail = $"integration-test{Guid.NewGuid()}@bitwarden.com"; + await _factory.LoginWithNewAccount(multiOrgUserEmail); + + var orgUserInOrgA = await OrganizationTestHelpers.CreateUserAsync(_factory, _organization.Id, + multiOrgUserEmail, OrganizationUserType.User); + await OrganizationTestHelpers.CreateUserAsync(_factory, orgB.Id, + multiOrgUserEmail, OrganizationUserType.User); + + // Re-authenticate as the owner of Org A + await _loginHelper.LoginAsync(_ownerEmail); + + var request = new PolicyRequestModel + { + Enabled = true, + Data = null + }; + + // Act - Enable Single Org policy on Org A + var response = await _client.PutAsync( + $"/organizations/{_organization.Id}/policies/{PolicyType.SingleOrg}", + JsonContent.Create(request)); + + // Assert + Assert.Equal(HttpStatusCode.OK, response.StatusCode); + + // Verify the multi-org user was revoked in Org A + var organizationUserRepository = _factory.GetService(); + var updatedOrgUser = await organizationUserRepository.GetByIdAsync(orgUserInOrgA.Id); + Assert.NotNull(updatedOrgUser); + Assert.Equal(OrganizationUserStatusType.Revoked, updatedOrgUser.Status); + } }