From 39f884ddcc29b1bd0ceb2adc92af146448f51622 Mon Sep 17 00:00:00 2001 From: Matt Bishop Date: Wed, 22 Mar 2023 11:05:09 -0400 Subject: [PATCH] Provide anonymous user context for unauthenticated requests using LaunchDarkly (#2819) --- .../LaunchDarklyFeatureService.cs | 41 ++++++++++++++----- .../Controllers/ConfigControllerTests.cs | 17 +++++++- 2 files changed, 47 insertions(+), 11 deletions(-) diff --git a/src/Core/Services/Implementations/LaunchDarklyFeatureService.cs b/src/Core/Services/Implementations/LaunchDarklyFeatureService.cs index b73d398d3..b3ac5bc62 100644 --- a/src/Core/Services/Implementations/LaunchDarklyFeatureService.cs +++ b/src/Core/Services/Implementations/LaunchDarklyFeatureService.cs @@ -8,6 +8,7 @@ namespace Bit.Core.Services; public class LaunchDarklyFeatureService : IFeatureService, IDisposable { private readonly LdClient _client; + private const string _anonymousUser = "25a15cac-58cf-4ac0-ad0f-b17c4bd92294"; public LaunchDarklyFeatureService( IGlobalSettings globalSettings) @@ -108,7 +109,18 @@ public class LaunchDarklyFeatureService : IFeatureService, IDisposable { case Identity.ClientType.User: { - var ldUser = LaunchDarkly.Sdk.Context.Builder(currentContext.UserId.Value.ToString()); + LaunchDarkly.Sdk.ContextBuilder ldUser; + if (currentContext.UserId.HasValue) + { + ldUser = LaunchDarkly.Sdk.Context.Builder(currentContext.UserId.Value.ToString()); + } + else + { + // group all unauthenticated activity under one anonymous user key and mark as such + ldUser = LaunchDarkly.Sdk.Context.Builder(_anonymousUser); + ldUser.Anonymous(true); + } + ldUser.Kind(LaunchDarkly.Sdk.ContextKind.Default); if (currentContext.Organizations?.Any() ?? false) @@ -123,21 +135,30 @@ public class LaunchDarklyFeatureService : IFeatureService, IDisposable case Identity.ClientType.Organization: { - var ldOrg = LaunchDarkly.Sdk.Context.Builder(currentContext.OrganizationId.Value.ToString()); - ldOrg.Kind("organization"); - builder.Add(ldOrg.Build()); + if (currentContext.OrganizationId.HasValue) + { + 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()); + if (currentContext.UserId.HasValue) + { + 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()); + if (currentContext.OrganizationId.HasValue) + { + var ldOrg = LaunchDarkly.Sdk.Context.Builder(currentContext.OrganizationId.Value.ToString()); + ldOrg.Kind("organization"); + builder.Add(ldOrg.Build()); + } } break; } diff --git a/test/Api.IntegrationTest/Controllers/ConfigControllerTests.cs b/test/Api.IntegrationTest/Controllers/ConfigControllerTests.cs index 12acca667..22c739839 100644 --- a/test/Api.IntegrationTest/Controllers/ConfigControllerTests.cs +++ b/test/Api.IntegrationTest/Controllers/ConfigControllerTests.cs @@ -41,8 +41,23 @@ public class ConfigControllerTests : IClassFixture, IAsyn } [Fact] - public async Task GetConfigs() + public async Task GetConfigs_Unauthenticated() { + _client.DefaultRequestHeaders.Authorization = null; + + var response = await _client.GetAsync("/config"); + response.EnsureSuccessStatusCode(); + var result = await response.Content.ReadFromJsonAsync(); + + Assert.NotNull(result); + Assert.NotEmpty(result!.Version); + } + + [Fact] + public async Task GetConfigs_Authenticated() + { + await LoginAsync(); + var response = await _client.GetAsync("/config"); response.EnsureSuccessStatusCode(); var result = await response.Content.ReadFromJsonAsync();