mirror of
https://github.com/bitwarden/server.git
synced 2025-06-30 23:52:50 -05:00
[PM-4619] Rewrite UserService
methods as commands (#3432)
* [PM-4619] feat: scaffold new create options command * [PM-4169] feat: implement credential create options command * [PM-4619] feat: create command for credential creation * [PM-4619] feat: create assertion options command * [PM-4619] chore: clean-up unused argument * [PM-4619] feat: implement assertion command * [PM-4619] feat: migrate to commands * [PM-4619] fix: lint * [PM-4169] fix: use constant * [PM-4619] fix: lint I have no idea what this commit acutally changes, but the file seems to have some character encoding issues. This fix was generated by `dotnet format`
This commit is contained in:
@ -0,0 +1,107 @@
|
||||
using System.Text;
|
||||
using Bit.Core.Auth.Entities;
|
||||
using Bit.Core.Auth.Repositories;
|
||||
using Bit.Core.Auth.UserFeatures.WebAuthnLogin.Implementations;
|
||||
using Bit.Core.Entities;
|
||||
using Bit.Core.Exceptions;
|
||||
using Bit.Core.Repositories;
|
||||
using Bit.Core.Utilities;
|
||||
using Bit.Test.Common.AutoFixture;
|
||||
using Bit.Test.Common.AutoFixture.Attributes;
|
||||
using Fido2NetLib;
|
||||
using Fido2NetLib.Objects;
|
||||
using NSubstitute;
|
||||
using NSubstitute.ReturnsExtensions;
|
||||
using Xunit;
|
||||
|
||||
namespace Bit.Core.Test.Auth.UserFeatures.WebAuthnLogin;
|
||||
|
||||
[SutProviderCustomize]
|
||||
public class AssertWebAuthnLoginCredentialCommandTests
|
||||
{
|
||||
[Theory, BitAutoData]
|
||||
internal async void InvalidUserHandle_ThrowsBadRequestException(SutProvider<AssertWebAuthnLoginCredentialCommand> sutProvider, AssertionOptions options, AuthenticatorAssertionRawResponse response)
|
||||
{
|
||||
// Arrange
|
||||
response.Response.UserHandle = Encoding.UTF8.GetBytes("invalid-user-handle");
|
||||
|
||||
// Act
|
||||
var result = async () => await sutProvider.Sut.AssertWebAuthnLoginCredential(options, response);
|
||||
|
||||
// Assert
|
||||
await Assert.ThrowsAsync<BadRequestException>(result);
|
||||
}
|
||||
|
||||
[Theory, BitAutoData]
|
||||
internal async void UserNotFound_ThrowsBadRequestException(SutProvider<AssertWebAuthnLoginCredentialCommand> sutProvider, User user, AssertionOptions options, AuthenticatorAssertionRawResponse response)
|
||||
{
|
||||
// Arrange
|
||||
response.Response.UserHandle = user.Id.ToByteArray();
|
||||
sutProvider.GetDependency<IUserRepository>().GetByIdAsync(user.Id).ReturnsNull();
|
||||
|
||||
// Act
|
||||
var result = async () => await sutProvider.Sut.AssertWebAuthnLoginCredential(options, response);
|
||||
|
||||
// Assert
|
||||
await Assert.ThrowsAsync<BadRequestException>(result);
|
||||
}
|
||||
|
||||
[Theory, BitAutoData]
|
||||
internal async void NoMatchingCredentialExists_ThrowsBadRequestException(SutProvider<AssertWebAuthnLoginCredentialCommand> sutProvider, User user, AssertionOptions options, AuthenticatorAssertionRawResponse response)
|
||||
{
|
||||
// Arrange
|
||||
response.Response.UserHandle = user.Id.ToByteArray();
|
||||
sutProvider.GetDependency<IUserRepository>().GetByIdAsync(user.Id).Returns(user);
|
||||
sutProvider.GetDependency<IWebAuthnCredentialRepository>().GetManyByUserIdAsync(user.Id).Returns(new WebAuthnCredential[] { });
|
||||
|
||||
// Act
|
||||
var result = async () => await sutProvider.Sut.AssertWebAuthnLoginCredential(options, response);
|
||||
|
||||
// Assert
|
||||
await Assert.ThrowsAsync<BadRequestException>(result);
|
||||
}
|
||||
|
||||
[Theory, BitAutoData]
|
||||
internal async void AssertionFails_ThrowsBadRequestException(SutProvider<AssertWebAuthnLoginCredentialCommand> sutProvider, User user, AssertionOptions options, AuthenticatorAssertionRawResponse response, WebAuthnCredential credential, AssertionVerificationResult assertionResult)
|
||||
{
|
||||
// Arrange
|
||||
var credentialId = Guid.NewGuid().ToByteArray();
|
||||
credential.CredentialId = CoreHelpers.Base64UrlEncode(credentialId);
|
||||
response.Id = credentialId;
|
||||
response.Response.UserHandle = user.Id.ToByteArray();
|
||||
assertionResult.Status = "Not ok";
|
||||
sutProvider.GetDependency<IUserRepository>().GetByIdAsync(user.Id).Returns(user);
|
||||
sutProvider.GetDependency<IWebAuthnCredentialRepository>().GetManyByUserIdAsync(user.Id).Returns(new WebAuthnCredential[] { credential });
|
||||
sutProvider.GetDependency<IFido2>().MakeAssertionAsync(response, options, Arg.Any<byte[]>(), Arg.Any<uint>(), Arg.Any<IsUserHandleOwnerOfCredentialIdAsync>())
|
||||
.Returns(assertionResult);
|
||||
|
||||
// Act
|
||||
var result = async () => await sutProvider.Sut.AssertWebAuthnLoginCredential(options, response);
|
||||
|
||||
// Assert
|
||||
await Assert.ThrowsAsync<BadRequestException>(result);
|
||||
}
|
||||
|
||||
[Theory, BitAutoData]
|
||||
internal async void AssertionSucceeds_ReturnsUserAndCredential(SutProvider<AssertWebAuthnLoginCredentialCommand> sutProvider, User user, AssertionOptions options, AuthenticatorAssertionRawResponse response, WebAuthnCredential credential, AssertionVerificationResult assertionResult)
|
||||
{
|
||||
// Arrange
|
||||
var credentialId = Guid.NewGuid().ToByteArray();
|
||||
credential.CredentialId = CoreHelpers.Base64UrlEncode(credentialId);
|
||||
response.Id = credentialId;
|
||||
response.Response.UserHandle = user.Id.ToByteArray();
|
||||
assertionResult.Status = "ok";
|
||||
sutProvider.GetDependency<IUserRepository>().GetByIdAsync(user.Id).Returns(user);
|
||||
sutProvider.GetDependency<IWebAuthnCredentialRepository>().GetManyByUserIdAsync(user.Id).Returns(new WebAuthnCredential[] { credential });
|
||||
sutProvider.GetDependency<IFido2>().MakeAssertionAsync(response, options, Arg.Any<byte[]>(), Arg.Any<uint>(), Arg.Any<IsUserHandleOwnerOfCredentialIdAsync>())
|
||||
.Returns(assertionResult);
|
||||
|
||||
// Act
|
||||
var result = await sutProvider.Sut.AssertWebAuthnLoginCredential(options, response);
|
||||
|
||||
// Assert
|
||||
var (userResult, credentialResult) = result;
|
||||
Assert.Equal(user, userResult);
|
||||
Assert.Equal(credential, credentialResult);
|
||||
}
|
||||
}
|
@ -0,0 +1,65 @@
|
||||
using AutoFixture;
|
||||
using Bit.Core.Auth.Entities;
|
||||
using Bit.Core.Auth.Repositories;
|
||||
using Bit.Core.Auth.UserFeatures.WebAuthnLogin.Implementations;
|
||||
using Bit.Core.Entities;
|
||||
using Bit.Test.Common.AutoFixture;
|
||||
using Bit.Test.Common.AutoFixture.Attributes;
|
||||
using Fido2NetLib;
|
||||
using Fido2NetLib.Objects;
|
||||
using NSubstitute;
|
||||
using Xunit;
|
||||
using static Fido2NetLib.Fido2;
|
||||
|
||||
namespace Bit.Core.Test.Auth.UserFeatures.WebAuthnLogin;
|
||||
|
||||
[SutProviderCustomize]
|
||||
public class CreateWebAuthnLoginCredentialCommandTests
|
||||
{
|
||||
[Theory, BitAutoData]
|
||||
internal async void ExceedsExistingCredentialsLimit_ReturnsFalse(SutProvider<CreateWebAuthnLoginCredentialCommand> sutProvider, User user, CredentialCreateOptions options, AuthenticatorAttestationRawResponse response, Generator<WebAuthnCredential> credentialGenerator)
|
||||
{
|
||||
// Arrange
|
||||
var existingCredentials = credentialGenerator.Take(CreateWebAuthnLoginCredentialCommand.MaxCredentialsPerUser).ToList();
|
||||
sutProvider.GetDependency<IWebAuthnCredentialRepository>().GetManyByUserIdAsync(user.Id).Returns(existingCredentials);
|
||||
|
||||
// Act
|
||||
var result = await sutProvider.Sut.CreateWebAuthnLoginCredentialAsync(user, "name", options, response, false, null, null, null);
|
||||
|
||||
// Assert
|
||||
Assert.False(result);
|
||||
await sutProvider.GetDependency<IWebAuthnCredentialRepository>().DidNotReceive().CreateAsync(Arg.Any<WebAuthnCredential>());
|
||||
}
|
||||
|
||||
[Theory, BitAutoData]
|
||||
internal async void DoesNotExceedExistingCredentialsLimit_CreatesCredential(SutProvider<CreateWebAuthnLoginCredentialCommand> sutProvider, User user, CredentialCreateOptions options, AuthenticatorAttestationRawResponse response, Generator<WebAuthnCredential> credentialGenerator)
|
||||
{
|
||||
// Arrange
|
||||
var existingCredentials = credentialGenerator.Take(CreateWebAuthnLoginCredentialCommand.MaxCredentialsPerUser - 1).ToList();
|
||||
sutProvider.GetDependency<IWebAuthnCredentialRepository>().GetManyByUserIdAsync(user.Id).Returns(existingCredentials);
|
||||
sutProvider.GetDependency<IFido2>().MakeNewCredentialAsync(
|
||||
response, options, Arg.Any<IsCredentialIdUniqueToUserAsyncDelegate>(), Arg.Any<byte[]>(), Arg.Any<CancellationToken>()
|
||||
).Returns(MakeCredentialResult());
|
||||
|
||||
// Act
|
||||
var result = await sutProvider.Sut.CreateWebAuthnLoginCredentialAsync(user, "name", options, response, false, null, null, null);
|
||||
|
||||
// Assert
|
||||
Assert.True(result);
|
||||
await sutProvider.GetDependency<IWebAuthnCredentialRepository>().Received().CreateAsync(Arg.Any<WebAuthnCredential>());
|
||||
}
|
||||
|
||||
private CredentialMakeResult MakeCredentialResult()
|
||||
{
|
||||
return new CredentialMakeResult("ok", "", new AttestationVerificationSuccess
|
||||
{
|
||||
Aaguid = new Guid(),
|
||||
Counter = 0,
|
||||
CredentialId = new Guid().ToByteArray(),
|
||||
CredType = "public-key",
|
||||
PublicKey = new byte[0],
|
||||
Status = "ok",
|
||||
User = new Fido2User(),
|
||||
});
|
||||
}
|
||||
}
|
@ -0,0 +1,60 @@
|
||||
using Bit.Core.Auth.Entities;
|
||||
using Bit.Core.Auth.Repositories;
|
||||
using Bit.Core.Auth.UserFeatures.WebAuthnLogin.Implementations;
|
||||
using Bit.Core.Entities;
|
||||
using Bit.Test.Common.AutoFixture;
|
||||
using Bit.Test.Common.AutoFixture.Attributes;
|
||||
using Fido2NetLib;
|
||||
using Fido2NetLib.Objects;
|
||||
using NSubstitute;
|
||||
using Xunit;
|
||||
|
||||
namespace Bit.Core.Test.Auth.UserFeatures.WebAuthnLogin;
|
||||
|
||||
[SutProviderCustomize]
|
||||
public class GetWebAuthnLoginCredentialCreateOptionsTests
|
||||
{
|
||||
[Theory, BitAutoData]
|
||||
internal async Task NoExistingCredentials_ReturnsOptionsWithoutExcludedCredentials(SutProvider<GetWebAuthnLoginCredentialCreateOptionsCommand> sutProvider, User user)
|
||||
{
|
||||
// Arrange
|
||||
sutProvider.GetDependency<IWebAuthnCredentialRepository>()
|
||||
.GetManyByUserIdAsync(user.Id)
|
||||
.Returns(new List<WebAuthnCredential>());
|
||||
|
||||
// Act
|
||||
var result = await sutProvider.Sut.GetWebAuthnLoginCredentialCreateOptionsAsync(user);
|
||||
|
||||
// Assert
|
||||
sutProvider.GetDependency<IFido2>()
|
||||
.Received()
|
||||
.RequestNewCredential(
|
||||
Arg.Any<Fido2User>(),
|
||||
Arg.Is<List<PublicKeyCredentialDescriptor>>(list => list.Count == 0),
|
||||
Arg.Any<AuthenticatorSelection>(),
|
||||
Arg.Any<AttestationConveyancePreference>(),
|
||||
Arg.Any<AuthenticationExtensionsClientInputs>());
|
||||
}
|
||||
|
||||
[Theory, BitAutoData]
|
||||
internal async Task HasExistingCredential_ReturnsOptionsWithExcludedCredential(SutProvider<GetWebAuthnLoginCredentialCreateOptionsCommand> sutProvider, User user, WebAuthnCredential credential)
|
||||
{
|
||||
// Arrange
|
||||
sutProvider.GetDependency<IWebAuthnCredentialRepository>()
|
||||
.GetManyByUserIdAsync(user.Id)
|
||||
.Returns(new List<WebAuthnCredential> { credential });
|
||||
|
||||
// Act
|
||||
var result = await sutProvider.Sut.GetWebAuthnLoginCredentialCreateOptionsAsync(user);
|
||||
|
||||
// Assert
|
||||
sutProvider.GetDependency<IFido2>()
|
||||
.Received()
|
||||
.RequestNewCredential(
|
||||
Arg.Any<Fido2User>(),
|
||||
Arg.Is<List<PublicKeyCredentialDescriptor>>(list => list.Count == 1),
|
||||
Arg.Any<AuthenticatorSelection>(),
|
||||
Arg.Any<AttestationConveyancePreference>(),
|
||||
Arg.Any<AuthenticationExtensionsClientInputs>());
|
||||
}
|
||||
}
|
Reference in New Issue
Block a user