mirror of
https://github.com/bitwarden/server.git
synced 2025-06-30 07:36:14 -05:00
[AC-2052] Block Manager role and AccessAll if using FlexibleCollections (#3671)
* Also don't assign AccessAll to the first orgUser if using Flexible Collections
This commit is contained in:
@ -251,6 +251,64 @@ public class OrganizationServiceTests
|
||||
);
|
||||
}
|
||||
|
||||
[Theory]
|
||||
[BitAutoData(PlanType.FamiliesAnnually)]
|
||||
public async Task SignUp_WithFlexibleCollections_SetsAccessAllToFalse
|
||||
(PlanType planType, OrganizationSignup signup, SutProvider<OrganizationService> sutProvider)
|
||||
{
|
||||
signup.Plan = planType;
|
||||
var plan = StaticStore.GetPlan(signup.Plan);
|
||||
signup.AdditionalSeats = 0;
|
||||
signup.PaymentMethodType = PaymentMethodType.Card;
|
||||
signup.PremiumAccessAddon = false;
|
||||
signup.UseSecretsManager = false;
|
||||
|
||||
sutProvider.GetDependency<IFeatureService>()
|
||||
.IsEnabled(FeatureFlagKeys.FlexibleCollectionsSignup)
|
||||
.Returns(true);
|
||||
|
||||
var result = await sutProvider.Sut.SignUpAsync(signup);
|
||||
|
||||
await sutProvider.GetDependency<IOrganizationUserRepository>().Received(1).CreateAsync(
|
||||
Arg.Is<OrganizationUser>(o =>
|
||||
o.UserId == signup.Owner.Id &&
|
||||
o.AccessAll == false));
|
||||
|
||||
Assert.NotNull(result);
|
||||
Assert.NotNull(result.Item1);
|
||||
Assert.NotNull(result.Item2);
|
||||
Assert.IsType<Tuple<Organization, OrganizationUser>>(result);
|
||||
}
|
||||
|
||||
[Theory]
|
||||
[BitAutoData(PlanType.FamiliesAnnually)]
|
||||
public async Task SignUp_WithoutFlexibleCollections_SetsAccessAllToTrue
|
||||
(PlanType planType, OrganizationSignup signup, SutProvider<OrganizationService> sutProvider)
|
||||
{
|
||||
signup.Plan = planType;
|
||||
var plan = StaticStore.GetPlan(signup.Plan);
|
||||
signup.AdditionalSeats = 0;
|
||||
signup.PaymentMethodType = PaymentMethodType.Card;
|
||||
signup.PremiumAccessAddon = false;
|
||||
signup.UseSecretsManager = false;
|
||||
|
||||
sutProvider.GetDependency<IFeatureService>()
|
||||
.IsEnabled(FeatureFlagKeys.FlexibleCollectionsSignup)
|
||||
.Returns(false);
|
||||
|
||||
var result = await sutProvider.Sut.SignUpAsync(signup);
|
||||
|
||||
await sutProvider.GetDependency<IOrganizationUserRepository>().Received(1).CreateAsync(
|
||||
Arg.Is<OrganizationUser>(o =>
|
||||
o.UserId == signup.Owner.Id &&
|
||||
o.AccessAll == true));
|
||||
|
||||
Assert.NotNull(result);
|
||||
Assert.NotNull(result.Item1);
|
||||
Assert.NotNull(result.Item2);
|
||||
Assert.IsType<Tuple<Organization, OrganizationUser>>(result);
|
||||
}
|
||||
|
||||
[Theory]
|
||||
[BitAutoData(PlanType.EnterpriseAnnually)]
|
||||
[BitAutoData(PlanType.EnterpriseMonthly)]
|
||||
@ -378,7 +436,7 @@ public class OrganizationServiceTests
|
||||
|
||||
[Theory]
|
||||
[OrganizationInviteCustomize(InviteeUserType = OrganizationUserType.User,
|
||||
InvitorUserType = OrganizationUserType.Owner), BitAutoData]
|
||||
InvitorUserType = OrganizationUserType.Owner), OrganizationCustomize(FlexibleCollections = false), BitAutoData]
|
||||
public async Task InviteUser_NoEmails_Throws(Organization organization, OrganizationUser invitor,
|
||||
OrganizationUserInvite invite, SutProvider<OrganizationService> sutProvider)
|
||||
{
|
||||
@ -391,7 +449,7 @@ public class OrganizationServiceTests
|
||||
}
|
||||
|
||||
[Theory]
|
||||
[OrganizationInviteCustomize, BitAutoData]
|
||||
[OrganizationInviteCustomize, OrganizationCustomize(FlexibleCollections = false), BitAutoData]
|
||||
public async Task InviteUser_DuplicateEmails_PassesWithoutDuplicates(Organization organization, OrganizationUser invitor,
|
||||
[OrganizationUser(OrganizationUserStatusType.Confirmed, OrganizationUserType.Owner)] OrganizationUser owner,
|
||||
OrganizationUserInvite invite, SutProvider<OrganizationService> sutProvider)
|
||||
@ -434,7 +492,7 @@ public class OrganizationServiceTests
|
||||
}
|
||||
|
||||
[Theory]
|
||||
[OrganizationInviteCustomize, BitAutoData]
|
||||
[OrganizationInviteCustomize, OrganizationCustomize(FlexibleCollections = false), BitAutoData]
|
||||
public async Task InviteUser_SsoOrgWithNullSsoConfig_Passes(Organization organization, OrganizationUser invitor,
|
||||
[OrganizationUser(OrganizationUserStatusType.Confirmed, OrganizationUserType.Owner)] OrganizationUser owner,
|
||||
OrganizationUserInvite invite, SutProvider<OrganizationService> sutProvider)
|
||||
@ -483,7 +541,7 @@ public class OrganizationServiceTests
|
||||
}
|
||||
|
||||
[Theory]
|
||||
[OrganizationInviteCustomize, BitAutoData]
|
||||
[OrganizationInviteCustomize, OrganizationCustomize(FlexibleCollections = false), BitAutoData]
|
||||
public async Task InviteUser_SsoOrgWithNeverEnabledRequireSsoPolicy_Passes(Organization organization, SsoConfig ssoConfig, OrganizationUser invitor,
|
||||
[OrganizationUser(OrganizationUserStatusType.Confirmed, OrganizationUserType.Owner)] OrganizationUser owner,
|
||||
OrganizationUserInvite invite, SutProvider<OrganizationService> sutProvider)
|
||||
@ -537,7 +595,7 @@ OrganizationUserInvite invite, SutProvider<OrganizationService> sutProvider)
|
||||
[OrganizationInviteCustomize(
|
||||
InviteeUserType = OrganizationUserType.Admin,
|
||||
InvitorUserType = OrganizationUserType.Owner
|
||||
), BitAutoData]
|
||||
), OrganizationCustomize(FlexibleCollections = false), BitAutoData]
|
||||
public async Task InviteUser_NoOwner_Throws(Organization organization, OrganizationUser invitor,
|
||||
OrganizationUserInvite invite, SutProvider<OrganizationService> sutProvider)
|
||||
{
|
||||
@ -553,7 +611,7 @@ OrganizationUserInvite invite, SutProvider<OrganizationService> sutProvider)
|
||||
[OrganizationInviteCustomize(
|
||||
InviteeUserType = OrganizationUserType.Owner,
|
||||
InvitorUserType = OrganizationUserType.Admin
|
||||
), BitAutoData]
|
||||
), OrganizationCustomize(FlexibleCollections = false), BitAutoData]
|
||||
public async Task InviteUser_NonOwnerConfiguringOwner_Throws(Organization organization, OrganizationUserInvite invite,
|
||||
OrganizationUser invitor, SutProvider<OrganizationService> sutProvider)
|
||||
{
|
||||
@ -572,7 +630,7 @@ OrganizationUserInvite invite, SutProvider<OrganizationService> sutProvider)
|
||||
[OrganizationInviteCustomize(
|
||||
InviteeUserType = OrganizationUserType.Custom,
|
||||
InvitorUserType = OrganizationUserType.User
|
||||
), BitAutoData]
|
||||
), OrganizationCustomize(FlexibleCollections = false), BitAutoData]
|
||||
public async Task InviteUser_NonAdminConfiguringAdmin_Throws(Organization organization, OrganizationUserInvite invite,
|
||||
OrganizationUser invitor, SutProvider<OrganizationService> sutProvider)
|
||||
{
|
||||
@ -593,7 +651,7 @@ OrganizationUserInvite invite, SutProvider<OrganizationService> sutProvider)
|
||||
[OrganizationInviteCustomize(
|
||||
InviteeUserType = OrganizationUserType.Custom,
|
||||
InvitorUserType = OrganizationUserType.Admin
|
||||
), BitAutoData]
|
||||
), OrganizationCustomize(FlexibleCollections = false), BitAutoData]
|
||||
public async Task InviteUser_WithCustomType_WhenUseCustomPermissionsIsFalse_Throws(Organization organization, OrganizationUserInvite invite,
|
||||
OrganizationUser invitor, SutProvider<OrganizationService> sutProvider)
|
||||
{
|
||||
@ -620,7 +678,7 @@ OrganizationUserInvite invite, SutProvider<OrganizationService> sutProvider)
|
||||
[OrganizationInviteCustomize(
|
||||
InviteeUserType = OrganizationUserType.Custom,
|
||||
InvitorUserType = OrganizationUserType.Admin
|
||||
), BitAutoData]
|
||||
), OrganizationCustomize(FlexibleCollections = false), BitAutoData]
|
||||
public async Task InviteUser_WithCustomType_WhenUseCustomPermissionsIsTrue_Passes(Organization organization, OrganizationUserInvite invite,
|
||||
OrganizationUser invitor, SutProvider<OrganizationService> sutProvider)
|
||||
{
|
||||
@ -646,6 +704,7 @@ OrganizationUserInvite invite, SutProvider<OrganizationService> sutProvider)
|
||||
}
|
||||
|
||||
[Theory]
|
||||
[OrganizationCustomize(FlexibleCollections = false)]
|
||||
[BitAutoData(OrganizationUserType.Admin)]
|
||||
[BitAutoData(OrganizationUserType.Manager)]
|
||||
[BitAutoData(OrganizationUserType.Owner)]
|
||||
@ -679,7 +738,7 @@ OrganizationUserInvite invite, SutProvider<OrganizationService> sutProvider)
|
||||
[OrganizationInviteCustomize(
|
||||
InviteeUserType = OrganizationUserType.Manager,
|
||||
InvitorUserType = OrganizationUserType.Custom
|
||||
), BitAutoData]
|
||||
), OrganizationCustomize(FlexibleCollections = false), BitAutoData]
|
||||
public async Task InviteUser_CustomUserWithoutManageUsersConfiguringUser_Throws(Organization organization, OrganizationUserInvite invite,
|
||||
OrganizationUser invitor, SutProvider<OrganizationService> sutProvider)
|
||||
{
|
||||
@ -707,7 +766,7 @@ OrganizationUserInvite invite, SutProvider<OrganizationService> sutProvider)
|
||||
[OrganizationInviteCustomize(
|
||||
InviteeUserType = OrganizationUserType.Admin,
|
||||
InvitorUserType = OrganizationUserType.Custom
|
||||
), BitAutoData]
|
||||
), OrganizationCustomize(FlexibleCollections = false), BitAutoData]
|
||||
public async Task InviteUser_CustomUserConfiguringAdmin_Throws(Organization organization, OrganizationUserInvite invite,
|
||||
OrganizationUser invitor, SutProvider<OrganizationService> sutProvider)
|
||||
{
|
||||
@ -733,7 +792,7 @@ OrganizationUserInvite invite, SutProvider<OrganizationService> sutProvider)
|
||||
[OrganizationInviteCustomize(
|
||||
InviteeUserType = OrganizationUserType.User,
|
||||
InvitorUserType = OrganizationUserType.Owner
|
||||
), BitAutoData]
|
||||
), OrganizationCustomize(FlexibleCollections = false), BitAutoData]
|
||||
public async Task InviteUser_NoPermissionsObject_Passes(Organization organization, OrganizationUserInvite invite,
|
||||
OrganizationUser invitor, SutProvider<OrganizationService> sutProvider)
|
||||
{
|
||||
@ -759,7 +818,7 @@ OrganizationUserInvite invite, SutProvider<OrganizationService> sutProvider)
|
||||
[OrganizationInviteCustomize(
|
||||
InviteeUserType = OrganizationUserType.User,
|
||||
InvitorUserType = OrganizationUserType.Custom
|
||||
), BitAutoData]
|
||||
), OrganizationCustomize(FlexibleCollections = false), BitAutoData]
|
||||
public async Task InviteUser_Passes(Organization organization, IEnumerable<(OrganizationUserInvite invite, string externalId)> invites,
|
||||
OrganizationUser invitor,
|
||||
[OrganizationUser(OrganizationUserStatusType.Confirmed, OrganizationUserType.Owner)] OrganizationUser owner,
|
||||
@ -832,7 +891,7 @@ OrganizationUserInvite invite, SutProvider<OrganizationService> sutProvider)
|
||||
[OrganizationInviteCustomize(
|
||||
InviteeUserType = OrganizationUserType.User,
|
||||
InvitorUserType = OrganizationUserType.Custom
|
||||
), BitAutoData]
|
||||
), OrganizationCustomize(FlexibleCollections = false), BitAutoData]
|
||||
public async Task InviteUser_WithEventSystemUser_Passes(Organization organization, EventSystemUser eventSystemUser, IEnumerable<(OrganizationUserInvite invite, string externalId)> invites,
|
||||
OrganizationUser invitor,
|
||||
[OrganizationUser(OrganizationUserStatusType.Confirmed, OrganizationUserType.Owner)] OrganizationUser owner,
|
||||
@ -882,7 +941,7 @@ OrganizationUserInvite invite, SutProvider<OrganizationService> sutProvider)
|
||||
await sutProvider.GetDependency<IEventService>().Received(1).LogOrganizationUserEventsAsync(Arg.Any<IEnumerable<(OrganizationUser, EventType, EventSystemUser, DateTime?)>>());
|
||||
}
|
||||
|
||||
[Theory, BitAutoData, OrganizationInviteCustomize]
|
||||
[Theory, BitAutoData, OrganizationCustomize(FlexibleCollections = false), OrganizationInviteCustomize]
|
||||
public async Task InviteUser_WithSecretsManager_Passes(Organization organization,
|
||||
IEnumerable<(OrganizationUserInvite invite, string externalId)> invites,
|
||||
OrganizationUser savingUser, SutProvider<OrganizationService> sutProvider)
|
||||
@ -916,7 +975,7 @@ OrganizationUserInvite invite, SutProvider<OrganizationService> sutProvider)
|
||||
!update.MaxAutoscaleSmSeatsChanged));
|
||||
}
|
||||
|
||||
[Theory, BitAutoData, OrganizationInviteCustomize]
|
||||
[Theory, BitAutoData, OrganizationCustomize(FlexibleCollections = false), OrganizationInviteCustomize]
|
||||
public async Task InviteUser_WithSecretsManager_WhenErrorIsThrown_RevertsAutoscaling(Organization organization,
|
||||
IEnumerable<(OrganizationUserInvite invite, string externalId)> invites,
|
||||
OrganizationUser savingUser, SutProvider<OrganizationService> sutProvider)
|
||||
@ -972,26 +1031,48 @@ OrganizationUserInvite invite, SutProvider<OrganizationService> sutProvider)
|
||||
});
|
||||
}
|
||||
|
||||
[Theory, BitAutoData]
|
||||
public async Task InviteUser_WithFCEnabled_WhenInvitingManager_Throws(OrganizationAbility organizationAbility,
|
||||
[Theory, OrganizationCustomize(FlexibleCollections = true), BitAutoData]
|
||||
public async Task InviteUser_WithFlexibleCollections_WhenInvitingManager_Throws(Organization organization,
|
||||
OrganizationUserInvite invite, OrganizationUser invitor, SutProvider<OrganizationService> sutProvider)
|
||||
{
|
||||
invite.Type = OrganizationUserType.Manager;
|
||||
organizationAbility.FlexibleCollections = true;
|
||||
organization.FlexibleCollections = true;
|
||||
|
||||
sutProvider.GetDependency<IApplicationCacheService>()
|
||||
.GetOrganizationAbilityAsync(organizationAbility.Id)
|
||||
.Returns(organizationAbility);
|
||||
sutProvider.GetDependency<IOrganizationRepository>()
|
||||
.GetByIdAsync(organization.Id)
|
||||
.Returns(organization);
|
||||
|
||||
sutProvider.GetDependency<ICurrentContext>()
|
||||
.ManageUsers(organizationAbility.Id)
|
||||
.ManageUsers(organization.Id)
|
||||
.Returns(true);
|
||||
|
||||
var exception = await Assert.ThrowsAsync<BadRequestException>(
|
||||
() => sutProvider.Sut.InviteUsersAsync(organizationAbility.Id, invitor.UserId,
|
||||
() => sutProvider.Sut.InviteUsersAsync(organization.Id, invitor.UserId,
|
||||
new (OrganizationUserInvite, string)[] { (invite, null) }));
|
||||
|
||||
Assert.Contains("manager role is deprecated", exception.Message.ToLowerInvariant());
|
||||
Assert.Contains("manager role has been deprecated", exception.Message.ToLowerInvariant());
|
||||
}
|
||||
|
||||
[Theory, OrganizationCustomize(FlexibleCollections = true), BitAutoData]
|
||||
public async Task InviteUser_WithFlexibleCollections_WithAccessAll_Throws(Organization organization,
|
||||
OrganizationUserInvite invite, OrganizationUser invitor, SutProvider<OrganizationService> sutProvider)
|
||||
{
|
||||
invite.Type = OrganizationUserType.User;
|
||||
invite.AccessAll = true;
|
||||
|
||||
sutProvider.GetDependency<IOrganizationRepository>()
|
||||
.GetByIdAsync(organization.Id)
|
||||
.Returns(organization);
|
||||
|
||||
sutProvider.GetDependency<ICurrentContext>()
|
||||
.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("accessall property has been deprecated", exception.Message.ToLowerInvariant());
|
||||
}
|
||||
|
||||
private void InviteUserHelper_ArrangeValidPermissions(Organization organization, OrganizationUser savingUser,
|
||||
@ -1275,15 +1356,21 @@ OrganizationUserInvite invite, SutProvider<OrganizationService> sutProvider)
|
||||
}
|
||||
|
||||
[Theory, BitAutoData]
|
||||
public async Task SaveUser_WithFCEnabled_WhenUpgradingToManager_Throws(
|
||||
public async Task SaveUser_WithFlexibleCollections_WhenUpgradingToManager_Throws(
|
||||
OrganizationAbility organizationAbility,
|
||||
[OrganizationUser(type: OrganizationUserType.User)] OrganizationUser oldUserData,
|
||||
[OrganizationUser(type: OrganizationUserType.Manager)] OrganizationUser newUserData,
|
||||
[OrganizationUser(type: OrganizationUserType.Owner, status: OrganizationUserStatusType.Confirmed)] OrganizationUser savingUser,
|
||||
IEnumerable<CollectionAccessSelection> collections,
|
||||
IEnumerable<Guid> groups,
|
||||
SutProvider<OrganizationService> sutProvider)
|
||||
{
|
||||
organizationAbility.FlexibleCollections = true;
|
||||
newUserData.Id = oldUserData.Id;
|
||||
newUserData.UserId = oldUserData.UserId;
|
||||
newUserData.OrganizationId = oldUserData.OrganizationId = savingUser.OrganizationId = organizationAbility.Id;
|
||||
newUserData.Permissions = CoreHelpers.ClassToJsonData(new Permissions());
|
||||
|
||||
sutProvider.GetDependency<IApplicationCacheService>()
|
||||
.GetOrganizationAbilityAsync(organizationAbility.Id)
|
||||
.Returns(organizationAbility);
|
||||
@ -1296,15 +1383,53 @@ OrganizationUserInvite invite, SutProvider<OrganizationService> sutProvider)
|
||||
.GetByIdAsync(oldUserData.Id)
|
||||
.Returns(oldUserData);
|
||||
|
||||
newUserData.Id = oldUserData.Id;
|
||||
newUserData.UserId = oldUserData.UserId;
|
||||
newUserData.OrganizationId = oldUserData.OrganizationId = organizationAbility.Id;
|
||||
newUserData.Permissions = CoreHelpers.ClassToJsonData(new Permissions());
|
||||
sutProvider.GetDependency<IOrganizationUserRepository>()
|
||||
.GetManyByOrganizationAsync(organizationAbility.Id, OrganizationUserType.Owner)
|
||||
.Returns(new List<OrganizationUser> { savingUser });
|
||||
|
||||
var exception = await Assert.ThrowsAsync<BadRequestException>(
|
||||
() => sutProvider.Sut.SaveUserAsync(newUserData, oldUserData.UserId, collections, groups));
|
||||
|
||||
Assert.Contains("manager role is deprecated", exception.Message.ToLowerInvariant());
|
||||
Assert.Contains("manager role has been deprecated", exception.Message.ToLowerInvariant());
|
||||
}
|
||||
|
||||
[Theory, BitAutoData]
|
||||
public async Task SaveUser_WithFlexibleCollections_WithAccessAll_Throws(
|
||||
OrganizationAbility organizationAbility,
|
||||
[OrganizationUser(type: OrganizationUserType.User)] OrganizationUser oldUserData,
|
||||
[OrganizationUser(type: OrganizationUserType.User)] OrganizationUser newUserData,
|
||||
[OrganizationUser(type: OrganizationUserType.Owner, status: OrganizationUserStatusType.Confirmed)] OrganizationUser savingUser,
|
||||
IEnumerable<CollectionAccessSelection> collections,
|
||||
IEnumerable<Guid> groups,
|
||||
SutProvider<OrganizationService> sutProvider)
|
||||
{
|
||||
organizationAbility.FlexibleCollections = true;
|
||||
newUserData.Id = oldUserData.Id;
|
||||
newUserData.UserId = oldUserData.UserId;
|
||||
newUserData.OrganizationId = oldUserData.OrganizationId = savingUser.OrganizationId = organizationAbility.Id;
|
||||
newUserData.Permissions = CoreHelpers.ClassToJsonData(new Permissions());
|
||||
newUserData.AccessAll = true;
|
||||
|
||||
sutProvider.GetDependency<IApplicationCacheService>()
|
||||
.GetOrganizationAbilityAsync(organizationAbility.Id)
|
||||
.Returns(organizationAbility);
|
||||
|
||||
sutProvider.GetDependency<ICurrentContext>()
|
||||
.ManageUsers(organizationAbility.Id)
|
||||
.Returns(true);
|
||||
|
||||
sutProvider.GetDependency<IOrganizationUserRepository>()
|
||||
.GetByIdAsync(oldUserData.Id)
|
||||
.Returns(oldUserData);
|
||||
|
||||
sutProvider.GetDependency<IOrganizationUserRepository>()
|
||||
.GetManyByOrganizationAsync(organizationAbility.Id, OrganizationUserType.Owner)
|
||||
.Returns(new List<OrganizationUser> { savingUser });
|
||||
|
||||
var exception = await Assert.ThrowsAsync<BadRequestException>(
|
||||
() => sutProvider.Sut.SaveUserAsync(newUserData, oldUserData.UserId, collections, groups));
|
||||
|
||||
Assert.Contains("the accessall property has been deprecated", exception.Message.ToLowerInvariant());
|
||||
}
|
||||
|
||||
[Theory, BitAutoData]
|
||||
|
Reference in New Issue
Block a user