mirror of
https://github.com/bitwarden/server.git
synced 2025-06-30 15:42:48 -05:00
[AC-1593] Auto-Grant SM access to org owner when they add SM (#3349)
* Auto grant SM access to org owner * Thomas' feedback
This commit is contained in:
@ -1,6 +1,8 @@
|
||||
using System.Security.Claims;
|
||||
using AutoFixture.Xunit2;
|
||||
using Bit.Api.AdminConsole.Controllers;
|
||||
using Bit.Api.AdminConsole.Models.Request.Organizations;
|
||||
using Bit.Api.Models.Request.Organizations;
|
||||
using Bit.Core.AdminConsole.OrganizationFeatures.OrganizationApiKeys.Interfaces;
|
||||
using Bit.Core.AdminConsole.Repositories;
|
||||
using Bit.Core.Auth.Entities;
|
||||
@ -10,13 +12,17 @@ using Bit.Core.Auth.Repositories;
|
||||
using Bit.Core.Auth.Services;
|
||||
using Bit.Core.Context;
|
||||
using Bit.Core.Entities;
|
||||
using Bit.Core.Enums;
|
||||
using Bit.Core.Exceptions;
|
||||
using Bit.Core.Models.Business;
|
||||
using Bit.Core.Models.Data.Organizations.OrganizationUsers;
|
||||
using Bit.Core.OrganizationFeatures.OrganizationLicenses.Interfaces;
|
||||
using Bit.Core.OrganizationFeatures.OrganizationSubscriptions.Interface;
|
||||
using Bit.Core.Repositories;
|
||||
using Bit.Core.Services;
|
||||
using Bit.Core.Settings;
|
||||
using NSubstitute;
|
||||
using NSubstitute.ReturnsExtensions;
|
||||
using Xunit;
|
||||
|
||||
namespace Bit.Api.Test.AdminConsole.Controllers;
|
||||
@ -145,4 +151,194 @@ public class OrganizationsControllerTests : IDisposable
|
||||
await _organizationService.DeleteUserAsync(orgId, user.Id);
|
||||
await _organizationService.Received(1).DeleteUserAsync(orgId, user.Id);
|
||||
}
|
||||
|
||||
[Theory, AutoData]
|
||||
public async Task OrganizationsController_PostUpgrade_UserCannotEditSubscription_ThrowsNotFoundException(
|
||||
Guid organizationId,
|
||||
OrganizationUpgradeRequestModel model)
|
||||
{
|
||||
_currentContext.EditSubscription(organizationId).Returns(false);
|
||||
|
||||
await Assert.ThrowsAsync<NotFoundException>(() => _sut.PostUpgrade(organizationId.ToString(), model));
|
||||
}
|
||||
|
||||
[Theory, AutoData]
|
||||
public async Task OrganizationsController_PostUpgrade_NonSMUpgrade_ReturnsCorrectResponse(
|
||||
Guid organizationId,
|
||||
OrganizationUpgradeRequestModel model,
|
||||
bool success,
|
||||
string paymentIntentClientSecret)
|
||||
{
|
||||
model.UseSecretsManager = false;
|
||||
|
||||
_currentContext.EditSubscription(organizationId).Returns(true);
|
||||
|
||||
_upgradeOrganizationPlanCommand.UpgradePlanAsync(organizationId, Arg.Any<OrganizationUpgrade>())
|
||||
.Returns(new Tuple<bool, string>(success, paymentIntentClientSecret));
|
||||
|
||||
var response = await _sut.PostUpgrade(organizationId.ToString(), model);
|
||||
|
||||
Assert.Equal(success, response.Success);
|
||||
Assert.Equal(paymentIntentClientSecret, response.PaymentIntentClientSecret);
|
||||
}
|
||||
|
||||
[Theory, AutoData]
|
||||
public async Task OrganizationsController_PostUpgrade_SMUpgrade_ProvidesAccess_ReturnsCorrectResponse(
|
||||
Guid organizationId,
|
||||
Guid userId,
|
||||
OrganizationUpgradeRequestModel model,
|
||||
bool success,
|
||||
string paymentIntentClientSecret,
|
||||
OrganizationUser organizationUser)
|
||||
{
|
||||
model.UseSecretsManager = true;
|
||||
organizationUser.AccessSecretsManager = false;
|
||||
|
||||
_currentContext.EditSubscription(organizationId).Returns(true);
|
||||
|
||||
_upgradeOrganizationPlanCommand.UpgradePlanAsync(organizationId, Arg.Any<OrganizationUpgrade>())
|
||||
.Returns(new Tuple<bool, string>(success, paymentIntentClientSecret));
|
||||
|
||||
_userService.GetProperUserId(Arg.Any<ClaimsPrincipal>()).Returns(userId);
|
||||
|
||||
_organizationUserRepository.GetByOrganizationAsync(organizationId, userId).Returns(organizationUser);
|
||||
|
||||
var response = await _sut.PostUpgrade(organizationId.ToString(), model);
|
||||
|
||||
Assert.Equal(success, response.Success);
|
||||
Assert.Equal(paymentIntentClientSecret, response.PaymentIntentClientSecret);
|
||||
|
||||
await _organizationUserRepository.Received(1).ReplaceAsync(Arg.Is<OrganizationUser>(orgUser =>
|
||||
orgUser.Id == organizationUser.Id && orgUser.AccessSecretsManager == true));
|
||||
}
|
||||
|
||||
[Theory, AutoData]
|
||||
public async Task OrganizationsController_PostUpgrade_SMUpgrade_NullOrgUser_ReturnsCorrectResponse(
|
||||
Guid organizationId,
|
||||
Guid userId,
|
||||
OrganizationUpgradeRequestModel model,
|
||||
bool success,
|
||||
string paymentIntentClientSecret)
|
||||
{
|
||||
model.UseSecretsManager = true;
|
||||
|
||||
_currentContext.EditSubscription(organizationId).Returns(true);
|
||||
|
||||
_upgradeOrganizationPlanCommand.UpgradePlanAsync(organizationId, Arg.Any<OrganizationUpgrade>())
|
||||
.Returns(new Tuple<bool, string>(success, paymentIntentClientSecret));
|
||||
|
||||
_userService.GetProperUserId(Arg.Any<ClaimsPrincipal>()).Returns(userId);
|
||||
|
||||
_organizationUserRepository.GetByOrganizationAsync(organizationId, userId).ReturnsNull();
|
||||
|
||||
var response = await _sut.PostUpgrade(organizationId.ToString(), model);
|
||||
|
||||
Assert.Equal(success, response.Success);
|
||||
Assert.Equal(paymentIntentClientSecret, response.PaymentIntentClientSecret);
|
||||
|
||||
await _organizationUserRepository.DidNotReceiveWithAnyArgs().ReplaceAsync(Arg.Any<OrganizationUser>());
|
||||
}
|
||||
|
||||
[Theory, AutoData]
|
||||
public async Task OrganizationsController_PostSubscribeSecretsManagerAsync_NullOrg_ThrowsNotFoundException(
|
||||
Guid organizationId,
|
||||
SecretsManagerSubscribeRequestModel model)
|
||||
{
|
||||
_organizationRepository.GetByIdAsync(organizationId).ReturnsNull();
|
||||
|
||||
await Assert.ThrowsAsync<NotFoundException>(() => _sut.PostSubscribeSecretsManagerAsync(organizationId, model));
|
||||
}
|
||||
|
||||
[Theory, AutoData]
|
||||
public async Task OrganizationsController_PostSubscribeSecretsManagerAsync_UserCannotEditSubscription_ThrowsNotFoundException(
|
||||
Guid organizationId,
|
||||
SecretsManagerSubscribeRequestModel model,
|
||||
Organization organization)
|
||||
{
|
||||
_organizationRepository.GetByIdAsync(organizationId).Returns(organization);
|
||||
|
||||
_currentContext.EditSubscription(organizationId).Returns(false);
|
||||
|
||||
await Assert.ThrowsAsync<NotFoundException>(() => _sut.PostSubscribeSecretsManagerAsync(organizationId, model));
|
||||
}
|
||||
|
||||
[Theory, AutoData]
|
||||
public async Task OrganizationsController_PostSubscribeSecretsManagerAsync_ProvidesAccess_ReturnsCorrectResponse(
|
||||
Guid organizationId,
|
||||
SecretsManagerSubscribeRequestModel model,
|
||||
Organization organization,
|
||||
Guid userId,
|
||||
OrganizationUser organizationUser,
|
||||
OrganizationUserOrganizationDetails organizationUserOrganizationDetails)
|
||||
{
|
||||
organizationUser.AccessSecretsManager = false;
|
||||
|
||||
var ssoConfigurationData = new SsoConfigurationData
|
||||
{
|
||||
MemberDecryptionType = MemberDecryptionType.KeyConnector,
|
||||
KeyConnectorUrl = "https://example.com"
|
||||
};
|
||||
|
||||
organizationUserOrganizationDetails.Permissions = string.Empty;
|
||||
organizationUserOrganizationDetails.SsoConfig = ssoConfigurationData.Serialize();
|
||||
|
||||
_organizationRepository.GetByIdAsync(organizationId).Returns(organization);
|
||||
|
||||
_currentContext.EditSubscription(organizationId).Returns(true);
|
||||
|
||||
_userService.GetProperUserId(Arg.Any<ClaimsPrincipal>()).Returns(userId);
|
||||
|
||||
_organizationUserRepository.GetByOrganizationAsync(organization.Id, userId).Returns(organizationUser);
|
||||
|
||||
_organizationUserRepository.GetDetailsByUserAsync(userId, organization.Id, OrganizationUserStatusType.Confirmed)
|
||||
.Returns(organizationUserOrganizationDetails);
|
||||
|
||||
var response = await _sut.PostSubscribeSecretsManagerAsync(organizationId, model);
|
||||
|
||||
Assert.Equal(response.Id, organizationUserOrganizationDetails.OrganizationId);
|
||||
Assert.Equal(response.Name, organizationUserOrganizationDetails.Name);
|
||||
|
||||
await _addSecretsManagerSubscriptionCommand.Received(1)
|
||||
.SignUpAsync(organization, model.AdditionalSmSeats, model.AdditionalServiceAccounts);
|
||||
await _organizationUserRepository.Received(1).ReplaceAsync(Arg.Is<OrganizationUser>(orgUser =>
|
||||
orgUser.Id == organizationUser.Id && orgUser.AccessSecretsManager == true));
|
||||
}
|
||||
|
||||
[Theory, AutoData]
|
||||
public async Task OrganizationsController_PostSubscribeSecretsManagerAsync_NullOrgUser_ReturnsCorrectResponse(
|
||||
Guid organizationId,
|
||||
SecretsManagerSubscribeRequestModel model,
|
||||
Organization organization,
|
||||
Guid userId,
|
||||
OrganizationUserOrganizationDetails organizationUserOrganizationDetails)
|
||||
{
|
||||
var ssoConfigurationData = new SsoConfigurationData
|
||||
{
|
||||
MemberDecryptionType = MemberDecryptionType.KeyConnector,
|
||||
KeyConnectorUrl = "https://example.com"
|
||||
};
|
||||
|
||||
organizationUserOrganizationDetails.Permissions = string.Empty;
|
||||
organizationUserOrganizationDetails.SsoConfig = ssoConfigurationData.Serialize();
|
||||
|
||||
_organizationRepository.GetByIdAsync(organizationId).Returns(organization);
|
||||
|
||||
_currentContext.EditSubscription(organizationId).Returns(true);
|
||||
|
||||
_userService.GetProperUserId(Arg.Any<ClaimsPrincipal>()).Returns(userId);
|
||||
|
||||
_organizationUserRepository.GetByOrganizationAsync(organization.Id, userId).ReturnsNull();
|
||||
|
||||
_organizationUserRepository.GetDetailsByUserAsync(userId, organization.Id, OrganizationUserStatusType.Confirmed)
|
||||
.Returns(organizationUserOrganizationDetails);
|
||||
|
||||
var response = await _sut.PostSubscribeSecretsManagerAsync(organizationId, model);
|
||||
|
||||
Assert.Equal(response.Id, organizationUserOrganizationDetails.OrganizationId);
|
||||
Assert.Equal(response.Name, organizationUserOrganizationDetails.Name);
|
||||
|
||||
await _addSecretsManagerSubscriptionCommand.Received(1)
|
||||
.SignUpAsync(organization, model.AdditionalSmSeats, model.AdditionalServiceAccounts);
|
||||
await _organizationUserRepository.DidNotReceiveWithAnyArgs().ReplaceAsync(Arg.Any<OrganizationUser>());
|
||||
}
|
||||
}
|
||||
|
Reference in New Issue
Block a user