using Bit.Api.Auth.Models.Request.WebAuthn; using Bit.Api.KeyManagement.Validators; using Bit.Core.Auth.Entities; using Bit.Core.Auth.Repositories; using Bit.Core.Entities; using Bit.Core.Exceptions; using Bit.Test.Common.AutoFixture; using Bit.Test.Common.AutoFixture.Attributes; using NSubstitute; using Xunit; namespace Bit.Api.Test.KeyManagement.Validators; [SutProviderCustomize] public class WebAuthnLoginKeyRotationValidatorTests { [Theory] [BitAutoData] public async Task ValidateAsync_Succeeds_ReturnsValidCredentials( SutProvider sutProvider, User user, IEnumerable webauthnRotateCredentialData) { var guid = Guid.NewGuid(); var webauthnKeysToRotate = webauthnRotateCredentialData.Select(e => new WebAuthnLoginRotateKeyRequestModel { Id = guid, EncryptedPublicKey = e.EncryptedPublicKey, EncryptedUserKey = e.EncryptedUserKey }).ToList(); var data = new WebAuthnCredential { Id = guid, SupportsPrf = true, EncryptedPublicKey = "TestPublicKey", EncryptedUserKey = "TestUserKey", EncryptedPrivateKey = "TestPrivateKey" }; sutProvider.GetDependency().GetManyByUserIdAsync(user.Id) .Returns(new List { data }); var result = await sutProvider.Sut.ValidateAsync(user, webauthnKeysToRotate); Assert.Single(result); Assert.Equal(guid, result.First().Id); } [Theory] [BitAutoData(false, null, null, null)] [BitAutoData(true, null, "TestPublicKey", "TestPrivateKey")] [BitAutoData(true, "TestUserKey", null, "TestPrivateKey")] [BitAutoData(true, "TestUserKey", "TestPublicKey", null)] public async Task ValidateAsync_NotEncryptedOrPrfNotSupported_Ignores( bool supportsPrf, string encryptedUserKey, string encryptedPublicKey, string encryptedPrivateKey, SutProvider sutProvider, User user, IEnumerable webauthnRotateCredentialData) { var guid = Guid.NewGuid(); var webauthnKeysToRotate = webauthnRotateCredentialData.Select(e => new WebAuthnLoginRotateKeyRequestModel { Id = guid, EncryptedUserKey = e.EncryptedUserKey, EncryptedPublicKey = e.EncryptedPublicKey, }).ToList(); var data = new WebAuthnCredential { Id = guid, SupportsPrf = supportsPrf, EncryptedUserKey = encryptedUserKey, EncryptedPublicKey = encryptedPublicKey, EncryptedPrivateKey = encryptedPrivateKey }; sutProvider.GetDependency().GetManyByUserIdAsync(user.Id) .Returns(new List { data }); var result = await sutProvider.Sut.ValidateAsync(user, webauthnKeysToRotate); Assert.Empty(result); } [Theory] [BitAutoData] public async Task ValidateAsync_WebAuthnKeysNotMatchingExisting_Throws( SutProvider sutProvider, User user, IEnumerable webauthnRotateCredentialData) { var webauthnKeysToRotate = webauthnRotateCredentialData.Select(e => new WebAuthnLoginRotateKeyRequestModel { Id = Guid.Parse("00000000-0000-0000-0000-000000000001"), EncryptedPublicKey = e.EncryptedPublicKey, EncryptedUserKey = e.EncryptedUserKey }).ToList(); var data = new WebAuthnCredential { Id = Guid.Parse("00000000-0000-0000-0000-000000000002"), SupportsPrf = true, EncryptedPublicKey = "TestPublicKey", EncryptedUserKey = "TestUserKey", EncryptedPrivateKey = "TestPrivateKey" }; sutProvider.GetDependency().GetManyByUserIdAsync(user.Id) .Returns(new List { data }); await Assert.ThrowsAsync(async () => await sutProvider.Sut.ValidateAsync(user, webauthnKeysToRotate)); } [Theory] [BitAutoData] public async Task ValidateAsync_NullUserKey_Throws( SutProvider sutProvider, User user, IEnumerable webauthnRotateCredentialData) { var guid = Guid.NewGuid(); var webauthnKeysToRotate = webauthnRotateCredentialData.Select(e => new WebAuthnLoginRotateKeyRequestModel { Id = guid, EncryptedPublicKey = e.EncryptedPublicKey, EncryptedUserKey = null }).ToList(); var data = new WebAuthnCredential { Id = guid, SupportsPrf = true, EncryptedPublicKey = "TestPublicKey", EncryptedUserKey = "TestUserKey", EncryptedPrivateKey = "TestPrivateKey" }; sutProvider.GetDependency().GetManyByUserIdAsync(user.Id) .Returns(new List { data }); await Assert.ThrowsAsync(async () => await sutProvider.Sut.ValidateAsync(user, webauthnKeysToRotate)); } [Theory] [BitAutoData] public async Task ValidateAsync_NullPublicKey_Throws( SutProvider sutProvider, User user, IEnumerable webauthnRotateCredentialData) { var guid = Guid.NewGuid(); var webauthnKeysToRotate = webauthnRotateCredentialData.Select(e => new WebAuthnLoginRotateKeyRequestModel { Id = guid, EncryptedUserKey = e.EncryptedUserKey, EncryptedPublicKey = null, }).ToList(); var data = new WebAuthnCredential { Id = guid, SupportsPrf = true, EncryptedPublicKey = "TestPublicKey", EncryptedUserKey = "TestUserKey", EncryptedPrivateKey = "TestPrivateKey" }; sutProvider.GetDependency().GetManyByUserIdAsync(user.Id) .Returns(new List { data }); await Assert.ThrowsAsync(async () => await sutProvider.Sut.ValidateAsync(user, webauthnKeysToRotate)); } }