VYPR
High severity8.0NVD Advisory· Published May 11, 2026· Updated May 16, 2026

CVE-2026-43639

CVE-2026-43639

Description

Bitwarden Server prior to v2026.4.0 contains a missing authorization vulnerability that allows a provider service user to add an arbitrary organization to their provider via POST /providers/{providerId}/clients/existing, resulting in takeover of the target organization; self-hosted installations are unaffected as this endpoint is restricted to Cloud via SelfHosted(NotSelfHostedOnly = true).

Affected products

1

Patches

1
0918bfdda6f5

Add checks and tests to provider controllers (#7372)

https://github.com/bitwarden/serverThomas RittsonApr 1, 2026via nvd-ref
7 files changed · +559 7
  • src/Api/AdminConsole/Controllers/ProviderClientsController.cs+15 3 modified
    @@ -171,18 +171,30 @@ public async Task<IResult> AddExistingOrganizationAsync(
             [FromRoute] Guid providerId,
             [FromBody] AddExistingOrganizationRequestBody requestBody)
         {
    -        var (provider, result) = await TryGetBillableProviderForServiceUserOperation(providerId);
    +        var userId = _currentContext.UserId;
    +        if (!userId.HasValue)
    +        {
    +            return Error.Unauthorized();
    +        }
    +
    +        var (provider, result) = await TryGetBillableProviderForAdminOperation(providerId);
     
             if (provider == null)
             {
                 return result;
             }
     
    -        var organization = await organizationRepository.GetByIdAsync(requestBody.OrganizationId);
    +        if (!await _currentContext.OrganizationOwner(requestBody.OrganizationId))
    +        {
    +            return Error.Unauthorized();
    +        }
    +
    +        var addableOrganizations = await organizationRepository.GetAddableToProviderByUserIdAsync(userId.Value, provider.Type);
    +        var organization = addableOrganizations.FirstOrDefault(o => o.Id == requestBody.OrganizationId);
     
             if (organization == null)
             {
    -            return Error.BadRequest("The organization being added to the provider does not exist.");
    +            return Error.NotFound();
             }
     
             await providerBillingService.AddExistingOrganization(provider, organization, requestBody.Key);
    
  • src/Api/AdminConsole/Controllers/ProviderOrganizationsController.cs+2 1 modified
    @@ -63,7 +63,8 @@ public async Task<ListResponseModel<ProviderOrganizationOrganizationDetailsRespo
         [HttpPost("add")]
         public async Task Add(Guid providerId, [FromBody] ProviderOrganizationAddRequestModel model)
         {
    -        if (!_currentContext.ManageProviderOrganizations(providerId))
    +        if (!_currentContext.ManageProviderOrganizations(providerId) ||
    +            !await _currentContext.OrganizationOwner(model.OrganizationId))
             {
                 throw new NotFoundException();
             }
    
  • src/Infrastructure.EntityFramework/AdminConsole/Repositories/OrganizationRepository.cs+2 3 modified
    @@ -11,7 +11,6 @@
     using Bit.Core.Models.Data.Organizations;
     using Bit.Core.Models.Data.Organizations.OrganizationUsers;
     using Bit.Core.Repositories;
    -using LinqToDB.Tools;
     using Microsoft.EntityFrameworkCore;
     using Microsoft.Extensions.DependencyInjection;
     using Microsoft.Extensions.Logging;
    @@ -177,7 +176,7 @@ public async Task<ICollection<OrganizationAbility>> GetManyAbilitiesAsync()
     
             var query =
                 from o in dbContext.Organizations
    -            where o.PlanType.NotIn(disallowedPlanTypes) &&
    +            where !disallowedPlanTypes.Contains(o.PlanType) &&
                       !dbContext.ProviderOrganizations.Any(po => po.OrganizationId == o.Id) &&
                       (string.IsNullOrWhiteSpace(name) || EF.Functions.Like(o.Name, $"%{name}%"))
                 select o;
    @@ -400,7 +399,7 @@ join organization in dbContext.Organizations on organizationUser.OrganizationId
                         organization.Seats > 0 &&
                         organization.Status == OrganizationStatusType.Created &&
                         !organization.UseSecretsManager &&
    -                    organization.PlanType.In(planTypes)
    +                    planTypes.Contains(organization.PlanType)
                     select organization;
     
                 return await query.ToArrayAsync();
    
  • test/Api.IntegrationTest/AdminConsole/Controllers/ProviderClientsControllerTests.cs+230 0 added
    @@ -0,0 +1,230 @@
    +using System.Net;
    +using Bit.Api.Billing.Models.Requests;
    +using Bit.Api.IntegrationTest.Factories;
    +using Bit.Api.IntegrationTest.Helpers;
    +using Bit.Core.AdminConsole.Entities;
    +using Bit.Core.AdminConsole.Entities.Provider;
    +using Bit.Core.AdminConsole.Enums.Provider;
    +using Bit.Core.AdminConsole.Repositories;
    +using Bit.Core.Billing.Enums;
    +using Bit.Core.Billing.Providers.Services;
    +using Bit.Core.Entities;
    +using Bit.Core.Enums;
    +using Bit.Core.Repositories;
    +using NSubstitute;
    +using Xunit;
    +
    +namespace Bit.Api.IntegrationTest.AdminConsole.Controllers;
    +
    +public class ProviderClientsControllerTests : IClassFixture<ApiApplicationFactory>, IAsyncLifetime
    +{
    +    private readonly HttpClient _client;
    +    private readonly ApiApplicationFactory _factory;
    +    private readonly LoginHelper _loginHelper;
    +
    +    private string _providerAdminEmail = null!;
    +    private string _serviceUserEmail = null!;
    +    private string _otherUserEmail = null!;
    +    private Provider _provider = null!;
    +    private Organization _addableOrg = null!;
    +    private Organization _managedOrg = null!;
    +    private Organization _otherOrg = null!;
    +
    +    public ProviderClientsControllerTests(ApiApplicationFactory factory)
    +    {
    +        _factory = factory;
    +        _factory.SubstituteService<IProviderBillingService>(_ => { });
    +        _client = _factory.CreateClient();
    +        _loginHelper = new LoginHelper(_factory, _client);
    +    }
    +
    +    public async Task InitializeAsync()
    +    {
    +        _providerAdminEmail = $"{Guid.NewGuid()}@test.com";
    +        await _factory.LoginWithNewAccount(_providerAdminEmail);
    +
    +        _serviceUserEmail = $"{Guid.NewGuid()}@test.com";
    +        await _factory.LoginWithNewAccount(_serviceUserEmail);
    +
    +        _otherUserEmail = $"{Guid.NewGuid()}@test.com";
    +        await _factory.LoginWithNewAccount(_otherUserEmail);
    +
    +        var userRepository = _factory.GetService<IUserRepository>();
    +        var orgRepository = _factory.GetService<IOrganizationRepository>();
    +        var orgUserRepository = _factory.GetService<IOrganizationUserRepository>();
    +        var providerRepository = _factory.GetService<IProviderRepository>();
    +        var providerUserRepository = _factory.GetService<IProviderUserRepository>();
    +
    +        var providerAdmin = await userRepository.GetByEmailAsync(_providerAdminEmail);
    +        var serviceUser = await userRepository.GetByEmailAsync(_serviceUserEmail);
    +        var otherUser = await userRepository.GetByEmailAsync(_otherUserEmail);
    +
    +        _provider = await providerRepository.CreateAsync(new Provider
    +        {
    +            Name = "Test MSP Provider",
    +            BillingEmail = "billing@test.com",
    +            Type = ProviderType.Msp,
    +            Status = ProviderStatusType.Billable,
    +            Enabled = true,
    +            GatewayCustomerId = $"cus_{Guid.NewGuid():N}",
    +            GatewaySubscriptionId = $"sub_{Guid.NewGuid():N}"
    +        });
    +
    +        await providerUserRepository.CreateAsync(new ProviderUser
    +        {
    +            ProviderId = _provider.Id,
    +            UserId = providerAdmin!.Id,
    +            Type = ProviderUserType.ProviderAdmin,
    +            Status = ProviderUserStatusType.Confirmed,
    +            Key = Guid.NewGuid().ToString()
    +        });
    +
    +        await providerUserRepository.CreateAsync(new ProviderUser
    +        {
    +            ProviderId = _provider.Id,
    +            UserId = serviceUser!.Id,
    +            Type = ProviderUserType.ServiceUser,
    +            Status = ProviderUserStatusType.Confirmed,
    +            Key = Guid.NewGuid().ToString()
    +        });
    +
    +        _addableOrg = await orgRepository.CreateAsync(new Organization
    +        {
    +            Name = "Addable Org",
    +            BillingEmail = _providerAdminEmail,
    +            Plan = "Teams (Monthly)",
    +            PlanType = PlanType.TeamsMonthly,
    +            Status = OrganizationStatusType.Created,
    +            Enabled = true,
    +            Seats = 10,
    +            GatewayCustomerId = $"cus_{Guid.NewGuid():N}",
    +            GatewaySubscriptionId = $"sub_{Guid.NewGuid():N}",
    +            UseSecretsManager = false
    +        });
    +
    +        await orgUserRepository.CreateAsync(new OrganizationUser
    +        {
    +            OrganizationId = _addableOrg.Id,
    +            UserId = providerAdmin.Id,
    +            Type = OrganizationUserType.Owner,
    +            Status = OrganizationUserStatusType.Confirmed,
    +            AccessSecretsManager = false
    +        });
    +
    +        _managedOrg = await orgRepository.CreateAsync(new Organization
    +        {
    +            Name = "Managed Org",
    +            BillingEmail = _providerAdminEmail,
    +            Plan = "Teams (Monthly)",
    +            PlanType = PlanType.TeamsMonthly,
    +            Status = OrganizationStatusType.Managed,
    +            Enabled = true,
    +            Seats = 10,
    +            GatewayCustomerId = $"cus_{Guid.NewGuid():N}",
    +            GatewaySubscriptionId = $"sub_{Guid.NewGuid():N}",
    +            UseSecretsManager = false
    +        });
    +
    +        await orgUserRepository.CreateAsync(new OrganizationUser
    +        {
    +            OrganizationId = _managedOrg.Id,
    +            UserId = providerAdmin.Id,
    +            Type = OrganizationUserType.Owner,
    +            Status = OrganizationUserStatusType.Confirmed,
    +            AccessSecretsManager = false
    +        });
    +
    +        _otherOrg = await orgRepository.CreateAsync(new Organization
    +        {
    +            Name = "Other User Org",
    +            BillingEmail = _otherUserEmail,
    +            Plan = "Teams (Monthly)",
    +            PlanType = PlanType.TeamsMonthly,
    +            Status = OrganizationStatusType.Created,
    +            Enabled = true,
    +            Seats = 10,
    +            GatewayCustomerId = $"cus_{Guid.NewGuid():N}",
    +            GatewaySubscriptionId = $"sub_{Guid.NewGuid():N}",
    +            UseSecretsManager = false
    +        });
    +
    +        await orgUserRepository.CreateAsync(new OrganizationUser
    +        {
    +            OrganizationId = _otherOrg.Id,
    +            UserId = otherUser!.Id,
    +            Type = OrganizationUserType.Owner,
    +            Status = OrganizationUserStatusType.Confirmed,
    +            AccessSecretsManager = false
    +        });
    +    }
    +
    +    public Task DisposeAsync()
    +    {
    +        _client.Dispose();
    +        return Task.CompletedTask;
    +    }
    +
    +    [Fact]
    +    public async Task AddExistingOrganizationAsync_Unauthenticated_ReturnsUnauthorized()
    +    {
    +        var request = new AddExistingOrganizationRequestBody { OrganizationId = _addableOrg.Id, Key = "key" };
    +
    +        var response = await _client.PostAsJsonAsync($"providers/{_provider.Id}/clients/existing", request);
    +
    +        Assert.Equal(HttpStatusCode.Unauthorized, response.StatusCode);
    +    }
    +
    +    [Fact]
    +    public async Task AddExistingOrganizationAsync_ServiceUser_ReturnsUnauthorized()
    +    {
    +        await _loginHelper.LoginAsync(_serviceUserEmail);
    +
    +        var request = new AddExistingOrganizationRequestBody { OrganizationId = _addableOrg.Id, Key = "key" };
    +
    +        var response = await _client.PostAsJsonAsync($"providers/{_provider.Id}/clients/existing", request);
    +
    +        Assert.Equal(HttpStatusCode.Unauthorized, response.StatusCode);
    +    }
    +
    +    [Fact]
    +    public async Task AddExistingOrganizationAsync_NotOrgOwner_ReturnsUnauthorized()
    +    {
    +        await _loginHelper.LoginAsync(_providerAdminEmail);
    +
    +        var request = new AddExistingOrganizationRequestBody { OrganizationId = _otherOrg.Id, Key = "key" };
    +
    +        var response = await _client.PostAsJsonAsync($"providers/{_provider.Id}/clients/existing", request);
    +
    +        Assert.Equal(HttpStatusCode.Unauthorized, response.StatusCode);
    +    }
    +
    +    [Fact]
    +    public async Task AddExistingOrganizationAsync_OrgNotAddable_ReturnsNotFound()
    +    {
    +        await _loginHelper.LoginAsync(_providerAdminEmail);
    +
    +        var request = new AddExistingOrganizationRequestBody { OrganizationId = _managedOrg.Id, Key = "key" };
    +
    +        var response = await _client.PostAsJsonAsync($"providers/{_provider.Id}/clients/existing", request);
    +
    +        Assert.Equal(HttpStatusCode.NotFound, response.StatusCode);
    +    }
    +
    +    [Fact]
    +    public async Task AddExistingOrganizationAsync_ValidRequest_ReturnsOk()
    +    {
    +        await _loginHelper.LoginAsync(_providerAdminEmail);
    +
    +        var request = new AddExistingOrganizationRequestBody { OrganizationId = _addableOrg.Id, Key = "key" };
    +
    +        var response = await _client.PostAsJsonAsync($"providers/{_provider.Id}/clients/existing", request);
    +
    +        Assert.Equal(HttpStatusCode.OK, response.StatusCode);
    +
    +        var billingService = _factory.GetService<IProviderBillingService>();
    +        await billingService.Received(1).AddExistingOrganization(
    +            Arg.Is<Provider>(p => p.Id == _provider.Id),
    +            Arg.Is<Organization>(o => o.Id == _addableOrg.Id),
    +            "key");
    +    }
    +}
    
  • test/Api.IntegrationTest/AdminConsole/Controllers/ProviderOrganizationsControllerTests.cs+158 0 added
    @@ -0,0 +1,158 @@
    +using System.Net;
    +using Bit.Api.AdminConsole.Models.Request.Providers;
    +using Bit.Api.IntegrationTest.Factories;
    +using Bit.Api.IntegrationTest.Helpers;
    +using Bit.Core.AdminConsole.Entities;
    +using Bit.Core.AdminConsole.Entities.Provider;
    +using Bit.Core.AdminConsole.Enums.Provider;
    +using Bit.Core.AdminConsole.Repositories;
    +using Bit.Core.Billing.Enums;
    +using Bit.Core.Entities;
    +using Bit.Core.Enums;
    +using Bit.Core.Repositories;
    +using Xunit;
    +
    +namespace Bit.Api.IntegrationTest.AdminConsole.Controllers;
    +
    +public class ProviderOrganizationsControllerTests : IClassFixture<ApiApplicationFactory>, IAsyncLifetime
    +{
    +    private readonly HttpClient _client;
    +    private readonly ApiApplicationFactory _factory;
    +    private readonly LoginHelper _loginHelper;
    +
    +    private string _providerAdminEmail = null!;
    +    private string _otherUserEmail = null!;
    +    private Provider _provider = null!;
    +    private Organization _org = null!;
    +    private Organization _otherOrg = null!;
    +
    +    public ProviderOrganizationsControllerTests(ApiApplicationFactory factory)
    +    {
    +        _factory = factory;
    +        _client = _factory.CreateClient();
    +        _loginHelper = new LoginHelper(_factory, _client);
    +    }
    +
    +    public async Task InitializeAsync()
    +    {
    +        _providerAdminEmail = $"{Guid.NewGuid()}@test.com";
    +        await _factory.LoginWithNewAccount(_providerAdminEmail);
    +
    +        _otherUserEmail = $"{Guid.NewGuid()}@test.com";
    +        await _factory.LoginWithNewAccount(_otherUserEmail);
    +
    +        var userRepository = _factory.GetService<IUserRepository>();
    +        var orgRepository = _factory.GetService<IOrganizationRepository>();
    +        var orgUserRepository = _factory.GetService<IOrganizationUserRepository>();
    +        var providerRepository = _factory.GetService<IProviderRepository>();
    +        var providerUserRepository = _factory.GetService<IProviderUserRepository>();
    +
    +        var providerAdmin = await userRepository.GetByEmailAsync(_providerAdminEmail);
    +        var otherUser = await userRepository.GetByEmailAsync(_otherUserEmail);
    +
    +        _provider = await providerRepository.CreateAsync(new Provider
    +        {
    +            Name = "Test Provider",
    +            BillingEmail = "billing@test.com",
    +            Type = ProviderType.Msp,
    +            Status = ProviderStatusType.Created,
    +            Enabled = true
    +        });
    +
    +        await providerUserRepository.CreateAsync(new ProviderUser
    +        {
    +            ProviderId = _provider.Id,
    +            UserId = providerAdmin!.Id,
    +            Type = ProviderUserType.ProviderAdmin,
    +            Status = ProviderUserStatusType.Confirmed,
    +            Key = Guid.NewGuid().ToString()
    +        });
    +
    +        _org = await orgRepository.CreateAsync(new Organization
    +        {
    +            Name = "Provider Admin Org",
    +            BillingEmail = _providerAdminEmail,
    +            Plan = "Teams (Monthly)",
    +            PlanType = PlanType.TeamsMonthly,
    +            Status = OrganizationStatusType.Created,
    +            Enabled = true,
    +            Seats = 10,
    +        });
    +
    +        await orgUserRepository.CreateAsync(new OrganizationUser
    +        {
    +            OrganizationId = _org.Id,
    +            UserId = providerAdmin.Id,
    +            Type = OrganizationUserType.Owner,
    +            Status = OrganizationUserStatusType.Confirmed,
    +            AccessSecretsManager = false
    +        });
    +
    +        _otherOrg = await orgRepository.CreateAsync(new Organization
    +        {
    +            Name = "Other User Org",
    +            BillingEmail = _otherUserEmail,
    +            Plan = "Teams (Monthly)",
    +            PlanType = PlanType.TeamsMonthly,
    +            Status = OrganizationStatusType.Created,
    +            Enabled = true,
    +            Seats = 10,
    +            UseSecretsManager = false
    +        });
    +
    +        await orgUserRepository.CreateAsync(new OrganizationUser
    +        {
    +            OrganizationId = _otherOrg.Id,
    +            UserId = otherUser!.Id,
    +            Type = OrganizationUserType.Owner,
    +            Status = OrganizationUserStatusType.Confirmed,
    +            AccessSecretsManager = false
    +        });
    +    }
    +
    +    public Task DisposeAsync()
    +    {
    +        _client.Dispose();
    +        return Task.CompletedTask;
    +    }
    +
    +    [Fact]
    +    public async Task Add_Unauthenticated_ReturnsUnauthorized()
    +    {
    +        var model = new ProviderOrganizationAddRequestModel { OrganizationId = _org.Id, Key = "key" };
    +
    +        var response = await _client.PostAsJsonAsync($"providers/{_provider.Id}/organizations/add", model);
    +
    +        Assert.Equal(HttpStatusCode.Unauthorized, response.StatusCode);
    +    }
    +
    +    [Fact]
    +    public async Task Add_NotOrgOwner_ReturnsNotFound()
    +    {
    +        await _loginHelper.LoginAsync(_providerAdminEmail);
    +
    +        var model = new ProviderOrganizationAddRequestModel { OrganizationId = _otherOrg.Id, Key = "key" };
    +
    +        var response = await _client.PostAsJsonAsync($"providers/{_provider.Id}/organizations/add", model);
    +
    +        Assert.Equal(HttpStatusCode.NotFound, response.StatusCode);
    +    }
    +
    +    [Fact]
    +    public async Task Add_ValidRequest_ReturnsOk()
    +    {
    +        await _loginHelper.LoginAsync(_providerAdminEmail);
    +
    +        var providerOrganizationRepository = _factory.GetService<IProviderOrganizationRepository>();
    +
    +        var model = new ProviderOrganizationAddRequestModel { OrganizationId = _org.Id, Key = "key" };
    +
    +        var response = await _client.PostAsJsonAsync($"providers/{_provider.Id}/organizations/add", model);
    +
    +        Assert.Equal(HttpStatusCode.OK, response.StatusCode);
    +
    +        var providerOrganization = await providerOrganizationRepository.GetByOrganizationId(_org.Id);
    +        Assert.NotNull(providerOrganization);
    +        Assert.Equal(_provider.Id, providerOrganization.ProviderId);
    +    }
    +}
    
  • test/Api.Test/AdminConsole/Controllers/ProviderClientsControllerTests.cs+85 0 modified
    @@ -92,6 +92,91 @@ await sutProvider.GetDependency<IProviderBillingService>().Received(1).CreateCus
     
         #endregion
     
    +    #region AddExistingOrganizationAsync
    +
    +    [Theory, BitAutoData]
    +    public async Task AddExistingOrganizationAsync_ServiceUser_Unauthorized(
    +        Provider provider,
    +        AddExistingOrganizationRequestBody requestBody,
    +        SutProvider<ProviderClientsController> sutProvider)
    +    {
    +        ConfigureStableProviderServiceUserInputs(provider, sutProvider);
    +
    +        var result = await sutProvider.Sut.AddExistingOrganizationAsync(provider.Id, requestBody);
    +
    +        AssertUnauthorized(result);
    +    }
    +
    +    [Theory, BitAutoData]
    +    public async Task AddExistingOrganizationAsync_NotOrgOwner_Unauthorized(
    +        Provider provider,
    +        AddExistingOrganizationRequestBody requestBody,
    +        SutProvider<ProviderClientsController> sutProvider)
    +    {
    +        ConfigureStableProviderAdminInputs(provider, sutProvider);
    +
    +        sutProvider.GetDependency<ICurrentContext>().OrganizationOwner(requestBody.OrganizationId)
    +            .Returns(false);
    +
    +        var result = await sutProvider.Sut.AddExistingOrganizationAsync(provider.Id, requestBody);
    +
    +        AssertUnauthorized(result);
    +    }
    +
    +    [Theory, BitAutoData]
    +    public async Task AddExistingOrganizationAsync_OrgNotAddable_NotFound(
    +        Provider provider,
    +        AddExistingOrganizationRequestBody requestBody,
    +        Guid userId,
    +        SutProvider<ProviderClientsController> sutProvider)
    +    {
    +        ConfigureStableProviderAdminInputs(provider, sutProvider);
    +
    +        sutProvider.GetDependency<ICurrentContext>().OrganizationOwner(requestBody.OrganizationId)
    +            .Returns(true);
    +
    +        sutProvider.GetDependency<ICurrentContext>().UserId.Returns(userId);
    +
    +        sutProvider.GetDependency<IOrganizationRepository>()
    +            .GetAddableToProviderByUserIdAsync(userId, provider.Type)
    +            .Returns([]);
    +
    +        var result = await sutProvider.Sut.AddExistingOrganizationAsync(provider.Id, requestBody);
    +
    +        AssertNotFound(result);
    +    }
    +
    +    [Theory, BitAutoData]
    +    public async Task AddExistingOrganizationAsync_Ok(
    +        Provider provider,
    +        AddExistingOrganizationRequestBody requestBody,
    +        Organization organization,
    +        Guid userId,
    +        SutProvider<ProviderClientsController> sutProvider)
    +    {
    +        organization.Id = requestBody.OrganizationId;
    +
    +        ConfigureStableProviderAdminInputs(provider, sutProvider);
    +
    +        sutProvider.GetDependency<ICurrentContext>().OrganizationOwner(requestBody.OrganizationId)
    +            .Returns(true);
    +
    +        sutProvider.GetDependency<ICurrentContext>().UserId.Returns(userId);
    +
    +        sutProvider.GetDependency<IOrganizationRepository>()
    +            .GetAddableToProviderByUserIdAsync(userId, provider.Type)
    +            .Returns([organization]);
    +
    +        var result = await sutProvider.Sut.AddExistingOrganizationAsync(provider.Id, requestBody);
    +
    +        await sutProvider.GetDependency<IProviderBillingService>().Received(1)
    +            .AddExistingOrganization(provider, organization, requestBody.Key);
    +
    +        Assert.IsType<Ok>(result);
    +    }
    +
    +    #endregion
    +
         #region UpdateAsync
     
         [Theory, BitAutoData]
    
  • test/Api.Test/AdminConsole/Controllers/ProviderOrganizationsControllerTests.cs+67 0 added
    @@ -0,0 +1,67 @@
    +using Bit.Api.AdminConsole.Controllers;
    +using Bit.Api.AdminConsole.Models.Request.Providers;
    +using Bit.Core.AdminConsole.Services;
    +using Bit.Core.Context;
    +using Bit.Core.Exceptions;
    +using Bit.Test.Common.AutoFixture;
    +using Bit.Test.Common.AutoFixture.Attributes;
    +using NSubstitute;
    +using Xunit;
    +
    +namespace Bit.Api.Test.AdminConsole.Controllers;
    +
    +[ControllerCustomize(typeof(ProviderOrganizationsController))]
    +[SutProviderCustomize]
    +public class ProviderOrganizationsControllerTests
    +{
    +    [Theory, BitAutoData]
    +    public async Task Add_NotProviderAdmin_ThrowsNotFound(
    +        Guid providerId,
    +        ProviderOrganizationAddRequestModel model,
    +        SutProvider<ProviderOrganizationsController> sutProvider)
    +    {
    +        sutProvider.GetDependency<ICurrentContext>().ManageProviderOrganizations(providerId)
    +            .Returns(false);
    +
    +        await Assert.ThrowsAsync<NotFoundException>(() => sutProvider.Sut.Add(providerId, model));
    +
    +        await sutProvider.GetDependency<IProviderService>().DidNotReceiveWithAnyArgs()
    +            .AddOrganization(default, default, default);
    +    }
    +
    +    [Theory, BitAutoData]
    +    public async Task Add_NotOrgOwner_ThrowsNotFound(
    +        Guid providerId,
    +        ProviderOrganizationAddRequestModel model,
    +        SutProvider<ProviderOrganizationsController> sutProvider)
    +    {
    +        sutProvider.GetDependency<ICurrentContext>().ManageProviderOrganizations(providerId)
    +            .Returns(true);
    +
    +        sutProvider.GetDependency<ICurrentContext>().OrganizationOwner(model.OrganizationId)
    +            .Returns(false);
    +
    +        await Assert.ThrowsAsync<NotFoundException>(() => sutProvider.Sut.Add(providerId, model));
    +
    +        await sutProvider.GetDependency<IProviderService>().DidNotReceiveWithAnyArgs()
    +            .AddOrganization(default, default, default);
    +    }
    +
    +    [Theory, BitAutoData]
    +    public async Task Add_Ok(
    +        Guid providerId,
    +        ProviderOrganizationAddRequestModel model,
    +        SutProvider<ProviderOrganizationsController> sutProvider)
    +    {
    +        sutProvider.GetDependency<ICurrentContext>().ManageProviderOrganizations(providerId)
    +            .Returns(true);
    +
    +        sutProvider.GetDependency<ICurrentContext>().OrganizationOwner(model.OrganizationId)
    +            .Returns(true);
    +
    +        await sutProvider.Sut.Add(providerId, model);
    +
    +        await sutProvider.GetDependency<IProviderService>().Received(1)
    +            .AddOrganization(providerId, model.OrganizationId, model.Key);
    +    }
    +}
    

Vulnerability mechanics

AI mechanics synthesis has not run for this CVE yet.

References

5

News mentions

0

No linked articles in our index yet.