1
0
mirror of https://github.com/bitwarden/server.git synced 2025-06-30 07:36:14 -05:00

PM-6675 - Remove old registration endpoint (#5585)

* feat : remove old registration endpoint

* fix: update integration test user registration to match current registration; We need to keep the IRegistrationCommand.RegisterUser method to JIT user.

* fix: updating accounts/profile tests to match current implementations
This commit is contained in:
Ike
2025-04-16 15:46:49 -04:00
committed by GitHub
parent 01a08c5814
commit 1399b1417e
14 changed files with 457 additions and 432 deletions

View File

@ -8,10 +8,8 @@ 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;
using Bit.Core.Utilities;
using Bit.Identity.Models.Request.Accounts;
using Bit.IntegrationTestCommon.Factories;
using Bit.Test.Common.AutoFixture.Attributes;
using Microsoft.AspNetCore.DataProtection;
@ -31,24 +29,6 @@ public class AccountsControllerTests : IClassFixture<IdentityApplicationFactory>
_factory = factory;
}
[Fact]
public async Task PostRegister_Success()
{
var context = await _factory.RegisterAsync(new RegisterRequestModel
{
Email = "test+register@email.com",
MasterPasswordHash = "master_password_hash"
});
Assert.Equal(StatusCodes.Status200OK, context.Response.StatusCode);
var database = _factory.GetDatabaseContext();
var user = await database.Users
.SingleAsync(u => u.Email == "test+register@email.com");
Assert.NotNull(user);
}
[Theory]
[BitAutoData("invalidEmail")]
[BitAutoData("")]
@ -154,6 +134,7 @@ public class AccountsControllerTests : IClassFixture<IdentityApplicationFactory>
}
[Theory, BitAutoData]
// marketing emails can stay at top level
public async Task RegistrationWithEmailVerification_WithEmailVerificationToken_Succeeds([Required] string name, bool receiveMarketingEmails,
[StringLength(1000), Required] string masterPasswordHash, [StringLength(50)] string masterPasswordHint, [Required] string userSymmetricKey,
[Required] KeysRequestModel userAsymmetricKeys, int kdfMemory, int kdfParallelism)
@ -161,16 +142,6 @@ public class AccountsControllerTests : IClassFixture<IdentityApplicationFactory>
// Localize substitutions to this test.
var localFactory = new IdentityApplicationFactory();
// First we must substitute the mail service in order to be able to get a valid email verification token
// for the complete registration step
string capturedEmailVerificationToken = null;
localFactory.SubstituteService<IMailService>(mailService =>
{
mailService.SendRegistrationVerificationEmailAsync(Arg.Any<string>(), Arg.Do<string>(t => capturedEmailVerificationToken = t))
.Returns(Task.CompletedTask);
});
// we must first call the send verification email endpoint to trigger the first part of the process
var email = $"test+register+{name}@email.com";
var sendVerificationEmailReqModel = new RegisterSendVerificationEmailRequestModel
@ -183,7 +154,7 @@ public class AccountsControllerTests : IClassFixture<IdentityApplicationFactory>
var sendEmailVerificationResponseHttpContext = await localFactory.PostRegisterSendEmailVerificationAsync(sendVerificationEmailReqModel);
Assert.Equal(StatusCodes.Status204NoContent, sendEmailVerificationResponseHttpContext.Response.StatusCode);
Assert.NotNull(capturedEmailVerificationToken);
Assert.NotNull(localFactory.RegistrationTokens[email]);
// Now we call the finish registration endpoint with the email verification token
var registerFinishReqModel = new RegisterFinishRequestModel
@ -191,7 +162,7 @@ public class AccountsControllerTests : IClassFixture<IdentityApplicationFactory>
Email = email,
MasterPasswordHash = masterPasswordHash,
MasterPasswordHint = masterPasswordHint,
EmailVerificationToken = capturedEmailVerificationToken,
EmailVerificationToken = localFactory.RegistrationTokens[email],
Kdf = KdfType.PBKDF2_SHA256,
KdfIterations = AuthConstants.PBKDF2_ITERATIONS.Default,
UserSymmetricKey = userSymmetricKey,

View File

@ -1,11 +1,13 @@
using System.Security.Claims;
using System.Text.Json;
using Bit.Core;
using Bit.Core.AdminConsole.Entities;
using Bit.Core.AdminConsole.Entities.Provider;
using Bit.Core.AdminConsole.Enums.Provider;
using Bit.Core.AdminConsole.Repositories;
using Bit.Core.Auth.Entities;
using Bit.Core.Auth.Enums;
using Bit.Core.Auth.Models.Api.Request.Accounts;
using Bit.Core.Auth.Models.Data;
using Bit.Core.Auth.Repositories;
using Bit.Core.Entities;
@ -13,7 +15,6 @@ using Bit.Core.Enums;
using Bit.Core.Models.Data;
using Bit.Core.Repositories;
using Bit.Core.Utilities;
using Bit.Identity.Models.Request.Accounts;
using Bit.IntegrationTestCommon.Factories;
using Bit.Test.Common.Helpers;
using Duende.IdentityModel;
@ -545,16 +546,15 @@ public class IdentityServerSsoTests
{
var factory = new IdentityApplicationFactory();
var authorizationCode = new AuthorizationCode
{
ClientId = "web",
CreationTime = DateTime.UtcNow,
Lifetime = (int)TimeSpan.FromMinutes(5).TotalSeconds,
RedirectUri = "https://localhost:8080/sso-connector.html",
RequestedScopes = new[] { "api", "offline_access" },
RequestedScopes = ["api", "offline_access"],
CodeChallenge = challenge.Sha256(),
CodeChallengeMethod = "plain", //
CodeChallengeMethod = "plain",
Subject = null!, // Temporarily set it to null
};
@ -564,16 +564,20 @@ public class IdentityServerSsoTests
.Returns(authorizationCode);
});
// This starts the server and finalizes services
var registerResponse = await factory.RegisterAsync(new RegisterRequestModel
{
Email = TestEmail,
MasterPasswordHash = "master_password_hash",
});
var userRepository = factory.Services.GetRequiredService<IUserRepository>();
var user = await userRepository.GetByEmailAsync(TestEmail);
Assert.NotNull(user);
var user = await factory.RegisterNewIdentityFactoryUserAsync(
new RegisterFinishRequestModel
{
Email = TestEmail,
MasterPasswordHash = "masterPasswordHash",
Kdf = KdfType.PBKDF2_SHA256,
KdfIterations = AuthConstants.PBKDF2_ITERATIONS.Default,
UserAsymmetricKeys = new KeysRequestModel()
{
PublicKey = "public_key",
EncryptedPrivateKey = "private_key"
},
UserSymmetricKey = "sym_key",
});
var organizationRepository = factory.Services.GetRequiredService<IOrganizationRepository>();
var organization = await organizationRepository.CreateAsync(new Organization

View File

@ -3,11 +3,13 @@ using Bit.Core;
using Bit.Core.AdminConsole.Entities;
using Bit.Core.AdminConsole.Enums;
using Bit.Core.AdminConsole.Repositories;
using Bit.Core.Auth.Models.Api.Request.Accounts;
using Bit.Core.Entities;
using Bit.Core.Enums;
using Bit.Core.Platform.Installations;
using Bit.Core.Repositories;
using Bit.Core.Test.Auth.AutoFixture;
using Bit.Identity.IdentityServer;
using Bit.Identity.Models.Request.Accounts;
using Bit.IntegrationTestCommon.Factories;
using Bit.Test.Common.AutoFixture.Attributes;
using Bit.Test.Common.Helpers;
@ -17,6 +19,7 @@ using Xunit;
namespace Bit.Identity.IntegrationTest.Endpoints;
[SutProviderCustomize]
public class IdentityServerTests : IClassFixture<IdentityApplicationFactory>
{
private const int SecondsInMinute = 60;
@ -27,7 +30,7 @@ public class IdentityServerTests : IClassFixture<IdentityApplicationFactory>
public IdentityServerTests(IdentityApplicationFactory factory)
{
_factory = factory;
ReinitializeDbForTests();
ReinitializeDbForTests(_factory);
}
[Fact]
@ -48,18 +51,14 @@ public class IdentityServerTests : IClassFixture<IdentityApplicationFactory>
AssertHelper.AssertEqualJson(endpointRoot, knownConfigurationRoot);
}
[Theory, BitAutoData]
public async Task TokenEndpoint_GrantTypePassword_Success(string deviceId)
[Theory, BitAutoData, RegisterFinishRequestModelCustomize]
public async Task TokenEndpoint_GrantTypePassword_Success(RegisterFinishRequestModel requestModel)
{
var username = "test+tokenpassword@email.com";
var localFactory = new IdentityApplicationFactory();
var user = await localFactory.RegisterNewIdentityFactoryUserAsync(requestModel);
await _factory.RegisterAsync(new RegisterRequestModel
{
Email = username,
MasterPasswordHash = "master_password_hash"
});
var context = await PostLoginAsync(_factory.Server, username, deviceId, context => context.SetAuthEmail(username));
var context = await PostLoginAsync(localFactory.Server, user, requestModel.MasterPasswordHash,
context => context.SetAuthEmail(user.Email));
using var body = await AssertDefaultTokenBodyAsync(context);
var root = body.RootElement;
@ -73,18 +72,16 @@ public class IdentityServerTests : IClassFixture<IdentityApplicationFactory>
AssertUserDecryptionOptions(root);
}
[Theory, BitAutoData]
public async Task TokenEndpoint_GrantTypePassword_NoAuthEmailHeader_Fails(string deviceId)
[Theory, BitAutoData, RegisterFinishRequestModelCustomize]
public async Task TokenEndpoint_GrantTypePassword_NoAuthEmailHeader_Fails(
RegisterFinishRequestModel requestModel)
{
var username = "test+noauthemailheader@email.com";
requestModel.Email = "test+noauthemailheader@email.com";
await _factory.RegisterAsync(new RegisterRequestModel
{
Email = username,
MasterPasswordHash = "master_password_hash",
});
var localFactory = new IdentityApplicationFactory();
var user = await localFactory.RegisterNewIdentityFactoryUserAsync(requestModel);
var context = await PostLoginAsync(_factory.Server, username, deviceId, null);
var context = await PostLoginAsync(localFactory.Server, user, requestModel.MasterPasswordHash, null);
Assert.Equal(StatusCodes.Status400BadRequest, context.Response.StatusCode);
@ -96,18 +93,17 @@ public class IdentityServerTests : IClassFixture<IdentityApplicationFactory>
AssertHelper.AssertJsonProperty(root, "error_description", JsonValueKind.String);
}
[Theory, BitAutoData]
public async Task TokenEndpoint_GrantTypePassword_InvalidBase64AuthEmailHeader_Fails(string deviceId)
[Theory, BitAutoData, RegisterFinishRequestModelCustomize]
public async Task TokenEndpoint_GrantTypePassword_InvalidBase64AuthEmailHeader_Fails(
RegisterFinishRequestModel requestModel)
{
var username = "test+badauthheader@email.com";
requestModel.Email = "test+badauthheader@email.com";
await _factory.RegisterAsync(new RegisterRequestModel
{
Email = username,
MasterPasswordHash = "master_password_hash",
});
var localFactory = new IdentityApplicationFactory();
var user = await localFactory.RegisterNewIdentityFactoryUserAsync(requestModel);
var context = await PostLoginAsync(_factory.Server, username, deviceId, context => context.Request.Headers.Append("Auth-Email", "bad_value"));
var context = await PostLoginAsync(localFactory.Server, user, requestModel.MasterPasswordHash,
context => context.Request.Headers.Append("Auth-Email", "bad_value"));
Assert.Equal(StatusCodes.Status400BadRequest, context.Response.StatusCode);
@ -119,18 +115,17 @@ public class IdentityServerTests : IClassFixture<IdentityApplicationFactory>
AssertHelper.AssertJsonProperty(root, "error_description", JsonValueKind.String);
}
[Theory, BitAutoData]
public async Task TokenEndpoint_GrantTypePassword_WrongAuthEmailHeader_Fails(string deviceId)
[Theory, BitAutoData, RegisterFinishRequestModelCustomize]
public async Task TokenEndpoint_GrantTypePassword_WrongAuthEmailHeader_Fails(
RegisterFinishRequestModel requestModel)
{
var username = "test+badauthheader@email.com";
requestModel.Email = "test+badauthheader@email.com";
await _factory.RegisterAsync(new RegisterRequestModel
{
Email = username,
MasterPasswordHash = "master_password_hash",
});
var localFactory = new IdentityApplicationFactory();
var user = await localFactory.RegisterNewIdentityFactoryUserAsync(requestModel);
var context = await PostLoginAsync(_factory.Server, username, deviceId, context => context.SetAuthEmail("bad_value"));
var context = await PostLoginAsync(localFactory.Server, user, requestModel.MasterPasswordHash,
context => context.SetAuthEmail("bad_value"));
Assert.Equal(StatusCodes.Status400BadRequest, context.Response.StatusCode);
@ -142,215 +137,198 @@ public class IdentityServerTests : IClassFixture<IdentityApplicationFactory>
AssertHelper.AssertJsonProperty(root, "error_description", JsonValueKind.String);
}
[Theory]
[Theory, RegisterFinishRequestModelCustomize]
[BitAutoData(OrganizationUserType.Owner)]
[BitAutoData(OrganizationUserType.Admin)]
[BitAutoData(OrganizationUserType.User)]
[BitAutoData(OrganizationUserType.Custom)]
public async Task TokenEndpoint_GrantTypePassword_WithAllUserTypes_WithSsoPolicyDisabled_WithEnforceSsoPolicyForAllUsersTrue_Success(OrganizationUserType organizationUserType, Guid organizationId, string deviceId, int generatedUsername)
public async Task TokenEndpoint_GrantTypePassword_WithAllUserTypes_WithSsoPolicyDisabled_WithEnforceSsoPolicyForAllUsersTrue_Success(
OrganizationUserType organizationUserType, RegisterFinishRequestModel requestModel, Guid organizationId, int generatedUsername)
{
var username = $"{generatedUsername}@example.com";
requestModel.Email = $"{generatedUsername}@example.com";
var server = _factory.WithWebHostBuilder(builder =>
var localFactory = new IdentityApplicationFactory();
var server = localFactory.WithWebHostBuilder(builder =>
{
builder.UseSetting("globalSettings:sso:enforceSsoPolicyForAllUsers", "true");
}).Server;
var user = await localFactory.RegisterNewIdentityFactoryUserAsync(requestModel);
await server.PostAsync("/accounts/register", JsonContent.Create(new RegisterRequestModel
{
Email = username,
MasterPasswordHash = "master_password_hash"
}));
await CreateOrganizationWithSsoPolicyAsync(localFactory,
organizationId, user.Email, organizationUserType, ssoPolicyEnabled: false);
await CreateOrganizationWithSsoPolicyAsync(organizationId, username, organizationUserType, ssoPolicyEnabled: false);
var context = await PostLoginAsync(server, username, deviceId, context => context.SetAuthEmail(username));
var context = await PostLoginAsync(server, user, requestModel.MasterPasswordHash,
context => context.SetAuthEmail(user.Email));
Assert.Equal(StatusCodes.Status200OK, context.Response.StatusCode);
}
[Theory]
[Theory, RegisterFinishRequestModelCustomize]
[BitAutoData(OrganizationUserType.Owner)]
[BitAutoData(OrganizationUserType.Admin)]
[BitAutoData(OrganizationUserType.User)]
[BitAutoData(OrganizationUserType.Custom)]
public async Task TokenEndpoint_GrantTypePassword_WithAllUserTypes_WithSsoPolicyDisabled_WithEnforceSsoPolicyForAllUsersFalse_Success(OrganizationUserType organizationUserType, Guid organizationId, string deviceId, int generatedUsername)
public async Task TokenEndpoint_GrantTypePassword_WithAllUserTypes_WithSsoPolicyDisabled_WithEnforceSsoPolicyForAllUsersFalse_Success(
OrganizationUserType organizationUserType, RegisterFinishRequestModel requestModel, Guid organizationId, int generatedUsername)
{
var username = $"{generatedUsername}@example.com";
requestModel.Email = $"{generatedUsername}@example.com";
var server = _factory.WithWebHostBuilder(builder =>
var localFactory = new IdentityApplicationFactory();
var server = localFactory.WithWebHostBuilder(builder =>
{
builder.UseSetting("globalSettings:sso:enforceSsoPolicyForAllUsers", "false");
}).Server;
var user = await localFactory.RegisterNewIdentityFactoryUserAsync(requestModel);
await server.PostAsync("/accounts/register", JsonContent.Create(new RegisterRequestModel
{
Email = username,
MasterPasswordHash = "master_password_hash"
}));
await CreateOrganizationWithSsoPolicyAsync(
localFactory, organizationId, user.Email, organizationUserType, ssoPolicyEnabled: false);
await CreateOrganizationWithSsoPolicyAsync(organizationId, username, organizationUserType, ssoPolicyEnabled: false);
var context = await PostLoginAsync(server, username, deviceId, context => context.SetAuthEmail(username));
var context = await PostLoginAsync(server, user, requestModel.MasterPasswordHash,
context => context.SetAuthEmail(user.Email));
Assert.Equal(StatusCodes.Status200OK, context.Response.StatusCode);
}
[Theory]
[Theory, RegisterFinishRequestModelCustomize]
[BitAutoData(OrganizationUserType.Owner)]
[BitAutoData(OrganizationUserType.Admin)]
[BitAutoData(OrganizationUserType.User)]
[BitAutoData(OrganizationUserType.Custom)]
public async Task TokenEndpoint_GrantTypePassword_WithAllUserTypes_WithSsoPolicyEnabled_WithEnforceSsoPolicyForAllUsersTrue_Throw(OrganizationUserType organizationUserType, Guid organizationId, string deviceId, int generatedUsername)
public async Task TokenEndpoint_GrantTypePassword_WithAllUserTypes_WithSsoPolicyEnabled_WithEnforceSsoPolicyForAllUsersTrue_Throw(
OrganizationUserType organizationUserType, RegisterFinishRequestModel requestModel, Guid organizationId, int generatedUsername)
{
var username = $"{generatedUsername}@example.com";
requestModel.Email = $"{generatedUsername}@example.com";
var server = _factory.WithWebHostBuilder(builder =>
var localFactory = new IdentityApplicationFactory();
var server = localFactory.WithWebHostBuilder(builder =>
{
builder.UseSetting("globalSettings:sso:enforceSsoPolicyForAllUsers", "true");
}).Server;
var user = await localFactory.RegisterNewIdentityFactoryUserAsync(requestModel);
await server.PostAsync("/accounts/register", JsonContent.Create(new RegisterRequestModel
{
Email = username,
MasterPasswordHash = "master_password_hash"
}));
await CreateOrganizationWithSsoPolicyAsync(localFactory, organizationId, user.Email, organizationUserType, ssoPolicyEnabled: true);
await CreateOrganizationWithSsoPolicyAsync(organizationId, username, organizationUserType, ssoPolicyEnabled: true);
var context = await PostLoginAsync(server, username, deviceId, context => context.SetAuthEmail(username));
var context = await PostLoginAsync(server, user, requestModel.MasterPasswordHash,
context => context.SetAuthEmail(user.Email));
Assert.Equal(StatusCodes.Status400BadRequest, context.Response.StatusCode);
await AssertRequiredSsoAuthenticationResponseAsync(context);
}
[Theory]
[Theory, RegisterFinishRequestModelCustomize]
[BitAutoData(OrganizationUserType.Owner)]
[BitAutoData(OrganizationUserType.Admin)]
public async Task TokenEndpoint_GrantTypePassword_WithOwnerOrAdmin_WithSsoPolicyEnabled_WithEnforceSsoPolicyForAllUsersFalse_Success(OrganizationUserType organizationUserType, Guid organizationId, string deviceId, int generatedUsername)
public async Task TokenEndpoint_GrantTypePassword_WithOwnerOrAdmin_WithSsoPolicyEnabled_WithEnforceSsoPolicyForAllUsersFalse_Success(
OrganizationUserType organizationUserType, RegisterFinishRequestModel requestModel, Guid organizationId, int generatedUsername)
{
var username = $"{generatedUsername}@example.com";
requestModel.Email = $"{generatedUsername}@example.com";
var server = _factory.WithWebHostBuilder(builder =>
var localFactory = new IdentityApplicationFactory();
var server = localFactory.WithWebHostBuilder(builder =>
{
builder.UseSetting("globalSettings:sso:enforceSsoPolicyForAllUsers", "false");
}).Server;
var user = await localFactory.RegisterNewIdentityFactoryUserAsync(requestModel);
await server.PostAsync("/accounts/register", JsonContent.Create(new RegisterRequestModel
{
Email = username,
MasterPasswordHash = "master_password_hash"
}));
await CreateOrganizationWithSsoPolicyAsync(localFactory, organizationId, user.Email, organizationUserType, ssoPolicyEnabled: true);
await CreateOrganizationWithSsoPolicyAsync(organizationId, username, organizationUserType, ssoPolicyEnabled: true);
var context = await PostLoginAsync(server, username, deviceId, context => context.SetAuthEmail(username));
var context = await PostLoginAsync(server, user, requestModel.MasterPasswordHash,
context => context.SetAuthEmail(user.Email));
Assert.Equal(StatusCodes.Status200OK, context.Response.StatusCode);
}
[Theory]
[Theory, RegisterFinishRequestModelCustomize]
[BitAutoData(OrganizationUserType.User)]
[BitAutoData(OrganizationUserType.Custom)]
public async Task TokenEndpoint_GrantTypePassword_WithNonOwnerOrAdmin_WithSsoPolicyEnabled_WithEnforceSsoPolicyForAllUsersFalse_Throws(OrganizationUserType organizationUserType, Guid organizationId, string deviceId, int generatedUsername)
public async Task TokenEndpoint_GrantTypePassword_WithNonOwnerOrAdmin_WithSsoPolicyEnabled_WithEnforceSsoPolicyForAllUsersFalse_Throws(
OrganizationUserType organizationUserType, RegisterFinishRequestModel requestModel, Guid organizationId, int generatedUsername)
{
var username = $"{generatedUsername}@example.com";
requestModel.Email = $"{generatedUsername}@example.com";
var server = _factory.WithWebHostBuilder(builder =>
var localFactory = new IdentityApplicationFactory();
var server = localFactory.WithWebHostBuilder(builder =>
{
builder.UseSetting("globalSettings:sso:enforceSsoPolicyForAllUsers", "false");
}).Server;
var user = await localFactory.RegisterNewIdentityFactoryUserAsync(requestModel);
await server.PostAsync("/accounts/register", JsonContent.Create(new RegisterRequestModel
{
Email = username,
MasterPasswordHash = "master_password_hash"
}));
await CreateOrganizationWithSsoPolicyAsync(localFactory, organizationId, user.Email, organizationUserType, ssoPolicyEnabled: true);
await CreateOrganizationWithSsoPolicyAsync(organizationId, username, organizationUserType, ssoPolicyEnabled: true);
var context = await PostLoginAsync(server, username, deviceId, context => context.SetAuthEmail(username));
var context = await PostLoginAsync(server, user, requestModel.MasterPasswordHash,
context => context.SetAuthEmail(user.Email));
Assert.Equal(StatusCodes.Status400BadRequest, context.Response.StatusCode);
await AssertRequiredSsoAuthenticationResponseAsync(context);
}
[Theory, BitAutoData]
public async Task TokenEndpoint_GrantTypeRefreshToken_Success(string deviceId)
[Theory, BitAutoData, RegisterFinishRequestModelCustomize]
public async Task TokenEndpoint_GrantTypeRefreshToken_Success(RegisterFinishRequestModel requestModel)
{
var username = "test+tokenrefresh@email.com";
var localFactory = new IdentityApplicationFactory();
await _factory.RegisterAsync(new RegisterRequestModel
{
Email = username,
MasterPasswordHash = "master_password_hash",
});
var user = await localFactory.RegisterNewIdentityFactoryUserAsync(requestModel);
var (_, refreshToken) = await _factory.TokenFromPasswordAsync(username, "master_password_hash", deviceId);
var (_, refreshToken) = await localFactory.TokenFromPasswordAsync(
requestModel.Email, requestModel.MasterPasswordHash);
var context = await _factory.Server.PostAsync("/connect/token", new FormUrlEncodedContent(new Dictionary<string, string>
{
{ "grant_type", "refresh_token" },
{ "client_id", "web" },
{ "refresh_token", refreshToken },
}));
var context = await localFactory.Server.PostAsync("/connect/token",
new FormUrlEncodedContent(new Dictionary<string, string>
{
{ "grant_type", "refresh_token" },
{ "client_id", "web" },
{ "refresh_token", refreshToken },
}));
using var body = await AssertDefaultTokenBodyAsync(context);
AssertRefreshTokenExists(body.RootElement);
}
[Theory, BitAutoData]
public async Task TokenEndpoint_GrantTypeClientCredentials_Success(string deviceId)
[Theory, BitAutoData, RegisterFinishRequestModelCustomize]
public async Task TokenEndpoint_GrantTypeClientCredentials_Success(RegisterFinishRequestModel model)
{
var username = "test+tokenclientcredentials@email.com";
var localFactory = new IdentityApplicationFactory();
var user = await localFactory.RegisterNewIdentityFactoryUserAsync(model);
await _factory.RegisterAsync(new RegisterRequestModel
{
Email = username,
MasterPasswordHash = "master_password_hash",
});
var database = _factory.GetDatabaseContext();
var user = await database.Users
.FirstAsync(u => u.Email == username);
var context = await _factory.Server.PostAsync("/connect/token", new FormUrlEncodedContent(new Dictionary<string, string>
{
{ "grant_type", "client_credentials" },
{ "client_id", $"user.{user.Id}" },
{ "client_secret", user.ApiKey },
{ "scope", "api" },
{ "DeviceIdentifier", deviceId },
{ "DeviceType", DeviceTypeAsString(DeviceType.FirefoxBrowser) },
{ "DeviceName", "firefox" },
}));
var context = await localFactory.Server.PostAsync("/connect/token",
new FormUrlEncodedContent(new Dictionary<string, string>
{
{ "grant_type", "client_credentials" },
{ "client_id", $"user.{user.Id}" },
{ "client_secret", user.ApiKey },
{ "scope", "api" },
{ "DeviceIdentifier", IdentityApplicationFactory.DefaultDeviceIdentifier },
{ "DeviceType", DeviceTypeAsString(DeviceType.FirefoxBrowser) },
{ "DeviceName", "firefox" },
})
);
await AssertDefaultTokenBodyAsync(context, "api");
}
[Theory, BitAutoData]
public async Task TokenEndpoint_GrantTypeClientCredentials_AsLegacyUser_NotOnWebClient_Fails(string deviceId)
[Theory, BitAutoData, RegisterFinishRequestModelCustomize]
public async Task TokenEndpoint_GrantTypeClientCredentials_AsLegacyUser_NotOnWebClient_Fails(
RegisterFinishRequestModel model,
string deviceId)
{
var server = _factory.WithWebHostBuilder(builder =>
var localFactory = new IdentityApplicationFactory();
var server = localFactory.WithWebHostBuilder(builder =>
{
builder.UseSetting("globalSettings:launchDarkly:flagValues:block-legacy-users", "true");
}).Server;
var username = "test+tokenclientcredentials@email.com";
model.Email = "test+tokenclientcredentials@email.com";
var user = await localFactory.RegisterNewIdentityFactoryUserAsync(model);
await server.PostAsync("/accounts/register", JsonContent.Create(new RegisterRequestModel
{
Email = username,
MasterPasswordHash = "master_password_hash"
}));
var database = _factory.GetDatabaseContext();
var user = await database.Users
.FirstAsync(u => u.Email == username);
user.PrivateKey = "EncryptedPrivateKey";
// Modify user to be legacy user. We have to fetch the user again to put it in the ef-context
// so when we modify change tracking will save the changes.
var database = localFactory.GetDatabaseContext();
user = await database.Users
.FirstAsync(u => u.Email == model.Email);
user.Key = null;
await database.SaveChangesAsync();
var context = await server.PostAsync("/connect/token", new FormUrlEncodedContent(
@ -362,9 +340,9 @@ public class IdentityServerTests : IClassFixture<IdentityApplicationFactory>
{ "deviceIdentifier", deviceId },
{ "deviceName", "chrome" },
{ "grant_type", "password" },
{ "username", username },
{ "password", "master_password_hash" },
}), context => context.SetAuthEmail(username));
{ "username", model.Email },
{ "password", model.MasterPasswordHash },
}), context => context.SetAuthEmail(model.Email));
Assert.Equal(StatusCodes.Status400BadRequest, context.Response.StatusCode);
@ -535,23 +513,21 @@ public class IdentityServerTests : IClassFixture<IdentityApplicationFactory>
Assert.Equal("invalid_client", error);
}
[Theory, BitAutoData]
public async Task TokenEndpoint_TooQuickInOneSecond_BlockRequest(string deviceId)
[Theory, BitAutoData, RegisterFinishRequestModelCustomize]
public async Task TokenEndpoint_TooQuickInOneSecond_BlockRequest(
RegisterFinishRequestModel requestModel)
{
const int AmountInOneSecondAllowed = 10;
// The rule we are testing is 10 requests in 1 second
var username = "test+ratelimiting@email.com";
requestModel.Email = "test+ratelimiting@email.com";
await _factory.RegisterAsync(new RegisterRequestModel
{
Email = username,
MasterPasswordHash = "master_password_hash",
});
var localFactory = new IdentityApplicationFactory();
var user = await localFactory.RegisterNewIdentityFactoryUserAsync(requestModel);
var database = _factory.GetDatabaseContext();
var user = await database.Users
.FirstAsync(u => u.Email == username);
var database = localFactory.GetDatabaseContext();
user = await database.Users
.FirstAsync(u => u.Email == user.Email);
var tasks = new Task<HttpContext>[AmountInOneSecondAllowed + 1];
@ -573,36 +549,40 @@ public class IdentityServerTests : IClassFixture<IdentityApplicationFactory>
{ "scope", "api offline_access" },
{ "client_id", "web" },
{ "deviceType", DeviceTypeAsString(DeviceType.FirefoxBrowser) },
{ "deviceIdentifier", deviceId },
{ "deviceIdentifier", IdentityApplicationFactory.DefaultDeviceIdentifier },
{ "deviceName", "firefox" },
{ "grant_type", "password" },
{ "username", username },
{ "username", user.Email},
{ "password", "master_password_hash" },
}), context => context.SetAuthEmail(username).SetIp("1.1.1.2"));
}), context => context.SetAuthEmail(user.Email).SetIp("1.1.1.2"));
}
}
private async Task<HttpContext> PostLoginAsync(TestServer server, string username, string deviceId, Action<HttpContext> extraConfiguration)
private async Task<HttpContext> PostLoginAsync(
TestServer server, User user, string MasterPasswordHash, Action<HttpContext> extraConfiguration)
{
return await server.PostAsync("/connect/token", new FormUrlEncodedContent(new Dictionary<string, string>
{
{ "scope", "api offline_access" },
{ "client_id", "web" },
{ "deviceType", DeviceTypeAsString(DeviceType.FirefoxBrowser) },
{ "deviceIdentifier", deviceId },
{ "deviceIdentifier", IdentityApplicationFactory.DefaultDeviceIdentifier },
{ "deviceName", "firefox" },
{ "grant_type", "password" },
{ "username", username },
{ "password", "master_password_hash" },
{ "username", user.Email },
{ "password", MasterPasswordHash },
}), extraConfiguration);
}
private async Task CreateOrganizationWithSsoPolicyAsync(Guid organizationId, string username, OrganizationUserType organizationUserType, bool ssoPolicyEnabled)
private async Task CreateOrganizationWithSsoPolicyAsync(
IdentityApplicationFactory localFactory,
Guid organizationId,
string username, OrganizationUserType organizationUserType, bool ssoPolicyEnabled)
{
var userRepository = _factory.Services.GetService<IUserRepository>();
var organizationRepository = _factory.Services.GetService<IOrganizationRepository>();
var organizationUserRepository = _factory.Services.GetService<IOrganizationUserRepository>();
var policyRepository = _factory.Services.GetService<IPolicyRepository>();
var userRepository = localFactory.Services.GetService<IUserRepository>();
var organizationRepository = localFactory.Services.GetService<IOrganizationRepository>();
var organizationUserRepository = localFactory.Services.GetService<IOrganizationUserRepository>();
var policyRepository = localFactory.Services.GetService<IPolicyRepository>();
var organization = new Organization
{
@ -617,7 +597,7 @@ public class IdentityServerTests : IClassFixture<IdentityApplicationFactory>
await organizationRepository.CreateAsync(organization);
var user = await userRepository.GetByEmailAsync(username);
var organizationUser = new Bit.Core.Entities.OrganizationUser
var organizationUser = new OrganizationUser
{
OrganizationId = organization.Id,
UserId = user.Id,
@ -703,9 +683,9 @@ public class IdentityServerTests : IClassFixture<IdentityApplicationFactory>
(prop) => { Assert.Equal("Object", prop.Name); Assert.Equal("userDecryptionOptions", prop.Value.GetString()); });
}
private void ReinitializeDbForTests()
private void ReinitializeDbForTests(IdentityApplicationFactory factory)
{
var databaseContext = _factory.GetDatabaseContext();
var databaseContext = factory.GetDatabaseContext();
databaseContext.Policies.RemoveRange(databaseContext.Policies);
databaseContext.OrganizationUsers.RemoveRange(databaseContext.OrganizationUsers);
databaseContext.Organizations.RemoveRange(databaseContext.Organizations);

View File

@ -1,8 +1,11 @@
using System.Security.Claims;
using System.Text;
using System.Text.Json;
using Bit.Core;
using Bit.Core.AdminConsole.Entities;
using Bit.Core.Auth.Entities;
using Bit.Core.Auth.Enums;
using Bit.Core.Auth.Models.Api.Request.Accounts;
using Bit.Core.Auth.Models.Data;
using Bit.Core.Auth.Repositories;
using Bit.Core.Entities;
@ -11,7 +14,6 @@ using Bit.Core.Models.Data;
using Bit.Core.Repositories;
using Bit.Core.Services;
using Bit.Core.Utilities;
using Bit.Identity.Models.Request.Accounts;
using Bit.IntegrationTestCommon.Factories;
using Bit.Test.Common.AutoFixture.Attributes;
using Bit.Test.Common.Helpers;
@ -19,6 +21,7 @@ using Duende.IdentityModel;
using Duende.IdentityServer.Models;
using Duende.IdentityServer.Stores;
using LinqToDB;
using Microsoft.Extensions.Caching.Distributed;
using NSubstitute;
using Xunit;
@ -61,19 +64,14 @@ public class IdentityServerTwoFactorTests : IClassFixture<IdentityApplicationFac
public async Task TokenEndpoint_GrantTypePassword_UserTwoFactorRequired_TwoFactorProvided_Success()
{
// Arrange
// we can't use the class factory here.
var factory = new IdentityApplicationFactory();
string emailToken = null;
factory.SubstituteService<IMailService>(mailService =>
// return specified email token from cache
var emailToken = "12345678";
factory.SubstituteService<IDistributedCache>(distCache =>
{
mailService.SendTwoFactorEmailAsync(
Arg.Any<string>(),
Arg.Any<string>(),
Arg.Do<string>(t => emailToken = t),
Arg.Any<string>(),
Arg.Any<string>())
.Returns(Task.CompletedTask);
distCache.GetAsync(Arg.Is<string>(s => s.StartsWith("EmailToken_")))
.Returns(Task.FromResult(Encoding.UTF8.GetBytes(emailToken)));
});
// Create Test User
@ -102,10 +100,11 @@ public class IdentityServerTwoFactorTests : IClassFixture<IdentityApplicationFac
public async Task TokenEndpoint_GrantTypePassword_InvalidTwoFactorToken_Fails()
{
// Arrange
await CreateUserAsync(_factory, _testEmail, _userEmailTwoFactor);
var localFactory = new IdentityApplicationFactory();
await CreateUserAsync(localFactory, _testEmail, _userEmailTwoFactor);
// Act
var context = await _factory.ContextFromPasswordWithTwoFactorAsync(
var context = await localFactory.ContextFromPasswordWithTwoFactorAsync(
_testEmail, _testPassword, twoFactorProviderType: "Email");
// Assert
@ -124,16 +123,17 @@ public class IdentityServerTwoFactorTests : IClassFixture<IdentityApplicationFac
public async Task TokenEndpoint_GrantTypePassword_OrgDuoTwoFactorRequired_NoTwoFactorProvided_Fails(string deviceId)
{
// Arrange
var localFactory = new IdentityApplicationFactory();
var challenge = new string('c', 50);
var ssoConfigData = new SsoConfigurationData
{
MemberDecryptionType = MemberDecryptionType.MasterPassword,
};
await CreateSsoOrganizationAndUserAsync(
_factory, ssoConfigData, challenge, _testEmail, orgTwoFactor: _organizationTwoFactor);
localFactory, ssoConfigData, challenge, _testEmail, orgTwoFactor: _organizationTwoFactor);
// Act
var context = await _factory.Server.PostAsync("/connect/token", new FormUrlEncodedContent(new Dictionary<string, string>
var context = await localFactory.Server.PostAsync("/connect/token", new FormUrlEncodedContent(new Dictionary<string, string>
{
{ "scope", "api offline_access" },
{ "client_id", "web" },
@ -156,10 +156,11 @@ public class IdentityServerTwoFactorTests : IClassFixture<IdentityApplicationFac
public async Task TokenEndpoint_GrantTypePassword_RememberTwoFactorType_InvalidTwoFactorToken_Fails()
{
// Arrange
await CreateUserAsync(_factory, _testEmail, _userEmailTwoFactor);
var localFactory = new IdentityApplicationFactory();
await CreateUserAsync(localFactory, _testEmail, _userEmailTwoFactor);
// Act
var context = await _factory.ContextFromPasswordWithTwoFactorAsync(
var context = await localFactory.ContextFromPasswordWithTwoFactorAsync(
_testEmail, _testPassword, twoFactorProviderType: "Remember");
// Assert
@ -210,13 +211,14 @@ public class IdentityServerTwoFactorTests : IClassFixture<IdentityApplicationFac
public async Task TokenEndpoint_GrantTypeClientCredential_IndvTwoFactorRequired_Success(string deviceId)
{
// Arrange
await CreateUserAsync(_factory, _testEmail, _userEmailTwoFactor);
var localFactory = new IdentityApplicationFactory();
await CreateUserAsync(localFactory, _testEmail, _userEmailTwoFactor);
var database = _factory.GetDatabaseContext();
var database = localFactory.GetDatabaseContext();
var user = await database.Users.FirstAsync(u => u.Email == _testEmail);
// Act
var context = await _factory.Server.PostAsync("/connect/token", new FormUrlEncodedContent(new Dictionary<string, string>
var context = await localFactory.Server.PostAsync("/connect/token", new FormUrlEncodedContent(new Dictionary<string, string>
{
{ "grant_type", "client_credentials" },
{ "client_id", $"user.{user.Id}" },
@ -275,16 +277,13 @@ public class IdentityServerTwoFactorTests : IClassFixture<IdentityApplicationFac
{
// Arrange
var localFactory = new IdentityApplicationFactory();
string emailToken = null;
localFactory.SubstituteService<IMailService>(mailService =>
// return specified email token from cache
var emailToken = "12345678";
localFactory.SubstituteService<IDistributedCache>(distCache =>
{
mailService.SendTwoFactorEmailAsync(
Arg.Any<string>(),
Arg.Any<string>(),
Arg.Do<string>(t => emailToken = t),
Arg.Any<string>(),
Arg.Any<string>())
.Returns(Task.CompletedTask);
distCache.GetAsync(Arg.Is<string>(s => s.StartsWith("EmailToken_")))
.Returns(Task.FromResult(Encoding.UTF8.GetBytes(emailToken)));
});
// Create Test User
@ -379,17 +378,24 @@ public class IdentityServerTwoFactorTests : IClassFixture<IdentityApplicationFac
string userTwoFactor = null)
{
// Create Test User
await factory.RegisterAsync(new RegisterRequestModel
{
Email = testEmail,
MasterPasswordHash = _testPassword,
});
var userRepository = factory.Services.GetRequiredService<IUserRepository>();
var user = await userRepository.GetByEmailAsync(testEmail);
var user = await factory.RegisterNewIdentityFactoryUserAsync(
new RegisterFinishRequestModel
{
Email = testEmail,
MasterPasswordHash = _testPassword,
Kdf = KdfType.PBKDF2_SHA256,
KdfIterations = AuthConstants.PBKDF2_ITERATIONS.Default,
UserAsymmetricKeys = new KeysRequestModel()
{
PublicKey = "public_key",
EncryptedPrivateKey = "private_key"
},
UserSymmetricKey = "sym_key",
});
Assert.NotNull(user);
var userService = factory.GetService<IUserService>();
var userRepository = factory.Services.GetRequiredService<IUserRepository>();
if (userTwoFactor != null)
{
user.TwoFactorProviders = userTwoFactor;
@ -426,16 +432,20 @@ public class IdentityServerTwoFactorTests : IClassFixture<IdentityApplicationFac
.Returns(authorizationCode);
});
// Create Test User
var registerResponse = await factory.RegisterAsync(new RegisterRequestModel
{
Email = testEmail,
MasterPasswordHash = _testPassword,
});
var userRepository = factory.Services.GetRequiredService<IUserRepository>();
var user = await userRepository.GetByEmailAsync(testEmail);
Assert.NotNull(user);
var user = await factory.RegisterNewIdentityFactoryUserAsync(
new RegisterFinishRequestModel
{
Email = testEmail,
MasterPasswordHash = _testPassword,
Kdf = KdfType.PBKDF2_SHA256,
KdfIterations = AuthConstants.PBKDF2_ITERATIONS.Default,
UserAsymmetricKeys = new KeysRequestModel()
{
PublicKey = "public_key",
EncryptedPrivateKey = "private_key"
},
UserSymmetricKey = "sym_key",
});
var userService = factory.GetService<IUserService>();
if (userTwoFactor != null)

View File

@ -24,6 +24,7 @@
<ItemGroup>
<ProjectReference Include="..\..\src\Identity\Identity.csproj" />
<ProjectReference Include="..\Common\Common.csproj" />
<ProjectReference Include="..\Core.Test\Core.Test.csproj" />
<ProjectReference Include="..\IntegrationTestCommon\IntegrationTestCommon.csproj" />
</ItemGroup>

View File

@ -1,11 +1,11 @@
using System.Text.Json;
using Bit.Core;
using Bit.Core.Auth.Entities;
using Bit.Core.Auth.Enums;
using Bit.Core.Auth.Models.Api.Request.Accounts;
using Bit.Core.Entities;
using Bit.Core.Enums;
using Bit.Core.Repositories;
using Bit.Core.Services;
using Bit.Identity.Models.Request.Accounts;
using Bit.IntegrationTestCommon.Factories;
using Bit.Test.Common.AutoFixture.Attributes;
using Bit.Test.Common.Helpers;
@ -19,28 +19,16 @@ public class ResourceOwnerPasswordValidatorTests : IClassFixture<IdentityApplica
private const string DefaultPassword = "master_password_hash";
private const string DefaultUsername = "test@email.qa";
private const string DefaultDeviceIdentifier = "test_identifier";
private readonly IdentityApplicationFactory _factory;
private readonly UserManager<User> _userManager;
private readonly IAuthRequestRepository _authRequestRepository;
private readonly IDeviceService _deviceService;
public ResourceOwnerPasswordValidatorTests(IdentityApplicationFactory factory)
{
_factory = factory;
_userManager = _factory.GetService<UserManager<User>>();
_authRequestRepository = _factory.GetService<IAuthRequestRepository>();
_deviceService = _factory.GetService<IDeviceService>();
}
[Fact]
public async Task ValidateAsync_Success()
{
// Arrange
await EnsureUserCreatedAsync();
var localFactory = new IdentityApplicationFactory();
await EnsureUserCreatedAsync(localFactory);
// Act
var context = await _factory.Server.PostAsync("/connect/token",
var context = await localFactory.Server.PostAsync("/connect/token",
GetFormUrlEncodedContent(),
context => context.SetAuthEmail(DefaultUsername));
@ -56,10 +44,11 @@ public class ResourceOwnerPasswordValidatorTests : IClassFixture<IdentityApplica
public async Task ValidateAsync_AuthEmailHeaderInvalid_InvalidGrantResponse()
{
// Arrange
await EnsureUserCreatedAsync();
var localFactory = new IdentityApplicationFactory();
await EnsureUserCreatedAsync(localFactory);
// Act
var context = await _factory.Server.PostAsync(
var context = await localFactory.Server.PostAsync(
"/connect/token",
GetFormUrlEncodedContent()
);
@ -75,8 +64,10 @@ public class ResourceOwnerPasswordValidatorTests : IClassFixture<IdentityApplica
[Theory, BitAutoData]
public async Task ValidateAsync_UserNull_Failure(string username)
{
// Arrange
var localFactory = new IdentityApplicationFactory();
// Act
var context = await _factory.Server.PostAsync("/connect/token",
var context = await localFactory.Server.PostAsync("/connect/token",
GetFormUrlEncodedContent(username: username),
context => context.SetAuthEmail(username));
@ -105,13 +96,16 @@ public class ResourceOwnerPasswordValidatorTests : IClassFixture<IdentityApplica
public async Task ValidateAsync_BadPassword_Failure(string badPassword)
{
// Arrange
await EnsureUserCreatedAsync();
var localFactory = new IdentityApplicationFactory();
await EnsureUserCreatedAsync(localFactory);
var userManager = localFactory.GetService<UserManager<User>>();
// Verify the User is not null to ensure the failure is due to bad password
Assert.NotNull(await _userManager.FindByEmailAsync(DefaultUsername));
Assert.NotNull(await userManager.FindByEmailAsync(DefaultUsername));
// Act
var context = await _factory.Server.PostAsync("/connect/token",
var context = await localFactory.Server.PostAsync("/connect/token",
GetFormUrlEncodedContent(password: badPassword),
context => context.SetAuthEmail(DefaultUsername));
@ -128,9 +122,12 @@ public class ResourceOwnerPasswordValidatorTests : IClassFixture<IdentityApplica
public async Task ValidateAsync_ValidateContextAsync_AuthRequest_NotNull_AgeLessThanOneHour_Success()
{
// Arrange
var localFactory = new IdentityApplicationFactory();
// Ensure User
await EnsureUserCreatedAsync();
var user = await _userManager.FindByEmailAsync(DefaultUsername);
await EnsureUserCreatedAsync(localFactory);
var userManager = localFactory.GetService<UserManager<User>>();
var user = await userManager.FindByEmailAsync(DefaultUsername);
Assert.NotNull(user);
// Connect Request to User and set CreationDate
@ -139,13 +136,14 @@ public class ResourceOwnerPasswordValidatorTests : IClassFixture<IdentityApplica
AuthRequestType.AuthenticateAndUnlock,
DateTime.UtcNow.AddMinutes(-30)
);
await _authRequestRepository.CreateAsync(authRequest);
var authRequestRepository = localFactory.GetService<IAuthRequestRepository>();
await authRequestRepository.CreateAsync(authRequest);
var expectedAuthRequest = await _authRequestRepository.GetManyByUserIdAsync(user.Id);
var expectedAuthRequest = await authRequestRepository.GetManyByUserIdAsync(user.Id);
Assert.NotEmpty(expectedAuthRequest);
// Act
var context = await _factory.Server.PostAsync("/connect/token",
var context = await localFactory.Server.PostAsync("/connect/token",
new FormUrlEncodedContent(new Dictionary<string, string>
{
{ "scope", "api offline_access" },
@ -171,9 +169,12 @@ public class ResourceOwnerPasswordValidatorTests : IClassFixture<IdentityApplica
public async Task ValidateAsync_ValidateContextAsync_AuthRequest_NotNull_AgeGreaterThanOneHour_Failure()
{
// Arrange
var localFactory = new IdentityApplicationFactory();
// Ensure User
await EnsureUserCreatedAsync(_factory);
var user = await _userManager.FindByEmailAsync(DefaultUsername);
await EnsureUserCreatedAsync(localFactory);
var userManager = localFactory.GetService<UserManager<User>>();
var user = await userManager.FindByEmailAsync(DefaultUsername);
Assert.NotNull(user);
// Create AuthRequest
@ -184,7 +185,7 @@ public class ResourceOwnerPasswordValidatorTests : IClassFixture<IdentityApplica
);
// Act
var context = await _factory.Server.PostAsync("/connect/token",
var context = await localFactory.Server.PostAsync("/connect/token",
new FormUrlEncodedContent(new Dictionary<string, string>
{
{ "scope", "api offline_access" },
@ -214,19 +215,23 @@ public class ResourceOwnerPasswordValidatorTests : IClassFixture<IdentityApplica
Assert.Equal("Username or password is incorrect. Try again.", errorMessage);
}
private async Task EnsureUserCreatedAsync(IdentityApplicationFactory factory = null)
private async Task EnsureUserCreatedAsync(IdentityApplicationFactory factory)
{
factory ??= _factory;
// No need to create more users than we need
if (await _userManager.FindByEmailAsync(DefaultUsername) == null)
{
// Register user
await factory.RegisterAsync(new RegisterRequestModel
// Register user
await factory.RegisterNewIdentityFactoryUserAsync(
new RegisterFinishRequestModel
{
Email = DefaultUsername,
MasterPasswordHash = DefaultPassword
MasterPasswordHash = DefaultPassword,
Kdf = KdfType.PBKDF2_SHA256,
KdfIterations = AuthConstants.PBKDF2_ITERATIONS.Default,
UserAsymmetricKeys = new KeysRequestModel()
{
PublicKey = "public_key",
EncryptedPrivateKey = "private_key"
},
UserSymmetricKey = "sym_key",
});
}
}
private FormUrlEncodedContent GetFormUrlEncodedContent(