mirror of
https://github.com/bitwarden/server.git
synced 2025-01-30 23:11:22 +01:00
[PM-14826] Add UsePolicies check to GET endpoints (#5046)
GetByToken and GetMasterPasswordPolicy endpoints provide policy information, so if the organization is not using policies, then we avoid the rest of the logic.
This commit is contained in:
parent
c852575a9e
commit
a76a9cb800
@ -27,19 +27,20 @@ namespace Bit.Api.AdminConsole.Controllers;
|
||||
[Authorize("Application")]
|
||||
public class PoliciesController : Controller
|
||||
{
|
||||
private readonly IPolicyRepository _policyRepository;
|
||||
private readonly IOrganizationUserRepository _organizationUserRepository;
|
||||
private readonly IUserService _userService;
|
||||
private readonly ICurrentContext _currentContext;
|
||||
private readonly GlobalSettings _globalSettings;
|
||||
private readonly IDataProtector _organizationServiceDataProtector;
|
||||
private readonly IDataProtectorTokenFactory<OrgUserInviteTokenable> _orgUserInviteTokenDataFactory;
|
||||
private readonly IFeatureService _featureService;
|
||||
private readonly GlobalSettings _globalSettings;
|
||||
private readonly IOrganizationHasVerifiedDomainsQuery _organizationHasVerifiedDomainsQuery;
|
||||
private readonly IOrganizationRepository _organizationRepository;
|
||||
private readonly IDataProtector _organizationServiceDataProtector;
|
||||
private readonly IOrganizationUserRepository _organizationUserRepository;
|
||||
private readonly IDataProtectorTokenFactory<OrgUserInviteTokenable> _orgUserInviteTokenDataFactory;
|
||||
private readonly IPolicyRepository _policyRepository;
|
||||
private readonly IUserService _userService;
|
||||
|
||||
private readonly ISavePolicyCommand _savePolicyCommand;
|
||||
|
||||
public PoliciesController(
|
||||
IPolicyRepository policyRepository,
|
||||
public PoliciesController(IPolicyRepository policyRepository,
|
||||
IOrganizationUserRepository organizationUserRepository,
|
||||
IUserService userService,
|
||||
ICurrentContext currentContext,
|
||||
@ -48,6 +49,7 @@ public class PoliciesController : Controller
|
||||
IDataProtectorTokenFactory<OrgUserInviteTokenable> orgUserInviteTokenDataFactory,
|
||||
IFeatureService featureService,
|
||||
IOrganizationHasVerifiedDomainsQuery organizationHasVerifiedDomainsQuery,
|
||||
IOrganizationRepository organizationRepository,
|
||||
ISavePolicyCommand savePolicyCommand)
|
||||
{
|
||||
_policyRepository = policyRepository;
|
||||
@ -57,7 +59,7 @@ public class PoliciesController : Controller
|
||||
_globalSettings = globalSettings;
|
||||
_organizationServiceDataProtector = dataProtectionProvider.CreateProtector(
|
||||
"OrganizationServiceDataProtector");
|
||||
|
||||
_organizationRepository = organizationRepository;
|
||||
_orgUserInviteTokenDataFactory = orgUserInviteTokenDataFactory;
|
||||
_featureService = featureService;
|
||||
_organizationHasVerifiedDomainsQuery = organizationHasVerifiedDomainsQuery;
|
||||
@ -104,6 +106,13 @@ public class PoliciesController : Controller
|
||||
public async Task<ListResponseModel<PolicyResponseModel>> GetByToken(Guid orgId, [FromQuery] string email,
|
||||
[FromQuery] string token, [FromQuery] Guid organizationUserId)
|
||||
{
|
||||
var organization = await _organizationRepository.GetByIdAsync(orgId);
|
||||
|
||||
if (organization is not { UsePolicies: true })
|
||||
{
|
||||
throw new NotFoundException();
|
||||
}
|
||||
|
||||
// TODO: PM-4142 - remove old token validation logic once 3 releases of backwards compatibility are complete
|
||||
var newTokenValid = OrgUserInviteTokenable.ValidateOrgUserInviteStringToken(
|
||||
_orgUserInviteTokenDataFactory, token, organizationUserId, email);
|
||||
@ -158,6 +167,13 @@ public class PoliciesController : Controller
|
||||
[HttpGet("master-password")]
|
||||
public async Task<PolicyResponseModel> GetMasterPasswordPolicy(Guid orgId)
|
||||
{
|
||||
var organization = await _organizationRepository.GetByIdAsync(orgId);
|
||||
|
||||
if (organization is not { UsePolicies: true })
|
||||
{
|
||||
throw new NotFoundException();
|
||||
}
|
||||
|
||||
var userId = _userService.GetProperUserId(User).Value;
|
||||
|
||||
var orgUser = await _organizationUserRepository.GetByOrganizationAsync(orgId, userId);
|
||||
|
@ -6,11 +6,13 @@ using Bit.Core.AdminConsole.Entities;
|
||||
using Bit.Core.AdminConsole.Enums;
|
||||
using Bit.Core.AdminConsole.Models.Data.Organizations.Policies;
|
||||
using Bit.Core.AdminConsole.Repositories;
|
||||
using Bit.Core.Auth.Models.Business.Tokenables;
|
||||
using Bit.Core.Context;
|
||||
using Bit.Core.Entities;
|
||||
using Bit.Core.Exceptions;
|
||||
using Bit.Core.Repositories;
|
||||
using Bit.Core.Services;
|
||||
using Bit.Core.Tokens;
|
||||
using Bit.Test.Common.AutoFixture;
|
||||
using Bit.Test.Common.AutoFixture.Attributes;
|
||||
using NSubstitute;
|
||||
@ -28,10 +30,19 @@ public class PoliciesControllerTests
|
||||
[Theory]
|
||||
[BitAutoData]
|
||||
public async Task GetMasterPasswordPolicy_WhenCalled_ReturnsMasterPasswordPolicy(
|
||||
SutProvider<PoliciesController> sutProvider, Guid orgId, Guid userId, OrganizationUser orgUser,
|
||||
Policy policy, MasterPasswordPolicyData mpPolicyData)
|
||||
SutProvider<PoliciesController> sutProvider,
|
||||
Guid orgId, Guid userId,
|
||||
OrganizationUser orgUser,
|
||||
Policy policy,
|
||||
MasterPasswordPolicyData mpPolicyData,
|
||||
Organization organization)
|
||||
{
|
||||
// Arrange
|
||||
organization.UsePolicies = true;
|
||||
|
||||
var organizationRepository = sutProvider.GetDependency<IOrganizationRepository>();
|
||||
organizationRepository.GetByIdAsync(orgId).Returns(organization);
|
||||
|
||||
sutProvider.GetDependency<IUserService>()
|
||||
.GetProperUserId(Arg.Any<ClaimsPrincipal>())
|
||||
.Returns((Guid?)userId);
|
||||
@ -135,6 +146,39 @@ public class PoliciesControllerTests
|
||||
await Assert.ThrowsAsync<NotFoundException>(() => sutProvider.Sut.GetMasterPasswordPolicy(orgId));
|
||||
}
|
||||
|
||||
[Theory]
|
||||
[BitAutoData]
|
||||
public async Task GetMasterPasswordPolicy_WhenUsePoliciesIsFalse_ThrowsNotFoundException(
|
||||
SutProvider<PoliciesController> sutProvider,
|
||||
Guid orgId)
|
||||
{
|
||||
// Arrange
|
||||
var organizationRepository = sutProvider.GetDependency<IOrganizationRepository>();
|
||||
organizationRepository.GetByIdAsync(orgId).Returns((Organization)null);
|
||||
|
||||
|
||||
// Act & Assert
|
||||
await Assert.ThrowsAsync<NotFoundException>(() => sutProvider.Sut.GetMasterPasswordPolicy(orgId));
|
||||
}
|
||||
|
||||
[Theory]
|
||||
[BitAutoData]
|
||||
public async Task GetMasterPasswordPolicy_WhenOrgIsNull_ThrowsNotFoundException(
|
||||
SutProvider<PoliciesController> sutProvider,
|
||||
Guid orgId,
|
||||
Organization organization)
|
||||
{
|
||||
// Arrange
|
||||
organization.UsePolicies = false;
|
||||
|
||||
var organizationRepository = sutProvider.GetDependency<IOrganizationRepository>();
|
||||
organizationRepository.GetByIdAsync(orgId).Returns(organization);
|
||||
|
||||
|
||||
// Act & Assert
|
||||
await Assert.ThrowsAsync<NotFoundException>(() => sutProvider.Sut.GetMasterPasswordPolicy(orgId));
|
||||
}
|
||||
|
||||
[Theory]
|
||||
[BitAutoData]
|
||||
public async Task Get_WhenUserCanManagePolicies_WithExistingType_ReturnsExistingPolicy(
|
||||
@ -142,16 +186,16 @@ public class PoliciesControllerTests
|
||||
{
|
||||
// Arrange
|
||||
sutProvider.GetDependency<ICurrentContext>()
|
||||
.ManagePolicies(orgId)
|
||||
.Returns(true);
|
||||
.ManagePolicies(orgId)
|
||||
.Returns(true);
|
||||
|
||||
policy.Type = (PolicyType)type;
|
||||
policy.Enabled = true;
|
||||
policy.Data = null;
|
||||
|
||||
sutProvider.GetDependency<IPolicyRepository>()
|
||||
.GetByOrganizationIdTypeAsync(orgId, (PolicyType)type)
|
||||
.Returns(policy);
|
||||
.GetByOrganizationIdTypeAsync(orgId, (PolicyType)type)
|
||||
.Returns(policy);
|
||||
|
||||
// Act
|
||||
var result = await sutProvider.Sut.Get(orgId, type);
|
||||
@ -171,12 +215,12 @@ public class PoliciesControllerTests
|
||||
{
|
||||
// Arrange
|
||||
sutProvider.GetDependency<ICurrentContext>()
|
||||
.ManagePolicies(orgId)
|
||||
.Returns(true);
|
||||
.ManagePolicies(orgId)
|
||||
.Returns(true);
|
||||
|
||||
sutProvider.GetDependency<IPolicyRepository>()
|
||||
.GetByOrganizationIdTypeAsync(orgId, (PolicyType)type)
|
||||
.Returns((Policy)null);
|
||||
.GetByOrganizationIdTypeAsync(orgId, (PolicyType)type)
|
||||
.Returns((Policy)null);
|
||||
|
||||
// Act
|
||||
var result = await sutProvider.Sut.Get(orgId, type);
|
||||
@ -194,11 +238,221 @@ public class PoliciesControllerTests
|
||||
{
|
||||
// Arrange
|
||||
sutProvider.GetDependency<ICurrentContext>()
|
||||
.ManagePolicies(orgId)
|
||||
.Returns(false);
|
||||
.ManagePolicies(orgId)
|
||||
.Returns(false);
|
||||
|
||||
// Act & Assert
|
||||
await Assert.ThrowsAsync<NotFoundException>(() => sutProvider.Sut.Get(orgId, type));
|
||||
}
|
||||
|
||||
[Theory]
|
||||
[BitAutoData]
|
||||
public async Task GetByToken_WhenOrganizationUseUsePoliciesIsFalse_ThrowsNotFoundException(
|
||||
SutProvider<PoliciesController> sutProvider, Guid orgId, Guid organizationUserId, string token, string email,
|
||||
Organization organization)
|
||||
{
|
||||
// Arrange
|
||||
organization.UsePolicies = false;
|
||||
|
||||
var organizationRepository = sutProvider.GetDependency<IOrganizationRepository>();
|
||||
organizationRepository.GetByIdAsync(orgId).Returns(organization);
|
||||
|
||||
|
||||
// Act & Assert
|
||||
await Assert.ThrowsAsync<NotFoundException>(() =>
|
||||
sutProvider.Sut.GetByToken(orgId, email, token, organizationUserId));
|
||||
}
|
||||
|
||||
[Theory]
|
||||
[BitAutoData]
|
||||
public async Task GetByToken_WhenOrganizationIsNull_ThrowsNotFoundException(
|
||||
SutProvider<PoliciesController> sutProvider, Guid orgId, Guid organizationUserId, string token, string email)
|
||||
{
|
||||
// Arrange
|
||||
var organizationRepository = sutProvider.GetDependency<IOrganizationRepository>();
|
||||
organizationRepository.GetByIdAsync(orgId).Returns((Organization)null);
|
||||
|
||||
// Act & Assert
|
||||
await Assert.ThrowsAsync<NotFoundException>(() =>
|
||||
sutProvider.Sut.GetByToken(orgId, email, token, organizationUserId));
|
||||
}
|
||||
|
||||
[Theory]
|
||||
[BitAutoData]
|
||||
public async Task GetByToken_WhenTokenIsInvalid_ThrowsNotFoundException(
|
||||
SutProvider<PoliciesController> sutProvider,
|
||||
Guid orgId,
|
||||
Guid organizationUserId,
|
||||
string token,
|
||||
string email,
|
||||
Organization organization
|
||||
)
|
||||
{
|
||||
// Arrange
|
||||
organization.UsePolicies = true;
|
||||
|
||||
var organizationRepository = sutProvider.GetDependency<IOrganizationRepository>();
|
||||
organizationRepository.GetByIdAsync(orgId).Returns(organization);
|
||||
|
||||
var decryptedToken = Substitute.For<OrgUserInviteTokenable>();
|
||||
decryptedToken.Valid.Returns(false);
|
||||
|
||||
var orgUserInviteTokenDataFactory = sutProvider.GetDependency<IDataProtectorTokenFactory<OrgUserInviteTokenable>>();
|
||||
|
||||
orgUserInviteTokenDataFactory.TryUnprotect(token, out Arg.Any<OrgUserInviteTokenable>())
|
||||
.Returns(x =>
|
||||
{
|
||||
x[1] = decryptedToken;
|
||||
return true;
|
||||
});
|
||||
|
||||
// Act & Assert
|
||||
await Assert.ThrowsAsync<NotFoundException>(() =>
|
||||
sutProvider.Sut.GetByToken(orgId, email, token, organizationUserId));
|
||||
}
|
||||
|
||||
[Theory]
|
||||
[BitAutoData]
|
||||
public async Task GetByToken_WhenUserIsNull_ThrowsNotFoundException(
|
||||
SutProvider<PoliciesController> sutProvider,
|
||||
Guid orgId,
|
||||
Guid organizationUserId,
|
||||
string token,
|
||||
string email,
|
||||
Organization organization
|
||||
)
|
||||
{
|
||||
// Arrange
|
||||
organization.UsePolicies = true;
|
||||
|
||||
var organizationRepository = sutProvider.GetDependency<IOrganizationRepository>();
|
||||
organizationRepository.GetByIdAsync(orgId).Returns(organization);
|
||||
|
||||
var decryptedToken = Substitute.For<OrgUserInviteTokenable>();
|
||||
decryptedToken.Valid.Returns(true);
|
||||
decryptedToken.OrgUserId = organizationUserId;
|
||||
decryptedToken.OrgUserEmail = email;
|
||||
|
||||
var orgUserInviteTokenDataFactory = sutProvider.GetDependency<IDataProtectorTokenFactory<OrgUserInviteTokenable>>();
|
||||
|
||||
orgUserInviteTokenDataFactory.TryUnprotect(token, out Arg.Any<OrgUserInviteTokenable>())
|
||||
.Returns(x =>
|
||||
{
|
||||
x[1] = decryptedToken;
|
||||
return true;
|
||||
});
|
||||
|
||||
sutProvider.GetDependency<IOrganizationUserRepository>()
|
||||
.GetByIdAsync(organizationUserId)
|
||||
.Returns((OrganizationUser)null);
|
||||
|
||||
// Act & Assert
|
||||
await Assert.ThrowsAsync<NotFoundException>(() =>
|
||||
sutProvider.Sut.GetByToken(orgId, email, token, organizationUserId));
|
||||
}
|
||||
|
||||
[Theory]
|
||||
[BitAutoData]
|
||||
public async Task GetByToken_WhenUserOrgIdDoesNotMatchOrgId_ThrowsNotFoundException(
|
||||
SutProvider<PoliciesController> sutProvider,
|
||||
Guid orgId,
|
||||
Guid organizationUserId,
|
||||
string token,
|
||||
string email,
|
||||
OrganizationUser orgUser,
|
||||
Organization organization
|
||||
)
|
||||
{
|
||||
// Arrange
|
||||
organization.UsePolicies = true;
|
||||
|
||||
var organizationRepository = sutProvider.GetDependency<IOrganizationRepository>();
|
||||
organizationRepository.GetByIdAsync(orgId).Returns(organization);
|
||||
|
||||
var decryptedToken = Substitute.For<OrgUserInviteTokenable>();
|
||||
decryptedToken.Valid.Returns(true);
|
||||
decryptedToken.OrgUserId = organizationUserId;
|
||||
decryptedToken.OrgUserEmail = email;
|
||||
|
||||
var orgUserInviteTokenDataFactory = sutProvider.GetDependency<IDataProtectorTokenFactory<OrgUserInviteTokenable>>();
|
||||
|
||||
orgUserInviteTokenDataFactory.TryUnprotect(token, out Arg.Any<OrgUserInviteTokenable>())
|
||||
.Returns(x =>
|
||||
{
|
||||
x[1] = decryptedToken;
|
||||
return true;
|
||||
});
|
||||
|
||||
orgUser.OrganizationId = Guid.Empty;
|
||||
|
||||
sutProvider.GetDependency<IOrganizationUserRepository>()
|
||||
.GetByIdAsync(organizationUserId)
|
||||
.Returns(orgUser);
|
||||
|
||||
// Act & Assert
|
||||
await Assert.ThrowsAsync<NotFoundException>(() =>
|
||||
sutProvider.Sut.GetByToken(orgId, email, token, organizationUserId));
|
||||
}
|
||||
|
||||
[Theory]
|
||||
[BitAutoData]
|
||||
public async Task GetByToken_ShouldReturnEnabledPolicies(
|
||||
SutProvider<PoliciesController> sutProvider,
|
||||
Guid orgId,
|
||||
Guid organizationUserId,
|
||||
string token,
|
||||
string email,
|
||||
OrganizationUser orgUser,
|
||||
Organization organization
|
||||
)
|
||||
{
|
||||
// Arrange
|
||||
organization.UsePolicies = true;
|
||||
|
||||
var organizationRepository = sutProvider.GetDependency<IOrganizationRepository>();
|
||||
organizationRepository.GetByIdAsync(orgId).Returns(organization);
|
||||
|
||||
var decryptedToken = Substitute.For<OrgUserInviteTokenable>();
|
||||
decryptedToken.Valid.Returns(true);
|
||||
decryptedToken.OrgUserId = organizationUserId;
|
||||
decryptedToken.OrgUserEmail = email;
|
||||
|
||||
var orgUserInviteTokenDataFactory = sutProvider.GetDependency<IDataProtectorTokenFactory<OrgUserInviteTokenable>>();
|
||||
|
||||
orgUserInviteTokenDataFactory.TryUnprotect(token, out Arg.Any<OrgUserInviteTokenable>())
|
||||
.Returns(x =>
|
||||
{
|
||||
x[1] = decryptedToken;
|
||||
return true;
|
||||
});
|
||||
|
||||
orgUser.OrganizationId = orgId;
|
||||
sutProvider.GetDependency<IOrganizationUserRepository>()
|
||||
.GetByIdAsync(organizationUserId)
|
||||
.Returns(orgUser);
|
||||
|
||||
var enabledPolicy = Substitute.For<Policy>();
|
||||
enabledPolicy.Enabled = true;
|
||||
var disabledPolicy = Substitute.For<Policy>();
|
||||
disabledPolicy.Enabled = false;
|
||||
|
||||
var policies = new[] { enabledPolicy, disabledPolicy };
|
||||
|
||||
|
||||
sutProvider.GetDependency<IPolicyRepository>()
|
||||
.GetManyByOrganizationIdAsync(orgId)
|
||||
.Returns(policies);
|
||||
|
||||
// Act
|
||||
var result = await sutProvider.Sut.GetByToken(orgId, email, token, organizationUserId);
|
||||
|
||||
// Assert
|
||||
var expectedPolicy = result.Data.Single();
|
||||
|
||||
Assert.NotNull(result);
|
||||
|
||||
Assert.Equal(enabledPolicy.Id, expectedPolicy.Id);
|
||||
Assert.Equal(enabledPolicy.Type, expectedPolicy.Type);
|
||||
Assert.Equal(enabledPolicy.Enabled, expectedPolicy.Enabled);
|
||||
}
|
||||
}
|
||||
|
Loading…
Reference in New Issue
Block a user