diff --git a/test/Api.IntegrationTest/Factories/ApiApplicationFactory.cs b/test/Api.IntegrationTest/Factories/ApiApplicationFactory.cs index 90a2335c2..f669e89eb 100644 --- a/test/Api.IntegrationTest/Factories/ApiApplicationFactory.cs +++ b/test/Api.IntegrationTest/Factories/ApiApplicationFactory.cs @@ -64,4 +64,13 @@ public class ApiApplicationFactory : WebApplicationFactoryBase base.Dispose(disposing); SqliteConnection.Dispose(); } + + /// + /// Helper for logging in via client secret. + /// Currently used for Secrets Manager service accounts + /// + public async Task LoginWithClientSecretAsync(Guid clientId, string clientSecret) + { + return await _identityApplicationFactory.TokenFromAccessTokenAsync(clientId, clientSecret); + } } diff --git a/test/Api.IntegrationTest/SecretsManager/Controllers/AccessPoliciesControllerTests.cs b/test/Api.IntegrationTest/SecretsManager/Controllers/AccessPoliciesControllerTests.cs index b8eb4a770..e1cce6870 100644 --- a/test/Api.IntegrationTest/SecretsManager/Controllers/AccessPoliciesControllerTests.cs +++ b/test/Api.IntegrationTest/SecretsManager/Controllers/AccessPoliciesControllerTests.cs @@ -1,7 +1,7 @@ using System.Net; -using System.Net.Http.Headers; using Bit.Api.IntegrationTest.Factories; using Bit.Api.IntegrationTest.SecretsManager.Enums; +using Bit.Api.IntegrationTest.SecretsManager.Helpers; using Bit.Api.Models.Response; using Bit.Api.SecretsManager.Models.Request; using Bit.Api.SecretsManager.Models.Response; @@ -28,6 +28,7 @@ public class AccessPoliciesControllerTests : IClassFixture(); _projectRepository = _factory.GetService(); _groupRepository = _factory.GetService(); + _loginHelper = new LoginHelper(_factory, _client); } public async Task InitializeAsync() @@ -54,12 +56,6 @@ public class AccessPoliciesControllerTests : IClassFixture(); Assert.NotNull(result); - Assert.Equal(serviceAccountId, result!.ServiceAccountAccessPolicies.First().ServiceAccountId); + Assert.Equal(serviceAccountId, result.ServiceAccountAccessPolicies.First().ServiceAccountId); Assert.True(result.ServiceAccountAccessPolicies.First().Read); Assert.True(result.ServiceAccountAccessPolicies.First().Write); AssertHelper.AssertRecent(result.ServiceAccountAccessPolicies.First().RevisionDate); @@ -168,7 +164,7 @@ public class AccessPoliciesControllerTests : IClassFixture { new UserProjectAccessPolicy @@ -249,13 +245,13 @@ public class AccessPoliciesControllerTests : IClassFixture(); Assert.NotNull(result); - Assert.Equal(expectedRead, result!.Read); + 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(expectedRead, updatedAccessPolicy.Read); Assert.Equal(expectedWrite, updatedAccessPolicy.Write); AssertHelper.AssertRecent(updatedAccessPolicy.RevisionDate); } @@ -271,7 +267,7 @@ public class AccessPoliciesControllerTests : IClassFixture { new UserProjectAccessPolicy @@ -327,7 +323,7 @@ public class AccessPoliciesControllerTests : IClassFixture(); Assert.NotNull(result); - Assert.Empty(result!.UserAccessPolicies); + Assert.Empty(result.UserAccessPolicies); Assert.Empty(result.GroupAccessPolicies); Assert.Empty(result.ServiceAccountAccessPolicies); } @@ -357,7 +353,7 @@ public class AccessPoliciesControllerTests : IClassFixture { new UserProjectAccessPolicy @@ -409,7 +405,7 @@ public class AccessPoliciesControllerTests : IClassFixture(); Assert.NotNull(result?.ServiceAccountAccessPolicies); - Assert.Single(result!.ServiceAccountAccessPolicies); + Assert.Single(result.ServiceAccountAccessPolicies); } [Theory] @@ -423,7 +419,7 @@ public class AccessPoliciesControllerTests : IClassFixture>(); Assert.NotNull(result?.Data); - Assert.NotEmpty(result!.Data); + Assert.NotEmpty(result.Data); } [Theory] @@ -467,7 +463,7 @@ public class AccessPoliciesControllerTests : IClassFixture>(); Assert.NotNull(result?.Data); - Assert.Empty(result!.Data); + Assert.Empty(result.Data); } [Theory] @@ -507,7 +503,7 @@ public class AccessPoliciesControllerTests : IClassFixture @@ -541,7 +537,7 @@ public class AccessPoliciesControllerTests : IClassFixture>(); Assert.NotNull(result?.Data); - Assert.NotEmpty(result!.Data); + Assert.NotEmpty(result.Data); Assert.Equal(serviceAccount.Id, result.Data.First(x => x.Id == serviceAccount.Id).Id); } @@ -556,7 +552,7 @@ public class AccessPoliciesControllerTests : IClassFixture>(); Assert.NotNull(result?.Data); - Assert.Empty(result!.Data); + Assert.Empty(result.Data); } [Theory] @@ -592,7 +588,7 @@ public class AccessPoliciesControllerTests : IClassFixture @@ -623,7 +619,7 @@ public class AccessPoliciesControllerTests : IClassFixture>(); Assert.NotNull(result?.Data); - Assert.NotEmpty(result!.Data); + Assert.NotEmpty(result.Data); Assert.Equal(project.Id, result.Data.First(x => x.Id == project.Id).Id); } @@ -638,7 +634,7 @@ public class AccessPoliciesControllerTests : IClassFixture>(); Assert.NotNull(result); - Assert.NotEmpty(result!.Data); + Assert.NotEmpty(result.Data); Assert.Equal(projectId, result.Data.First().GrantedProjectId); var createdAccessPolicy = await _accessPolicyRepository.GetByIdAsync(result.Data.First().Id); Assert.NotNull(createdAccessPolicy); - Assert.Equal(result.Data.First().Read, createdAccessPolicy!.Read); + Assert.Equal(result.Data.First().Read, createdAccessPolicy.Read); Assert.Equal(result.Data.First().Write, createdAccessPolicy.Write); Assert.Equal(result.Data.First().Id, createdAccessPolicy.Id); AssertHelper.AssertRecent(createdAccessPolicy.CreationDate); @@ -747,7 +743,7 @@ public class AccessPoliciesControllerTests : IClassFixture>(); Assert.NotNull(result); - Assert.Empty(result!.Data); + Assert.Empty(result.Data); } [Fact] @@ -782,7 +778,7 @@ public class AccessPoliciesControllerTests : IClassFixture>(); Assert.NotNull(result); - Assert.Empty(result!.Data); + Assert.Empty(result.Data); } [Theory] @@ -801,13 +797,13 @@ public class AccessPoliciesControllerTests : IClassFixture { new UserProjectAccessPolicy @@ -825,7 +821,7 @@ public class AccessPoliciesControllerTests : IClassFixture>(); Assert.NotNull(result?.Data); - Assert.NotEmpty(result!.Data); + Assert.NotEmpty(result.Data); Assert.Equal(initData.ServiceAccountId, result.Data.First().ServiceAccountId); Assert.NotNull(result.Data.First().ServiceAccountName); Assert.NotNull(result.Data.First().GrantedProjectName); @@ -842,7 +838,7 @@ public class AccessPoliciesControllerTests : IClassFixture(); Assert.NotNull(result); - Assert.Empty(result!.UserAccessPolicies); + Assert.Empty(result.UserAccessPolicies); Assert.Empty(result.GroupAccessPolicies); } @@ -881,7 +877,7 @@ public class AccessPoliciesControllerTests : IClassFixture(); Assert.NotNull(result?.UserAccessPolicies); - Assert.Single(result!.UserAccessPolicies); + Assert.Single(result.UserAccessPolicies); } [Theory] @@ -924,7 +920,7 @@ public class AccessPoliciesControllerTests : IClassFixture(); Assert.NotNull(result); - Assert.Empty(result!.UserAccessPolicies); + Assert.Empty(result.UserAccessPolicies); Assert.Empty(result.GroupAccessPolicies); } @@ -1061,7 +1057,7 @@ public class AccessPoliciesControllerTests : IClassFixture(); Assert.NotNull(result?.UserAccessPolicies); - Assert.Single(result!.UserAccessPolicies); + Assert.Single(result.UserAccessPolicies); } [Theory] @@ -1100,7 +1096,7 @@ public class AccessPoliciesControllerTests : IClassFixture { new UserProjectAccessPolicy @@ -1361,35 +1357,6 @@ public class AccessPoliciesControllerTests : IClassFixture SetupUserServiceAccountAccessPolicyRequestAsync( - PermissionType permissionType, Guid userId, Guid serviceAccountId) - { - if (permissionType == PermissionType.RunAsUserWithPermission) - { - var (email, newOrgUser) = await _organizationHelper.CreateNewUser(OrganizationUserType.User, true); - await LoginAsync(email); - var accessPolicies = new List - { - new UserServiceAccountAccessPolicy - { - GrantedServiceAccountId = serviceAccountId, - OrganizationUserId = newOrgUser.Id, - Read = true, - Write = true, - }, - }; - await _accessPolicyRepository.CreateManyAsync(accessPolicies); - } - - return new AccessPoliciesCreateRequest - { - UserAccessPolicyRequests = new List - { - new() { GranteeId = userId, Read = true, Write = true }, - }, - }; - } - private class RequestSetupData { public Guid ProjectId { get; set; } diff --git a/test/Api.IntegrationTest/SecretsManager/Controllers/ProjectsControllerTests.cs b/test/Api.IntegrationTest/SecretsManager/Controllers/ProjectsControllerTests.cs index 523998ee2..95ddfd678 100644 --- a/test/Api.IntegrationTest/SecretsManager/Controllers/ProjectsControllerTests.cs +++ b/test/Api.IntegrationTest/SecretsManager/Controllers/ProjectsControllerTests.cs @@ -1,7 +1,7 @@ using System.Net; -using System.Net.Http.Headers; using Bit.Api.IntegrationTest.Factories; using Bit.Api.IntegrationTest.SecretsManager.Enums; +using Bit.Api.IntegrationTest.SecretsManager.Helpers; using Bit.Api.Models.Response; using Bit.Api.SecretsManager.Models.Request; using Bit.Api.SecretsManager.Models.Response; @@ -10,7 +10,6 @@ using Bit.Core.Enums; using Bit.Core.SecretsManager.Entities; using Bit.Core.SecretsManager.Repositories; using Bit.Test.Common.Helpers; -using Pipelines.Sockets.Unofficial.Arenas; using Xunit; namespace Bit.Api.IntegrationTest.SecretsManager.Controllers; @@ -24,6 +23,7 @@ public class ProjectsControllerTests : IClassFixture, IAs private readonly ApiApplicationFactory _factory; private readonly IProjectRepository _projectRepository; private readonly IAccessPolicyRepository _accessPolicyRepository; + private readonly LoginHelper _loginHelper; private string _email = null!; private SecretsManagerOrganizationHelper _organizationHelper = null!; @@ -34,6 +34,7 @@ public class ProjectsControllerTests : IClassFixture, IAs _client = _factory.CreateClient(); _projectRepository = _factory.GetService(); _accessPolicyRepository = _factory.GetService(); + _loginHelper = new LoginHelper(_factory, _client); } public async Task InitializeAsync() @@ -49,12 +50,6 @@ public class ProjectsControllerTests : IClassFixture, IAs return Task.CompletedTask; } - private async Task LoginAsync(string email) - { - var tokens = await _factory.LoginAsync(email); - _client.DefaultRequestHeaders.Authorization = new AuthenticationHeaderValue("Bearer", tokens.Token); - } - [Theory] [InlineData(false, false, false)] [InlineData(false, false, true)] @@ -66,7 +61,7 @@ public class ProjectsControllerTests : IClassFixture, IAs public async Task ListByOrganization_SmAccessDenied_NotFound(bool useSecrets, bool accessSecrets, bool organizationEnabled) { var (org, _) = await _organizationHelper.Initialize(useSecrets, accessSecrets, organizationEnabled); - await LoginAsync(_email); + await _loginHelper.LoginAsync(_email); var response = await _client.GetAsync($"/organizations/{org.Id}/projects"); Assert.Equal(HttpStatusCode.NotFound, response.StatusCode); @@ -77,7 +72,7 @@ public class ProjectsControllerTests : IClassFixture, IAs { var (org, _) = await _organizationHelper.Initialize(true, true, true); var (email, _) = await _organizationHelper.CreateNewUser(OrganizationUserType.User, true); - await LoginAsync(email); + await _loginHelper.LoginAsync(email); await CreateProjectsAsync(org.Id); @@ -86,7 +81,7 @@ public class ProjectsControllerTests : IClassFixture, IAs var result = await response.Content.ReadFromJsonAsync>(); Assert.NotNull(result); - Assert.Empty(result!.Data); + Assert.Empty(result.Data); } [Theory] @@ -101,7 +96,7 @@ public class ProjectsControllerTests : IClassFixture, IAs var result = await response.Content.ReadFromJsonAsync>(); Assert.NotNull(result); - Assert.NotEmpty(result!.Data); + Assert.NotEmpty(result.Data); Assert.Equal(projectIds.Count, result.Data.Count()); } @@ -116,7 +111,7 @@ public class ProjectsControllerTests : IClassFixture, IAs public async Task Create_SmAccessDenied_NotFound(bool useSecrets, bool accessSecrets, bool organizationEnabled) { var (org, _) = await _organizationHelper.Initialize(useSecrets, accessSecrets, organizationEnabled); - await LoginAsync(_email); + await _loginHelper.LoginAsync(_email); var request = new ProjectCreateRequestModel { Name = _mockEncryptedString }; @@ -129,7 +124,7 @@ public class ProjectsControllerTests : IClassFixture, IAs [InlineData(PermissionType.RunAsUserWithPermission)] public async Task Create_AtMaxProjects_BadRequest(PermissionType permissionType) { - var (_, organization) = await SetupProjectsWithAccessAsync(permissionType, 3); + var (_, organization) = await SetupProjectsWithAccessAsync(permissionType); var request = new ProjectCreateRequestModel { Name = _mockEncryptedString }; var response = await _client.PostAsJsonAsync($"/organizations/{organization.Id}/projects", request); @@ -143,14 +138,14 @@ public class ProjectsControllerTests : IClassFixture, IAs public async Task Create_Success(PermissionType permissionType) { var (org, adminOrgUser) = await _organizationHelper.Initialize(true, true, true); - await LoginAsync(_email); + await _loginHelper.LoginAsync(_email); var orgUserId = adminOrgUser.Id; var currentUserId = adminOrgUser.UserId!.Value; if (permissionType == PermissionType.RunAsUserWithPermission) { var (email, orgUser) = await _organizationHelper.CreateNewUser(OrganizationUserType.User, true); - await LoginAsync(email); + await _loginHelper.LoginAsync(email); orgUserId = orgUser.Id; currentUserId = orgUser.UserId!.Value; } @@ -162,7 +157,7 @@ public class ProjectsControllerTests : IClassFixture, IAs var result = await response.Content.ReadFromJsonAsync(); Assert.NotNull(result); - Assert.Equal(request.Name, result!.Name); + Assert.Equal(request.Name, result.Name); AssertHelper.AssertRecent(result.RevisionDate); AssertHelper.AssertRecent(result.CreationDate); @@ -196,7 +191,7 @@ public class ProjectsControllerTests : IClassFixture, IAs public async Task Update_SmAccessDenied_NotFound(bool useSecrets, bool accessSecrets, bool organizationEnabled) { var (org, _) = await _organizationHelper.Initialize(useSecrets, accessSecrets, organizationEnabled); - await LoginAsync(_email); + await _loginHelper.LoginAsync(_email); var initialProject = await _projectRepository.CreateAsync(new Project { @@ -244,7 +239,7 @@ public class ProjectsControllerTests : IClassFixture, IAs public async Task Update_NonExistingProject_NotFound() { await _organizationHelper.Initialize(true, true, true); - await LoginAsync(_email); + await _loginHelper.LoginAsync(_email); var request = new ProjectUpdateRequestModel { @@ -262,7 +257,7 @@ public class ProjectsControllerTests : IClassFixture, IAs { var (org, _) = await _organizationHelper.Initialize(true, true, true); var (email, _) = await _organizationHelper.CreateNewUser(OrganizationUserType.User, true); - await LoginAsync(email); + await _loginHelper.LoginAsync(email); var project = await _projectRepository.CreateAsync(new Project { @@ -292,7 +287,7 @@ public class ProjectsControllerTests : IClassFixture, IAs public async Task Get_SmAccessDenied_NotFound(bool useSecrets, bool accessSecrets, bool organizationEnabled) { var (org, _) = await _organizationHelper.Initialize(useSecrets, accessSecrets, organizationEnabled); - await LoginAsync(_email); + await _loginHelper.LoginAsync(_email); var project = await _projectRepository.CreateAsync(new Project { @@ -313,7 +308,7 @@ public class ProjectsControllerTests : IClassFixture, IAs { var (org, _) = await _organizationHelper.Initialize(true, true, true); var (email, _) = await _organizationHelper.CreateNewUser(OrganizationUserType.User, true); - await LoginAsync(email); + await _loginHelper.LoginAsync(email); var createdProject = await _projectRepository.CreateAsync(new Project { @@ -330,7 +325,7 @@ public class ProjectsControllerTests : IClassFixture, IAs { var (org, _) = await _organizationHelper.Initialize(true, true, true); var (email, _) = await _organizationHelper.CreateNewUser(OrganizationUserType.User, true); - await LoginAsync(email); + await _loginHelper.LoginAsync(email); var createdProject = await _projectRepository.CreateAsync(new Project { @@ -338,7 +333,7 @@ public class ProjectsControllerTests : IClassFixture, IAs Name = _mockEncryptedString, }); - var deleteResponse = await _client.PostAsync("/projects/delete", JsonContent.Create(createdProject.Id)); + await _client.PostAsync("/projects/delete", JsonContent.Create(createdProject.Id)); var response = await _client.GetAsync($"/projects/{createdProject.Id}"); Assert.Equal(HttpStatusCode.NotFound, response.StatusCode); @@ -372,7 +367,7 @@ public class ProjectsControllerTests : IClassFixture, IAs public async Task Delete_SmAccessDenied_NotFound(bool useSecrets, bool accessSecrets, bool organizationEnabled) { var (org, _) = await _organizationHelper.Initialize(useSecrets, accessSecrets, organizationEnabled); - await LoginAsync(_email); + await _loginHelper.LoginAsync(_email); var projectIds = await CreateProjectsAsync(org.Id); @@ -385,7 +380,7 @@ public class ProjectsControllerTests : IClassFixture, IAs { var (org, _) = await _organizationHelper.Initialize(true, true, true); var (email, _) = await _organizationHelper.CreateNewUser(OrganizationUserType.User, true); - await LoginAsync(email); + await _loginHelper.LoginAsync(email); var projectIds = await CreateProjectsAsync(org.Id); @@ -394,7 +389,7 @@ public class ProjectsControllerTests : IClassFixture, IAs var results = await response.Content.ReadFromJsonAsync>(); Assert.NotNull(results); Assert.Equal(projectIds.OrderBy(x => x), - results!.Data.Select(x => x.Id).OrderBy(x => x)); + results.Data.Select(x => x.Id).OrderBy(x => x)); Assert.All(results.Data, item => Assert.Equal("access denied", item.Error)); } @@ -411,7 +406,7 @@ public class ProjectsControllerTests : IClassFixture, IAs var results = await response.Content.ReadFromJsonAsync>(); Assert.NotNull(results); Assert.Equal(projectIds.OrderBy(x => x), - results!.Data.Select(x => x.Id).OrderBy(x => x)); + results.Data.Select(x => x.Id).OrderBy(x => x)); Assert.DoesNotContain(results.Data, x => x.Error != null); var projects = await _projectRepository.GetManyWithSecretsByIds(projectIds); @@ -438,7 +433,7 @@ public class ProjectsControllerTests : IClassFixture, IAs int projectsToCreate = 3) { var (org, _) = await _organizationHelper.Initialize(true, true, true); - await LoginAsync(_email); + await _loginHelper.LoginAsync(_email); var projectIds = await CreateProjectsAsync(org.Id, projectsToCreate); if (permissionType == PermissionType.RunAsAdmin) @@ -447,7 +442,7 @@ public class ProjectsControllerTests : IClassFixture, IAs } var (email, orgUser) = await _organizationHelper.CreateNewUser(OrganizationUserType.User, true); - await LoginAsync(email); + await _loginHelper.LoginAsync(email); var accessPolicies = projectIds.Select(projectId => new UserProjectAccessPolicy { @@ -467,7 +462,7 @@ public class ProjectsControllerTests : IClassFixture, IAs private async Task SetupProjectWithAccessAsync(PermissionType permissionType) { var (org, _) = await _organizationHelper.Initialize(true, true, true); - await LoginAsync(_email); + await _loginHelper.LoginAsync(_email); var initialProject = await _projectRepository.CreateAsync(new Project { @@ -481,7 +476,7 @@ public class ProjectsControllerTests : IClassFixture, IAs } var (email, orgUser) = await _organizationHelper.CreateNewUser(OrganizationUserType.User, true); - await LoginAsync(email); + await _loginHelper.LoginAsync(email); var accessPolicies = new List { diff --git a/test/Api.IntegrationTest/SecretsManager/Controllers/SecretsControllerTests.cs b/test/Api.IntegrationTest/SecretsManager/Controllers/SecretsControllerTests.cs index 4932ad9b9..0ff7396ed 100644 --- a/test/Api.IntegrationTest/SecretsManager/Controllers/SecretsControllerTests.cs +++ b/test/Api.IntegrationTest/SecretsManager/Controllers/SecretsControllerTests.cs @@ -1,7 +1,7 @@ using System.Net; -using System.Net.Http.Headers; using Bit.Api.IntegrationTest.Factories; using Bit.Api.IntegrationTest.SecretsManager.Enums; +using Bit.Api.IntegrationTest.SecretsManager.Helpers; using Bit.Api.Models.Response; using Bit.Api.SecretsManager.Models.Request; using Bit.Api.SecretsManager.Models.Response; @@ -23,6 +23,7 @@ public class SecretsControllerTests : IClassFixture, IAsy private readonly ISecretRepository _secretRepository; private readonly IProjectRepository _projectRepository; private readonly IAccessPolicyRepository _accessPolicyRepository; + private readonly LoginHelper _loginHelper; private string _email = null!; private SecretsManagerOrganizationHelper _organizationHelper = null!; @@ -34,6 +35,7 @@ public class SecretsControllerTests : IClassFixture, IAsy _secretRepository = _factory.GetService(); _projectRepository = _factory.GetService(); _accessPolicyRepository = _factory.GetService(); + _loginHelper = new LoginHelper(_factory, _client); } public async Task InitializeAsync() @@ -49,12 +51,6 @@ public class SecretsControllerTests : IClassFixture, IAsy return Task.CompletedTask; } - private async Task LoginAsync(string email) - { - var tokens = await _factory.LoginAsync(email); - _client.DefaultRequestHeaders.Authorization = new AuthenticationHeaderValue("Bearer", tokens.Token); - } - [Theory] [InlineData(false, false, false)] [InlineData(false, false, true)] @@ -66,7 +62,7 @@ public class SecretsControllerTests : IClassFixture, IAsy public async Task ListByOrganization_SmAccessDenied_NotFound(bool useSecrets, bool accessSecrets, bool organizationEnabled) { var (org, _) = await _organizationHelper.Initialize(useSecrets, accessSecrets, organizationEnabled); - await LoginAsync(_email); + await _loginHelper.LoginAsync(_email); var response = await _client.GetAsync($"/organizations/{org.Id}/secrets"); Assert.Equal(HttpStatusCode.NotFound, response.StatusCode); @@ -77,8 +73,8 @@ public class SecretsControllerTests : IClassFixture, IAsy [InlineData(PermissionType.RunAsUserWithPermission)] public async Task ListByOrganization_Success(PermissionType permissionType) { - var (org, orgUserOwner) = await _organizationHelper.Initialize(true, true, true); - await LoginAsync(_email); + var (org, _) = await _organizationHelper.Initialize(true, true, true); + await _loginHelper.LoginAsync(_email); var project = await _projectRepository.CreateAsync(new Project { @@ -90,7 +86,7 @@ public class SecretsControllerTests : IClassFixture, IAsy if (permissionType == PermissionType.RunAsUserWithPermission) { var (email, orgUser) = await _organizationHelper.CreateNewUser(OrganizationUserType.User, true); - await LoginAsync(email); + await _loginHelper.LoginAsync(email); var accessPolicies = new List { @@ -122,7 +118,7 @@ public class SecretsControllerTests : IClassFixture, IAsy var result = await response.Content.ReadFromJsonAsync(); Assert.NotNull(result); - Assert.NotEmpty(result!.Secrets); + Assert.NotEmpty(result.Secrets); Assert.Equal(secretIds.Count, result.Secrets.Count()); } @@ -137,7 +133,7 @@ public class SecretsControllerTests : IClassFixture, IAsy public async Task Create_SmAccessDenied_NotFound(bool useSecrets, bool accessSecrets, bool organizationEnabled) { var (org, _) = await _organizationHelper.Initialize(useSecrets, accessSecrets, organizationEnabled); - await LoginAsync(_email); + await _loginHelper.LoginAsync(_email); var request = new SecretCreateRequestModel { @@ -154,7 +150,7 @@ public class SecretsControllerTests : IClassFixture, IAsy public async Task CreateWithoutProject_RunAsAdmin_Success() { var (org, _) = await _organizationHelper.Initialize(true, true, true); - await LoginAsync(_email); + await _loginHelper.LoginAsync(_email); var request = new SecretCreateRequestModel { @@ -168,7 +164,7 @@ public class SecretsControllerTests : IClassFixture, IAsy var result = await response.Content.ReadFromJsonAsync(); Assert.NotNull(result); - Assert.Equal(request.Key, result!.Key); + Assert.Equal(request.Key, result.Key); Assert.Equal(request.Value, result.Value); Assert.Equal(request.Note, result.Note); AssertHelper.AssertRecent(result.RevisionDate); @@ -188,7 +184,7 @@ public class SecretsControllerTests : IClassFixture, IAsy public async Task CreateWithDifferentProjectOrgId_RunAsAdmin_NotFound() { var (org, _) = await _organizationHelper.Initialize(true, true, true); - await LoginAsync(_email); + await _loginHelper.LoginAsync(_email); var anotherOrg = await _organizationHelper.CreateSmOrganizationAsync(); var project = @@ -210,7 +206,7 @@ public class SecretsControllerTests : IClassFixture, IAsy public async Task CreateWithMultipleProjects_RunAsAdmin_BadRequest() { var (org, _) = await _organizationHelper.Initialize(true, true, true); - await LoginAsync(_email); + await _loginHelper.LoginAsync(_email); var projectA = await _projectRepository.CreateAsync(new Project { OrganizationId = org.Id, Name = "123A" }); var projectB = await _projectRepository.CreateAsync(new Project { OrganizationId = org.Id, Name = "123B" }); @@ -231,8 +227,8 @@ public class SecretsControllerTests : IClassFixture, IAsy public async Task CreateWithoutProject_RunAsUser_NotFound() { var (org, _) = await _organizationHelper.Initialize(true, true, true); - var (email, orgUser) = await _organizationHelper.CreateNewUser(OrganizationUserType.User, true); - await LoginAsync(email); + var (email, _) = await _organizationHelper.CreateNewUser(OrganizationUserType.User, true); + await _loginHelper.LoginAsync(email); var request = new SecretCreateRequestModel { @@ -251,9 +247,9 @@ public class SecretsControllerTests : IClassFixture, IAsy public async Task CreateWithProject_Success(PermissionType permissionType) { var (org, orgAdminUser) = await _organizationHelper.Initialize(true, true, true); - await LoginAsync(_email); + await _loginHelper.LoginAsync(_email); - AccessClientType accessType = AccessClientType.NoAccessCheck; + var accessType = AccessClientType.NoAccessCheck; var project = await _projectRepository.CreateAsync(new Project() { @@ -267,12 +263,12 @@ public class SecretsControllerTests : IClassFixture, IAsy if (permissionType == PermissionType.RunAsUserWithPermission) { var (email, orgUser) = await _organizationHelper.CreateNewUser(OrganizationUserType.User, true); - await LoginAsync(email); + await _loginHelper.LoginAsync(email); accessType = AccessClientType.User; var accessPolicies = new List { - new Core.SecretsManager.Entities.UserProjectAccessPolicy + new UserProjectAccessPolicy { GrantedProjectId = project.Id, OrganizationUserId = orgUser.Id , Read = true, Write = true, }, @@ -296,7 +292,7 @@ public class SecretsControllerTests : IClassFixture, IAsy var secret = result.Secret; Assert.NotNull(secretResult); - Assert.Equal(secret.Id, secretResult!.Id); + Assert.Equal(secret.Id, secretResult.Id); Assert.Equal(secret.OrganizationId, secretResult.OrganizationId); Assert.Equal(secret.Key, secretResult.Key); Assert.Equal(secret.Value, secretResult.Value); @@ -316,7 +312,7 @@ public class SecretsControllerTests : IClassFixture, IAsy public async Task Get_SmAccessDenied_NotFound(bool useSecrets, bool accessSecrets, bool organizationEnabled) { var (org, _) = await _organizationHelper.Initialize(useSecrets, accessSecrets, organizationEnabled); - await LoginAsync(_email); + await _loginHelper.LoginAsync(_email); var secret = await _secretRepository.CreateAsync(new Secret { @@ -336,7 +332,7 @@ public class SecretsControllerTests : IClassFixture, IAsy public async Task Get_Success(PermissionType permissionType) { var (org, _) = await _organizationHelper.Initialize(true, true, true); - await LoginAsync(_email); + await _loginHelper.LoginAsync(_email); var project = await _projectRepository.CreateAsync(new Project() { @@ -348,7 +344,7 @@ public class SecretsControllerTests : IClassFixture, IAsy if (permissionType == PermissionType.RunAsUserWithPermission) { var (email, orgUser) = await _organizationHelper.CreateNewUser(OrganizationUserType.User, true); - await LoginAsync(email); + await _loginHelper.LoginAsync(email); var accessPolicies = new List { @@ -361,8 +357,8 @@ public class SecretsControllerTests : IClassFixture, IAsy } else { - var (email, orgUser) = await _organizationHelper.CreateNewUser(OrganizationUserType.Admin, true); - await LoginAsync(email); + var (email, _) = await _organizationHelper.CreateNewUser(OrganizationUserType.Admin, true); + await _loginHelper.LoginAsync(email); } var secret = await _secretRepository.CreateAsync(new Secret @@ -395,7 +391,7 @@ public class SecretsControllerTests : IClassFixture, IAsy public async Task GetSecretsByProject_SmAccessDenied_NotFound(bool useSecrets, bool accessSecrets, bool organizationEnabled) { var (org, _) = await _organizationHelper.Initialize(useSecrets, accessSecrets, organizationEnabled); - await LoginAsync(_email); + await _loginHelper.LoginAsync(_email); var project = await _projectRepository.CreateAsync(new Project { @@ -411,8 +407,8 @@ public class SecretsControllerTests : IClassFixture, IAsy public async Task GetSecretsByProject_UserWithNoPermission_EmptyList() { var (org, _) = await _organizationHelper.Initialize(true, true, true); - var (email, orgUser) = await _organizationHelper.CreateNewUser(OrganizationUserType.User, true); - await LoginAsync(email); + var (email, _) = await _organizationHelper.CreateNewUser(OrganizationUserType.User, true); + await _loginHelper.LoginAsync(email); var project = await _projectRepository.CreateAsync(new Project() { @@ -421,7 +417,7 @@ public class SecretsControllerTests : IClassFixture, IAsy Name = _mockEncryptedString }); - var secret = await _secretRepository.CreateAsync(new Secret + await _secretRepository.CreateAsync(new Secret { OrganizationId = org.Id, Key = _mockEncryptedString, @@ -434,8 +430,8 @@ public class SecretsControllerTests : IClassFixture, IAsy response.EnsureSuccessStatusCode(); var result = await response.Content.ReadFromJsonAsync(); Assert.NotNull(result); - Assert.Empty(result!.Secrets); - Assert.Empty(result!.Projects); + Assert.Empty(result.Secrets); + Assert.Empty(result.Projects); } [Theory] @@ -444,7 +440,7 @@ public class SecretsControllerTests : IClassFixture, IAsy public async Task GetSecretsByProject_Success(PermissionType permissionType) { var (org, _) = await _organizationHelper.Initialize(true, true, true); - await LoginAsync(_email); + await _loginHelper.LoginAsync(_email); var project = await _projectRepository.CreateAsync(new Project() { @@ -456,7 +452,7 @@ public class SecretsControllerTests : IClassFixture, IAsy if (permissionType == PermissionType.RunAsUserWithPermission) { var (email, orgUser) = await _organizationHelper.CreateNewUser(OrganizationUserType.User, true); - await LoginAsync(email); + await _loginHelper.LoginAsync(email); var accessPolicies = new List { @@ -501,7 +497,7 @@ public class SecretsControllerTests : IClassFixture, IAsy public async Task Update_SmAccessDenied_NotFound(bool useSecrets, bool accessSecrets, bool organizationEnabled) { var (org, _) = await _organizationHelper.Initialize(useSecrets, accessSecrets, organizationEnabled); - await LoginAsync(_email); + await _loginHelper.LoginAsync(_email); var secret = await _secretRepository.CreateAsync(new Secret { @@ -525,32 +521,18 @@ public class SecretsControllerTests : IClassFixture, IAsy [Theory] [InlineData(PermissionType.RunAsAdmin)] [InlineData(PermissionType.RunAsUserWithPermission)] + [InlineData(PermissionType.RunAsServiceAccountWithPermission)] public async Task Update_Success(PermissionType permissionType) { var (org, _) = await _organizationHelper.Initialize(true, true, true); - await LoginAsync(_email); - var project = await _projectRepository.CreateAsync(new Project() { - Id = new Guid(), + Id = Guid.NewGuid(), OrganizationId = org.Id, Name = _mockEncryptedString }); - if (permissionType == PermissionType.RunAsUserWithPermission) - { - var (email, orgUser) = await _organizationHelper.CreateNewUser(OrganizationUserType.User, true); - await LoginAsync(email); - - var accessPolicies = new List - { - new UserProjectAccessPolicy - { - GrantedProjectId = project.Id, OrganizationUserId = orgUser.Id, Read = true, Write = true, - }, - }; - await _accessPolicyRepository.CreateManyAsync(accessPolicies); - } + await SetupProjectPermissionAndLoginAsync(permissionType, project); var secret = await _secretRepository.CreateAsync(new Secret { @@ -558,7 +540,7 @@ public class SecretsControllerTests : IClassFixture, IAsy Key = _mockEncryptedString, Value = _mockEncryptedString, Note = _mockEncryptedString, - Projects = permissionType == PermissionType.RunAsUserWithPermission ? new List() { project } : null + Projects = permissionType != PermissionType.RunAsAdmin ? new List() { project } : null }); var request = new SecretUpdateRequestModel() @@ -566,7 +548,7 @@ public class SecretsControllerTests : IClassFixture, IAsy Key = _mockEncryptedString, Value = "2.3Uk+WNBIoU5xzmVFNcoWzz==|1MsPIYuRfdOHfu/0uY6H2Q==|/98xy4wb6pHP1VTZ9JcNCYgQjEUMFPlqJgCwRk1YXKg=", Note = _mockEncryptedString, - ProjectIds = permissionType == PermissionType.RunAsUserWithPermission ? new Guid[] { project.Id } : null + ProjectIds = permissionType != PermissionType.RunAsAdmin ? new Guid[] { project.Id } : null }; var response = await _client.PutAsJsonAsync($"/secrets/{secret.Id}", request); @@ -595,7 +577,7 @@ public class SecretsControllerTests : IClassFixture, IAsy public async Task UpdateWithDifferentProjectOrgId_RunAsAdmin_NotFound() { var (org, _) = await _organizationHelper.Initialize(true, true, true); - await LoginAsync(_email); + await _loginHelper.LoginAsync(_email); var anotherOrg = await _organizationHelper.CreateSmOrganizationAsync(); var project = await _projectRepository.CreateAsync(new Project { Name = "123", OrganizationId = anotherOrg.Id }); @@ -624,7 +606,7 @@ public class SecretsControllerTests : IClassFixture, IAsy public async Task UpdateWithMultipleProjects_BadRequest() { var (org, _) = await _organizationHelper.Initialize(true, true, true); - await LoginAsync(_email); + await _loginHelper.LoginAsync(_email); var projectA = await _projectRepository.CreateAsync(new Project { OrganizationId = org.Id, Name = "123A" }); var projectB = await _projectRepository.CreateAsync(new Project { OrganizationId = org.Id, Name = "123B" }); @@ -660,7 +642,7 @@ public class SecretsControllerTests : IClassFixture, IAsy public async Task Delete_SmAccessDenied_NotFound(bool useSecrets, bool accessSecrets, bool organizationEnabled) { var (org, _) = await _organizationHelper.Initialize(useSecrets, accessSecrets, organizationEnabled); - await LoginAsync(_email); + await _loginHelper.LoginAsync(_email); var secret = await _secretRepository.CreateAsync(new Secret { @@ -680,33 +662,34 @@ public class SecretsControllerTests : IClassFixture, IAsy { var (org, _) = await _organizationHelper.Initialize(true, true, true); var (email, _) = await _organizationHelper.CreateNewUser(OrganizationUserType.User, true); - await LoginAsync(email); + await _loginHelper.LoginAsync(email); - var (_, secretIds) = await CreateSecretsAsync(org.Id, 3); + var (_, secretIds) = await CreateSecretsAsync(org.Id); var response = await _client.PostAsync("/secrets/delete", JsonContent.Create(secretIds)); var results = await response.Content.ReadFromJsonAsync>(); Assert.NotNull(results); Assert.Equal(secretIds.OrderBy(x => x), - results!.Data.Select(x => x.Id).OrderBy(x => x)); + results.Data.Select(x => x.Id).OrderBy(x => x)); Assert.All(results.Data, item => Assert.Equal("access denied", item.Error)); } [Theory] [InlineData(PermissionType.RunAsAdmin)] [InlineData(PermissionType.RunAsUserWithPermission)] + [InlineData(PermissionType.RunAsServiceAccountWithPermission)] public async Task Delete_Success(PermissionType permissionType) { var (org, _) = await _organizationHelper.Initialize(true, true, true); - await LoginAsync(_email); + await _loginHelper.LoginAsync(_email); var (project, secretIds) = await CreateSecretsAsync(org.Id); if (permissionType == PermissionType.RunAsUserWithPermission) { var (email, orgUser) = await _organizationHelper.CreateNewUser(OrganizationUserType.User, true); - await LoginAsync(email); + await _loginHelper.LoginAsync(email); var accessPolicies = new List { @@ -723,8 +706,8 @@ public class SecretsControllerTests : IClassFixture, IAsy var results = await response.Content.ReadFromJsonAsync>(); Assert.NotNull(results?.Data); - Assert.Equal(secretIds.Count, results!.Data.Count()); - foreach (var result in results!.Data) + Assert.Equal(secretIds.Count, results.Data.Count()); + foreach (var result in results.Data) { Assert.Contains(result.Id, secretIds); Assert.Null(result.Error); @@ -745,7 +728,7 @@ public class SecretsControllerTests : IClassFixture, IAsy public async Task GetSecretsByIds_SmAccessDenied_NotFound(bool useSecrets, bool accessSecrets, bool organizationEnabled) { var (org, _) = await _organizationHelper.Initialize(useSecrets, accessSecrets, organizationEnabled); - await LoginAsync(_email); + await _loginHelper.LoginAsync(_email); var secret = await _secretRepository.CreateAsync(new Secret { @@ -767,14 +750,14 @@ public class SecretsControllerTests : IClassFixture, IAsy public async Task GetSecretsByIds_Success(PermissionType permissionType) { var (org, _) = await _organizationHelper.Initialize(true, true, true); - await LoginAsync(_email); + await _loginHelper.LoginAsync(_email); var (project, secretIds) = await CreateSecretsAsync(org.Id); if (permissionType == PermissionType.RunAsUserWithPermission) { var (email, orgUser) = await _organizationHelper.CreateNewUser(OrganizationUserType.User, true); - await LoginAsync(email); + await _loginHelper.LoginAsync(email); var accessPolicies = new List { @@ -788,7 +771,7 @@ public class SecretsControllerTests : IClassFixture, IAsy else { var (email, _) = await _organizationHelper.CreateNewUser(OrganizationUserType.Admin, true); - await LoginAsync(email); + await _loginHelper.LoginAsync(email); } var request = new GetSecretsRequestModel { Ids = secretIds }; @@ -797,8 +780,8 @@ public class SecretsControllerTests : IClassFixture, IAsy response.EnsureSuccessStatusCode(); var result = await response.Content.ReadFromJsonAsync>(); Assert.NotNull(result); - Assert.NotEmpty(result!.Data); - Assert.Equal(secretIds.Count, result!.Data.Count()); + Assert.NotEmpty(result.Data); + Assert.Equal(secretIds.Count, result.Data.Count()); } private async Task<(Project Project, List secretIds)> CreateSecretsAsync(Guid orgId, int numberToCreate = 3) @@ -826,4 +809,48 @@ public class SecretsControllerTests : IClassFixture, IAsy return (project, secretIds); } + + private async Task SetupProjectPermissionAndLoginAsync(PermissionType permissionType, Project project) + { + switch (permissionType) + { + case PermissionType.RunAsAdmin: + { + await _loginHelper.LoginAsync(_email); + break; + } + case PermissionType.RunAsUserWithPermission: + { + var (email, orgUser) = await _organizationHelper.CreateNewUser(OrganizationUserType.User, true); + await _loginHelper.LoginAsync(email); + + var accessPolicies = new List + { + new UserProjectAccessPolicy + { + GrantedProjectId = project.Id, OrganizationUserId = orgUser.Id, Read = true, Write = true, + }, + }; + await _accessPolicyRepository.CreateManyAsync(accessPolicies); + break; + } + case PermissionType.RunAsServiceAccountWithPermission: + { + var apiKeyDetails = await _organizationHelper.CreateNewServiceAccountApiKeyAsync(); + await _loginHelper.LoginWithApiKeyAsync(apiKeyDetails); + + var accessPolicies = new List + { + new ServiceAccountProjectAccessPolicy + { + GrantedProjectId = project.Id, ServiceAccountId = apiKeyDetails.ApiKey.ServiceAccountId, Read = true, Write = true, + }, + }; + await _accessPolicyRepository.CreateManyAsync(accessPolicies); + break; + } + default: + throw new ArgumentOutOfRangeException(nameof(permissionType), permissionType, null); + } + } } diff --git a/test/Api.IntegrationTest/SecretsManager/Controllers/SecretsManagerEventsControllerTests.cs b/test/Api.IntegrationTest/SecretsManager/Controllers/SecretsManagerEventsControllerTests.cs index 4c053c3a2..036e307d3 100644 --- a/test/Api.IntegrationTest/SecretsManager/Controllers/SecretsManagerEventsControllerTests.cs +++ b/test/Api.IntegrationTest/SecretsManager/Controllers/SecretsManagerEventsControllerTests.cs @@ -1,6 +1,7 @@ using System.Net; using System.Net.Http.Headers; using Bit.Api.IntegrationTest.Factories; +using Bit.Api.IntegrationTest.SecretsManager.Helpers; using Bit.Core.SecretsManager.Entities; using Bit.Core.SecretsManager.Repositories; using Xunit; diff --git a/test/Api.IntegrationTest/SecretsManager/Controllers/SecretsManagerPortingControllerTests.cs b/test/Api.IntegrationTest/SecretsManager/Controllers/SecretsManagerPortingControllerTests.cs index c57ceb20d..ba41c1e86 100644 --- a/test/Api.IntegrationTest/SecretsManager/Controllers/SecretsManagerPortingControllerTests.cs +++ b/test/Api.IntegrationTest/SecretsManager/Controllers/SecretsManagerPortingControllerTests.cs @@ -1,8 +1,7 @@ using System.Net; -using System.Net.Http.Headers; using Bit.Api.IntegrationTest.Factories; +using Bit.Api.IntegrationTest.SecretsManager.Helpers; using Bit.Api.SecretsManager.Models.Request; -using Bit.Core.SecretsManager.Repositories; using Xunit; namespace Bit.Api.IntegrationTest.SecretsManager.Controllers; @@ -11,8 +10,7 @@ public class SecretsManagerPortingControllerTests : IClassFixture(); - _accessPolicyRepository = _factory.GetService(); + _loginHelper = new LoginHelper(_factory, _client); } public async Task InitializeAsync() @@ -38,12 +35,6 @@ public class SecretsManagerPortingControllerTests : IClassFixture(); var secretsList = new List(); @@ -76,7 +67,7 @@ public class SecretsManagerPortingControllerTests : IClassFixture, private readonly HttpClient _client; private readonly ApiApplicationFactory _factory; private readonly ISecretRepository _secretRepository; + private readonly LoginHelper _loginHelper; private string _email = null!; private SecretsManagerOrganizationHelper _organizationHelper = null!; @@ -26,6 +27,7 @@ public class SecretsTrashControllerTests : IClassFixture, _factory = factory; _client = _factory.CreateClient(); _secretRepository = _factory.GetService(); + _loginHelper = new LoginHelper(_factory, _client); } public async Task InitializeAsync() @@ -41,12 +43,6 @@ public class SecretsTrashControllerTests : IClassFixture, return Task.CompletedTask; } - private async Task LoginAsync(string email) - { - var tokens = await _factory.LoginAsync(email); - _client.DefaultRequestHeaders.Authorization = new AuthenticationHeaderValue("Bearer", tokens.Token); - } - [Theory] [InlineData(false, false, false)] [InlineData(false, false, true)] @@ -58,7 +54,7 @@ public class SecretsTrashControllerTests : IClassFixture, public async Task ListByOrganization_SmAccessDenied_NotFound(bool useSecrets, bool accessSecrets, bool organizationEnabled) { var (org, _) = await _organizationHelper.Initialize(useSecrets, accessSecrets, organizationEnabled); - await LoginAsync(_email); + await _loginHelper.LoginAsync(_email); var response = await _client.GetAsync($"/secrets/{org.Id}/trash"); Assert.Equal(HttpStatusCode.NotFound, response.StatusCode); @@ -69,7 +65,7 @@ public class SecretsTrashControllerTests : IClassFixture, { var (org, _) = await _organizationHelper.Initialize(true, true, true); var (email, _) = await _organizationHelper.CreateNewUser(OrganizationUserType.User, true); - await LoginAsync(email); + await _loginHelper.LoginAsync(email); var response = await _client.GetAsync($"/secrets/{org.Id}/trash"); Assert.Equal(HttpStatusCode.Unauthorized, response.StatusCode); @@ -79,7 +75,7 @@ public class SecretsTrashControllerTests : IClassFixture, public async Task ListByOrganization_Success() { var (org, _) = await _organizationHelper.Initialize(true, true, true); - await LoginAsync(_email); + await _loginHelper.LoginAsync(_email); await _secretRepository.CreateAsync(new Secret { @@ -114,7 +110,7 @@ public class SecretsTrashControllerTests : IClassFixture, public async Task Empty_SmAccessDenied_NotFound(bool useSecrets, bool accessSecrets, bool organizationEnabled) { var (org, _) = await _organizationHelper.Initialize(useSecrets, accessSecrets, organizationEnabled); - await LoginAsync(_email); + await _loginHelper.LoginAsync(_email); var ids = new List { Guid.NewGuid() }; var response = await _client.PostAsJsonAsync($"/secrets/{org.Id}/trash/empty", ids); @@ -126,7 +122,7 @@ public class SecretsTrashControllerTests : IClassFixture, { var (org, _) = await _organizationHelper.Initialize(true, true, true); var (email, _) = await _organizationHelper.CreateNewUser(OrganizationUserType.User, true); - await LoginAsync(email); + await _loginHelper.LoginAsync(email); var ids = new List { Guid.NewGuid() }; var response = await _client.PostAsJsonAsync($"/secrets/{org.Id}/trash/empty", ids); @@ -137,7 +133,7 @@ public class SecretsTrashControllerTests : IClassFixture, public async Task Empty_Invalid_NotFound() { var (org, _) = await _organizationHelper.Initialize(true, true, true); - await LoginAsync(_email); + await _loginHelper.LoginAsync(_email); var secret = await _secretRepository.CreateAsync(new Secret { @@ -155,7 +151,7 @@ public class SecretsTrashControllerTests : IClassFixture, public async Task Empty_Success() { var (org, _) = await _organizationHelper.Initialize(true, true, true); - await LoginAsync(_email); + await _loginHelper.LoginAsync(_email); var secret = await _secretRepository.CreateAsync(new Secret { @@ -181,7 +177,7 @@ public class SecretsTrashControllerTests : IClassFixture, public async Task Restore_SmAccessDenied_NotFound(bool useSecrets, bool accessSecrets, bool organizationEnabled) { var (org, _) = await _organizationHelper.Initialize(useSecrets, accessSecrets, organizationEnabled); - await LoginAsync(_email); + await _loginHelper.LoginAsync(_email); var ids = new List { Guid.NewGuid() }; var response = await _client.PostAsJsonAsync($"/secrets/{org.Id}/trash/restore", ids); @@ -193,7 +189,7 @@ public class SecretsTrashControllerTests : IClassFixture, { var (org, _) = await _organizationHelper.Initialize(true, true, true); var (email, _) = await _organizationHelper.CreateNewUser(OrganizationUserType.User, true); - await LoginAsync(email); + await _loginHelper.LoginAsync(email); var ids = new List { Guid.NewGuid() }; var response = await _client.PostAsJsonAsync($"/secrets/{org.Id}/trash/restore", ids); @@ -204,7 +200,7 @@ public class SecretsTrashControllerTests : IClassFixture, public async Task Restore_Invalid_NotFound() { var (org, _) = await _organizationHelper.Initialize(true, true, true); - await LoginAsync(_email); + await _loginHelper.LoginAsync(_email); var secret = await _secretRepository.CreateAsync(new Secret { @@ -222,7 +218,7 @@ public class SecretsTrashControllerTests : IClassFixture, public async Task Restore_Success() { var (org, _) = await _organizationHelper.Initialize(true, true, true); - await LoginAsync(_email); + await _loginHelper.LoginAsync(_email); var secret = await _secretRepository.CreateAsync(new Secret { diff --git a/test/Api.IntegrationTest/SecretsManager/Controllers/ServiceAccountsControllerTests.cs b/test/Api.IntegrationTest/SecretsManager/Controllers/ServiceAccountsControllerTests.cs index a482d9b04..f25005b26 100644 --- a/test/Api.IntegrationTest/SecretsManager/Controllers/ServiceAccountsControllerTests.cs +++ b/test/Api.IntegrationTest/SecretsManager/Controllers/ServiceAccountsControllerTests.cs @@ -1,7 +1,7 @@ using System.Net; -using System.Net.Http.Headers; using Bit.Api.IntegrationTest.Factories; using Bit.Api.IntegrationTest.SecretsManager.Enums; +using Bit.Api.IntegrationTest.SecretsManager.Helpers; using Bit.Api.Models.Response; using Bit.Api.SecretsManager.Models.Request; using Bit.Api.SecretsManager.Models.Response; @@ -24,6 +24,7 @@ public class ServiceAccountsControllerTests : IClassFixture(); _accessPolicyRepository = _factory.GetService(); _apiKeyRepository = _factory.GetService(); + _loginHelper = new LoginHelper(_factory, _client); } public async Task InitializeAsync() @@ -54,12 +56,6 @@ public class ServiceAccountsControllerTests : IClassFixture>(); Assert.NotNull(result); - Assert.NotEmpty(result!.Data); + Assert.NotEmpty(result.Data); Assert.Equal(serviceAccountIds.Count, result.Data.Count()); } @@ -99,7 +95,7 @@ public class ServiceAccountsControllerTests : IClassFixture>(); Assert.NotNull(result); - Assert.NotEmpty(result!.Data); + Assert.NotEmpty(result.Data); Assert.Equal(2, result.Data.Count()); } @@ -135,7 +131,7 @@ public class ServiceAccountsControllerTests : IClassFixture(); Assert.NotNull(result); - Assert.Equal(serviceAccount.Id, result!.Id); + Assert.Equal(serviceAccount.Id, result.Id); Assert.Equal(serviceAccount.OrganizationId, result.OrganizationId); Assert.Equal(serviceAccount.Name, result.Name); Assert.Equal(serviceAccount.CreationDate, result.CreationDate); @@ -203,7 +199,7 @@ public class ServiceAccountsControllerTests : IClassFixture(); Assert.NotNull(result); - Assert.Equal(request.Name, result!.Name); + Assert.Equal(request.Name, result.Name); AssertHelper.AssertRecent(result.RevisionDate); AssertHelper.AssertRecent(result.CreationDate); @@ -270,7 +266,7 @@ public class ServiceAccountsControllerTests : IClassFixture(); Assert.NotNull(result); - Assert.Equal(request.Name, result!.Name); + Assert.Equal(request.Name, result.Name); Assert.NotEqual(initialServiceAccount.Name, result.Name); AssertHelper.AssertRecent(result.RevisionDate); Assert.NotEqual(initialServiceAccount.RevisionDate, result.RevisionDate); @@ -353,7 +349,7 @@ public class ServiceAccountsControllerTests : IClassFixture { new UserServiceAccountAccessPolicy @@ -443,7 +439,7 @@ public class ServiceAccountsControllerTests : IClassFixture { new UserServiceAccountAccessPolicy @@ -540,7 +536,7 @@ public class ServiceAccountsControllerTests : IClassFixture(); Assert.NotNull(result); - Assert.Equal(request.Name, result!.Name); + Assert.Equal(request.Name, result.Name); Assert.NotNull(result.ClientSecret); Assert.Equal(mockExpiresAt, result.ExpireAt); AssertHelper.AssertRecent(result.RevisionDate); @@ -599,7 +595,7 @@ public class ServiceAccountsControllerTests : IClassFixture(); Assert.NotNull(result); - Assert.Equal(request.Name, result!.Name); + Assert.Equal(request.Name, result.Name); Assert.NotNull(result.ClientSecret); Assert.Equal(mockExpiresAt, result.ExpireAt); AssertHelper.AssertRecent(result.RevisionDate); @@ -635,7 +631,7 @@ public class ServiceAccountsControllerTests : IClassFixture(); Assert.NotNull(result); - Assert.Equal(request.Name, result!.Name); + Assert.Equal(request.Name, result.Name); Assert.NotNull(result.ClientSecret); Assert.Null(result.ExpireAt); AssertHelper.AssertRecent(result.RevisionDate); @@ -699,7 +695,7 @@ public class ServiceAccountsControllerTests : IClassFixture { new UserServiceAccountAccessPolicy @@ -847,7 +843,7 @@ public class ServiceAccountsControllerTests : IClassFixture SetupServiceAccountWithAccessAsync(PermissionType permissionType) { var (org, _) = await _organizationHelper.Initialize(true, true, true); - await LoginAsync(_email); + await _loginHelper.LoginAsync(_email); var initialServiceAccount = await _serviceAccountRepository.CreateAsync(new ServiceAccount { @@ -861,7 +857,7 @@ public class ServiceAccountsControllerTests : IClassFixture { diff --git a/test/Api.IntegrationTest/SecretsManager/Enums/PermissionType.cs b/test/Api.IntegrationTest/SecretsManager/Enums/PermissionType.cs index 7f1c4d7b9..972bc7f0b 100644 --- a/test/Api.IntegrationTest/SecretsManager/Enums/PermissionType.cs +++ b/test/Api.IntegrationTest/SecretsManager/Enums/PermissionType.cs @@ -4,4 +4,5 @@ public enum PermissionType { RunAsAdmin, RunAsUserWithPermission, + RunAsServiceAccountWithPermission, } diff --git a/test/Api.IntegrationTest/SecretsManager/Helpers/LoginHelper.cs b/test/Api.IntegrationTest/SecretsManager/Helpers/LoginHelper.cs new file mode 100644 index 000000000..9de66bc11 --- /dev/null +++ b/test/Api.IntegrationTest/SecretsManager/Helpers/LoginHelper.cs @@ -0,0 +1,30 @@ +using System.Net.Http.Headers; +using Bit.Api.IntegrationTest.Factories; +using Bit.Core.SecretsManager.Models.Data; + +namespace Bit.Api.IntegrationTest.SecretsManager.Helpers; + +public class LoginHelper +{ + private readonly HttpClient _client; + private readonly ApiApplicationFactory _factory; + + public LoginHelper(ApiApplicationFactory factory, HttpClient client) + { + _factory = factory; + _client = client; + } + + public async Task LoginAsync(string email) + { + var tokens = await _factory.LoginAsync(email); + _client.DefaultRequestHeaders.Authorization = new AuthenticationHeaderValue("Bearer", tokens.Token); + } + + public async Task LoginWithApiKeyAsync(ApiKeyClientSecretDetails apiKeyDetails) + { + var token = await _factory.LoginWithClientSecretAsync(apiKeyDetails.ApiKey.Id, apiKeyDetails.ClientSecret); + _client.DefaultRequestHeaders.Authorization = new AuthenticationHeaderValue("Bearer", token); + _client.DefaultRequestHeaders.Add("service_account_id", apiKeyDetails.ApiKey.ServiceAccountId.ToString()); + } +} diff --git a/test/Api.IntegrationTest/SecretsManager/SecretsManagerOrganizationHelper.cs b/test/Api.IntegrationTest/SecretsManager/Helpers/SecretsManagerOrganizationHelper.cs similarity index 58% rename from test/Api.IntegrationTest/SecretsManager/SecretsManagerOrganizationHelper.cs rename to test/Api.IntegrationTest/SecretsManager/Helpers/SecretsManagerOrganizationHelper.cs index fea05de31..d2d03d979 100644 --- a/test/Api.IntegrationTest/SecretsManager/SecretsManagerOrganizationHelper.cs +++ b/test/Api.IntegrationTest/SecretsManager/Helpers/SecretsManagerOrganizationHelper.cs @@ -4,8 +4,12 @@ using Bit.Core.AdminConsole.Entities; using Bit.Core.Entities; using Bit.Core.Enums; using Bit.Core.Repositories; +using Bit.Core.SecretsManager.Commands.AccessTokens.Interfaces; +using Bit.Core.SecretsManager.Entities; +using Bit.Core.SecretsManager.Models.Data; +using Bit.Core.SecretsManager.Repositories; -namespace Bit.Api.IntegrationTest.SecretsManager; +namespace Bit.Api.IntegrationTest.SecretsManager.Helpers; public class SecretsManagerOrganizationHelper { @@ -13,17 +17,20 @@ public class SecretsManagerOrganizationHelper private readonly string _ownerEmail; private readonly IOrganizationRepository _organizationRepository; private readonly IOrganizationUserRepository _organizationUserRepository; + private readonly IServiceAccountRepository _serviceAccountRepository; + private readonly ICreateAccessTokenCommand _createAccessTokenCommand; - public Organization _organization = null!; - public OrganizationUser _owner = null!; + private Organization _organization = null!; + private OrganizationUser _owner = null!; public SecretsManagerOrganizationHelper(ApiApplicationFactory factory, string ownerEmail) { _factory = factory; _organizationRepository = factory.GetService(); _organizationUserRepository = factory.GetService(); - _ownerEmail = ownerEmail; + _serviceAccountRepository = factory.GetService(); + _createAccessTokenCommand = factory.GetService(); } public async Task<(Organization organization, OrganizationUser owner)> Initialize(bool useSecrets, bool ownerAccessSecrets, bool organizationEnabled) @@ -58,8 +65,7 @@ public class SecretsManagerOrganizationHelper { var email = $"integration-test{Guid.NewGuid()}@bitwarden.com"; await _factory.LoginWithNewAccount(email); - var (organization, owner) = - await OrganizationTestHelpers.SignUpAsync(_factory, ownerEmail: email, billingEmail: email); + var (organization, _) = await OrganizationTestHelpers.SignUpAsync(_factory, ownerEmail: email, billingEmail: email); return organization; } @@ -71,4 +77,29 @@ public class SecretsManagerOrganizationHelper return (email, orgUser); } + + public async Task CreateNewServiceAccountApiKeyAsync() + { + var serviceAccountId = Guid.NewGuid(); + var serviceAccount = new ServiceAccount + { + Id = serviceAccountId, + OrganizationId = _organization.Id, + Name = $"integration-test-{serviceAccountId}sa", + CreationDate = DateTime.UtcNow, + RevisionDate = DateTime.UtcNow + }; + await _serviceAccountRepository.CreateAsync(serviceAccount); + + var apiKey = new ApiKey + { + ServiceAccountId = serviceAccountId, + Name = "integration-token", + Key = Guid.NewGuid().ToString(), + ExpireAt = null, + Scope = "[\"api.secrets\"]", + EncryptedPayload = Guid.NewGuid().ToString() + }; + return await _createAccessTokenCommand.CreateAsync(apiKey); + } } diff --git a/test/IntegrationTestCommon/Factories/IdentityApplicationFactory.cs b/test/IntegrationTestCommon/Factories/IdentityApplicationFactory.cs index def8f5c14..2dc23056d 100644 --- a/test/IntegrationTestCommon/Factories/IdentityApplicationFactory.cs +++ b/test/IntegrationTestCommon/Factories/IdentityApplicationFactory.cs @@ -42,4 +42,23 @@ public class IdentityApplicationFactory : WebApplicationFactoryBase return (root.GetProperty("access_token").GetString(), root.GetProperty("refresh_token").GetString()); } + + public async Task TokenFromAccessTokenAsync(Guid clientId, string clientSecret, + DeviceType deviceType = DeviceType.SDK) + { + var context = await Server.PostAsync("/connect/token", + new FormUrlEncodedContent(new Dictionary + { + { "scope", "api.secrets" }, + { "client_id", clientId.ToString() }, + { "client_secret", clientSecret }, + { "grant_type", "client_credentials" }, + { "deviceType", ((int)deviceType).ToString() } + })); + + using var body = await AssertHelper.AssertResponseTypeIs(context); + var root = body.RootElement; + + return root.GetProperty("access_token").GetString(); + } }