Skip to content
Merged
Show file tree
Hide file tree
Changes from 6 commits
Commits
Show all changes
42 commits
Select commit Hold shift + click to select a range
6c7daa6
feat(register): [PM-27084] Account Register Uses New Data Types - Iniโ€ฆ
Patrick-Pimentel-Bitwarden Dec 9, 2025
1535fa3
feat(register): [PM-27084] Account Register Uses New Data Types - Fixโ€ฆ
Patrick-Pimentel-Bitwarden Dec 9, 2025
9000474
fix(register): [PM-27084] Account Register Uses New Data Types - Addeโ€ฆ
Patrick-Pimentel-Bitwarden Dec 10, 2025
d7ddf2e
fix(register): [PM-27084] Account Register Uses New Data Types - Accoโ€ฆ
Patrick-Pimentel-Bitwarden Dec 11, 2025
08f3acd
docs(register): [PM-27084] Account Register Uses New Data Types - Madโ€ฆ
Patrick-Pimentel-Bitwarden Dec 11, 2025
f47dac9
test(register): [PM-27084] Account Register Uses New Data Types - Addโ€ฆ
Patrick-Pimentel-Bitwarden Dec 11, 2025
bb2ba14
Update src/Core/Auth/Models/Api/Request/Accounts/RegisterFinishRequesโ€ฆ
Patrick-Pimentel-Bitwarden Dec 11, 2025
7cb55eb
Merge branch 'main' into auth/pm-27084/register-accepts-new-data-types
Patrick-Pimentel-Bitwarden Dec 11, 2025
b33e1ac
docs(register): [PM-27084] Account Register Uses New Data Types - Addโ€ฆ
Patrick-Pimentel-Bitwarden Dec 11, 2025
c21d7b4
test(register): [PM-27084] Account Register Uses New Data Types - Tesโ€ฆ
Patrick-Pimentel-Bitwarden Dec 16, 2025
aa8e8cc
test(register): [PM-27084] Account Register Uses New Data Types - Fixโ€ฆ
Patrick-Pimentel-Bitwarden Dec 16, 2025
5b2edef
test(register): [PM-27084] Account Register Uses New Data Types - Addโ€ฆ
Patrick-Pimentel-Bitwarden Dec 23, 2025
57f69ad
Merge branch 'main' into auth/pm-27084/register-accepts-new-data-types
Patrick-Pimentel-Bitwarden Dec 23, 2025
4f81d75
Update src/Core/Auth/Models/Api/Request/Accounts/RegisterFinishRequesโ€ฆ
Patrick-Pimentel-Bitwarden Dec 23, 2025
fac1d4b
fix(register): [PM-27084] Account Register Uses New Data Types - Addeโ€ฆ
Patrick-Pimentel-Bitwarden Dec 29, 2025
2d9786e
fix(register): [PM-27084] Account Register Uses New Data Types - Fixeโ€ฆ
Patrick-Pimentel-Bitwarden Dec 29, 2025
cc895d0
fix(register): [PM-27084] Account Register Uses New Data Types - Addeโ€ฆ
Patrick-Pimentel-Bitwarden Dec 29, 2025
4475649
fix(register): [PM-27084] Account Register Uses New Data Types - Remoโ€ฆ
Patrick-Pimentel-Bitwarden Dec 30, 2025
a705ea4
fix(register): [PM-27084] Account Register Uses New Data Types - Shufโ€ฆ
Patrick-Pimentel-Bitwarden Dec 31, 2025
227f3a0
comment(register): [PM-27084] Account Register Uses New Data Types - โ€ฆ
Patrick-Pimentel-Bitwarden Dec 31, 2025
fb54d21
comment(register): [PM-27084] Account Register Uses New Data Types - โ€ฆ
Patrick-Pimentel-Bitwarden Dec 31, 2025
b0cce70
comment(register): [PM-27084] Account Register Uses New Data Types - โ€ฆ
Patrick-Pimentel-Bitwarden Dec 31, 2025
af2f704
comment(register): [PM-27084] Account Register Uses New Data Types - โ€ฆ
Patrick-Pimentel-Bitwarden Dec 31, 2025
015d2ed
comment(register): [PM-27084] Account Register Uses New Data Types - โ€ฆ
Patrick-Pimentel-Bitwarden Dec 31, 2025
67ff0da
Merge branch 'main' into auth/pm-27084/register-accepts-new-data-types
Patrick-Pimentel-Bitwarden Dec 31, 2025
fc507a4
comment(register): [PM-27084] Account Register Uses New Data Types - โ€ฆ
Patrick-Pimentel-Bitwarden Dec 31, 2025
05d8cc5
test(register): [PM-27084] Account Register Uses New Data Types - Fixโ€ฆ
Patrick-Pimentel-Bitwarden Dec 31, 2025
e531ab1
test(register): [PM-27084] Account Register Uses New Data Types - Fixโ€ฆ
Patrick-Pimentel-Bitwarden Dec 31, 2025
28640d0
fix(register): [PM-27084] Account Register Uses New Data Types - Addrโ€ฆ
Patrick-Pimentel-Bitwarden Jan 1, 2026
260b289
fix(register): [PM-27084] Account Register Uses New Data Types - Fixeโ€ฆ
Patrick-Pimentel-Bitwarden Jan 2, 2026
06bf7b8
fix(register): [PM-27084] Account Register Uses New Data Types - Convโ€ฆ
Patrick-Pimentel-Bitwarden Jan 2, 2026
c255e39
fix(register): [PM-27084] Account Register Uses New Data Types - Addeโ€ฆ
Patrick-Pimentel-Bitwarden Jan 2, 2026
3aa0e4c
fix(register): [PM-27084] Account Register Uses New Data Types - Shufโ€ฆ
Patrick-Pimentel-Bitwarden Jan 2, 2026
2111df7
fix(register): [PM-27084] Account Register Uses New Data Types - Remoโ€ฆ
Patrick-Pimentel-Bitwarden Jan 2, 2026
65c0ac9
fix(register): [PM-27084] Account Register Uses New Data Types - Remoโ€ฆ
Patrick-Pimentel-Bitwarden Jan 2, 2026
a5890d2
Merge branch 'main' into auth/pm-27084/register-accepts-new-data-types
Patrick-Pimentel-Bitwarden Jan 2, 2026
b5dadcd
Merge branch 'main' into auth/pm-27084/register-accepts-new-data-types
Patrick-Pimentel-Bitwarden Jan 5, 2026
9e43ca2
test(register): [PM-27084] Account Register Uses New Data Types - Addโ€ฆ
Patrick-Pimentel-Bitwarden Jan 9, 2026
93c9631
test(register): [PM-27084] Account Register Uses New Data Types - Addโ€ฆ
Patrick-Pimentel-Bitwarden Jan 12, 2026
f73904d
Merge remote-tracking branch 'origin' into auth/pm-27084/register-accโ€ฆ
Patrick-Pimentel-Bitwarden Jan 12, 2026
f92d7d2
test(register): [PM-27084] Account Register Uses New Data Types - Addโ€ฆ
Patrick-Pimentel-Bitwarden Jan 12, 2026
6301dbf
test(register): [PM-27084] Account Register Uses New Data Types - Fixโ€ฆ
Patrick-Pimentel-Bitwarden Jan 15, 2026
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
@@ -1,6 +1,6 @@
๏ปฟ#nullable enable
using Bit.Core.Entities;
๏ปฟusing Bit.Core.Entities;
using Bit.Core.Enums;
using Bit.Core.KeyManagement.Models.Data;
using Bit.Core.Utilities;

namespace Bit.Core.Auth.Models.Api.Request.Accounts;
Expand All @@ -21,19 +21,28 @@ public class RegisterFinishRequestModel : IValidatableObject
public required string Email { get; set; }
public string? EmailVerificationToken { get; set; }

public MasterPasswordAuthenticationData? MasterPasswordAuthenticationData { get; set; }
public MasterPasswordUnlockData? MasterPasswordUnlockData { get; set; }

// PM-28143 - Remove line below (made optional during migration to MasterPasswordUnlockData)
[StringLength(1000)]
public required string MasterPasswordHash { get; set; }
public string? MasterPasswordHash { get; set; }

[StringLength(50)]
public string? MasterPasswordHint { get; set; }

public required string UserSymmetricKey { get; set; }
// PM-28143 - Remove line below (made optional during migration to MasterPasswordUnlockData)
public string? UserSymmetricKey { get; set; }

public required KeysRequestModel UserAsymmetricKeys { get; set; }
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

โ„น๏ธ This is outside of the scope of this PR, but fyi, for account registration V2, instead of UserAsymmetricKeys (will become optional for V1 compatibility), we will use AccountKeysRequestModel

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Thank you for sharing that knowledge, helps me understand future changes.


public required KdfType Kdf { get; set; }
public required int KdfIterations { get; set; }
// PM-28143 - Remove line below (made optional during migration to MasterPasswordUnlockData)
public KdfType? Kdf { get; set; }
// PM-28143 - Remove line below (made optional during migration to MasterPasswordUnlockData)
public int? KdfIterations { get; set; }
// PM-28143 - Remove line below
public int? KdfMemory { get; set; }
// PM-28143 - Remove line below
public int? KdfParallelism { get; set; }

public Guid? OrganizationUserId { get; set; }
Expand All @@ -54,11 +63,13 @@ public User ToUser()
{
Email = Email,
MasterPasswordHint = MasterPasswordHint,
Kdf = Kdf,
KdfIterations = KdfIterations,
KdfMemory = KdfMemory,
KdfParallelism = KdfParallelism,
Key = UserSymmetricKey,
Kdf = MasterPasswordUnlockData?.Kdf.KdfType ?? Kdf ?? throw new Exception("KdfType couldn't be found on either the MasterPasswordUnlockData or the Kdf property passed in."),
KdfIterations = MasterPasswordUnlockData?.Kdf.Iterations ?? KdfIterations ?? throw new Exception("KdfIterations couldn't be found on either the MasterPasswordUnlockData or the KdfIterations property passed in."),
KdfMemory = MasterPasswordUnlockData?.Kdf.Memory ?? KdfMemory,
KdfParallelism = MasterPasswordUnlockData?.Kdf.Parallelism ?? KdfParallelism,
// PM-28827 To be added when MasterPasswordSalt is added to the user column
// MasterPasswordSalt = MasterPasswordUnlockData?.Salt ?? Email.ToLower().Trim(),
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

โ“ This might be just my opinon, but this is future proofing, which is not great. Why not leave it to PM-28827, especially considering account registration V2 will be next in priority and i can't predict how this request model will look like later.

Key = MasterPasswordUnlockData?.MasterKeyWrappedUserKey ?? UserSymmetricKey,
};

UserAsymmetricKeys.ToUser(user);
Expand Down Expand Up @@ -95,6 +106,28 @@ public RegisterFinishTokenType GetTokenType()

public IEnumerable<ValidationResult> Validate(ValidationContext validationContext)
{
return KdfSettingsValidator.Validate(Kdf, KdfIterations, KdfMemory, KdfParallelism);
// PM-28143 - Remove line below
var kdf = MasterPasswordUnlockData?.Kdf.KdfType
?? Kdf
?? throw new Exception($"{nameof(Kdf)} not found on RequestModel");

// PM-28143 - Remove line below
var kdfIterations = MasterPasswordUnlockData?.Kdf.Iterations
?? KdfIterations
?? throw new Exception($"{nameof(KdfIterations)} not found on RequestModel");

// PM-28143 - Remove line below
var kdfMemory = MasterPasswordUnlockData?.Kdf.Memory
?? KdfMemory;

// PM-28143 - Remove line below
var kdfParallelism = MasterPasswordUnlockData?.Kdf.Parallelism
?? KdfParallelism;

// PM-28143 - Remove line below in favor of using the unlock data.
return KdfSettingsValidator.Validate(kdf, kdfIterations, kdfMemory, kdfParallelism);

// PM-28143 - Uncomment
// return KdfSettingsValidator.Validate(MasterPasswordUnlockData);
}
}
6 changes: 3 additions & 3 deletions src/Core/Entities/User.cs
Original file line number Diff line number Diff line change
Expand Up @@ -7,8 +7,6 @@
using Bit.Core.Utilities;
using Microsoft.AspNetCore.Identity;

#nullable enable

namespace Bit.Core.Entities;

public class User : ITableObject<Guid>, IStorableSubscriber, IRevisable, ITwoFactorProvidersUser
Expand Down Expand Up @@ -51,7 +49,7 @@ public class User : ITableObject<Guid>, IStorableSubscriber, IRevisable, ITwoFac
public string? Key { get; set; }
/// <summary>
/// The raw public key, without a signature from the user's signature key.
/// </summary>
/// </summary>
public string? PublicKey { get; set; }
/// <summary>
/// User key wrapped private key.
Expand Down Expand Up @@ -102,6 +100,8 @@ public class User : ITableObject<Guid>, IStorableSubscriber, IRevisable, ITwoFac
public DateTime? LastKeyRotationDate { get; set; }
public DateTime? LastEmailChangeDate { get; set; }
public bool VerifyDevices { get; set; } = true;
// PM-28827 Uncomment below line.
// public string? MasterPasswordSalt { get; set; }

public string GetMasterPasswordSalt()
{
Expand Down
29 changes: 29 additions & 0 deletions src/Core/Utilities/KdfSettingsValidator.cs
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@ namespace Bit.Core.Utilities;

public static class KdfSettingsValidator
{
// PM-28143 - Remove below when fixing ticket
public static IEnumerable<ValidationResult> Validate(KdfType kdfType, int kdfIterations, int? kdfMemory, int? kdfParallelism)
{
switch (kdfType)
Expand Down Expand Up @@ -36,6 +37,34 @@ public static IEnumerable<ValidationResult> Validate(KdfType kdfType, int kdfIte
}
}

// PM-28143 - Will be used in the referenced ticket.
public static IEnumerable<ValidationResult> Validate(MasterPasswordUnlockData masterPasswordUnlockData)
{
switch (masterPasswordUnlockData.Kdf.KdfType)
{
case KdfType.PBKDF2_SHA256:
if (!AuthConstants.PBKDF2_ITERATIONS.InsideRange(masterPasswordUnlockData.Kdf.Iterations))
{
yield return new ValidationResult($"KDF iterations must be between {AuthConstants.PBKDF2_ITERATIONS.Min} and {AuthConstants.PBKDF2_ITERATIONS.Max}.");
}
break;
case KdfType.Argon2id:
if (!AuthConstants.ARGON2_ITERATIONS.InsideRange(masterPasswordUnlockData.Kdf.Iterations))
{
yield return new ValidationResult($"Argon2 iterations must be between {AuthConstants.ARGON2_ITERATIONS.Min} and {AuthConstants.ARGON2_ITERATIONS.Max}.");
}
else if (!masterPasswordUnlockData.Kdf.Memory.HasValue || !AuthConstants.ARGON2_MEMORY.InsideRange(masterPasswordUnlockData.Kdf.Memory.Value))
{
yield return new ValidationResult($"Argon2 memory must be between {AuthConstants.ARGON2_MEMORY.Min}mb and {AuthConstants.ARGON2_MEMORY.Max}mb.");
}
else if (!masterPasswordUnlockData.Kdf.Parallelism.HasValue || !AuthConstants.ARGON2_PARALLELISM.InsideRange(masterPasswordUnlockData.Kdf.Parallelism.Value))
{
yield return new ValidationResult($"Argon2 parallelism must be between {AuthConstants.ARGON2_PARALLELISM.Min} and {AuthConstants.ARGON2_PARALLELISM.Max}.");
}
break;
}
}

public static IEnumerable<ValidationResult> Validate(KdfSettings settings)
{
return Validate(settings.KdfType, settings.Iterations, settings.Memory, settings.Parallelism);
Expand Down
83 changes: 62 additions & 21 deletions src/Identity/Controllers/AccountsController.cs
Original file line number Diff line number Diff line change
@@ -1,8 +1,4 @@
๏ปฟ// FIXME: Update this file to be null safe and then delete the line below
#nullable disable

using System.Diagnostics;
using System.Text;
๏ปฟusing System.Text;
using Bit.Core;
using Bit.Core.Auth.Enums;
using Bit.Core.Auth.Models.Api.Request.Accounts;
Expand Down Expand Up @@ -42,7 +38,7 @@
private readonly IFeatureService _featureService;
private readonly IDataProtectorTokenFactory<RegistrationEmailVerificationTokenable> _registrationEmailVerificationTokenDataFactory;

private readonly byte[] _defaultKdfHmacKey = null;
private readonly byte[]? _defaultKdfHmacKey = null;
private static readonly List<UserKdfInformation> _defaultKdfResults =
[
// The first result (index 0) should always return the "normal" default.
Expand Down Expand Up @@ -107,7 +103,7 @@
}

[HttpPost("register/send-verification-email")]
public async Task<IActionResult> PostRegisterSendVerificationEmail([FromBody] RegisterSendVerificationEmailRequestModel model)

Check warning on line 106 in src/Identity/Controllers/AccountsController.cs

View workflow job for this annotation

GitHub Actions / Sonar / Quality scan

ModelState.IsValid should be checked in controller actions. (https://rules.sonarsource.com/csharp/RSPEC-6967)
{
// Only pass fromMarketing if the feature flag is enabled
var isMarketingFeatureEnabled = _featureService.IsEnabled(FeatureFlagKeys.MarketingInitiatedPremiumFlow);
Expand All @@ -125,7 +121,7 @@
}

[HttpPost("register/verification-email-clicked")]
public async Task<IActionResult> PostRegisterVerificationEmailClicked([FromBody] RegisterVerificationEmailClickedRequestModel model)

Check warning on line 124 in src/Identity/Controllers/AccountsController.cs

View workflow job for this annotation

GitHub Actions / Sonar / Quality scan

ModelState.IsValid should be checked in controller actions. (https://rules.sonarsource.com/csharp/RSPEC-6967)
{
var tokenValid = RegistrationEmailVerificationTokenable.ValidateToken(_registrationEmailVerificationTokenDataFactory, model.EmailVerificationToken, model.Email);

Expand All @@ -143,42 +139,87 @@
}

[HttpPost("register/finish")]
public async Task<RegisterFinishResponseModel> PostRegisterFinish([FromBody] RegisterFinishRequestModel model)

Check warning on line 142 in src/Identity/Controllers/AccountsController.cs

View workflow job for this annotation

GitHub Actions / Sonar / Quality scan

ModelState.IsValid should be checked in controller actions. (https://rules.sonarsource.com/csharp/RSPEC-6967)
{
var user = model.ToUser();
User user;

try
{
user = model.ToUser();
}
catch (Exception e)
{
throw new BadRequestException(e.Message);
}

// Users will either have an emailed token or an email verification token - not both.
IdentityResult identityResult = null;
IdentityResult? identityResult = null;

// PM-28143 - Just use the MasterPasswordAuthenticationData.MasterPasswordAuthenticationHash
string masterPasswordHash = model.MasterPasswordAuthenticationData?.MasterPasswordAuthenticationHash
?? model.MasterPasswordHash ?? throw new BadRequestException("MasterPasswordHash couldn't be found on either the MasterPasswordAuthenticationData or the MasterPasswordHash property passed in.");

switch (model.GetTokenType())
{
case RegisterFinishTokenType.EmailVerification:
identityResult =
await _registerUserCommand.RegisterUserViaEmailVerificationToken(user, model.MasterPasswordHash,
model.EmailVerificationToken);
if (string.IsNullOrEmpty(model.EmailVerificationToken))
throw new BadRequestException("Email verification token absent when processing register/finish.");

identityResult = await _registerUserCommand.RegisterUserViaEmailVerificationToken(
user,
masterPasswordHash,
model.EmailVerificationToken);
return ProcessRegistrationResult(identityResult, user);
case RegisterFinishTokenType.OrganizationInvite:
identityResult = await _registerUserCommand.RegisterUserViaOrganizationInviteToken(user, model.MasterPasswordHash,
model.OrgInviteToken, model.OrganizationUserId);

case RegisterFinishTokenType.OrganizationInvite:
if (string.IsNullOrEmpty(model.OrgInviteToken))
throw new BadRequestException("Organization invite token absent when processing register/finish.");

identityResult = await _registerUserCommand.RegisterUserViaOrganizationInviteToken(
user,
masterPasswordHash,
model.OrgInviteToken,
model.OrganizationUserId);
return ProcessRegistrationResult(identityResult, user);

case RegisterFinishTokenType.OrgSponsoredFreeFamilyPlan:
identityResult = await _registerUserCommand.RegisterUserViaOrganizationSponsoredFreeFamilyPlanInviteToken(user, model.MasterPasswordHash, model.OrgSponsoredFreeFamilyPlanToken);
if (string.IsNullOrEmpty(model.OrgSponsoredFreeFamilyPlanToken))
throw new BadRequestException("Organization sponsored free family plan token absent when processing register/finish.");

identityResult = await _registerUserCommand.RegisterUserViaOrganizationSponsoredFreeFamilyPlanInviteToken(
user,
masterPasswordHash,
model.OrgSponsoredFreeFamilyPlanToken);
return ProcessRegistrationResult(identityResult, user);

case RegisterFinishTokenType.EmergencyAccessInvite:
Debug.Assert(model.AcceptEmergencyAccessId.HasValue);
identityResult = await _registerUserCommand.RegisterUserViaAcceptEmergencyAccessInviteToken(user, model.MasterPasswordHash,
model.AcceptEmergencyAccessInviteToken, model.AcceptEmergencyAccessId.Value);
if (string.IsNullOrEmpty(model.AcceptEmergencyAccessInviteToken))
throw new BadRequestException("Accept emergency access invite token absent when processing register/finish.");

if (model.AcceptEmergencyAccessId == null || model.AcceptEmergencyAccessId == Guid.Empty)
throw new BadRequestException("Accept emergency access id absent when processing register/finish.");

identityResult = await _registerUserCommand.RegisterUserViaAcceptEmergencyAccessInviteToken(
user,
masterPasswordHash,
model.AcceptEmergencyAccessInviteToken,
model.AcceptEmergencyAccessId.Value);
return ProcessRegistrationResult(identityResult, user);

case RegisterFinishTokenType.ProviderInvite:
Debug.Assert(model.ProviderUserId.HasValue);
identityResult = await _registerUserCommand.RegisterUserViaProviderInviteToken(user, model.MasterPasswordHash,
model.ProviderInviteToken, model.ProviderUserId.Value);
if (string.IsNullOrEmpty(model.ProviderInviteToken))
throw new BadRequestException("Provider invite token absent when processing register/finish.");

if (model.ProviderUserId == null || model.ProviderUserId == Guid.Empty)
throw new BadRequestException("Provider user id absent when processing register/finish.");

identityResult = await _registerUserCommand.RegisterUserViaProviderInviteToken(
user,
masterPasswordHash,
model.ProviderInviteToken,
model.ProviderUserId.Value);
return ProcessRegistrationResult(identityResult, user);

default:
throw new BadRequestException("Invalid registration finish request");
}
Expand All @@ -202,7 +243,7 @@
[HttpPost("prelogin")]
[Obsolete("Migrating to use a more descriptive endpoint that would support different types of prelogins. " +
"Use prelogin/password instead. This endpoint has no EOL at the time of writing.")]
public async Task<PasswordPreloginResponseModel> PostPrelogin([FromBody] PasswordPreloginRequestModel model)

Check warning on line 246 in src/Identity/Controllers/AccountsController.cs

View workflow job for this annotation

GitHub Actions / Sonar / Quality scan

ModelState.IsValid should be checked in controller actions. (https://rules.sonarsource.com/csharp/RSPEC-6967)
{
// Same as PostPasswordPrelogin to maintain compatibility. Do not make changes in this function body,
// only make changes in MakePasswordPreloginCall
Expand All @@ -213,7 +254,7 @@
// cannot handle two of the same post attributes on the same function call. That is why there is a
// PostPrelogin and the more appropriate PostPasswordPrelogin.
[HttpPost("prelogin/password")]
public async Task<PasswordPreloginResponseModel> PostPasswordPrelogin([FromBody] PasswordPreloginRequestModel model)

Check warning on line 257 in src/Identity/Controllers/AccountsController.cs

View workflow job for this annotation

GitHub Actions / Sonar / Quality scan

ModelState.IsValid should be checked in controller actions. (https://rules.sonarsource.com/csharp/RSPEC-6967)
{
// Same as PostPrelogin to maintain backwards compatibility. Do not make changes in this function body,
// only make changes in MakePasswordPreloginCall
Expand Down
Loading
Loading