1
0
mirror of https://github.com/bitwarden/server.git synced 2025-07-02 08:32:50 -05:00

Merge branch 'main' into jmccannon/ac/pm-16811-scim-invite-optimization

# Conflicts:
#	src/Core/AdminConsole/Services/Implementations/OrganizationService.cs
#	test/Infrastructure.IntegrationTest/AdminConsole/Repositories/OrganizationUserRepositoryTests.cs
This commit is contained in:
jrmccannon
2025-03-05 15:24:13 -06:00
272 changed files with 16059 additions and 1921 deletions

View File

@ -0,0 +1,79 @@
using Bit.Core.AdminConsole.Entities;
using Bit.Core.AdminConsole.OrganizationFeatures.Organizations;
using Bit.Core.Repositories;
using Bit.Core.Services;
using Bit.Test.Common.AutoFixture;
using Bit.Test.Common.AutoFixture.Attributes;
using NSubstitute;
using Xunit;
namespace Bit.Core.Test.AdminConsole.OrganizationFeatures.Organizations;
[SutProviderCustomize]
public class OrganizationDisableCommandTests
{
[Theory, BitAutoData]
public async Task DisableAsync_WhenOrganizationEnabled_DisablesSuccessfully(
Organization organization,
DateTime expirationDate,
SutProvider<OrganizationDisableCommand> sutProvider)
{
organization.Enabled = true;
sutProvider.GetDependency<IOrganizationRepository>()
.GetByIdAsync(organization.Id)
.Returns(organization);
await sutProvider.Sut.DisableAsync(organization.Id, expirationDate);
Assert.False(organization.Enabled);
Assert.Equal(expirationDate, organization.ExpirationDate);
await sutProvider.GetDependency<IOrganizationRepository>()
.Received(1)
.ReplaceAsync(organization);
await sutProvider.GetDependency<IApplicationCacheService>()
.Received(1)
.UpsertOrganizationAbilityAsync(organization);
}
[Theory, BitAutoData]
public async Task DisableAsync_WhenOrganizationNotFound_DoesNothing(
Guid organizationId,
DateTime expirationDate,
SutProvider<OrganizationDisableCommand> sutProvider)
{
sutProvider.GetDependency<IOrganizationRepository>()
.GetByIdAsync(organizationId)
.Returns((Organization)null);
await sutProvider.Sut.DisableAsync(organizationId, expirationDate);
await sutProvider.GetDependency<IOrganizationRepository>()
.DidNotReceive()
.ReplaceAsync(Arg.Any<Organization>());
await sutProvider.GetDependency<IApplicationCacheService>()
.DidNotReceive()
.UpsertOrganizationAbilityAsync(Arg.Any<Organization>());
}
[Theory, BitAutoData]
public async Task DisableAsync_WhenOrganizationAlreadyDisabled_DoesNothing(
Organization organization,
DateTime expirationDate,
SutProvider<OrganizationDisableCommand> sutProvider)
{
organization.Enabled = false;
sutProvider.GetDependency<IOrganizationRepository>()
.GetByIdAsync(organization.Id)
.Returns(organization);
await sutProvider.Sut.DisableAsync(organization.Id, expirationDate);
await sutProvider.GetDependency<IOrganizationRepository>()
.DidNotReceive()
.ReplaceAsync(Arg.Any<Organization>());
await sutProvider.GetDependency<IApplicationCacheService>()
.DidNotReceive()
.UpsertOrganizationAbilityAsync(Arg.Any<Organization>());
}
}

View File

@ -2,6 +2,7 @@
using Bit.Core.AdminConsole.OrganizationFeatures.Organizations;
using Bit.Core.Billing.Enums;
using Bit.Core.Billing.Models.Sales;
using Bit.Core.Billing.Pricing;
using Bit.Core.Billing.Services;
using Bit.Core.Entities;
using Bit.Core.Enums;
@ -38,6 +39,8 @@ public class CloudICloudOrganizationSignUpCommandTests
signup.IsFromSecretsManagerTrial = false;
signup.IsFromProvider = false;
sutProvider.GetDependency<IPricingClient>().GetPlanOrThrow(signup.Plan).Returns(StaticStore.GetPlan(signup.Plan));
var result = await sutProvider.Sut.SignUpOrganizationAsync(signup);
await sutProvider.GetDependency<IOrganizationRepository>().Received(1).CreateAsync(
@ -66,7 +69,7 @@ public class CloudICloudOrganizationSignUpCommandTests
sale.CustomerSetup.TokenizedPaymentSource.Token == signup.PaymentToken &&
sale.CustomerSetup.TaxInformation.Country == signup.TaxInfo.BillingAddressCountry &&
sale.CustomerSetup.TaxInformation.PostalCode == signup.TaxInfo.BillingAddressPostalCode &&
sale.SubscriptionSetup.Plan == plan &&
sale.SubscriptionSetup.PlanType == plan.Type &&
sale.SubscriptionSetup.PasswordManagerOptions.Seats == signup.AdditionalSeats &&
sale.SubscriptionSetup.PasswordManagerOptions.Storage == signup.AdditionalStorageGb &&
sale.SubscriptionSetup.SecretsManagerOptions == null));
@ -84,6 +87,8 @@ public class CloudICloudOrganizationSignUpCommandTests
signup.UseSecretsManager = false;
signup.IsFromProvider = false;
sutProvider.GetDependency<IPricingClient>().GetPlanOrThrow(signup.Plan).Returns(StaticStore.GetPlan(signup.Plan));
// Extract orgUserId when created
Guid? orgUserId = null;
await sutProvider.GetDependency<IOrganizationUserRepository>()
@ -128,6 +133,7 @@ public class CloudICloudOrganizationSignUpCommandTests
signup.IsFromSecretsManagerTrial = false;
signup.IsFromProvider = false;
sutProvider.GetDependency<IPricingClient>().GetPlanOrThrow(signup.Plan).Returns(StaticStore.GetPlan(signup.Plan));
var result = await sutProvider.Sut.SignUpOrganizationAsync(signup);
@ -157,7 +163,7 @@ public class CloudICloudOrganizationSignUpCommandTests
sale.CustomerSetup.TokenizedPaymentSource.Token == signup.PaymentToken &&
sale.CustomerSetup.TaxInformation.Country == signup.TaxInfo.BillingAddressCountry &&
sale.CustomerSetup.TaxInformation.PostalCode == signup.TaxInfo.BillingAddressPostalCode &&
sale.SubscriptionSetup.Plan == plan &&
sale.SubscriptionSetup.PlanType == plan.Type &&
sale.SubscriptionSetup.PasswordManagerOptions.Seats == signup.AdditionalSeats &&
sale.SubscriptionSetup.PasswordManagerOptions.Storage == signup.AdditionalStorageGb &&
sale.SubscriptionSetup.SecretsManagerOptions.Seats == signup.AdditionalSmSeats &&
@ -177,6 +183,8 @@ public class CloudICloudOrganizationSignUpCommandTests
signup.PremiumAccessAddon = false;
signup.IsFromProvider = true;
sutProvider.GetDependency<IPricingClient>().GetPlanOrThrow(signup.Plan).Returns(StaticStore.GetPlan(signup.Plan));
var exception = await Assert.ThrowsAsync<BadRequestException>(() => sutProvider.Sut.SignUpOrganizationAsync(signup));
Assert.Contains("Organizations with a Managed Service Provider do not support Secrets Manager.", exception.Message);
}
@ -195,6 +203,8 @@ public class CloudICloudOrganizationSignUpCommandTests
signup.AdditionalStorageGb = 0;
signup.IsFromProvider = false;
sutProvider.GetDependency<IPricingClient>().GetPlanOrThrow(signup.Plan).Returns(StaticStore.GetPlan(signup.Plan));
var exception = await Assert.ThrowsAsync<BadRequestException>(
() => sutProvider.Sut.SignUpOrganizationAsync(signup));
Assert.Contains("Plan does not allow additional Machine Accounts.", exception.Message);
@ -213,6 +223,8 @@ public class CloudICloudOrganizationSignUpCommandTests
signup.AdditionalServiceAccounts = 10;
signup.IsFromProvider = false;
sutProvider.GetDependency<IPricingClient>().GetPlanOrThrow(signup.Plan).Returns(StaticStore.GetPlan(signup.Plan));
var exception = await Assert.ThrowsAsync<BadRequestException>(
() => sutProvider.Sut.SignUpOrganizationAsync(signup));
Assert.Contains("You cannot have more Secrets Manager seats than Password Manager seats", exception.Message);
@ -231,6 +243,8 @@ public class CloudICloudOrganizationSignUpCommandTests
signup.AdditionalServiceAccounts = -10;
signup.IsFromProvider = false;
sutProvider.GetDependency<IPricingClient>().GetPlanOrThrow(signup.Plan).Returns(StaticStore.GetPlan(signup.Plan));
var exception = await Assert.ThrowsAsync<BadRequestException>(
() => sutProvider.Sut.SignUpOrganizationAsync(signup));
Assert.Contains("You can't subtract Machine Accounts!", exception.Message);
@ -249,6 +263,8 @@ public class CloudICloudOrganizationSignUpCommandTests
Owner = new User { Id = Guid.NewGuid() }
};
sutProvider.GetDependency<IPricingClient>().GetPlanOrThrow(signup.Plan).Returns(StaticStore.GetPlan(signup.Plan));
sutProvider.GetDependency<IOrganizationUserRepository>()
.GetCountByFreeOrganizationAdminUserAsync(signup.Owner.Id)
.Returns(1);

View File

@ -0,0 +1,10 @@
using Bit.Core.AdminConsole.Models.Data.Organizations.Policies;
using Bit.Core.Utilities;
namespace Bit.Core.Test.AdminConsole.OrganizationFeatures.Policies.PolicyRequirements;
public static class PolicyDetailsTestExtensions
{
public static void SetDataModel<T>(this PolicyDetails policyDetails, T data) where T : IPolicyDataModel
=> policyDetails.PolicyData = CoreHelpers.ClassToJsonData(data);
}

View File

@ -0,0 +1,138 @@
using AutoFixture.Xunit2;
using Bit.Core.AdminConsole.Enums;
using Bit.Core.AdminConsole.Models.Data.Organizations.Policies;
using Bit.Core.AdminConsole.OrganizationFeatures.Policies.PolicyRequirements;
using Bit.Core.Enums;
using Bit.Core.Test.AdminConsole.AutoFixture;
using Xunit;
namespace Bit.Core.Test.AdminConsole.OrganizationFeatures.Policies.PolicyRequirements;
public class SendPolicyRequirementTests
{
[Theory, AutoData]
public void DisableSend_IsFalse_IfNoDisableSendPolicies(
[PolicyDetails(PolicyType.RequireSso)] PolicyDetails otherPolicy1,
[PolicyDetails(PolicyType.SendOptions)] PolicyDetails otherPolicy2)
{
EnableDisableHideEmail(otherPolicy2);
var actual = SendPolicyRequirement.Create([otherPolicy1, otherPolicy2]);
Assert.False(actual.DisableSend);
}
[Theory]
[InlineAutoData(OrganizationUserType.Owner, false)]
[InlineAutoData(OrganizationUserType.Admin, false)]
[InlineAutoData(OrganizationUserType.User, true)]
[InlineAutoData(OrganizationUserType.Custom, true)]
public void DisableSend_TestRoles(
OrganizationUserType userType,
bool shouldBeEnforced,
[PolicyDetails(PolicyType.DisableSend)] PolicyDetails policyDetails)
{
policyDetails.OrganizationUserType = userType;
var actual = SendPolicyRequirement.Create([policyDetails]);
Assert.Equal(shouldBeEnforced, actual.DisableSend);
}
[Theory, AutoData]
public void DisableSend_Not_EnforcedAgainstProviders(
[PolicyDetails(PolicyType.DisableSend, isProvider: true)] PolicyDetails policyDetails)
{
var actual = SendPolicyRequirement.Create([policyDetails]);
Assert.False(actual.DisableSend);
}
[Theory]
[InlineAutoData(OrganizationUserStatusType.Confirmed, true)]
[InlineAutoData(OrganizationUserStatusType.Accepted, true)]
[InlineAutoData(OrganizationUserStatusType.Invited, false)]
[InlineAutoData(OrganizationUserStatusType.Revoked, false)]
public void DisableSend_TestStatuses(
OrganizationUserStatusType userStatus,
bool shouldBeEnforced,
[PolicyDetails(PolicyType.DisableSend)] PolicyDetails policyDetails)
{
policyDetails.OrganizationUserStatus = userStatus;
var actual = SendPolicyRequirement.Create([policyDetails]);
Assert.Equal(shouldBeEnforced, actual.DisableSend);
}
[Theory, AutoData]
public void DisableHideEmail_IsFalse_IfNoSendOptionsPolicies(
[PolicyDetails(PolicyType.RequireSso)] PolicyDetails otherPolicy1,
[PolicyDetails(PolicyType.DisableSend)] PolicyDetails otherPolicy2)
{
var actual = SendPolicyRequirement.Create([otherPolicy1, otherPolicy2]);
Assert.False(actual.DisableHideEmail);
}
[Theory]
[InlineAutoData(OrganizationUserType.Owner, false)]
[InlineAutoData(OrganizationUserType.Admin, false)]
[InlineAutoData(OrganizationUserType.User, true)]
[InlineAutoData(OrganizationUserType.Custom, true)]
public void DisableHideEmail_TestRoles(
OrganizationUserType userType,
bool shouldBeEnforced,
[PolicyDetails(PolicyType.SendOptions)] PolicyDetails policyDetails)
{
EnableDisableHideEmail(policyDetails);
policyDetails.OrganizationUserType = userType;
var actual = SendPolicyRequirement.Create([policyDetails]);
Assert.Equal(shouldBeEnforced, actual.DisableHideEmail);
}
[Theory, AutoData]
public void DisableHideEmail_Not_EnforcedAgainstProviders(
[PolicyDetails(PolicyType.SendOptions, isProvider: true)] PolicyDetails policyDetails)
{
EnableDisableHideEmail(policyDetails);
var actual = SendPolicyRequirement.Create([policyDetails]);
Assert.False(actual.DisableHideEmail);
}
[Theory]
[InlineAutoData(OrganizationUserStatusType.Confirmed, true)]
[InlineAutoData(OrganizationUserStatusType.Accepted, true)]
[InlineAutoData(OrganizationUserStatusType.Invited, false)]
[InlineAutoData(OrganizationUserStatusType.Revoked, false)]
public void DisableHideEmail_TestStatuses(
OrganizationUserStatusType userStatus,
bool shouldBeEnforced,
[PolicyDetails(PolicyType.SendOptions)] PolicyDetails policyDetails)
{
EnableDisableHideEmail(policyDetails);
policyDetails.OrganizationUserStatus = userStatus;
var actual = SendPolicyRequirement.Create([policyDetails]);
Assert.Equal(shouldBeEnforced, actual.DisableHideEmail);
}
[Theory, AutoData]
public void DisableHideEmail_HandlesNullData(
[PolicyDetails(PolicyType.SendOptions)] PolicyDetails policyDetails)
{
policyDetails.PolicyData = null;
var actual = SendPolicyRequirement.Create([policyDetails]);
Assert.False(actual.DisableHideEmail);
}
private static void EnableDisableHideEmail(PolicyDetails policyDetails)
=> policyDetails.SetDataModel(new SendOptionsPolicyData { DisableHideEmail = true });
}