mirror of
https://github.com/bitwarden/server
synced 2026-01-12 05:24:15 +00:00
fix(auth-validator): [PM-22975] Client Version Validator - Fixed tests.
This commit is contained in:
@@ -13,6 +13,7 @@ namespace Bit.Identity.IntegrationTest.Login;
|
||||
public class ClientVersionGateTests : IClassFixture<IdentityApplicationFactory>
|
||||
{
|
||||
private readonly IdentityApplicationFactory _factory;
|
||||
private const string DefaultEncryptedString = "2.3Uk+WNBIoU5xzmVFNcoWzz==|1MsPIYuRfdOHfu/0uY6H2Q==|/98sp4wb6pHP1VTZ9JcNCYgQjEUMFPlqJgCwRk1YXKg=";
|
||||
|
||||
public ClientVersionGateTests(IdentityApplicationFactory factory)
|
||||
{
|
||||
@@ -23,6 +24,7 @@ public class ClientVersionGateTests : IClassFixture<IdentityApplicationFactory>
|
||||
[Theory, BitAutoData, RegisterFinishRequestModelCustomize]
|
||||
public async Task TokenEndpoint_GrantTypePassword_V2User_OnOldClientVersion_Blocked(RegisterFinishRequestModel requestModel)
|
||||
{
|
||||
NormalizeEncryptedStrings(requestModel);
|
||||
var localFactory = new IdentityApplicationFactory
|
||||
{
|
||||
UseMockClientVersionValidator = false
|
||||
@@ -72,6 +74,7 @@ public class ClientVersionGateTests : IClassFixture<IdentityApplicationFactory>
|
||||
[Theory, BitAutoData, RegisterFinishRequestModelCustomize]
|
||||
public async Task TokenEndpoint_GrantTypePassword_V2User_OnMinClientVersion_Succeeds(RegisterFinishRequestModel requestModel)
|
||||
{
|
||||
NormalizeEncryptedStrings(requestModel);
|
||||
var localFactory = new IdentityApplicationFactory
|
||||
{
|
||||
UseMockClientVersionValidator = false
|
||||
@@ -123,4 +126,24 @@ public class ClientVersionGateTests : IClassFixture<IdentityApplicationFactory>
|
||||
databaseContext.Users.RemoveRange(databaseContext.Users);
|
||||
databaseContext.SaveChanges();
|
||||
}
|
||||
|
||||
private static void NormalizeEncryptedStrings(RegisterFinishRequestModel requestModel)
|
||||
{
|
||||
var accountKeys = requestModel.UserAsymmetricKeys.AccountKeys;
|
||||
if (accountKeys == null)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
accountKeys.UserKeyEncryptedAccountPrivateKey = DefaultEncryptedString;
|
||||
if (accountKeys.PublicKeyEncryptionKeyPair != null)
|
||||
{
|
||||
accountKeys.PublicKeyEncryptionKeyPair.WrappedPrivateKey = DefaultEncryptedString;
|
||||
}
|
||||
if (accountKeys.SignatureKeyPair != null)
|
||||
{
|
||||
accountKeys.SignatureKeyPair.WrappedSigningKey = DefaultEncryptedString;
|
||||
accountKeys.SignatureKeyPair.SignatureAlgorithm = "ed25519";
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -3,6 +3,7 @@
|
||||
|
||||
using System.Collections.Concurrent;
|
||||
using System.Net.Http.Json;
|
||||
using System.Text;
|
||||
using System.Text.Json;
|
||||
using Bit.Core.Auth.Models.Api.Request.Accounts;
|
||||
using Bit.Core.Entities;
|
||||
@@ -25,6 +26,7 @@ public class IdentityApplicationFactory : WebApplicationFactoryBase<Startup>
|
||||
public const string DefaultDeviceIdentifier = "92b9d953-b9b6-4eaf-9d3e-11d57144dfeb";
|
||||
public const string DefaultUserEmail = "DefaultEmail@bitwarden.com";
|
||||
public const string DefaultUserPasswordHash = "default_password_hash";
|
||||
private const string DefaultEncryptedString = "2.3Uk+WNBIoU5xzmVFNcoWzz==|1MsPIYuRfdOHfu/0uY6H2Q==|/98sp4wb6pHP1VTZ9JcNCYgQjEUMFPlqJgCwRk1YXKg=";
|
||||
public bool UseMockClientVersionValidator { get; set; } = true;
|
||||
|
||||
/// <summary>
|
||||
@@ -88,20 +90,8 @@ public class IdentityApplicationFactory : WebApplicationFactoryBase<Startup>
|
||||
var context = await ContextFromPasswordAsync(
|
||||
username, password, deviceIdentifier, clientId, deviceType, deviceName);
|
||||
|
||||
// Provide clearer diagnostics on failure
|
||||
if (context.Response.StatusCode != StatusCodes.Status200OK)
|
||||
{
|
||||
var contentType = context.Response.ContentType ?? string.Empty;
|
||||
if (context.Response.Body.CanSeek)
|
||||
{
|
||||
context.Response.Body.Position = 0;
|
||||
}
|
||||
string rawBody = await new StreamReader(context.Response.Body).ReadToEndAsync();
|
||||
throw new Xunit.Sdk.XunitException($"Login failed: status={context.Response.StatusCode}, contentType='{contentType}', body='{rawBody}'");
|
||||
}
|
||||
|
||||
using var jsonDoc = await AssertHelper.AssertResponseTypeIs<JsonDocument>(context);
|
||||
var root = jsonDoc.RootElement;
|
||||
using var body = await AssertHelper.AssertResponseTypeIs<JsonDocument>(context);
|
||||
var root = body.RootElement;
|
||||
|
||||
return (root.GetProperty("access_token").GetString(), root.GetProperty("refresh_token").GetString());
|
||||
}
|
||||
@@ -124,13 +114,7 @@ public class IdentityApplicationFactory : WebApplicationFactoryBase<Startup>
|
||||
{ "grant_type", "password" },
|
||||
{ "username", username },
|
||||
{ "password", password },
|
||||
}),
|
||||
http =>
|
||||
{
|
||||
// Ensure JSON content negotiation for errors and set a sane client version
|
||||
http.Request.Headers.Append("Accept", "application/json");
|
||||
http.Request.Headers.Append("Bitwarden-Client-Version", "2025.11.0");
|
||||
});
|
||||
}));
|
||||
|
||||
return context;
|
||||
}
|
||||
@@ -242,8 +226,11 @@ public class IdentityApplicationFactory : WebApplicationFactoryBase<Startup>
|
||||
requestModel.EmailVerificationToken = RegistrationTokens[requestModel.Email];
|
||||
|
||||
var postRegisterFinishHttpContext = await PostRegisterFinishAsync(requestModel);
|
||||
|
||||
Assert.Equal(StatusCodes.Status200OK, postRegisterFinishHttpContext.Response.StatusCode);
|
||||
if (postRegisterFinishHttpContext.Response.StatusCode != StatusCodes.Status200OK)
|
||||
{
|
||||
var body = await ReadResponseBodyAsync(postRegisterFinishHttpContext);
|
||||
Assert.Fail($"register/finish failed (status {postRegisterFinishHttpContext.Response.StatusCode}). Body: {body}");
|
||||
}
|
||||
|
||||
var database = GetDatabaseContext();
|
||||
var user = await database.Users
|
||||
@@ -253,4 +240,32 @@ public class IdentityApplicationFactory : WebApplicationFactoryBase<Startup>
|
||||
|
||||
return user;
|
||||
}
|
||||
|
||||
private static async Task<string> ReadResponseBodyAsync(HttpContext ctx)
|
||||
{
|
||||
try
|
||||
{
|
||||
if (ctx?.Response.Body == null)
|
||||
{
|
||||
return "<no body>";
|
||||
}
|
||||
var stream = ctx.Response.Body;
|
||||
if (stream.CanSeek)
|
||||
{
|
||||
stream.Seek(0, SeekOrigin.Begin);
|
||||
}
|
||||
using var reader = new StreamReader(stream, Encoding.UTF8, detectEncodingFromByteOrderMarks: false, leaveOpen: true);
|
||||
var text = await reader.ReadToEndAsync();
|
||||
if (stream.CanSeek)
|
||||
{
|
||||
stream.Seek(0, SeekOrigin.Begin);
|
||||
}
|
||||
return string.IsNullOrWhiteSpace(text) ? "<empty body>" : text;
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
return $"<error reading body: {ex.Message}>";
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user