1
0
mirror of https://github.com/bitwarden/server.git synced 2024-12-01 13:43:23 +01:00
bitwarden-server/test/Core.Test/Services/OrganizationServiceTests.cs

381 lines
20 KiB
C#
Raw Normal View History

2019-02-19 22:27:05 +01:00
using System;
using System.Collections.Generic;
using System.Threading.Tasks;
using Bit.Core.Models.Data;
using Bit.Core.Models.Table;
using Bit.Core.Models.Business;
2019-02-19 22:27:05 +01:00
using Bit.Core.Repositories;
using Bit.Core.Services;
using Bit.Core.Settings;
2019-02-19 22:27:05 +01:00
using Microsoft.AspNetCore.DataProtection;
using NSubstitute;
using Xunit;
using Bit.Core.Test.AutoFixture;
using Bit.Core.Exceptions;
using Bit.Core.Enums;
using Bit.Core.Test.AutoFixture.Attributes;
using Bit.Core.Test.AutoFixture.OrganizationFixtures;
using System.Text.Json;
2019-02-19 22:27:05 +01:00
namespace Bit.Core.Test.Services
{
public class OrganizationServiceTests
{
[Fact]
public async Task OrgImportCreateNewUsers()
{
var orgRepo = Substitute.For<IOrganizationRepository>();
var orgUserRepo = Substitute.For<IOrganizationUserRepository>();
var collectionRepo = Substitute.For<ICollectionRepository>();
var userRepo = Substitute.For<IUserRepository>();
var groupRepo = Substitute.For<IGroupRepository>();
var dataProtector = Substitute.For<IDataProtector>();
var mailService = Substitute.For<IMailService>();
var pushNotService = Substitute.For<IPushNotificationService>();
var pushRegService = Substitute.For<IPushRegistrationService>();
var deviceRepo = Substitute.For<IDeviceRepository>();
var licenseService = Substitute.For<ILicensingService>();
var eventService = Substitute.For<IEventService>();
var installationRepo = Substitute.For<IInstallationRepository>();
var appCacheService = Substitute.For<IApplicationCacheService>();
var paymentService = Substitute.For<IPaymentService>();
2020-01-15 21:00:54 +01:00
var policyRepo = Substitute.For<IPolicyRepository>();
var ssoConfigRepo = Substitute.For<ISsoConfigRepository>();
var ssoUserRepo = Substitute.For<ISsoUserRepository>();
2020-07-08 21:05:24 +02:00
var referenceEventService = Substitute.For<IReferenceEventService>();
2019-02-19 22:27:05 +01:00
var globalSettings = Substitute.For<GlobalSettings>();
var taxRateRepository = Substitute.For<ITaxRateRepository>();
2019-02-19 22:27:05 +01:00
var orgService = new OrganizationService(orgRepo, orgUserRepo, collectionRepo, userRepo,
groupRepo, dataProtector, mailService, pushNotService, pushRegService, deviceRepo,
2020-01-15 21:00:54 +01:00
licenseService, eventService, installationRepo, appCacheService, paymentService, policyRepo,
ssoConfigRepo, ssoUserRepo, referenceEventService, globalSettings, taxRateRepository);
2019-02-19 22:27:05 +01:00
var id = Guid.NewGuid();
var userId = Guid.NewGuid();
var org = new Organization
{
Id = id,
Name = "Test Org",
UseDirectory = true,
UseGroups = true,
Seats = 3
};
orgRepo.GetByIdAsync(id).Returns(org);
var existingUsers = new List<OrganizationUserUserDetails>();
existingUsers.Add(new OrganizationUserUserDetails
{
Id = Guid.NewGuid(),
ExternalId = "a",
Email = "a@test.com"
});
orgUserRepo.GetManyDetailsByOrganizationAsync(id).Returns(existingUsers);
orgUserRepo.GetCountByOrganizationIdAsync(id).Returns(1);
var newUsers = new List<Models.Business.ImportedOrganizationUser>();
newUsers.Add(new Models.Business.ImportedOrganizationUser { Email = "a@test.com", ExternalId = "a" });
newUsers.Add(new Models.Business.ImportedOrganizationUser { Email = "b@test.com", ExternalId = "b" });
newUsers.Add(new Models.Business.ImportedOrganizationUser { Email = "c@test.com", ExternalId = "c" });
2019-05-07 03:52:21 +02:00
await orgService.ImportAsync(id, userId, null, newUsers, null, false);
2019-02-19 22:27:05 +01:00
await orgUserRepo.DidNotReceive().UpsertAsync(Arg.Any<OrganizationUser>());
await orgUserRepo.Received(2).CreateAsync(Arg.Any<OrganizationUser>());
}
[Fact]
public async Task OrgImportCreateNewUsersAndMarryExistingUser()
{
var orgRepo = Substitute.For<IOrganizationRepository>();
var orgUserRepo = Substitute.For<IOrganizationUserRepository>();
var collectionRepo = Substitute.For<ICollectionRepository>();
var userRepo = Substitute.For<IUserRepository>();
var groupRepo = Substitute.For<IGroupRepository>();
var dataProtector = Substitute.For<IDataProtector>();
var mailService = Substitute.For<IMailService>();
var pushNotService = Substitute.For<IPushNotificationService>();
var pushRegService = Substitute.For<IPushRegistrationService>();
var deviceRepo = Substitute.For<IDeviceRepository>();
var licenseService = Substitute.For<ILicensingService>();
var eventService = Substitute.For<IEventService>();
var installationRepo = Substitute.For<IInstallationRepository>();
var appCacheService = Substitute.For<IApplicationCacheService>();
var paymentService = Substitute.For<IPaymentService>();
2020-01-15 21:00:54 +01:00
var policyRepo = Substitute.For<IPolicyRepository>();
var ssoConfigRepo = Substitute.For<ISsoConfigRepository>();
var ssoUserRepo = Substitute.For<ISsoUserRepository>();
2020-07-08 21:05:24 +02:00
var referenceEventService = Substitute.For<IReferenceEventService>();
2019-02-19 22:27:05 +01:00
var globalSettings = Substitute.For<GlobalSettings>();
var taxRateRepo = Substitute.For<ITaxRateRepository>();
2019-02-19 22:27:05 +01:00
var orgService = new OrganizationService(orgRepo, orgUserRepo, collectionRepo, userRepo,
groupRepo, dataProtector, mailService, pushNotService, pushRegService, deviceRepo,
2020-01-15 21:00:54 +01:00
licenseService, eventService, installationRepo, appCacheService, paymentService, policyRepo,
ssoConfigRepo, ssoUserRepo, referenceEventService, globalSettings, taxRateRepo);
2019-02-19 22:27:05 +01:00
var id = Guid.NewGuid();
var userId = Guid.NewGuid();
var org = new Organization
{
Id = id,
Name = "Test Org",
UseDirectory = true,
UseGroups = true,
Seats = 3
};
orgRepo.GetByIdAsync(id).Returns(org);
var existingUserAId = Guid.NewGuid();
var existingUsers = new List<OrganizationUserUserDetails>();
existingUsers.Add(new OrganizationUserUserDetails
{
Id = existingUserAId,
// No external id here
Email = "a@test.com"
});
orgUserRepo.GetManyDetailsByOrganizationAsync(id).Returns(existingUsers);
orgUserRepo.GetCountByOrganizationIdAsync(id).Returns(1);
orgUserRepo.GetByIdAsync(existingUserAId).Returns(new OrganizationUser { Id = existingUserAId });
var newUsers = new List<Models.Business.ImportedOrganizationUser>();
newUsers.Add(new Models.Business.ImportedOrganizationUser { Email = "a@test.com", ExternalId = "a" });
newUsers.Add(new Models.Business.ImportedOrganizationUser { Email = "b@test.com", ExternalId = "b" });
newUsers.Add(new Models.Business.ImportedOrganizationUser { Email = "c@test.com", ExternalId = "c" });
2019-05-07 03:52:21 +02:00
await orgService.ImportAsync(id, userId, null, newUsers, null, false);
2019-02-19 22:27:05 +01:00
await orgUserRepo.Received(1).UpsertAsync(Arg.Any<OrganizationUser>());
await orgUserRepo.Received(2).CreateAsync(Arg.Any<OrganizationUser>());
}
[Theory, CustomAutoData(typeof(SutProviderCustomization))]
public async Task UpgradePlan_OrganizationIsNull_Throws(Guid organizationId, OrganizationUpgrade upgrade,
SutProvider<OrganizationService> sutProvider)
{
sutProvider.GetDependency<IOrganizationRepository>().GetByIdAsync(organizationId).Returns(Task.FromResult<Organization>(null));
var exception = await Assert.ThrowsAsync<NotFoundException>(
() => sutProvider.Sut.UpgradePlanAsync(organizationId, upgrade));
}
[Theory, CustomAutoData(typeof(SutProviderCustomization))]
public async Task UpgradePlan_GatewayCustomIdIsNull_Throws(Organization organization, OrganizationUpgrade upgrade,
SutProvider<OrganizationService> sutProvider)
{
organization.GatewayCustomerId = string.Empty;
sutProvider.GetDependency<IOrganizationRepository>().GetByIdAsync(organization.Id).Returns(organization);
var exception = await Assert.ThrowsAsync<BadRequestException>(
() => sutProvider.Sut.UpgradePlanAsync(organization.Id, upgrade));
Assert.Contains("no payment method", exception.Message);
}
[Theory, CustomAutoData(typeof(SutProviderCustomization))]
public async Task UpgradePlan_AlreadyInPlan_Throws(Organization organization, OrganizationUpgrade upgrade,
SutProvider<OrganizationService> sutProvider)
{
upgrade.Plan = organization.PlanType;
sutProvider.GetDependency<IOrganizationRepository>().GetByIdAsync(organization.Id).Returns(organization);
var exception = await Assert.ThrowsAsync<BadRequestException>(
() => sutProvider.Sut.UpgradePlanAsync(organization.Id, upgrade));
Assert.Contains("already on this plan", exception.Message);
}
[Theory, PaidOrganizationAutoData]
public async Task UpgradePlan_UpgradeFromPaidPlan_Throws(Organization organization, OrganizationUpgrade upgrade,
SutProvider<OrganizationService> sutProvider)
{
sutProvider.GetDependency<IOrganizationRepository>().GetByIdAsync(organization.Id).Returns(organization);
var exception = await Assert.ThrowsAsync<BadRequestException>(
() => sutProvider.Sut.UpgradePlanAsync(organization.Id, upgrade));
Assert.Contains("can only upgrade", exception.Message);
}
[Theory]
[FreeOrganizationUpgradeAutoData]
public async Task UpgradePlan_Passes(Organization organization, OrganizationUpgrade upgrade,
SutProvider<OrganizationService> sutProvider)
{
sutProvider.GetDependency<IOrganizationRepository>().GetByIdAsync(organization.Id).Returns(organization);
await sutProvider.Sut.UpgradePlanAsync(organization.Id, upgrade);
await sutProvider.GetDependency<IOrganizationRepository>().Received(1).ReplaceAsync(organization);
}
[Theory]
[OrganizationInviteAutoData]
public async Task InviteUser_NoEmails_Throws(Organization organization, OrganizationUser invitor,
OrganizationUserInvite invite, SutProvider<OrganizationService> sutProvider)
{
invite.Emails = null;
sutProvider.GetDependency<IOrganizationRepository>().GetByIdAsync(organization.Id).Returns(organization);
await Assert.ThrowsAsync<NotFoundException>(
() => sutProvider.Sut.InviteUserAsync(organization.Id, invitor.UserId, null, invite));
}
[Theory]
[OrganizationInviteAutoData(
inviteeUserType: (int)OrganizationUserType.Owner,
invitorUserType: (int)OrganizationUserType.Admin
)]
public async Task InviteUser_NonOwnerConfiguringOwner_Throws(Organization organization, OrganizationUserInvite invite,
OrganizationUser invitor, SutProvider<OrganizationService> sutProvider)
{
var organizationRepository = sutProvider.GetDependency<IOrganizationRepository>();
var organizationUserRepository = sutProvider.GetDependency<IOrganizationUserRepository>();
organizationRepository.GetByIdAsync(organization.Id).Returns(organization);
organizationUserRepository.GetManyByUserAsync(invitor.Id).Returns(new List<OrganizationUser> { invitor });
var exception = await Assert.ThrowsAsync<BadRequestException>(
() => sutProvider.Sut.InviteUserAsync(organization.Id, invitor.UserId, null, invite));
Assert.Contains("only an owner", exception.Message.ToLowerInvariant());
}
[Theory]
[OrganizationInviteAutoData(
inviteeUserType: (int)OrganizationUserType.Custom,
invitorUserType: (int)OrganizationUserType.Admin
)]
public async Task InviteUser_NonAdminConfiguringAdmin_Throws(Organization organization, OrganizationUserInvite invite,
OrganizationUser invitor, SutProvider<OrganizationService> sutProvider)
{
var organizationRepository = sutProvider.GetDependency<IOrganizationRepository>();
var organizationUserRepository = sutProvider.GetDependency<IOrganizationUserRepository>();
organizationRepository.GetByIdAsync(organization.Id).Returns(organization);
organizationUserRepository.GetManyByUserAsync(invitor.Id).Returns(new List<OrganizationUser> { invitor });
var exception = await Assert.ThrowsAsync<BadRequestException>(
() => sutProvider.Sut.InviteUserAsync(organization.Id, invitor.UserId, null, invite));
Assert.Contains("only owners and admins", exception.Message.ToLowerInvariant());
}
[Theory]
[OrganizationInviteAutoData(
inviteeUserType: (int)OrganizationUserType.Manager,
invitorUserType: (int)OrganizationUserType.Custom
)]
public async Task InviteUser_CustomUserWithoutManageUsersConfiguringUser_Throws(Organization organization, OrganizationUserInvite invite,
OrganizationUser invitor, SutProvider<OrganizationService> sutProvider)
{
invitor.Permissions = JsonSerializer.Serialize(new Permissions() { ManageUsers = false },
new JsonSerializerOptions
{
PropertyNamingPolicy = JsonNamingPolicy.CamelCase,
});
var organizationRepository = sutProvider.GetDependency<IOrganizationRepository>();
var organizationUserRepository = sutProvider.GetDependency<IOrganizationUserRepository>();
organizationRepository.GetByIdAsync(organization.Id).Returns(organization);
organizationUserRepository.GetManyByUserAsync(invitor.UserId.Value).Returns(new List<OrganizationUser> { invitor });
var exception = await Assert.ThrowsAsync<BadRequestException>(
() => sutProvider.Sut.InviteUserAsync(organization.Id, invitor.UserId, null, invite));
Assert.Contains("account does not have permission", exception.Message.ToLowerInvariant());
}
[Theory]
[OrganizationInviteAutoData(
inviteeUserType: (int)OrganizationUserType.Admin,
invitorUserType: (int)OrganizationUserType.Custom
)]
public async Task InviteUser_CustomUserConfiguringAdmin_Throws(Organization organization, OrganizationUserInvite invite,
OrganizationUser invitor, SutProvider<OrganizationService> sutProvider)
{
invitor.Permissions = JsonSerializer.Serialize(new Permissions() { ManageUsers = true },
new JsonSerializerOptions
{
PropertyNamingPolicy = JsonNamingPolicy.CamelCase,
});
var organizationRepository = sutProvider.GetDependency<IOrganizationRepository>();
var organizationUserRepository = sutProvider.GetDependency<IOrganizationUserRepository>();
organizationRepository.GetByIdAsync(organization.Id).Returns(organization);
organizationUserRepository.GetManyByUserAsync(invitor.UserId.Value).Returns(new List<OrganizationUser> { invitor });
var exception = await Assert.ThrowsAsync<BadRequestException>(
() => sutProvider.Sut.InviteUserAsync(organization.Id, invitor.UserId, null, invite));
Assert.Contains("can not manage admins", exception.Message.ToLowerInvariant());
}
[Theory]
[OrganizationInviteAutoData(
inviteeUserType: (int)OrganizationUserType.User,
invitorUserType: (int)OrganizationUserType.Owner
)]
public async Task InviteUser_NoPermissionsObject_Passes(Organization organization, OrganizationUserInvite invite,
OrganizationUser invitor, SutProvider<OrganizationService> sutProvider)
{
invite.Permissions = null;
var organizationRepository = sutProvider.GetDependency<IOrganizationRepository>();
var organizationUserRepository = sutProvider.GetDependency<IOrganizationUserRepository>();
var eventService = sutProvider.GetDependency<IEventService>();
organizationRepository.GetByIdAsync(organization.Id).Returns(organization);
organizationUserRepository.GetManyByUserAsync(invitor.UserId.Value).Returns(new List<OrganizationUser> { invitor });
await sutProvider.Sut.InviteUserAsync(organization.Id, invitor.UserId, null, invite);
}
[Theory]
[OrganizationInviteAutoData(
inviteeUserType: (int)OrganizationUserType.User,
invitorUserType: (int)OrganizationUserType.Custom
)]
public async Task InviteUser_Passes(Organization organization, OrganizationUserInvite invite,
OrganizationUser invitor, SutProvider<OrganizationService> sutProvider)
{
invitor.Permissions = JsonSerializer.Serialize(new Permissions() { ManageUsers = true },
new JsonSerializerOptions
{
PropertyNamingPolicy = JsonNamingPolicy.CamelCase,
});
var organizationRepository = sutProvider.GetDependency<IOrganizationRepository>();
var organizationUserRepository = sutProvider.GetDependency<IOrganizationUserRepository>();
var eventService = sutProvider.GetDependency<IEventService>();
organizationRepository.GetByIdAsync(organization.Id).Returns(organization);
organizationUserRepository.GetManyByUserAsync(invitor.UserId.Value).Returns(new List<OrganizationUser> { invitor });
await sutProvider.Sut.InviteUserAsync(organization.Id, invitor.UserId, null, invite);
}
[Theory, CustomAutoData(typeof(SutProviderCustomization))]
public async Task SaveUser_NoUserId_Throws(OrganizationUser user, Guid? savingUserId,
IEnumerable<SelectionReadOnly> collections, SutProvider<OrganizationService> sutProvider)
{
user.Id = default(Guid);
var exception = await Assert.ThrowsAsync<BadRequestException>(
() => sutProvider.Sut.SaveUserAsync(user, savingUserId, collections));
Assert.Contains("invite the user first", exception.Message.ToLowerInvariant());
}
[Theory, CustomAutoData(typeof(SutProviderCustomization))]
public async Task SaveUser_NoChangeToData_Throws(OrganizationUser user, Guid? savingUserId,
IEnumerable<SelectionReadOnly> collections, SutProvider<OrganizationService> sutProvider)
{
var organizationUserRepository = sutProvider.GetDependency<IOrganizationUserRepository>();
organizationUserRepository.GetByIdAsync(user.Id).Returns(user);
var exception = await Assert.ThrowsAsync<BadRequestException>(
() => sutProvider.Sut.SaveUserAsync(user, savingUserId, collections));
Assert.Contains("make changes before saving", exception.Message.ToLowerInvariant());
}
[Theory, CustomAutoData(typeof(SutProviderCustomization))]
public async Task SaveUser_Passes(OrganizationUser oldUserData, OrganizationUser newUserData,
IEnumerable<SelectionReadOnly> collections, OrganizationUser savingUser, SutProvider<OrganizationService> sutProvider)
{
var organizationUserRepository = sutProvider.GetDependency<IOrganizationUserRepository>();
newUserData.Id = oldUserData.Id;
newUserData.UserId = oldUserData.UserId;
newUserData.OrganizationId = savingUser.OrganizationId = oldUserData.OrganizationId;
savingUser.Type = OrganizationUserType.Owner;
organizationUserRepository.GetByIdAsync(oldUserData.Id).Returns(oldUserData);
organizationUserRepository.GetManyByUserAsync(savingUser.UserId.Value).Returns(new List<OrganizationUser> { savingUser });
await sutProvider.Sut.SaveUserAsync(newUserData, savingUser.UserId, collections);
}
2019-02-19 22:27:05 +01:00
}
}