1
0
mirror of https://github.com/bitwarden/server.git synced 2025-06-30 07:36:14 -05:00

[SM-380] Access checks for listing projects (#2496)

* Add project access checks for listing
This commit is contained in:
Oscar Hinton
2023-01-20 16:33:11 +01:00
committed by GitHub
parent a7c2ff9dbf
commit 5cd571df64
20 changed files with 452 additions and 69 deletions

View File

@ -1,10 +1,12 @@
using System.Net.Http.Headers;
using System.Net;
using System.Net.Http.Headers;
using Bit.Api.IntegrationTest.Factories;
using Bit.Api.IntegrationTest.Helpers;
using Bit.Api.Models.Response;
using Bit.Api.SecretManagerFeatures.Models.Request;
using Bit.Api.SecretManagerFeatures.Models.Response;
using Bit.Core.Entities;
using Bit.Core.Enums;
using Bit.Core.Repositories;
using Bit.Test.Common.Helpers;
using Xunit;
@ -31,10 +33,19 @@ public class ProjectsControllerTest : IClassFixture<ApiApplicationFactory>, IAsy
public async Task InitializeAsync()
{
var ownerEmail = $"integration-test{Guid.NewGuid()}@bitwarden.com";
var tokens = await _factory.LoginWithNewAccount(ownerEmail);
var (organization, _) = await OrganizationTestHelpers.SignUpAsync(_factory, ownerEmail: ownerEmail, billingEmail: ownerEmail);
await _factory.LoginWithNewAccount(ownerEmail);
(_organization, _) = await OrganizationTestHelpers.SignUpAsync(_factory, ownerEmail: ownerEmail, billingEmail: ownerEmail);
var tokens = await _factory.LoginAsync(ownerEmail);
_client.DefaultRequestHeaders.Authorization = new AuthenticationHeaderValue("Bearer", tokens.Token);
}
public async Task LoginAsNewOrgUser(OrganizationUserType type = OrganizationUserType.User)
{
var email = $"integration-test{Guid.NewGuid()}@bitwarden.com";
await _factory.LoginWithNewAccount(email);
await OrganizationTestHelpers.CreateUserAsync(_factory, _organization.Id, email, type);
var tokens = await _factory.LoginAsync(email);
_client.DefaultRequestHeaders.Authorization = new AuthenticationHeaderValue("Bearer", tokens.Token);
_organization = organization;
}
public Task DisposeAsync()
@ -44,12 +55,9 @@ public class ProjectsControllerTest : IClassFixture<ApiApplicationFactory>, IAsy
}
[Fact]
public async Task CreateProject()
public async Task CreateProject_Success()
{
var request = new ProjectCreateRequestModel()
{
Name = _mockEncryptedString
};
var request = new ProjectCreateRequestModel { Name = _mockEncryptedString };
var response = await _client.PostAsJsonAsync($"/organizations/{_organization.Id}/projects", request);
response.EnsureSuccessStatusCode();
@ -69,7 +77,17 @@ public class ProjectsControllerTest : IClassFixture<ApiApplicationFactory>, IAsy
}
[Fact]
public async Task UpdateProject()
public async Task CreateProject_NoPermission()
{
var request = new ProjectCreateRequestModel { Name = _mockEncryptedString };
var response = await _client.PostAsJsonAsync("/organizations/911d9106-7cf1-4d55-a3f9-f9abdeadecb3/projects", request);
Assert.Equal(HttpStatusCode.NotFound, response.StatusCode);
}
[Fact]
public async Task UpdateProject_Success()
{
var initialProject = await _projectRepository.CreateAsync(new Project
{
@ -101,6 +119,42 @@ public class ProjectsControllerTest : IClassFixture<ApiApplicationFactory>, IAsy
Assert.NotEqual(initialProject.RevisionDate, updatedProject.RevisionDate);
}
[Fact]
public async Task UpdateProject_NotFound()
{
var request = new ProjectUpdateRequestModel()
{
Name = "2.3Uk+WNBIoU5xzmVFNcoWzz==|1MsPIYuRfdOHfu/0uY6H2Q==|/98xy4wb6pHP1VTZ9JcNCYgQjEUMFPlqJgCwRk1YXKg=",
};
var response = await _client.PutAsJsonAsync("/projects/c53de509-4581-402c-8cbd-f26d2c516fba", request);
Assert.Equal(HttpStatusCode.NotFound, response.StatusCode);
}
[Fact]
public async Task UpdateProject_MissingPermission()
{
// Create a new account as a user
await LoginAsNewOrgUser();
var project = await _projectRepository.CreateAsync(new Project
{
OrganizationId = _organization.Id,
Name = _mockEncryptedString
});
var request = new ProjectUpdateRequestModel()
{
Name = "2.3Uk+WNBIoU5xzmVFNcoWzz==|1MsPIYuRfdOHfu/0uY6H2Q==|/98xy4wb6pHP1VTZ9JcNCYgQjEUMFPlqJgCwRk1YXKg=",
};
var response = await _client.PutAsJsonAsync($"/projects/{project.Id}", request);
Assert.Equal(HttpStatusCode.Unauthorized, response.StatusCode);
}
[Fact]
public async Task GetProject()
{

View File

@ -45,4 +45,12 @@ public class ApiApplicationFactory : WebApplicationFactoryBase<Startup>
return await _identityApplicationFactory.TokenFromPasswordAsync(email, masterPasswordHash);
}
/// <summary>
/// Helper for logging in to an account
/// </summary>
public async Task<(string Token, string RefreshToken)> LoginAsync(string email = "integration-test@bitwarden.com", string masterPasswordHash = "master_password_hash")
{
return await _identityApplicationFactory.TokenFromPasswordAsync(email, masterPasswordHash);
}
}

View File

@ -9,7 +9,8 @@ namespace Bit.Api.IntegrationTest.Helpers;
public static class OrganizationTestHelpers
{
public static async Task<Tuple<Organization, OrganizationUser>> SignUpAsync<T>(WebApplicationFactoryBase<T> factory,
public static async Task<Tuple<Organization, OrganizationUser>> SignUpAsync<T>(
WebApplicationFactoryBase<T> factory,
PlanType plan = PlanType.Free,
string ownerEmail = "integration-test@bitwarden.com",
string name = "Integration Test Org",
@ -30,4 +31,32 @@ public static class OrganizationTestHelpers
Owner = owner,
});
}
public static async Task<OrganizationUser> CreateUserAsync<T>(
WebApplicationFactoryBase<T> factory,
Guid organizationId,
string userEmail,
OrganizationUserType type
) where T : class
{
var userRepository = factory.GetService<IUserRepository>();
var organizationUserRepository = factory.GetService<IOrganizationUserRepository>();
var user = await userRepository.GetByEmailAsync(userEmail);
var orgUser = new OrganizationUser
{
OrganizationId = organizationId,
UserId = user.Id,
Key = null,
Type = type,
Status = OrganizationUserStatusType.Invited,
AccessAll = false,
ExternalId = null,
};
await organizationUserRepository.CreateAsync(orgUser);
return orgUser;
}
}