1
0
mirror of https://github.com/bitwarden/server.git synced 2025-06-30 23:52:50 -05:00

[SM-702] Extract access policy checks from create/update project commands (#2842)

* Move to access query for project commands

* Swap to hasAccess method per action

* Swap to authorization handler pattern

* Move ProjectOperationRequirement to Core

* Add default throw + tests

* Swap to reflection for testing switch
This commit is contained in:
Thomas Avery
2023-05-03 09:40:24 -05:00
committed by GitHub
parent 7be19b53f4
commit 5474d3da18
28 changed files with 490 additions and 166 deletions

View File

@ -1,4 +1,5 @@
using Bit.Api.SecretsManager.Controllers;
using System.Security.Claims;
using Bit.Api.SecretsManager.Controllers;
using Bit.Api.SecretsManager.Models.Request;
using Bit.Api.Test.SecretsManager.Enums;
using Bit.Core.Context;
@ -13,6 +14,7 @@ using Bit.Core.Test.SecretsManager.AutoFixture.ProjectsFixture;
using Bit.Test.Common.AutoFixture;
using Bit.Test.Common.AutoFixture.Attributes;
using Bit.Test.Common.Helpers;
using Microsoft.AspNetCore.Authorization;
using NSubstitute;
using Xunit;
@ -102,10 +104,18 @@ public class ProjectsControllerTests
[Theory]
[BitAutoData]
public async void Create_SmNotEnabled_Throws(SutProvider<ProjectsController> sutProvider, Guid orgId,
ProjectCreateRequestModel data)
public async void Create_NoAccess_Throws(SutProvider<ProjectsController> sutProvider,
Guid orgId, ProjectCreateRequestModel data)
{
sutProvider.GetDependency<ICurrentContext>().AccessSecretsManager(orgId).Returns(false);
sutProvider.GetDependency<IAuthorizationService>()
.AuthorizeAsync(Arg.Any<ClaimsPrincipal>(), data.ToProject(orgId),
Arg.Any<IEnumerable<IAuthorizationRequirement>>()).ReturnsForAnyArgs(AuthorizationResult.Failed());
sutProvider.GetDependency<IUserService>().GetProperUserId(default).ReturnsForAnyArgs(Guid.NewGuid());
var resultProject = data.ToProject(orgId);
sutProvider.GetDependency<ICreateProjectCommand>().CreateAsync(default, default)
.ReturnsForAnyArgs(resultProject);
await Assert.ThrowsAsync<NotFoundException>(() => sutProvider.Sut.CreateAsync(orgId, data));
await sutProvider.GetDependency<ICreateProjectCommand>().DidNotReceiveWithAnyArgs()
@ -113,22 +123,17 @@ public class ProjectsControllerTests
}
[Theory]
[BitAutoData(PermissionType.RunAsAdmin)]
[BitAutoData(PermissionType.RunAsUserWithPermission)]
public async void Create_Success(PermissionType permissionType, SutProvider<ProjectsController> sutProvider,
[BitAutoData]
public async void Create_Success(SutProvider<ProjectsController> sutProvider,
Guid orgId, ProjectCreateRequestModel data)
{
switch (permissionType)
{
case PermissionType.RunAsAdmin:
SetupAdmin(sutProvider, orgId);
break;
case PermissionType.RunAsUserWithPermission:
SetupUserWithPermission(sutProvider, orgId);
break;
}
sutProvider.GetDependency<IAuthorizationService>()
.AuthorizeAsync(Arg.Any<ClaimsPrincipal>(), data.ToProject(orgId),
Arg.Any<IEnumerable<IAuthorizationRequirement>>()).ReturnsForAnyArgs(AuthorizationResult.Success());
sutProvider.GetDependency<IUserService>().GetProperUserId(default).ReturnsForAnyArgs(Guid.NewGuid());
var resultProject = data.ToProject(orgId);
sutProvider.GetDependency<ICreateProjectCommand>().CreateAsync(default, default)
.ReturnsForAnyArgs(resultProject);
@ -139,29 +144,44 @@ public class ProjectsControllerTests
}
[Theory]
[BitAutoData(PermissionType.RunAsAdmin)]
[BitAutoData(PermissionType.RunAsUserWithPermission)]
public async void Update_Success(PermissionType permissionType, SutProvider<ProjectsController> sutProvider,
Guid orgId, ProjectUpdateRequestModel data)
[BitAutoData]
public async void Update_NoAccess_Throws(SutProvider<ProjectsController> sutProvider,
Guid userId, ProjectUpdateRequestModel data, Project existingProject)
{
switch (permissionType)
{
case PermissionType.RunAsAdmin:
SetupAdmin(sutProvider, orgId);
break;
case PermissionType.RunAsUserWithPermission:
SetupUserWithPermission(sutProvider, orgId);
break;
}
sutProvider.GetDependency<IAuthorizationService>()
.AuthorizeAsync(Arg.Any<ClaimsPrincipal>(), data.ToProject(existingProject.Id),
Arg.Any<IEnumerable<IAuthorizationRequirement>>()).ReturnsForAnyArgs(AuthorizationResult.Failed());
sutProvider.GetDependency<IProjectRepository>().GetByIdAsync(existingProject.Id).ReturnsForAnyArgs(existingProject);
sutProvider.GetDependency<IUserService>().GetProperUserId(default).ReturnsForAnyArgs(userId);
var resultProject = data.ToProject(orgId);
sutProvider.GetDependency<IUpdateProjectCommand>().UpdateAsync(default, default)
var resultProject = data.ToProject(existingProject.Id);
sutProvider.GetDependency<IUpdateProjectCommand>().UpdateAsync(default)
.ReturnsForAnyArgs(resultProject);
await sutProvider.Sut.UpdateAsync(orgId, data);
await Assert.ThrowsAsync<NotFoundException>(() => sutProvider.Sut.UpdateAsync(existingProject.Id, data));
await sutProvider.GetDependency<IUpdateProjectCommand>().DidNotReceiveWithAnyArgs()
.UpdateAsync(Arg.Any<Project>());
}
[Theory]
[BitAutoData]
public async void Update_Success(SutProvider<ProjectsController> sutProvider,
Guid userId, ProjectUpdateRequestModel data, Project existingProject)
{
sutProvider.GetDependency<IAuthorizationService>()
.AuthorizeAsync(Arg.Any<ClaimsPrincipal>(), data.ToProject(existingProject.Id),
Arg.Any<IEnumerable<IAuthorizationRequirement>>()).ReturnsForAnyArgs(AuthorizationResult.Success());
sutProvider.GetDependency<IProjectRepository>().GetByIdAsync(existingProject.Id).ReturnsForAnyArgs(existingProject);
sutProvider.GetDependency<IUserService>().GetProperUserId(default).ReturnsForAnyArgs(userId);
var resultProject = data.ToProject(existingProject.Id);
sutProvider.GetDependency<IUpdateProjectCommand>().UpdateAsync(default)
.ReturnsForAnyArgs(resultProject);
await sutProvider.Sut.UpdateAsync(existingProject.Id, data);
await sutProvider.GetDependency<IUpdateProjectCommand>().Received(1)
.UpdateAsync(Arg.Any<Project>(), Arg.Any<Guid>());
.UpdateAsync(Arg.Any<Project>());
}
[Theory]