1
0
mirror of https://github.com/bitwarden/server synced 2025-12-26 13:13:24 +00:00

[PM-22696] send enumeration protection (#6352)

* feat: add static enumeration helper class
* test: add enumeration helper class unit tests

* feat: implement NeverAuthenticateValidator
* test: unit and integration tests SendNeverAuthenticateValidator

* test: use static class for common integration test setup for Send Access unit and integration tests
* test: update tests to use static helper
This commit is contained in:
Ike
2025-09-23 06:38:22 -04:00
committed by GitHub
parent c6f5d5e36e
commit 3b54fea309
19 changed files with 989 additions and 290 deletions

View File

@@ -1,12 +1,8 @@
using System.Collections.Specialized;
using Bit.Core;
using Bit.Core;
using Bit.Core.Auth.Identity;
using Bit.Core.Auth.IdentityServer;
using Bit.Core.Enums;
using Bit.Core.Services;
using Bit.Core.Tools.Models.Data;
using Bit.Core.Tools.SendFeatures.Queries.Interfaces;
using Bit.Core.Utilities;
using Bit.Identity.IdentityServer.Enums;
using Bit.Identity.IdentityServer.RequestValidators.SendAccess;
using Bit.Test.Common.AutoFixture;
@@ -81,7 +77,7 @@ public class SendAccessGrantValidatorTests
var context = new ExtensionGrantValidationContext();
tokenRequest.GrantType = CustomGrantTypes.SendAccess;
tokenRequest.Raw = CreateTokenRequestBody(Guid.Empty);
tokenRequest.Raw = SendAccessTestUtilities.CreateValidatedTokenRequest(Guid.Empty);
// To preserve the CreateTokenRequestBody method for more general usage we over write the sendId
tokenRequest.Raw.Set(SendAccessConstants.TokenRequest.SendId, "invalid-guid-format");
@@ -118,7 +114,9 @@ public class SendAccessGrantValidatorTests
public async Task ValidateAsync_NeverAuthenticateMethod_ReturnsInvalidGrant(
[AutoFixture.ValidatedTokenRequest] ValidatedTokenRequest tokenRequest,
SutProvider<SendAccessGrantValidator> sutProvider,
Guid sendId)
NeverAuthenticate neverAuthenticate,
Guid sendId,
GrantValidationResult expectedResult)
{
// Arrange
var context = SetupTokenRequest(
@@ -128,14 +126,20 @@ public class SendAccessGrantValidatorTests
sutProvider.GetDependency<ISendAuthenticationQuery>()
.GetAuthenticationMethod(sendId)
.Returns(new NeverAuthenticate());
.Returns(neverAuthenticate);
sutProvider.GetDependency<ISendAuthenticationMethodValidator<NeverAuthenticate>>()
.ValidateRequestAsync(context, neverAuthenticate, sendId)
.Returns(expectedResult);
// Act
await sutProvider.Sut.ValidateAsync(context);
// Assert
Assert.Equal(OidcConstants.TokenErrors.InvalidGrant, context.Result.Error);
Assert.Equal($"{SendAccessConstants.TokenRequest.SendId} is invalid.", context.Result.ErrorDescription);
Assert.Equal(expectedResult, context.Result);
await sutProvider.GetDependency<ISendAuthenticationMethodValidator<NeverAuthenticate>>()
.Received(1)
.ValidateRequestAsync(context, neverAuthenticate, sendId);
}
[Theory, BitAutoData]
@@ -264,7 +268,7 @@ public class SendAccessGrantValidatorTests
public void GrantType_ReturnsCorrectType()
{
// Arrange & Act
var validator = new SendAccessGrantValidator(null!, null!, null!, null!);
var validator = new SendAccessGrantValidator(null!, null!, null!, null!, null!);
// Assert
Assert.Equal(CustomGrantTypes.SendAccess, ((IExtensionGrantValidator)validator).GrantType);
@@ -289,44 +293,9 @@ public class SendAccessGrantValidatorTests
var context = new ExtensionGrantValidationContext();
request.GrantType = CustomGrantTypes.SendAccess;
request.Raw = CreateTokenRequestBody(sendId);
request.Raw = SendAccessTestUtilities.CreateValidatedTokenRequest(sendId);
context.Request = request;
return context;
}
private static NameValueCollection CreateTokenRequestBody(
Guid sendId,
string passwordHash = null,
string sendEmail = null,
string otpCode = null)
{
var sendIdBase64 = CoreHelpers.Base64UrlEncode(sendId.ToByteArray());
var rawRequestParameters = new NameValueCollection
{
{ OidcConstants.TokenRequest.GrantType, CustomGrantTypes.SendAccess },
{ OidcConstants.TokenRequest.ClientId, BitwardenClient.Send },
{ OidcConstants.TokenRequest.Scope, ApiScopes.ApiSendAccess },
{ "deviceType", ((int)DeviceType.FirefoxBrowser).ToString() },
{ SendAccessConstants.TokenRequest.SendId, sendIdBase64 }
};
if (passwordHash != null)
{
rawRequestParameters.Add(SendAccessConstants.TokenRequest.ClientB64HashedPassword, passwordHash);
}
if (sendEmail != null)
{
rawRequestParameters.Add(SendAccessConstants.TokenRequest.Email, sendEmail);
}
if (otpCode != null && sendEmail != null)
{
rawRequestParameters.Add(SendAccessConstants.TokenRequest.Otp, otpCode);
}
return rawRequestParameters;
}
}