1
0
mirror of https://github.com/bitwarden/server.git synced 2025-06-30 07:36:14 -05:00

[EC-343] Gate custom permissions behind enterprise plan (#2352)

* [EC-343] Added column 'UseCustomPermissions' to Organization table

* [EC-343] Added 'UseCustomPermissions' to Api responses

* [EC-343] Added 'UseCustomPermissions' to Admin view

* [EC-343] Add constraint to Organization table to have default UseCustomPermissions value

* [EC-343] Recreate OrganizationView to include UseCustomPermissions column

* [EC-343] Add MySql EF migrations

* [EC-343] Add Postgres EF migrations

* Revert "[EC-343] Add Postgres EF migrations"

This reverts commit 8f1654cb7d.

* [EC-343] Add Postgres migrations and script

* [EC-343] dotnet format

* [EC-343] Set 'Custom Permissions' feature as unchecked for teams plan

* [EC-343] Add CustomPermissions to plan upgrades

* [EC-343] Update CURRENT_LICENSE_FILE_VERSION

* [EC-343] Enable 'Custom Permissions' on Enterprise 2019 plan

* [EC-343] Updated migration script to include Enterprise 2019 plan

* [EC-343] Update CURRENT_LICENSE_FILE_VERSION to 10

* [EC-343] Move logic checking if Organization can use custom permissions to OrganizationService

* [EC-343] Add unit tests to validate UseCustomPermissions check

* [EC-343] Revert UseCustomPermissionsFlag migration

* [EC-343] Fix typo in OrganizationUserOrganizationDetailsViewQuery

* [EC-343] Add Postgres migrations without affecting other datetime column

* [EC-343] Create ValidateOrganizationCustomPermissionsEnabledAsync. Add more unit tests around CustomPermissions check

* [EC-343] Add curly brackets to if condition

* [EC-343] Rename unit tests
This commit is contained in:
Rui Tomé
2022-12-06 09:50:08 +00:00
committed by GitHub
parent e0f37e514e
commit ae280a313c
33 changed files with 4135 additions and 11 deletions

View File

@ -263,6 +263,8 @@ public class OrganizationServiceTests
public async Task InviteUser_NonAdminConfiguringAdmin_Throws(Organization organization, OrganizationUserInvite invite,
OrganizationUser invitor, SutProvider<OrganizationService> sutProvider)
{
organization.UseCustomPermissions = true;
var organizationRepository = sutProvider.GetDependency<IOrganizationRepository>();
var currentContext = sutProvider.GetDependency<ICurrentContext>();
@ -274,6 +276,84 @@ public class OrganizationServiceTests
Assert.Contains("only owners and admins", exception.Message.ToLowerInvariant());
}
[Theory]
[OrganizationInviteCustomize(
InviteeUserType = OrganizationUserType.Custom,
InvitorUserType = OrganizationUserType.Admin
), BitAutoData]
public async Task InviteUser_WithCustomType_WhenUseCustomPermissionsIsFalse_Throws(Organization organization, OrganizationUserInvite invite,
OrganizationUser invitor, SutProvider<OrganizationService> sutProvider)
{
organization.UseCustomPermissions = false;
invite.Permissions = null;
invitor.Status = OrganizationUserStatusType.Confirmed;
var organizationRepository = sutProvider.GetDependency<IOrganizationRepository>();
var organizationUserRepository = sutProvider.GetDependency<IOrganizationUserRepository>();
var currentContext = sutProvider.GetDependency<ICurrentContext>();
organizationRepository.GetByIdAsync(organization.Id).Returns(organization);
organizationUserRepository.GetManyByOrganizationAsync(organization.Id, OrganizationUserType.Owner)
.Returns(new[] { invitor });
currentContext.OrganizationOwner(organization.Id).Returns(true);
currentContext.ManageUsers(organization.Id).Returns(true);
var exception = await Assert.ThrowsAsync<BadRequestException>(
() => sutProvider.Sut.InviteUsersAsync(organization.Id, invitor.UserId, new (OrganizationUserInvite, string)[] { (invite, null) }));
Assert.Contains("to enable custom permissions", exception.Message.ToLowerInvariant());
}
[Theory]
[OrganizationInviteCustomize(
InviteeUserType = OrganizationUserType.Custom,
InvitorUserType = OrganizationUserType.Admin
), BitAutoData]
public async Task InviteUser_WithCustomType_WhenUseCustomPermissionsIsTrue_Passes(Organization organization, OrganizationUserInvite invite,
OrganizationUser invitor, SutProvider<OrganizationService> sutProvider)
{
organization.UseCustomPermissions = true;
invite.Permissions = null;
invitor.Status = OrganizationUserStatusType.Confirmed;
var organizationRepository = sutProvider.GetDependency<IOrganizationRepository>();
var organizationUserRepository = sutProvider.GetDependency<IOrganizationUserRepository>();
var currentContext = sutProvider.GetDependency<ICurrentContext>();
organizationRepository.GetByIdAsync(organization.Id).Returns(organization);
organizationUserRepository.GetManyByOrganizationAsync(organization.Id, OrganizationUserType.Owner)
.Returns(new[] { invitor });
currentContext.OrganizationOwner(organization.Id).Returns(true);
currentContext.ManageUsers(organization.Id).Returns(true);
await sutProvider.Sut.InviteUsersAsync(organization.Id, invitor.UserId, new (OrganizationUserInvite, string)[] { (invite, null) });
}
[Theory]
[BitAutoData(OrganizationUserType.Admin)]
[BitAutoData(OrganizationUserType.Manager)]
[BitAutoData(OrganizationUserType.Owner)]
[BitAutoData(OrganizationUserType.User)]
public async Task InviteUser_WithNonCustomType_WhenUseCustomPermissionsIsFalse_Passes(OrganizationUserType inviteUserType, Organization organization, OrganizationUserInvite invite,
OrganizationUser invitor, SutProvider<OrganizationService> sutProvider)
{
organization.UseCustomPermissions = false;
invite.Type = inviteUserType;
invite.Permissions = null;
invitor.Status = OrganizationUserStatusType.Confirmed;
var organizationRepository = sutProvider.GetDependency<IOrganizationRepository>();
var organizationUserRepository = sutProvider.GetDependency<IOrganizationUserRepository>();
var currentContext = sutProvider.GetDependency<ICurrentContext>();
organizationRepository.GetByIdAsync(organization.Id).Returns(organization);
organizationUserRepository.GetManyByOrganizationAsync(organization.Id, OrganizationUserType.Owner)
.Returns(new[] { invitor });
currentContext.OrganizationOwner(organization.Id).Returns(true);
currentContext.ManageUsers(organization.Id).Returns(true);
await sutProvider.Sut.InviteUsersAsync(organization.Id, invitor.UserId, new (OrganizationUserInvite, string)[] { (invite, null) });
}
[Theory]
[OrganizationInviteCustomize(
InviteeUserType = OrganizationUserType.Manager,
@ -440,18 +520,114 @@ public class OrganizationServiceTests
[Theory, BitAutoData]
public async Task SaveUser_Passes(
Organization organization,
OrganizationUser oldUserData,
OrganizationUser newUserData,
IEnumerable<SelectionReadOnly> collections,
[OrganizationUser(type: OrganizationUserType.Owner)] OrganizationUser savingUser,
SutProvider<OrganizationService> sutProvider)
{
var organizationRepository = sutProvider.GetDependency<IOrganizationRepository>();
var organizationUserRepository = sutProvider.GetDependency<IOrganizationUserRepository>();
var currentContext = sutProvider.GetDependency<ICurrentContext>();
organizationRepository.GetByIdAsync(organization.Id).Returns(organization);
newUserData.Id = oldUserData.Id;
newUserData.UserId = oldUserData.UserId;
newUserData.OrganizationId = savingUser.OrganizationId = oldUserData.OrganizationId;
newUserData.OrganizationId = savingUser.OrganizationId = oldUserData.OrganizationId = organization.Id;
organizationUserRepository.GetByIdAsync(oldUserData.Id).Returns(oldUserData);
organizationUserRepository.GetManyByOrganizationAsync(savingUser.OrganizationId, OrganizationUserType.Owner)
.Returns(new List<OrganizationUser> { savingUser });
currentContext.OrganizationOwner(savingUser.OrganizationId).Returns(true);
await sutProvider.Sut.SaveUserAsync(newUserData, savingUser.UserId, collections);
}
[Theory, BitAutoData]
public async Task SaveUser_WithCustomType_WhenUseCustomPermissionsIsFalse_Throws(
Organization organization,
OrganizationUser oldUserData,
[OrganizationUser(type: OrganizationUserType.Custom)] OrganizationUser newUserData,
IEnumerable<SelectionReadOnly> collections,
[OrganizationUser(type: OrganizationUserType.Owner)] OrganizationUser savingUser,
SutProvider<OrganizationService> sutProvider)
{
organization.UseCustomPermissions = false;
var organizationRepository = sutProvider.GetDependency<IOrganizationRepository>();
var organizationUserRepository = sutProvider.GetDependency<IOrganizationUserRepository>();
var currentContext = sutProvider.GetDependency<ICurrentContext>();
organizationRepository.GetByIdAsync(organization.Id).Returns(organization);
newUserData.Id = oldUserData.Id;
newUserData.UserId = oldUserData.UserId;
newUserData.OrganizationId = savingUser.OrganizationId = oldUserData.OrganizationId = organization.Id;
organizationUserRepository.GetByIdAsync(oldUserData.Id).Returns(oldUserData);
organizationUserRepository.GetManyByOrganizationAsync(savingUser.OrganizationId, OrganizationUserType.Owner)
.Returns(new List<OrganizationUser> { savingUser });
currentContext.OrganizationOwner(savingUser.OrganizationId).Returns(true);
var exception = await Assert.ThrowsAsync<BadRequestException>(
() => sutProvider.Sut.SaveUserAsync(newUserData, savingUser.UserId, collections));
Assert.Contains("to enable custom permissions", exception.Message.ToLowerInvariant());
}
[Theory]
[BitAutoData(OrganizationUserType.Admin)]
[BitAutoData(OrganizationUserType.Manager)]
[BitAutoData(OrganizationUserType.Owner)]
[BitAutoData(OrganizationUserType.User)]
public async Task SaveUser_WithNonCustomType_WhenUseCustomPermissionsIsFalse_Passes(
OrganizationUserType newUserType,
Organization organization,
OrganizationUser oldUserData,
OrganizationUser newUserData,
IEnumerable<SelectionReadOnly> collections,
[OrganizationUser(type: OrganizationUserType.Owner)] OrganizationUser savingUser,
SutProvider<OrganizationService> sutProvider)
{
organization.UseCustomPermissions = false;
var organizationRepository = sutProvider.GetDependency<IOrganizationRepository>();
var organizationUserRepository = sutProvider.GetDependency<IOrganizationUserRepository>();
var currentContext = sutProvider.GetDependency<ICurrentContext>();
organizationRepository.GetByIdAsync(organization.Id).Returns(organization);
newUserData.Id = oldUserData.Id;
newUserData.UserId = oldUserData.UserId;
newUserData.OrganizationId = savingUser.OrganizationId = oldUserData.OrganizationId = organization.Id;
newUserData.Type = newUserType;
organizationUserRepository.GetByIdAsync(oldUserData.Id).Returns(oldUserData);
organizationUserRepository.GetManyByOrganizationAsync(savingUser.OrganizationId, OrganizationUserType.Owner)
.Returns(new List<OrganizationUser> { savingUser });
currentContext.OrganizationOwner(savingUser.OrganizationId).Returns(true);
await sutProvider.Sut.SaveUserAsync(newUserData, savingUser.UserId, collections);
}
[Theory, BitAutoData]
public async Task SaveUser_WithCustomType_WhenUseCustomPermissionsIsTrue_Passes(
Organization organization,
OrganizationUser oldUserData,
[OrganizationUser(type: OrganizationUserType.Custom)] OrganizationUser newUserData,
IEnumerable<SelectionReadOnly> collections,
[OrganizationUser(type: OrganizationUserType.Owner)] OrganizationUser savingUser,
SutProvider<OrganizationService> sutProvider)
{
organization.UseCustomPermissions = true;
var organizationRepository = sutProvider.GetDependency<IOrganizationRepository>();
var organizationUserRepository = sutProvider.GetDependency<IOrganizationUserRepository>();
var currentContext = sutProvider.GetDependency<ICurrentContext>();
organizationRepository.GetByIdAsync(organization.Id).Returns(organization);
newUserData.Id = oldUserData.Id;
newUserData.UserId = oldUserData.UserId;
newUserData.OrganizationId = savingUser.OrganizationId = oldUserData.OrganizationId = organization.Id;
organizationUserRepository.GetByIdAsync(oldUserData.Id).Returns(oldUserData);
organizationUserRepository.GetManyByOrganizationAsync(savingUser.OrganizationId, OrganizationUserType.Owner)
.Returns(new List<OrganizationUser> { savingUser });

View File

@ -34,6 +34,7 @@ public class OrganizationCompare : IEqualityComparer<Organization>
x.UseApi.Equals(y.UseApi) &&
x.SelfHost.Equals(y.SelfHost) &&
x.UsersGetPremium.Equals(y.UsersGetPremium) &&
x.UseCustomPermissions.Equals(y.UseCustomPermissions) &&
x.Storage.Equals(y.Storage) &&
x.MaxStorageGb.Equals(y.MaxStorageGb) &&
x.Gateway.Equals(y.Gateway) &&