| // 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_ |