1
0
mirror of https://github.com/bitwarden/server synced 2025-12-06 00:03:34 +00:00
Files
server/test/Api.IntegrationTest/Helpers/OrganizationTestHelpers.cs
Rui Tomé de56b7f327 [PM-26099] Update public list members endpoint to include collections (#6503)
* Add CreateCollectionAsync method to OrganizationTestHelpers for collection creation with user and group associations

* Update public MembersController List endpoint to include associated collections in member response model

* Update MembersControllerTests to validate collection associations in List endpoint. Add JsonConstructor to AssociationWithPermissionsResponseModel

* Refactor MembersController by removing unused IUserService and IApplicationCacheService dependencies.

* Remove nullable disable directive from Public MembersController
2025-11-03 15:24:40 +00:00

218 lines
9.6 KiB
C#

using System.Diagnostics;
using Bit.Api.IntegrationTest.Factories;
using Bit.Core.AdminConsole.Entities;
using Bit.Core.AdminConsole.Enums;
using Bit.Core.AdminConsole.OrganizationFeatures.Organizations;
using Bit.Core.AdminConsole.Repositories;
using Bit.Core.Billing.Enums;
using Bit.Core.Entities;
using Bit.Core.Enums;
using Bit.Core.Models.Business;
using Bit.Core.Models.Data;
using Bit.Core.Repositories;
using Bit.IntegrationTestCommon.Factories;
namespace Bit.Api.IntegrationTest.Helpers;
public static class OrganizationTestHelpers
{
public static async Task<Tuple<Organization, OrganizationUser>> SignUpAsync<T>(WebApplicationFactoryBase<T> factory,
PlanType plan = PlanType.Free,
string ownerEmail = "integration-test@bitwarden.com",
string name = "Integration Test Org",
string billingEmail = "integration-test@bitwarden.com",
string ownerKey = "test-key",
int passwordManagerSeats = 0,
PaymentMethodType paymentMethod = PaymentMethodType.None) where T : class
{
var userRepository = factory.GetService<IUserRepository>();
var organizationSignUpCommand = factory.GetService<ICloudOrganizationSignUpCommand>();
var owner = await userRepository.GetByEmailAsync(ownerEmail);
var signUpResult = await organizationSignUpCommand.SignUpOrganizationAsync(new OrganizationSignup
{
Name = name,
BillingEmail = billingEmail,
Plan = plan,
OwnerKey = ownerKey,
Owner = owner,
AdditionalSeats = passwordManagerSeats,
PaymentMethodType = paymentMethod,
PaymentToken = "TOKEN",
TaxInfo = new TaxInfo
{
BillingAddressCountry = "US",
BillingAddressPostalCode = "12345"
}
});
Debug.Assert(signUpResult.OrganizationUser is not null);
return new Tuple<Organization, OrganizationUser>(signUpResult.Organization, signUpResult.OrganizationUser);
}
/// <summary>
/// Creates an OrganizationUser. The user account must already be created.
/// </summary>
public static async Task<OrganizationUser> CreateUserAsync<T>(
WebApplicationFactoryBase<T> factory,
Guid organizationId,
string userEmail,
OrganizationUserType type,
bool accessSecretsManager = false,
Permissions? permissions = null,
OrganizationUserStatusType userStatusType = OrganizationUserStatusType.Confirmed,
string? externalId = null
) where T : class
{
var userRepository = factory.GetService<IUserRepository>();
var organizationUserRepository = factory.GetService<IOrganizationUserRepository>();
var user = await userRepository.GetByEmailAsync(userEmail);
Debug.Assert(user is not null);
var orgUser = new OrganizationUser
{
OrganizationId = organizationId,
UserId = user.Id,
Key = null,
Type = type,
Status = userStatusType,
ExternalId = externalId,
AccessSecretsManager = accessSecretsManager,
Email = userEmail
};
if (permissions != null)
{
orgUser.SetPermissions(permissions);
}
await organizationUserRepository.CreateAsync(orgUser);
return orgUser;
}
/// <summary>
/// Creates a new User account with a unique email address and a corresponding OrganizationUser for
/// the specified organization.
/// </summary>
public static async Task<(string, OrganizationUser)> CreateNewUserWithAccountAsync(
ApiApplicationFactory factory,
Guid organizationId,
OrganizationUserType userType,
Permissions? permissions = null
)
{
var email = $"integration-test{Guid.NewGuid()}@bitwarden.com";
// Create user
await factory.LoginWithNewAccount(email);
// Create organizationUser
var organizationUser = await CreateUserAsync(factory, organizationId, email, userType,
permissions: permissions);
return (email, organizationUser);
}
/// <summary>
/// Creates a VerifiedDomain for the specified organization.
/// </summary>
public static async Task CreateVerifiedDomainAsync(ApiApplicationFactory factory, Guid organizationId, string domain)
{
var organizationDomainRepository = factory.GetService<IOrganizationDomainRepository>();
var verifiedDomain = new OrganizationDomain
{
OrganizationId = organizationId,
DomainName = domain,
Txt = "btw+test18383838383"
};
verifiedDomain.SetVerifiedDate();
await organizationDomainRepository.CreateAsync(verifiedDomain);
}
public static async Task<Group> CreateGroup(ApiApplicationFactory factory, Guid organizationId)
{
var groupRepository = factory.GetService<IGroupRepository>();
var group = new Group
{
OrganizationId = organizationId,
Id = new Guid(),
ExternalId = "bwtest-externalId",
Name = "bwtest"
};
await groupRepository.CreateAsync(group, new List<CollectionAccessSelection>());
return group;
}
/// <summary>
/// Creates a collection with optional user and group associations.
/// </summary>
public static async Task<Collection> CreateCollectionAsync(
ApiApplicationFactory factory,
Guid organizationId,
string name,
IEnumerable<CollectionAccessSelection>? users = null,
IEnumerable<CollectionAccessSelection>? groups = null)
{
var collectionRepository = factory.GetService<ICollectionRepository>();
var collection = new Collection
{
OrganizationId = organizationId,
Name = name,
Type = CollectionType.SharedCollection
};
await collectionRepository.CreateAsync(collection, groups, users);
return collection;
}
/// <summary>
/// Enables the Organization Data Ownership policy for the specified organization.
/// </summary>
public static async Task EnableOrganizationDataOwnershipPolicyAsync<T>(
WebApplicationFactoryBase<T> factory,
Guid organizationId) where T : class
{
var policyRepository = factory.GetService<IPolicyRepository>();
var policy = new Policy
{
OrganizationId = organizationId,
Type = PolicyType.OrganizationDataOwnership,
Enabled = true
};
await policyRepository.CreateAsync(policy);
}
/// <summary>
/// Creates a user account without a Master Password and adds them as a member to the specified organization.
/// </summary>
public static async Task<(User User, OrganizationUser OrganizationUser)> CreateUserWithoutMasterPasswordAsync(ApiApplicationFactory factory, string email, Guid organizationId)
{
var userRepository = factory.GetService<IUserRepository>();
var user = await userRepository.CreateAsync(new User
{
Email = email,
Culture = "en-US",
SecurityStamp = "D7ZH62BWAZ5R5CASKULCDDIQGKDA2EJ6",
PublicKey = "MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAwMj7W00xS7H0NWasGn7PfEq8VfH3fa5XuZucsKxLLRAHHZk0xGRZJH2lFIznizv3GpF8vzhHhe9VpmMkrdIa5oWhwHpy+D7Z1QCQxuUXzvMKpa95GOntr89nN/mWKpk6abjgjmDcqFJ0lhDqkKnDfes+d8BBd5oEA8p41/Ykz7OfG7AiktVBpTQFW09MQh1NOvcLxVgiUUVRPwNRKrOeCekWDtOjZhASMETv3kI1ogvhHukOQ3ztDzrxvmwnLQ+cXl1EeD8gQnGDp3QLiJqxPgh2EdmANh4IzjRexoDn6BqhRGqLLIoLAbbkoiNrd6NYujrWW0N8KMMoVEXuJL2g4wIDAQAB",
PrivateKey = "2.Ytudv+Qk3ET9hN8whqpuGg==|ijsFhmjaf1aaT9uz+IPhVTzMS+2W/ldAP8LdT5VyJaFdx4HSdLcWSZvz5xWuuW94zfv1Qh+p3iQIuZOr29G4jcx47rYtz4ssiFtB7Ia552ZeF+cb7uuVg40CIe7ycuJQITk00o8gots+wFnaEvk0Vjgycnqutm0jpeBJ1joWJWqTVgSsYdUGLu7PiJywQ9NgY4+bJXqadlcviS3rhPKJXtiXYJhqJqSw+vI0Yxp96MJ0HcFJk/LG22YJPTvL5kzuDq/Wzj40kj8blQ+ag+xHD4P/KJ/MppEB3OpDw3UoJ50Ek+YB9pOqGxZtvqMEzBDsgh0yoz1O992UnhaUqtJ5e9Bxy3PA6cJsdyn9npduNOreEb8vePCidN2XC+chjJpPFpjms9muHLKgfaTIfpiJA2Tz8E9dvSyhHHTE1mY+xEA7P08BYKN3LNoSGIjdiZuouJ1V/KZvCssDfVG1tli2qpnhTIh4m3rAMhbM8WW3B7wCV8N0MpcJJSvndkVcMgRbgWcbivLeXuKdE/K98n01RvOLSJyslhLGCGEQQKw6N3HQ2iELfv84YQZi2fjDK+OqAmXDq1pNcjKX2I8dqBwl31tPC8qSZiWnfinwLdqQTvSQjOIyAHb4sSjAwgdMbCRzUTChRr09l+PAZqGWdMC5N2Bw+bA8WP0l2Wdxuv9Abxl3F7xGeAA9Rw9PU5wGKujaMRmO4V9MFjNyyCcw4D9pzKMW6OUKsHsHE7tsG7KskCzksHzrZGawAt0S41BYQA/JwePCrD3F6dM92anlC1LfA00KJb0tmFdU0yJNmJfR+S78yn8yM6wDgIs2cFB3W1fYfpfUvQm+zzPoEQihNxBxnwFsBtMAOtPy54FjSzKmxsQTrYT9E6NFb8k6ZIIm2gNeOPK9OUJgjw+4g2BXErM6ikHTzM3xcaTq/cQaePZ52emndw1qOtdV06hr2EeuLM8frfLHpsknUe8JeYeW5p9E8QdZjjSN9034usdYNamUdxzmn/Mw/ar8z1xSKS6zcaQoTQ7aYLEX3dWJndc4W64HyiaRkLjO6qLUFeOerfz5UvcxxRY89eAA0KLC2xnGkBMOhXxYzIB3lF8Zxqb4JMhoBGw1n31TDfhRDGDHHEAsZuAIcH7aC5RDVxU08Jxmw4oLmeTDZA5BFcqp2A3fusNVZUnfpmMy6DCJyFprlRl8jSlJMAvhbxVuuLFDZnjl77Z2of796Ur6DgmNwYtMPNEntZPIcZ76VPLWAL8lqiRBm20c4qiwr5rNSr5kry9bR1EfXHwFRjy5pxFQ+5+ilpRl8WPfT/iUuORd8J2wnCmghm7uxiJd9t82kX0s6benhL29dQ1etqt5soX2RnlfKan16GVWoI3xrljIQrCAY4xpdptSpglOnrpSClbN1nhGkDfFPNq2pWhQrDbznDknAJ9MxQaVnLYPhn7I849GMd7EvpSkydwQu7QXn9+H4jxn6UEntNGxcL0xkG+xippvZEe+HBvcDD40efDQW1bDbILLjPb4rNRx4d3xaQnVNaF7L33osm5LgfXAQSwHJiURdkU4zmhtPP4zn0br0OdFlR3mPcrkeNeSvs7FxiKtD6n6s+av+4bKjbLL1OyuwmTnMilL6p+m8ldte0yos/r+zOuxWeI=|euhiXWXehYbFQhlAV6LIECSIPCIRaHbNdr9OI4cTPUM=",
ApiKey = "CfGrD4MoJu3NprOBZNL8tu5ocmtnmU",
KdfIterations = 600000
});
var organizationUser = await CreateUserAsync(factory, organizationId, user.Email,
OrganizationUserType.User, externalId: email);
return (user, organizationUser);
}
}