mirror of
https://github.com/bitwarden/server.git
synced 2025-07-01 16:12:49 -05:00
[AC-1751] AC Team code ownership moves: OrganizationUser (part 1) (#3487)
* Move OrganizationUser domain to AC Team ownership * Namespaces will be updated in a separate commit
This commit is contained in:
@ -0,0 +1,54 @@
|
||||
using System.Diagnostics.CodeAnalysis;
|
||||
using Bit.Core.AdminConsole.Entities;
|
||||
|
||||
namespace Bit.Infrastructure.EFIntegration.Test.Repositories.EqualityComparers;
|
||||
|
||||
public class OrganizationCompare : IEqualityComparer<Organization>
|
||||
{
|
||||
public bool Equals(Organization x, Organization y)
|
||||
{
|
||||
var a = x.ExpirationDate.ToString();
|
||||
var b = y.ExpirationDate.ToString();
|
||||
return x.Identifier.Equals(y.Identifier) &&
|
||||
x.Name.Equals(y.Name) &&
|
||||
x.BusinessName.Equals(y.BusinessName) &&
|
||||
x.BusinessAddress1.Equals(y.BusinessAddress1) &&
|
||||
x.BusinessAddress2.Equals(y.BusinessAddress2) &&
|
||||
x.BusinessAddress3.Equals(y.BusinessAddress3) &&
|
||||
x.BusinessCountry.Equals(y.BusinessCountry) &&
|
||||
x.BusinessTaxNumber.Equals(y.BusinessTaxNumber) &&
|
||||
x.BillingEmail.Equals(y.BillingEmail) &&
|
||||
x.Plan.Equals(y.Plan) &&
|
||||
x.PlanType.Equals(y.PlanType) &&
|
||||
x.Seats.Equals(y.Seats) &&
|
||||
x.MaxCollections.Equals(y.MaxCollections) &&
|
||||
x.UsePolicies.Equals(y.UsePolicies) &&
|
||||
x.UseSso.Equals(y.UseSso) &&
|
||||
x.UseKeyConnector.Equals(y.UseKeyConnector) &&
|
||||
x.UseScim.Equals(y.UseScim) &&
|
||||
x.UseGroups.Equals(y.UseGroups) &&
|
||||
x.UseDirectory.Equals(y.UseDirectory) &&
|
||||
x.UseEvents.Equals(y.UseEvents) &&
|
||||
x.UseTotp.Equals(y.UseTotp) &&
|
||||
x.Use2fa.Equals(y.Use2fa) &&
|
||||
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) &&
|
||||
x.GatewayCustomerId.Equals(y.GatewayCustomerId) &&
|
||||
x.GatewaySubscriptionId.Equals(y.GatewaySubscriptionId) &&
|
||||
x.ReferenceData.Equals(y.ReferenceData) &&
|
||||
x.Enabled.Equals(y.Enabled) &&
|
||||
x.LicenseKey.Equals(y.LicenseKey) &&
|
||||
x.TwoFactorProviders.Equals(y.TwoFactorProviders) &&
|
||||
x.ExpirationDate.ToString().Equals(y.ExpirationDate.ToString());
|
||||
}
|
||||
|
||||
public int GetHashCode([DisallowNull] Organization obj)
|
||||
{
|
||||
return base.GetHashCode();
|
||||
}
|
||||
}
|
@ -0,0 +1,22 @@
|
||||
using System.Diagnostics.CodeAnalysis;
|
||||
using Bit.Core.Entities;
|
||||
|
||||
namespace Bit.Infrastructure.EFIntegration.Test.Repositories.EqualityComparers;
|
||||
|
||||
public class OrganizationUserCompare : IEqualityComparer<OrganizationUser>
|
||||
{
|
||||
public bool Equals(OrganizationUser x, OrganizationUser y)
|
||||
{
|
||||
return x.Email == y.Email &&
|
||||
x.Status == y.Status &&
|
||||
x.Type == y.Type &&
|
||||
x.AccessAll == y.AccessAll &&
|
||||
x.ExternalId == y.ExternalId &&
|
||||
x.Permissions == y.Permissions;
|
||||
}
|
||||
|
||||
public int GetHashCode([DisallowNull] OrganizationUser obj)
|
||||
{
|
||||
return base.GetHashCode();
|
||||
}
|
||||
}
|
@ -0,0 +1,43 @@
|
||||
using Bit.Core.Models.Data.Organizations.OrganizationUsers;
|
||||
|
||||
namespace Bit.Infrastructure.EFIntegration.Test.Repositories.EqualityComparers;
|
||||
|
||||
public class OrganizationUserPolicyDetailsCompare : IEqualityComparer<OrganizationUserPolicyDetails>
|
||||
{
|
||||
public bool Equals(OrganizationUserPolicyDetails x, OrganizationUserPolicyDetails y)
|
||||
{
|
||||
if (ReferenceEquals(x, y))
|
||||
{
|
||||
return true;
|
||||
}
|
||||
|
||||
if (ReferenceEquals(x, null))
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
if (ReferenceEquals(y, null))
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
if (x.GetType() != y.GetType())
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
return x.OrganizationId.Equals(y.OrganizationId) &&
|
||||
x.PolicyType == y.PolicyType &&
|
||||
x.PolicyEnabled == y.PolicyEnabled &&
|
||||
x.PolicyData == y.PolicyData &&
|
||||
x.OrganizationUserType == y.OrganizationUserType &&
|
||||
x.OrganizationUserStatus == y.OrganizationUserStatus &&
|
||||
x.OrganizationUserPermissionsData == y.OrganizationUserPermissionsData &&
|
||||
x.IsProvider == y.IsProvider;
|
||||
}
|
||||
|
||||
public int GetHashCode(OrganizationUserPolicyDetails obj)
|
||||
{
|
||||
return HashCode.Combine(obj.OrganizationId, (int)obj.PolicyType, obj.PolicyEnabled, obj.PolicyData, (int)obj.OrganizationUserType, (int)obj.OrganizationUserStatus, obj.OrganizationUserPermissionsData, obj.IsProvider);
|
||||
}
|
||||
}
|
@ -0,0 +1,291 @@
|
||||
using System.Text.Json;
|
||||
using Bit.Core.AdminConsole.Entities;
|
||||
using Bit.Core.AdminConsole.Entities.Provider;
|
||||
using Bit.Core.AdminConsole.Enums;
|
||||
using Bit.Core.AdminConsole.Repositories;
|
||||
using Bit.Core.Entities;
|
||||
using Bit.Core.Enums;
|
||||
using Bit.Core.Models.Data;
|
||||
using Bit.Core.Models.Data.Organizations.OrganizationUsers;
|
||||
using Bit.Core.Repositories;
|
||||
using Bit.Core.Test.AutoFixture.Attributes;
|
||||
using Bit.Infrastructure.EFIntegration.Test.AutoFixture;
|
||||
using Bit.Infrastructure.EFIntegration.Test.Repositories.EqualityComparers;
|
||||
using Xunit;
|
||||
using EfAdminConsoleRepo = Bit.Infrastructure.EntityFramework.AdminConsole.Repositories;
|
||||
using EfRepo = Bit.Infrastructure.EntityFramework.Repositories;
|
||||
using OrganizationUser = Bit.Core.Entities.OrganizationUser;
|
||||
using SqlAdminConsoleRepo = Bit.Infrastructure.Dapper.AdminConsole.Repositories;
|
||||
using SqlRepo = Bit.Infrastructure.Dapper.Repositories;
|
||||
|
||||
namespace Bit.Infrastructure.EFIntegration.Test.Repositories;
|
||||
|
||||
public class OrganizationUserRepositoryTests
|
||||
{
|
||||
[CiSkippedTheory, EfOrganizationUserAutoData]
|
||||
public async void CreateAsync_Works_DataMatches(OrganizationUser orgUser, User user, Organization org,
|
||||
OrganizationUserCompare equalityComparer, List<EfRepo.OrganizationUserRepository> suts,
|
||||
List<EfRepo.OrganizationRepository> efOrgRepos, List<EfRepo.UserRepository> efUserRepos,
|
||||
SqlRepo.OrganizationUserRepository sqlOrgUserRepo, SqlRepo.UserRepository sqlUserRepo,
|
||||
SqlRepo.OrganizationRepository sqlOrgRepo)
|
||||
{
|
||||
var savedOrgUsers = new List<OrganizationUser>();
|
||||
foreach (var sut in suts)
|
||||
{
|
||||
var i = suts.IndexOf(sut);
|
||||
var postEfUser = await efUserRepos[i].CreateAsync(user);
|
||||
var postEfOrg = await efOrgRepos[i].CreateAsync(org);
|
||||
sut.ClearChangeTracking();
|
||||
|
||||
orgUser.UserId = postEfUser.Id;
|
||||
orgUser.OrganizationId = postEfOrg.Id;
|
||||
var postEfOrgUser = await sut.CreateAsync(orgUser);
|
||||
sut.ClearChangeTracking();
|
||||
|
||||
var savedOrgUser = await sut.GetByIdAsync(postEfOrgUser.Id);
|
||||
savedOrgUsers.Add(savedOrgUser);
|
||||
}
|
||||
|
||||
var postSqlUser = await sqlUserRepo.CreateAsync(user);
|
||||
var postSqlOrg = await sqlOrgRepo.CreateAsync(org);
|
||||
|
||||
orgUser.UserId = postSqlUser.Id;
|
||||
orgUser.OrganizationId = postSqlOrg.Id;
|
||||
var sqlOrgUser = await sqlOrgUserRepo.CreateAsync(orgUser);
|
||||
|
||||
var savedSqlOrgUser = await sqlOrgUserRepo.GetByIdAsync(sqlOrgUser.Id);
|
||||
savedOrgUsers.Add(savedSqlOrgUser);
|
||||
|
||||
var distinctItems = savedOrgUsers.Distinct(equalityComparer);
|
||||
Assert.True(!distinctItems.Skip(1).Any());
|
||||
}
|
||||
|
||||
[CiSkippedTheory, EfOrganizationUserAutoData]
|
||||
public async void ReplaceAsync_Works_DataMatches(
|
||||
OrganizationUser postOrgUser,
|
||||
OrganizationUser replaceOrgUser,
|
||||
User user,
|
||||
Organization org,
|
||||
OrganizationUserCompare equalityComparer,
|
||||
List<EfRepo.OrganizationUserRepository> suts,
|
||||
List<EfRepo.UserRepository> efUserRepos,
|
||||
List<EfRepo.OrganizationRepository> efOrgRepos,
|
||||
SqlRepo.OrganizationUserRepository sqlOrgUserRepo,
|
||||
SqlRepo.UserRepository sqlUserRepo,
|
||||
SqlRepo.OrganizationRepository sqlOrgRepo
|
||||
)
|
||||
{
|
||||
var savedOrgUsers = new List<OrganizationUser>();
|
||||
foreach (var sut in suts)
|
||||
{
|
||||
var i = suts.IndexOf(sut);
|
||||
var postEfUser = await efUserRepos[i].CreateAsync(user);
|
||||
var postEfOrg = await efOrgRepos[i].CreateAsync(org);
|
||||
sut.ClearChangeTracking();
|
||||
|
||||
postOrgUser.UserId = replaceOrgUser.UserId = postEfUser.Id;
|
||||
postOrgUser.OrganizationId = replaceOrgUser.OrganizationId = postEfOrg.Id;
|
||||
var postEfOrgUser = await sut.CreateAsync(postOrgUser);
|
||||
sut.ClearChangeTracking();
|
||||
|
||||
replaceOrgUser.Id = postOrgUser.Id;
|
||||
await sut.ReplaceAsync(replaceOrgUser);
|
||||
sut.ClearChangeTracking();
|
||||
|
||||
var replacedOrganizationUser = await sut.GetByIdAsync(replaceOrgUser.Id);
|
||||
savedOrgUsers.Add(replacedOrganizationUser);
|
||||
}
|
||||
|
||||
var postSqlUser = await sqlUserRepo.CreateAsync(user);
|
||||
var postSqlOrg = await sqlOrgRepo.CreateAsync(org);
|
||||
|
||||
postOrgUser.UserId = replaceOrgUser.UserId = postSqlUser.Id;
|
||||
postOrgUser.OrganizationId = replaceOrgUser.OrganizationId = postSqlOrg.Id;
|
||||
var postSqlOrgUser = await sqlOrgUserRepo.CreateAsync(postOrgUser);
|
||||
|
||||
replaceOrgUser.Id = postSqlOrgUser.Id;
|
||||
await sqlOrgUserRepo.ReplaceAsync(replaceOrgUser);
|
||||
|
||||
var replacedSqlUser = await sqlOrgUserRepo.GetByIdAsync(replaceOrgUser.Id);
|
||||
|
||||
var distinctItems = savedOrgUsers.Distinct(equalityComparer);
|
||||
Assert.True(!distinctItems.Skip(1).Any());
|
||||
}
|
||||
|
||||
[CiSkippedTheory, EfOrganizationUserAutoData]
|
||||
public async void DeleteAsync_Works_DataMatches(OrganizationUser orgUser, User user, Organization org, List<EfRepo.OrganizationUserRepository> suts,
|
||||
List<EfRepo.UserRepository> efUserRepos, List<EfRepo.OrganizationRepository> efOrgRepos,
|
||||
SqlRepo.OrganizationUserRepository sqlOrgUserRepo, SqlRepo.UserRepository sqlUserRepo,
|
||||
SqlRepo.OrganizationRepository sqlOrgRepo)
|
||||
{
|
||||
foreach (var sut in suts)
|
||||
{
|
||||
var i = suts.IndexOf(sut);
|
||||
var postEfUser = await efUserRepos[i].CreateAsync(user);
|
||||
var postEfOrg = await efOrgRepos[i].CreateAsync(org);
|
||||
sut.ClearChangeTracking();
|
||||
|
||||
orgUser.UserId = postEfUser.Id;
|
||||
orgUser.OrganizationId = postEfOrg.Id;
|
||||
var postEfOrgUser = await sut.CreateAsync(orgUser);
|
||||
sut.ClearChangeTracking();
|
||||
|
||||
var savedEfOrgUser = await sut.GetByIdAsync(postEfOrgUser.Id);
|
||||
Assert.True(savedEfOrgUser != null);
|
||||
sut.ClearChangeTracking();
|
||||
|
||||
await sut.DeleteAsync(savedEfOrgUser);
|
||||
sut.ClearChangeTracking();
|
||||
|
||||
savedEfOrgUser = await sut.GetByIdAsync(savedEfOrgUser.Id);
|
||||
Assert.True(savedEfOrgUser == null);
|
||||
}
|
||||
|
||||
var postSqlUser = await sqlUserRepo.CreateAsync(user);
|
||||
var postSqlOrg = await sqlOrgRepo.CreateAsync(org);
|
||||
|
||||
orgUser.UserId = postSqlUser.Id;
|
||||
orgUser.OrganizationId = postSqlOrg.Id;
|
||||
var postSqlOrgUser = await sqlOrgUserRepo.CreateAsync(orgUser);
|
||||
|
||||
var savedSqlOrgUser = await sqlOrgUserRepo.GetByIdAsync(postSqlOrgUser.Id);
|
||||
Assert.True(savedSqlOrgUser != null);
|
||||
|
||||
await sqlOrgUserRepo.DeleteAsync(postSqlOrgUser);
|
||||
savedSqlOrgUser = await sqlOrgUserRepo.GetByIdAsync(postSqlOrgUser.Id);
|
||||
Assert.True(savedSqlOrgUser == null);
|
||||
}
|
||||
|
||||
[CiSkippedTheory]
|
||||
[EfPolicyApplicableToUserInlineAutoData(OrganizationUserType.User, false, OrganizationUserStatusType.Confirmed, true, false)] // Ordinary user
|
||||
[EfPolicyApplicableToUserInlineAutoData(OrganizationUserType.User, false, OrganizationUserStatusType.Invited, true, false)] // Invited user
|
||||
[EfPolicyApplicableToUserInlineAutoData(OrganizationUserType.Owner, false, OrganizationUserStatusType.Confirmed, true, false)] // Owner
|
||||
[EfPolicyApplicableToUserInlineAutoData(OrganizationUserType.Admin, false, OrganizationUserStatusType.Confirmed, true, false)] // Admin
|
||||
[EfPolicyApplicableToUserInlineAutoData(OrganizationUserType.User, true, OrganizationUserStatusType.Confirmed, true, false)] // canManagePolicies
|
||||
[EfPolicyApplicableToUserInlineAutoData(OrganizationUserType.User, false, OrganizationUserStatusType.Confirmed, true, true)] // Provider
|
||||
[EfPolicyApplicableToUserInlineAutoData(OrganizationUserType.User, false, OrganizationUserStatusType.Confirmed, false, false)] // Policy disabled
|
||||
[EfPolicyApplicableToUserInlineAutoData(OrganizationUserType.User, false, OrganizationUserStatusType.Confirmed, true, false)] // No policy of Type
|
||||
[EfPolicyApplicableToUserInlineAutoData(OrganizationUserType.User, false, OrganizationUserStatusType.Invited, true, false)] // User not minStatus
|
||||
public async void GetByUserIdWithPolicyDetailsAsync_Works_DataMatches(
|
||||
// Inline data
|
||||
OrganizationUserType userType,
|
||||
bool canManagePolicies,
|
||||
OrganizationUserStatusType orgUserStatus,
|
||||
bool policyEnabled,
|
||||
bool isProvider,
|
||||
|
||||
// Auto data - models
|
||||
Policy policy,
|
||||
User user,
|
||||
Organization organization,
|
||||
OrganizationUser orgUser,
|
||||
Provider provider,
|
||||
ProviderOrganization providerOrganization,
|
||||
ProviderUser providerUser,
|
||||
OrganizationUserPolicyDetailsCompare equalityComparer,
|
||||
|
||||
// Auto data - EF repos
|
||||
List<EfAdminConsoleRepo.PolicyRepository> efPolicyRepository,
|
||||
List<EfRepo.UserRepository> efUserRepository,
|
||||
List<EfRepo.OrganizationRepository> efOrganizationRepository,
|
||||
List<EfRepo.OrganizationUserRepository> suts,
|
||||
List<EfAdminConsoleRepo.ProviderRepository> efProviderRepository,
|
||||
List<EfAdminConsoleRepo.ProviderOrganizationRepository> efProviderOrganizationRepository,
|
||||
List<EfAdminConsoleRepo.ProviderUserRepository> efProviderUserRepository,
|
||||
|
||||
// Auto data - SQL repos
|
||||
SqlAdminConsoleRepo.PolicyRepository sqlPolicyRepo,
|
||||
SqlRepo.UserRepository sqlUserRepo,
|
||||
SqlRepo.OrganizationRepository sqlOrganizationRepo,
|
||||
EfAdminConsoleRepo.ProviderRepository sqlProviderRepo,
|
||||
SqlRepo.OrganizationUserRepository sqlOrganizationUserRepo,
|
||||
EfAdminConsoleRepo.ProviderOrganizationRepository sqlProviderOrganizationRepo,
|
||||
EfAdminConsoleRepo.ProviderUserRepository sqlProviderUserRepo
|
||||
)
|
||||
{
|
||||
// Combine EF and SQL repos into one list per type
|
||||
var policyRepos = efPolicyRepository.ToList<IPolicyRepository>();
|
||||
policyRepos.Add(sqlPolicyRepo);
|
||||
var userRepos = efUserRepository.ToList<IUserRepository>();
|
||||
userRepos.Add(sqlUserRepo);
|
||||
var orgRepos = efOrganizationRepository.ToList<IOrganizationRepository>();
|
||||
orgRepos.Add(sqlOrganizationRepo);
|
||||
var orgUserRepos = suts.ToList<IOrganizationUserRepository>();
|
||||
orgUserRepos.Add(sqlOrganizationUserRepo);
|
||||
var providerRepos = efProviderRepository.ToList<IProviderRepository>();
|
||||
providerRepos.Add(sqlProviderRepo);
|
||||
var providerOrgRepos = efProviderOrganizationRepository.ToList<IProviderOrganizationRepository>();
|
||||
providerOrgRepos.Add(sqlProviderOrganizationRepo);
|
||||
var providerUserRepos = efProviderUserRepository.ToList<IProviderUserRepository>();
|
||||
providerUserRepos.Add(sqlProviderUserRepo);
|
||||
|
||||
// Arrange data
|
||||
var savedPolicyType = PolicyType.SingleOrg;
|
||||
|
||||
orgUser.Type = userType;
|
||||
orgUser.Status = orgUserStatus;
|
||||
var permissionsData = new Permissions { ManagePolicies = canManagePolicies };
|
||||
orgUser.Permissions = JsonSerializer.Serialize(permissionsData, new JsonSerializerOptions
|
||||
{
|
||||
PropertyNamingPolicy = JsonNamingPolicy.CamelCase,
|
||||
});
|
||||
|
||||
policy.Enabled = policyEnabled;
|
||||
policy.Type = savedPolicyType;
|
||||
|
||||
var results = new List<OrganizationUserPolicyDetails>();
|
||||
|
||||
foreach (var policyRepo in policyRepos)
|
||||
{
|
||||
var i = policyRepos.IndexOf(policyRepo);
|
||||
|
||||
// Seed database
|
||||
user.CreationDate = user.RevisionDate = DateTime.Now;
|
||||
var savedUser = await userRepos[i].CreateAsync(user);
|
||||
var savedOrg = await orgRepos[i].CreateAsync(organization);
|
||||
|
||||
// Invited orgUsers are not associated with an account yet, so they are identified by Email not UserId
|
||||
if (orgUserStatus == OrganizationUserStatusType.Invited)
|
||||
{
|
||||
orgUser.Email = savedUser.Email;
|
||||
orgUser.UserId = null;
|
||||
}
|
||||
else
|
||||
{
|
||||
orgUser.UserId = savedUser.Id;
|
||||
}
|
||||
|
||||
orgUser.OrganizationId = savedOrg.Id;
|
||||
await orgUserRepos[i].CreateAsync(orgUser);
|
||||
|
||||
if (isProvider)
|
||||
{
|
||||
var savedProvider = await providerRepos[i].CreateAsync(provider);
|
||||
|
||||
providerOrganization.OrganizationId = savedOrg.Id;
|
||||
providerOrganization.ProviderId = savedProvider.Id;
|
||||
await providerOrgRepos[i].CreateAsync(providerOrganization);
|
||||
|
||||
providerUser.UserId = savedUser.Id;
|
||||
providerUser.ProviderId = savedProvider.Id;
|
||||
await providerUserRepos[i].CreateAsync(providerUser);
|
||||
}
|
||||
|
||||
policy.OrganizationId = savedOrg.Id;
|
||||
await policyRepo.CreateAsync(policy);
|
||||
if (efPolicyRepository.Contains(policyRepo))
|
||||
{
|
||||
(policyRepo as EfRepo.BaseEntityFrameworkRepository).ClearChangeTracking();
|
||||
}
|
||||
|
||||
// Act
|
||||
var result = await orgUserRepos[i].GetByUserIdWithPolicyDetailsAsync(savedUser.Id, policy.Type);
|
||||
results.Add(result.FirstOrDefault());
|
||||
}
|
||||
|
||||
// Assert
|
||||
var distinctItems = results.Distinct(equalityComparer);
|
||||
|
||||
Assert.Single(distinctItems);
|
||||
}
|
||||
}
|
Reference in New Issue
Block a user