0

[webauthn] Use provider name for MacOS passkeys

Use ASAuthorizationWebBrowserPlatformPublicKeyCredential's providerName
to identify the provider of a passkey sourced from a third-party passkey
provider on MacOS.

Fixed: 392837090
Change-Id: I0a6747c451c813768065cd4f70d13f96a89e2541
Reviewed-on: https://chromium-review.googlesource.com/c/chromium/src/+/6213993
Reviewed-by: Mohamed Amir Yosef <mamir@chromium.org>
Commit-Queue: Mohamed Amir Yosef <mamir@chromium.org>
Auto-Submit: Nina Satragno <nsatragno@chromium.org>
Reviewed-by: Adem Derinel <derinel@google.com>
Cr-Commit-Position: refs/heads/main@{#1419889}
This commit is contained in:
Nina Satragno
2025-02-13 07:27:37 -08:00
committed by Chromium LUCI CQ
parent a3c55198aa
commit dffa0e82f4
23 changed files with 169 additions and 64 deletions

@ -71,21 +71,24 @@ const device::DiscoverableCredentialMetadata user1{
device::PublicKeyCredentialUserEntity(
device::fido_parsing_utils::Materialize(kUserId),
kUserName1,
/*display_name=*/std::nullopt)};
/*display_name=*/std::nullopt),
/*provider_name=*/std::nullopt};
const device::DiscoverableCredentialMetadata user2{
device::AuthenticatorType::kOther, kRpId,
device::fido_parsing_utils::Materialize(kCredId2),
device::PublicKeyCredentialUserEntity(
device::fido_parsing_utils::Materialize(kUserId),
kUserName2,
/*display_name=*/std::nullopt)};
/*display_name=*/std::nullopt),
/*provider_name=*/std::nullopt};
const device::DiscoverableCredentialMetadata userGpm{
device::AuthenticatorType::kEnclave, kRpId,
device::fido_parsing_utils::Materialize(kCredIdGpm),
device::PublicKeyCredentialUserEntity(
device::fido_parsing_utils::Materialize(kUserId),
kUserName1,
/*display_name=*/std::nullopt)};
/*display_name=*/std::nullopt),
/*provider_name=*/std::nullopt};
PasskeyCredential CreatePasskey(std::vector<uint8_t> cred_id,
std::string username,

@ -39,7 +39,7 @@ AccountHoverListModel::AccountHoverListModel(
items_.emplace_back(
NameTokenForDisplay(cred.user.name.value_or("")),
AuthenticatorRequestDialogModel::GetMechanismDescription(
cred.source, dialog_model->priority_phone_name),
cred, dialog_model->priority_phone_name),
ui::ImageModel::FromVectorIcon(vector_icons::kPasskeyIcon,
dialog_model->ui_disabled_
? ui::kColorIconDisabled

@ -664,23 +664,38 @@ class GPMPasskeysAuthenticatorDialogTest : public DialogBrowserTest {
device::DiscoverableCredentialMetadata gpm_cred(
device::AuthenticatorType::kEnclave, "example.com", {1},
device::PublicKeyCredentialUserEntity({1}, "elisa.g.beckett@gmail.com",
"Elisa Beckett"));
"Elisa Beckett"),
std::nullopt);
device::DiscoverableCredentialMetadata local_cred1(
device::AuthenticatorType::kTouchID, "example.com", {1},
device::PublicKeyCredentialUserEntity({1}, "elisa.g.beckett@gmail.com",
"Elisa Beckett"));
"Elisa Beckett"),
std::nullopt);
device::DiscoverableCredentialMetadata local_cred2(
device::AuthenticatorType::kTouchID, "example.com", {2},
device::PublicKeyCredentialUserEntity({2}, "elisa.beckett@ink-42.com",
"Elisa Beckett"));
"Elisa Beckett"),
std::nullopt);
device::DiscoverableCredentialMetadata phone_cred1(
device::AuthenticatorType::kPhone, "example.com", {3},
device::PublicKeyCredentialUserEntity({1}, "elisa.g.beckett@gmail.com",
"Elisa Beckett"));
"Elisa Beckett"),
std::nullopt);
device::DiscoverableCredentialMetadata phone_cred2(
device::AuthenticatorType::kPhone, "example.com", {4},
device::PublicKeyCredentialUserEntity({2}, "elisa.beckett@ink-42.com",
"Elisa Beckett"));
"Elisa Beckett"),
std::nullopt);
device::DiscoverableCredentialMetadata ick_cred1(
device::AuthenticatorType::kICloudKeychain, "example.com", {5},
device::PublicKeyCredentialUserEntity({1}, "elisa.beckett@gmail.com",
"Elisa Beckett"),
"Example Passkey Provider");
device::DiscoverableCredentialMetadata ick_cred2(
device::AuthenticatorType::kICloudKeychain, "example.com", {6},
device::PublicKeyCredentialUserEntity({2}, "elisa.beckett@ink-42.com",
"Elisa Beckett"),
"Another Example Passkey Provider");
model_->user_entity = local_cred1.user;
// Configure a phone from sync.
@ -822,6 +837,13 @@ class GPMPasskeysAuthenticatorDialogTest : public DialogBrowserTest {
} else if (name == "gpm_locked_pin") {
controller_->SetCurrentStepForTesting(
AuthenticatorRequestDialogModel::Step::kGPMLockedPin);
} else if (name == "icloud_keychain_cred") {
transport_availability.has_empty_allow_list = true;
controller_->set_allow_icloud_keychain(true);
transport_availability.recognized_credentials = {
std::move(ick_cred1),
std::move(ick_cred2),
};
} else {
NOTREACHED();
}
@ -973,6 +995,11 @@ IN_PROC_BROWSER_TEST_F(GPMPasskeysAuthenticatorDialogTest,
ShowAndVerifyUi();
}
IN_PROC_BROWSER_TEST_F(GPMPasskeysAuthenticatorDialogTest,
InvokeUi_icloud_keychain_cred) {
ShowAndVerifyUi();
}
#if BUILDFLAG(IS_MAC)
IN_PROC_BROWSER_TEST_F(GPMPasskeysAuthenticatorDialogTest, InvokeUi_touchid) {
if (__builtin_available(macos 12, *)) {

@ -441,7 +441,8 @@ TEST_F(PasskeysHandlerTest, TestHandleEdit) {
device::PublicKeyCredentialUserEntity(
{0xa, 0xa, 0xa, 0xa, 0xa, 0xa, 0xa, 0xa, 0xa, 0xa, 0xa, 0xa,
0xa, 0xa, 0xa, 0xa},
"new-username", "new-username")}};
"new-username", "new-username"),
/*provider_name=*/std::nullopt}};
std::move(callback).Run(std::move(credential_metadata));
base::RunLoop().RunUntilIdle();
});

@ -1412,7 +1412,8 @@ void AuthenticatorRequestDialogController::SelectAccount(
for (const auto& response : ephemeral_state_.responses_) {
model_->creds.emplace_back(AuthenticatorType::kOther,
model_->relying_party_id,
response.credential->id, *response.user_entity);
response.credential->id, *response.user_entity,
/*provider_name=*/std::nullopt);
}
selection_callback_ = std::move(callback);
SetCurrentStep(Step::kSelectAccount);
@ -2145,7 +2146,7 @@ void AuthenticatorRequestDialogController::PopulateMechanisms() {
base::Unretained(this), cred.cred_id));
mechanism.description =
AuthenticatorRequestDialogModel::GetMechanismDescription(
cred.source, model_->priority_phone_name);
cred, model_->priority_phone_name);
}
for (const auto& password : passwords_) {
Mechanism mechanism(

@ -29,6 +29,7 @@
#include "content/public/browser/global_routing_id.h"
#include "content/public/browser/render_frame_host.h"
#include "content/public/browser/web_contents.h"
#include "device/fido/discoverable_credential_metadata.h"
#include "device/fido/features.h"
#include "device/fido/fido_types.h"
#include "ui/base/l10n/l10n_util.h"
@ -91,16 +92,22 @@ AUTHENTICATOR_EVENTS
// static
std::u16string AuthenticatorRequestDialogModel::GetMechanismDescription(
device::AuthenticatorType type,
const device::DiscoverableCredentialMetadata& cred,
const std::optional<std::string>& phone_name) {
if (type == device::AuthenticatorType::kPhone) {
if (cred.source == device::AuthenticatorType::kPhone) {
return l10n_util::GetStringFUTF16(IDS_WEBAUTHN_SOURCE_PHONE,
base::UTF8ToUTF16(*phone_name));
}
int message;
const bool gpm_enabled =
base::FeatureList::IsEnabled(device::kWebAuthnEnclaveAuthenticator);
switch (type) {
if (cred.provider_name) {
return gpm_enabled ? base::UTF8ToUTF16(*cred.provider_name)
: l10n_util::GetStringFUTF16(
IDS_WEBAUTHN_SOURCE_CUSTOM_VENDOR,
base::UTF8ToUTF16(*cred.provider_name));
}
int message;
switch (cred.source) {
case device::AuthenticatorType::kWinNative:
message = gpm_enabled ? IDS_WEBAUTHN_SOURCE_WINDOWS_HELLO_NEW
: IDS_WEBAUTHN_SOURCE_WINDOWS_HELLO;
@ -110,8 +117,6 @@ std::u16string AuthenticatorRequestDialogModel::GetMechanismDescription(
: IDS_WEBAUTHN_SOURCE_CHROME_PROFILE;
break;
case device::AuthenticatorType::kICloudKeychain:
// TODO(crbug.com/40265798): Use IDS_WEBAUTHN_SOURCE_CUSTOM_VENDOR for
// third party providers.
message = gpm_enabled ? IDS_WEBAUTHN_SOURCE_ICLOUD_KEYCHAIN_NEW
: IDS_WEBAUTHN_SOURCE_ICLOUD_KEYCHAIN;
break;

@ -379,7 +379,7 @@ struct AuthenticatorRequestDialogModel
// Returns a user-friendly description for a |type|. If |type| is kPhone, a
// |phone_name| must be passed.
static std::u16string GetMechanismDescription(
device::AuthenticatorType type,
const device::DiscoverableCredentialMetadata& cred,
const std::optional<std::string>& phone_name);
explicit AuthenticatorRequestDialogModel(

@ -312,32 +312,66 @@ const device::PublicKeyCredentialUserEntity kPhoneUser2({3, 4, 5, 6},
"D",
std::nullopt);
const device::DiscoverableCredentialMetadata
kCred1(device::AuthenticatorType::kOther, "rp.com", {0}, kUser1);
const device::DiscoverableCredentialMetadata kCred1(
device::AuthenticatorType::kOther,
"rp.com",
{0},
kUser1,
/*provider_name=*/std::nullopt);
const device::DiscoverableCredentialMetadata kCred1FromICloudKeychain(
device::AuthenticatorType::kICloudKeychain,
"rp.com",
{4},
kUser1);
kUser1,
/*provider_name=*/std::nullopt);
const device::DiscoverableCredentialMetadata kCred1FromChromeOS(
device::AuthenticatorType::kChromeOS,
"rp.com",
{4},
kUser1);
const device::DiscoverableCredentialMetadata
kCred2(device::AuthenticatorType::kOther, "rp.com", {1}, kUser2);
const device::DiscoverableCredentialMetadata
kPhoneCred1(device::AuthenticatorType::kPhone, "rp.com", {2}, kPhoneUser1);
const device::DiscoverableCredentialMetadata
kPhoneCred2(device::AuthenticatorType::kPhone, "rp.com", {3}, kPhoneUser2);
const device::DiscoverableCredentialMetadata
kWinCred1(device::AuthenticatorType::kWinNative, "rp.com", {0}, kUser1);
const device::DiscoverableCredentialMetadata
kWinCred2(device::AuthenticatorType::kWinNative, "rp.com", {1}, kUser2);
const device::DiscoverableCredentialMetadata
kTouchIDCred1(device::AuthenticatorType::kTouchID, "rp.com", {4}, kUser1);
const device::DiscoverableCredentialMetadata
kEnclaveCred1(device::AuthenticatorType::kEnclave, "rp.com", {1}, kUser1);
kUser1,
/*provider_name=*/std::nullopt);
const device::DiscoverableCredentialMetadata kCred2(
device::AuthenticatorType::kOther,
"rp.com",
{1},
kUser2,
/*provider_name=*/std::nullopt);
const device::DiscoverableCredentialMetadata kPhoneCred1(
device::AuthenticatorType::kPhone,
"rp.com",
{2},
kPhoneUser1,
/*provider_name=*/std::nullopt);
const device::DiscoverableCredentialMetadata kPhoneCred2(
device::AuthenticatorType::kPhone,
"rp.com",
{3},
kPhoneUser2,
/*provider_name=*/std::nullopt);
const device::DiscoverableCredentialMetadata kWinCred1(
device::AuthenticatorType::kWinNative,
"rp.com",
{0},
kUser1,
/*provider_name=*/std::nullopt);
const device::DiscoverableCredentialMetadata kWinCred2(
device::AuthenticatorType::kWinNative,
"rp.com",
{1},
kUser2,
/*provider_name=*/std::nullopt);
const device::DiscoverableCredentialMetadata kTouchIDCred1(
device::AuthenticatorType::kTouchID,
"rp.com",
{4},
kUser1,
/*provider_name=*/std::nullopt);
const device::DiscoverableCredentialMetadata kEnclaveCred1(
device::AuthenticatorType::kEnclave,
"rp.com",
{1},
kUser1,
/*provider_name=*/std::nullopt);
AuthenticatorRequestDialogModel::Mechanism::CredentialInfo CredentialInfoFrom(
const device::DiscoverableCredentialMetadata& metadata) {

@ -1171,7 +1171,8 @@ void ChromeAuthenticatorRequestDelegate::GetPhoneContactableGpmPasskeysForRpId(
device::PublicKeyCredentialUserEntity(
std::vector<uint8_t>(passkey.user_id().begin(),
passkey.user_id().end()),
passkey.user_name(), passkey.user_display_name()));
passkey.user_name(), passkey.user_display_name()),
/*provider_name=*/std::nullopt);
}
}

@ -651,7 +651,8 @@ TEST_F(ChromeAuthenticatorRequestDelegateTest, FilterGoogleComPasskeys) {
device::AuthenticatorType::kOther, test.rp_id,
std::vector<uint8_t>{0},
device::PublicKeyCredentialUserEntity(
std::vector<uint8_t>(user_id.begin(), user_id.end())));
std::vector<uint8_t>(user_id.begin(), user_id.end())),
/*provider_name=*/std::nullopt);
}
data.has_platform_authenticator_credential = test.recognized_credential;
@ -659,7 +660,8 @@ TEST_F(ChromeAuthenticatorRequestDelegateTest, FilterGoogleComPasskeys) {
// affect setting the recognized credentials flag.
data.recognized_credentials.emplace_back(
device::AuthenticatorType::kICloudKeychain, test.rp_id,
std::vector<uint8_t>{0}, device::PublicKeyCredentialUserEntity({1}));
std::vector<uint8_t>{0}, device::PublicKeyCredentialUserEntity({1}),
/*provider_name=*/std::nullopt);
data.has_icloud_keychain_credential = device::FidoRequestHandlerBase::
RecognizedCredential::kHasRecognizedCredential;
@ -708,7 +710,8 @@ TEST_F(ChromeAuthenticatorRequestDelegateTest,
data.recognized_credentials.emplace_back(
device::AuthenticatorType::kOther, kGoogleRpId, std::vector<uint8_t>{0},
device::PublicKeyCredentialUserEntity(
std::vector<uint8_t>(user_id.begin(), user_id.end())));
std::vector<uint8_t>(user_id.begin(), user_id.end())),
/*provider_name=*/std::nullopt);
data.has_platform_authenticator_credential = device::FidoRequestHandlerBase::
RecognizedCredential::kHasRecognizedCredential;
@ -1010,7 +1013,8 @@ TEST_F(ChromeAuthenticatorRequestDelegateWithPasswordsTest,
transports_info.recognized_credentials = {
device::DiscoverableCredentialMetadata(
device::AuthenticatorType::kEnclave, kRpId, {},
device::PublicKeyCredentialUserEntity())};
device::PublicKeyCredentialUserEntity(),
/*provider_name=*/std::nullopt)};
// still waiting for passwords.
EXPECT_CALL(mock_closure, Run).Times(0);

@ -51,7 +51,8 @@ void LocalCredentialManagementMac::Enumerate(
credential_metadata.emplace_back(
device::AuthenticatorType::kTouchID, credential.rp_id,
credential.credential_id,
credential.metadata.ToPublicKeyCredentialUserEntity());
credential.metadata.ToPublicKeyCredentialUserEntity(),
/*provider_name=*/std::nullopt);
}
std::sort(credential_metadata.begin(), credential_metadata.end(),
CredentialComparator());

@ -9485,7 +9485,8 @@ class ICloudKeychainAuthenticatorImplTest : public AuthenticatorImplTest {
static std::vector<device::DiscoverableCredentialMetadata> GetCredentials() {
device::DiscoverableCredentialMetadata metadata(
device::AuthenticatorType::kICloudKeychain, kTestRelyingPartyId,
{1, 2, 3, 4}, {{5, 6, 7, 8}, "name", "displayName"});
{1, 2, 3, 4}, {{5, 6, 7, 8}, "name", "displayName"},
/*provider_name=*/std::nullopt);
return {std::move(metadata)};
}

@ -4,17 +4,21 @@
#include "device/fido/discoverable_credential_metadata.h"
#include <optional>
namespace device {
DiscoverableCredentialMetadata::DiscoverableCredentialMetadata(
AuthenticatorType source_in,
std::string rp_id_in,
std::vector<uint8_t> cred_id_in,
PublicKeyCredentialUserEntity user_in)
PublicKeyCredentialUserEntity user_in,
std::optional<std::string> provider_name_in)
: source(source_in),
rp_id(std::move(rp_id_in)),
cred_id(std::move(cred_id_in)),
user(std::move(user_in)) {}
user(std::move(user_in)),
provider_name(std::move(provider_name_in)) {}
DiscoverableCredentialMetadata::DiscoverableCredentialMetadata() = default;
DiscoverableCredentialMetadata::DiscoverableCredentialMetadata(

@ -5,6 +5,7 @@
#ifndef DEVICE_FIDO_DISCOVERABLE_CREDENTIAL_METADATA_H_
#define DEVICE_FIDO_DISCOVERABLE_CREDENTIAL_METADATA_H_
#include <optional>
#include <vector>
#include "base/component_export.h"
@ -21,7 +22,8 @@ class COMPONENT_EXPORT(DEVICE_FIDO) DiscoverableCredentialMetadata {
DiscoverableCredentialMetadata(AuthenticatorType source,
std::string rp_id,
std::vector<uint8_t> cred_id,
PublicKeyCredentialUserEntity user);
PublicKeyCredentialUserEntity user,
std::optional<std::string> provider_name);
DiscoverableCredentialMetadata();
DiscoverableCredentialMetadata(const DiscoverableCredentialMetadata& other);
@ -41,6 +43,10 @@ class COMPONENT_EXPORT(DEVICE_FIDO) DiscoverableCredentialMetadata {
// automatically by the system. This can happen on Windows where (at least) a
// credential for login.microsoft.com can be auto-created for users.
bool system_created = false;
// The name of the third-party provider the passkey is stored in. This is
// populated for credentials coming from the MacOS API.
std::optional<std::string> provider_name;
};
} // namespace device

@ -76,7 +76,8 @@ void TouchIdAuthenticator::GetPlatformCredentialInfoForRequest(
for (const auto& credential : *credentials) {
result.emplace_back(AuthenticatorType::kTouchID, request.rp_id,
credential.credential_id,
credential.metadata.ToPublicKeyCredentialUserEntity());
credential.metadata.ToPublicKeyCredentialUserEntity(),
/*provider_name=*/std::nullopt);
}
std::move(callback).Run(
std::move(result),

@ -60,7 +60,7 @@ TEST_F(TouchIdAuthenticatorTest, GetPlatformCredentialInfoForRequest_RK) {
->first;
DiscoverableCredentialMetadata credential_metadata(
AuthenticatorType::kTouchID, kRp1, credential.credential_id,
std::move(user));
std::move(user), /*provider_name=*/std::nullopt);
// Inject a non resident credential for RP 2. This one should be ignored.
PublicKeyCredentialUserEntity user2(kUserId2);
@ -105,7 +105,7 @@ TEST_F(TouchIdAuthenticatorTest, GetPlatformCredentialInfoForRequest_NonRK) {
->first;
DiscoverableCredentialMetadata credential_metadata(
AuthenticatorType::kTouchID, kRp1, credential.credential_id,
std::move(user));
std::move(user), /*provider_name=*/std::nullopt);
{
// RP 1 should report the credential if it is in the allow list but not

@ -22,6 +22,7 @@ API_AVAILABLE(macos(13.3))
@property(nonatomic, copy) NSString* name;
@property(nonatomic, copy) NSString* relyingParty;
@property(nonatomic, copy) NSData* userHandle;
@property(nonatomic, copy) NSString* providerName;
@end
@implementation FakeBrowserPlatformPublicKeyCredential
@ -29,6 +30,7 @@ API_AVAILABLE(macos(13.3))
@synthesize name = _name;
@synthesize relyingParty = _relyingParty;
@synthesize userHandle = _userHandle;
@synthesize providerName = _providerName;
@end
API_AVAILABLE(macos(13.3))
@ -199,6 +201,8 @@ void FakeSystemInterface::GetPlatformCredentials(
cred.relyingParty = base::SysUTF8ToNSString(rp_id);
cred.name = base::SysUTF8ToNSString(cred_values.user.name.value_or(""));
[ret addObject:cred];
cred.providerName = base::SysUTF8ToNSString(
cred_values.provider_name.value_or("(Not provided)"));
}
block(ret);

@ -255,7 +255,8 @@ class API_AVAILABLE(macos(13.3)) Authenticator : public FidoAuthenticator {
ToVector(cred.userHandle), cred.name.UTF8String,
/* iCloud Keychain does not store
a displayName for passkeys */
std::nullopt));
std::nullopt),
cred.providerName.UTF8String);
}
const auto has_credentials =
ret.empty() ? FidoRequestHandlerBase::RecognizedCredential::

@ -511,7 +511,8 @@ TEST_F(iCloudKeychainTest, FetchCredentialMetadata) {
{AuthenticatorType::kICloudKeychain,
"example.com",
{1, 2, 3, 4},
{{4, 3, 2, 1}, "name", std::nullopt}}};
{{4, 3, 2, 1}, "name", std::nullopt},
"Example provider"}};
fake_->SetCredentials(creds);
base::test::TestFuture<std::vector<DiscoverableCredentialMetadata>,
FidoRequestHandlerBase::RecognizedCredential>
@ -538,11 +539,13 @@ TEST_F(iCloudKeychainTest, FetchCredentialMetadataWithAllowlist) {
{AuthenticatorType::kICloudKeychain,
"example.com",
{1, 2, 3, 4},
{{4, 3, 2, 1}, "name", std::nullopt}},
{{4, 3, 2, 1}, "name", std::nullopt},
"Example provider"},
{AuthenticatorType::kICloudKeychain,
"example.com",
{1, 2, 3, 5},
{{4, 3, 2, 2}, "name", std::nullopt}},
{{4, 3, 2, 2}, "name", std::nullopt},
"Example provider"},
};
fake_->SetCredentials(creds);
base::test::TestFuture<std::vector<DiscoverableCredentialMetadata>,

@ -41,7 +41,8 @@ void VirtualFidoDeviceAuthenticator::GetPlatformCredentialInfoForRequest(
}))) {
credentials.emplace_back(
AuthenticatorType::kOther, request.rp_id, registration.first,
registration.second.user.value_or(PublicKeyCredentialUserEntity()));
registration.second.user.value_or(PublicKeyCredentialUserEntity()),
std::nullopt);
}
}
FidoRequestHandlerBase::RecognizedCredential has_credentials =

@ -125,7 +125,7 @@ TEST_F(VirtualFidoDeviceAuthenticatorTest,
EXPECT_TRUE(future.Wait());
DiscoverableCredentialMetadata expected = DiscoverableCredentialMetadata(
AuthenticatorType::kOther, kRpId, credential_id,
PublicKeyCredentialUserEntity());
PublicKeyCredentialUserEntity(), /*provider_name=*/std::nullopt);
EXPECT_THAT(std::get<0>(future.Get()),
testing::UnorderedElementsAre(expected));
EXPECT_EQ(
@ -147,10 +147,12 @@ TEST_F(VirtualFidoDeviceAuthenticatorTest,
authenticator_->GetPlatformCredentialInfoForRequest(
request, CtapGetAssertionOptions(), future.GetCallback());
EXPECT_TRUE(future.Wait());
DiscoverableCredentialMetadata expected1 = DiscoverableCredentialMetadata(
AuthenticatorType::kOther, kRpId, id1, user1);
DiscoverableCredentialMetadata expected2 = DiscoverableCredentialMetadata(
AuthenticatorType::kOther, kRpId, id2, user2);
DiscoverableCredentialMetadata expected1 =
DiscoverableCredentialMetadata(AuthenticatorType::kOther, kRpId, id1,
user1, /*provider_name=*/std::nullopt);
DiscoverableCredentialMetadata expected2 =
DiscoverableCredentialMetadata(AuthenticatorType::kOther, kRpId, id2,
user2, /*provider_name=*/std::nullopt);
EXPECT_THAT(std::get<0>(future.Get()),
testing::UnorderedElementsAre(expected1, expected2));
EXPECT_EQ(

@ -128,7 +128,8 @@ TEST_F(WinAuthenticatorTest,
EXPECT_TRUE(future.Wait());
DiscoverableCredentialMetadata expected = DiscoverableCredentialMetadata(
AuthenticatorType::kWinNative, kRpId, kCredentialId, user);
AuthenticatorType::kWinNative, kRpId, kCredentialId, user,
/*provider_name=*/std::nullopt);
EXPECT_EQ(std::get<0>(future.Get()),
std::vector<DiscoverableCredentialMetadata>{expected});
EXPECT_EQ(
@ -202,7 +203,8 @@ TEST_F(WinAuthenticatorTest, GetCredentialInformationForRequest_Unsupported) {
EXPECT_TRUE(future.Wait());
DiscoverableCredentialMetadata expected = DiscoverableCredentialMetadata(
AuthenticatorType::kWinNative, kRpId, kCredentialId, user);
AuthenticatorType::kWinNative, kRpId, kCredentialId, user,
/*provider_name=*/std::nullopt);
EXPECT_EQ(std::get<0>(future.Get()),
std::vector<DiscoverableCredentialMetadata>{});
EXPECT_EQ(std::get<1>(future.Get()),
@ -230,7 +232,8 @@ TEST_F(WinAuthenticatorTest,
EXPECT_TRUE(future.Wait());
DiscoverableCredentialMetadata expected = DiscoverableCredentialMetadata(
AuthenticatorType::kWinNative, kRpId, kCredentialId, user1);
AuthenticatorType::kWinNative, kRpId, kCredentialId, user1,
/*provider_name=*/std::nullopt);
EXPECT_THAT(std::get<0>(future.Get()), testing::ElementsAre(expected));
EXPECT_EQ(
std::get<1>(future.Get()),

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