mirror of
https://github.com/bitwarden/server.git
synced 2026-06-01 01:55:55 -05:00
Implement feature flag for fetching new policies and organization details in SyncController (#7506) (#7529)
- Added support for retrieving confirmed accepted policies and organization user details based on the feature flag 'PoliciesInAcceptedState'. - Updated SyncResponseModel to include new properties for these details. - Enhanced SyncControllerTests to verify behavior with the feature flag enabled and disabled.
This commit is contained in:
@@ -16,6 +16,7 @@ using Bit.Core.KeyManagement.Models.Data;
|
||||
using Bit.Core.KeyManagement.Queries.Interfaces;
|
||||
using Bit.Core.Models.Data;
|
||||
using Bit.Core.Models.Data.Organizations;
|
||||
using Bit.Core.Models.Data.Organizations.OrganizationUsers;
|
||||
using Bit.Core.Repositories;
|
||||
using Bit.Core.Services;
|
||||
using Bit.Core.Settings;
|
||||
@@ -135,9 +136,18 @@ public class SyncController : Controller
|
||||
userAccountKeys = await _userAccountKeysQuery.Run(user);
|
||||
}
|
||||
|
||||
IEnumerable<Policy> policiesNew = null;
|
||||
IEnumerable<OrganizationUserOrganizationDetails> organizationUserDetailsNew = null;
|
||||
if (_featureService.IsEnabled(FeatureFlagKeys.PoliciesInAcceptedState))
|
||||
{
|
||||
policiesNew = await _policyRepository.GetManyConfirmedAcceptedByUserIdAsync(user.Id);
|
||||
organizationUserDetailsNew = await _organizationUserRepository.GetManyConfirmedAcceptedDetailsByUserAsync(user.Id);
|
||||
}
|
||||
|
||||
var response = new SyncResponseModel(_globalSettings, user, userAccountKeys, userTwoFactorEnabled, userHasPremiumFromOrganization, organizationAbilities,
|
||||
organizationIdsClaimingActiveUser, organizationUserDetails, providerUserDetails, providerUserOrganizationDetails,
|
||||
folders, collections, ciphers, collectionCiphersGroupDict, excludeDomains, policies, sends, webAuthnCredentials);
|
||||
folders, collections, ciphers, collectionCiphersGroupDict, excludeDomains, policies, sends, webAuthnCredentials,
|
||||
policiesNew, organizationUserDetailsNew);
|
||||
return response;
|
||||
}
|
||||
|
||||
|
||||
@@ -44,7 +44,9 @@ public class SyncResponseModel() : ResponseModel("sync")
|
||||
bool excludeDomains,
|
||||
IEnumerable<Policy> policies,
|
||||
IEnumerable<Send> sends,
|
||||
IEnumerable<WebAuthnCredential> webAuthnCredentials)
|
||||
IEnumerable<WebAuthnCredential> webAuthnCredentials,
|
||||
IEnumerable<Policy> policiesNew = null,
|
||||
IEnumerable<OrganizationUserOrganizationDetails> organizationUserDetailsNew = null)
|
||||
: this()
|
||||
{
|
||||
Profile = new ProfileResponseModel(user, userAccountKeysData, organizationUserDetails, providerUserDetails,
|
||||
@@ -61,6 +63,8 @@ public class SyncResponseModel() : ResponseModel("sync")
|
||||
c => new CollectionDetailsResponseModel(c)) ?? new List<CollectionDetailsResponseModel>();
|
||||
Domains = excludeDomains ? null : new DomainsResponseModel(user, false);
|
||||
Policies = policies?.Select(p => new PolicyResponseModel(p)) ?? new List<PolicyResponseModel>();
|
||||
PoliciesNew = policiesNew?.Select(p => new PolicyResponseModel(p));
|
||||
OrganizationsNew = organizationUserDetailsNew?.Select(o => new ProfileOrganizationResponseModel(o, organizationIdsClaimingingUser));
|
||||
Sends = sends.Select(s => new SendResponseModel(s));
|
||||
var webAuthnPrfOptions = webAuthnCredentials
|
||||
.Where(c => c.GetPrfStatus() == WebAuthnPrfStatus.Enabled)
|
||||
@@ -119,6 +123,18 @@ public class SyncResponseModel() : ResponseModel("sync")
|
||||
public IEnumerable<CipherDetailsResponseModel> Ciphers { get; set; }
|
||||
public DomainsResponseModel Domains { get; set; }
|
||||
public IEnumerable<PolicyResponseModel> Policies { get; set; }
|
||||
/// <summary>
|
||||
/// Policies for organizations where the user is in the Confirmed or Accepted status.
|
||||
/// Null when the <c>pm-34145-policies-in-accepted-state</c> feature flag is disabled.
|
||||
/// New clients should prefer this property and fall back to <see cref="Policies"/> if absent.
|
||||
/// </summary>
|
||||
public IEnumerable<PolicyResponseModel> PoliciesNew { get; set; }
|
||||
/// <summary>
|
||||
/// Organizations where the user is in the Confirmed or Accepted status.
|
||||
/// Null when the <c>pm-34145-policies-in-accepted-state</c> feature flag is disabled.
|
||||
/// New clients should prefer this property and fall back to <see cref="Profile"/>.<c>Organizations</c> if absent.
|
||||
/// </summary>
|
||||
public IEnumerable<ProfileOrganizationResponseModel> OrganizationsNew { get; set; }
|
||||
public IEnumerable<SendResponseModel> Sends { get; set; }
|
||||
public UserDecryptionResponseModel UserDecryption { get; set; }
|
||||
}
|
||||
|
||||
@@ -615,6 +615,86 @@ public class SyncControllerTests
|
||||
Assert.Contains(result.Ciphers, c => c.Type == CipherType.Login);
|
||||
}
|
||||
|
||||
[Theory]
|
||||
[BitAutoData]
|
||||
public async Task Get_PoliciesInAcceptedState_FlagEnabled_CallsNewRepositoryMethods(
|
||||
User user,
|
||||
ICollection<Policy> policiesAccepted,
|
||||
ICollection<OrganizationUserOrganizationDetails> organizationsAccepted,
|
||||
SutProvider<SyncController> sutProvider)
|
||||
{
|
||||
user.EquivalentDomains = null;
|
||||
user.ExcludedGlobalEquivalentDomains = null;
|
||||
|
||||
var userService = sutProvider.GetDependency<IUserService>();
|
||||
userService.GetUserByPrincipalAsync(Arg.Any<ClaimsPrincipal>()).ReturnsForAnyArgs(user);
|
||||
|
||||
var userAccountKeysQuery = sutProvider.GetDependency<IUserAccountKeysQuery>();
|
||||
userAccountKeysQuery.Run(user).Returns(new UserAccountKeysData
|
||||
{
|
||||
PublicKeyEncryptionKeyPairData = user.GetPublicKeyEncryptionKeyPair(),
|
||||
SignatureKeyPairData = null,
|
||||
});
|
||||
|
||||
sutProvider.GetDependency<IFeatureService>()
|
||||
.IsEnabled(FeatureFlagKeys.PoliciesInAcceptedState).Returns(true);
|
||||
|
||||
var policyRepository = sutProvider.GetDependency<IPolicyRepository>();
|
||||
policyRepository.GetManyConfirmedAcceptedByUserIdAsync(user.Id).Returns(policiesAccepted);
|
||||
|
||||
var organizationUserRepository = sutProvider.GetDependency<IOrganizationUserRepository>();
|
||||
organizationUserRepository.GetManyConfirmedAcceptedDetailsByUserAsync(user.Id).Returns(organizationsAccepted);
|
||||
|
||||
sutProvider.GetDependency<ITwoFactorIsEnabledQuery>()
|
||||
.TwoFactorIsEnabledAsync(user).Returns(false);
|
||||
userService.HasPremiumFromOrganization(user).Returns(false);
|
||||
|
||||
var result = await sutProvider.Sut.Get();
|
||||
|
||||
Assert.IsType<SyncResponseModel>(result);
|
||||
await policyRepository.Received(1).GetManyConfirmedAcceptedByUserIdAsync(user.Id);
|
||||
await organizationUserRepository.Received(1).GetManyConfirmedAcceptedDetailsByUserAsync(user.Id);
|
||||
Assert.NotNull(result.PoliciesNew);
|
||||
Assert.NotNull(result.OrganizationsNew);
|
||||
}
|
||||
|
||||
[Theory]
|
||||
[BitAutoData]
|
||||
public async Task Get_PoliciesInAcceptedState_FlagDisabled_DoesNotCallNewRepositoryMethods(
|
||||
User user,
|
||||
SutProvider<SyncController> sutProvider)
|
||||
{
|
||||
user.EquivalentDomains = null;
|
||||
user.ExcludedGlobalEquivalentDomains = null;
|
||||
|
||||
var userService = sutProvider.GetDependency<IUserService>();
|
||||
userService.GetUserByPrincipalAsync(Arg.Any<ClaimsPrincipal>()).ReturnsForAnyArgs(user);
|
||||
|
||||
var userAccountKeysQuery = sutProvider.GetDependency<IUserAccountKeysQuery>();
|
||||
userAccountKeysQuery.Run(user).Returns(new UserAccountKeysData
|
||||
{
|
||||
PublicKeyEncryptionKeyPairData = user.GetPublicKeyEncryptionKeyPair(),
|
||||
SignatureKeyPairData = null,
|
||||
});
|
||||
|
||||
sutProvider.GetDependency<IFeatureService>()
|
||||
.IsEnabled(FeatureFlagKeys.PoliciesInAcceptedState).Returns(false);
|
||||
|
||||
sutProvider.GetDependency<ITwoFactorIsEnabledQuery>()
|
||||
.TwoFactorIsEnabledAsync(user).Returns(false);
|
||||
userService.HasPremiumFromOrganization(user).Returns(false);
|
||||
|
||||
var result = await sutProvider.Sut.Get();
|
||||
|
||||
Assert.IsType<SyncResponseModel>(result);
|
||||
var policyRepository = sutProvider.GetDependency<IPolicyRepository>();
|
||||
var organizationUserRepository = sutProvider.GetDependency<IOrganizationUserRepository>();
|
||||
await policyRepository.DidNotReceive().GetManyConfirmedAcceptedByUserIdAsync(Arg.Any<Guid>());
|
||||
await organizationUserRepository.DidNotReceive().GetManyConfirmedAcceptedDetailsByUserAsync(Arg.Any<Guid>());
|
||||
Assert.Null(result.PoliciesNew);
|
||||
Assert.Null(result.OrganizationsNew);
|
||||
}
|
||||
|
||||
private async Task AssertMethodsCalledAsync(IUserService userService,
|
||||
ITwoFactorIsEnabledQuery twoFactorIsEnabledQuery,
|
||||
IOrganizationUserRepository organizationUserRepository,
|
||||
|
||||
Reference in New Issue
Block a user