1
0
mirror of https://github.com/bitwarden/server synced 2026-01-06 18:43:36 +00:00

[PM-22241] Add DefaultUserCollectionName support to bulk organization user confirmation (#6153)

* Implement GetByOrganizationAsync method in PolicyRequirementQuery and add corresponding unit tests

* Refactor ConfirmOrganizationUserCommand for clarity and add bulk support

* Update ConfirmOrganizationUserCommandTests to use GetByOrganizationAsync for policy requirement queries

* Add DefaultUserCollectionName property to OrganizationUserBulkConfirmRequestModel with encryption attributes

* Update ConfirmUsersAsync method to include DefaultUserCollectionName parameter in OrganizationUsersController

* Add EnableOrganizationDataOwnershipPolicyAsync method to OrganizationTestHelpers

* Add integration tests for confirming organization users in OrganizationUserControllerTests

- Implemented Confirm_WithValidUser test to verify successful confirmation of a single user.
- Added BulkConfirm_WithValidUsers test to ensure multiple users can be confirmed successfully.

* Refactor organization user confirmation integration tests to also test when the organization data ownership policy is disabled

* Refactor ConfirmOrganizationUserCommand to consolidate confirmation side effects handling

- Replaced single and bulk confirmation side effect methods with a unified HandleConfirmationSideEffectsAsync method.
- Updated related logic to handle confirmed organization users more efficiently.
- Adjusted unit tests to reflect changes in the collection creation process for confirmed users.

* Refactor OrganizationUserControllerTests to simplify feature flag handling and consolidate test logic

- Removed redundant feature flag checks in Confirm and BulkConfirm tests.
- Updated tests to directly enable the Organization Data Ownership policy without conditional checks.
- Ensured verification of DefaultUserCollection for confirmed users remains intact.

* Refactor OrganizationUserControllerTests to enhance clarity and reduce redundancy

- Simplified user creation and confirmation logic in tests by introducing helper methods.
- Consolidated verification of confirmed users and their associated collections.
- Removed unnecessary comments and streamlined test flow for better readability.
This commit is contained in:
Rui Tomé
2025-08-05 15:34:13 +01:00
committed by GitHub
parent 11cc50af6e
commit 7454430aa1
10 changed files with 294 additions and 48 deletions

View File

@@ -79,4 +79,73 @@ public class PolicyRequirementQueryTests
Assert.Empty(requirement.Policies);
}
[Theory, BitAutoData]
public async Task GetByOrganizationAsync_IgnoresOtherPolicyTypes(Guid organizationId)
{
var policyRepository = Substitute.For<IPolicyRepository>();
var thisPolicy = new OrganizationPolicyDetails { PolicyType = PolicyType.SingleOrg, UserId = Guid.NewGuid() };
var otherPolicy = new OrganizationPolicyDetails { PolicyType = PolicyType.RequireSso, UserId = Guid.NewGuid() };
// Force the repository to return both policies even though that is not the expected result
policyRepository.GetPolicyDetailsByOrganizationIdAsync(organizationId, PolicyType.SingleOrg)
.Returns([thisPolicy, otherPolicy]);
var factory = new TestPolicyRequirementFactory(_ => true);
var sut = new PolicyRequirementQuery(policyRepository, [factory]);
var requirement = await sut.GetByOrganizationAsync<TestPolicyRequirement>(organizationId);
await policyRepository.Received(1).GetPolicyDetailsByOrganizationIdAsync(organizationId, PolicyType.SingleOrg);
Assert.Contains(thisPolicy, requirement.Policies.Cast<OrganizationPolicyDetails>());
Assert.DoesNotContain(otherPolicy, requirement.Policies.Cast<OrganizationPolicyDetails>());
}
[Theory, BitAutoData]
public async Task GetByOrganizationAsync_CallsEnforceCallback(Guid organizationId)
{
var policyRepository = Substitute.For<IPolicyRepository>();
var thisPolicy = new OrganizationPolicyDetails { PolicyType = PolicyType.SingleOrg, UserId = Guid.NewGuid() };
var otherPolicy = new OrganizationPolicyDetails { PolicyType = PolicyType.SingleOrg, UserId = Guid.NewGuid() };
policyRepository.GetPolicyDetailsByOrganizationIdAsync(organizationId, PolicyType.SingleOrg).Returns([thisPolicy, otherPolicy]);
var callback = Substitute.For<Func<PolicyDetails, bool>>();
callback(Arg.Any<PolicyDetails>()).Returns(x => x.Arg<PolicyDetails>() == thisPolicy);
var factory = new TestPolicyRequirementFactory(callback);
var sut = new PolicyRequirementQuery(policyRepository, [factory]);
var requirement = await sut.GetByOrganizationAsync<TestPolicyRequirement>(organizationId);
Assert.Contains(thisPolicy, requirement.Policies.Cast<OrganizationPolicyDetails>());
Assert.DoesNotContain(otherPolicy, requirement.Policies.Cast<OrganizationPolicyDetails>());
callback.Received()(Arg.Is<PolicyDetails>(p => p == thisPolicy));
callback.Received()(Arg.Is<PolicyDetails>(p => p == otherPolicy));
}
[Theory, BitAutoData]
public async Task GetByOrganizationAsync_ThrowsIfNoFactoryRegistered(Guid organizationId)
{
var policyRepository = Substitute.For<IPolicyRepository>();
var sut = new PolicyRequirementQuery(policyRepository, []);
var exception = await Assert.ThrowsAsync<NotImplementedException>(()
=> sut.GetByOrganizationAsync<TestPolicyRequirement>(organizationId));
Assert.Contains("No Requirement Factory found", exception.Message);
}
[Theory, BitAutoData]
public async Task GetByOrganizationAsync_HandlesNoPolicies(Guid organizationId)
{
var policyRepository = Substitute.For<IPolicyRepository>();
policyRepository.GetPolicyDetailsByOrganizationIdAsync(organizationId, PolicyType.SingleOrg).Returns([]);
var factory = new TestPolicyRequirementFactory(x => x.IsProvider);
var sut = new PolicyRequirementQuery(policyRepository, [factory]);
var requirement = await sut.GetByOrganizationAsync<TestPolicyRequirement>(organizationId);
Assert.Empty(requirement.Policies);
}
}