diff --git a/src/Core/Services/Implementations/LaunchDarklyFeatureService.cs b/src/Core/Services/Implementations/LaunchDarklyFeatureService.cs index dac309a1f..b73d398d3 100644 --- a/src/Core/Services/Implementations/LaunchDarklyFeatureService.cs +++ b/src/Core/Services/Implementations/LaunchDarklyFeatureService.cs @@ -104,18 +104,42 @@ public class LaunchDarklyFeatureService : IFeatureService, IDisposable { var builder = LaunchDarkly.Sdk.Context.MultiBuilder(); - if (currentContext.UserId.HasValue) + switch (currentContext.ClientType) { - var user = LaunchDarkly.Sdk.Context.Builder(currentContext.UserId.Value.ToString()); - user.Kind(LaunchDarkly.Sdk.ContextKind.Default); - builder.Add(user.Build()); - } + case Identity.ClientType.User: + { + var ldUser = LaunchDarkly.Sdk.Context.Builder(currentContext.UserId.Value.ToString()); + ldUser.Kind(LaunchDarkly.Sdk.ContextKind.Default); - if (currentContext.OrganizationId.HasValue) - { - var org = LaunchDarkly.Sdk.Context.Builder(currentContext.OrganizationId.Value.ToString()); - org.Kind("org"); - builder.Add(org.Build()); + if (currentContext.Organizations?.Any() ?? false) + { + var ldOrgs = currentContext.Organizations.Select(o => LaunchDarkly.Sdk.LdValue.Of(o.Id.ToString())); + ldUser.Set("organizations", LaunchDarkly.Sdk.LdValue.ArrayFrom(ldOrgs)); + } + + builder.Add(ldUser.Build()); + } + break; + + case Identity.ClientType.Organization: + { + var ldOrg = LaunchDarkly.Sdk.Context.Builder(currentContext.OrganizationId.Value.ToString()); + ldOrg.Kind("organization"); + builder.Add(ldOrg.Build()); + } + break; + + case Identity.ClientType.ServiceAccount: + { + var ldServiceAccount = LaunchDarkly.Sdk.Context.Builder(currentContext.UserId.Value.ToString()); + ldServiceAccount.Kind("service-account"); + builder.Add(ldServiceAccount.Build()); + + var ldOrg = LaunchDarkly.Sdk.Context.Builder(currentContext.OrganizationId.Value.ToString()); + ldOrg.Kind("organization"); + builder.Add(ldOrg.Build()); + } + break; } return builder.Build(); diff --git a/test/Api.IntegrationTest/Controllers/ConfigControllerTests.cs b/test/Api.IntegrationTest/Controllers/ConfigControllerTests.cs index bafd7dcb5..12acca667 100644 --- a/test/Api.IntegrationTest/Controllers/ConfigControllerTests.cs +++ b/test/Api.IntegrationTest/Controllers/ConfigControllerTests.cs @@ -1,30 +1,79 @@ using System.Net.Http.Headers; using Bit.Api.IntegrationTest.Factories; +using Bit.Api.IntegrationTest.Helpers; using Bit.Api.Models.Response; +using Bit.Core.Entities; using Xunit; namespace Bit.Api.IntegrationTest.Controllers; -public class ConfigControllerTests : IClassFixture +public class ConfigControllerTests : IClassFixture, IAsyncLifetime { + private readonly HttpClient _client; private readonly ApiApplicationFactory _factory; - public ConfigControllerTests(ApiApplicationFactory factory) => _factory = factory; + private string _email = null!; + + public ConfigControllerTests(ApiApplicationFactory factory) + { + _factory = factory; + _client = _factory.CreateClient(); + } + + public async Task InitializeAsync() + { + _email = $"integration-test{Guid.NewGuid()}@bitwarden.com"; + + var tokens = await _factory.LoginWithNewAccount(_email); + _client.DefaultRequestHeaders.Authorization = new AuthenticationHeaderValue("Bearer", tokens.Token); + } + + public Task DisposeAsync() + { + _client.Dispose(); + return Task.CompletedTask; + } + + private async Task LoginAsync() + { + var tokens = await _factory.LoginAsync(_email); + _client.DefaultRequestHeaders.Authorization = new AuthenticationHeaderValue("Bearer", tokens.Token); + } [Fact] public async Task GetConfigs() { - var tokens = await _factory.LoginWithNewAccount(); - var client = _factory.CreateClient(); - - using var message = new HttpRequestMessage(HttpMethod.Get, "/config"); - message.Headers.Authorization = new AuthenticationHeaderValue("Bearer", tokens.Token); - var response = await client.SendAsync(message); - + var response = await _client.GetAsync("/config"); response.EnsureSuccessStatusCode(); + var result = await response.Content.ReadFromJsonAsync(); - var content = await response.Content.ReadFromJsonAsync(); + Assert.NotNull(result); + Assert.NotEmpty(result!.Version); + } - Assert.NotEmpty(content!.Version); + [Theory] + [InlineData(1)] + [InlineData(3)] + public async Task GetConfigs_WithOrganizations(int orgCount) + { + for (var i = 0; i < orgCount; i++) + { + var ownerEmail = $"integration-test{Guid.NewGuid()}@bitwarden.com"; + await _factory.LoginWithNewAccount(ownerEmail); + + Organization org; + (org, _) = await OrganizationTestHelpers.SignUpAsync(_factory, plan: Core.Enums.PlanType.Free, ownerEmail: ownerEmail, + name: i.ToString(), billingEmail: ownerEmail, ownerKey: i.ToString()); + await OrganizationTestHelpers.CreateUserAsync(_factory, org.Id, _email, Core.Enums.OrganizationUserType.User); + } + + await LoginAsync(); + + var response = await _client.GetAsync("/config"); + response.EnsureSuccessStatusCode(); + var result = await response.Content.ReadFromJsonAsync(); + + Assert.NotNull(result); + Assert.NotEmpty(result!.Version); } }