0

[webauthn] Use provider name for Windows passkeys

Use the new Windows WebAuthn v8 pwszAuthenticatorName property to label
credentials from third party providers on Windows.

Fixed: 396434681
Change-Id: I9044484a5d40617b0f1487f43710c5f659e91d8f
Reviewed-on: https://chromium-review.googlesource.com/c/chromium/src/+/6270536
Commit-Queue: Ken Buchanan <kenrb@chromium.org>
Reviewed-by: Ken Buchanan <kenrb@chromium.org>
Auto-Submit: Nina Satragno <nsatragno@chromium.org>
Cr-Commit-Position: refs/heads/main@{#1421527}
This commit is contained in:
Nina Satragno
2025-02-18 11:17:17 -08:00
committed by Chromium LUCI CQ
parent 49c6c62a6c
commit fdc85d82ca
8 changed files with 88 additions and 55 deletions

@@ -658,7 +658,8 @@ class WebAuthnWindowsAutofillIntegrationTest
"Flandre Scarlet"); "Flandre Scarlet");
device::PublicKeyCredentialRpEntity rp(kRpId); device::PublicKeyCredentialRpEntity rp(kRpId);
fake_webauthn_api_->InjectDiscoverableCredential( fake_webauthn_api_->InjectDiscoverableCredential(
kCredentialID1, std::move(rp), std::move(user)); kCredentialID1, std::move(rp), std::move(user),
/*provider_name=*/std::nullopt);
win_webauthn_api_override_ = win_webauthn_api_override_ =
std::make_unique<device::WinWebAuthnApi::ScopedOverride>( std::make_unique<device::WinWebAuthnApi::ScopedOverride>(
@@ -698,7 +699,8 @@ IN_PROC_BROWSER_TEST_F(WebAuthnWindowsAutofillIntegrationTest,
"Sakuya Izayoi"); "Sakuya Izayoi");
device::PublicKeyCredentialRpEntity rp(kRpId); device::PublicKeyCredentialRpEntity rp(kRpId);
fake_webauthn_api_->InjectDiscoverableCredential( fake_webauthn_api_->InjectDiscoverableCredential(
kCredentialID2, std::move(rp), std::move(user)); kCredentialID2, std::move(rp), std::move(user),
/*provider_name=*/std::nullopt);
RunSelectAccountTest(kConditionalUIRequestFiltered); RunSelectAccountTest(kConditionalUIRequestFiltered);
} }

@@ -84,7 +84,8 @@ TEST_F(LocalCredentialManagementTest, OneCredential) {
// With a credential injected, `HasCredentials` should return true and should // With a credential injected, `HasCredentials` should return true and should
// cache that in the profile. Enumerate should return that credential. // cache that in the profile. Enumerate should return that credential.
api_.InjectDiscoverableCredential(kCredId, {kRpId, std::nullopt}, api_.InjectDiscoverableCredential(kCredId, {kRpId, std::nullopt},
{{1, 2, 3, 4}, std::nullopt, std::nullopt}); {{1, 2, 3, 4}, std::nullopt, std::nullopt},
std::nullopt);
EXPECT_TRUE(HasCredentials()); EXPECT_TRUE(HasCredentials());
EXPECT_TRUE(profile_.GetPrefs()->GetBoolean(kHasPlatformCredentialsPref)); EXPECT_TRUE(profile_.GetPrefs()->GetBoolean(kHasPlatformCredentialsPref));
@@ -124,22 +125,26 @@ TEST_F(LocalCredentialManagementTest, Sorting) {
constexpr uint8_t kCredId7[] = {7}; constexpr uint8_t kCredId7[] = {7};
api_.InjectDiscoverableCredential(kCredId7, {"zzz.de", std::nullopt}, api_.InjectDiscoverableCredential(kCredId7, {"zzz.de", std::nullopt},
{{1, 2, 3, 4}, "username", std::nullopt}); {{1, 2, 3, 4}, "username", std::nullopt},
std::nullopt);
api_.InjectDiscoverableCredential(kCredId2, {"zzz.de", std::nullopt}, api_.InjectDiscoverableCredential(kCredId2, {"zzz.de", std::nullopt},
{{1, 2, 3, 4}, "username", std::nullopt}); {{1, 2, 3, 4}, "username", std::nullopt},
api_.InjectDiscoverableCredential(kCredId3, std::nullopt);
{"www.example.co.uk", std::nullopt}, api_.InjectDiscoverableCredential(
{{1, 2, 3, 4}, "user1", std::nullopt}); kCredId3, {"www.example.co.uk", std::nullopt},
api_.InjectDiscoverableCredential(kCredId4, {{1, 2, 3, 4}, "user1", std::nullopt}, std::nullopt);
{"foo.www.example.co.uk", std::nullopt}, api_.InjectDiscoverableCredential(
{{1, 2, 3, 4}, "user1", std::nullopt}); kCredId4, {"foo.www.example.co.uk", std::nullopt},
api_.InjectDiscoverableCredential(kCredId5, {{1, 2, 3, 4}, "user1", std::nullopt}, std::nullopt);
{"foo.example.co.uk", std::nullopt}, api_.InjectDiscoverableCredential(
{{1, 2, 3, 4}, "user1", std::nullopt}); kCredId5, {"foo.example.co.uk", std::nullopt},
{{1, 2, 3, 4}, "user1", std::nullopt}, std::nullopt);
api_.InjectDiscoverableCredential(kCredId6, {"aardvark.us", std::nullopt}, api_.InjectDiscoverableCredential(kCredId6, {"aardvark.us", std::nullopt},
{{1, 2, 3, 4}, "username", std::nullopt}); {{1, 2, 3, 4}, "username", std::nullopt},
std::nullopt);
api_.InjectDiscoverableCredential(kCredId1, {"example.co.uk", std::nullopt}, api_.InjectDiscoverableCredential(kCredId1, {"example.co.uk", std::nullopt},
{{1, 2, 3, 4}, "user2", std::nullopt}); {{1, 2, 3, 4}, "user2", std::nullopt},
std::nullopt);
const std::vector<device::DiscoverableCredentialMetadata> result = const std::vector<device::DiscoverableCredentialMetadata> result =
Enumerate().value(); Enumerate().value();

@@ -8409,7 +8409,8 @@ TEST_F(ResidentKeyAuthenticatorImplTest, ConditionalUI_Incognito) {
device::PublicKeyCredentialRpEntity rp(kTestRelyingPartyId); device::PublicKeyCredentialRpEntity rp(kTestRelyingPartyId);
device::PublicKeyCredentialUserEntity user({1, 2, 3, 4}); device::PublicKeyCredentialUserEntity user({1, 2, 3, 4});
fake_win_webauthn_api_.InjectDiscoverableCredential( fake_win_webauthn_api_.InjectDiscoverableCredential(
/*credential_id=*/{{4, 3, 2, 1}}, std::move(rp), std::move(user)); /*credential_id=*/{{4, 3, 2, 1}}, std::move(rp), std::move(user),
/*provider_name=*/std::nullopt);
// |SelectAccount| should not be called for conditional UI requests. // |SelectAccount| should not be called for conditional UI requests.
test_client_.delegate_config.expected_accounts = "<invalid>"; test_client_.delegate_config.expected_accounts = "<invalid>";

@@ -129,6 +129,9 @@ class COMPONENT_EXPORT(DEVICE_FIDO) VirtualFidoDevice : public FidoDevice {
std::optional<LargeBlob> large_blob; std::optional<LargeBlob> large_blob;
std::optional<std::array<uint8_t, 32>> large_blob_key; std::optional<std::array<uint8_t, 32>> large_blob_key;
std::optional<std::vector<uint8_t>> cred_blob; std::optional<std::vector<uint8_t>> cred_blob;
// The custom provider name for this credential.
std::optional<std::string> provider_name;
}; };
using Credential = std::pair<base::span<const uint8_t>, RegistrationData*>; using Credential = std::pair<base::span<const uint8_t>, RegistrationData*>;

@@ -57,6 +57,7 @@ constexpr char kRpId2[] = "meteora.example.com";
const std::vector<uint8_t> kUserId = {5, 6, 7, 8}; const std::vector<uint8_t> kUserId = {5, 6, 7, 8};
constexpr char kUserName[] = "unit-aarc-noa"; constexpr char kUserName[] = "unit-aarc-noa";
constexpr char kUserDisplayName[] = "Noa"; constexpr char kUserDisplayName[] = "Noa";
constexpr char kProviderName[] = "Windows Provider";
const std::vector<uint8_t> kLargeBlob = {'b', 'l', 'o', 'b'}; const std::vector<uint8_t> kLargeBlob = {'b', 'l', 'o', 'b'};
const std::vector<uint8_t> kUserId2 = {1, 1, 1, 1}; const std::vector<uint8_t> kUserId2 = {1, 1, 1, 1};
constexpr char kUserName2[] = "chloe"; constexpr char kUserName2[] = "chloe";
@@ -119,7 +120,8 @@ TEST_F(WinAuthenticatorTest,
GetCredentialInformationForRequest_HasCredentials) { GetCredentialInformationForRequest_HasCredentials) {
PublicKeyCredentialRpEntity rp(kRpId); PublicKeyCredentialRpEntity rp(kRpId);
PublicKeyCredentialUserEntity user(kUserId, kUserName, kUserDisplayName); PublicKeyCredentialUserEntity user(kUserId, kUserName, kUserDisplayName);
fake_webauthn_api_->InjectDiscoverableCredential(kCredentialId, rp, user); fake_webauthn_api_->InjectDiscoverableCredential(kCredentialId, rp, user,
kProviderName);
CtapGetAssertionRequest request(kRpId, /*client_data_json=*/""); CtapGetAssertionRequest request(kRpId, /*client_data_json=*/"");
GetCredentialFuture future; GetCredentialFuture future;
@@ -193,7 +195,8 @@ TEST_F(WinAuthenticatorTest, GetCredentialInformationForRequest_UnknownError) {
TEST_F(WinAuthenticatorTest, GetCredentialInformationForRequest_Unsupported) { TEST_F(WinAuthenticatorTest, GetCredentialInformationForRequest_Unsupported) {
PublicKeyCredentialRpEntity rp(kRpId); PublicKeyCredentialRpEntity rp(kRpId);
PublicKeyCredentialUserEntity user(kUserId, kUserName, kUserDisplayName); PublicKeyCredentialUserEntity user(kUserId, kUserName, kUserDisplayName);
fake_webauthn_api_->InjectDiscoverableCredential(kCredentialId, rp, user); fake_webauthn_api_->InjectDiscoverableCredential(kCredentialId, rp, user,
kProviderName);
fake_webauthn_api_->set_supports_silent_discovery(false); fake_webauthn_api_->set_supports_silent_discovery(false);
CtapGetAssertionRequest request(kRpId, /*client_data_json=*/""); CtapGetAssertionRequest request(kRpId, /*client_data_json=*/"");
@@ -218,11 +221,12 @@ TEST_F(WinAuthenticatorTest,
GetCredentialInformationForRequest_NonEmptyAllowList_Found) { GetCredentialInformationForRequest_NonEmptyAllowList_Found) {
PublicKeyCredentialRpEntity rp(kRpId); PublicKeyCredentialRpEntity rp(kRpId);
PublicKeyCredentialUserEntity user1(kUserId, kUserName, kUserDisplayName); PublicKeyCredentialUserEntity user1(kUserId, kUserName, kUserDisplayName);
fake_webauthn_api_->InjectDiscoverableCredential(kCredentialId, rp, user1); fake_webauthn_api_->InjectDiscoverableCredential(kCredentialId, rp, user1,
kProviderName);
PublicKeyCredentialUserEntity user2(kUserId2, kUserName2, kUserDisplayName2); PublicKeyCredentialUserEntity user2(kUserId2, kUserName2, kUserDisplayName2);
fake_webauthn_api_->InjectDiscoverableCredential(kCredentialId2, rp, fake_webauthn_api_->InjectDiscoverableCredential(
std::move(user2)); kCredentialId2, rp, std::move(user2), kProviderName);
CtapGetAssertionRequest request(kRpId, /*client_data_json=*/""); CtapGetAssertionRequest request(kRpId, /*client_data_json=*/"");
request.allow_list.emplace_back(CredentialType::kPublicKey, kCredentialId); request.allow_list.emplace_back(CredentialType::kPublicKey, kCredentialId);
@@ -247,8 +251,8 @@ TEST_F(WinAuthenticatorTest,
GetCredentialInformationForRequest_NonEmptyAllowList_NotMatching) { GetCredentialInformationForRequest_NonEmptyAllowList_NotMatching) {
PublicKeyCredentialRpEntity rp(kRpId); PublicKeyCredentialRpEntity rp(kRpId);
PublicKeyCredentialUserEntity user(kUserId, kUserName, kUserDisplayName); PublicKeyCredentialUserEntity user(kUserId, kUserName, kUserDisplayName);
fake_webauthn_api_->InjectDiscoverableCredential(kCredentialId, rp, fake_webauthn_api_->InjectDiscoverableCredential(
std::move(user)); kCredentialId, rp, std::move(user), kProviderName);
CtapGetAssertionRequest request(kRpId, /*client_data_json=*/""); CtapGetAssertionRequest request(kRpId, /*client_data_json=*/"");
request.allow_list.emplace_back(CredentialType::kPublicKey, kCredentialId2); request.allow_list.emplace_back(CredentialType::kPublicKey, kCredentialId2);
@@ -322,7 +326,8 @@ TEST_F(WinAuthenticatorTest,
TEST_F(WinAuthenticatorTest, EnumeratePlatformCredentials_NotSupported) { TEST_F(WinAuthenticatorTest, EnumeratePlatformCredentials_NotSupported) {
PublicKeyCredentialRpEntity rp(kRpId); PublicKeyCredentialRpEntity rp(kRpId);
PublicKeyCredentialUserEntity user(kUserId, kUserName, kUserDisplayName); PublicKeyCredentialUserEntity user(kUserId, kUserName, kUserDisplayName);
fake_webauthn_api_->InjectDiscoverableCredential(kCredentialId, rp, user); fake_webauthn_api_->InjectDiscoverableCredential(kCredentialId, rp, user,
kProviderName);
fake_webauthn_api_->set_supports_silent_discovery(false); fake_webauthn_api_->set_supports_silent_discovery(false);
base::test::TestFuture<std::vector<DiscoverableCredentialMetadata>> future; base::test::TestFuture<std::vector<DiscoverableCredentialMetadata>> future;
@@ -339,7 +344,8 @@ TEST_F(WinAuthenticatorTest, EnumeratePlatformCredentials_NotSupported) {
TEST_F(WinAuthenticatorTest, EnumeratePlatformCredentials_Supported) { TEST_F(WinAuthenticatorTest, EnumeratePlatformCredentials_Supported) {
PublicKeyCredentialRpEntity rp(kRpId); PublicKeyCredentialRpEntity rp(kRpId);
PublicKeyCredentialUserEntity user(kUserId, kUserName, kUserDisplayName); PublicKeyCredentialUserEntity user(kUserId, kUserName, kUserDisplayName);
fake_webauthn_api_->InjectDiscoverableCredential(kCredentialId, rp, user); fake_webauthn_api_->InjectDiscoverableCredential(kCredentialId, rp, user,
kProviderName);
fake_webauthn_api_->set_supports_silent_discovery(true); fake_webauthn_api_->set_supports_silent_discovery(true);
base::test::TestFuture<std::vector<DiscoverableCredentialMetadata>> future; base::test::TestFuture<std::vector<DiscoverableCredentialMetadata>> future;
@@ -358,6 +364,7 @@ TEST_F(WinAuthenticatorTest, EnumeratePlatformCredentials_Supported) {
EXPECT_EQ(cred.cred_id, kCredentialId); EXPECT_EQ(cred.cred_id, kCredentialId);
EXPECT_EQ(cred.user.name, kUserName); EXPECT_EQ(cred.user.name, kUserName);
EXPECT_EQ(cred.user.display_name, kUserDisplayName); EXPECT_EQ(cred.user.display_name, kUserDisplayName);
EXPECT_EQ(cred.provider_name, kProviderName);
} }
TEST_F(WinAuthenticatorTest, MakeCredentialLargeBlob) { TEST_F(WinAuthenticatorTest, MakeCredentialLargeBlob) {
@@ -445,8 +452,8 @@ TEST_F(WinAuthenticatorTest, GetAssertionLargeBlobNotSupported) {
SetVersion(WEBAUTHN_API_VERSION_2); SetVersion(WEBAUTHN_API_VERSION_2);
PublicKeyCredentialRpEntity rp(kRpId); PublicKeyCredentialRpEntity rp(kRpId);
PublicKeyCredentialUserEntity user(kUserId, kUserName, kUserDisplayName); PublicKeyCredentialUserEntity user(kUserId, kUserName, kUserDisplayName);
fake_webauthn_api_->InjectDiscoverableCredential(kCredentialId, std::move(rp), fake_webauthn_api_->InjectDiscoverableCredential(
std::move(user)); kCredentialId, std::move(rp), std::move(user), kProviderName);
{ {
// Read large blob. // Read large blob.
CtapGetAssertionRequest request(kRpId, /*client_data_json=*/""); CtapGetAssertionRequest request(kRpId, /*client_data_json=*/"");
@@ -477,8 +484,8 @@ TEST_F(WinAuthenticatorTest, GetAssertionLargeBlobError) {
SetVersion(WEBAUTHN_API_VERSION_3); SetVersion(WEBAUTHN_API_VERSION_3);
PublicKeyCredentialRpEntity rp(kRpId); PublicKeyCredentialRpEntity rp(kRpId);
PublicKeyCredentialUserEntity user(kUserId, kUserName, kUserDisplayName); PublicKeyCredentialUserEntity user(kUserId, kUserName, kUserDisplayName);
fake_webauthn_api_->InjectDiscoverableCredential(kCredentialId, std::move(rp), fake_webauthn_api_->InjectDiscoverableCredential(
std::move(user)); kCredentialId, std::move(rp), std::move(user), kProviderName);
fake_webauthn_api_->set_large_blob_result( fake_webauthn_api_->set_large_blob_result(
WEBAUTHN_CRED_LARGE_BLOB_STATUS_NOT_SUPPORTED); WEBAUTHN_CRED_LARGE_BLOB_STATUS_NOT_SUPPORTED);
{ {
@@ -511,8 +518,8 @@ TEST_F(WinAuthenticatorTest, GetAssertionLargeBlobSuccess) {
SetVersion(WEBAUTHN_API_VERSION_3); SetVersion(WEBAUTHN_API_VERSION_3);
PublicKeyCredentialRpEntity rp(kRpId); PublicKeyCredentialRpEntity rp(kRpId);
PublicKeyCredentialUserEntity user(kUserId, kUserName, kUserDisplayName); PublicKeyCredentialUserEntity user(kUserId, kUserName, kUserDisplayName);
fake_webauthn_api_->InjectDiscoverableCredential(kCredentialId, std::move(rp), fake_webauthn_api_->InjectDiscoverableCredential(
std::move(user)); kCredentialId, std::move(rp), std::move(user), kProviderName);
{ {
// Read large blob. // Read large blob.
CtapGetAssertionRequest request(kRpId, /*client_data_json=*/""); CtapGetAssertionRequest request(kRpId, /*client_data_json=*/"");
@@ -561,8 +568,8 @@ TEST_F(WinAuthenticatorTest, SignalUnknownCredential_NotFound) {
SetVersion(WEBAUTHN_API_VERSION_4); SetVersion(WEBAUTHN_API_VERSION_4);
PublicKeyCredentialRpEntity rp(kRpId); PublicKeyCredentialRpEntity rp(kRpId);
PublicKeyCredentialUserEntity user(kUserId, kUserName, kUserDisplayName); PublicKeyCredentialUserEntity user(kUserId, kUserName, kUserDisplayName);
fake_webauthn_api_->InjectDiscoverableCredential(kCredentialId, std::move(rp), fake_webauthn_api_->InjectDiscoverableCredential(
std::move(user)); kCredentialId, std::move(rp), std::move(user), kProviderName);
ASSERT_EQ(fake_webauthn_api_->registrations().size(), 1u); ASSERT_EQ(fake_webauthn_api_->registrations().size(), 1u);
WinWebAuthnApiAuthenticator::SignalUnknownCredential(fake_webauthn_api_.get(), WinWebAuthnApiAuthenticator::SignalUnknownCredential(fake_webauthn_api_.get(),
@@ -577,8 +584,8 @@ TEST_F(WinAuthenticatorTest, SignalUnknownCredential_WrongRpId) {
SetVersion(WEBAUTHN_API_VERSION_4); SetVersion(WEBAUTHN_API_VERSION_4);
PublicKeyCredentialRpEntity rp(kRpId); PublicKeyCredentialRpEntity rp(kRpId);
PublicKeyCredentialUserEntity user(kUserId, kUserName, kUserDisplayName); PublicKeyCredentialUserEntity user(kUserId, kUserName, kUserDisplayName);
fake_webauthn_api_->InjectDiscoverableCredential(kCredentialId, std::move(rp), fake_webauthn_api_->InjectDiscoverableCredential(
std::move(user)); kCredentialId, std::move(rp), std::move(user), kProviderName);
ASSERT_EQ(fake_webauthn_api_->registrations().size(), 1u); ASSERT_EQ(fake_webauthn_api_->registrations().size(), 1u);
WinWebAuthnApiAuthenticator::SignalUnknownCredential(fake_webauthn_api_.get(), WinWebAuthnApiAuthenticator::SignalUnknownCredential(fake_webauthn_api_.get(),
@@ -594,8 +601,8 @@ TEST_F(WinAuthenticatorTest, SignalUnknownCredential_NotSupported) {
fake_webauthn_api_->set_supports_silent_discovery(false); fake_webauthn_api_->set_supports_silent_discovery(false);
PublicKeyCredentialRpEntity rp(kRpId); PublicKeyCredentialRpEntity rp(kRpId);
PublicKeyCredentialUserEntity user(kUserId, kUserName, kUserDisplayName); PublicKeyCredentialUserEntity user(kUserId, kUserName, kUserDisplayName);
fake_webauthn_api_->InjectDiscoverableCredential(kCredentialId, std::move(rp), fake_webauthn_api_->InjectDiscoverableCredential(
std::move(user)); kCredentialId, std::move(rp), std::move(user), kProviderName);
ASSERT_EQ(fake_webauthn_api_->registrations().size(), 1u); ASSERT_EQ(fake_webauthn_api_->registrations().size(), 1u);
WinWebAuthnApiAuthenticator::SignalUnknownCredential(fake_webauthn_api_.get(), WinWebAuthnApiAuthenticator::SignalUnknownCredential(fake_webauthn_api_.get(),
@@ -610,8 +617,8 @@ TEST_F(WinAuthenticatorTest, SignalUnknownCredential) {
SetVersion(WEBAUTHN_API_VERSION_4); SetVersion(WEBAUTHN_API_VERSION_4);
PublicKeyCredentialRpEntity rp(kRpId); PublicKeyCredentialRpEntity rp(kRpId);
PublicKeyCredentialUserEntity user(kUserId, kUserName, kUserDisplayName); PublicKeyCredentialUserEntity user(kUserId, kUserName, kUserDisplayName);
fake_webauthn_api_->InjectDiscoverableCredential(kCredentialId, std::move(rp), fake_webauthn_api_->InjectDiscoverableCredential(
std::move(user)); kCredentialId, std::move(rp), std::move(user), kProviderName);
ASSERT_EQ(fake_webauthn_api_->registrations().size(), 1u); ASSERT_EQ(fake_webauthn_api_->registrations().size(), 1u);
WinWebAuthnApiAuthenticator::SignalUnknownCredential(fake_webauthn_api_.get(), WinWebAuthnApiAuthenticator::SignalUnknownCredential(fake_webauthn_api_.get(),
@@ -626,8 +633,8 @@ TEST_F(WinAuthenticatorTest, SignalAllAcceptedCredentials_Found) {
SetVersion(WEBAUTHN_API_VERSION_4); SetVersion(WEBAUTHN_API_VERSION_4);
PublicKeyCredentialRpEntity rp(kRpId); PublicKeyCredentialRpEntity rp(kRpId);
PublicKeyCredentialUserEntity user(kUserId, kUserName, kUserDisplayName); PublicKeyCredentialUserEntity user(kUserId, kUserName, kUserDisplayName);
fake_webauthn_api_->InjectDiscoverableCredential(kCredentialId, std::move(rp), fake_webauthn_api_->InjectDiscoverableCredential(
std::move(user)); kCredentialId, std::move(rp), std::move(user), kProviderName);
ASSERT_EQ(fake_webauthn_api_->registrations().size(), 1u); ASSERT_EQ(fake_webauthn_api_->registrations().size(), 1u);
WinWebAuthnApiAuthenticator::SignalAllAcceptedCredentials( WinWebAuthnApiAuthenticator::SignalAllAcceptedCredentials(
@@ -642,8 +649,8 @@ TEST_F(WinAuthenticatorTest, SignalAllAcceptedCredentials_NoMatchingUserId) {
SetVersion(WEBAUTHN_API_VERSION_4); SetVersion(WEBAUTHN_API_VERSION_4);
PublicKeyCredentialRpEntity rp(kRpId); PublicKeyCredentialRpEntity rp(kRpId);
PublicKeyCredentialUserEntity user(kUserId, kUserName, kUserDisplayName); PublicKeyCredentialUserEntity user(kUserId, kUserName, kUserDisplayName);
fake_webauthn_api_->InjectDiscoverableCredential(kCredentialId, std::move(rp), fake_webauthn_api_->InjectDiscoverableCredential(
std::move(user)); kCredentialId, std::move(rp), std::move(user), kProviderName);
ASSERT_EQ(fake_webauthn_api_->registrations().size(), 1u); ASSERT_EQ(fake_webauthn_api_->registrations().size(), 1u);
WinWebAuthnApiAuthenticator::SignalAllAcceptedCredentials( WinWebAuthnApiAuthenticator::SignalAllAcceptedCredentials(
@@ -658,8 +665,8 @@ TEST_F(WinAuthenticatorTest, SignalAllAcceptedCredentials_NoMatchingRpId) {
SetVersion(WEBAUTHN_API_VERSION_4); SetVersion(WEBAUTHN_API_VERSION_4);
PublicKeyCredentialRpEntity rp(kRpId); PublicKeyCredentialRpEntity rp(kRpId);
PublicKeyCredentialUserEntity user(kUserId, kUserName, kUserDisplayName); PublicKeyCredentialUserEntity user(kUserId, kUserName, kUserDisplayName);
fake_webauthn_api_->InjectDiscoverableCredential(kCredentialId, std::move(rp), fake_webauthn_api_->InjectDiscoverableCredential(
std::move(user)); kCredentialId, std::move(rp), std::move(user), kProviderName);
ASSERT_EQ(fake_webauthn_api_->registrations().size(), 1u); ASSERT_EQ(fake_webauthn_api_->registrations().size(), 1u);
WinWebAuthnApiAuthenticator::SignalAllAcceptedCredentials( WinWebAuthnApiAuthenticator::SignalAllAcceptedCredentials(
@@ -675,8 +682,8 @@ TEST_F(WinAuthenticatorTest, SignalAllAcceptedCredentials_NotSupported) {
fake_webauthn_api_->set_supports_silent_discovery(false); fake_webauthn_api_->set_supports_silent_discovery(false);
PublicKeyCredentialRpEntity rp(kRpId); PublicKeyCredentialRpEntity rp(kRpId);
PublicKeyCredentialUserEntity user(kUserId, kUserName, kUserDisplayName); PublicKeyCredentialUserEntity user(kUserId, kUserName, kUserDisplayName);
fake_webauthn_api_->InjectDiscoverableCredential(kCredentialId, std::move(rp), fake_webauthn_api_->InjectDiscoverableCredential(
std::move(user)); kCredentialId, std::move(rp), std::move(user), kProviderName);
ASSERT_EQ(fake_webauthn_api_->registrations().size(), 1u); ASSERT_EQ(fake_webauthn_api_->registrations().size(), 1u);
WinWebAuthnApiAuthenticator::SignalAllAcceptedCredentials( WinWebAuthnApiAuthenticator::SignalAllAcceptedCredentials(
@@ -692,8 +699,8 @@ TEST_F(WinAuthenticatorTest, SignalAllAcceptedCredentials_NotFound) {
SetVersion(WEBAUTHN_API_VERSION_4); SetVersion(WEBAUTHN_API_VERSION_4);
PublicKeyCredentialRpEntity rp(kRpId); PublicKeyCredentialRpEntity rp(kRpId);
PublicKeyCredentialUserEntity user(kUserId, kUserName, kUserDisplayName); PublicKeyCredentialUserEntity user(kUserId, kUserName, kUserDisplayName);
fake_webauthn_api_->InjectDiscoverableCredential(kCredentialId, std::move(rp), fake_webauthn_api_->InjectDiscoverableCredential(
std::move(user)); kCredentialId, std::move(rp), std::move(user), kProviderName);
ASSERT_EQ(fake_webauthn_api_->registrations().size(), 1u); ASSERT_EQ(fake_webauthn_api_->registrations().size(), 1u);
WinWebAuthnApiAuthenticator::SignalAllAcceptedCredentials( WinWebAuthnApiAuthenticator::SignalAllAcceptedCredentials(

@@ -94,6 +94,7 @@ struct FakeWinWebAuthnApi::CredentialInfo {
WEBAUTHN_CREDENTIAL_DETAILS details; WEBAUTHN_CREDENTIAL_DETAILS details;
std::vector<uint8_t> credential_id; std::vector<uint8_t> credential_id;
std::optional<std::u16string> provider_name;
WEBAUTHN_RP_ENTITY_INFORMATION rp; WEBAUTHN_RP_ENTITY_INFORMATION rp;
std::u16string rp_id; std::u16string rp_id;
@@ -162,13 +163,15 @@ bool FakeWinWebAuthnApi::InjectNonDiscoverableCredential(
bool FakeWinWebAuthnApi::InjectDiscoverableCredential( bool FakeWinWebAuthnApi::InjectDiscoverableCredential(
base::span<const uint8_t> credential_id, base::span<const uint8_t> credential_id,
device::PublicKeyCredentialRpEntity rp, device::PublicKeyCredentialRpEntity rp,
device::PublicKeyCredentialUserEntity user) { device::PublicKeyCredentialUserEntity user,
std::optional<std::string> provider_name) {
RegistrationData registration(VirtualFidoDevice::PrivateKey::FreshP256Key(), RegistrationData registration(VirtualFidoDevice::PrivateKey::FreshP256Key(),
fido_parsing_utils::CreateSHA256Hash(rp.id), fido_parsing_utils::CreateSHA256Hash(rp.id),
/*counter=*/0); /*counter=*/0);
registration.is_resident = true; registration.is_resident = true;
registration.user = std::move(user); registration.user = std::move(user);
registration.rp = std::move(rp); registration.rp = std::move(rp);
registration.provider_name = std::move(provider_name);
bool was_inserted; bool was_inserted;
std::tie(std::ignore, was_inserted) = std::tie(std::ignore, was_inserted) =
@@ -498,6 +501,10 @@ HRESULT FakeWinWebAuthnApi::GetPlatformCredentialList(
auto credential = std::make_unique<CredentialInfo>(); auto credential = std::make_unique<CredentialInfo>();
credential->credential_id = registration.first; credential->credential_id = registration.first;
credential->provider_name = registration.second.provider_name
? std::make_optional(base::UTF8ToUTF16(
*registration.second.provider_name))
: std::nullopt;
credential->rp_id = base::UTF8ToUTF16(registration.second.rp->id); credential->rp_id = base::UTF8ToUTF16(registration.second.rp->id);
credential->rp_name = credential->rp_name =
base::UTF8ToUTF16(registration.second.rp->name.value_or("")); base::UTF8ToUTF16(registration.second.rp->name.value_or(""));
@@ -519,12 +526,16 @@ HRESULT FakeWinWebAuthnApi::GetPlatformCredentialList(
.pwszDisplayName = base::as_wcstr(credential->user_display_name), .pwszDisplayName = base::as_wcstr(credential->user_display_name),
}; };
credential->details = { credential->details = {
.dwVersion = WEBAUTHN_CREDENTIAL_DETAILS_VERSION_1, .dwVersion = WEBAUTHN_CREDENTIAL_DETAILS_CURRENT_VERSION,
.cbCredentialID = static_cast<DWORD>(credential->credential_id.size()), .cbCredentialID = static_cast<DWORD>(credential->credential_id.size()),
.pbCredentialID = credential->credential_id.data(), .pbCredentialID = credential->credential_id.data(),
.pRpInformation = &credential->rp, .pRpInformation = &credential->rp,
.pUserInformation = &credential->user, .pUserInformation = &credential->user,
.bRemovable = true, .bRemovable = true,
.pwszAuthenticatorName =
credential->provider_name
? base::as_wcstr(*credential->provider_name)
: nullptr,
}; };
credential_list->win_credentials.push_back(&credential->details); credential_list->win_credentials.push_back(&credential->details);
credential_list->credentials.push_back(std::move(credential)); credential_list->credentials.push_back(std::move(credential));

@@ -47,7 +47,8 @@ class COMPONENT_EXPORT(DEVICE_FIDO) FakeWinWebAuthnApi : public WinWebAuthnApi {
// AuthenticatorGetAssertion(). // AuthenticatorGetAssertion().
bool InjectDiscoverableCredential(base::span<const uint8_t> credential_id, bool InjectDiscoverableCredential(base::span<const uint8_t> credential_id,
device::PublicKeyCredentialRpEntity rp, device::PublicKeyCredentialRpEntity rp,
device::PublicKeyCredentialUserEntity user); device::PublicKeyCredentialUserEntity user,
std::optional<std::string> provider_name);
// Inject the return value for WinWebAuthnApi::IsAvailable(). // Inject the return value for WinWebAuthnApi::IsAvailable().
void set_available(bool available) { is_available_ = available; } void set_available(bool available) { is_available_ = available; }

@@ -375,8 +375,11 @@ WinCredentialDetailsListToCredentialMetadata(
user->pwszDisplayName user->pwszDisplayName
? std::make_optional(base::WideToUTF8(user->pwszDisplayName)) ? std::make_optional(base::WideToUTF8(user->pwszDisplayName))
: std::nullopt), : std::nullopt),
// TODO(nsatragno): integrate with pwszAuthenticatorName. credential->dwVersion >= WEBAUTHN_CREDENTIAL_DETAILS_VERSION_3 &&
/*provider_name=*/std::nullopt); credential->pwszAuthenticatorName
? std::make_optional(
base::WideToUTF8(credential->pwszAuthenticatorName))
: std::nullopt);
metadata.system_created = !credential->bRemovable; metadata.system_created = !credential->bRemovable;
result.push_back(std::move(metadata)); result.push_back(std::move(metadata));
} }