mirror of
https://github.com/bitwarden/server.git
synced 2025-12-12 07:34:55 -06:00
And other refactors: - move update organization method to a command - separate authorization from business logic - add tests - move Billing Team logic into their service
197 lines
7.6 KiB
C#
197 lines
7.6 KiB
C#
using System.Net;
|
|
using Bit.Api.AdminConsole.Models.Request.Organizations;
|
|
using Bit.Api.IntegrationTest.Factories;
|
|
using Bit.Api.IntegrationTest.Helpers;
|
|
using Bit.Core.AdminConsole.Entities;
|
|
using Bit.Core.AdminConsole.Enums.Provider;
|
|
using Bit.Core.Billing.Enums;
|
|
using Bit.Core.Enums;
|
|
using Bit.Core.Repositories;
|
|
using Xunit;
|
|
|
|
namespace Bit.Api.IntegrationTest.AdminConsole.Controllers;
|
|
|
|
public class OrganizationsControllerTests : IClassFixture<ApiApplicationFactory>, IAsyncLifetime
|
|
{
|
|
private readonly HttpClient _client;
|
|
private readonly ApiApplicationFactory _factory;
|
|
private readonly LoginHelper _loginHelper;
|
|
|
|
private Organization _organization = null!;
|
|
private string _ownerEmail = null!;
|
|
private readonly string _billingEmail = "billing@example.com";
|
|
private readonly string _organizationName = "Organizations Controller Test Org";
|
|
|
|
public OrganizationsControllerTests(ApiApplicationFactory apiFactory)
|
|
{
|
|
_factory = apiFactory;
|
|
_client = _factory.CreateClient();
|
|
_loginHelper = new LoginHelper(_factory, _client);
|
|
}
|
|
|
|
public async Task InitializeAsync()
|
|
{
|
|
_ownerEmail = $"org-integration-test-{Guid.NewGuid()}@example.com";
|
|
await _factory.LoginWithNewAccount(_ownerEmail);
|
|
|
|
(_organization, _) = await OrganizationTestHelpers.SignUpAsync(_factory,
|
|
name: _organizationName,
|
|
billingEmail: _billingEmail,
|
|
plan: PlanType.EnterpriseAnnually,
|
|
ownerEmail: _ownerEmail,
|
|
passwordManagerSeats: 5,
|
|
paymentMethod: PaymentMethodType.Card);
|
|
}
|
|
|
|
public Task DisposeAsync()
|
|
{
|
|
_client.Dispose();
|
|
return Task.CompletedTask;
|
|
}
|
|
|
|
[Fact]
|
|
public async Task Put_AsOwner_WithoutProvider_CanUpdateOrganization()
|
|
{
|
|
// Arrange - Regular organization owner (no provider)
|
|
await _loginHelper.LoginAsync(_ownerEmail);
|
|
|
|
var updateRequest = new OrganizationUpdateRequestModel
|
|
{
|
|
Name = "Updated Organization Name",
|
|
BillingEmail = "newbillingemail@example.com"
|
|
};
|
|
|
|
// Act
|
|
var response = await _client.PutAsJsonAsync($"/organizations/{_organization.Id}", updateRequest);
|
|
|
|
// Assert
|
|
Assert.Equal(HttpStatusCode.OK, response.StatusCode);
|
|
|
|
// Verify the organization name was updated
|
|
var organizationRepository = _factory.GetService<IOrganizationRepository>();
|
|
var updatedOrg = await organizationRepository.GetByIdAsync(_organization.Id);
|
|
Assert.NotNull(updatedOrg);
|
|
Assert.Equal("Updated Organization Name", updatedOrg.Name);
|
|
Assert.Equal("newbillingemail@example.com", updatedOrg.BillingEmail);
|
|
}
|
|
|
|
[Fact]
|
|
public async Task Put_AsProvider_CanUpdateOrganization()
|
|
{
|
|
// Create and login as a new account to be the provider user (not the owner)
|
|
var providerUserEmail = $"provider-{Guid.NewGuid()}@example.com";
|
|
var (token, _) = await _factory.LoginWithNewAccount(providerUserEmail);
|
|
|
|
// Set up provider linked to org and ProviderUser entry
|
|
var provider = await ProviderTestHelpers.CreateProviderAndLinkToOrganizationAsync(_factory, _organization.Id,
|
|
ProviderType.Msp);
|
|
await ProviderTestHelpers.CreateProviderUserAsync(_factory, provider.Id, providerUserEmail,
|
|
ProviderUserType.ProviderAdmin);
|
|
|
|
await _loginHelper.LoginAsync(providerUserEmail);
|
|
|
|
var updateRequest = new OrganizationUpdateRequestModel
|
|
{
|
|
Name = "Updated Organization Name",
|
|
BillingEmail = "newbillingemail@example.com"
|
|
};
|
|
|
|
// Act
|
|
var response = await _client.PutAsJsonAsync($"/organizations/{_organization.Id}", updateRequest);
|
|
|
|
// Assert
|
|
Assert.Equal(HttpStatusCode.OK, response.StatusCode);
|
|
|
|
// Verify the organization name was updated
|
|
var organizationRepository = _factory.GetService<IOrganizationRepository>();
|
|
var updatedOrg = await organizationRepository.GetByIdAsync(_organization.Id);
|
|
Assert.NotNull(updatedOrg);
|
|
Assert.Equal("Updated Organization Name", updatedOrg.Name);
|
|
Assert.Equal("newbillingemail@example.com", updatedOrg.BillingEmail);
|
|
}
|
|
|
|
[Fact]
|
|
public async Task Put_NotMemberOrProvider_CannotUpdateOrganization()
|
|
{
|
|
// Create and login as a new account to be unrelated to the org
|
|
var userEmail = "stranger@example.com";
|
|
await _factory.LoginWithNewAccount(userEmail);
|
|
await _loginHelper.LoginAsync(userEmail);
|
|
|
|
var updateRequest = new OrganizationUpdateRequestModel
|
|
{
|
|
Name = "Updated Organization Name",
|
|
BillingEmail = "newbillingemail@example.com"
|
|
};
|
|
|
|
// Act
|
|
var response = await _client.PutAsJsonAsync($"/organizations/{_organization.Id}", updateRequest);
|
|
|
|
// Assert
|
|
Assert.Equal(HttpStatusCode.Unauthorized, response.StatusCode);
|
|
|
|
// Verify the organization name was not updated
|
|
var organizationRepository = _factory.GetService<IOrganizationRepository>();
|
|
var updatedOrg = await organizationRepository.GetByIdAsync(_organization.Id);
|
|
Assert.NotNull(updatedOrg);
|
|
Assert.Equal(_organizationName, updatedOrg.Name);
|
|
Assert.Equal(_billingEmail, updatedOrg.BillingEmail);
|
|
}
|
|
|
|
[Fact]
|
|
public async Task Put_AsOwner_WithProvider_CanRenameOrganization()
|
|
{
|
|
// Arrange - Create provider and link to organization
|
|
// The active user is ONLY an org owner, NOT a provider user
|
|
await ProviderTestHelpers.CreateProviderAndLinkToOrganizationAsync(_factory, _organization.Id, ProviderType.Msp);
|
|
await _loginHelper.LoginAsync(_ownerEmail);
|
|
|
|
var updateRequest = new OrganizationUpdateRequestModel
|
|
{
|
|
Name = "Updated Organization Name",
|
|
BillingEmail = null
|
|
};
|
|
|
|
// Act
|
|
var response = await _client.PutAsJsonAsync($"/organizations/{_organization.Id}", updateRequest);
|
|
|
|
// Assert
|
|
Assert.Equal(HttpStatusCode.OK, response.StatusCode);
|
|
|
|
// Verify the organization name was actually updated
|
|
var organizationRepository = _factory.GetService<IOrganizationRepository>();
|
|
var updatedOrg = await organizationRepository.GetByIdAsync(_organization.Id);
|
|
Assert.NotNull(updatedOrg);
|
|
Assert.Equal("Updated Organization Name", updatedOrg.Name);
|
|
Assert.Equal(_billingEmail, updatedOrg.BillingEmail);
|
|
}
|
|
|
|
[Fact]
|
|
public async Task Put_AsOwner_WithProvider_CannotChangeBillingEmail()
|
|
{
|
|
// Arrange - Create provider and link to organization
|
|
// The active user is ONLY an org owner, NOT a provider user
|
|
await ProviderTestHelpers.CreateProviderAndLinkToOrganizationAsync(_factory, _organization.Id, ProviderType.Msp);
|
|
await _loginHelper.LoginAsync(_ownerEmail);
|
|
|
|
var updateRequest = new OrganizationUpdateRequestModel
|
|
{
|
|
Name = "Updated Organization Name",
|
|
BillingEmail = "updatedbilling@example.com"
|
|
};
|
|
|
|
// Act
|
|
var response = await _client.PutAsJsonAsync($"/organizations/{_organization.Id}", updateRequest);
|
|
|
|
// Assert
|
|
Assert.Equal(HttpStatusCode.Unauthorized, response.StatusCode);
|
|
|
|
// Verify the organization was not updated
|
|
var organizationRepository = _factory.GetService<IOrganizationRepository>();
|
|
var updatedOrg = await organizationRepository.GetByIdAsync(_organization.Id);
|
|
Assert.NotNull(updatedOrg);
|
|
Assert.Equal(_organizationName, updatedOrg.Name);
|
|
Assert.Equal(_billingEmail, updatedOrg.BillingEmail);
|
|
}
|
|
}
|