using System.Net.Http.Headers; using Bit.Api.IntegrationTest.Factories; using Bit.Api.IntegrationTest.Helpers; using Bit.Api.SecretsManager.Models.Request; using Bit.Api.SecretsManager.Models.Response; using Bit.Core.Entities; using Bit.Core.SecretsManager.Entities; using Bit.Core.SecretsManager.Repositories; using Bit.Test.Common.Helpers; using Xunit; namespace Bit.Api.IntegrationTest.SecretsManager.Controllers; public class AccessPoliciesControllerTest : IClassFixture, IAsyncLifetime { private readonly IAccessPolicyRepository _accessPolicyRepository; private readonly HttpClient _client; private readonly ApiApplicationFactory _factory; private const string _mockEncryptedString = "2.3Uk+WNBIoU5xzmVFNcoWzz==|1MsPIYuRfdOHfu/0uY6H2Q==|/98sp4wb6pHP1VTZ9JcNCYgQjEUMFPlqJgCwRk1YXKg="; private readonly IProjectRepository _projectRepository; private readonly IServiceAccountRepository _serviceAccountRepository; private Organization _organization = null!; public AccessPoliciesControllerTest(ApiApplicationFactory factory) { _factory = factory; _client = _factory.CreateClient(); _accessPolicyRepository = _factory.GetService(); _serviceAccountRepository = _factory.GetService(); _projectRepository = _factory.GetService(); } 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); _client.DefaultRequestHeaders.Authorization = new AuthenticationHeaderValue("Bearer", tokens.Token); _organization = organization; } public Task DisposeAsync() => Task.CompletedTask; [Fact] public async Task CreateProjectAccessPolicies() { var initialProject = await _projectRepository.CreateAsync(new Project { OrganizationId = _organization.Id, Name = _mockEncryptedString }); var initialServiceAccount = await _serviceAccountRepository.CreateAsync(new ServiceAccount { OrganizationId = _organization.Id, Name = _mockEncryptedString }); var request = new AccessPoliciesCreateRequest { ServiceAccountAccessPolicyRequests = new List { new() { GranteeId = initialServiceAccount.Id, Read = true, Write = true } } }; var response = await _client.PostAsJsonAsync($"/projects/{initialProject.Id}/access-policies", request); response.EnsureSuccessStatusCode(); var result = await response.Content.ReadFromJsonAsync(); Assert.NotNull(result); Assert.Equal(initialServiceAccount.Id, result!.ServiceAccountAccessPolicies.First().ServiceAccountId); Assert.True(result.ServiceAccountAccessPolicies.First().Read); Assert.True(result.ServiceAccountAccessPolicies.First().Write); AssertHelper.AssertRecent(result.ServiceAccountAccessPolicies.First().RevisionDate); AssertHelper.AssertRecent(result.ServiceAccountAccessPolicies.First().CreationDate); var createdAccessPolicy = await _accessPolicyRepository.GetByIdAsync(result.ServiceAccountAccessPolicies.First().Id); Assert.NotNull(createdAccessPolicy); Assert.Equal(result.ServiceAccountAccessPolicies.First().Read, createdAccessPolicy!.Read); Assert.Equal(result.ServiceAccountAccessPolicies.First().Write, createdAccessPolicy.Write); Assert.Equal(result.ServiceAccountAccessPolicies.First().Id, createdAccessPolicy.Id); AssertHelper.AssertRecent(createdAccessPolicy.CreationDate); AssertHelper.AssertRecent(createdAccessPolicy.RevisionDate); } [Fact] public async Task UpdateAccessPolicy() { var initData = await SetupAccessPolicyRequest(); const bool expectedRead = true; const bool expectedWrite = false; var request = new AccessPolicyUpdateRequest { Read = expectedRead, Write = expectedWrite }; var response = await _client.PutAsJsonAsync($"/access-policies/{initData.InitialAccessPolicyId}", request); response.EnsureSuccessStatusCode(); var result = await response.Content.ReadFromJsonAsync(); Assert.NotNull(result); Assert.Equal(expectedRead, result!.Read); Assert.Equal(expectedWrite, result.Write); AssertHelper.AssertRecent(result.RevisionDate); var updatedAccessPolicy = await _accessPolicyRepository.GetByIdAsync(result.Id); Assert.NotNull(updatedAccessPolicy); Assert.Equal(expectedRead, updatedAccessPolicy!.Read); Assert.Equal(expectedWrite, updatedAccessPolicy.Write); AssertHelper.AssertRecent(updatedAccessPolicy.RevisionDate); } [Fact] public async Task DeleteAccessPolicy() { var initData = await SetupAccessPolicyRequest(); var response = await _client.DeleteAsync($"/access-policies/{initData.InitialAccessPolicyId}"); response.EnsureSuccessStatusCode(); var test = await _accessPolicyRepository.GetByIdAsync(initData.InitialAccessPolicyId); Assert.Null(test); } [Fact] public async Task GetProjectAccessPolicies() { var initData = await SetupAccessPolicyRequest(); var response = await _client.GetAsync($"/projects/{initData.InitialProjectId}/access-policies"); response.EnsureSuccessStatusCode(); var result = await response.Content.ReadFromJsonAsync(); Assert.NotNull(result?.ServiceAccountAccessPolicies); Assert.Single(result!.ServiceAccountAccessPolicies); } private async Task SetupAccessPolicyRequest() { var initialProject = await _projectRepository.CreateAsync(new Project { OrganizationId = _organization.Id, Name = _mockEncryptedString, }); var initialServiceAccount = await _serviceAccountRepository.CreateAsync(new ServiceAccount { OrganizationId = _organization.Id, Name = _mockEncryptedString, }); var initialAccessPolicy = await _accessPolicyRepository.CreateManyAsync( new List { new ServiceAccountProjectAccessPolicy { Read = true, Write = true, ServiceAccountId = initialServiceAccount.Id, GrantedProjectId = initialProject.Id, } }); return new RequestSetupData { InitialProjectId = initialProject.Id, InitialServiceAccountId = initialServiceAccount.Id, InitialAccessPolicyId = initialAccessPolicy.First().Id, }; } private class RequestSetupData { public Guid InitialProjectId { get; set; } public Guid InitialAccessPolicyId { get; set; } public Guid InitialServiceAccountId { get; set; } } }