From 7d8df767cde94df8bffa8efe042647c76314d3d4 Mon Sep 17 00:00:00 2001 From: Jared Snider <116684653+JaredSnider-Bitwarden@users.noreply.github.com> Date: Thu, 12 Sep 2024 15:24:47 -0400 Subject: [PATCH] Auth/PM-11945 - Registration with Email Verification - Fix Org Sponsored Free Family Plan not working (#4772) * PM-11945 - Rename RegisterUserWithOptionalOrgInvite to RegisterUserViaOrgInvite as the org invite isn't optional in the function - just the overall process of registration. * PM-11945 - Yet another rename * PM-11945 - Wire up call to RegisterUserViaOrgSponsoredFreeFamilyPlanInviteToken and test. * PM-11945 - RegisterUserCommandTests - test new method * PM-11949 - Rename tests * PM-11945 - AccountsControllerTests.cs - add integration test for RegistrationWithEmailVerification_WithOrgSponsoredFreeFamilyPlanInviteToken_Succeeds * PM-11945 - Adjust naming per PR feedback to match docs. * PM-11945 - More renaming --- .../Accounts/RegisterFinishRequestModel.cs | 1 + .../Registration/IRegisterUserCommand.cs | 4 +- .../Implementations/RegisterUserCommand.cs | 61 ++++++++++-- .../Controllers/AccountsController.cs | 11 ++- .../Registration/RegisterUserCommandTests.cs | 92 +++++++++++++++++-- .../Controllers/AccountsControllerTests.cs | 79 ++++++++++++++++ .../Controllers/AccountsControllerTests.cs | 12 +-- 7 files changed, 231 insertions(+), 29 deletions(-) diff --git a/src/Core/Auth/Models/Api/Request/Accounts/RegisterFinishRequestModel.cs b/src/Core/Auth/Models/Api/Request/Accounts/RegisterFinishRequestModel.cs index 87a0cacdc..d9b3e10da 100644 --- a/src/Core/Auth/Models/Api/Request/Accounts/RegisterFinishRequestModel.cs +++ b/src/Core/Auth/Models/Api/Request/Accounts/RegisterFinishRequestModel.cs @@ -31,6 +31,7 @@ public class RegisterFinishRequestModel : IValidatableObject public Guid? OrganizationUserId { get; set; } public string? OrgInviteToken { get; set; } + public string? OrgSponsoredFreeFamilyPlanToken { get; set; } public User ToUser() { diff --git a/src/Core/Auth/UserFeatures/Registration/IRegisterUserCommand.cs b/src/Core/Auth/UserFeatures/Registration/IRegisterUserCommand.cs index 259dfd759..bd742de8b 100644 --- a/src/Core/Auth/UserFeatures/Registration/IRegisterUserCommand.cs +++ b/src/Core/Auth/UserFeatures/Registration/IRegisterUserCommand.cs @@ -24,7 +24,7 @@ public interface IRegisterUserCommand /// The org invite token sent to the user via email /// The associated org user guid that was created at the time of invite /// - public Task RegisterUserWithOptionalOrgInvite(User user, string masterPasswordHash, string orgInviteToken, Guid? orgUserId); + public Task RegisterUserViaOrganizationInviteToken(User user, string masterPasswordHash, string orgInviteToken, Guid? orgUserId); /// /// Creates a new user with a given master password hash, sends a welcome email, and raises the signup reference event. @@ -37,4 +37,6 @@ public interface IRegisterUserCommand /// public Task RegisterUserViaEmailVerificationToken(User user, string masterPasswordHash, string emailVerificationToken); + public Task RegisterUserViaOrganizationSponsoredFreeFamilyPlanInviteToken(User user, string masterPasswordHash, string orgSponsoredFreeFamilyPlanInviteToken); + } diff --git a/src/Core/Auth/UserFeatures/Registration/Implementations/RegisterUserCommand.cs b/src/Core/Auth/UserFeatures/Registration/Implementations/RegisterUserCommand.cs index 9d6a3bb3b..937a44e82 100644 --- a/src/Core/Auth/UserFeatures/Registration/Implementations/RegisterUserCommand.cs +++ b/src/Core/Auth/UserFeatures/Registration/Implementations/RegisterUserCommand.cs @@ -6,6 +6,7 @@ using Bit.Core.Auth.Models.Business.Tokenables; using Bit.Core.Context; using Bit.Core.Entities; using Bit.Core.Exceptions; +using Bit.Core.OrganizationFeatures.OrganizationSponsorships.FamiliesForEnterprise.Interfaces; using Bit.Core.Repositories; using Bit.Core.Services; using Bit.Core.Settings; @@ -37,6 +38,8 @@ public class RegisterUserCommand : IRegisterUserCommand private readonly IUserService _userService; private readonly IMailService _mailService; + private readonly IValidateRedemptionTokenCommand _validateRedemptionTokenCommand; + private readonly string _disabledUserRegistrationExceptionMsg = "Open registration has been disabled by the system administrator."; public RegisterUserCommand( @@ -49,7 +52,8 @@ public class RegisterUserCommand : IRegisterUserCommand IDataProtectorTokenFactory registrationEmailVerificationTokenDataFactory, ICurrentContext currentContext, IUserService userService, - IMailService mailService + IMailService mailService, + IValidateRedemptionTokenCommand validateRedemptionTokenCommand ) { _globalSettings = globalSettings; @@ -66,6 +70,7 @@ public class RegisterUserCommand : IRegisterUserCommand _userService = userService; _mailService = mailService; + _validateRedemptionTokenCommand = validateRedemptionTokenCommand; } @@ -81,8 +86,7 @@ public class RegisterUserCommand : IRegisterUserCommand return result; } - - public async Task RegisterUserWithOptionalOrgInvite(User user, string masterPasswordHash, + public async Task RegisterUserViaOrganizationInviteToken(User user, string masterPasswordHash, string orgInviteToken, Guid? orgUserId) { ValidateOrgInviteToken(orgInviteToken, orgUserId, user); @@ -233,13 +237,8 @@ public class RegisterUserCommand : IRegisterUserCommand public async Task RegisterUserViaEmailVerificationToken(User user, string masterPasswordHash, string emailVerificationToken) { - // We validate open registration on send of initial email and here b/c a user could technically start the - // account creation process while open registration is enabled and then finish it after it has been - // disabled by the self hosted admin. - if (_globalSettings.DisableUserRegistration) - { - throw new BadRequestException(_disabledUserRegistrationExceptionMsg); - } + + ValidateOpenRegistrationAllowed(); var tokenable = ValidateRegistrationEmailVerificationTokenable(emailVerificationToken, user.Email); @@ -260,6 +259,48 @@ public class RegisterUserCommand : IRegisterUserCommand return result; } + public async Task RegisterUserViaOrganizationSponsoredFreeFamilyPlanInviteToken(User user, string masterPasswordHash, + string orgSponsoredFreeFamilyPlanInviteToken) + { + ValidateOpenRegistrationAllowed(); + await ValidateOrgSponsoredFreeFamilyPlanInviteToken(orgSponsoredFreeFamilyPlanInviteToken, user.Email); + + user.EmailVerified = true; + user.ApiKey = CoreHelpers.SecureRandomString(30); // API key can't be null. + + var result = await _userService.CreateUserAsync(user, masterPasswordHash); + if (result == IdentityResult.Success) + { + await _mailService.SendWelcomeEmailAsync(user); + await _referenceEventService.RaiseEventAsync(new ReferenceEvent(ReferenceEventType.Signup, user, _currentContext)); + } + + return result; + } + + private void ValidateOpenRegistrationAllowed() + { + // We validate open registration on send of initial email and here b/c a user could technically start the + // account creation process while open registration is enabled and then finish it after it has been + // disabled by the self hosted admin.Ï + if (_globalSettings.DisableUserRegistration) + { + throw new BadRequestException(_disabledUserRegistrationExceptionMsg); + } + } + + private async Task ValidateOrgSponsoredFreeFamilyPlanInviteToken(string orgSponsoredFreeFamilyPlanInviteToken, string userEmail) + { + var (valid, sponsorship) = await _validateRedemptionTokenCommand.ValidateRedemptionTokenAsync(orgSponsoredFreeFamilyPlanInviteToken, userEmail); + + if (!valid) + { + throw new BadRequestException("Invalid org sponsored free family plan token."); + } + + } + + private RegistrationEmailVerificationTokenable ValidateRegistrationEmailVerificationTokenable(string emailVerificationToken, string userEmail) { _registrationEmailVerificationTokenDataFactory.TryUnprotect(emailVerificationToken, out var tokenable); diff --git a/src/Identity/Controllers/AccountsController.cs b/src/Identity/Controllers/AccountsController.cs index c3cad4a4a..74a58ee2f 100644 --- a/src/Identity/Controllers/AccountsController.cs +++ b/src/Identity/Controllers/AccountsController.cs @@ -75,7 +75,7 @@ public class AccountsController : Controller public async Task PostRegister([FromBody] RegisterRequestModel model) { var user = model.ToUser(); - var identityResult = await _registerUserCommand.RegisterUserWithOptionalOrgInvite(user, model.MasterPasswordHash, + var identityResult = await _registerUserCommand.RegisterUserViaOrganizationInviteToken(user, model.MasterPasswordHash, model.Token, model.OrganizationUserId); // delaysEnabled false is only for the new registration with email verification process return await ProcessRegistrationResult(identityResult, user, delaysEnabled: true); @@ -151,12 +151,19 @@ public class AccountsController : Controller if (!string.IsNullOrEmpty(model.OrgInviteToken) && model.OrganizationUserId.HasValue) { - identityResult = await _registerUserCommand.RegisterUserWithOptionalOrgInvite(user, model.MasterPasswordHash, + identityResult = await _registerUserCommand.RegisterUserViaOrganizationInviteToken(user, model.MasterPasswordHash, model.OrgInviteToken, model.OrganizationUserId); return await ProcessRegistrationResult(identityResult, user, delaysEnabled); } + if (!string.IsNullOrEmpty(model.OrgSponsoredFreeFamilyPlanToken)) + { + identityResult = await _registerUserCommand.RegisterUserViaOrganizationSponsoredFreeFamilyPlanInviteToken(user, model.MasterPasswordHash, model.OrgSponsoredFreeFamilyPlanToken); + + return await ProcessRegistrationResult(identityResult, user, delaysEnabled); + } + identityResult = await _registerUserCommand.RegisterUserViaEmailVerificationToken(user, model.MasterPasswordHash, model.EmailVerificationToken); return await ProcessRegistrationResult(identityResult, user, delaysEnabled); diff --git a/test/Core.Test/Auth/UserFeatures/Registration/RegisterUserCommandTests.cs b/test/Core.Test/Auth/UserFeatures/Registration/RegisterUserCommandTests.cs index d61a34541..60db00ab9 100644 --- a/test/Core.Test/Auth/UserFeatures/Registration/RegisterUserCommandTests.cs +++ b/test/Core.Test/Auth/UserFeatures/Registration/RegisterUserCommandTests.cs @@ -7,6 +7,7 @@ using Bit.Core.Auth.Models.Business.Tokenables; using Bit.Core.Auth.UserFeatures.Registration.Implementations; using Bit.Core.Entities; using Bit.Core.Exceptions; +using Bit.Core.OrganizationFeatures.OrganizationSponsorships.FamiliesForEnterprise.Interfaces; using Bit.Core.Repositories; using Bit.Core.Services; using Bit.Core.Settings; @@ -84,12 +85,11 @@ public class RegisterUserCommandTests .RaiseEventAsync(Arg.Any()); } - // RegisterUserWithOptionalOrgInvite tests - + // RegisterUserWithOrganizationInviteToken tests // Simple happy path test [Theory] [BitAutoData] - public async Task RegisterUserWithOptionalOrgInvite_NoOrgInviteOrOrgUserIdOrReferenceData_Succeeds( + public async Task RegisterUserViaOrganizationInviteToken_NoOrgInviteOrOrgUserIdOrReferenceData_Succeeds( SutProvider sutProvider, User user, string masterPasswordHash) { // Arrange @@ -100,7 +100,7 @@ public class RegisterUserCommandTests .Returns(IdentityResult.Success); // Act - var result = await sutProvider.Sut.RegisterUserWithOptionalOrgInvite(user, masterPasswordHash, null, null); + var result = await sutProvider.Sut.RegisterUserViaOrganizationInviteToken(user, masterPasswordHash, null, null); // Assert Assert.True(result.Succeeded); @@ -119,7 +119,7 @@ public class RegisterUserCommandTests [BitAutoData(false, null)] [BitAutoData(true, "sampleInitiationPath")] [BitAutoData(true, "Secrets Manager trial")] - public async Task RegisterUserWithOptionalOrgInvite_ComplexHappyPath_Succeeds(bool addUserReferenceData, string initiationPath, + public async Task RegisterUserViaOrganizationInviteToken_ComplexHappyPath_Succeeds(bool addUserReferenceData, string initiationPath, SutProvider sutProvider, User user, string masterPasswordHash, OrganizationUser orgUser, string orgInviteToken, Guid orgUserId, Policy twoFactorPolicy) { // Arrange @@ -158,7 +158,7 @@ public class RegisterUserCommandTests user.ReferenceData = addUserReferenceData ? $"{{\"initiationPath\":\"{initiationPath}\"}}" : null; // Act - var result = await sutProvider.Sut.RegisterUserWithOptionalOrgInvite(user, masterPasswordHash, orgInviteToken, orgUserId); + var result = await sutProvider.Sut.RegisterUserViaOrganizationInviteToken(user, masterPasswordHash, orgInviteToken, orgUserId); // Assert await sutProvider.GetDependency() @@ -227,7 +227,7 @@ public class RegisterUserCommandTests [BitAutoData("invalidOrgInviteToken")] [BitAutoData("nullOrgInviteToken")] [BitAutoData("nullOrgUserId")] - public async Task RegisterUserWithOptionalOrgInvite_MissingOrInvalidOrgInviteDataWithDisabledOpenRegistration_ThrowsBadRequestException(string scenario, + public async Task RegisterUserViaOrganizationInviteToken_MissingOrInvalidOrgInviteDataWithDisabledOpenRegistration_ThrowsBadRequestException(string scenario, SutProvider sutProvider, User user, string masterPasswordHash, OrganizationUser orgUser, string orgInviteToken, Guid? orgUserId) { // Arrange @@ -257,7 +257,7 @@ public class RegisterUserCommandTests } // Act & Assert - var exception = await Assert.ThrowsAsync(() => sutProvider.Sut.RegisterUserWithOptionalOrgInvite(user, masterPasswordHash, orgInviteToken, orgUserId)); + var exception = await Assert.ThrowsAsync(() => sutProvider.Sut.RegisterUserViaOrganizationInviteToken(user, masterPasswordHash, orgInviteToken, orgUserId)); Assert.Equal("Open registration has been disabled by the system administrator.", exception.Message); } @@ -265,7 +265,7 @@ public class RegisterUserCommandTests [BitAutoData("invalidOrgInviteToken")] [BitAutoData("nullOrgInviteToken")] [BitAutoData("nullOrgUserId")] - public async Task RegisterUserWithOptionalOrgInvite_MissingOrInvalidOrgInviteDataWithEnabledOpenRegistration_ThrowsBadRequestException(string scenario, + public async Task RegisterUserViaOrganizationInviteToken_MissingOrInvalidOrgInviteDataWithEnabledOpenRegistration_ThrowsBadRequestException(string scenario, SutProvider sutProvider, User user, string masterPasswordHash, OrganizationUser orgUser, string orgInviteToken, Guid? orgUserId) { // Arrange @@ -307,7 +307,7 @@ public class RegisterUserCommandTests // Act var exception = await Assert.ThrowsAsync(() => - sutProvider.Sut.RegisterUserWithOptionalOrgInvite(user, masterPasswordHash, orgInviteToken, orgUserId)); + sutProvider.Sut.RegisterUserViaOrganizationInviteToken(user, masterPasswordHash, orgInviteToken, orgUserId)); Assert.Equal(expectedErrorMessage, exception.Message); } @@ -381,4 +381,76 @@ public class RegisterUserCommandTests } + + + // RegisterUserViaOrganizationSponsoredFreeFamilyPlanInviteToken + + + [Theory] + [BitAutoData] + public async Task RegisterUserViaOrganizationSponsoredFreeFamilyPlanInviteToken_Succeeds(SutProvider sutProvider, User user, string masterPasswordHash, + string orgSponsoredFreeFamilyPlanInviteToken) + { + // Arrange + sutProvider.GetDependency() + .ValidateRedemptionTokenAsync(orgSponsoredFreeFamilyPlanInviteToken, user.Email) + .Returns((true, new OrganizationSponsorship())); + + sutProvider.GetDependency() + .CreateUserAsync(user, masterPasswordHash) + .Returns(IdentityResult.Success); + + // Act + var result = await sutProvider.Sut.RegisterUserViaOrganizationSponsoredFreeFamilyPlanInviteToken(user, masterPasswordHash, orgSponsoredFreeFamilyPlanInviteToken); + + // Assert + Assert.True(result.Succeeded); + + await sutProvider.GetDependency() + .Received(1) + .CreateUserAsync(Arg.Is(u => u.Name == user.Name && u.EmailVerified == true && u.ApiKey != null), masterPasswordHash); + + await sutProvider.GetDependency() + .Received(1) + .SendWelcomeEmailAsync(user); + + await sutProvider.GetDependency() + .Received(1) + .RaiseEventAsync(Arg.Is(refEvent => refEvent.Type == ReferenceEventType.Signup)); + } + + [Theory] + [BitAutoData] + public async Task RegisterUserViaOrganizationSponsoredFreeFamilyPlanInviteToken_InvalidToken_ThrowsBadRequestException(SutProvider sutProvider, User user, + string masterPasswordHash, string orgSponsoredFreeFamilyPlanInviteToken) + { + // Arrange + sutProvider.GetDependency() + .ValidateRedemptionTokenAsync(orgSponsoredFreeFamilyPlanInviteToken, user.Email) + .Returns((false, new OrganizationSponsorship())); + + // Act & Assert + var result = await Assert.ThrowsAsync(() => + sutProvider.Sut.RegisterUserViaOrganizationSponsoredFreeFamilyPlanInviteToken(user, masterPasswordHash, orgSponsoredFreeFamilyPlanInviteToken)); + Assert.Equal("Invalid org sponsored free family plan token.", result.Message); + + } + + [Theory] + [BitAutoData] + public async Task RegisterUserViaOrganizationSponsoredFreeFamilyPlanInviteToken_DisabledOpenRegistration_ThrowsBadRequestException(SutProvider sutProvider, User user, + string masterPasswordHash, string orgSponsoredFreeFamilyPlanInviteToken) + { + // Arrange + sutProvider.GetDependency() + .DisableUserRegistration = true; + + // Act & Assert + var result = await Assert.ThrowsAsync(() => + sutProvider.Sut.RegisterUserViaOrganizationSponsoredFreeFamilyPlanInviteToken(user, masterPasswordHash, orgSponsoredFreeFamilyPlanInviteToken)); + Assert.Equal("Open registration has been disabled by the system administrator.", result.Message); + + } + + } diff --git a/test/Identity.IntegrationTest/Controllers/AccountsControllerTests.cs b/test/Identity.IntegrationTest/Controllers/AccountsControllerTests.cs index c5f10aacb..dcf2740c0 100644 --- a/test/Identity.IntegrationTest/Controllers/AccountsControllerTests.cs +++ b/test/Identity.IntegrationTest/Controllers/AccountsControllerTests.cs @@ -4,6 +4,7 @@ using Bit.Core.Auth.Models.Api.Request.Accounts; using Bit.Core.Auth.Models.Business.Tokenables; using Bit.Core.Entities; using Bit.Core.Enums; +using Bit.Core.Models.Business.Tokenables; using Bit.Core.Repositories; using Bit.Core.Services; using Bit.Core.Tokens; @@ -322,6 +323,84 @@ public class AccountsControllerTests : IClassFixture Assert.Equal(kdfParallelism, user.KdfParallelism); } + + [Theory, BitAutoData] + public async Task RegistrationWithEmailVerification_WithOrgSponsoredFreeFamilyPlanInviteToken_Succeeds( + [StringLength(1000)] string masterPasswordHash, [StringLength(50)] string masterPasswordHint, string userSymmetricKey, + KeysRequestModel userAsymmetricKeys, int kdfMemory, int kdfParallelism, Guid orgSponsorshipId) + { + + // Localize factory to just this test. + var localFactory = new IdentityApplicationFactory(); + + // Hardcoded, valid org sponsored free family plan invite token data + var email = "jsnider+local10000008@bitwarden.com"; + var orgSponsoredFreeFamilyPlanToken = "BWOrganizationSponsorship_CfDJ8HFsgwUNr89EtnCal5H72cx11wdMdD5_FSNMJoXJKp9migo8ZXi2Qx8GOM2b8IccesQEvZxzX_VDvhaaFi1NZc7-5bdadsfaPiwvzy28qwaW5-iF72vncmixArxKt8_FrJCqvn-5Yh45DvUWeOUBl1fPPx6LB4lgf6DcFkFZaHKOxIEywkFWEX9IWsLAfBfhU9K7AYZ02kxLRgXDK_eH3SKY0luoyUbRLBJRq1J9WnAQNcPLx9GOywQDUGRNvQGYmrzpAdq8y3MgUby_XD2NBf4-Vfr_0DIYPlGVJz0Ab1CwKbQ5G9vTXrFbbHQni40GVgohTq6WeVwk-PBMW9kjBw2rHO8QzWUb4whn831y-dEC"; + + var orgSponsorship = new OrganizationSponsorship + { + Id = orgSponsorshipId, + PlanSponsorshipType = PlanSponsorshipType.FamiliesForEnterprise, + OfferedToEmail = email + }; + + var orgSponsorshipOfferTokenable = new OrganizationSponsorshipOfferTokenable(orgSponsorship) { }; + + localFactory.SubstituteService>(dataProtectorTokenFactory => + { + dataProtectorTokenFactory.TryUnprotect(Arg.Is(orgSponsoredFreeFamilyPlanToken), out Arg.Any()) + .Returns(callInfo => + { + callInfo[1] = orgSponsorshipOfferTokenable; + return true; + }); + }); + + localFactory.SubstituteService(organizationSponsorshipRepository => + { + organizationSponsorshipRepository.GetByIdAsync(orgSponsorshipId) + .Returns(orgSponsorship); + }); + + var registerFinishReqModel = new RegisterFinishRequestModel + { + Email = email, + MasterPasswordHash = masterPasswordHash, + MasterPasswordHint = masterPasswordHint, + OrgSponsoredFreeFamilyPlanToken = orgSponsoredFreeFamilyPlanToken, + Kdf = KdfType.PBKDF2_SHA256, + KdfIterations = AuthConstants.PBKDF2_ITERATIONS.Default, + UserSymmetricKey = userSymmetricKey, + UserAsymmetricKeys = userAsymmetricKeys, + KdfMemory = kdfMemory, + KdfParallelism = kdfParallelism + }; + + var postRegisterFinishHttpContext = await localFactory.PostRegisterFinishAsync(registerFinishReqModel); + + Assert.Equal(StatusCodes.Status200OK, postRegisterFinishHttpContext.Response.StatusCode); + + var database = localFactory.GetDatabaseContext(); + var user = await database.Users + .SingleAsync(u => u.Email == email); + + Assert.NotNull(user); + + // Assert user properties match the request model + Assert.Equal(email, user.Email); + Assert.NotEqual(masterPasswordHash, user.MasterPassword); // We execute server side hashing + Assert.NotNull(user.MasterPassword); + Assert.Equal(masterPasswordHint, user.MasterPasswordHint); + Assert.Equal(userSymmetricKey, user.Key); + Assert.Equal(userAsymmetricKeys.EncryptedPrivateKey, user.PrivateKey); + Assert.Equal(userAsymmetricKeys.PublicKey, user.PublicKey); + Assert.Equal(KdfType.PBKDF2_SHA256, user.Kdf); + Assert.Equal(AuthConstants.PBKDF2_ITERATIONS.Default, user.KdfIterations); + Assert.Equal(kdfMemory, user.KdfMemory); + Assert.Equal(kdfParallelism, user.KdfParallelism); + } + + [Theory, BitAutoData] public async Task PostRegisterVerificationEmailClicked_Success( [Required, StringLength(20)] string name, diff --git a/test/Identity.Test/Controllers/AccountsControllerTests.cs b/test/Identity.Test/Controllers/AccountsControllerTests.cs index 3abaa8a0b..8acebbabe 100644 --- a/test/Identity.Test/Controllers/AccountsControllerTests.cs +++ b/test/Identity.Test/Controllers/AccountsControllerTests.cs @@ -111,7 +111,7 @@ public class AccountsControllerTests : IDisposable var passwordHash = "abcdef"; var token = "123456"; var userGuid = new Guid(); - _registerUserCommand.RegisterUserWithOptionalOrgInvite(Arg.Any(), passwordHash, token, userGuid) + _registerUserCommand.RegisterUserViaOrganizationInviteToken(Arg.Any(), passwordHash, token, userGuid) .Returns(Task.FromResult(IdentityResult.Success)); var request = new RegisterRequestModel { @@ -125,7 +125,7 @@ public class AccountsControllerTests : IDisposable await _sut.PostRegister(request); - await _registerUserCommand.Received(1).RegisterUserWithOptionalOrgInvite(Arg.Any(), passwordHash, token, userGuid); + await _registerUserCommand.Received(1).RegisterUserViaOrganizationInviteToken(Arg.Any(), passwordHash, token, userGuid); } [Fact] @@ -134,7 +134,7 @@ public class AccountsControllerTests : IDisposable var passwordHash = "abcdef"; var token = "123456"; var userGuid = new Guid(); - _registerUserCommand.RegisterUserWithOptionalOrgInvite(Arg.Any(), passwordHash, token, userGuid) + _registerUserCommand.RegisterUserViaOrganizationInviteToken(Arg.Any(), passwordHash, token, userGuid) .Returns(Task.FromResult(IdentityResult.Failed())); var request = new RegisterRequestModel { @@ -219,7 +219,7 @@ public class AccountsControllerTests : IDisposable var user = model.ToUser(); - _registerUserCommand.RegisterUserWithOptionalOrgInvite(Arg.Any(), masterPasswordHash, orgInviteToken, organizationUserId) + _registerUserCommand.RegisterUserViaOrganizationInviteToken(Arg.Any(), masterPasswordHash, orgInviteToken, organizationUserId) .Returns(Task.FromResult(IdentityResult.Success)); // Act @@ -227,7 +227,7 @@ public class AccountsControllerTests : IDisposable // Assert Assert.NotNull(result); - await _registerUserCommand.Received(1).RegisterUserWithOptionalOrgInvite(Arg.Is(u => + await _registerUserCommand.Received(1).RegisterUserViaOrganizationInviteToken(Arg.Is(u => u.Email == user.Email && u.MasterPasswordHint == user.MasterPasswordHint && u.Kdf == user.Kdf && @@ -270,7 +270,7 @@ public class AccountsControllerTests : IDisposable new IdentityError { Code = duplicateUserEmailErrorCode, Description = duplicateUserEmailErrorDesc } ); - _registerUserCommand.RegisterUserWithOptionalOrgInvite(Arg.Is(u => + _registerUserCommand.RegisterUserViaOrganizationInviteToken(Arg.Is(u => u.Email == user.Email && u.MasterPasswordHint == user.MasterPasswordHint && u.Kdf == user.Kdf &&