blob: fab62f8adab2ffe4e7a3bfa7e4b011b6e7e6f425 [file]
// Copyright 2025 The Chromium Authors
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
#ifndef CONTENT_BROWSER_WEBID_ACCOUNTS_FETCHER_H_
#define CONTENT_BROWSER_WEBID_ACCOUNTS_FETCHER_H_
#include <memory>
#include <set>
#include "base/containers/flat_map.h"
#include "base/memory/raw_ptr.h"
#include "base/memory/weak_ptr.h"
#include "content/browser/webid/config_fetcher.h"
#include "content/browser/webid/identity_provider_info.h"
#include "content/browser/webid/idp_network_request_manager.h"
#include "content/common/content_export.h"
#include "content/public/browser/webid/native_idp_fetcher.h"
#include "url/gurl.h"
namespace content {
class FederatedIdentityPermissionContextDelegate;
class FederatedIdentityApiPermissionContextDelegate;
class RenderFrameHost;
namespace webid {
class Metrics;
// A class that fetches accounts from a set of IDPs.
class CONTENT_EXPORT AccountsFetcher {
public:
using IdentityRequestAccountPtr = scoped_refptr<IdentityRequestAccount>;
static constexpr char kWildcardDomainHint[] = "any";
struct CONTENT_EXPORT IdentityProviderGetInfo {
IdentityProviderGetInfo(blink::mojom::IdentityProviderRequestOptionsPtr,
blink::mojom::RpContext rp_context,
blink::mojom::RpMode rp_mode,
std::optional<blink::mojom::Format> format);
~IdentityProviderGetInfo();
IdentityProviderGetInfo(const IdentityProviderGetInfo&);
IdentityProviderGetInfo& operator=(const IdentityProviderGetInfo& other);
blink::mojom::IdentityProviderRequestOptionsPtr provider;
blink::mojom::RpContext rp_context{blink::mojom::RpContext::kSignIn};
blink::mojom::RpMode rp_mode{blink::mojom::RpMode::kPassive};
std::optional<blink::mojom::Format> format;
};
struct CONTENT_EXPORT FedCmFetchingParams {
FedCmFetchingParams(blink::mojom::RpMode rp_mode,
int icon_ideal_size,
int icon_minimum_size,
::password_manager::CredentialMediationRequirement
mediation_requirement);
~FedCmFetchingParams();
blink::mojom::RpMode rp_mode;
int icon_ideal_size;
int icon_minimum_size;
::password_manager::CredentialMediationRequirement mediation_requirement;
};
struct CONTENT_EXPORT Result {
Result();
~Result();
Result(Result&&);
Result& operator=(Result&&);
GURL idp_config_url;
std::unique_ptr<IdentityProviderInfo> idp_info;
std::optional<IdpNetworkRequestManager::AccountsResponse> accounts;
std::vector<IdentityRequestAccountPtr> filtered_accounts;
std::optional<blink::mojom::FederatedRequestResult> error;
std::optional<RequestIdTokenStatus> token_status;
// Whether the callback should be delayed for this result.
// TODO(crbug.com/475277488): Remove this as callback delay should not be
// per-result. Also consider removing `show_active_mode_modal_dialog` as
// well.
bool should_delay_callback = false;
bool is_mismatch = false;
bool show_active_mode_modal_dialog = false;
bool use_native_app_ui = false;
base::TimeTicks accounts_fetched_time;
base::TimeTicks client_metadata_fetched_time;
};
using AccountsFetcherCallback =
base::OnceCallback<void(base::TimeTicks, std::vector<Result>)>;
using FilterAccountsCallback = base::RepeatingCallback<void(
const GURL&,
const GURL&,
std::vector<scoped_refptr<IdentityRequestAccount>>&)>;
AccountsFetcher(
RenderFrameHost& render_frame_host,
IdpNetworkRequestManager* network_manager,
FederatedIdentityApiPermissionContextDelegate* api_permission_delegate,
FederatedIdentityPermissionContextDelegate* permission_delegate,
FedCmFetchingParams fetching_params,
AccountsFetcherCallback callback);
~AccountsFetcher();
// Note that a single AccountsFetcher instance should invoke either
// FetchEndpointsForIdps() or FetchAccountsForIdps() only once in its
// lifetime.
// Fetch well-known, config, accounts and client metadata endpoints for
// passed-in IdPs. Uses parameters from `token_request_get_infos`.
void FetchEndpointsForIdps(
const std::vector<ConfigFetcher::FetchRequest>& idps,
const base::flat_map<GURL, IdentityProviderGetInfo>&
token_request_get_infos,
Metrics* fedcm_metrics,
const url::Origin& embedding_origin,
FilterAccountsCallback filter_accounts_callback);
// Fetches accounts for IdPs whose config and well-known files are already
// fetched (e.g. from cache or after ConfigFetcher completion).
void FetchAccountsForIdps(
const std::vector<std::unique_ptr<IdentityProviderInfo>>& idp_infos,
const base::flat_map<GURL, IdentityProviderGetInfo>&
token_request_get_infos,
Metrics* fedcm_metrics,
const url::Origin& embedding_origin,
FilterAccountsCallback filter_accounts_callback);
// Notifies metrics endpoint that either the user did not select the IDP in
// the prompt or that there was an error in fetching data for the IDP.
void SendAllFailedTokenRequestMetrics(
blink::mojom::FederatedRequestResult result,
bool did_show_ui);
void SendSuccessfulTokenRequestMetrics(
const GURL& idp_config_url,
base::TimeDelta api_call_to_show_dialog_time,
base::TimeDelta show_dialog_to_continue_clicked_time,
base::TimeDelta account_selected_to_token_response_time,
base::TimeDelta api_call_to_token_response_time,
bool did_show_ui);
private:
void OnAllConfigAndWellKnownFetched(
std::vector<ConfigFetcher::FetchResult> fetch_results);
void OnAccountsResponseReceived(
std::unique_ptr<IdentityProviderInfo> idp_info,
FetchStatus status,
IdpNetworkRequestManager::AccountsResponse accounts);
void OnNativeAccountsFetched(std::unique_ptr<IdentityProviderInfo> idp_info,
std::optional<bool> old_idp_signin_status,
FetchStatus status,
base::TimeTicks accounts_fetched_time,
NativeIdpFetcher::FetchResult result);
void OnAccountsFetchSucceeded(
std::unique_ptr<IdentityProviderInfo> idp_info,
FetchStatus status,
IdpNetworkRequestManager::AccountsResponse accounts,
std::vector<IdentityRequestAccountPtr> filtered_accounts,
base::TimeTicks accounts_fetched_time);
void OnClientMetadataResponseReceived(
std::unique_ptr<IdentityProviderInfo> idp_info,
IdpNetworkRequestManager::AccountsResponse&& accounts,
std::vector<IdentityRequestAccountPtr> filtered_accounts,
base::TimeTicks accounts_fetched_time,
FetchStatus status,
IdpNetworkRequestManager::ClientMetadata client_metadata);
void OnFetchDataForIdpSucceeded(
const IdpNetworkRequestManager::ClientMetadata& client_metadata,
std::vector<IdentityRequestAccountPtr> filtered_accounts,
base::TimeTicks accounts_fetched_time,
base::TimeTicks client_metadata_fetched_time,
IdpNetworkRequestManager::AccountsResponse accounts,
std::unique_ptr<IdentityProviderInfo> idp_info,
const gfx::Image& rp_brand_icon);
void MarkAccountsWithLabel(const std::string& label,
std::vector<IdentityRequestAccountPtr>& accounts);
void MarkAccountsWithLoginHint(
const std::string& login_hint,
std::vector<IdentityRequestAccountPtr>& accounts);
void MarkAccountsWithDomainHint(
const std::string& domain_hint,
std::vector<IdentityRequestAccountPtr>& accounts);
// Computes the login state of accounts. It uses the IDP-provided signal, if
// it had been populated. Otherwise, it uses the browser knowledge on which
// accounts are returning and which are not.
void ComputeLoginStates(const GURL& idp_config_url,
const std::string& client_id,
std::vector<IdentityRequestAccountPtr>& accounts);
// Updates the IdpSigninStatus in case of accounts fetch failure and shows a
// failure UI if applicable.
void HandleAccountsFetchFailure(
std::unique_ptr<IdentityProviderInfo> idp_info,
std::optional<bool> old_idp_signin_status,
blink::mojom::FederatedRequestResult result,
std::optional<RequestIdTokenStatus> token_status,
const FetchStatus& status,
std::vector<IdentityRequestAccountPtr> filtered_accounts,
base::TimeTicks accounts_fetched_time);
void OnIdpMismatch(base::TimeTicks accounts_fetched_time,
std::unique_ptr<IdentityProviderInfo> idp_info);
void SendFailedTokenRequestMetrics(
const GURL& metrics_endpoint,
blink::mojom::FederatedRequestResult result,
bool did_show_ui);
// Adds a fetch result to the end of the results_ vector and decrements
// pending_requests_. If pending_requests_ reaches 0, runs the callback_.
void AddResult(Result&& result);
// Login dialog is only shown in Active Mode with 1 IDP.
bool ShouldImmediatelyShowLoginDialog() const;
base::flat_map<
GURL,
std::pair<blink::mojom::FederatedRequestResult, RequestIdTokenStatus>>
idp_config_url_to_result_;
std::unique_ptr<ConfigFetcher> config_fetcher_;
// Populated in OnAllConfigAndWellKnownFetched().
base::flat_map<GURL, GURL> metrics_endpoints_;
// Owned by RequestHandler.
raw_ref<RenderFrameHost> render_frame_host_;
raw_ptr<IdpNetworkRequestManager> network_manager_;
raw_ptr<FederatedIdentityApiPermissionContextDelegate>
api_permission_delegate_;
raw_ptr<FederatedIdentityPermissionContextDelegate> permission_delegate_;
FedCmFetchingParams params_;
AccountsFetcherCallback callback_;
FilterAccountsCallback filter_accounts_callback_;
base::flat_map<GURL, IdentityProviderGetInfo> request_get_infos_;
raw_ptr<Metrics> fedcm_metrics_;
url::Origin embedding_origin_;
int num_pending_requests_ = 0;
std::vector<Result> results_;
base::TimeTicks well_known_and_config_fetched_time_;
base::WeakPtrFactory<AccountsFetcher> weak_ptr_factory_{this};
};
} // namespace webid
} // namespace content
#endif // CONTENT_BROWSER_WEBID_ACCOUNTS_FETCHER_H_