Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -57,7 +57,6 @@ public class ProviderService : IProviderService
private readonly IOrganizationService _organizationService;
private readonly ICurrentContext _currentContext;
private readonly IStripeAdapter _stripeAdapter;
private readonly IFeatureService _featureService;
private readonly IDataProtectorTokenFactory<ProviderDeleteTokenable> _providerDeleteTokenDataFactory;
private readonly IApplicationCacheService _applicationCacheService;
private readonly IProviderBillingService _providerBillingService;
Expand All @@ -70,7 +69,7 @@ public ProviderService(IProviderRepository providerRepository, IProviderUserRepo
IUserService userService, IOrganizationService organizationService, IMailService mailService,
IDataProtectionProvider dataProtectionProvider, IEventService eventService,
IOrganizationRepository organizationRepository, GlobalSettings globalSettings,
ICurrentContext currentContext, IStripeAdapter stripeAdapter, IFeatureService featureService,
ICurrentContext currentContext, IStripeAdapter stripeAdapter,
IDataProtectorTokenFactory<ProviderDeleteTokenable> providerDeleteTokenDataFactory,
IApplicationCacheService applicationCacheService, IProviderBillingService providerBillingService, IPricingClient pricingClient,
IProviderClientOrganizationSignUpCommand providerClientOrganizationSignUpCommand,
Expand All @@ -89,7 +88,6 @@ public ProviderService(IProviderRepository providerRepository, IProviderUserRepo
_dataProtector = dataProtectionProvider.CreateProtector("ProviderServiceDataProtector");
_currentContext = currentContext;
_stripeAdapter = stripeAdapter;
_featureService = featureService;
_providerDeleteTokenDataFactory = providerDeleteTokenDataFactory;
_applicationCacheService = applicationCacheService;
_providerBillingService = providerBillingService;
Expand Down Expand Up @@ -123,16 +121,13 @@ public async Task<Provider> CompleteSetupAsync(Provider provider, Guid ownerUser
throw new BadRequestException("Invalid owner.");
}

if (_featureService.IsEnabled(FeatureFlagKeys.AutomaticConfirmUsers))
{
var organizationAutoConfirmPolicyRequirement = await _policyRequirementQuery
.GetAsync<AutomaticUserConfirmationPolicyRequirement>(ownerUserId);
var organizationAutoConfirmPolicyRequirement = await _policyRequirementQuery
.GetAsync<AutomaticUserConfirmationPolicyRequirement>(ownerUserId);

if (organizationAutoConfirmPolicyRequirement
.CannotCreateProvider())
{
throw new BadRequestException(new UserCannotJoinProvider().Message);
}
if (organizationAutoConfirmPolicyRequirement
.CannotCreateProvider())
{
throw new BadRequestException(new UserCannotJoinProvider().Message);
}

var customer = await _providerBillingService.SetupCustomer(provider, paymentMethod, billingAddress);
Expand Down Expand Up @@ -267,16 +262,13 @@ public async Task<ProviderUser> AcceptUserAsync(Guid providerUserId, User user,
throw new BadRequestException("User email does not match invite.");
}

if (_featureService.IsEnabled(FeatureFlagKeys.AutomaticConfirmUsers))
{
var organizationAutoConfirmPolicyRequirement = await _policyRequirementQuery
.GetAsync<AutomaticUserConfirmationPolicyRequirement>(user.Id);
var organizationAutoConfirmPolicyRequirement = await _policyRequirementQuery
.GetAsync<AutomaticUserConfirmationPolicyRequirement>(user.Id);

if (organizationAutoConfirmPolicyRequirement
.CannotJoinProvider())
{
throw new BadRequestException(new UserCannotJoinProvider().Message);
}
if (organizationAutoConfirmPolicyRequirement
.CannotJoinProvider())
{
throw new BadRequestException(new UserCannotJoinProvider().Message);
}

providerUser.Status = ProviderUserStatusType.Accepted;
Expand Down Expand Up @@ -324,17 +316,14 @@ public async Task<List<Tuple<ProviderUser, string>>> ConfirmUsersAsync(Guid prov
throw new BadRequestException("Invalid user.");
}

if (_featureService.IsEnabled(FeatureFlagKeys.AutomaticConfirmUsers))
{
var organizationAutoConfirmPolicyRequirement = await _policyRequirementQuery
.GetAsync<AutomaticUserConfirmationPolicyRequirement>(user.Id);
var organizationAutoConfirmPolicyRequirement = await _policyRequirementQuery
.GetAsync<AutomaticUserConfirmationPolicyRequirement>(user.Id);

if (organizationAutoConfirmPolicyRequirement
.CannotJoinProvider())
{
result.Add(Tuple.Create(providerUser, new UserCannotJoinProvider().Message));
continue;
}
if (organizationAutoConfirmPolicyRequirement
.CannotJoinProvider())
{
result.Add(Tuple.Create(providerUser, new UserCannotJoinProvider().Message));
continue;
}

providerUser.Status = ProviderUserStatusType.Confirmed;
Expand Down
Original file line number Diff line number Diff line change
@@ -1,6 +1,5 @@
ο»Ώusing Bit.Commercial.Core.AdminConsole.Services;
using Bit.Commercial.Core.Test.AdminConsole.AutoFixture;
using Bit.Core;
using Bit.Core.AdminConsole.Entities;
using Bit.Core.AdminConsole.Entities.Provider;
using Bit.Core.AdminConsole.Enums.Provider;
Expand Down Expand Up @@ -90,6 +89,10 @@ public async Task CompleteSetupAsync_Success(User user, Provider provider, strin
var subscription = new Subscription { Id = "subscription_id" };
providerBillingService.SetupSubscription(provider).Returns(subscription);

sutProvider.GetDependency<IPolicyRequirementQuery>()
.GetAsync<AutomaticUserConfirmationPolicyRequirement>(user.Id)
.Returns(new AutomaticUserConfirmationPolicyRequirement([]));

sutProvider.Create();

var token = protector.Protect($"ProviderSetupInvite {provider.Id} {user.Email} {CoreHelpers.ToEpocMilliseconds(DateTime.UtcNow)}");
Expand Down Expand Up @@ -134,10 +137,6 @@ public async Task CompleteSetupAsync_WithAutoConfirmEnabled_ThrowsUserCannotJoin
var subscription = new Subscription { Id = "subscription_id" };
providerBillingService.SetupSubscription(provider).Returns(subscription);

sutProvider.GetDependency<IFeatureService>()
.IsEnabled(FeatureFlagKeys.AutomaticConfirmUsers)
.Returns(true);

var policyDetails = new List<PolicyDetails> { new() { OrganizationId = Guid.NewGuid(), IsProvider = false } };
var policyRequirement = new AutomaticUserConfirmationPolicyRequirement(policyDetails);
sutProvider.GetDependency<IPolicyRequirementQuery>()
Expand Down Expand Up @@ -630,6 +629,10 @@ public async Task AcceptUserAsync_Success(
providerUser.Email = user.Email;
var token = protector.Protect($"ProviderUserInvite {providerUser.Id} {user.Email} {CoreHelpers.ToEpocMilliseconds(DateTime.UtcNow)}");

sutProvider.GetDependency<IPolicyRequirementQuery>()
.GetAsync<AutomaticUserConfirmationPolicyRequirement>(user.Id)
.Returns(new AutomaticUserConfirmationPolicyRequirement([]));

var pu = await sutProvider.Sut.AcceptUserAsync(providerUser.Id, user, token);
Assert.Null(pu.Email);
Assert.Equal(ProviderUserStatusType.Accepted, pu.Status);
Expand Down Expand Up @@ -660,10 +663,6 @@ public async Task AcceptUserAsync_WithAutoConfirmEnabledAndPolicyExists_Throws(
providerUser.Email = user.Email;
var token = protector.Protect($"ProviderUserInvite {providerUser.Id} {user.Email} {CoreHelpers.ToEpocMilliseconds(DateTime.UtcNow)}");

sutProvider.GetDependency<IFeatureService>()
.IsEnabled(FeatureFlagKeys.AutomaticConfirmUsers)
.Returns(true);

var policyDetails = new List<PolicyDetails>
{
new() { OrganizationId = Guid.NewGuid(), IsProvider = false }
Expand Down Expand Up @@ -703,10 +702,6 @@ public async Task AcceptUserAsync_WithAutoConfirmEnabledButNoPolicyExists_Succes
providerUser.Email = user.Email;
var token = protector.Protect($"ProviderUserInvite {providerUser.Id} {user.Email} {CoreHelpers.ToEpocMilliseconds(DateTime.UtcNow)}");

sutProvider.GetDependency<IFeatureService>()
.IsEnabled(FeatureFlagKeys.AutomaticConfirmUsers)
.Returns(true);

var policyRequirement = new AutomaticUserConfirmationPolicyRequirement([]);
sutProvider.GetDependency<IPolicyRequirementQuery>()
.GetAsync<AutomaticUserConfirmationPolicyRequirement>(user.Id)
Expand All @@ -721,47 +716,6 @@ public async Task AcceptUserAsync_WithAutoConfirmEnabledButNoPolicyExists_Succes
Assert.Equal(user.Id, pu.UserId);
}

[Theory, BitAutoData]
public async Task AcceptUserAsync_WithAutoConfirmDisabled_Success(
[ProviderUser(ProviderUserStatusType.Invited)] ProviderUser providerUser,
User user,
SutProvider<ProviderService> sutProvider)
{
// Arrange
sutProvider.GetDependency<IProviderUserRepository>()
.GetByIdAsync(providerUser.Id)
.Returns(providerUser);

var protector = DataProtectionProvider
.Create("ApplicationName")
.CreateProtector("ProviderServiceDataProtector");

sutProvider.GetDependency<IDataProtectionProvider>()
.CreateProtector("ProviderServiceDataProtector")
.Returns(protector);
sutProvider.Create();

providerUser.Email = user.Email;
var token = protector.Protect($"ProviderUserInvite {providerUser.Id} {user.Email} {CoreHelpers.ToEpocMilliseconds(DateTime.UtcNow)}");

sutProvider.GetDependency<IFeatureService>()
.IsEnabled(FeatureFlagKeys.AutomaticConfirmUsers)
.Returns(false);

// Act
var pu = await sutProvider.Sut.AcceptUserAsync(providerUser.Id, user, token);

// Assert
Assert.Null(pu.Email);
Assert.Equal(ProviderUserStatusType.Accepted, pu.Status);
Assert.Equal(user.Id, pu.UserId);

// Verify that policy check was never called when feature flag is disabled
await sutProvider.GetDependency<IPolicyRequirementQuery>()
.DidNotReceive()
.GetAsync<AutomaticUserConfirmationPolicyRequirement>(user.Id);
}

[Theory, BitAutoData]
public async Task ConfirmUsersAsync_NoValid(
[ProviderUser(ProviderUserStatusType.Invited)] ProviderUser pu1,
Expand Down Expand Up @@ -800,6 +754,10 @@ public async Task ConfirmUsersAsync_Success(
var userRepository = sutProvider.GetDependency<IUserRepository>();
userRepository.GetManyAsync(default).ReturnsForAnyArgs(new[] { u1, u2, u3 });

sutProvider.GetDependency<IPolicyRequirementQuery>()
.GetAsync<AutomaticUserConfirmationPolicyRequirement>(u2.Id)
.Returns(new AutomaticUserConfirmationPolicyRequirement([]));

var dict = providerUsers.ToDictionary(pu => pu.Id, _ => "key");
var result = await sutProvider.Sut.ConfirmUsersAsync(pu1.ProviderId, dict, user.Id);

Expand All @@ -823,10 +781,6 @@ public async Task ConfirmUsersAsync_WithAutoConfirmEnabledAndPolicyExists_Return
sutProvider.GetDependency<IProviderRepository>().GetByIdAsync(provider.Id).Returns(provider);
sutProvider.GetDependency<IUserRepository>().GetManyAsync([]).ReturnsForAnyArgs([u1]);

sutProvider.GetDependency<IFeatureService>()
.IsEnabled(FeatureFlagKeys.AutomaticConfirmUsers)
.Returns(true);

var policyDetails = new List<PolicyDetails>
{
new() { OrganizationId = Guid.NewGuid(), IsProvider = false }
Expand Down Expand Up @@ -864,10 +818,6 @@ public async Task ConfirmUsersAsync_WithAutoConfirmEnabledButNoPolicyExists_Succ
sutProvider.GetDependency<IProviderRepository>().GetByIdAsync(provider.Id).Returns(provider);
sutProvider.GetDependency<IUserRepository>().GetManyAsync([]).ReturnsForAnyArgs([u1]);

sutProvider.GetDependency<IFeatureService>()
.IsEnabled(FeatureFlagKeys.AutomaticConfirmUsers)
.Returns(true);

var policyRequirement = new AutomaticUserConfirmationPolicyRequirement(new List<PolicyDetails>());
sutProvider.GetDependency<IPolicyRequirementQuery>()
.GetAsync<AutomaticUserConfirmationPolicyRequirement>(u1.Id)
Expand All @@ -887,45 +837,6 @@ await providerUserRepository.Received(1).ReplaceAsync(Arg.Is<ProviderUser>(pu =>
pu.Status == ProviderUserStatusType.Confirmed));
}

[Theory, BitAutoData]
public async Task ConfirmUsersAsync_WithAutoConfirmDisabled_Success(
[ProviderUser(ProviderUserStatusType.Accepted)] ProviderUser pu1, User u1,
Provider provider, User confirmingUser, SutProvider<ProviderService> sutProvider)
{
// Arrange
pu1.ProviderId = provider.Id;
pu1.UserId = u1.Id;
var providerUsers = new[] { pu1 };

var providerUserRepository = sutProvider.GetDependency<IProviderUserRepository>();
providerUserRepository.GetManyAsync([]).ReturnsForAnyArgs(providerUsers);

sutProvider.GetDependency<IProviderRepository>().GetByIdAsync(provider.Id).Returns(provider);
sutProvider.GetDependency<IUserRepository>().GetManyAsync([]).ReturnsForAnyArgs([u1]);

sutProvider.GetDependency<IFeatureService>()
.IsEnabled(FeatureFlagKeys.AutomaticConfirmUsers)
.Returns(false);

var dict = providerUsers.ToDictionary(pu => pu.Id, _ => "key");

// Act
var result = await sutProvider.Sut.ConfirmUsersAsync(pu1.ProviderId, dict, confirmingUser.Id);

// Assert
Assert.Single(result);
Assert.Equal("", result[0].Item2);

// Verify user was confirmed
await providerUserRepository.Received(1).ReplaceAsync(Arg.Is<ProviderUser>(pu =>
pu.Status == ProviderUserStatusType.Confirmed));

// Verify that policy check was never called when feature flag is disabled
await sutProvider.GetDependency<IPolicyRequirementQuery>()
.DidNotReceive()
.GetAsync<AutomaticUserConfirmationPolicyRequirement>(Arg.Any<Guid>());
}

[Theory, BitAutoData]
public async Task SaveUserAsync_UserIdIsInvalid_Throws(ProviderUser providerUser,
SutProvider<ProviderService> sutProvider)
Expand Down
11 changes: 4 additions & 7 deletions src/Admin/AdminConsole/Views/Shared/_OrganizationForm.cshtml
Original file line number Diff line number Diff line change
Expand Up @@ -160,13 +160,10 @@
<input type="checkbox" class="form-check-input" asp-for="UsePhishingBlocker" disabled='@(canEditPlan ? null : "disabled")'>
<label class="form-check-label" asp-for="UsePhishingBlocker"></label>
</div>
@if(FeatureService.IsEnabled(FeatureFlagKeys.AutomaticConfirmUsers))
{
<div class="form-check">
<input type="checkbox" class="form-check-input" asp-for="UseAutomaticUserConfirmation" disabled='@(canEditPlan ? null : "disabled")'>
<label class="form-check-label" asp-for="UseAutomaticUserConfirmation"></label>
</div>
}
<div class="form-check">
<input type="checkbox" class="form-check-input" asp-for="UseAutomaticUserConfirmation" disabled='@(canEditPlan ? null : "disabled")'>
<label class="form-check-label" asp-for="UseAutomaticUserConfirmation"></label>
</div>
</div>
<div class="col-3">
<h3>Password Manager</h3>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -807,7 +807,6 @@ public async Task PatchBulkEnableSecretsManagerAsync(Guid orgId,

[HttpPost("{id}/auto-confirm")]
[Authorize<ManageUsersRequirement>]
[RequireFeature(FeatureFlagKeys.AutomaticConfirmUsers)]
public async Task<IResult> AutomaticallyConfirmOrganizationUserAsync([FromRoute] Guid orgId,
[FromRoute] Guid id,
[FromBody] OrganizationUserConfirmRequestModel model)
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -28,7 +28,6 @@ public class AcceptOrgUserCommand : IAcceptOrgUserCommand
private readonly IUserRepository _userRepository;
private readonly ITwoFactorIsEnabledQuery _twoFactorIsEnabledQuery;
private readonly IDataProtectorTokenFactory<OrgUserInviteTokenable> _orgUserInviteTokenDataFactory;
private readonly IFeatureService _featureService;
private readonly IPolicyRequirementQuery _policyRequirementQuery;
private readonly IAutomaticUserConfirmationPolicyEnforcementValidator _automaticUserConfirmationPolicyEnforcementValidator;
private readonly IPushAutoConfirmNotificationCommand _pushAutoConfirmNotificationCommand;
Expand All @@ -41,7 +40,6 @@ public AcceptOrgUserCommand(
IUserRepository userRepository,
ITwoFactorIsEnabledQuery twoFactorIsEnabledQuery,
IDataProtectorTokenFactory<OrgUserInviteTokenable> orgUserInviteTokenDataFactory,
IFeatureService featureService,
IPolicyRequirementQuery policyRequirementQuery,
IAutomaticUserConfirmationPolicyEnforcementValidator automaticUserConfirmationPolicyEnforcementValidator,
IPushAutoConfirmNotificationCommand pushAutoConfirmNotificationCommand,
Expand All @@ -53,7 +51,6 @@ public AcceptOrgUserCommand(
_userRepository = userRepository;
_twoFactorIsEnabledQuery = twoFactorIsEnabledQuery;
_orgUserInviteTokenDataFactory = orgUserInviteTokenDataFactory;
_featureService = featureService;
_policyRequirementQuery = policyRequirementQuery;
_automaticUserConfirmationPolicyEnforcementValidator = automaticUserConfirmationPolicyEnforcementValidator;
_pushAutoConfirmNotificationCommand = pushAutoConfirmNotificationCommand;
Expand Down Expand Up @@ -169,10 +166,7 @@ public async Task<OrganizationUser> AcceptOrgUserAsync(OrganizationUser orgUser,

var allOrgUsers = await _organizationUserRepository.GetManyByUserAsync(user.Id);

if (_featureService.IsEnabled(FeatureFlagKeys.AutomaticConfirmUsers))
{
await HandleAutomaticUserConfirmationPolicyAsync(orgUser, allOrgUsers, user);
}
await HandleAutomaticUserConfirmationPolicyAsync(orgUser, allOrgUsers, user);

await ValidateSingleOrganizationPolicyAsync(orgUser, allOrgUsers, user);

Expand All @@ -194,10 +188,7 @@ public async Task<OrganizationUser> AcceptOrgUserAsync(OrganizationUser orgUser,
await _mailService.SendOrganizationAcceptedEmailAsync(organization, user.Email, adminEmails);
}

if (_featureService.IsEnabled(FeatureFlagKeys.AutomaticConfirmUsers))
{
await _pushAutoConfirmNotificationCommand.PushAsync(user.Id, orgUser.OrganizationId);
}
await _pushAutoConfirmNotificationCommand.PushAsync(user.Id, orgUser.OrganizationId);

return orgUser;
}
Expand Down
Loading
Loading