blob: 9e0dc0aa963fe6106e4a0018b898ef655ac436fd [file]
// Copyright 2026 The Chromium Authors
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
#include "content/browser/webid/identity_credential_source_impl.h"
#include <memory>
#include <vector>
#include "base/memory/ptr_util.h"
#include "base/memory/raw_ptr.h"
#include "base/task/sequenced_task_runner.h"
#include "base/test/bind.h"
#include "base/test/gmock_callback_support.h"
#include "content/browser/webid/identity_provider_info.h"
#include "content/browser/webid/request_page_data.h"
#include "content/browser/webid/request_service.h"
#include "content/browser/webid/test/mock_api_permission_delegate.h"
#include "content/browser/webid/test/mock_auto_reauthn_permission_delegate.h"
#include "content/browser/webid/test/mock_identity_registry.h"
#include "content/browser/webid/test/mock_identity_request_dialog_controller.h"
#include "content/browser/webid/test/mock_idp_network_request_manager.h"
#include "content/browser/webid/test/mock_permission_delegate.h"
#include "content/public/browser/webid/identity_request_account.h"
#include "content/public/test/navigation_simulator.h"
#include "content/public/test/test_renderer_host.h"
#include "testing/gmock/include/gmock/gmock.h"
#include "testing/gtest/include/gtest/gtest.h"
#include "ui/gfx/image/image.h"
#include "url/gurl.h"
#include "url/origin.h"
using ::testing::_;
using ::testing::DoAll;
using ::testing::NiceMock;
using ::testing::Return;
using ::testing::WithArg;
namespace content::webid {
class TestIdentityCredentialSourceImpl : public IdentityCredentialSourceImpl {
public:
explicit TestIdentityCredentialSourceImpl(RenderFrameHost* rfh)
: IdentityCredentialSourceImpl(rfh) {}
static void InitializeRequestService(
RequestService* request_service,
std::unique_ptr<IdpNetworkRequestManager> network_manager) {
if (!request_service->fedcm_metrics_) {
request_service->fedcm_metrics_ = request_service->CreateFedCmMetrics();
}
request_service->network_manager_ = std::move(network_manager);
request_service->accounts_dialog_display_time_ = base::TimeTicks::Now();
}
static void SetAccounts(
RequestService* request_service,
std::vector<scoped_refptr<IdentityRequestAccount>> accounts) {
request_service->accounts_ = std::move(accounts);
}
static void SetIdpInfo(RequestService* request_service,
const GURL& idp_config_url,
std::unique_ptr<IdentityProviderInfo> idp_info) {
request_service->idp_infos_[idp_config_url] = std::move(idp_info);
}
static void SetIdentitySelectionType(
RequestService* request_service,
RequestService::IdentitySelectionType type) {
request_service->identity_selection_type_ = type;
}
};
namespace {
constexpr char kIdpUrl[] = "https://idp.example";
constexpr char kConfigUrl[] = "https://idp.example/fedcm.json";
constexpr char kAccountsUrl[] = "https://idp.example/accounts";
constexpr char kTokenUrl[] = "https://idp.example/token";
constexpr char kAccountId[] = "123";
constexpr char kAccountIdSignIn[] = "signin";
constexpr char kAccountIdSignUp[] = "signup";
} // namespace
class IdentityCredentialSourceImplTest : public RenderViewHostTestHarness {
public:
void SetUp() override {
RenderViewHostTestHarness::SetUp();
NavigateAndCommit(GURL("https://www.example.com"));
source_ =
IdentityCredentialSourceImpl::GetOrCreateForCurrentDocument(main_rfh());
auto network_manager =
std::make_unique<NiceMock<MockIdpNetworkRequestManager>>();
network_manager_ = network_manager.get();
source_->SetNetworkManagerForTests(std::move(network_manager));
permission_delegate_ = std::make_unique<NiceMock<MockPermissionDelegate>>();
source_->SetPermissionDelegateForTests(permission_delegate_.get());
}
void TearDown() override {
source_ = nullptr;
network_manager_ = nullptr;
RenderViewHostTestHarness::TearDown();
}
protected:
raw_ptr<IdentityCredentialSourceImpl> source_;
raw_ptr<MockIdpNetworkRequestManager> network_manager_;
std::unique_ptr<MockPermissionDelegate> permission_delegate_;
};
TEST_F(IdentityCredentialSourceImplTest, SuccessfulFetching) {
GURL idp_url(kIdpUrl);
GURL config_url(kConfigUrl);
GURL accounts_url(kAccountsUrl);
// Mock IdP Signin Status
EXPECT_CALL(*permission_delegate_,
GetIdpSigninStatus(url::Origin::Create(idp_url)))
.WillRepeatedly(Return(true));
// Mock FetchWellKnown
IdpNetworkRequestManager::WellKnown well_known;
well_known.provider_urls = std::set<GURL>{config_url};
EXPECT_CALL(*network_manager_, FetchWellKnown(config_url, _))
.WillOnce(base::test::RunOnceCallback<1>(
FetchStatus{ParseStatus::kSuccess, 200}, well_known));
// Mock FetchConfig
IdpNetworkRequestManager::Endpoints endpoints;
endpoints.token = GURL(kTokenUrl);
endpoints.accounts = accounts_url;
IdentityProviderMetadata idp_metadata;
idp_metadata.idp_login_url = GURL("https://idp.example/login");
EXPECT_CALL(*network_manager_, FetchConfig(config_url, _, _, _))
.WillOnce(base::test::RunOnceCallback<3>(
FetchStatus{ParseStatus::kSuccess, 200}, endpoints, idp_metadata));
// Mock SendAccountsRequest
IdentityRequestAccountPtr account = base::MakeRefCounted<
IdentityRequestAccount>(
kAccountId, "[email protected]", "Test User", "[email protected]",
"Test User", "Test", GURL(), "", "",
/*the original string is fc432178f9155c4e24762de5b9505f2eexample.com*/
std::vector<std::string>{
"870f48f3c28efb5dbf46d14881d802a4c34141a36ef9e66d28cec211b1969f7d"},
std::vector<std::string>(), std::vector<std::string>(),
std::vector<std::string>(),
content::IdentityRequestAccount::LoginState::kSignIn);
IdpNetworkRequestManager::AccountsResponse accounts_response;
accounts_response.site_salt = "fc432178f9155c4e24762de5b9505f2e";
accounts_response.accounts.push_back(account);
EXPECT_CALL(*network_manager_, SendAccountsRequest(_, accounts_url, _, _))
.WillOnce(
[&](const url::Origin&, const GURL&, const std::string&,
IdpNetworkRequestManager::AccountsRequestCallback callback) {
base::SequencedTaskRunner::GetCurrentDefault()->PostTask(
FROM_HERE,
base::BindOnce(std::move(callback),
FetchStatus{ParseStatus::kSuccess, 200},
std::move(accounts_response)));
return true;
});
base::RunLoop run_loop;
source_->GetIdentityCredentialSuggestions(
{config_url},
base::BindLambdaForTesting(
[&](const std::optional<std::vector<IdentityRequestAccountPtr>>&
accounts) {
ASSERT_TRUE(accounts.has_value());
ASSERT_EQ(1u, accounts->size());
EXPECT_EQ(kAccountId, accounts->at(0)->id);
run_loop.Quit();
}));
run_loop.Run();
}
TEST_F(IdentityCredentialSourceImplTest, UserNotSignedInToIdP) {
GURL idp_url(kIdpUrl);
// Mock IdP Signin Status to return false (not signed in)
EXPECT_CALL(*permission_delegate_,
GetIdpSigninStatus(url::Origin::Create(idp_url)))
.WillOnce(Return(false));
// Should NOT call FetchWellKnown or anything else.
EXPECT_CALL(*network_manager_, FetchWellKnown(_, _)).Times(0);
EXPECT_CALL(*network_manager_, SendAccountsRequest(_, _, _, _)).Times(0);
base::RunLoop run_loop;
source_->GetIdentityCredentialSuggestions(
{idp_url},
base::BindLambdaForTesting(
[&](const std::optional<std::vector<IdentityRequestAccountPtr>>&
accounts) {
// Should return empty list because request was skipped
ASSERT_TRUE(accounts.has_value());
EXPECT_TRUE(accounts->empty());
run_loop.Quit();
}));
run_loop.Run();
}
TEST_F(IdentityCredentialSourceImplTest, FilterOutSignupAccount) {
GURL idp_url(kIdpUrl);
GURL config_url(kConfigUrl);
GURL accounts_url(kAccountsUrl);
// Mock IdP Signin Status
EXPECT_CALL(*permission_delegate_,
GetIdpSigninStatus(url::Origin::Create(idp_url)))
.WillRepeatedly(Return(true));
// Mock FetchWellKnown
IdpNetworkRequestManager::WellKnown well_known;
well_known.provider_urls = std::set<GURL>{config_url};
EXPECT_CALL(*network_manager_, FetchWellKnown(config_url, _))
.WillOnce(base::test::RunOnceCallback<1>(
FetchStatus{ParseStatus::kSuccess, 200}, well_known));
// Mock FetchConfig
IdpNetworkRequestManager::Endpoints endpoints;
endpoints.token = GURL(kTokenUrl);
endpoints.accounts = accounts_url;
IdentityProviderMetadata idp_metadata;
idp_metadata.idp_login_url = GURL("https://idp.example/login");
EXPECT_CALL(*network_manager_, FetchConfig(config_url, _, _, _))
.WillOnce(base::test::RunOnceCallback<3>(
FetchStatus{ParseStatus::kSuccess, 200}, endpoints, idp_metadata));
// Mock SendAccountsRequest with two accounts: one matching origin, one not.
IdentityRequestAccountPtr account_matching = base::MakeRefCounted<
IdentityRequestAccount>(
kAccountIdSignIn, "[email protected]", "Test User", "[email protected]",
"Test User", "Test", GURL(), "", "",
/*the original string is fc432178f9155c4e24762de5b9505f2eexample.com*/
std::vector<std::string>{
"870f48f3c28efb5dbf46d14881d802a4c34141a36ef9e66d28cec211b1969f7d"},
std::vector<std::string>(), std::vector<std::string>(),
std::vector<std::string>());
IdentityRequestAccountPtr account_not_matching =
base::MakeRefCounted<IdentityRequestAccount>(
kAccountIdSignUp, "[email protected]", "Test User", "[email protected]",
"Test User", "Test", GURL(), "", "", std::vector<std::string>(),
std::vector<std::string>(), std::vector<std::string>(),
std::vector<std::string>());
IdpNetworkRequestManager::AccountsResponse accounts_response;
accounts_response.site_salt = "fc432178f9155c4e24762de5b9505f2e";
accounts_response.accounts.push_back(account_matching);
accounts_response.accounts.push_back(account_not_matching);
EXPECT_CALL(*network_manager_, SendAccountsRequest(_, accounts_url, _, _))
.WillOnce(
[&](const url::Origin&, const GURL&, const std::string&,
IdpNetworkRequestManager::AccountsRequestCallback callback) {
base::SequencedTaskRunner::GetCurrentDefault()->PostTask(
FROM_HERE,
base::BindOnce(std::move(callback),
FetchStatus{ParseStatus::kSuccess, 200},
std::move(accounts_response)));
return true;
});
base::RunLoop run_loop;
source_->GetIdentityCredentialSuggestions(
{config_url},
base::BindLambdaForTesting(
[&](const std::optional<std::vector<IdentityRequestAccountPtr>>&
accounts) {
ASSERT_TRUE(accounts.has_value());
// Should only have the matching account.
ASSERT_EQ(1u, accounts->size());
EXPECT_EQ(kAccountIdSignIn, accounts->at(0)->id);
run_loop.Quit();
}));
run_loop.Run();
}
TEST_F(IdentityCredentialSourceImplTest, SelectAccountSameSite) {
GURL config_url(kConfigUrl);
url::Origin idp_origin = url::Origin::Create(config_url);
MockApiPermissionDelegate api_permission_delegate;
EXPECT_CALL(api_permission_delegate, GetApiPermissionStatus(_))
.WillRepeatedly(Return(FederatedIdentityApiPermissionContextDelegate::
PermissionStatus::GRANTED));
MockAutoReauthnPermissionDelegate auto_reauthn_permission_delegate;
EXPECT_CALL(auto_reauthn_permission_delegate, IsAutoReauthnSettingEnabled())
.WillRepeatedly(Return(false));
MockIdentityRegistry identity_registry(web_contents(), nullptr,
idp_origin.GetURL());
mojo::Remote<blink::mojom::FederatedAuthRequest> remote;
RequestService& request_service = RequestService::CreateForTesting(
*main_rfh(), &api_permission_delegate, &auto_reauthn_permission_delegate,
permission_delegate_.get(), &identity_registry,
remote.BindNewPipeAndPassReceiver());
TestIdentityCredentialSourceImpl::InitializeRequestService(
&request_service,
std::make_unique<NiceMock<MockIdpNetworkRequestManager>>());
request_service.SetDialogControllerForTests(
std::make_unique<NiceMock<MockIdentityRequestDialogController>>());
RequestPageData::GetOrCreateForPage(main_rfh()->GetPage())
->SetPendingWebIdentityRequest(&request_service);
blink::mojom::IdentityProviderRequestOptionsPtr options =
blink::mojom::IdentityProviderRequestOptions::New();
options->config = blink::mojom::IdentityProviderConfig::New();
options->config->config_url = config_url;
auto idp_info = std::make_unique<IdentityProviderInfo>(
options, IdpNetworkRequestManager::Endpoints(),
IdentityProviderMetadata(), blink::mojom::RpContext::kSignIn,
blink::mojom::RpMode::kPassive, std::nullopt);
idp_info->client_is_third_party_to_top_frame_origin = false;
IdentityProviderMetadata idp_metadata;
idp_metadata.config_url = config_url;
idp_info->data = base::MakeRefCounted<IdentityProviderData>(
"idp", idp_metadata, ClientMetadata(GURL(), GURL(), GURL(), gfx::Image()),
blink::mojom::RpContext::kSignIn, std::nullopt,
std::vector<IdentityRequestDialogDisclosureField>(),
/*has_login_status_mismatch=*/false);
IdentityRequestAccountPtr account =
base::MakeRefCounted<IdentityRequestAccount>(
kAccountId, "[email protected]", "Test User", "[email protected]",
"Test User", "Test", GURL(), "", "", std::vector<std::string>(),
std::vector<std::string>(), std::vector<std::string>(),
std::vector<std::string>(),
content::IdentityRequestAccount::LoginState::kSignIn);
account->identity_provider = idp_info->data;
IdpNetworkRequestManager::AccountsResponse accounts_response;
accounts_response.accounts.push_back(account);
TestIdentityCredentialSourceImpl::SetAccounts(
&request_service, std::move(accounts_response.accounts));
TestIdentityCredentialSourceImpl::SetIdpInfo(&request_service, config_url,
std::move(idp_info));
TestIdentityCredentialSourceImpl::SetIdentitySelectionType(
&request_service, RequestService::kAutoPassive);
// Should succeed because it is same-site (main frame)
EXPECT_TRUE(source_->SelectAccount(idp_origin, kAccountId));
RequestPageData::GetOrCreateForPage(main_rfh()->GetPage())
->SetPendingWebIdentityRequest(nullptr);
}
TEST_F(IdentityCredentialSourceImplTest, SelectAccountCrossSiteFail) {
GURL config_url(kConfigUrl);
url::Origin idp_origin = url::Origin::Create(config_url);
RenderFrameHost* subframe =
RenderFrameHostTester::For(main_rfh())->AppendChild("subframe");
subframe = NavigationSimulator::NavigateAndCommitFromDocument(
GURL("https://other.com"), subframe);
MockApiPermissionDelegate api_permission_delegate;
EXPECT_CALL(api_permission_delegate, GetApiPermissionStatus(_))
.WillRepeatedly(Return(FederatedIdentityApiPermissionContextDelegate::
PermissionStatus::GRANTED));
MockAutoReauthnPermissionDelegate auto_reauthn_permission_delegate;
EXPECT_CALL(auto_reauthn_permission_delegate, IsAutoReauthnSettingEnabled())
.WillRepeatedly(Return(false));
MockIdentityRegistry identity_registry(web_contents(), nullptr,
idp_origin.GetURL());
mojo::Remote<blink::mojom::FederatedAuthRequest> remote;
RequestService& request_service = RequestService::CreateForTesting(
*subframe, &api_permission_delegate, &auto_reauthn_permission_delegate,
permission_delegate_.get(), &identity_registry,
remote.BindNewPipeAndPassReceiver());
TestIdentityCredentialSourceImpl::InitializeRequestService(
&request_service,
std::make_unique<NiceMock<MockIdpNetworkRequestManager>>());
request_service.SetDialogControllerForTests(
std::make_unique<NiceMock<MockIdentityRequestDialogController>>());
RequestPageData::GetOrCreateForPage(main_rfh()->GetPage())
->SetPendingWebIdentityRequest(&request_service);
blink::mojom::IdentityProviderRequestOptionsPtr options =
blink::mojom::IdentityProviderRequestOptions::New();
options->config = blink::mojom::IdentityProviderConfig::New();
options->config->config_url = config_url;
auto idp_info = std::make_unique<IdentityProviderInfo>(
options, IdpNetworkRequestManager::Endpoints(),
IdentityProviderMetadata(), blink::mojom::RpContext::kSignIn,
blink::mojom::RpMode::kPassive, std::nullopt);
idp_info->client_is_third_party_to_top_frame_origin = true;
IdentityProviderMetadata idp_metadata;
idp_metadata.config_url = config_url;
idp_info->data = base::MakeRefCounted<IdentityProviderData>(
"idp", idp_metadata, ClientMetadata(GURL(), GURL(), GURL(), gfx::Image()),
blink::mojom::RpContext::kSignIn, std::nullopt,
std::vector<IdentityRequestDialogDisclosureField>(),
/*has_login_status_mismatch=*/false);
IdentityRequestAccountPtr account =
base::MakeRefCounted<IdentityRequestAccount>(
kAccountId, "[email protected]", "Test User", "[email protected]",
"Test User", "Test", GURL(), "", "", std::vector<std::string>(),
std::vector<std::string>(), std::vector<std::string>(),
std::vector<std::string>(),
content::IdentityRequestAccount::LoginState::kSignIn);
account->identity_provider = idp_info->data;
IdpNetworkRequestManager::AccountsResponse accounts_response;
accounts_response.accounts.push_back(account);
TestIdentityCredentialSourceImpl::SetAccounts(
&request_service, std::move(accounts_response.accounts));
TestIdentityCredentialSourceImpl::SetIdpInfo(&request_service, config_url,
std::move(idp_info));
TestIdentityCredentialSourceImpl::SetIdentitySelectionType(
&request_service, RequestService::kAutoPassive);
// Should fail because it is cross-site and third party.
EXPECT_FALSE(source_->SelectAccount(idp_origin, kAccountId));
RequestPageData::GetOrCreateForPage(main_rfh()->GetPage())
->SetPendingWebIdentityRequest(nullptr);
}
TEST_F(IdentityCredentialSourceImplTest,
SelectAccountCrossSiteButNotThirdPartySuccess) {
GURL config_url(kConfigUrl);
url::Origin idp_origin = url::Origin::Create(config_url);
RenderFrameHost* subframe =
RenderFrameHostTester::For(main_rfh())->AppendChild("subframe");
subframe = NavigationSimulator::NavigateAndCommitFromDocument(
GURL("https://other.com"), subframe);
MockApiPermissionDelegate api_permission_delegate;
EXPECT_CALL(api_permission_delegate, GetApiPermissionStatus(_))
.WillRepeatedly(Return(FederatedIdentityApiPermissionContextDelegate::
PermissionStatus::GRANTED));
MockAutoReauthnPermissionDelegate auto_reauthn_permission_delegate;
EXPECT_CALL(auto_reauthn_permission_delegate, IsAutoReauthnSettingEnabled())
.WillRepeatedly(Return(false));
MockIdentityRegistry identity_registry(web_contents(), nullptr,
idp_origin.GetURL());
mojo::Remote<blink::mojom::FederatedAuthRequest> remote;
RequestService& request_service = RequestService::CreateForTesting(
*subframe, &api_permission_delegate, &auto_reauthn_permission_delegate,
permission_delegate_.get(), &identity_registry,
remote.BindNewPipeAndPassReceiver());
TestIdentityCredentialSourceImpl::InitializeRequestService(
&request_service,
std::make_unique<NiceMock<MockIdpNetworkRequestManager>>());
request_service.SetDialogControllerForTests(
std::make_unique<NiceMock<MockIdentityRequestDialogController>>());
RequestPageData::GetOrCreateForPage(main_rfh()->GetPage())
->SetPendingWebIdentityRequest(&request_service);
blink::mojom::IdentityProviderRequestOptionsPtr options =
blink::mojom::IdentityProviderRequestOptions::New();
options->config = blink::mojom::IdentityProviderConfig::New();
options->config->config_url = config_url;
auto idp_info = std::make_unique<IdentityProviderInfo>(
options, IdpNetworkRequestManager::Endpoints(),
IdentityProviderMetadata(), blink::mojom::RpContext::kSignIn,
blink::mojom::RpMode::kPassive, std::nullopt);
idp_info->client_is_third_party_to_top_frame_origin = false;
IdentityProviderMetadata idp_metadata;
idp_metadata.config_url = config_url;
idp_info->data = base::MakeRefCounted<IdentityProviderData>(
"idp", idp_metadata, ClientMetadata(GURL(), GURL(), GURL(), gfx::Image()),
blink::mojom::RpContext::kSignIn, std::nullopt,
std::vector<IdentityRequestDialogDisclosureField>(),
/*has_login_status_mismatch=*/false);
IdentityRequestAccountPtr account =
base::MakeRefCounted<IdentityRequestAccount>(
kAccountId, "[email protected]", "Test User", "[email protected]",
"Test User", "Test", GURL(), "", "", std::vector<std::string>(),
std::vector<std::string>(), std::vector<std::string>(),
std::vector<std::string>(),
content::IdentityRequestAccount::LoginState::kSignIn);
account->identity_provider = idp_info->data;
IdpNetworkRequestManager::AccountsResponse accounts_response;
accounts_response.accounts.push_back(account);
TestIdentityCredentialSourceImpl::SetAccounts(
&request_service, std::move(accounts_response.accounts));
TestIdentityCredentialSourceImpl::SetIdpInfo(&request_service, config_url,
std::move(idp_info));
TestIdentityCredentialSourceImpl::SetIdentitySelectionType(
&request_service, RequestService::kAutoPassive);
// Should succeed because it is cross site but same party.
EXPECT_TRUE(source_->SelectAccount(idp_origin, kAccountId));
RequestPageData::GetOrCreateForPage(main_rfh()->GetPage())
->SetPendingWebIdentityRequest(nullptr);
}
// Tests that GetIdentityCredentialSuggestions() filters out accounts from an
// existing pending request if the iframe is third-party to the top-frame
// origin.
TEST_F(IdentityCredentialSourceImplTest,
GetIdentityCredentialSuggestionsFilterCrossSiteThirdParty) {
GURL config_url(kConfigUrl);
RenderFrameHost* subframe =
RenderFrameHostTester::For(main_rfh())->AppendChild("subframe");
subframe = NavigationSimulator::NavigateAndCommitFromDocument(
GURL("https://other.com"), subframe);
IdentityCredentialSourceImpl* subframe_source =
IdentityCredentialSourceImpl::GetOrCreateForCurrentDocument(subframe);
auto subframe_network_manager =
std::make_unique<NiceMock<MockIdpNetworkRequestManager>>();
MockIdpNetworkRequestManager* subframe_network_manager_ptr =
subframe_network_manager.get();
subframe_source->SetNetworkManagerForTests(
std::move(subframe_network_manager));
MockApiPermissionDelegate api_permission_delegate;
EXPECT_CALL(api_permission_delegate, GetApiPermissionStatus)
.WillRepeatedly(Return(FederatedIdentityApiPermissionContextDelegate::
PermissionStatus::GRANTED));
MockAutoReauthnPermissionDelegate auto_reauthn_permission_delegate;
EXPECT_CALL(auto_reauthn_permission_delegate, IsAutoReauthnSettingEnabled)
.WillRepeatedly(Return(false));
MockIdentityRegistry identity_registry(web_contents(), nullptr, config_url);
mojo::Remote<blink::mojom::FederatedAuthRequest> remote;
RequestService& request_service = RequestService::CreateForTesting(
*subframe, &api_permission_delegate, &auto_reauthn_permission_delegate,
permission_delegate_.get(), &identity_registry,
remote.BindNewPipeAndPassReceiver());
TestIdentityCredentialSourceImpl::InitializeRequestService(
&request_service,
std::make_unique<NiceMock<MockIdpNetworkRequestManager>>());
request_service.SetDialogControllerForTests(
std::make_unique<NiceMock<MockIdentityRequestDialogController>>());
RequestPageData::GetOrCreateForPage(subframe->GetPage())
->SetPendingWebIdentityRequest(&request_service);
blink::mojom::IdentityProviderRequestOptionsPtr options =
blink::mojom::IdentityProviderRequestOptions::New();
options->config = blink::mojom::IdentityProviderConfig::New();
options->config->config_url = config_url;
auto idp_info = std::make_unique<IdentityProviderInfo>(
options, IdpNetworkRequestManager::Endpoints(),
IdentityProviderMetadata(), blink::mojom::RpContext::kSignIn,
blink::mojom::RpMode::kPassive, std::nullopt);
idp_info->client_is_third_party_to_top_frame_origin = true;
IdentityProviderMetadata idp_metadata;
idp_metadata.config_url = config_url;
idp_info->data = base::MakeRefCounted<IdentityProviderData>(
"idp", idp_metadata, ClientMetadata(GURL(), GURL(), GURL(), gfx::Image()),
blink::mojom::RpContext::kSignIn, std::nullopt,
std::vector<IdentityRequestDialogDisclosureField>(),
/*has_login_status_mismatch=*/false);
IdentityRequestAccountPtr account =
base::MakeRefCounted<IdentityRequestAccount>(
kAccountId, "[email protected]", "Test User", "[email protected]",
"Test User", "Test", GURL(), "", "", std::vector<std::string>(),
std::vector<std::string>(), std::vector<std::string>(),
std::vector<std::string>(),
content::IdentityRequestAccount::LoginState::kSignIn);
account->identity_provider = idp_info->data;
IdpNetworkRequestManager::AccountsResponse accounts_response;
accounts_response.site_salt = "fc432178f9155c4e24762de5b9505f2e";
accounts_response.accounts.push_back(account);
IdpNetworkRequestManager::AccountsResponse accounts_response_copy;
accounts_response_copy.site_salt = accounts_response.site_salt;
accounts_response_copy.accounts.push_back(account);
TestIdentityCredentialSourceImpl::SetAccounts(
&request_service, std::move(accounts_response.accounts));
TestIdentityCredentialSourceImpl::SetIdpInfo(&request_service, config_url,
std::move(idp_info));
// If the accounts are filtered out from the pending request, it will
// proceed to fetch. We mock the fetch here.
EXPECT_CALL(*permission_delegate_,
GetIdpSigninStatus(url::Origin::Create(config_url)))
.WillRepeatedly(Return(true));
IdpNetworkRequestManager::WellKnown well_known;
well_known.provider_urls = std::set<GURL>{config_url};
EXPECT_CALL(*subframe_network_manager_ptr, FetchWellKnown(config_url, _))
.WillOnce(base::test::RunOnceCallback<1>(
FetchStatus{ParseStatus::kSuccess, 200}, well_known));
IdpNetworkRequestManager::Endpoints endpoints;
endpoints.token = GURL(kTokenUrl);
endpoints.accounts = GURL(kAccountsUrl);
endpoints.client_metadata = GURL("https://idp.example/client_metadata");
IdentityProviderMetadata idp_metadata_fetch;
idp_metadata_fetch.idp_login_url = GURL("https://idp.example/login");
EXPECT_CALL(*subframe_network_manager_ptr, FetchConfig(config_url, _, _, _))
.WillOnce(base::test::RunOnceCallback<3>(
FetchStatus{ParseStatus::kSuccess, 200}, endpoints,
idp_metadata_fetch));
// Mock SendAccountsRequest returning an account that will be filtered out
// in OnAccountsFetchCompleted.
EXPECT_CALL(*subframe_network_manager_ptr,
SendAccountsRequest(_, GURL(kAccountsUrl), _, _))
.WillOnce(
[&](const url::Origin&, const GURL&, const std::string&,
IdpNetworkRequestManager::AccountsRequestCallback callback) {
base::SequencedTaskRunner::GetCurrentDefault()->PostTask(
FROM_HERE,
base::BindOnce(std::move(callback),
FetchStatus{ParseStatus::kSuccess, 200},
std::move(accounts_response_copy)));
return true;
});
// Mock FetchClientMetadata
IdpNetworkRequestManager::ClientMetadata client_metadata;
client_metadata.client_is_third_party_to_top_frame_origin = true;
EXPECT_CALL(*subframe_network_manager_ptr, FetchClientMetadata)
.WillOnce(base::test::RunOnceCallback<4>(
FetchStatus{ParseStatus::kSuccess, 200}, client_metadata));
base::RunLoop run_loop;
subframe_source->GetIdentityCredentialSuggestions(
{config_url},
base::BindLambdaForTesting(
[&](const std::optional<std::vector<IdentityRequestAccountPtr>>&
accounts) {
ASSERT_TRUE(accounts.has_value());
// Should be empty because it was filtered out.
EXPECT_TRUE(accounts->empty());
run_loop.Quit();
}));
run_loop.Run();
RequestPageData::GetOrCreateForPage(subframe->GetPage())
->SetPendingWebIdentityRequest(nullptr);
}
} // namespace content::webid