mirror of
https://github.com/bitwarden/server.git
synced 2024-11-21 12:05:42 +01:00
Split Organization.LimitCollectionCreationDeletion
into two separate business rules (#4730)
* Add feature flag * Promoted the new Entiy Framework properties * Deprecate the old property * Update references * Fix mispelling * Re-add contextual comment regarding dropped license properties * Add back deleted assertion for deprecated property * Add back removed fixture property assignment * Improve feature toggling scenerios for self hosted org creation/update * Unblock `PutCollectionManagement` for self host * Simplify logic of a couple of conditionals * Feature toggle route unblocking * Adjust logic collection creation/deletion authorization handler * Create tests * Fix bug caught by tests * Fix bugs caught during manual testing * Remove remark about license
This commit is contained in:
parent
4fec7cadb7
commit
91409a45f0
@ -1,4 +1,6 @@
|
|||||||
@model OrganizationViewModel
|
@inject Bit.Core.Services.IFeatureService FeatureService
|
||||||
|
@model OrganizationViewModel
|
||||||
|
|
||||||
<dl class="row">
|
<dl class="row">
|
||||||
<dt class="col-sm-4 col-lg-3">Id</dt>
|
<dt class="col-sm-4 col-lg-3">Id</dt>
|
||||||
<dd id="org-id" class="col-sm-8 col-lg-9"><code>@Model.Organization.Id</code></dd>
|
<dd id="org-id" class="col-sm-8 col-lg-9"><code>@Model.Organization.Id</code></dd>
|
||||||
@ -53,8 +55,19 @@
|
|||||||
<dt class="col-sm-4 col-lg-3">Administrators manage all collections</dt>
|
<dt class="col-sm-4 col-lg-3">Administrators manage all collections</dt>
|
||||||
<dd id="pm-manage-collections" class="col-sm-8 col-lg-9">@(Model.Organization.AllowAdminAccessToAllCollectionItems ? "On" : "Off")</dd>
|
<dd id="pm-manage-collections" class="col-sm-8 col-lg-9">@(Model.Organization.AllowAdminAccessToAllCollectionItems ? "On" : "Off")</dd>
|
||||||
|
|
||||||
<dt class="col-sm-4 col-lg-3">Limit collection creation to administrators</dt>
|
@if (!FeatureService.IsEnabled(Bit.Core.FeatureFlagKeys.LimitCollectionCreationDeletionSplit))
|
||||||
<dd id="pm-collection-creation" class="col-sm-8 col-lg-9">@(Model.Organization.LimitCollectionCreationDeletion ? "On" : "Off")</dd>
|
{
|
||||||
|
<dt class="col-sm-4 col-lg-3">Limit collection creation to administrators</dt>
|
||||||
|
<dd id="pm-collection-creation" class="col-sm-8 col-lg-9">@(Model.Organization.LimitCollectionCreationDeletion ? "On" : "Off")</dd>
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
<dt class="col-sm-4 col-lg-3">Limit collection creation to administrators</dt>
|
||||||
|
<dd id="pm-collection-creation" class="col-sm-8 col-lg-9">@(Model.Organization.LimitCollectionCreation ? "On" : "Off")</dd>
|
||||||
|
|
||||||
|
<dt class="col-sm-4 col-lg-3">Limit collection deletion to administrators</dt>
|
||||||
|
<dd id="pm-collection-deletion" class="col-sm-8 col-lg-9">@(Model.Organization.LimitCollectionDeletion ? "On" : "Off")</dd>
|
||||||
|
}
|
||||||
</dl>
|
</dl>
|
||||||
|
|
||||||
<h2>Secrets Manager</h2>
|
<h2>Secrets Manager</h2>
|
||||||
|
@ -520,9 +520,16 @@ public class OrganizationsController : Controller
|
|||||||
}
|
}
|
||||||
|
|
||||||
[HttpPut("{id}/collection-management")]
|
[HttpPut("{id}/collection-management")]
|
||||||
[SelfHosted(NotSelfHostedOnly = true)]
|
|
||||||
public async Task<OrganizationResponseModel> PutCollectionManagement(Guid id, [FromBody] OrganizationCollectionManagementUpdateRequestModel model)
|
public async Task<OrganizationResponseModel> PutCollectionManagement(Guid id, [FromBody] OrganizationCollectionManagementUpdateRequestModel model)
|
||||||
{
|
{
|
||||||
|
if (
|
||||||
|
_globalSettings.SelfHosted &&
|
||||||
|
!_featureService.IsEnabled(FeatureFlagKeys.LimitCollectionCreationDeletionSplit)
|
||||||
|
)
|
||||||
|
{
|
||||||
|
throw new BadRequestException("Only allowed when not self hosted.");
|
||||||
|
}
|
||||||
|
|
||||||
var organization = await _organizationRepository.GetByIdAsync(id);
|
var organization = await _organizationRepository.GetByIdAsync(id);
|
||||||
if (organization == null)
|
if (organization == null)
|
||||||
{
|
{
|
||||||
@ -534,7 +541,7 @@ public class OrganizationsController : Controller
|
|||||||
throw new NotFoundException();
|
throw new NotFoundException();
|
||||||
}
|
}
|
||||||
|
|
||||||
await _organizationService.UpdateAsync(model.ToOrganization(organization), eventType: EventType.Organization_CollectionManagement_Updated);
|
await _organizationService.UpdateAsync(model.ToOrganization(organization, _featureService), eventType: EventType.Organization_CollectionManagement_Updated);
|
||||||
return new OrganizationResponseModel(organization);
|
return new OrganizationResponseModel(organization);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -55,6 +55,9 @@ public class OrganizationResponseModel : ResponseModel
|
|||||||
SmServiceAccounts = organization.SmServiceAccounts;
|
SmServiceAccounts = organization.SmServiceAccounts;
|
||||||
MaxAutoscaleSmSeats = organization.MaxAutoscaleSmSeats;
|
MaxAutoscaleSmSeats = organization.MaxAutoscaleSmSeats;
|
||||||
MaxAutoscaleSmServiceAccounts = organization.MaxAutoscaleSmServiceAccounts;
|
MaxAutoscaleSmServiceAccounts = organization.MaxAutoscaleSmServiceAccounts;
|
||||||
|
LimitCollectionCreation = organization.LimitCollectionCreation;
|
||||||
|
LimitCollectionDeletion = organization.LimitCollectionDeletion;
|
||||||
|
// Deprecated: https://bitwarden.atlassian.net/browse/PM-10863
|
||||||
LimitCollectionCreationDeletion = organization.LimitCollectionCreationDeletion;
|
LimitCollectionCreationDeletion = organization.LimitCollectionCreationDeletion;
|
||||||
AllowAdminAccessToAllCollectionItems = organization.AllowAdminAccessToAllCollectionItems;
|
AllowAdminAccessToAllCollectionItems = organization.AllowAdminAccessToAllCollectionItems;
|
||||||
}
|
}
|
||||||
@ -98,6 +101,9 @@ public class OrganizationResponseModel : ResponseModel
|
|||||||
public int? SmServiceAccounts { get; set; }
|
public int? SmServiceAccounts { get; set; }
|
||||||
public int? MaxAutoscaleSmSeats { get; set; }
|
public int? MaxAutoscaleSmSeats { get; set; }
|
||||||
public int? MaxAutoscaleSmServiceAccounts { get; set; }
|
public int? MaxAutoscaleSmServiceAccounts { get; set; }
|
||||||
|
public bool LimitCollectionCreation { get; set; }
|
||||||
|
public bool LimitCollectionDeletion { get; set; }
|
||||||
|
// Deperectated: https://bitwarden.atlassian.net/browse/PM-10863
|
||||||
public bool LimitCollectionCreationDeletion { get; set; }
|
public bool LimitCollectionCreationDeletion { get; set; }
|
||||||
public bool AllowAdminAccessToAllCollectionItems { get; set; }
|
public bool AllowAdminAccessToAllCollectionItems { get; set; }
|
||||||
}
|
}
|
||||||
|
@ -65,6 +65,9 @@ public class ProfileOrganizationResponseModel : ResponseModel
|
|||||||
FamilySponsorshipToDelete = organization.FamilySponsorshipToDelete;
|
FamilySponsorshipToDelete = organization.FamilySponsorshipToDelete;
|
||||||
FamilySponsorshipValidUntil = organization.FamilySponsorshipValidUntil;
|
FamilySponsorshipValidUntil = organization.FamilySponsorshipValidUntil;
|
||||||
AccessSecretsManager = organization.AccessSecretsManager;
|
AccessSecretsManager = organization.AccessSecretsManager;
|
||||||
|
LimitCollectionCreation = organization.LimitCollectionCreation;
|
||||||
|
LimitCollectionDeletion = organization.LimitCollectionDeletion;
|
||||||
|
// Deprecated: https://bitwarden.atlassian.net/browse/PM-10863
|
||||||
LimitCollectionCreationDeletion = organization.LimitCollectionCreationDeletion;
|
LimitCollectionCreationDeletion = organization.LimitCollectionCreationDeletion;
|
||||||
AllowAdminAccessToAllCollectionItems = organization.AllowAdminAccessToAllCollectionItems;
|
AllowAdminAccessToAllCollectionItems = organization.AllowAdminAccessToAllCollectionItems;
|
||||||
UserIsManagedByOrganization = organizationIdsManagingUser.Contains(organization.OrganizationId);
|
UserIsManagedByOrganization = organizationIdsManagingUser.Contains(organization.OrganizationId);
|
||||||
@ -124,6 +127,9 @@ public class ProfileOrganizationResponseModel : ResponseModel
|
|||||||
public DateTime? FamilySponsorshipValidUntil { get; set; }
|
public DateTime? FamilySponsorshipValidUntil { get; set; }
|
||||||
public bool? FamilySponsorshipToDelete { get; set; }
|
public bool? FamilySponsorshipToDelete { get; set; }
|
||||||
public bool AccessSecretsManager { get; set; }
|
public bool AccessSecretsManager { get; set; }
|
||||||
|
public bool LimitCollectionCreation { get; set; }
|
||||||
|
public bool LimitCollectionDeletion { get; set; }
|
||||||
|
// Deprecated: https://bitwarden.atlassian.net/browse/PM-10863
|
||||||
public bool LimitCollectionCreationDeletion { get; set; }
|
public bool LimitCollectionCreationDeletion { get; set; }
|
||||||
public bool AllowAdminAccessToAllCollectionItems { get; set; }
|
public bool AllowAdminAccessToAllCollectionItems { get; set; }
|
||||||
/// <summary>
|
/// <summary>
|
||||||
|
@ -44,6 +44,9 @@ public class ProfileProviderOrganizationResponseModel : ProfileOrganizationRespo
|
|||||||
ProviderId = organization.ProviderId;
|
ProviderId = organization.ProviderId;
|
||||||
ProviderName = organization.ProviderName;
|
ProviderName = organization.ProviderName;
|
||||||
ProductTierType = StaticStore.GetPlan(organization.PlanType).ProductTier;
|
ProductTierType = StaticStore.GetPlan(organization.PlanType).ProductTier;
|
||||||
|
LimitCollectionCreation = organization.LimitCollectionCreation;
|
||||||
|
LimitCollectionDeletion = organization.LimitCollectionDeletion;
|
||||||
|
// https://bitwarden.atlassian.net/browse/PM-10863
|
||||||
LimitCollectionCreationDeletion = organization.LimitCollectionCreationDeletion;
|
LimitCollectionCreationDeletion = organization.LimitCollectionCreationDeletion;
|
||||||
AllowAdminAccessToAllCollectionItems = organization.AllowAdminAccessToAllCollectionItems;
|
AllowAdminAccessToAllCollectionItems = organization.AllowAdminAccessToAllCollectionItems;
|
||||||
}
|
}
|
||||||
|
@ -1,15 +1,29 @@
|
|||||||
using Bit.Core.AdminConsole.Entities;
|
using Bit.Core;
|
||||||
|
using Bit.Core.AdminConsole.Entities;
|
||||||
|
using Bit.Core.Services;
|
||||||
|
|
||||||
namespace Bit.Api.Models.Request.Organizations;
|
namespace Bit.Api.Models.Request.Organizations;
|
||||||
|
|
||||||
public class OrganizationCollectionManagementUpdateRequestModel
|
public class OrganizationCollectionManagementUpdateRequestModel
|
||||||
{
|
{
|
||||||
|
public bool LimitCollectionCreation { get; set; }
|
||||||
|
public bool LimitCollectionDeletion { get; set; }
|
||||||
|
// Deprecated: https://bitwarden.atlassian.net/browse/PM-10863
|
||||||
public bool LimitCreateDeleteOwnerAdmin { get; set; }
|
public bool LimitCreateDeleteOwnerAdmin { get; set; }
|
||||||
public bool AllowAdminAccessToAllCollectionItems { get; set; }
|
public bool AllowAdminAccessToAllCollectionItems { get; set; }
|
||||||
|
|
||||||
public virtual Organization ToOrganization(Organization existingOrganization)
|
public virtual Organization ToOrganization(Organization existingOrganization, IFeatureService featureService)
|
||||||
{
|
{
|
||||||
existingOrganization.LimitCollectionCreationDeletion = LimitCreateDeleteOwnerAdmin;
|
if (featureService.IsEnabled(FeatureFlagKeys.LimitCollectionCreationDeletionSplit))
|
||||||
|
{
|
||||||
|
existingOrganization.LimitCollectionCreation = LimitCollectionCreation;
|
||||||
|
existingOrganization.LimitCollectionDeletion = LimitCollectionDeletion;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
existingOrganization.LimitCollectionCreationDeletion = LimitCreateDeleteOwnerAdmin || LimitCollectionCreation || LimitCollectionDeletion;
|
||||||
|
}
|
||||||
|
|
||||||
existingOrganization.AllowAdminAccessToAllCollectionItems = AllowAdminAccessToAllCollectionItems;
|
existingOrganization.AllowAdminAccessToAllCollectionItems = AllowAdminAccessToAllCollectionItems;
|
||||||
return existingOrganization;
|
return existingOrganization;
|
||||||
}
|
}
|
||||||
|
@ -1,5 +1,6 @@
|
|||||||
#nullable enable
|
#nullable enable
|
||||||
using System.Diagnostics;
|
using System.Diagnostics;
|
||||||
|
using Bit.Core;
|
||||||
using Bit.Core.Context;
|
using Bit.Core.Context;
|
||||||
using Bit.Core.Entities;
|
using Bit.Core.Entities;
|
||||||
using Bit.Core.Enums;
|
using Bit.Core.Enums;
|
||||||
@ -101,7 +102,7 @@ public class BulkCollectionAuthorizationHandler : BulkAuthorizationHandler<BulkC
|
|||||||
break;
|
break;
|
||||||
|
|
||||||
case null:
|
case null:
|
||||||
// requirement isn't actually nullable but since we use the
|
// requirement isn't actually nullable but since we use the
|
||||||
// not null when trick it makes the compiler think that requirement
|
// not null when trick it makes the compiler think that requirement
|
||||||
// could actually be nullable.
|
// could actually be nullable.
|
||||||
throw new UnreachableException();
|
throw new UnreachableException();
|
||||||
@ -123,10 +124,24 @@ public class BulkCollectionAuthorizationHandler : BulkAuthorizationHandler<BulkC
|
|||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
// If the limit collection management setting is disabled, allow any user to create collections
|
if (_featureService.IsEnabled(FeatureFlagKeys.LimitCollectionCreationDeletionSplit))
|
||||||
if (await GetOrganizationAbilityAsync(org) is { LimitCollectionCreationDeletion: false })
|
|
||||||
{
|
{
|
||||||
return true;
|
var userIsMemberOfOrg = org is not null;
|
||||||
|
var limitCollectionCreationEnabled = await GetOrganizationAbilityAsync(org) is { LimitCollectionCreation: true };
|
||||||
|
var userIsOrgOwnerOrAdmin = org is { Type: OrganizationUserType.Owner or OrganizationUserType.Admin };
|
||||||
|
// If the limit collection management setting is disabled, allow any user to create collections
|
||||||
|
if (userIsMemberOfOrg && (!limitCollectionCreationEnabled || userIsOrgOwnerOrAdmin))
|
||||||
|
{
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
// If the limit collection management setting is disabled, allow any user to create collections
|
||||||
|
if (await GetOrganizationAbilityAsync(org) is { LimitCollectionCreationDeletion: false })
|
||||||
|
{
|
||||||
|
return true;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// Allow provider users to create collections if they are a provider for the target organization
|
// Allow provider users to create collections if they are a provider for the target organization
|
||||||
@ -246,21 +261,35 @@ public class BulkCollectionAuthorizationHandler : BulkAuthorizationHandler<BulkC
|
|||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
// If AllowAdminAccessToAllCollectionItems is true, Owners and Admins can delete any collection, regardless of LimitCollectionCreationDeletion setting
|
// If AllowAdminAccessToAllCollectionItems is true, Owners and Admins can delete any collection, regardless of LimitCollectionDeletion setting
|
||||||
if (await AllowAdminAccessToAllCollectionItems(org) && org is { Type: OrganizationUserType.Owner or OrganizationUserType.Admin })
|
if (await AllowAdminAccessToAllCollectionItems(org) && org is { Type: OrganizationUserType.Owner or OrganizationUserType.Admin })
|
||||||
{
|
{
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
// If LimitCollectionCreationDeletion is false, AllowAdminAccessToAllCollectionItems setting is irrelevant.
|
if (_featureService.IsEnabled(FeatureFlagKeys.LimitCollectionCreationDeletionSplit))
|
||||||
// Ensure acting user has manage permissions for all collections being deleted
|
|
||||||
// If LimitCollectionCreationDeletion is true, only Owners and Admins can delete collections they manage
|
|
||||||
var organizationAbility = await GetOrganizationAbilityAsync(org);
|
|
||||||
var canDeleteManagedCollections = organizationAbility is { LimitCollectionCreationDeletion: false } ||
|
|
||||||
org is { Type: OrganizationUserType.Owner or OrganizationUserType.Admin };
|
|
||||||
if (canDeleteManagedCollections && await CanManageCollectionsAsync(resources, org))
|
|
||||||
{
|
{
|
||||||
return true;
|
var userIsMemberOfOrg = org is not null;
|
||||||
|
var limitCollectionDeletionEnabled = await GetOrganizationAbilityAsync(org) is { LimitCollectionDeletion: true };
|
||||||
|
var userIsOrgOwnerOrAdmin = org is { Type: OrganizationUserType.Owner or OrganizationUserType.Admin };
|
||||||
|
// If the limit collection management setting is disabled, allow any user to delete collections
|
||||||
|
if (userIsMemberOfOrg && (!limitCollectionDeletionEnabled || userIsOrgOwnerOrAdmin) && await CanManageCollectionsAsync(resources, org))
|
||||||
|
{
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
// If LimitCollectionCreationDeletion is false, AllowAdminAccessToAllCollectionItems setting is irrelevant.
|
||||||
|
// Ensure acting user has manage permissions for all collections being deleted
|
||||||
|
// If LimitCollectionCreationDeletion is true, only Owners and Admins can delete collections they manage
|
||||||
|
var organizationAbility = await GetOrganizationAbilityAsync(org);
|
||||||
|
var canDeleteManagedCollections = organizationAbility is { LimitCollectionCreationDeletion: false } ||
|
||||||
|
org is { Type: OrganizationUserType.Owner or OrganizationUserType.Admin };
|
||||||
|
if (canDeleteManagedCollections && await CanManageCollectionsAsync(resources, org))
|
||||||
|
{
|
||||||
|
return true;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// Allow providers to delete collections if they are a provider for the target organization
|
// Allow providers to delete collections if they are a provider for the target organization
|
||||||
|
@ -7,6 +7,7 @@ using Bit.Core.Billing.Enums;
|
|||||||
using Bit.Core.Entities;
|
using Bit.Core.Entities;
|
||||||
using Bit.Core.Enums;
|
using Bit.Core.Enums;
|
||||||
using Bit.Core.Models.Business;
|
using Bit.Core.Models.Business;
|
||||||
|
using Bit.Core.Services;
|
||||||
using Bit.Core.Tools.Entities;
|
using Bit.Core.Tools.Entities;
|
||||||
using Bit.Core.Utilities;
|
using Bit.Core.Utilities;
|
||||||
|
|
||||||
@ -93,7 +94,20 @@ public class Organization : ITableObject<Guid>, IStorableSubscriber, IRevisable,
|
|||||||
/// If set to false, any organization member can create a collection, and any member can delete a collection that
|
/// If set to false, any organization member can create a collection, and any member can delete a collection that
|
||||||
/// they have Can Manage permissions for.
|
/// they have Can Manage permissions for.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
public bool LimitCollectionCreationDeletion { get; set; }
|
public bool LimitCollectionCreation { get; set; }
|
||||||
|
public bool LimitCollectionDeletion { get; set; }
|
||||||
|
// Deprecated by https://bitwarden.atlassian.net/browse/PM-10863. This
|
||||||
|
// was replaced with `LimitCollectionCreation` and
|
||||||
|
// `LimitCollectionDeletion`.
|
||||||
|
public bool LimitCollectionCreationDeletion
|
||||||
|
{
|
||||||
|
get => LimitCollectionCreation || LimitCollectionDeletion;
|
||||||
|
set
|
||||||
|
{
|
||||||
|
LimitCollectionCreation = value;
|
||||||
|
LimitCollectionDeletion = value;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// If set to true, admins, owners, and some custom users can read/write all collections and items in the Admin Console.
|
/// If set to true, admins, owners, and some custom users can read/write all collections and items in the Admin Console.
|
||||||
@ -265,7 +279,7 @@ public class Organization : ITableObject<Guid>, IStorableSubscriber, IRevisable,
|
|||||||
return providers[provider];
|
return providers[provider];
|
||||||
}
|
}
|
||||||
|
|
||||||
public void UpdateFromLicense(OrganizationLicense license)
|
public void UpdateFromLicense(OrganizationLicense license, IFeatureService featureService)
|
||||||
{
|
{
|
||||||
// The following properties are intentionally excluded from being updated:
|
// The following properties are intentionally excluded from being updated:
|
||||||
// - Id - self-hosted org will have its own unique Guid
|
// - Id - self-hosted org will have its own unique Guid
|
||||||
@ -300,7 +314,11 @@ public class Organization : ITableObject<Guid>, IStorableSubscriber, IRevisable,
|
|||||||
UseSecretsManager = license.UseSecretsManager;
|
UseSecretsManager = license.UseSecretsManager;
|
||||||
SmSeats = license.SmSeats;
|
SmSeats = license.SmSeats;
|
||||||
SmServiceAccounts = license.SmServiceAccounts;
|
SmServiceAccounts = license.SmServiceAccounts;
|
||||||
LimitCollectionCreationDeletion = license.LimitCollectionCreationDeletion;
|
|
||||||
AllowAdminAccessToAllCollectionItems = license.AllowAdminAccessToAllCollectionItems;
|
if (!featureService.IsEnabled(FeatureFlagKeys.LimitCollectionCreationDeletionSplit))
|
||||||
|
{
|
||||||
|
LimitCollectionCreationDeletion = license.LimitCollectionCreationDeletion;
|
||||||
|
AllowAdminAccessToAllCollectionItems = license.AllowAdminAccessToAllCollectionItems;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -21,6 +21,9 @@ public class OrganizationAbility
|
|||||||
UseResetPassword = organization.UseResetPassword;
|
UseResetPassword = organization.UseResetPassword;
|
||||||
UseCustomPermissions = organization.UseCustomPermissions;
|
UseCustomPermissions = organization.UseCustomPermissions;
|
||||||
UsePolicies = organization.UsePolicies;
|
UsePolicies = organization.UsePolicies;
|
||||||
|
LimitCollectionCreation = organization.LimitCollectionCreation;
|
||||||
|
LimitCollectionDeletion = organization.LimitCollectionDeletion;
|
||||||
|
// Deprecated: https://bitwarden.atlassian.net/browse/PM-10863
|
||||||
LimitCollectionCreationDeletion = organization.LimitCollectionCreationDeletion;
|
LimitCollectionCreationDeletion = organization.LimitCollectionCreationDeletion;
|
||||||
AllowAdminAccessToAllCollectionItems = organization.AllowAdminAccessToAllCollectionItems;
|
AllowAdminAccessToAllCollectionItems = organization.AllowAdminAccessToAllCollectionItems;
|
||||||
}
|
}
|
||||||
@ -37,6 +40,9 @@ public class OrganizationAbility
|
|||||||
public bool UseResetPassword { get; set; }
|
public bool UseResetPassword { get; set; }
|
||||||
public bool UseCustomPermissions { get; set; }
|
public bool UseCustomPermissions { get; set; }
|
||||||
public bool UsePolicies { get; set; }
|
public bool UsePolicies { get; set; }
|
||||||
|
public bool LimitCollectionCreation { get; set; }
|
||||||
|
public bool LimitCollectionDeletion { get; set; }
|
||||||
|
// Deprecated: https://bitwarden.atlassian.net/browse/PM-10863
|
||||||
public bool LimitCollectionCreationDeletion { get; set; }
|
public bool LimitCollectionCreationDeletion { get; set; }
|
||||||
public bool AllowAdminAccessToAllCollectionItems { get; set; }
|
public bool AllowAdminAccessToAllCollectionItems { get; set; }
|
||||||
}
|
}
|
||||||
|
@ -54,6 +54,9 @@ public class OrganizationUserOrganizationDetails
|
|||||||
public bool UsePasswordManager { get; set; }
|
public bool UsePasswordManager { get; set; }
|
||||||
public int? SmSeats { get; set; }
|
public int? SmSeats { get; set; }
|
||||||
public int? SmServiceAccounts { get; set; }
|
public int? SmServiceAccounts { get; set; }
|
||||||
|
public bool LimitCollectionCreation { get; set; }
|
||||||
|
public bool LimitCollectionDeletion { get; set; }
|
||||||
|
// Deprecated: https://bitwarden.atlassian.net/browse/PM-10863
|
||||||
public bool LimitCollectionCreationDeletion { get; set; }
|
public bool LimitCollectionCreationDeletion { get; set; }
|
||||||
public bool AllowAdminAccessToAllCollectionItems { get; set; }
|
public bool AllowAdminAccessToAllCollectionItems { get; set; }
|
||||||
}
|
}
|
||||||
|
@ -144,6 +144,9 @@ public class SelfHostedOrganizationDetails : Organization
|
|||||||
RevisionDate = RevisionDate,
|
RevisionDate = RevisionDate,
|
||||||
MaxAutoscaleSeats = MaxAutoscaleSeats,
|
MaxAutoscaleSeats = MaxAutoscaleSeats,
|
||||||
OwnersNotifiedOfAutoscaling = OwnersNotifiedOfAutoscaling,
|
OwnersNotifiedOfAutoscaling = OwnersNotifiedOfAutoscaling,
|
||||||
|
LimitCollectionCreation = LimitCollectionCreation,
|
||||||
|
LimitCollectionDeletion = LimitCollectionDeletion,
|
||||||
|
// Deprecated: https://bitwarden.atlassian.net/browse/PM-10863
|
||||||
LimitCollectionCreationDeletion = LimitCollectionCreationDeletion,
|
LimitCollectionCreationDeletion = LimitCollectionCreationDeletion,
|
||||||
AllowAdminAccessToAllCollectionItems = AllowAdminAccessToAllCollectionItems,
|
AllowAdminAccessToAllCollectionItems = AllowAdminAccessToAllCollectionItems,
|
||||||
Status = Status
|
Status = Status
|
||||||
|
@ -40,6 +40,8 @@ public class ProviderUserOrganizationDetails
|
|||||||
[JsonConverter(typeof(HtmlEncodingStringConverter))]
|
[JsonConverter(typeof(HtmlEncodingStringConverter))]
|
||||||
public string ProviderName { get; set; }
|
public string ProviderName { get; set; }
|
||||||
public PlanType PlanType { get; set; }
|
public PlanType PlanType { get; set; }
|
||||||
|
public bool LimitCollectionCreation { get; set; }
|
||||||
|
public bool LimitCollectionDeletion { get; set; }
|
||||||
public bool LimitCollectionCreationDeletion { get; set; }
|
public bool LimitCollectionCreationDeletion { get; set; }
|
||||||
public bool AllowAdminAccessToAllCollectionItems { get; set; }
|
public bool AllowAdminAccessToAllCollectionItems { get; set; }
|
||||||
}
|
}
|
||||||
|
@ -708,10 +708,16 @@ public class OrganizationService : IOrganizationService
|
|||||||
UseSecretsManager = license.UseSecretsManager,
|
UseSecretsManager = license.UseSecretsManager,
|
||||||
SmSeats = license.SmSeats,
|
SmSeats = license.SmSeats,
|
||||||
SmServiceAccounts = license.SmServiceAccounts,
|
SmServiceAccounts = license.SmServiceAccounts,
|
||||||
LimitCollectionCreationDeletion = license.LimitCollectionCreationDeletion,
|
|
||||||
AllowAdminAccessToAllCollectionItems = license.AllowAdminAccessToAllCollectionItems,
|
|
||||||
};
|
};
|
||||||
|
|
||||||
|
// These fields are being removed from consideration when processing
|
||||||
|
// licenses.
|
||||||
|
if (!_featureService.IsEnabled(FeatureFlagKeys.LimitCollectionCreationDeletionSplit))
|
||||||
|
{
|
||||||
|
organization.LimitCollectionCreationDeletion = license.LimitCollectionCreationDeletion;
|
||||||
|
organization.AllowAdminAccessToAllCollectionItems = license.AllowAdminAccessToAllCollectionItems;
|
||||||
|
}
|
||||||
|
|
||||||
var result = await SignUpAsync(organization, owner.Id, ownerKey, collectionName, false);
|
var result = await SignUpAsync(organization, owner.Id, ownerKey, collectionName, false);
|
||||||
|
|
||||||
var dir = $"{_globalSettings.LicenseDirectory}/organization";
|
var dir = $"{_globalSettings.LicenseDirectory}/organization";
|
||||||
|
@ -146,6 +146,7 @@ public static class FeatureFlagKeys
|
|||||||
public const string RemoveServerVersionHeader = "remove-server-version-header";
|
public const string RemoveServerVersionHeader = "remove-server-version-header";
|
||||||
public const string AccessIntelligence = "pm-13227-access-intelligence";
|
public const string AccessIntelligence = "pm-13227-access-intelligence";
|
||||||
public const string VerifiedSsoDomainEndpoint = "pm-12337-refactor-sso-details-endpoint";
|
public const string VerifiedSsoDomainEndpoint = "pm-12337-refactor-sso-details-endpoint";
|
||||||
|
public const string LimitCollectionCreationDeletionSplit = "pm-10863-limit-collection-creation-deletion-split";
|
||||||
|
|
||||||
public static List<string> GetAllKeys()
|
public static List<string> GetAllKeys()
|
||||||
{
|
{
|
||||||
|
@ -53,8 +53,11 @@ public class OrganizationLicense : ILicense
|
|||||||
UseSecretsManager = org.UseSecretsManager;
|
UseSecretsManager = org.UseSecretsManager;
|
||||||
SmSeats = org.SmSeats;
|
SmSeats = org.SmSeats;
|
||||||
SmServiceAccounts = org.SmServiceAccounts;
|
SmServiceAccounts = org.SmServiceAccounts;
|
||||||
|
|
||||||
|
// Deprecated. Left for backwards compatibility with old license versions.
|
||||||
LimitCollectionCreationDeletion = org.LimitCollectionCreationDeletion;
|
LimitCollectionCreationDeletion = org.LimitCollectionCreationDeletion;
|
||||||
AllowAdminAccessToAllCollectionItems = org.AllowAdminAccessToAllCollectionItems;
|
AllowAdminAccessToAllCollectionItems = org.AllowAdminAccessToAllCollectionItems;
|
||||||
|
//
|
||||||
|
|
||||||
if (subscriptionInfo?.Subscription == null)
|
if (subscriptionInfo?.Subscription == null)
|
||||||
{
|
{
|
||||||
@ -138,8 +141,12 @@ public class OrganizationLicense : ILicense
|
|||||||
public bool UseSecretsManager { get; set; }
|
public bool UseSecretsManager { get; set; }
|
||||||
public int? SmSeats { get; set; }
|
public int? SmSeats { get; set; }
|
||||||
public int? SmServiceAccounts { get; set; }
|
public int? SmServiceAccounts { get; set; }
|
||||||
|
|
||||||
|
// Deprecated. Left for backwards compatibility with old license versions.
|
||||||
public bool LimitCollectionCreationDeletion { get; set; } = true;
|
public bool LimitCollectionCreationDeletion { get; set; } = true;
|
||||||
public bool AllowAdminAccessToAllCollectionItems { get; set; } = true;
|
public bool AllowAdminAccessToAllCollectionItems { get; set; } = true;
|
||||||
|
//
|
||||||
|
|
||||||
public bool Trial { get; set; }
|
public bool Trial { get; set; }
|
||||||
public LicenseType? LicenseType { get; set; }
|
public LicenseType? LicenseType { get; set; }
|
||||||
public string Hash { get; set; }
|
public string Hash { get; set; }
|
||||||
@ -150,7 +157,8 @@ public class OrganizationLicense : ILicense
|
|||||||
/// Represents the current version of the license format. Should be updated whenever new fields are added.
|
/// Represents the current version of the license format. Should be updated whenever new fields are added.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
/// <remarks>Intentionally set one version behind to allow self hosted users some time to update before
|
/// <remarks>Intentionally set one version behind to allow self hosted users some time to update before
|
||||||
/// getting out of date license errors</remarks>
|
/// getting out of date license errors
|
||||||
|
/// </remarks>
|
||||||
public const int CurrentLicenseFileVersion = 14;
|
public const int CurrentLicenseFileVersion = 14;
|
||||||
private bool ValidLicenseVersion
|
private bool ValidLicenseVersion
|
||||||
{
|
{
|
||||||
@ -368,10 +376,11 @@ public class OrganizationLicense : ILicense
|
|||||||
}
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Version 14 added LimitCollectionCreationDeletion and Version 15 added AllowAdminAccessToAllCollectionItems,
|
* Version 14 added LimitCollectionCreationDeletion and Version
|
||||||
* however these are just user settings and it is not worth failing validation if they mismatch.
|
* 15 added AllowAdminAccessToAllCollectionItems, however they
|
||||||
* They are intentionally excluded.
|
* are no longer used and are intentionally excluded from
|
||||||
*/
|
* validation.
|
||||||
|
*/
|
||||||
|
|
||||||
return valid;
|
return valid;
|
||||||
}
|
}
|
||||||
|
@ -17,15 +17,18 @@ public class UpdateOrganizationLicenseCommand : IUpdateOrganizationLicenseComman
|
|||||||
private readonly ILicensingService _licensingService;
|
private readonly ILicensingService _licensingService;
|
||||||
private readonly IGlobalSettings _globalSettings;
|
private readonly IGlobalSettings _globalSettings;
|
||||||
private readonly IOrganizationService _organizationService;
|
private readonly IOrganizationService _organizationService;
|
||||||
|
private readonly IFeatureService _featureService;
|
||||||
|
|
||||||
public UpdateOrganizationLicenseCommand(
|
public UpdateOrganizationLicenseCommand(
|
||||||
ILicensingService licensingService,
|
ILicensingService licensingService,
|
||||||
IGlobalSettings globalSettings,
|
IGlobalSettings globalSettings,
|
||||||
IOrganizationService organizationService)
|
IOrganizationService organizationService,
|
||||||
|
IFeatureService featureService)
|
||||||
{
|
{
|
||||||
_licensingService = licensingService;
|
_licensingService = licensingService;
|
||||||
_globalSettings = globalSettings;
|
_globalSettings = globalSettings;
|
||||||
_organizationService = organizationService;
|
_organizationService = organizationService;
|
||||||
|
_featureService = featureService;
|
||||||
}
|
}
|
||||||
|
|
||||||
public async Task UpdateLicenseAsync(SelfHostedOrganizationDetails selfHostedOrganization,
|
public async Task UpdateLicenseAsync(SelfHostedOrganizationDetails selfHostedOrganization,
|
||||||
@ -59,7 +62,8 @@ public class UpdateOrganizationLicenseCommand : IUpdateOrganizationLicenseComman
|
|||||||
private async Task UpdateOrganizationAsync(SelfHostedOrganizationDetails selfHostedOrganizationDetails, OrganizationLicense license)
|
private async Task UpdateOrganizationAsync(SelfHostedOrganizationDetails selfHostedOrganizationDetails, OrganizationLicense license)
|
||||||
{
|
{
|
||||||
var organization = selfHostedOrganizationDetails.ToOrganization();
|
var organization = selfHostedOrganizationDetails.ToOrganization();
|
||||||
organization.UpdateFromLicense(license);
|
|
||||||
|
organization.UpdateFromLicense(license, _featureService);
|
||||||
|
|
||||||
await _organizationService.ReplaceAndUpdateCacheAsync(organization);
|
await _organizationService.ReplaceAndUpdateCacheAsync(organization);
|
||||||
}
|
}
|
||||||
|
@ -9,10 +9,6 @@ namespace Bit.Infrastructure.EntityFramework.AdminConsole.Models;
|
|||||||
|
|
||||||
public class Organization : Core.AdminConsole.Entities.Organization
|
public class Organization : Core.AdminConsole.Entities.Organization
|
||||||
{
|
{
|
||||||
// Shadow properties - to be introduced by https://bitwarden.atlassian.net/browse/PM-10863
|
|
||||||
public bool LimitCollectionCreation { get => LimitCollectionCreationDeletion; set => LimitCollectionCreationDeletion = value; }
|
|
||||||
public bool LimitCollectionDeletion { get => LimitCollectionCreationDeletion; set => LimitCollectionCreationDeletion = value; }
|
|
||||||
|
|
||||||
public virtual ICollection<Cipher> Ciphers { get; set; }
|
public virtual ICollection<Cipher> Ciphers { get; set; }
|
||||||
public virtual ICollection<OrganizationUser> OrganizationUsers { get; set; }
|
public virtual ICollection<OrganizationUser> OrganizationUsers { get; set; }
|
||||||
public virtual ICollection<Group> Groups { get; set; }
|
public virtual ICollection<Group> Groups { get; set; }
|
||||||
@ -42,9 +38,6 @@ public class OrganizationMapperProfile : Profile
|
|||||||
.ForMember(org => org.ApiKeys, opt => opt.Ignore())
|
.ForMember(org => org.ApiKeys, opt => opt.Ignore())
|
||||||
.ForMember(org => org.Connections, opt => opt.Ignore())
|
.ForMember(org => org.Connections, opt => opt.Ignore())
|
||||||
.ForMember(org => org.Domains, opt => opt.Ignore())
|
.ForMember(org => org.Domains, opt => opt.Ignore())
|
||||||
// Shadow properties - to be introduced by https://bitwarden.atlassian.net/browse/PM-10863
|
|
||||||
.ForMember(org => org.LimitCollectionCreation, opt => opt.Ignore())
|
|
||||||
.ForMember(org => org.LimitCollectionDeletion, opt => opt.Ignore())
|
|
||||||
.ReverseMap();
|
.ReverseMap();
|
||||||
|
|
||||||
CreateProjection<Organization, SelfHostedOrganizationDetails>()
|
CreateProjection<Organization, SelfHostedOrganizationDetails>()
|
||||||
|
@ -99,6 +99,9 @@ public class OrganizationRepository : Repository<Core.AdminConsole.Entities.Orga
|
|||||||
UseScim = e.UseScim,
|
UseScim = e.UseScim,
|
||||||
UseCustomPermissions = e.UseCustomPermissions,
|
UseCustomPermissions = e.UseCustomPermissions,
|
||||||
UsePolicies = e.UsePolicies,
|
UsePolicies = e.UsePolicies,
|
||||||
|
LimitCollectionCreation = e.LimitCollectionCreation,
|
||||||
|
LimitCollectionDeletion = e.LimitCollectionDeletion,
|
||||||
|
// Deprecated: https://bitwarden.atlassian.net/browse/PM-10863
|
||||||
LimitCollectionCreationDeletion = e.LimitCollectionCreationDeletion,
|
LimitCollectionCreationDeletion = e.LimitCollectionCreationDeletion,
|
||||||
AllowAdminAccessToAllCollectionItems = e.AllowAdminAccessToAllCollectionItems
|
AllowAdminAccessToAllCollectionItems = e.AllowAdminAccessToAllCollectionItems
|
||||||
}).ToListAsync();
|
}).ToListAsync();
|
||||||
|
@ -66,6 +66,9 @@ public class OrganizationUserOrganizationDetailsViewQuery : IQuery<OrganizationU
|
|||||||
UsePasswordManager = o.UsePasswordManager,
|
UsePasswordManager = o.UsePasswordManager,
|
||||||
SmSeats = o.SmSeats,
|
SmSeats = o.SmSeats,
|
||||||
SmServiceAccounts = o.SmServiceAccounts,
|
SmServiceAccounts = o.SmServiceAccounts,
|
||||||
|
LimitCollectionCreation = o.LimitCollectionCreation,
|
||||||
|
LimitCollectionDeletion = o.LimitCollectionDeletion,
|
||||||
|
// Deprecated: https://bitwarden.atlassian.net/browse/PM-10863
|
||||||
LimitCollectionCreationDeletion = o.LimitCollectionCreationDeletion,
|
LimitCollectionCreationDeletion = o.LimitCollectionCreationDeletion,
|
||||||
AllowAdminAccessToAllCollectionItems = o.AllowAdminAccessToAllCollectionItems,
|
AllowAdminAccessToAllCollectionItems = o.AllowAdminAccessToAllCollectionItems,
|
||||||
};
|
};
|
||||||
|
@ -44,6 +44,9 @@ public class ProviderUserOrganizationDetailsViewQuery : IQuery<ProviderUserOrgan
|
|||||||
ProviderId = x.p.Id,
|
ProviderId = x.p.Id,
|
||||||
ProviderName = x.p.Name,
|
ProviderName = x.p.Name,
|
||||||
PlanType = x.o.PlanType,
|
PlanType = x.o.PlanType,
|
||||||
|
LimitCollectionCreation = x.o.LimitCollectionCreation,
|
||||||
|
LimitCollectionDeletion = x.o.LimitCollectionDeletion,
|
||||||
|
// Deprecated: https://bitwarden.atlassian.net/browse/PM-10863
|
||||||
LimitCollectionCreationDeletion = x.o.LimitCollectionCreationDeletion,
|
LimitCollectionCreationDeletion = x.o.LimitCollectionCreationDeletion,
|
||||||
AllowAdminAccessToAllCollectionItems = x.o.AllowAdminAccessToAllCollectionItems,
|
AllowAdminAccessToAllCollectionItems = x.o.AllowAdminAccessToAllCollectionItems,
|
||||||
});
|
});
|
||||||
|
@ -1,5 +1,6 @@
|
|||||||
using System.Security.Claims;
|
using System.Security.Claims;
|
||||||
using Bit.Api.Vault.AuthorizationHandlers.Collections;
|
using Bit.Api.Vault.AuthorizationHandlers.Collections;
|
||||||
|
using Bit.Core;
|
||||||
using Bit.Core.Context;
|
using Bit.Core.Context;
|
||||||
using Bit.Core.Entities;
|
using Bit.Core.Entities;
|
||||||
using Bit.Core.Enums;
|
using Bit.Core.Enums;
|
||||||
@ -32,7 +33,10 @@ public class BulkCollectionAuthorizationHandlerTests
|
|||||||
organization.Type = userType;
|
organization.Type = userType;
|
||||||
organization.Permissions = new Permissions();
|
organization.Permissions = new Permissions();
|
||||||
|
|
||||||
ArrangeOrganizationAbility(sutProvider, organization, true);
|
// `LimitCollectonCreationDeletionSplit` feature flag state isn't
|
||||||
|
// relevant for this test. The flag is never checked for in this
|
||||||
|
// test. This is asserted below.
|
||||||
|
ArrangeOrganizationAbility_WithLimitCollectionCreationDeletionSplitFeatureEnabled(sutProvider, organization, true, true);
|
||||||
|
|
||||||
var context = new AuthorizationHandlerContext(
|
var context = new AuthorizationHandlerContext(
|
||||||
new[] { BulkCollectionOperations.Create },
|
new[] { BulkCollectionOperations.Create },
|
||||||
@ -44,11 +48,12 @@ public class BulkCollectionAuthorizationHandlerTests
|
|||||||
|
|
||||||
await sutProvider.Sut.HandleAsync(context);
|
await sutProvider.Sut.HandleAsync(context);
|
||||||
|
|
||||||
|
sutProvider.GetDependency<IFeatureService>().DidNotReceiveWithAnyArgs().IsEnabled(FeatureFlagKeys.LimitCollectionCreationDeletionSplit);
|
||||||
Assert.True(context.HasSucceeded);
|
Assert.True(context.HasSucceeded);
|
||||||
}
|
}
|
||||||
|
|
||||||
[Theory, BitAutoData, CollectionCustomization]
|
[Theory, BitAutoData, CollectionCustomization]
|
||||||
public async Task CanCreateAsync_WhenUser_WithLimitCollectionCreationDeletionFalse_Success(
|
public async Task CanCreateAsync_WhenUser_WithLimitCollectionCreationFalse_WithLimitCollectionCreationDeletionSplitFeatureDisabled_Success(
|
||||||
SutProvider<BulkCollectionAuthorizationHandler> sutProvider,
|
SutProvider<BulkCollectionAuthorizationHandler> sutProvider,
|
||||||
ICollection<Collection> collections,
|
ICollection<Collection> collections,
|
||||||
CurrentContextOrganization organization)
|
CurrentContextOrganization organization)
|
||||||
@ -57,7 +62,7 @@ public class BulkCollectionAuthorizationHandlerTests
|
|||||||
|
|
||||||
organization.Type = OrganizationUserType.User;
|
organization.Type = OrganizationUserType.User;
|
||||||
|
|
||||||
ArrangeOrganizationAbility(sutProvider, organization, false);
|
ArrangeOrganizationAbility_WithLimitCollectionCreationDeletionSplitFeatureDisabled(sutProvider, organization, false, false);
|
||||||
|
|
||||||
var context = new AuthorizationHandlerContext(
|
var context = new AuthorizationHandlerContext(
|
||||||
new[] { BulkCollectionOperations.Create },
|
new[] { BulkCollectionOperations.Create },
|
||||||
@ -66,16 +71,49 @@ public class BulkCollectionAuthorizationHandlerTests
|
|||||||
|
|
||||||
sutProvider.GetDependency<ICurrentContext>().UserId.Returns(actingUserId);
|
sutProvider.GetDependency<ICurrentContext>().UserId.Returns(actingUserId);
|
||||||
sutProvider.GetDependency<ICurrentContext>().GetOrganization(organization.Id).Returns(organization);
|
sutProvider.GetDependency<ICurrentContext>().GetOrganization(organization.Id).Returns(organization);
|
||||||
|
sutProvider.GetDependency<IFeatureService>()
|
||||||
|
.IsEnabled(FeatureFlagKeys.LimitCollectionCreationDeletionSplit)
|
||||||
|
.Returns(false);
|
||||||
|
|
||||||
await sutProvider.Sut.HandleAsync(context);
|
await sutProvider.Sut.HandleAsync(context);
|
||||||
|
|
||||||
|
sutProvider.GetDependency<IFeatureService>().Received(1).IsEnabled(FeatureFlagKeys.LimitCollectionCreationDeletionSplit);
|
||||||
|
Assert.True(context.HasSucceeded);
|
||||||
|
}
|
||||||
|
|
||||||
|
[Theory, BitAutoData, CollectionCustomization]
|
||||||
|
public async Task CanCreateAsync_WhenUser_WithLimitCollectionCreationFalse_WithLimitCollectionCreationDeletionSplitFeatureEnabled_Success(
|
||||||
|
SutProvider<BulkCollectionAuthorizationHandler> sutProvider,
|
||||||
|
ICollection<Collection> collections,
|
||||||
|
CurrentContextOrganization organization)
|
||||||
|
{
|
||||||
|
var actingUserId = Guid.NewGuid();
|
||||||
|
|
||||||
|
organization.Type = OrganizationUserType.User;
|
||||||
|
|
||||||
|
ArrangeOrganizationAbility_WithLimitCollectionCreationDeletionSplitFeatureEnabled(sutProvider, organization, false, false);
|
||||||
|
|
||||||
|
var context = new AuthorizationHandlerContext(
|
||||||
|
new[] { BulkCollectionOperations.Create },
|
||||||
|
new ClaimsPrincipal(),
|
||||||
|
collections);
|
||||||
|
|
||||||
|
sutProvider.GetDependency<ICurrentContext>().UserId.Returns(actingUserId);
|
||||||
|
sutProvider.GetDependency<ICurrentContext>().GetOrganization(organization.Id).Returns(organization);
|
||||||
|
sutProvider.GetDependency<IFeatureService>()
|
||||||
|
.IsEnabled(FeatureFlagKeys.LimitCollectionCreationDeletionSplit)
|
||||||
|
.Returns(true);
|
||||||
|
|
||||||
|
await sutProvider.Sut.HandleAsync(context);
|
||||||
|
|
||||||
|
sutProvider.GetDependency<IFeatureService>().Received(1).IsEnabled(FeatureFlagKeys.LimitCollectionCreationDeletionSplit);
|
||||||
Assert.True(context.HasSucceeded);
|
Assert.True(context.HasSucceeded);
|
||||||
}
|
}
|
||||||
|
|
||||||
[Theory, CollectionCustomization]
|
[Theory, CollectionCustomization]
|
||||||
[BitAutoData(OrganizationUserType.User)]
|
[BitAutoData(OrganizationUserType.User)]
|
||||||
[BitAutoData(OrganizationUserType.Custom)]
|
[BitAutoData(OrganizationUserType.Custom)]
|
||||||
public async Task CanCreateAsync_WhenMissingPermissions_NoSuccess(
|
public async Task CanCreateAsync_WhenMissingPermissions_WithLimitCollectionCreationDeletionSplitFeatureDisabled_NoSuccess(
|
||||||
OrganizationUserType userType,
|
OrganizationUserType userType,
|
||||||
SutProvider<BulkCollectionAuthorizationHandler> sutProvider,
|
SutProvider<BulkCollectionAuthorizationHandler> sutProvider,
|
||||||
ICollection<Collection> collections,
|
ICollection<Collection> collections,
|
||||||
@ -92,7 +130,7 @@ public class BulkCollectionAuthorizationHandlerTests
|
|||||||
ManageUsers = false
|
ManageUsers = false
|
||||||
};
|
};
|
||||||
|
|
||||||
ArrangeOrganizationAbility(sutProvider, organization, true);
|
ArrangeOrganizationAbility_WithLimitCollectionCreationDeletionSplitFeatureDisabled(sutProvider, organization, true, true);
|
||||||
|
|
||||||
var context = new AuthorizationHandlerContext(
|
var context = new AuthorizationHandlerContext(
|
||||||
new[] { BulkCollectionOperations.Create },
|
new[] { BulkCollectionOperations.Create },
|
||||||
@ -102,21 +140,61 @@ public class BulkCollectionAuthorizationHandlerTests
|
|||||||
sutProvider.GetDependency<ICurrentContext>().UserId.Returns(actingUserId);
|
sutProvider.GetDependency<ICurrentContext>().UserId.Returns(actingUserId);
|
||||||
sutProvider.GetDependency<ICurrentContext>().GetOrganization(organization.Id).Returns(organization);
|
sutProvider.GetDependency<ICurrentContext>().GetOrganization(organization.Id).Returns(organization);
|
||||||
sutProvider.GetDependency<ICurrentContext>().ProviderUserForOrgAsync(Arg.Any<Guid>()).Returns(false);
|
sutProvider.GetDependency<ICurrentContext>().ProviderUserForOrgAsync(Arg.Any<Guid>()).Returns(false);
|
||||||
|
sutProvider.GetDependency<IFeatureService>().IsEnabled(FeatureFlagKeys.LimitCollectionCreationDeletionSplit).Returns(false);
|
||||||
|
|
||||||
await sutProvider.Sut.HandleAsync(context);
|
await sutProvider.Sut.HandleAsync(context);
|
||||||
|
|
||||||
|
sutProvider.GetDependency<IFeatureService>().Received(1).IsEnabled(FeatureFlagKeys.LimitCollectionCreationDeletionSplit);
|
||||||
|
Assert.False(context.HasSucceeded);
|
||||||
|
}
|
||||||
|
|
||||||
|
[Theory, CollectionCustomization]
|
||||||
|
[BitAutoData(OrganizationUserType.User)]
|
||||||
|
[BitAutoData(OrganizationUserType.Custom)]
|
||||||
|
public async Task CanCreateAsync_WhenMissingPermissions_WithLimitCollectionCreationDeletionSplitFeatureEnabled_NoSuccess(
|
||||||
|
OrganizationUserType userType,
|
||||||
|
SutProvider<BulkCollectionAuthorizationHandler> sutProvider,
|
||||||
|
ICollection<Collection> collections,
|
||||||
|
CurrentContextOrganization organization)
|
||||||
|
{
|
||||||
|
var actingUserId = Guid.NewGuid();
|
||||||
|
|
||||||
|
organization.Type = userType;
|
||||||
|
organization.Permissions = new Permissions
|
||||||
|
{
|
||||||
|
EditAnyCollection = false,
|
||||||
|
DeleteAnyCollection = false,
|
||||||
|
ManageGroups = false,
|
||||||
|
ManageUsers = false
|
||||||
|
};
|
||||||
|
|
||||||
|
ArrangeOrganizationAbility_WithLimitCollectionCreationDeletionSplitFeatureEnabled(sutProvider, organization, true, true);
|
||||||
|
|
||||||
|
var context = new AuthorizationHandlerContext(
|
||||||
|
new[] { BulkCollectionOperations.Create },
|
||||||
|
new ClaimsPrincipal(),
|
||||||
|
collections);
|
||||||
|
|
||||||
|
sutProvider.GetDependency<ICurrentContext>().UserId.Returns(actingUserId);
|
||||||
|
sutProvider.GetDependency<ICurrentContext>().GetOrganization(organization.Id).Returns(organization);
|
||||||
|
sutProvider.GetDependency<ICurrentContext>().ProviderUserForOrgAsync(Arg.Any<Guid>()).Returns(false);
|
||||||
|
sutProvider.GetDependency<IFeatureService>().IsEnabled(FeatureFlagKeys.LimitCollectionCreationDeletionSplit).Returns(true);
|
||||||
|
|
||||||
|
await sutProvider.Sut.HandleAsync(context);
|
||||||
|
|
||||||
|
sutProvider.GetDependency<IFeatureService>().Received(1).IsEnabled(FeatureFlagKeys.LimitCollectionCreationDeletionSplit);
|
||||||
Assert.False(context.HasSucceeded);
|
Assert.False(context.HasSucceeded);
|
||||||
}
|
}
|
||||||
|
|
||||||
[Theory, BitAutoData, CollectionCustomization]
|
[Theory, BitAutoData, CollectionCustomization]
|
||||||
public async Task CanCreateAsync_WhenMissingOrgAccess_NoSuccess(
|
public async Task CanCreateAsync_WhenMissingOrgAccess_WithLimitCollectionCreationDeletionSplitDisabled_NoSuccess(
|
||||||
Guid userId,
|
Guid userId,
|
||||||
CurrentContextOrganization organization,
|
CurrentContextOrganization organization,
|
||||||
List<Collection> collections,
|
List<Collection> collections,
|
||||||
SutProvider<BulkCollectionAuthorizationHandler> sutProvider)
|
SutProvider<BulkCollectionAuthorizationHandler> sutProvider)
|
||||||
{
|
{
|
||||||
collections.ForEach(c => c.OrganizationId = organization.Id);
|
collections.ForEach(c => c.OrganizationId = organization.Id);
|
||||||
ArrangeOrganizationAbility(sutProvider, organization, true);
|
ArrangeOrganizationAbility_WithLimitCollectionCreationDeletionSplitFeatureDisabled(sutProvider, organization, true, true);
|
||||||
|
|
||||||
var context = new AuthorizationHandlerContext(
|
var context = new AuthorizationHandlerContext(
|
||||||
new[] { BulkCollectionOperations.Create },
|
new[] { BulkCollectionOperations.Create },
|
||||||
@ -127,8 +205,38 @@ public class BulkCollectionAuthorizationHandlerTests
|
|||||||
sutProvider.GetDependency<ICurrentContext>().UserId.Returns(userId);
|
sutProvider.GetDependency<ICurrentContext>().UserId.Returns(userId);
|
||||||
sutProvider.GetDependency<ICurrentContext>().GetOrganization(Arg.Any<Guid>()).Returns((CurrentContextOrganization)null);
|
sutProvider.GetDependency<ICurrentContext>().GetOrganization(Arg.Any<Guid>()).Returns((CurrentContextOrganization)null);
|
||||||
sutProvider.GetDependency<ICurrentContext>().ProviderUserForOrgAsync(Arg.Any<Guid>()).Returns(false);
|
sutProvider.GetDependency<ICurrentContext>().ProviderUserForOrgAsync(Arg.Any<Guid>()).Returns(false);
|
||||||
|
sutProvider.GetDependency<IFeatureService>().IsEnabled(FeatureFlagKeys.LimitCollectionCreationDeletionSplit).Returns(false);
|
||||||
|
|
||||||
await sutProvider.Sut.HandleAsync(context);
|
await sutProvider.Sut.HandleAsync(context);
|
||||||
|
|
||||||
|
sutProvider.GetDependency<IFeatureService>().Received(1).IsEnabled(FeatureFlagKeys.LimitCollectionCreationDeletionSplit);
|
||||||
|
Assert.False(context.HasSucceeded);
|
||||||
|
}
|
||||||
|
|
||||||
|
[Theory, BitAutoData, CollectionCustomization]
|
||||||
|
public async Task CanCreateAsync_WhenMissingOrgAccess_WithLimitCollectionCreationDeletionSplitEnabled_NoSuccess(
|
||||||
|
Guid userId,
|
||||||
|
CurrentContextOrganization organization,
|
||||||
|
List<Collection> collections,
|
||||||
|
SutProvider<BulkCollectionAuthorizationHandler> sutProvider)
|
||||||
|
{
|
||||||
|
collections.ForEach(c => c.OrganizationId = organization.Id);
|
||||||
|
ArrangeOrganizationAbility_WithLimitCollectionCreationDeletionSplitFeatureEnabled(sutProvider, organization, true, true);
|
||||||
|
|
||||||
|
var context = new AuthorizationHandlerContext(
|
||||||
|
new[] { BulkCollectionOperations.Create },
|
||||||
|
new ClaimsPrincipal(),
|
||||||
|
collections
|
||||||
|
);
|
||||||
|
|
||||||
|
sutProvider.GetDependency<ICurrentContext>().UserId.Returns(userId);
|
||||||
|
sutProvider.GetDependency<ICurrentContext>().GetOrganization(Arg.Any<Guid>()).Returns((CurrentContextOrganization)null);
|
||||||
|
sutProvider.GetDependency<ICurrentContext>().ProviderUserForOrgAsync(Arg.Any<Guid>()).Returns(false);
|
||||||
|
sutProvider.GetDependency<IFeatureService>().IsEnabled(FeatureFlagKeys.LimitCollectionCreationDeletionSplit).Returns(true);
|
||||||
|
|
||||||
|
await sutProvider.Sut.HandleAsync(context);
|
||||||
|
|
||||||
|
sutProvider.GetDependency<IFeatureService>().Received(1).IsEnabled(FeatureFlagKeys.LimitCollectionCreationDeletionSplit);
|
||||||
Assert.False(context.HasSucceeded);
|
Assert.False(context.HasSucceeded);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -904,7 +1012,10 @@ public class BulkCollectionAuthorizationHandlerTests
|
|||||||
DeleteAnyCollection = true
|
DeleteAnyCollection = true
|
||||||
};
|
};
|
||||||
|
|
||||||
ArrangeOrganizationAbility(sutProvider, organization, true);
|
// `LimitCollectonCreationDeletionSplit` feature flag state isn't
|
||||||
|
// relevant for this test. The flag is never checked for in this
|
||||||
|
// test. This is asserted below.
|
||||||
|
ArrangeOrganizationAbility_WithLimitCollectionCreationDeletionSplitFeatureEnabled(sutProvider, organization, true, true);
|
||||||
|
|
||||||
var context = new AuthorizationHandlerContext(
|
var context = new AuthorizationHandlerContext(
|
||||||
new[] { BulkCollectionOperations.Delete },
|
new[] { BulkCollectionOperations.Delete },
|
||||||
@ -916,6 +1027,7 @@ public class BulkCollectionAuthorizationHandlerTests
|
|||||||
|
|
||||||
await sutProvider.Sut.HandleAsync(context);
|
await sutProvider.Sut.HandleAsync(context);
|
||||||
|
|
||||||
|
sutProvider.GetDependency<IFeatureService>().DidNotReceiveWithAnyArgs().IsEnabled(FeatureFlagKeys.LimitCollectionCreationDeletionSplit);
|
||||||
Assert.True(context.HasSucceeded);
|
Assert.True(context.HasSucceeded);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -931,7 +1043,10 @@ public class BulkCollectionAuthorizationHandlerTests
|
|||||||
organization.Type = userType;
|
organization.Type = userType;
|
||||||
organization.Permissions = new Permissions();
|
organization.Permissions = new Permissions();
|
||||||
|
|
||||||
ArrangeOrganizationAbility(sutProvider, organization, true);
|
// `LimitCollectonCreationDeletionSplit` feature flag state isn't
|
||||||
|
// relevant for this test. The flag is never checked for in this
|
||||||
|
// test. This is asserted below.
|
||||||
|
ArrangeOrganizationAbility_WithLimitCollectionCreationDeletionSplitFeatureEnabled(sutProvider, organization, true, true);
|
||||||
|
|
||||||
var context = new AuthorizationHandlerContext(
|
var context = new AuthorizationHandlerContext(
|
||||||
new[] { BulkCollectionOperations.Delete },
|
new[] { BulkCollectionOperations.Delete },
|
||||||
@ -943,11 +1058,12 @@ public class BulkCollectionAuthorizationHandlerTests
|
|||||||
|
|
||||||
await sutProvider.Sut.HandleAsync(context);
|
await sutProvider.Sut.HandleAsync(context);
|
||||||
|
|
||||||
|
sutProvider.GetDependency<IFeatureService>().DidNotReceiveWithAnyArgs().IsEnabled(FeatureFlagKeys.LimitCollectionCreationDeletionSplit);
|
||||||
Assert.True(context.HasSucceeded);
|
Assert.True(context.HasSucceeded);
|
||||||
}
|
}
|
||||||
|
|
||||||
[Theory, BitAutoData, CollectionCustomization]
|
[Theory, BitAutoData, CollectionCustomization]
|
||||||
public async Task CanDeleteAsync_WhenUser_LimitCollectionCreationDeletionFalse_WithCanManagePermission_Success(
|
public async Task CanDeleteAsync_WhenUser_LimitCollectionDeletionFalse_WithCanManagePermission_WithLimitCollectionCreationDeletionSplitFeatureDisabled_Success(
|
||||||
SutProvider<BulkCollectionAuthorizationHandler> sutProvider,
|
SutProvider<BulkCollectionAuthorizationHandler> sutProvider,
|
||||||
ICollection<CollectionDetails> collections,
|
ICollection<CollectionDetails> collections,
|
||||||
CurrentContextOrganization organization)
|
CurrentContextOrganization organization)
|
||||||
@ -957,11 +1073,12 @@ public class BulkCollectionAuthorizationHandlerTests
|
|||||||
organization.Type = OrganizationUserType.User;
|
organization.Type = OrganizationUserType.User;
|
||||||
organization.Permissions = new Permissions();
|
organization.Permissions = new Permissions();
|
||||||
|
|
||||||
ArrangeOrganizationAbility(sutProvider, organization, false);
|
ArrangeOrganizationAbility_WithLimitCollectionCreationDeletionSplitFeatureDisabled(sutProvider, organization, false, false);
|
||||||
|
|
||||||
sutProvider.GetDependency<ICurrentContext>().UserId.Returns(actingUserId);
|
sutProvider.GetDependency<ICurrentContext>().UserId.Returns(actingUserId);
|
||||||
sutProvider.GetDependency<ICurrentContext>().GetOrganization(organization.Id).Returns(organization);
|
sutProvider.GetDependency<ICurrentContext>().GetOrganization(organization.Id).Returns(organization);
|
||||||
sutProvider.GetDependency<ICollectionRepository>().GetManyByUserIdAsync(actingUserId).Returns(collections);
|
sutProvider.GetDependency<ICollectionRepository>().GetManyByUserIdAsync(actingUserId).Returns(collections);
|
||||||
|
sutProvider.GetDependency<IFeatureService>().IsEnabled(FeatureFlagKeys.LimitCollectionCreationDeletionSplit).Returns(false);
|
||||||
|
|
||||||
foreach (var c in collections)
|
foreach (var c in collections)
|
||||||
{
|
{
|
||||||
@ -975,6 +1092,41 @@ public class BulkCollectionAuthorizationHandlerTests
|
|||||||
|
|
||||||
await sutProvider.Sut.HandleAsync(context);
|
await sutProvider.Sut.HandleAsync(context);
|
||||||
|
|
||||||
|
sutProvider.GetDependency<IFeatureService>().Received(1).IsEnabled(FeatureFlagKeys.LimitCollectionCreationDeletionSplit);
|
||||||
|
Assert.True(context.HasSucceeded);
|
||||||
|
}
|
||||||
|
|
||||||
|
[Theory, BitAutoData, CollectionCustomization]
|
||||||
|
public async Task CanDeleteAsync_WhenUser_LimitCollectionDeletionFalse_WithCanManagePermission_WithLimitCollectionCreationDeletionSplitFeatureEnabled_Success(
|
||||||
|
SutProvider<BulkCollectionAuthorizationHandler> sutProvider,
|
||||||
|
ICollection<CollectionDetails> collections,
|
||||||
|
CurrentContextOrganization organization)
|
||||||
|
{
|
||||||
|
var actingUserId = Guid.NewGuid();
|
||||||
|
|
||||||
|
organization.Type = OrganizationUserType.User;
|
||||||
|
organization.Permissions = new Permissions();
|
||||||
|
|
||||||
|
ArrangeOrganizationAbility_WithLimitCollectionCreationDeletionSplitFeatureEnabled(sutProvider, organization, false, false);
|
||||||
|
|
||||||
|
sutProvider.GetDependency<ICurrentContext>().UserId.Returns(actingUserId);
|
||||||
|
sutProvider.GetDependency<ICurrentContext>().GetOrganization(organization.Id).Returns(organization);
|
||||||
|
sutProvider.GetDependency<ICollectionRepository>().GetManyByUserIdAsync(actingUserId).Returns(collections);
|
||||||
|
sutProvider.GetDependency<IFeatureService>().IsEnabled(FeatureFlagKeys.LimitCollectionCreationDeletionSplit).Returns(true);
|
||||||
|
|
||||||
|
foreach (var c in collections)
|
||||||
|
{
|
||||||
|
c.Manage = true;
|
||||||
|
}
|
||||||
|
|
||||||
|
var context = new AuthorizationHandlerContext(
|
||||||
|
new[] { BulkCollectionOperations.Delete },
|
||||||
|
new ClaimsPrincipal(),
|
||||||
|
collections);
|
||||||
|
|
||||||
|
await sutProvider.Sut.HandleAsync(context);
|
||||||
|
|
||||||
|
sutProvider.GetDependency<IFeatureService>().Received(1).IsEnabled(FeatureFlagKeys.LimitCollectionCreationDeletionSplit);
|
||||||
Assert.True(context.HasSucceeded);
|
Assert.True(context.HasSucceeded);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -982,7 +1134,7 @@ public class BulkCollectionAuthorizationHandlerTests
|
|||||||
[BitAutoData(OrganizationUserType.Admin)]
|
[BitAutoData(OrganizationUserType.Admin)]
|
||||||
[BitAutoData(OrganizationUserType.Owner)]
|
[BitAutoData(OrganizationUserType.Owner)]
|
||||||
[BitAutoData(OrganizationUserType.User)]
|
[BitAutoData(OrganizationUserType.User)]
|
||||||
public async Task CanDeleteAsync_LimitCollectionCreationDeletionFalse_AllowAdminAccessToAllCollectionItemsFalse_WithCanManagePermission_Success(
|
public async Task CanDeleteAsync_LimitCollectionDeletionFalse_AllowAdminAccessToAllCollectionItemsFalse_WithCanManagePermission_WithLimitCollectionCreationDeletionSplitFeatureDisabled_Success(
|
||||||
OrganizationUserType userType,
|
OrganizationUserType userType,
|
||||||
SutProvider<BulkCollectionAuthorizationHandler> sutProvider,
|
SutProvider<BulkCollectionAuthorizationHandler> sutProvider,
|
||||||
ICollection<CollectionDetails> collections,
|
ICollection<CollectionDetails> collections,
|
||||||
@ -993,11 +1145,12 @@ public class BulkCollectionAuthorizationHandlerTests
|
|||||||
organization.Type = userType;
|
organization.Type = userType;
|
||||||
organization.Permissions = new Permissions();
|
organization.Permissions = new Permissions();
|
||||||
|
|
||||||
ArrangeOrganizationAbility(sutProvider, organization, false, false);
|
ArrangeOrganizationAbility_WithLimitCollectionCreationDeletionSplitFeatureDisabled(sutProvider, organization, false, false, false);
|
||||||
|
|
||||||
sutProvider.GetDependency<ICurrentContext>().UserId.Returns(actingUserId);
|
sutProvider.GetDependency<ICurrentContext>().UserId.Returns(actingUserId);
|
||||||
sutProvider.GetDependency<ICurrentContext>().GetOrganization(organization.Id).Returns(organization);
|
sutProvider.GetDependency<ICurrentContext>().GetOrganization(organization.Id).Returns(organization);
|
||||||
sutProvider.GetDependency<ICollectionRepository>().GetManyByUserIdAsync(actingUserId).Returns(collections);
|
sutProvider.GetDependency<ICollectionRepository>().GetManyByUserIdAsync(actingUserId).Returns(collections);
|
||||||
|
sutProvider.GetDependency<IFeatureService>().IsEnabled(FeatureFlagKeys.LimitCollectionCreationDeletionSplit).Returns(false);
|
||||||
|
|
||||||
foreach (var c in collections)
|
foreach (var c in collections)
|
||||||
{
|
{
|
||||||
@ -1011,13 +1164,15 @@ public class BulkCollectionAuthorizationHandlerTests
|
|||||||
|
|
||||||
await sutProvider.Sut.HandleAsync(context);
|
await sutProvider.Sut.HandleAsync(context);
|
||||||
|
|
||||||
|
sutProvider.GetDependency<IFeatureService>().Received(1).IsEnabled(FeatureFlagKeys.LimitCollectionCreationDeletionSplit);
|
||||||
Assert.True(context.HasSucceeded);
|
Assert.True(context.HasSucceeded);
|
||||||
}
|
}
|
||||||
|
|
||||||
[Theory, CollectionCustomization]
|
[Theory, CollectionCustomization]
|
||||||
[BitAutoData(OrganizationUserType.Admin)]
|
[BitAutoData(OrganizationUserType.Admin)]
|
||||||
[BitAutoData(OrganizationUserType.Owner)]
|
[BitAutoData(OrganizationUserType.Owner)]
|
||||||
public async Task CanDeleteAsync_WhenAdminOrOwner_LimitCollectionCreationDeletionTrue_AllowAdminAccessToAllCollectionItemsFalse_WithCanManagePermission_Success(
|
[BitAutoData(OrganizationUserType.User)]
|
||||||
|
public async Task CanDeleteAsync_LimitCollectionDeletionFalse_AllowAdminAccessToAllCollectionItemsFalse_WithCanManagePermission_WithLimitCollectionCreationDeletionSplitFeatureEnabled_Success(
|
||||||
OrganizationUserType userType,
|
OrganizationUserType userType,
|
||||||
SutProvider<BulkCollectionAuthorizationHandler> sutProvider,
|
SutProvider<BulkCollectionAuthorizationHandler> sutProvider,
|
||||||
ICollection<CollectionDetails> collections,
|
ICollection<CollectionDetails> collections,
|
||||||
@ -1028,11 +1183,12 @@ public class BulkCollectionAuthorizationHandlerTests
|
|||||||
organization.Type = userType;
|
organization.Type = userType;
|
||||||
organization.Permissions = new Permissions();
|
organization.Permissions = new Permissions();
|
||||||
|
|
||||||
ArrangeOrganizationAbility(sutProvider, organization, true, false);
|
ArrangeOrganizationAbility_WithLimitCollectionCreationDeletionSplitFeatureEnabled(sutProvider, organization, false, false, false);
|
||||||
|
|
||||||
sutProvider.GetDependency<ICurrentContext>().UserId.Returns(actingUserId);
|
sutProvider.GetDependency<ICurrentContext>().UserId.Returns(actingUserId);
|
||||||
sutProvider.GetDependency<ICurrentContext>().GetOrganization(organization.Id).Returns(organization);
|
sutProvider.GetDependency<ICurrentContext>().GetOrganization(organization.Id).Returns(organization);
|
||||||
sutProvider.GetDependency<ICollectionRepository>().GetManyByUserIdAsync(actingUserId).Returns(collections);
|
sutProvider.GetDependency<ICollectionRepository>().GetManyByUserIdAsync(actingUserId).Returns(collections);
|
||||||
|
sutProvider.GetDependency<IFeatureService>().IsEnabled(FeatureFlagKeys.LimitCollectionCreationDeletionSplit).Returns(true);
|
||||||
|
|
||||||
foreach (var c in collections)
|
foreach (var c in collections)
|
||||||
{
|
{
|
||||||
@ -1046,13 +1202,14 @@ public class BulkCollectionAuthorizationHandlerTests
|
|||||||
|
|
||||||
await sutProvider.Sut.HandleAsync(context);
|
await sutProvider.Sut.HandleAsync(context);
|
||||||
|
|
||||||
|
sutProvider.GetDependency<IFeatureService>().Received(1).IsEnabled(FeatureFlagKeys.LimitCollectionCreationDeletionSplit);
|
||||||
Assert.True(context.HasSucceeded);
|
Assert.True(context.HasSucceeded);
|
||||||
}
|
}
|
||||||
|
|
||||||
[Theory, CollectionCustomization]
|
[Theory, CollectionCustomization]
|
||||||
[BitAutoData(OrganizationUserType.Admin)]
|
[BitAutoData(OrganizationUserType.Admin)]
|
||||||
[BitAutoData(OrganizationUserType.Owner)]
|
[BitAutoData(OrganizationUserType.Owner)]
|
||||||
public async Task CanDeleteAsync_WhenAdminOrOwner_LimitCollectionCreationDeletionTrue_AllowAdminAccessToAllCollectionItemsFalse_WithoutCanManagePermission_Failure(
|
public async Task CanDeleteAsync_WhenAdminOrOwner_LimitCollectionDeletionTrue_AllowAdminAccessToAllCollectionItemsFalse_WithCanManagePermission_WithLimitCollectionCreationDeletionSplitFeatureDisabled_Success(
|
||||||
OrganizationUserType userType,
|
OrganizationUserType userType,
|
||||||
SutProvider<BulkCollectionAuthorizationHandler> sutProvider,
|
SutProvider<BulkCollectionAuthorizationHandler> sutProvider,
|
||||||
ICollection<CollectionDetails> collections,
|
ICollection<CollectionDetails> collections,
|
||||||
@ -1063,12 +1220,87 @@ public class BulkCollectionAuthorizationHandlerTests
|
|||||||
organization.Type = userType;
|
organization.Type = userType;
|
||||||
organization.Permissions = new Permissions();
|
organization.Permissions = new Permissions();
|
||||||
|
|
||||||
ArrangeOrganizationAbility(sutProvider, organization, true, false);
|
ArrangeOrganizationAbility_WithLimitCollectionCreationDeletionSplitFeatureDisabled(sutProvider, organization, true, true, false);
|
||||||
|
|
||||||
|
sutProvider.GetDependency<ICurrentContext>().UserId.Returns(actingUserId);
|
||||||
|
sutProvider.GetDependency<ICurrentContext>().GetOrganization(organization.Id).Returns(organization);
|
||||||
|
sutProvider.GetDependency<ICollectionRepository>().GetManyByUserIdAsync(actingUserId).Returns(collections);
|
||||||
|
sutProvider.GetDependency<IFeatureService>().IsEnabled(FeatureFlagKeys.LimitCollectionCreationDeletionSplit).Returns(false);
|
||||||
|
|
||||||
|
foreach (var c in collections)
|
||||||
|
{
|
||||||
|
c.Manage = true;
|
||||||
|
}
|
||||||
|
|
||||||
|
var context = new AuthorizationHandlerContext(
|
||||||
|
new[] { BulkCollectionOperations.Delete },
|
||||||
|
new ClaimsPrincipal(),
|
||||||
|
collections);
|
||||||
|
|
||||||
|
await sutProvider.Sut.HandleAsync(context);
|
||||||
|
|
||||||
|
sutProvider.GetDependency<IFeatureService>().Received(1).IsEnabled(FeatureFlagKeys.LimitCollectionCreationDeletionSplit);
|
||||||
|
Assert.True(context.HasSucceeded);
|
||||||
|
}
|
||||||
|
|
||||||
|
[Theory, CollectionCustomization]
|
||||||
|
[BitAutoData(OrganizationUserType.Admin)]
|
||||||
|
[BitAutoData(OrganizationUserType.Owner)]
|
||||||
|
public async Task CanDeleteAsync_WhenAdminOrOwner_LimitCollectionDeletionTrue_AllowAdminAccessToAllCollectionItemsFalse_WithCanManagePermission_WithLimitCollectionCreationDeletionSplitFeatureEnabled_Success(
|
||||||
|
OrganizationUserType userType,
|
||||||
|
SutProvider<BulkCollectionAuthorizationHandler> sutProvider,
|
||||||
|
ICollection<CollectionDetails> collections,
|
||||||
|
CurrentContextOrganization organization)
|
||||||
|
{
|
||||||
|
var actingUserId = Guid.NewGuid();
|
||||||
|
|
||||||
|
organization.Type = userType;
|
||||||
|
organization.Permissions = new Permissions();
|
||||||
|
|
||||||
|
ArrangeOrganizationAbility_WithLimitCollectionCreationDeletionSplitFeatureEnabled(sutProvider, organization, true, true, false);
|
||||||
|
|
||||||
|
sutProvider.GetDependency<ICurrentContext>().UserId.Returns(actingUserId);
|
||||||
|
sutProvider.GetDependency<ICurrentContext>().GetOrganization(organization.Id).Returns(organization);
|
||||||
|
sutProvider.GetDependency<ICollectionRepository>().GetManyByUserIdAsync(actingUserId).Returns(collections);
|
||||||
|
sutProvider.GetDependency<IFeatureService>().IsEnabled(FeatureFlagKeys.LimitCollectionCreationDeletionSplit).Returns(true);
|
||||||
|
|
||||||
|
foreach (var c in collections)
|
||||||
|
{
|
||||||
|
c.Manage = true;
|
||||||
|
}
|
||||||
|
|
||||||
|
var context = new AuthorizationHandlerContext(
|
||||||
|
new[] { BulkCollectionOperations.Delete },
|
||||||
|
new ClaimsPrincipal(),
|
||||||
|
collections);
|
||||||
|
|
||||||
|
await sutProvider.Sut.HandleAsync(context);
|
||||||
|
|
||||||
|
sutProvider.GetDependency<IFeatureService>().Received(1).IsEnabled(FeatureFlagKeys.LimitCollectionCreationDeletionSplit);
|
||||||
|
Assert.True(context.HasSucceeded);
|
||||||
|
}
|
||||||
|
|
||||||
|
[Theory, CollectionCustomization]
|
||||||
|
[BitAutoData(OrganizationUserType.Admin)]
|
||||||
|
[BitAutoData(OrganizationUserType.Owner)]
|
||||||
|
public async Task CanDeleteAsync_WhenAdminOrOwner_LimitCollectionDeletionTrue_AllowAdminAccessToAllCollectionItemsFalse_WithoutCanManagePermission_WithLimitCollectionCreationDeletionSplitFeatureDisabled_Failure(
|
||||||
|
OrganizationUserType userType,
|
||||||
|
SutProvider<BulkCollectionAuthorizationHandler> sutProvider,
|
||||||
|
ICollection<CollectionDetails> collections,
|
||||||
|
CurrentContextOrganization organization)
|
||||||
|
{
|
||||||
|
var actingUserId = Guid.NewGuid();
|
||||||
|
|
||||||
|
organization.Type = userType;
|
||||||
|
organization.Permissions = new Permissions();
|
||||||
|
|
||||||
|
ArrangeOrganizationAbility_WithLimitCollectionCreationDeletionSplitFeatureDisabled(sutProvider, organization, true, true, false);
|
||||||
|
|
||||||
sutProvider.GetDependency<ICurrentContext>().UserId.Returns(actingUserId);
|
sutProvider.GetDependency<ICurrentContext>().UserId.Returns(actingUserId);
|
||||||
sutProvider.GetDependency<ICurrentContext>().GetOrganization(organization.Id).Returns(organization);
|
sutProvider.GetDependency<ICurrentContext>().GetOrganization(organization.Id).Returns(organization);
|
||||||
sutProvider.GetDependency<ICollectionRepository>().GetManyByUserIdAsync(actingUserId).Returns(collections);
|
sutProvider.GetDependency<ICollectionRepository>().GetManyByUserIdAsync(actingUserId).Returns(collections);
|
||||||
sutProvider.GetDependency<ICurrentContext>().ProviderUserForOrgAsync(Arg.Any<Guid>()).Returns(false);
|
sutProvider.GetDependency<ICurrentContext>().ProviderUserForOrgAsync(Arg.Any<Guid>()).Returns(false);
|
||||||
|
sutProvider.GetDependency<IFeatureService>().IsEnabled(FeatureFlagKeys.LimitCollectionCreationDeletionSplit).Returns(false);
|
||||||
|
|
||||||
foreach (var c in collections)
|
foreach (var c in collections)
|
||||||
{
|
{
|
||||||
@ -1082,11 +1314,50 @@ public class BulkCollectionAuthorizationHandlerTests
|
|||||||
|
|
||||||
await sutProvider.Sut.HandleAsync(context);
|
await sutProvider.Sut.HandleAsync(context);
|
||||||
|
|
||||||
|
sutProvider.GetDependency<IFeatureService>().Received(1).IsEnabled(FeatureFlagKeys.LimitCollectionCreationDeletionSplit);
|
||||||
|
Assert.False(context.HasSucceeded);
|
||||||
|
}
|
||||||
|
|
||||||
|
[Theory, CollectionCustomization]
|
||||||
|
[BitAutoData(OrganizationUserType.Admin)]
|
||||||
|
[BitAutoData(OrganizationUserType.Owner)]
|
||||||
|
public async Task CanDeleteAsync_WhenAdminOrOwner_LimitCollectionDeletionTrue_AllowAdminAccessToAllCollectionItemsFalse_WithoutCanManagePermission_WithLimitCollectionCreationDeletionSplitFeatureEnabled_Failure(
|
||||||
|
OrganizationUserType userType,
|
||||||
|
SutProvider<BulkCollectionAuthorizationHandler> sutProvider,
|
||||||
|
ICollection<CollectionDetails> collections,
|
||||||
|
CurrentContextOrganization organization)
|
||||||
|
{
|
||||||
|
var actingUserId = Guid.NewGuid();
|
||||||
|
|
||||||
|
organization.Type = userType;
|
||||||
|
organization.Permissions = new Permissions();
|
||||||
|
|
||||||
|
ArrangeOrganizationAbility_WithLimitCollectionCreationDeletionSplitFeatureEnabled(sutProvider, organization, true, true, false);
|
||||||
|
|
||||||
|
sutProvider.GetDependency<ICurrentContext>().UserId.Returns(actingUserId);
|
||||||
|
sutProvider.GetDependency<ICurrentContext>().GetOrganization(organization.Id).Returns(organization);
|
||||||
|
sutProvider.GetDependency<ICollectionRepository>().GetManyByUserIdAsync(actingUserId).Returns(collections);
|
||||||
|
sutProvider.GetDependency<ICurrentContext>().ProviderUserForOrgAsync(Arg.Any<Guid>()).Returns(false);
|
||||||
|
sutProvider.GetDependency<IFeatureService>().IsEnabled(FeatureFlagKeys.LimitCollectionCreationDeletionSplit).Returns(true);
|
||||||
|
|
||||||
|
foreach (var c in collections)
|
||||||
|
{
|
||||||
|
c.Manage = false;
|
||||||
|
}
|
||||||
|
|
||||||
|
var context = new AuthorizationHandlerContext(
|
||||||
|
new[] { BulkCollectionOperations.Delete },
|
||||||
|
new ClaimsPrincipal(),
|
||||||
|
collections);
|
||||||
|
|
||||||
|
await sutProvider.Sut.HandleAsync(context);
|
||||||
|
|
||||||
|
sutProvider.GetDependency<IFeatureService>().Received(1).IsEnabled(FeatureFlagKeys.LimitCollectionCreationDeletionSplit);
|
||||||
Assert.False(context.HasSucceeded);
|
Assert.False(context.HasSucceeded);
|
||||||
}
|
}
|
||||||
|
|
||||||
[Theory, BitAutoData, CollectionCustomization]
|
[Theory, BitAutoData, CollectionCustomization]
|
||||||
public async Task CanDeleteAsync_WhenUser_LimitCollectionCreationDeletionTrue_AllowAdminAccessToAllCollectionItemsTrue_Failure(
|
public async Task CanDeleteAsync_WhenUser_LimitCollectionDeletionTrue_AllowAdminAccessToAllCollectionItemsTrue_WithLimitCollectionCreationDeletionSplitFeatureDisabled_Failure(
|
||||||
SutProvider<BulkCollectionAuthorizationHandler> sutProvider,
|
SutProvider<BulkCollectionAuthorizationHandler> sutProvider,
|
||||||
ICollection<CollectionDetails> collections,
|
ICollection<CollectionDetails> collections,
|
||||||
CurrentContextOrganization organization)
|
CurrentContextOrganization organization)
|
||||||
@ -1096,12 +1367,13 @@ public class BulkCollectionAuthorizationHandlerTests
|
|||||||
organization.Type = OrganizationUserType.User;
|
organization.Type = OrganizationUserType.User;
|
||||||
organization.Permissions = new Permissions();
|
organization.Permissions = new Permissions();
|
||||||
|
|
||||||
ArrangeOrganizationAbility(sutProvider, organization, true);
|
ArrangeOrganizationAbility_WithLimitCollectionCreationDeletionSplitFeatureDisabled(sutProvider, organization, true, true);
|
||||||
|
|
||||||
sutProvider.GetDependency<ICurrentContext>().UserId.Returns(actingUserId);
|
sutProvider.GetDependency<ICurrentContext>().UserId.Returns(actingUserId);
|
||||||
sutProvider.GetDependency<ICurrentContext>().GetOrganization(organization.Id).Returns(organization);
|
sutProvider.GetDependency<ICurrentContext>().GetOrganization(organization.Id).Returns(organization);
|
||||||
sutProvider.GetDependency<ICollectionRepository>().GetManyByUserIdAsync(actingUserId).Returns(collections);
|
sutProvider.GetDependency<ICollectionRepository>().GetManyByUserIdAsync(actingUserId).Returns(collections);
|
||||||
sutProvider.GetDependency<ICurrentContext>().ProviderUserForOrgAsync(Arg.Any<Guid>()).Returns(false);
|
sutProvider.GetDependency<ICurrentContext>().ProviderUserForOrgAsync(Arg.Any<Guid>()).Returns(false);
|
||||||
|
sutProvider.GetDependency<IFeatureService>().IsEnabled(FeatureFlagKeys.LimitCollectionCreationDeletionSplit).Returns(false);
|
||||||
|
|
||||||
foreach (var c in collections)
|
foreach (var c in collections)
|
||||||
{
|
{
|
||||||
@ -1115,11 +1387,12 @@ public class BulkCollectionAuthorizationHandlerTests
|
|||||||
|
|
||||||
await sutProvider.Sut.HandleAsync(context);
|
await sutProvider.Sut.HandleAsync(context);
|
||||||
|
|
||||||
|
sutProvider.GetDependency<IFeatureService>().Received(1).IsEnabled(FeatureFlagKeys.LimitCollectionCreationDeletionSplit);
|
||||||
Assert.False(context.HasSucceeded);
|
Assert.False(context.HasSucceeded);
|
||||||
}
|
}
|
||||||
|
|
||||||
[Theory, BitAutoData, CollectionCustomization]
|
[Theory, BitAutoData, CollectionCustomization]
|
||||||
public async Task CanDeleteAsync_WhenUser_LimitCollectionCreationDeletionTrue_AllowAdminAccessToAllCollectionItemsFalse_Failure(
|
public async Task CanDeleteAsync_WhenUser_LimitCollectionDeletionTrue_AllowAdminAccessToAllCollectionItemsTrue_WithLimitCollectionCreationDeletionSplitFeatureEnabled_Failure(
|
||||||
SutProvider<BulkCollectionAuthorizationHandler> sutProvider,
|
SutProvider<BulkCollectionAuthorizationHandler> sutProvider,
|
||||||
ICollection<CollectionDetails> collections,
|
ICollection<CollectionDetails> collections,
|
||||||
CurrentContextOrganization organization)
|
CurrentContextOrganization organization)
|
||||||
@ -1129,12 +1402,13 @@ public class BulkCollectionAuthorizationHandlerTests
|
|||||||
organization.Type = OrganizationUserType.User;
|
organization.Type = OrganizationUserType.User;
|
||||||
organization.Permissions = new Permissions();
|
organization.Permissions = new Permissions();
|
||||||
|
|
||||||
ArrangeOrganizationAbility(sutProvider, organization, true, false);
|
ArrangeOrganizationAbility_WithLimitCollectionCreationDeletionSplitFeatureEnabled(sutProvider, organization, true, true);
|
||||||
|
|
||||||
sutProvider.GetDependency<ICurrentContext>().UserId.Returns(actingUserId);
|
sutProvider.GetDependency<ICurrentContext>().UserId.Returns(actingUserId);
|
||||||
sutProvider.GetDependency<ICurrentContext>().GetOrganization(organization.Id).Returns(organization);
|
sutProvider.GetDependency<ICurrentContext>().GetOrganization(organization.Id).Returns(organization);
|
||||||
sutProvider.GetDependency<ICollectionRepository>().GetManyByUserIdAsync(actingUserId).Returns(collections);
|
sutProvider.GetDependency<ICollectionRepository>().GetManyByUserIdAsync(actingUserId).Returns(collections);
|
||||||
sutProvider.GetDependency<ICurrentContext>().ProviderUserForOrgAsync(Arg.Any<Guid>()).Returns(false);
|
sutProvider.GetDependency<ICurrentContext>().ProviderUserForOrgAsync(Arg.Any<Guid>()).Returns(false);
|
||||||
|
sutProvider.GetDependency<IFeatureService>().IsEnabled(FeatureFlagKeys.LimitCollectionCreationDeletionSplit).Returns(true);
|
||||||
|
|
||||||
foreach (var c in collections)
|
foreach (var c in collections)
|
||||||
{
|
{
|
||||||
@ -1148,13 +1422,88 @@ public class BulkCollectionAuthorizationHandlerTests
|
|||||||
|
|
||||||
await sutProvider.Sut.HandleAsync(context);
|
await sutProvider.Sut.HandleAsync(context);
|
||||||
|
|
||||||
|
sutProvider.GetDependency<IFeatureService>().Received(1).IsEnabled(FeatureFlagKeys.LimitCollectionCreationDeletionSplit);
|
||||||
|
Assert.False(context.HasSucceeded);
|
||||||
|
}
|
||||||
|
|
||||||
|
[Theory, BitAutoData, CollectionCustomization]
|
||||||
|
public async Task CanDeleteAsync_WhenUser_LimitCollectionDeletionTrue_AllowAdminAccessToAllCollectionItemsFalse_WithLimitCollectionCreationDeletionSplitFeatureDisabled_Failure(
|
||||||
|
SutProvider<BulkCollectionAuthorizationHandler> sutProvider,
|
||||||
|
ICollection<CollectionDetails> collections,
|
||||||
|
CurrentContextOrganization organization)
|
||||||
|
{
|
||||||
|
var actingUserId = Guid.NewGuid();
|
||||||
|
|
||||||
|
organization.Type = OrganizationUserType.User;
|
||||||
|
organization.Permissions = new Permissions();
|
||||||
|
|
||||||
|
ArrangeOrganizationAbility_WithLimitCollectionCreationDeletionSplitFeatureDisabled(sutProvider, organization, true, true, false);
|
||||||
|
|
||||||
|
sutProvider.GetDependency<ICurrentContext>().UserId.Returns(actingUserId);
|
||||||
|
sutProvider.GetDependency<ICurrentContext>().GetOrganization(organization.Id).Returns(organization);
|
||||||
|
sutProvider.GetDependency<ICollectionRepository>().GetManyByUserIdAsync(actingUserId).Returns(collections);
|
||||||
|
sutProvider.GetDependency<ICurrentContext>().ProviderUserForOrgAsync(Arg.Any<Guid>()).Returns(false);
|
||||||
|
sutProvider.GetDependency<IFeatureService>()
|
||||||
|
.IsEnabled(FeatureFlagKeys.LimitCollectionCreationDeletionSplit)
|
||||||
|
.Returns(false);
|
||||||
|
|
||||||
|
foreach (var c in collections)
|
||||||
|
{
|
||||||
|
c.Manage = true;
|
||||||
|
}
|
||||||
|
|
||||||
|
var context = new AuthorizationHandlerContext(
|
||||||
|
new[] { BulkCollectionOperations.Delete },
|
||||||
|
new ClaimsPrincipal(),
|
||||||
|
collections);
|
||||||
|
|
||||||
|
await sutProvider.Sut.HandleAsync(context);
|
||||||
|
|
||||||
|
sutProvider.GetDependency<IFeatureService>().Received(1).IsEnabled(FeatureFlagKeys.LimitCollectionCreationDeletionSplit);
|
||||||
|
Assert.False(context.HasSucceeded);
|
||||||
|
}
|
||||||
|
|
||||||
|
[Theory, BitAutoData, CollectionCustomization]
|
||||||
|
public async Task CanDeleteAsync_WhenUser_LimitCollectionDeletionTrue_AllowAdminAccessToAllCollectionItemsFalse_WithLimitCollectionCreationDeletionSplitFeatureEnabled_Failure(
|
||||||
|
SutProvider<BulkCollectionAuthorizationHandler> sutProvider,
|
||||||
|
ICollection<CollectionDetails> collections,
|
||||||
|
CurrentContextOrganization organization)
|
||||||
|
{
|
||||||
|
var actingUserId = Guid.NewGuid();
|
||||||
|
|
||||||
|
organization.Type = OrganizationUserType.User;
|
||||||
|
organization.Permissions = new Permissions();
|
||||||
|
|
||||||
|
ArrangeOrganizationAbility_WithLimitCollectionCreationDeletionSplitFeatureEnabled(sutProvider, organization, true, true, false);
|
||||||
|
|
||||||
|
sutProvider.GetDependency<ICurrentContext>().UserId.Returns(actingUserId);
|
||||||
|
sutProvider.GetDependency<ICurrentContext>().GetOrganization(organization.Id).Returns(organization);
|
||||||
|
sutProvider.GetDependency<ICollectionRepository>().GetManyByUserIdAsync(actingUserId).Returns(collections);
|
||||||
|
sutProvider.GetDependency<ICurrentContext>().ProviderUserForOrgAsync(Arg.Any<Guid>()).Returns(false);
|
||||||
|
sutProvider.GetDependency<IFeatureService>()
|
||||||
|
.IsEnabled(FeatureFlagKeys.LimitCollectionCreationDeletionSplit)
|
||||||
|
.Returns(true);
|
||||||
|
|
||||||
|
foreach (var c in collections)
|
||||||
|
{
|
||||||
|
c.Manage = true;
|
||||||
|
}
|
||||||
|
|
||||||
|
var context = new AuthorizationHandlerContext(
|
||||||
|
new[] { BulkCollectionOperations.Delete },
|
||||||
|
new ClaimsPrincipal(),
|
||||||
|
collections);
|
||||||
|
|
||||||
|
await sutProvider.Sut.HandleAsync(context);
|
||||||
|
|
||||||
|
sutProvider.GetDependency<IFeatureService>().Received(1).IsEnabled(FeatureFlagKeys.LimitCollectionCreationDeletionSplit);
|
||||||
Assert.False(context.HasSucceeded);
|
Assert.False(context.HasSucceeded);
|
||||||
}
|
}
|
||||||
|
|
||||||
[Theory, CollectionCustomization]
|
[Theory, CollectionCustomization]
|
||||||
[BitAutoData(OrganizationUserType.User)]
|
[BitAutoData(OrganizationUserType.User)]
|
||||||
[BitAutoData(OrganizationUserType.Custom)]
|
[BitAutoData(OrganizationUserType.Custom)]
|
||||||
public async Task CanDeleteAsync_WhenMissingPermissions_NoSuccess(
|
public async Task CanDeleteAsync_WhenMissingPermissions_WithLimitCollectionCreationDeletionSplitFeatureDisabled_NoSuccess(
|
||||||
OrganizationUserType userType,
|
OrganizationUserType userType,
|
||||||
SutProvider<BulkCollectionAuthorizationHandler> sutProvider,
|
SutProvider<BulkCollectionAuthorizationHandler> sutProvider,
|
||||||
ICollection<Collection> collections,
|
ICollection<Collection> collections,
|
||||||
@ -1171,7 +1520,7 @@ public class BulkCollectionAuthorizationHandlerTests
|
|||||||
ManageUsers = false
|
ManageUsers = false
|
||||||
};
|
};
|
||||||
|
|
||||||
ArrangeOrganizationAbility(sutProvider, organization, true);
|
ArrangeOrganizationAbility_WithLimitCollectionCreationDeletionSplitFeatureDisabled(sutProvider, organization, true, true);
|
||||||
|
|
||||||
var context = new AuthorizationHandlerContext(
|
var context = new AuthorizationHandlerContext(
|
||||||
new[] { BulkCollectionOperations.Delete },
|
new[] { BulkCollectionOperations.Delete },
|
||||||
@ -1181,14 +1530,54 @@ public class BulkCollectionAuthorizationHandlerTests
|
|||||||
sutProvider.GetDependency<ICurrentContext>().UserId.Returns(actingUserId);
|
sutProvider.GetDependency<ICurrentContext>().UserId.Returns(actingUserId);
|
||||||
sutProvider.GetDependency<ICurrentContext>().GetOrganization(organization.Id).Returns(organization);
|
sutProvider.GetDependency<ICurrentContext>().GetOrganization(organization.Id).Returns(organization);
|
||||||
sutProvider.GetDependency<ICurrentContext>().ProviderUserForOrgAsync(Arg.Any<Guid>()).Returns(false);
|
sutProvider.GetDependency<ICurrentContext>().ProviderUserForOrgAsync(Arg.Any<Guid>()).Returns(false);
|
||||||
|
sutProvider.GetDependency<IFeatureService>().IsEnabled(FeatureFlagKeys.LimitCollectionCreationDeletionSplit).Returns(false);
|
||||||
|
|
||||||
await sutProvider.Sut.HandleAsync(context);
|
await sutProvider.Sut.HandleAsync(context);
|
||||||
|
|
||||||
|
sutProvider.GetDependency<IFeatureService>().Received(1).IsEnabled(FeatureFlagKeys.LimitCollectionCreationDeletionSplit);
|
||||||
|
Assert.False(context.HasSucceeded);
|
||||||
|
}
|
||||||
|
|
||||||
|
[Theory, CollectionCustomization]
|
||||||
|
[BitAutoData(OrganizationUserType.User)]
|
||||||
|
[BitAutoData(OrganizationUserType.Custom)]
|
||||||
|
public async Task CanDeleteAsync_WhenMissingPermissions_WithLimitCollectionCreationDeletionSplitFeatureEnabled_NoSuccess(
|
||||||
|
OrganizationUserType userType,
|
||||||
|
SutProvider<BulkCollectionAuthorizationHandler> sutProvider,
|
||||||
|
ICollection<Collection> collections,
|
||||||
|
CurrentContextOrganization organization)
|
||||||
|
{
|
||||||
|
var actingUserId = Guid.NewGuid();
|
||||||
|
|
||||||
|
organization.Type = userType;
|
||||||
|
organization.Permissions = new Permissions
|
||||||
|
{
|
||||||
|
EditAnyCollection = false,
|
||||||
|
DeleteAnyCollection = false,
|
||||||
|
ManageGroups = false,
|
||||||
|
ManageUsers = false
|
||||||
|
};
|
||||||
|
|
||||||
|
ArrangeOrganizationAbility_WithLimitCollectionCreationDeletionSplitFeatureEnabled(sutProvider, organization, true, true);
|
||||||
|
|
||||||
|
var context = new AuthorizationHandlerContext(
|
||||||
|
new[] { BulkCollectionOperations.Delete },
|
||||||
|
new ClaimsPrincipal(),
|
||||||
|
collections);
|
||||||
|
|
||||||
|
sutProvider.GetDependency<ICurrentContext>().UserId.Returns(actingUserId);
|
||||||
|
sutProvider.GetDependency<ICurrentContext>().GetOrganization(organization.Id).Returns(organization);
|
||||||
|
sutProvider.GetDependency<ICurrentContext>().ProviderUserForOrgAsync(Arg.Any<Guid>()).Returns(false);
|
||||||
|
sutProvider.GetDependency<IFeatureService>().IsEnabled(FeatureFlagKeys.LimitCollectionCreationDeletionSplit).Returns(true);
|
||||||
|
|
||||||
|
await sutProvider.Sut.HandleAsync(context);
|
||||||
|
|
||||||
|
sutProvider.GetDependency<IFeatureService>().Received(1).IsEnabled(FeatureFlagKeys.LimitCollectionCreationDeletionSplit);
|
||||||
Assert.False(context.HasSucceeded);
|
Assert.False(context.HasSucceeded);
|
||||||
}
|
}
|
||||||
|
|
||||||
[Theory, BitAutoData, CollectionCustomization]
|
[Theory, BitAutoData, CollectionCustomization]
|
||||||
public async Task CanDeleteAsync_WhenMissingOrgAccess_NoSuccess(
|
public async Task CanDeleteAsync_WhenMissingOrgAccess_WithLimitCollectionCreationDeletionSplitFeatureDisabled_NoSuccess(
|
||||||
Guid userId,
|
Guid userId,
|
||||||
ICollection<Collection> collections,
|
ICollection<Collection> collections,
|
||||||
SutProvider<BulkCollectionAuthorizationHandler> sutProvider)
|
SutProvider<BulkCollectionAuthorizationHandler> sutProvider)
|
||||||
@ -1202,8 +1591,34 @@ public class BulkCollectionAuthorizationHandlerTests
|
|||||||
sutProvider.GetDependency<ICurrentContext>().UserId.Returns(userId);
|
sutProvider.GetDependency<ICurrentContext>().UserId.Returns(userId);
|
||||||
sutProvider.GetDependency<ICurrentContext>().GetOrganization(Arg.Any<Guid>()).Returns((CurrentContextOrganization)null);
|
sutProvider.GetDependency<ICurrentContext>().GetOrganization(Arg.Any<Guid>()).Returns((CurrentContextOrganization)null);
|
||||||
sutProvider.GetDependency<ICurrentContext>().ProviderUserForOrgAsync(Arg.Any<Guid>()).Returns(false);
|
sutProvider.GetDependency<ICurrentContext>().ProviderUserForOrgAsync(Arg.Any<Guid>()).Returns(false);
|
||||||
|
sutProvider.GetDependency<IFeatureService>().IsEnabled(FeatureFlagKeys.LimitCollectionCreationDeletionSplit).Returns(false);
|
||||||
|
|
||||||
await sutProvider.Sut.HandleAsync(context);
|
await sutProvider.Sut.HandleAsync(context);
|
||||||
|
|
||||||
|
sutProvider.GetDependency<IFeatureService>().Received(1).IsEnabled(FeatureFlagKeys.LimitCollectionCreationDeletionSplit);
|
||||||
|
Assert.False(context.HasSucceeded);
|
||||||
|
}
|
||||||
|
|
||||||
|
[Theory, BitAutoData, CollectionCustomization]
|
||||||
|
public async Task CanDeleteAsync_WhenMissingOrgAccess_WithLimitCollectionCreationDeletionSplitFeatureEnabled_NoSuccess(
|
||||||
|
Guid userId,
|
||||||
|
ICollection<Collection> collections,
|
||||||
|
SutProvider<BulkCollectionAuthorizationHandler> sutProvider)
|
||||||
|
{
|
||||||
|
var context = new AuthorizationHandlerContext(
|
||||||
|
new[] { BulkCollectionOperations.Delete },
|
||||||
|
new ClaimsPrincipal(),
|
||||||
|
collections
|
||||||
|
);
|
||||||
|
|
||||||
|
sutProvider.GetDependency<ICurrentContext>().UserId.Returns(userId);
|
||||||
|
sutProvider.GetDependency<ICurrentContext>().GetOrganization(Arg.Any<Guid>()).Returns((CurrentContextOrganization)null);
|
||||||
|
sutProvider.GetDependency<ICurrentContext>().ProviderUserForOrgAsync(Arg.Any<Guid>()).Returns(false);
|
||||||
|
sutProvider.GetDependency<IFeatureService>().IsEnabled(FeatureFlagKeys.LimitCollectionCreationDeletionSplit).Returns(true);
|
||||||
|
|
||||||
|
await sutProvider.Sut.HandleAsync(context);
|
||||||
|
|
||||||
|
sutProvider.GetDependency<IFeatureService>().Received(1).IsEnabled(FeatureFlagKeys.LimitCollectionCreationDeletionSplit);
|
||||||
Assert.False(context.HasSucceeded);
|
Assert.False(context.HasSucceeded);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -1224,6 +1639,7 @@ public class BulkCollectionAuthorizationHandlerTests
|
|||||||
await sutProvider.Sut.HandleAsync(context);
|
await sutProvider.Sut.HandleAsync(context);
|
||||||
Assert.True(context.HasFailed);
|
Assert.True(context.HasFailed);
|
||||||
sutProvider.GetDependency<ICollectionRepository>().DidNotReceiveWithAnyArgs();
|
sutProvider.GetDependency<ICollectionRepository>().DidNotReceiveWithAnyArgs();
|
||||||
|
sutProvider.GetDependency<IFeatureService>().DidNotReceiveWithAnyArgs().IsEnabled(FeatureFlagKeys.LimitCollectionCreationDeletionSplit);
|
||||||
}
|
}
|
||||||
|
|
||||||
[Theory, BitAutoData, CollectionCustomization]
|
[Theory, BitAutoData, CollectionCustomization]
|
||||||
@ -1247,10 +1663,11 @@ public class BulkCollectionAuthorizationHandlerTests
|
|||||||
var exception = await Assert.ThrowsAsync<BadRequestException>(() => sutProvider.Sut.HandleAsync(context));
|
var exception = await Assert.ThrowsAsync<BadRequestException>(() => sutProvider.Sut.HandleAsync(context));
|
||||||
Assert.Equal("Requested collections must belong to the same organization.", exception.Message);
|
Assert.Equal("Requested collections must belong to the same organization.", exception.Message);
|
||||||
sutProvider.GetDependency<ICurrentContext>().DidNotReceiveWithAnyArgs().GetOrganization(default);
|
sutProvider.GetDependency<ICurrentContext>().DidNotReceiveWithAnyArgs().GetOrganization(default);
|
||||||
|
sutProvider.GetDependency<IFeatureService>().DidNotReceiveWithAnyArgs().IsEnabled(FeatureFlagKeys.LimitCollectionCreationDeletionSplit);
|
||||||
}
|
}
|
||||||
|
|
||||||
[Theory, BitAutoData, CollectionCustomization]
|
[Theory, BitAutoData, CollectionCustomization]
|
||||||
public async Task HandleRequirementAsync_Provider_Success(
|
public async Task HandleRequirementAsync_Provider_WithLimitCollectionCreationDeletionSplitFeatureDisabled_Success(
|
||||||
SutProvider<BulkCollectionAuthorizationHandler> sutProvider,
|
SutProvider<BulkCollectionAuthorizationHandler> sutProvider,
|
||||||
ICollection<Collection> collections)
|
ICollection<Collection> collections)
|
||||||
{
|
{
|
||||||
@ -1286,6 +1703,63 @@ public class BulkCollectionAuthorizationHandlerTests
|
|||||||
sutProvider.GetDependency<IApplicationCacheService>().GetOrganizationAbilitiesAsync()
|
sutProvider.GetDependency<IApplicationCacheService>().GetOrganizationAbilitiesAsync()
|
||||||
.Returns(organizationAbilities);
|
.Returns(organizationAbilities);
|
||||||
sutProvider.GetDependency<ICurrentContext>().ProviderUserForOrgAsync(Arg.Any<Guid>()).Returns(true);
|
sutProvider.GetDependency<ICurrentContext>().ProviderUserForOrgAsync(Arg.Any<Guid>()).Returns(true);
|
||||||
|
sutProvider.GetDependency<IFeatureService>().IsEnabled(FeatureFlagKeys.LimitCollectionCreationDeletionSplit).Returns(false);
|
||||||
|
|
||||||
|
var context = new AuthorizationHandlerContext(
|
||||||
|
new[] { op },
|
||||||
|
new ClaimsPrincipal(),
|
||||||
|
collections
|
||||||
|
);
|
||||||
|
|
||||||
|
await sutProvider.Sut.HandleAsync(context);
|
||||||
|
|
||||||
|
Assert.True(context.HasSucceeded);
|
||||||
|
await sutProvider.GetDependency<ICurrentContext>().Received().ProviderUserForOrgAsync(orgId);
|
||||||
|
|
||||||
|
// Recreate the SUT to reset the mocks/dependencies between tests
|
||||||
|
sutProvider.Recreate();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
[Theory, BitAutoData, CollectionCustomization]
|
||||||
|
public async Task HandleRequirementAsync_Provider_WithLimitCollectionCreationDeletionSplitFeatureEnabled_Success(
|
||||||
|
SutProvider<BulkCollectionAuthorizationHandler> sutProvider,
|
||||||
|
ICollection<Collection> collections)
|
||||||
|
{
|
||||||
|
var actingUserId = Guid.NewGuid();
|
||||||
|
var orgId = collections.First().OrganizationId;
|
||||||
|
|
||||||
|
var organizationAbilities = new Dictionary<Guid, OrganizationAbility>
|
||||||
|
{
|
||||||
|
{ collections.First().OrganizationId,
|
||||||
|
new OrganizationAbility
|
||||||
|
{
|
||||||
|
LimitCollectionCreation = true,
|
||||||
|
LimitCollectionDeletion = true,
|
||||||
|
AllowAdminAccessToAllCollectionItems = true
|
||||||
|
}
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
var operationsToTest = new[]
|
||||||
|
{
|
||||||
|
BulkCollectionOperations.Create,
|
||||||
|
BulkCollectionOperations.Read,
|
||||||
|
BulkCollectionOperations.ReadAccess,
|
||||||
|
BulkCollectionOperations.Update,
|
||||||
|
BulkCollectionOperations.ModifyUserAccess,
|
||||||
|
BulkCollectionOperations.ModifyGroupAccess,
|
||||||
|
BulkCollectionOperations.Delete,
|
||||||
|
};
|
||||||
|
|
||||||
|
foreach (var op in operationsToTest)
|
||||||
|
{
|
||||||
|
sutProvider.GetDependency<ICurrentContext>().UserId.Returns(actingUserId);
|
||||||
|
sutProvider.GetDependency<ICurrentContext>().GetOrganization(orgId).Returns((CurrentContextOrganization)null);
|
||||||
|
sutProvider.GetDependency<IApplicationCacheService>().GetOrganizationAbilitiesAsync()
|
||||||
|
.Returns(organizationAbilities);
|
||||||
|
sutProvider.GetDependency<ICurrentContext>().ProviderUserForOrgAsync(Arg.Any<Guid>()).Returns(true);
|
||||||
|
sutProvider.GetDependency<IFeatureService>().IsEnabled(FeatureFlagKeys.LimitCollectionCreationDeletionSplit).Returns(true);
|
||||||
|
|
||||||
var context = new AuthorizationHandlerContext(
|
var context = new AuthorizationHandlerContext(
|
||||||
new[] { op },
|
new[] { op },
|
||||||
@ -1336,14 +1810,37 @@ public class BulkCollectionAuthorizationHandlerTests
|
|||||||
await sutProvider.GetDependency<ICollectionRepository>().Received(1).GetManyByUserIdAsync(Arg.Any<Guid>());
|
await sutProvider.GetDependency<ICollectionRepository>().Received(1).GetManyByUserIdAsync(Arg.Any<Guid>());
|
||||||
}
|
}
|
||||||
|
|
||||||
private static void ArrangeOrganizationAbility(
|
private static void ArrangeOrganizationAbility_WithLimitCollectionCreationDeletionSplitFeatureDisabled(
|
||||||
SutProvider<BulkCollectionAuthorizationHandler> sutProvider,
|
SutProvider<BulkCollectionAuthorizationHandler> sutProvider,
|
||||||
CurrentContextOrganization organization, bool limitCollectionCreationDeletion,
|
CurrentContextOrganization organization,
|
||||||
|
bool limitCollectionCreation,
|
||||||
|
bool limitCollectionDeletion,
|
||||||
bool allowAdminAccessToAllCollectionItems = true)
|
bool allowAdminAccessToAllCollectionItems = true)
|
||||||
{
|
{
|
||||||
var organizationAbility = new OrganizationAbility();
|
var organizationAbility = new OrganizationAbility();
|
||||||
organizationAbility.Id = organization.Id;
|
organizationAbility.Id = organization.Id;
|
||||||
organizationAbility.LimitCollectionCreationDeletion = limitCollectionCreationDeletion;
|
|
||||||
|
organizationAbility.LimitCollectionCreationDeletion = limitCollectionCreation || limitCollectionDeletion;
|
||||||
|
|
||||||
|
organizationAbility.AllowAdminAccessToAllCollectionItems = allowAdminAccessToAllCollectionItems;
|
||||||
|
|
||||||
|
sutProvider.GetDependency<IApplicationCacheService>().GetOrganizationAbilityAsync(organizationAbility.Id)
|
||||||
|
.Returns(organizationAbility);
|
||||||
|
}
|
||||||
|
|
||||||
|
private static void ArrangeOrganizationAbility_WithLimitCollectionCreationDeletionSplitFeatureEnabled(
|
||||||
|
SutProvider<BulkCollectionAuthorizationHandler> sutProvider,
|
||||||
|
CurrentContextOrganization organization,
|
||||||
|
bool limitCollectionCreation,
|
||||||
|
bool limitCollectionDeletion,
|
||||||
|
bool allowAdminAccessToAllCollectionItems = true)
|
||||||
|
{
|
||||||
|
var organizationAbility = new OrganizationAbility();
|
||||||
|
organizationAbility.Id = organization.Id;
|
||||||
|
|
||||||
|
organizationAbility.LimitCollectionCreation = limitCollectionCreation;
|
||||||
|
organizationAbility.LimitCollectionDeletion = limitCollectionDeletion;
|
||||||
|
|
||||||
organizationAbility.AllowAdminAccessToAllCollectionItems = allowAdminAccessToAllCollectionItems;
|
organizationAbility.AllowAdminAccessToAllCollectionItems = allowAdminAccessToAllCollectionItems;
|
||||||
|
|
||||||
sutProvider.GetDependency<IApplicationCacheService>().GetOrganizationAbilityAsync(organizationAbility.Id)
|
sutProvider.GetDependency<IApplicationCacheService>().GetOrganizationAbilityAsync(organizationAbility.Id)
|
||||||
|
@ -253,6 +253,9 @@ public class OrganizationUserRepositoryTests
|
|||||||
Assert.Equal(orgUser1.Permissions, result.Permissions);
|
Assert.Equal(orgUser1.Permissions, result.Permissions);
|
||||||
Assert.Equal(organization.SmSeats, result.SmSeats);
|
Assert.Equal(organization.SmSeats, result.SmSeats);
|
||||||
Assert.Equal(organization.SmServiceAccounts, result.SmServiceAccounts);
|
Assert.Equal(organization.SmServiceAccounts, result.SmServiceAccounts);
|
||||||
|
Assert.Equal(organization.LimitCollectionCreation, result.LimitCollectionCreation);
|
||||||
|
Assert.Equal(organization.LimitCollectionDeletion, result.LimitCollectionDeletion);
|
||||||
|
// Deprecated: https://bitwarden.atlassian.net/browse/PM-10863
|
||||||
Assert.Equal(organization.LimitCollectionCreationDeletion, result.LimitCollectionCreationDeletion);
|
Assert.Equal(organization.LimitCollectionCreationDeletion, result.LimitCollectionCreationDeletion);
|
||||||
Assert.Equal(organization.AllowAdminAccessToAllCollectionItems, result.AllowAdminAccessToAllCollectionItems);
|
Assert.Equal(organization.AllowAdminAccessToAllCollectionItems, result.AllowAdminAccessToAllCollectionItems);
|
||||||
}
|
}
|
||||||
|
Loading…
Reference in New Issue
Block a user