mirror of
https://github.com/bitwarden/server.git
synced 2024-11-25 12:45:18 +01:00
Establish IFeatureService as scoped (#3679)
* Establish IFeatureService as scoped * Lint * Feedback around injection
This commit is contained in:
parent
cd006f3779
commit
974d23efdd
@ -27,7 +27,7 @@ public class UsersController : Controller
|
||||
private readonly IFeatureService _featureService;
|
||||
|
||||
private bool UseFlexibleCollections =>
|
||||
_featureService.IsEnabled(FeatureFlagKeys.FlexibleCollections, _currentContext);
|
||||
_featureService.IsEnabled(FeatureFlagKeys.FlexibleCollections);
|
||||
|
||||
public UsersController(
|
||||
IUserRepository userRepository,
|
||||
|
@ -37,7 +37,6 @@ public class GroupsController : Controller
|
||||
ICreateGroupCommand createGroupCommand,
|
||||
IUpdateGroupCommand updateGroupCommand,
|
||||
IDeleteGroupCommand deleteGroupCommand,
|
||||
IFeatureService featureService,
|
||||
IAuthorizationService authorizationService,
|
||||
IApplicationCacheService applicationCacheService)
|
||||
{
|
||||
|
@ -803,7 +803,7 @@ public class OrganizationsController : Controller
|
||||
throw new BadRequestException("Organization does not have collection enhancements enabled");
|
||||
}
|
||||
|
||||
var v1Enabled = _featureService.IsEnabled(FeatureFlagKeys.FlexibleCollectionsV1, _currentContext);
|
||||
var v1Enabled = _featureService.IsEnabled(FeatureFlagKeys.FlexibleCollectionsV1);
|
||||
|
||||
if (!v1Enabled)
|
||||
{
|
||||
|
@ -21,7 +21,6 @@ using Bit.Core.Auth.Services;
|
||||
using Bit.Core.Auth.UserFeatures.UserKey;
|
||||
using Bit.Core.Auth.UserFeatures.UserMasterPassword.Interfaces;
|
||||
using Bit.Core.Auth.Utilities;
|
||||
using Bit.Core.Context;
|
||||
using Bit.Core.Entities;
|
||||
using Bit.Core.Enums;
|
||||
using Bit.Core.Exceptions;
|
||||
@ -63,10 +62,9 @@ public class AccountsController : Controller
|
||||
private readonly ISetInitialMasterPasswordCommand _setInitialMasterPasswordCommand;
|
||||
private readonly IRotateUserKeyCommand _rotateUserKeyCommand;
|
||||
private readonly IFeatureService _featureService;
|
||||
private readonly ICurrentContext _currentContext;
|
||||
|
||||
private bool UseFlexibleCollections =>
|
||||
_featureService.IsEnabled(FeatureFlagKeys.FlexibleCollections, _currentContext);
|
||||
_featureService.IsEnabled(FeatureFlagKeys.FlexibleCollections);
|
||||
|
||||
private readonly IRotationValidator<IEnumerable<CipherWithIdRequestModel>, IEnumerable<Cipher>> _cipherValidator;
|
||||
private readonly IRotationValidator<IEnumerable<FolderWithIdRequestModel>, IEnumerable<Folder>> _folderValidator;
|
||||
@ -95,7 +93,6 @@ public class AccountsController : Controller
|
||||
ISetInitialMasterPasswordCommand setInitialMasterPasswordCommand,
|
||||
IRotateUserKeyCommand rotateUserKeyCommand,
|
||||
IFeatureService featureService,
|
||||
ICurrentContext currentContext,
|
||||
IRotationValidator<IEnumerable<CipherWithIdRequestModel>, IEnumerable<Cipher>> cipherValidator,
|
||||
IRotationValidator<IEnumerable<FolderWithIdRequestModel>, IEnumerable<Folder>> folderValidator,
|
||||
IRotationValidator<IEnumerable<SendWithIdRequestModel>, IReadOnlyList<Send>> sendValidator,
|
||||
@ -121,7 +118,6 @@ public class AccountsController : Controller
|
||||
_setInitialMasterPasswordCommand = setInitialMasterPasswordCommand;
|
||||
_rotateUserKeyCommand = rotateUserKeyCommand;
|
||||
_featureService = featureService;
|
||||
_currentContext = currentContext;
|
||||
_cipherValidator = cipherValidator;
|
||||
_folderValidator = folderValidator;
|
||||
_sendValidator = sendValidator;
|
||||
@ -425,7 +421,7 @@ public class AccountsController : Controller
|
||||
}
|
||||
|
||||
IdentityResult result;
|
||||
if (_featureService.IsEnabled(FeatureFlagKeys.KeyRotationImprovements, _currentContext))
|
||||
if (_featureService.IsEnabled(FeatureFlagKeys.KeyRotationImprovements))
|
||||
{
|
||||
var dataModel = new RotateUserKeyData
|
||||
{
|
||||
|
@ -1,5 +1,4 @@
|
||||
using Bit.Api.Models.Response;
|
||||
using Bit.Core.Context;
|
||||
using Bit.Core.Services;
|
||||
using Bit.Core.Settings;
|
||||
|
||||
@ -11,22 +10,19 @@ namespace Bit.Api.Controllers;
|
||||
public class ConfigController : Controller
|
||||
{
|
||||
private readonly IGlobalSettings _globalSettings;
|
||||
private readonly ICurrentContext _currentContext;
|
||||
private readonly IFeatureService _featureService;
|
||||
|
||||
public ConfigController(
|
||||
IGlobalSettings globalSettings,
|
||||
ICurrentContext currentContext,
|
||||
IFeatureService featureService)
|
||||
{
|
||||
_globalSettings = globalSettings;
|
||||
_currentContext = currentContext;
|
||||
_featureService = featureService;
|
||||
}
|
||||
|
||||
[HttpGet("")]
|
||||
public ConfigResponseModel GetConfigs()
|
||||
{
|
||||
return new ConfigResponseModel(_globalSettings, _featureService.GetAll(_currentContext));
|
||||
return new ConfigResponseModel(_globalSettings, _featureService.GetAll());
|
||||
}
|
||||
}
|
||||
|
@ -43,7 +43,7 @@ public class CiphersController : Controller
|
||||
private readonly IFeatureService _featureService;
|
||||
|
||||
private bool UseFlexibleCollections =>
|
||||
_featureService.IsEnabled(FeatureFlagKeys.FlexibleCollections, _currentContext);
|
||||
_featureService.IsEnabled(FeatureFlagKeys.FlexibleCollections);
|
||||
|
||||
public CiphersController(
|
||||
ICipherRepository cipherRepository,
|
||||
|
@ -3,7 +3,6 @@ using Bit.Core;
|
||||
using Bit.Core.AdminConsole.Entities;
|
||||
using Bit.Core.AdminConsole.Enums.Provider;
|
||||
using Bit.Core.AdminConsole.Repositories;
|
||||
using Bit.Core.Context;
|
||||
using Bit.Core.Entities;
|
||||
using Bit.Core.Enums;
|
||||
using Bit.Core.Exceptions;
|
||||
@ -32,11 +31,10 @@ public class SyncController : Controller
|
||||
private readonly IPolicyRepository _policyRepository;
|
||||
private readonly ISendRepository _sendRepository;
|
||||
private readonly GlobalSettings _globalSettings;
|
||||
private readonly ICurrentContext _currentContext;
|
||||
private readonly IFeatureService _featureService;
|
||||
|
||||
private bool UseFlexibleCollections =>
|
||||
_featureService.IsEnabled(FeatureFlagKeys.FlexibleCollections, _currentContext);
|
||||
_featureService.IsEnabled(FeatureFlagKeys.FlexibleCollections);
|
||||
|
||||
public SyncController(
|
||||
IUserService userService,
|
||||
@ -49,7 +47,6 @@ public class SyncController : Controller
|
||||
IPolicyRepository policyRepository,
|
||||
ISendRepository sendRepository,
|
||||
GlobalSettings globalSettings,
|
||||
ICurrentContext currentContext,
|
||||
IFeatureService featureService)
|
||||
{
|
||||
_userService = userService;
|
||||
@ -62,7 +59,6 @@ public class SyncController : Controller
|
||||
_policyRepository = policyRepository;
|
||||
_sendRepository = sendRepository;
|
||||
_globalSettings = globalSettings;
|
||||
_currentContext = currentContext;
|
||||
_featureService = featureService;
|
||||
}
|
||||
|
||||
|
@ -1,7 +1,6 @@
|
||||
using Bit.Api.Auth.Validators;
|
||||
using Bit.Api.Vault.Models.Request;
|
||||
using Bit.Core;
|
||||
using Bit.Core.Context;
|
||||
using Bit.Core.Entities;
|
||||
using Bit.Core.Exceptions;
|
||||
using Bit.Core.Services;
|
||||
@ -13,19 +12,15 @@ namespace Bit.Api.Vault.Validators;
|
||||
public class CipherRotationValidator : IRotationValidator<IEnumerable<CipherWithIdRequestModel>, IEnumerable<Cipher>>
|
||||
{
|
||||
private readonly ICipherRepository _cipherRepository;
|
||||
private readonly ICurrentContext _currentContext;
|
||||
private readonly IFeatureService _featureService;
|
||||
|
||||
private bool UseFlexibleCollections =>
|
||||
_featureService.IsEnabled(FeatureFlagKeys.FlexibleCollections, _currentContext);
|
||||
_featureService.IsEnabled(FeatureFlagKeys.FlexibleCollections);
|
||||
|
||||
public CipherRotationValidator(ICipherRepository cipherRepository, ICurrentContext currentContext,
|
||||
IFeatureService featureService)
|
||||
public CipherRotationValidator(ICipherRepository cipherRepository, IFeatureService featureService)
|
||||
{
|
||||
_cipherRepository = cipherRepository;
|
||||
_currentContext = currentContext;
|
||||
_featureService = featureService;
|
||||
|
||||
}
|
||||
|
||||
public async Task<IEnumerable<Cipher>> ValidateAsync(User user, IEnumerable<CipherWithIdRequestModel> ciphers)
|
||||
|
@ -442,10 +442,10 @@ public class OrganizationService : IOrganizationService
|
||||
}
|
||||
|
||||
var flexibleCollectionsSignupEnabled =
|
||||
_featureService.IsEnabled(FeatureFlagKeys.FlexibleCollectionsSignup, _currentContext);
|
||||
_featureService.IsEnabled(FeatureFlagKeys.FlexibleCollectionsSignup);
|
||||
|
||||
var flexibleCollectionsV1IsEnabled =
|
||||
_featureService.IsEnabled(FeatureFlagKeys.FlexibleCollectionsV1, _currentContext);
|
||||
_featureService.IsEnabled(FeatureFlagKeys.FlexibleCollectionsV1);
|
||||
|
||||
var organization = new Organization
|
||||
{
|
||||
@ -572,7 +572,7 @@ public class OrganizationService : IOrganizationService
|
||||
await ValidateSignUpPoliciesAsync(owner.Id);
|
||||
|
||||
var flexibleCollectionsSignupEnabled =
|
||||
_featureService.IsEnabled(FeatureFlagKeys.FlexibleCollectionsSignup, _currentContext);
|
||||
_featureService.IsEnabled(FeatureFlagKeys.FlexibleCollectionsSignup);
|
||||
|
||||
var organization = new Organization
|
||||
{
|
||||
|
@ -5,7 +5,6 @@ using Bit.Core.Auth.Enums;
|
||||
using Bit.Core.Auth.Models;
|
||||
using Bit.Core.Auth.Models.Business.Tokenables;
|
||||
using Bit.Core.Auth.Models.Data;
|
||||
using Bit.Core.Context;
|
||||
using Bit.Core.Entities;
|
||||
using Bit.Core.Enums;
|
||||
using Bit.Core.Exceptions;
|
||||
@ -34,11 +33,10 @@ public class EmergencyAccessService : IEmergencyAccessService
|
||||
private readonly IPasswordHasher<User> _passwordHasher;
|
||||
private readonly IOrganizationService _organizationService;
|
||||
private readonly IDataProtectorTokenFactory<EmergencyAccessInviteTokenable> _dataProtectorTokenizer;
|
||||
private readonly ICurrentContext _currentContext;
|
||||
private readonly IFeatureService _featureService;
|
||||
|
||||
private bool UseFlexibleCollections =>
|
||||
_featureService.IsEnabled(FeatureFlagKeys.FlexibleCollections, _currentContext);
|
||||
_featureService.IsEnabled(FeatureFlagKeys.FlexibleCollections);
|
||||
|
||||
public EmergencyAccessService(
|
||||
IEmergencyAccessRepository emergencyAccessRepository,
|
||||
@ -53,7 +51,6 @@ public class EmergencyAccessService : IEmergencyAccessService
|
||||
GlobalSettings globalSettings,
|
||||
IOrganizationService organizationService,
|
||||
IDataProtectorTokenFactory<EmergencyAccessInviteTokenable> dataProtectorTokenizer,
|
||||
ICurrentContext currentContext,
|
||||
IFeatureService featureService)
|
||||
{
|
||||
_emergencyAccessRepository = emergencyAccessRepository;
|
||||
@ -68,7 +65,6 @@ public class EmergencyAccessService : IEmergencyAccessService
|
||||
_globalSettings = globalSettings;
|
||||
_organizationService = organizationService;
|
||||
_dataProtectorTokenizer = dataProtectorTokenizer;
|
||||
_currentContext = currentContext;
|
||||
_featureService = featureService;
|
||||
}
|
||||
|
||||
|
@ -8,7 +8,6 @@ using Bit.Core.Enums;
|
||||
using Bit.Core.Identity;
|
||||
using Bit.Core.Models.Data;
|
||||
using Bit.Core.Repositories;
|
||||
using Bit.Core.Services;
|
||||
using Bit.Core.Settings;
|
||||
using Bit.Core.Utilities;
|
||||
using Microsoft.AspNetCore.Http;
|
||||
@ -19,7 +18,6 @@ public class CurrentContext : ICurrentContext
|
||||
{
|
||||
private readonly IProviderOrganizationRepository _providerOrganizationRepository;
|
||||
private readonly IProviderUserRepository _providerUserRepository;
|
||||
private readonly IFeatureService _featureService;
|
||||
private bool _builtHttpContext;
|
||||
private bool _builtClaimsPrincipal;
|
||||
private IEnumerable<ProviderOrganizationProviderDetails> _providerOrganizationProviderDetails;
|
||||
@ -46,12 +44,10 @@ public class CurrentContext : ICurrentContext
|
||||
|
||||
public CurrentContext(
|
||||
IProviderOrganizationRepository providerOrganizationRepository,
|
||||
IProviderUserRepository providerUserRepository,
|
||||
IFeatureService featureService)
|
||||
IProviderUserRepository providerUserRepository)
|
||||
{
|
||||
_providerOrganizationRepository = providerOrganizationRepository;
|
||||
_providerUserRepository = providerUserRepository;
|
||||
_featureService = featureService; ;
|
||||
}
|
||||
|
||||
public async virtual Task BuildAsync(HttpContext httpContext, GlobalSettings globalSettings)
|
||||
|
@ -1,6 +1,4 @@
|
||||
using Bit.Core.Context;
|
||||
|
||||
namespace Bit.Core.Services;
|
||||
namespace Bit.Core.Services;
|
||||
|
||||
public interface IFeatureService
|
||||
{
|
||||
@ -14,33 +12,29 @@ public interface IFeatureService
|
||||
/// Checks whether a given feature is enabled.
|
||||
/// </summary>
|
||||
/// <param name="key">The key of the feature to check.</param>
|
||||
/// <param name="currentContext">A context providing information that can be used to evaluate whether a feature should be on or off.</param>
|
||||
/// <param name="defaultValue">The default value for the feature.</param>
|
||||
/// <returns>True if the feature is enabled, otherwise false.</returns>
|
||||
bool IsEnabled(string key, ICurrentContext currentContext, bool defaultValue = false);
|
||||
bool IsEnabled(string key, bool defaultValue = false);
|
||||
|
||||
/// <summary>
|
||||
/// Gets the integer variation of a feature.
|
||||
/// </summary>
|
||||
/// <param name="key">The key of the feature to check.</param>
|
||||
/// <param name="currentContext">A context providing information that can be used to evaluate the feature value.</param>
|
||||
/// <param name="defaultValue">The default value for the feature.</param>
|
||||
/// <returns>The feature variation value.</returns>
|
||||
int GetIntVariation(string key, ICurrentContext currentContext, int defaultValue = 0);
|
||||
int GetIntVariation(string key, int defaultValue = 0);
|
||||
|
||||
/// <summary>
|
||||
/// Gets the string variation of a feature.
|
||||
/// </summary>
|
||||
/// <param name="key">The key of the feature to check.</param>
|
||||
/// <param name="currentContext">A context providing information that can be used to evaluate the feature value.</param>
|
||||
/// <param name="defaultValue">The default value for the feature.</param>
|
||||
/// <returns>The feature variation value.</returns>
|
||||
string GetStringVariation(string key, ICurrentContext currentContext, string defaultValue = null);
|
||||
string GetStringVariation(string key, string defaultValue = null);
|
||||
|
||||
/// <summary>
|
||||
/// Gets all feature values.
|
||||
/// </summary>
|
||||
/// <param name="currentContext">A context providing information that can be used to evaluate the feature values.</param>
|
||||
/// <returns>A dictionary of feature keys and their values.</returns>
|
||||
Dictionary<string, object> GetAll(ICurrentContext currentContext);
|
||||
Dictionary<string, object> GetAll();
|
||||
}
|
||||
|
@ -56,7 +56,7 @@ public class CollectionService : ICollectionService
|
||||
var usersList = users?.ToList();
|
||||
|
||||
// If using Flexible Collections - a collection should always have someone with Can Manage permissions
|
||||
if (_featureService.IsEnabled(FeatureFlagKeys.FlexibleCollectionsV1, _currentContext))
|
||||
if (_featureService.IsEnabled(FeatureFlagKeys.FlexibleCollectionsV1))
|
||||
{
|
||||
var groupHasManageAccess = groupsList?.Any(g => g.Manage) ?? false;
|
||||
var userHasManageAccess = usersList?.Any(u => u.Manage) ?? false;
|
||||
@ -124,7 +124,7 @@ public class CollectionService : ICollectionService
|
||||
{
|
||||
var collections = await _collectionRepository.GetManyByUserIdAsync(
|
||||
_currentContext.UserId.Value,
|
||||
_featureService.IsEnabled(FeatureFlagKeys.FlexibleCollections, _currentContext)
|
||||
_featureService.IsEnabled(FeatureFlagKeys.FlexibleCollections)
|
||||
);
|
||||
orgCollections = collections.Where(c => c.OrganizationId == organizationId);
|
||||
}
|
||||
|
@ -4,16 +4,25 @@ using Bit.Core.Utilities;
|
||||
using LaunchDarkly.Logging;
|
||||
using LaunchDarkly.Sdk.Server;
|
||||
using LaunchDarkly.Sdk.Server.Integrations;
|
||||
using LaunchDarkly.Sdk.Server.Interfaces;
|
||||
|
||||
namespace Bit.Core.Services;
|
||||
|
||||
public class LaunchDarklyFeatureService : IFeatureService, IDisposable
|
||||
public class LaunchDarklyFeatureService : IFeatureService
|
||||
{
|
||||
private readonly LdClient _client;
|
||||
private readonly ILdClient _client;
|
||||
private readonly ICurrentContext _currentContext;
|
||||
private const string _anonymousUser = "25a15cac-58cf-4ac0-ad0f-b17c4bd92294";
|
||||
|
||||
public LaunchDarklyFeatureService(
|
||||
IGlobalSettings globalSettings)
|
||||
ILdClient client,
|
||||
ICurrentContext currentContext)
|
||||
{
|
||||
_client = client;
|
||||
_currentContext = currentContext;
|
||||
}
|
||||
|
||||
public static Configuration GetConfiguredClient(GlobalSettings globalSettings)
|
||||
{
|
||||
var ldConfig = Configuration.Builder(globalSettings.LaunchDarkly?.SdkKey);
|
||||
ldConfig.Logging(Components.Logging().Level(LogLevel.Error));
|
||||
@ -64,7 +73,7 @@ public class LaunchDarklyFeatureService : IFeatureService, IDisposable
|
||||
ldConfig.Offline(true);
|
||||
}
|
||||
|
||||
_client = new LdClient(ldConfig.Build());
|
||||
return ldConfig.Build();
|
||||
}
|
||||
|
||||
public bool IsOnline()
|
||||
@ -72,28 +81,28 @@ public class LaunchDarklyFeatureService : IFeatureService, IDisposable
|
||||
return _client.Initialized && !_client.IsOffline();
|
||||
}
|
||||
|
||||
public bool IsEnabled(string key, ICurrentContext currentContext, bool defaultValue = false)
|
||||
public bool IsEnabled(string key, bool defaultValue = false)
|
||||
{
|
||||
return _client.BoolVariation(key, BuildContext(currentContext), defaultValue);
|
||||
return _client.BoolVariation(key, BuildContext(), defaultValue);
|
||||
}
|
||||
|
||||
public int GetIntVariation(string key, ICurrentContext currentContext, int defaultValue = 0)
|
||||
public int GetIntVariation(string key, int defaultValue = 0)
|
||||
{
|
||||
return _client.IntVariation(key, BuildContext(currentContext), defaultValue);
|
||||
return _client.IntVariation(key, BuildContext(), defaultValue);
|
||||
}
|
||||
|
||||
public string GetStringVariation(string key, ICurrentContext currentContext, string defaultValue = null)
|
||||
public string GetStringVariation(string key, string defaultValue = null)
|
||||
{
|
||||
return _client.StringVariation(key, BuildContext(currentContext), defaultValue);
|
||||
return _client.StringVariation(key, BuildContext(), defaultValue);
|
||||
}
|
||||
|
||||
public Dictionary<string, object> GetAll(ICurrentContext currentContext)
|
||||
public Dictionary<string, object> GetAll()
|
||||
{
|
||||
var results = new Dictionary<string, object>();
|
||||
|
||||
var keys = FeatureFlagKeys.GetAllKeys();
|
||||
|
||||
var values = _client.AllFlagsState(BuildContext(currentContext));
|
||||
var values = _client.AllFlagsState(BuildContext());
|
||||
if (values.Valid)
|
||||
{
|
||||
foreach (var key in keys)
|
||||
@ -119,23 +128,18 @@ public class LaunchDarklyFeatureService : IFeatureService, IDisposable
|
||||
return results;
|
||||
}
|
||||
|
||||
public void Dispose()
|
||||
{
|
||||
_client?.Dispose();
|
||||
}
|
||||
|
||||
private LaunchDarkly.Sdk.Context BuildContext(ICurrentContext currentContext)
|
||||
private LaunchDarkly.Sdk.Context BuildContext()
|
||||
{
|
||||
var builder = LaunchDarkly.Sdk.Context.MultiBuilder();
|
||||
|
||||
switch (currentContext.ClientType)
|
||||
switch (_currentContext.ClientType)
|
||||
{
|
||||
case Identity.ClientType.User:
|
||||
{
|
||||
LaunchDarkly.Sdk.ContextBuilder ldUser;
|
||||
if (currentContext.UserId.HasValue)
|
||||
if (_currentContext.UserId.HasValue)
|
||||
{
|
||||
ldUser = LaunchDarkly.Sdk.Context.Builder(currentContext.UserId.Value.ToString());
|
||||
ldUser = LaunchDarkly.Sdk.Context.Builder(_currentContext.UserId.Value.ToString());
|
||||
}
|
||||
else
|
||||
{
|
||||
@ -146,9 +150,9 @@ public class LaunchDarklyFeatureService : IFeatureService, IDisposable
|
||||
|
||||
ldUser.Kind(LaunchDarkly.Sdk.ContextKind.Default);
|
||||
|
||||
if (currentContext.Organizations?.Any() ?? false)
|
||||
if (_currentContext.Organizations?.Any() ?? false)
|
||||
{
|
||||
var ldOrgs = currentContext.Organizations.Select(o => LaunchDarkly.Sdk.LdValue.Of(o.Id.ToString()));
|
||||
var ldOrgs = _currentContext.Organizations.Select(o => LaunchDarkly.Sdk.LdValue.Of(o.Id.ToString()));
|
||||
ldUser.Set("organizations", LaunchDarkly.Sdk.LdValue.ArrayFrom(ldOrgs));
|
||||
}
|
||||
|
||||
@ -158,9 +162,9 @@ public class LaunchDarklyFeatureService : IFeatureService, IDisposable
|
||||
|
||||
case Identity.ClientType.Organization:
|
||||
{
|
||||
if (currentContext.OrganizationId.HasValue)
|
||||
if (_currentContext.OrganizationId.HasValue)
|
||||
{
|
||||
var ldOrg = LaunchDarkly.Sdk.Context.Builder(currentContext.OrganizationId.Value.ToString());
|
||||
var ldOrg = LaunchDarkly.Sdk.Context.Builder(_currentContext.OrganizationId.Value.ToString());
|
||||
ldOrg.Kind("organization");
|
||||
builder.Add(ldOrg.Build());
|
||||
}
|
||||
@ -169,16 +173,16 @@ public class LaunchDarklyFeatureService : IFeatureService, IDisposable
|
||||
|
||||
case Identity.ClientType.ServiceAccount:
|
||||
{
|
||||
if (currentContext.UserId.HasValue)
|
||||
if (_currentContext.UserId.HasValue)
|
||||
{
|
||||
var ldServiceAccount = LaunchDarkly.Sdk.Context.Builder(currentContext.UserId.Value.ToString());
|
||||
var ldServiceAccount = LaunchDarkly.Sdk.Context.Builder(_currentContext.UserId.Value.ToString());
|
||||
ldServiceAccount.Kind("service-account");
|
||||
builder.Add(ldServiceAccount.Build());
|
||||
}
|
||||
|
||||
if (currentContext.OrganizationId.HasValue)
|
||||
if (_currentContext.OrganizationId.HasValue)
|
||||
{
|
||||
var ldOrg = LaunchDarkly.Sdk.Context.Builder(currentContext.OrganizationId.Value.ToString());
|
||||
var ldOrg = LaunchDarkly.Sdk.Context.Builder(_currentContext.OrganizationId.Value.ToString());
|
||||
ldOrg.Kind("organization");
|
||||
builder.Add(ldOrg.Build());
|
||||
}
|
||||
@ -189,7 +193,7 @@ public class LaunchDarklyFeatureService : IFeatureService, IDisposable
|
||||
return builder.Build();
|
||||
}
|
||||
|
||||
private TestData BuildDataSource(Dictionary<string, string> values)
|
||||
private static TestData BuildDataSource(Dictionary<string, string> values)
|
||||
{
|
||||
var source = TestData.DataSource();
|
||||
foreach (var kvp in values)
|
||||
|
@ -1,5 +1,4 @@
|
||||
using Bit.Core.Context;
|
||||
using Bit.Core.Exceptions;
|
||||
using Bit.Core.Exceptions;
|
||||
using Bit.Core.Services;
|
||||
using Microsoft.AspNetCore.Mvc.Filters;
|
||||
using Microsoft.Extensions.DependencyInjection;
|
||||
@ -25,10 +24,9 @@ public class RequireFeatureAttribute : ActionFilterAttribute
|
||||
|
||||
public override void OnActionExecuting(ActionExecutingContext context)
|
||||
{
|
||||
var currentContext = context.HttpContext.RequestServices.GetRequiredService<ICurrentContext>();
|
||||
var featureService = context.HttpContext.RequestServices.GetRequiredService<IFeatureService>();
|
||||
|
||||
if (!featureService.IsEnabled(_featureFlagKey, currentContext))
|
||||
if (!featureService.IsEnabled(_featureFlagKey))
|
||||
{
|
||||
throw new FeatureUnavailableException();
|
||||
}
|
||||
|
@ -41,7 +41,7 @@ public class CipherService : ICipherService
|
||||
private readonly IFeatureService _featureService;
|
||||
|
||||
private bool UseFlexibleCollections =>
|
||||
_featureService.IsEnabled(FeatureFlagKeys.FlexibleCollections, _currentContext);
|
||||
_featureService.IsEnabled(FeatureFlagKeys.FlexibleCollections);
|
||||
|
||||
public CipherService(
|
||||
ICipherRepository cipherRepository,
|
||||
|
@ -73,7 +73,7 @@ public class CollectController : Controller
|
||||
}
|
||||
else
|
||||
{
|
||||
var useFlexibleCollections = _featureService.IsEnabled(FeatureFlagKeys.FlexibleCollections, _currentContext);
|
||||
var useFlexibleCollections = _featureService.IsEnabled(FeatureFlagKeys.FlexibleCollections);
|
||||
cipher = await _cipherRepository.GetByIdAsync(eventModel.CipherId.Value,
|
||||
_currentContext.UserId.Value,
|
||||
useFlexibleCollections);
|
||||
|
@ -70,7 +70,7 @@ public class Startup
|
||||
services.AddSingleton<IEventWriteService, RepositoryEventWriteService>();
|
||||
}
|
||||
|
||||
services.AddSingleton<IFeatureService, LaunchDarklyFeatureService>();
|
||||
services.AddOptionality();
|
||||
|
||||
// Mvc
|
||||
services.AddMvc(config =>
|
||||
|
@ -66,7 +66,7 @@ public class WebAuthnGrantValidator : BaseRequestValidator<ExtensionGrantValidat
|
||||
|
||||
public async Task ValidateAsync(ExtensionGrantValidationContext context)
|
||||
{
|
||||
if (!FeatureService.IsEnabled(FeatureFlagKeys.PasswordlessLogin, CurrentContext))
|
||||
if (!FeatureService.IsEnabled(FeatureFlagKeys.PasswordlessLogin))
|
||||
{
|
||||
context.Result = new GrantValidationResult(TokenRequestErrors.InvalidGrant);
|
||||
return;
|
||||
|
@ -18,7 +18,7 @@ public class NotificationsHub : Microsoft.AspNetCore.SignalR.Hub
|
||||
|
||||
public override async Task OnConnectedAsync()
|
||||
{
|
||||
var currentContext = new CurrentContext(null, null, null);
|
||||
var currentContext = new CurrentContext(null, null);
|
||||
await currentContext.BuildAsync(Context.User, _globalSettings);
|
||||
if (currentContext.Organizations != null)
|
||||
{
|
||||
@ -33,7 +33,7 @@ public class NotificationsHub : Microsoft.AspNetCore.SignalR.Hub
|
||||
|
||||
public override async Task OnDisconnectedAsync(Exception exception)
|
||||
{
|
||||
var currentContext = new CurrentContext(null, null, null);
|
||||
var currentContext = new CurrentContext(null, null);
|
||||
await currentContext.BuildAsync(Context.User, _globalSettings);
|
||||
if (currentContext.Organizations != null)
|
||||
{
|
||||
|
@ -35,6 +35,8 @@ using Bit.Infrastructure.EntityFramework;
|
||||
using DnsClient;
|
||||
using Duende.IdentityServer.Configuration;
|
||||
using IdentityModel;
|
||||
using LaunchDarkly.Sdk.Server;
|
||||
using LaunchDarkly.Sdk.Server.Interfaces;
|
||||
using Microsoft.AspNetCore.Authentication.Cookies;
|
||||
using Microsoft.AspNetCore.Authentication.JwtBearer;
|
||||
using Microsoft.AspNetCore.Authorization;
|
||||
@ -222,7 +224,7 @@ public static class ServiceCollectionExtensions
|
||||
return new LookupClient(options);
|
||||
});
|
||||
services.AddSingleton<IDnsResolverService, DnsResolverService>();
|
||||
services.AddSingleton<IFeatureService, LaunchDarklyFeatureService>();
|
||||
services.AddOptionality();
|
||||
services.AddTokenizers();
|
||||
|
||||
if (CoreHelpers.SettingHasValue(globalSettings.ServiceBus.ConnectionString) &&
|
||||
@ -426,8 +428,6 @@ public static class ServiceCollectionExtensions
|
||||
return identityBuilder;
|
||||
}
|
||||
|
||||
|
||||
|
||||
public static void AddIdentityAuthenticationServices(
|
||||
this IServiceCollection services, GlobalSettings globalSettings, IWebHostEnvironment environment,
|
||||
Action<AuthorizationOptions> addAuthorization)
|
||||
@ -727,4 +727,17 @@ public static class ServiceCollectionExtensions
|
||||
});
|
||||
});
|
||||
}
|
||||
|
||||
public static IServiceCollection AddOptionality(this IServiceCollection services)
|
||||
{
|
||||
services.AddSingleton<ILdClient>(s =>
|
||||
{
|
||||
return new LdClient(LaunchDarklyFeatureService.GetConfiguredClient(
|
||||
s.GetRequiredService<GlobalSettings>()));
|
||||
});
|
||||
|
||||
services.AddScoped<IFeatureService, LaunchDarklyFeatureService>();
|
||||
|
||||
return services;
|
||||
}
|
||||
}
|
||||
|
@ -14,7 +14,6 @@ using Bit.Core.Auth.Models.Api.Request.Accounts;
|
||||
using Bit.Core.Auth.Services;
|
||||
using Bit.Core.Auth.UserFeatures.UserKey;
|
||||
using Bit.Core.Auth.UserFeatures.UserMasterPassword.Interfaces;
|
||||
using Bit.Core.Context;
|
||||
using Bit.Core.Entities;
|
||||
using Bit.Core.Enums;
|
||||
using Bit.Core.Exceptions;
|
||||
@ -54,7 +53,6 @@ public class AccountsControllerTests : IDisposable
|
||||
private readonly ISetInitialMasterPasswordCommand _setInitialMasterPasswordCommand;
|
||||
private readonly IRotateUserKeyCommand _rotateUserKeyCommand;
|
||||
private readonly IFeatureService _featureService;
|
||||
private readonly ICurrentContext _currentContext;
|
||||
|
||||
private readonly IRotationValidator<IEnumerable<CipherWithIdRequestModel>, IEnumerable<Cipher>> _cipherValidator;
|
||||
private readonly IRotationValidator<IEnumerable<FolderWithIdRequestModel>, IEnumerable<Folder>> _folderValidator;
|
||||
@ -84,7 +82,6 @@ public class AccountsControllerTests : IDisposable
|
||||
_setInitialMasterPasswordCommand = Substitute.For<ISetInitialMasterPasswordCommand>();
|
||||
_rotateUserKeyCommand = Substitute.For<IRotateUserKeyCommand>();
|
||||
_featureService = Substitute.For<IFeatureService>();
|
||||
_currentContext = Substitute.For<ICurrentContext>();
|
||||
_cipherValidator =
|
||||
Substitute.For<IRotationValidator<IEnumerable<CipherWithIdRequestModel>, IEnumerable<Cipher>>>();
|
||||
_folderValidator =
|
||||
@ -113,7 +110,6 @@ public class AccountsControllerTests : IDisposable
|
||||
_setInitialMasterPasswordCommand,
|
||||
_rotateUserKeyCommand,
|
||||
_featureService,
|
||||
_currentContext,
|
||||
_cipherValidator,
|
||||
_folderValidator,
|
||||
_sendValidator,
|
||||
|
@ -1,6 +1,5 @@
|
||||
using AutoFixture.Xunit2;
|
||||
using Bit.Api.Controllers;
|
||||
using Bit.Core.Context;
|
||||
using Bit.Core.Services;
|
||||
using Bit.Core.Settings;
|
||||
using NSubstitute;
|
||||
@ -13,17 +12,14 @@ public class ConfigControllerTests : IDisposable
|
||||
private readonly ConfigController _sut;
|
||||
private readonly GlobalSettings _globalSettings;
|
||||
private readonly IFeatureService _featureService;
|
||||
private readonly ICurrentContext _currentContext;
|
||||
|
||||
public ConfigControllerTests()
|
||||
{
|
||||
_globalSettings = new GlobalSettings();
|
||||
_currentContext = Substitute.For<ICurrentContext>();
|
||||
_featureService = Substitute.For<IFeatureService>();
|
||||
|
||||
_sut = new ConfigController(
|
||||
_globalSettings,
|
||||
_currentContext,
|
||||
_featureService
|
||||
);
|
||||
}
|
||||
@ -36,7 +32,7 @@ public class ConfigControllerTests : IDisposable
|
||||
[Theory, AutoData]
|
||||
public void GetConfigs_WithFeatureStates(Dictionary<string, object> featureStates)
|
||||
{
|
||||
_featureService.GetAll(_currentContext).Returns(featureStates);
|
||||
_featureService.GetAll().Returns(featureStates);
|
||||
|
||||
var response = _sut.GetConfigs();
|
||||
|
||||
|
@ -114,7 +114,7 @@ public class CollectionServiceTest
|
||||
collection.Id = default;
|
||||
sutProvider.GetDependency<IOrganizationRepository>().GetByIdAsync(organization.Id).Returns(organization);
|
||||
sutProvider.GetDependency<IFeatureService>()
|
||||
.IsEnabled(FeatureFlagKeys.FlexibleCollectionsV1, Arg.Any<ICurrentContext>(), Arg.Any<bool>())
|
||||
.IsEnabled(FeatureFlagKeys.FlexibleCollectionsV1, Arg.Any<bool>())
|
||||
.Returns(true);
|
||||
organization.AllowAdminAccessToAllCollectionItems = false;
|
||||
|
||||
|
@ -4,6 +4,7 @@ using Bit.Core.Services;
|
||||
using Bit.Core.Settings;
|
||||
using Bit.Test.Common.AutoFixture;
|
||||
using Bit.Test.Common.AutoFixture.Attributes;
|
||||
using LaunchDarkly.Sdk.Server.Interfaces;
|
||||
using NSubstitute;
|
||||
using Xunit;
|
||||
|
||||
@ -19,9 +20,16 @@ public class LaunchDarklyFeatureServiceTests
|
||||
{
|
||||
globalSettings.ProjectName = "LaunchDarkly Tests";
|
||||
|
||||
var currentContext = Substitute.For<ICurrentContext>();
|
||||
currentContext.UserId.Returns(Guid.NewGuid());
|
||||
|
||||
var client = Substitute.For<ILdClient>();
|
||||
|
||||
var fixture = new Fixture();
|
||||
return new SutProvider<LaunchDarklyFeatureService>(fixture)
|
||||
.SetDependency(globalSettings)
|
||||
.SetDependency(currentContext)
|
||||
.SetDependency(client)
|
||||
.Create();
|
||||
}
|
||||
|
||||
@ -30,10 +38,7 @@ public class LaunchDarklyFeatureServiceTests
|
||||
{
|
||||
var sutProvider = GetSutProvider(new Settings.GlobalSettings { SelfHosted = true });
|
||||
|
||||
var currentContext = Substitute.For<ICurrentContext>();
|
||||
currentContext.UserId.Returns(Guid.NewGuid());
|
||||
|
||||
Assert.False(sutProvider.Sut.IsEnabled(key, currentContext));
|
||||
Assert.False(sutProvider.Sut.IsEnabled(key));
|
||||
}
|
||||
|
||||
[Fact]
|
||||
@ -41,10 +46,7 @@ public class LaunchDarklyFeatureServiceTests
|
||||
{
|
||||
var sutProvider = GetSutProvider(new Settings.GlobalSettings());
|
||||
|
||||
var currentContext = Substitute.For<ICurrentContext>();
|
||||
currentContext.UserId.Returns(Guid.NewGuid());
|
||||
|
||||
Assert.False(sutProvider.Sut.IsEnabled(_fakeFeatureKey, currentContext));
|
||||
Assert.False(sutProvider.Sut.IsEnabled(_fakeFeatureKey));
|
||||
}
|
||||
|
||||
[Fact(Skip = "For local development")]
|
||||
@ -54,10 +56,7 @@ public class LaunchDarklyFeatureServiceTests
|
||||
|
||||
var sutProvider = GetSutProvider(settings);
|
||||
|
||||
var currentContext = Substitute.For<ICurrentContext>();
|
||||
currentContext.UserId.Returns(Guid.NewGuid());
|
||||
|
||||
Assert.False(sutProvider.Sut.IsEnabled(_fakeFeatureKey, currentContext));
|
||||
Assert.False(sutProvider.Sut.IsEnabled(_fakeFeatureKey));
|
||||
}
|
||||
|
||||
[Fact(Skip = "For local development")]
|
||||
@ -67,10 +66,7 @@ public class LaunchDarklyFeatureServiceTests
|
||||
|
||||
var sutProvider = GetSutProvider(settings);
|
||||
|
||||
var currentContext = Substitute.For<ICurrentContext>();
|
||||
currentContext.UserId.Returns(Guid.NewGuid());
|
||||
|
||||
Assert.Equal(0, sutProvider.Sut.GetIntVariation(_fakeFeatureKey, currentContext));
|
||||
Assert.Equal(0, sutProvider.Sut.GetIntVariation(_fakeFeatureKey));
|
||||
}
|
||||
|
||||
[Fact(Skip = "For local development")]
|
||||
@ -80,10 +76,7 @@ public class LaunchDarklyFeatureServiceTests
|
||||
|
||||
var sutProvider = GetSutProvider(settings);
|
||||
|
||||
var currentContext = Substitute.For<ICurrentContext>();
|
||||
currentContext.UserId.Returns(Guid.NewGuid());
|
||||
|
||||
Assert.Null(sutProvider.Sut.GetStringVariation(_fakeFeatureKey, currentContext));
|
||||
Assert.Null(sutProvider.Sut.GetStringVariation(_fakeFeatureKey));
|
||||
}
|
||||
|
||||
[Fact(Skip = "For local development")]
|
||||
@ -91,10 +84,7 @@ public class LaunchDarklyFeatureServiceTests
|
||||
{
|
||||
var sutProvider = GetSutProvider(new Settings.GlobalSettings());
|
||||
|
||||
var currentContext = Substitute.For<ICurrentContext>();
|
||||
currentContext.UserId.Returns(Guid.NewGuid());
|
||||
|
||||
var results = sutProvider.Sut.GetAll(currentContext);
|
||||
var results = sutProvider.Sut.GetAll();
|
||||
|
||||
Assert.NotNull(results);
|
||||
Assert.NotEmpty(results);
|
||||
|
@ -64,7 +64,7 @@ public class RequireFeatureAttributeTests
|
||||
var featureService = Substitute.For<IFeatureService>();
|
||||
var currentContext = Substitute.For<ICurrentContext>();
|
||||
|
||||
featureService.IsEnabled(_testFeature, Arg.Any<ICurrentContext>()).Returns(enabled);
|
||||
featureService.IsEnabled(_testFeature).Returns(enabled);
|
||||
|
||||
services.AddSingleton(featureService);
|
||||
services.AddSingleton(currentContext);
|
||||
|
Loading…
Reference in New Issue
Block a user