From a08466d220f38eafefcb7063b2620e2cd75bf5cc Mon Sep 17 00:00:00 2001 From: Andreas Coroiu Date: Fri, 19 Jan 2024 11:23:56 +0100 Subject: [PATCH] [PM-5731] feat: find discoverable credentials --- .../Services/Fido2AuthenticatorService.cs | 19 +++++++-- .../Services/Fido2AuthenticatorTests.cs | 39 ++++++++++++++++++- 2 files changed, 53 insertions(+), 5 deletions(-) diff --git a/src/Core/Services/Fido2AuthenticatorService.cs b/src/Core/Services/Fido2AuthenticatorService.cs index fb897044d..b8fa56c8c 100644 --- a/src/Core/Services/Fido2AuthenticatorService.cs +++ b/src/Core/Services/Fido2AuthenticatorService.cs @@ -34,8 +34,7 @@ namespace Bit.Core.Services assertionParams.RpId ); } else { - cipherOptions = new List(); - // cipherOptions = await this.findCredentialsByRp(params.rpId); + cipherOptions = await FindCredentialsByRp(assertionParams.RpId); } if (cipherOptions.Count == 0) { @@ -82,8 +81,20 @@ namespace Bit.Core.Services !cipher.IsDeleted && cipher.Type == CipherType.Login && cipher.Login.HasFido2Credentials && - cipher.Login.Fido2Credentials[0].RpId == rpId && - ids.Contains(cipher.Login.Fido2Credentials[0].CredentialId) + cipher.Login.MainFido2Credential.RpId == rpId && + ids.Contains(cipher.Login.MainFido2Credential.CredentialId) + ); + } + + private async Task> FindCredentialsByRp(string rpId) + { + var ciphers = await _cipherService.GetAllDecryptedAsync(); + return ciphers.FindAll((cipher) => + !cipher.IsDeleted && + cipher.Type == CipherType.Login && + cipher.Login.HasFido2Credentials && + cipher.Login.MainFido2Credential.RpId == rpId && + cipher.Login.MainFido2Credential.IsDiscoverable ); } diff --git a/test/Core.Test/Services/Fido2AuthenticatorTests.cs b/test/Core.Test/Services/Fido2AuthenticatorTests.cs index 577f3a8cd..0c73e4ea4 100644 --- a/test/Core.Test/Services/Fido2AuthenticatorTests.cs +++ b/test/Core.Test/Services/Fido2AuthenticatorTests.cs @@ -76,7 +76,44 @@ namespace Bit.Core.Test.Services (pickCredentialParams) => pickCredentialParams.CipherIds.SequenceEqual(ciphers.Select((cipher) => cipher.Id)) && pickCredentialParams.UserVerification == aParams.RequireUserVerification )); } - + + [Theory] + [InlineCustomAutoData(new[] { typeof(SutProviderCustomization) })] + public async Task GetAssertionAsync_AsksForDiscoverableCredentials_ParamsDoesNotContainsAllowedCredentialsList(SutProvider sutProvider, Fido2AuthenticatorGetAssertionParams aParams) + { + var credentialIds = new[] { Guid.NewGuid(), Guid.NewGuid() }; + List ciphers = [ + CreateCipherView(credentialIds[0].ToString(), "bitwarden.com", false), + CreateCipherView(credentialIds[1].ToString(), "bitwarden.com", true) + ]; + var discoverableCiphers = ciphers.Where((cipher) => cipher.Login.MainFido2Credential.IsDiscoverable).ToList(); + aParams.RpId = "bitwarden.com"; + aParams.AllowCredentialDescriptorList = null; + sutProvider.GetDependency().GetAllDecryptedAsync().Returns(ciphers); + + await sutProvider.Sut.GetAssertionAsync(aParams); + + await sutProvider.GetDependency().Received().PickCredentialAsync(Arg.Is( + (pickCredentialParams) => pickCredentialParams.CipherIds.SequenceEqual(discoverableCiphers.Select((cipher) => cipher.Id)) && pickCredentialParams.UserVerification == aParams.RequireUserVerification + )); + } + + // it("should only ask for discoverable credentials matched by rpId when params does not contains allowedCredentials list", async () => { + // params.allowCredentialDescriptorList = undefined; + // const discoverableCiphers = ciphers.filter((c) => c.login.fido2Credentials[0].discoverable); + // userInterfaceSession.pickCredential.mockResolvedValue({ + // cipherId: discoverableCiphers[0].id, + // userVerified: false, + // }); + + // await authenticator.getAssertion(params, tab); + + // expect(userInterfaceSession.pickCredential).toHaveBeenCalledWith({ + // cipherIds: [discoverableCiphers[0].id], + // userVerification: false, + // }); + // }); + #endregion private byte[] RandomBytes(int length)