blob: 3b231d5a92610179d0952822c93d23b2432b76de [file] [log] [blame]
// Copyright 2020 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_FEDERATED_AUTH_REQUEST_IMPL_H_
#define CONTENT_BROWSER_WEBID_FEDERATED_AUTH_REQUEST_IMPL_H_
#include <memory>
#include <string>
#include <vector>
#include "base/callback_forward.h"
#include "base/containers/queue.h"
#include "base/memory/raw_ptr.h"
#include "base/time/time.h"
#include "content/browser/webid/fedcm_metrics.h"
#include "content/browser/webid/federated_provider_fetcher.h"
#include "content/browser/webid/idp_network_request_manager.h"
#include "content/common/content_export.h"
#include "content/public/browser/document_service.h"
#include "content/public/browser/identity_request_dialog_controller.h"
#include "content/public/browser/web_contents.h"
#include "third_party/blink/public/mojom/devtools/inspector_issue.mojom.h"
#include "third_party/blink/public/mojom/webid/federated_auth_request.mojom.h"
#include "url/gurl.h"
namespace content {
class FederatedIdentityApiPermissionContextDelegate;
class FederatedIdentityPermissionContextDelegate;
class RenderFrameHost;
// FederatedAuthRequestImpl handles mojo connections from the renderer to
// fulfill WebID-related requests.
//
// In practice, it is owned and managed by a RenderFrameHost. It accomplishes
// that via subclassing DocumentService, which observes the lifecycle of a
// RenderFrameHost and manages its own memory.
// Create() creates a self-managed instance of FederatedAuthRequestImpl and
// binds it to the receiver.
class CONTENT_EXPORT FederatedAuthRequestImpl
: public DocumentService<blink::mojom::FederatedAuthRequest> {
public:
static void Create(RenderFrameHost*,
mojo::PendingReceiver<blink::mojom::FederatedAuthRequest>);
static FederatedAuthRequestImpl& CreateForTesting(
RenderFrameHost&,
FederatedIdentityApiPermissionContextDelegate*,
FederatedIdentityPermissionContextDelegate*,
mojo::PendingReceiver<blink::mojom::FederatedAuthRequest>);
FederatedAuthRequestImpl(const FederatedAuthRequestImpl&) = delete;
FederatedAuthRequestImpl& operator=(const FederatedAuthRequestImpl&) = delete;
~FederatedAuthRequestImpl() override;
// blink::mojom::FederatedAuthRequest:
void RequestToken(std::vector<blink::mojom::IdentityProviderGetParametersPtr>
idp_get_params_ptrs,
RequestTokenCallback) override;
void CancelTokenRequest() override;
void LogoutRps(std::vector<blink::mojom::LogoutRpsRequestPtr> logout_requests,
LogoutRpsCallback) override;
void SetIdpSigninStatus(const url::Origin& origin,
blink::mojom::IdpSigninStatus status) override;
void SetTokenRequestDelayForTests(base::TimeDelta delay);
void SetNetworkManagerForTests(
std::unique_ptr<IdpNetworkRequestManager> manager);
void SetDialogControllerForTests(
std::unique_ptr<IdentityRequestDialogController> controller);
// Rejects the pending request if it has not been resolved naturally yet.
void OnRejectRequest();
struct IdentityProviderGetInfo {
IdentityProviderGetInfo(blink::mojom::IdentityProviderConfig,
bool prefer_auto_signin);
~IdentityProviderGetInfo();
IdentityProviderGetInfo(const IdentityProviderGetInfo&);
blink::mojom::IdentityProviderConfig provider;
bool prefer_auto_signin{false};
};
struct IdentityProviderInfo {
IdentityProviderInfo(blink::mojom::IdentityProviderConfig,
IdpNetworkRequestManager::Endpoints,
IdentityProviderMetadata,
bool prefer_auto_signin);
~IdentityProviderInfo();
IdentityProviderInfo(const IdentityProviderInfo&);
blink::mojom::IdentityProviderConfig provider;
IdpNetworkRequestManager::Endpoints endpoints;
IdentityProviderMetadata metadata;
bool prefer_auto_signin{false};
bool has_failing_idp_signin_status{false};
absl::optional<IdentityProviderData> data;
};
private:
friend class FederatedAuthRequestImplTest;
FederatedAuthRequestImpl(
RenderFrameHost&,
FederatedIdentityApiPermissionContextDelegate*,
FederatedIdentityPermissionContextDelegate*,
mojo::PendingReceiver<blink::mojom::FederatedAuthRequest>);
bool HasPendingRequest() const;
void OnAllConfigAndWellKnownFetched(
base::flat_map<GURL, IdentityProviderGetInfo> get_infos,
std::vector<FederatedProviderFetcher::FetchResult> fetch_results);
void OnClientMetadataResponseReceived(
std::unique_ptr<IdentityProviderInfo> idp_info,
const IdpNetworkRequestManager::AccountList& accounts,
IdpNetworkRequestManager::FetchStatus status,
IdpNetworkRequestManager::ClientMetadata client_metadata);
// Called when all of the data needed to display the FedCM prompt has been
// fetched for `idp_info`.
void OnFetchDataForIdpSucceeded(
std::unique_ptr<IdentityProviderInfo> idp_info,
const IdpNetworkRequestManager::AccountList& accounts,
const IdpNetworkRequestManager::ClientMetadata& client_metadata);
// Called when there is an error in fetching information to show the prompt
// for a given IDP - `idp_info`.
void OnFetchDataForIdpFailed(
std::unique_ptr<IdentityProviderInfo> idp_info,
blink::mojom::FederatedAuthRequestResult result,
absl::optional<content::FedCmRequestIdTokenStatus> token_status,
bool should_delay_callback);
void MaybeShowAccountsDialog();
// Updates the IdpSigninStatus in case of accounts fetch failure and shows a
// failure UI if applicable.
void HandleAccountsFetchFailure(
std::unique_ptr<IdentityProviderInfo> idp_info,
blink::mojom::FederatedAuthRequestResult result,
absl::optional<content::FedCmRequestIdTokenStatus> token_status);
void OnAccountsResponseReceived(
std::unique_ptr<IdentityProviderInfo> idp_info,
IdpNetworkRequestManager::FetchStatus status,
IdpNetworkRequestManager::AccountList accounts);
void OnAccountSelected(const GURL& idp_config_url,
const std::string& account_id,
bool is_sign_in);
void OnDismissFailureDialog(
blink::mojom::FederatedAuthRequestResult result,
absl::optional<content::FedCmRequestIdTokenStatus> token_status,
bool should_delay_callback,
IdentityRequestDialogController::DismissReason dismiss_reason);
void OnDialogDismissed(
IdentityRequestDialogController::DismissReason dismiss_reason);
void CompleteTokenRequest(const blink::mojom::IdentityProviderConfig& idp,
IdpNetworkRequestManager::FetchStatus status,
const std::string& token);
void OnTokenResponseReceived(const blink::mojom::IdentityProviderConfig& idp,
IdpNetworkRequestManager::FetchStatus status,
const std::string& token);
void DispatchOneLogout();
void OnLogoutCompleted();
void CompleteRequestWithError(
blink::mojom::FederatedAuthRequestResult result,
absl::optional<content::FedCmRequestIdTokenStatus> token_status,
bool should_delay_callback);
void CompleteRequest(
blink::mojom::FederatedAuthRequestResult result,
absl::optional<content::FedCmRequestIdTokenStatus> token_status,
const absl::optional<GURL>& selected_idp_config_url,
const std::string& token,
bool should_delay_callback);
void CompleteLogoutRequest(blink::mojom::LogoutRpsStatus);
// 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 SendFailedTokenRequestMetrics(
const GURL& metrics_endpoint,
blink::mojom::FederatedAuthRequestResult result);
void CleanUp();
std::unique_ptr<IdpNetworkRequestManager> CreateNetworkManager();
std::unique_ptr<IdentityRequestDialogController> CreateDialogController();
// Creates an inspector issue related to a federated authentication request to
// the Issues panel in DevTools.
void AddInspectorIssue(blink::mojom::FederatedAuthRequestResult result);
// Adds a console error message related to a federated authentication request
// issue. The Issues panel is preferred, but for now we also surface console
// error messages since it is much simpler to add.
// TODO(crbug.com/1294415): When the FedCM API is more stable, we should
// ensure that the Issues panel contains all of the needed debugging
// information and then we can remove the console error messages.
void AddConsoleErrorMessage(blink::mojom::FederatedAuthRequestResult result);
void MaybeAddResponseCodeToConsole(const char* fetch_description,
int response_code);
bool ShouldCompleteRequestImmediately();
// 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. In either case, this method also
// reorders accounts so that those that are considered returning users are
// before users that are not returning.
void ComputeLoginStateAndReorderAccounts(
const blink::mojom::IdentityProviderConfig& idp,
IdpNetworkRequestManager::AccountList& accounts);
url::Origin GetEmbeddingOrigin() const;
std::unique_ptr<IdpNetworkRequestManager> network_manager_;
std::unique_ptr<IdentityRequestDialogController> request_dialog_controller_;
// Replacements for testing.
std::unique_ptr<IdpNetworkRequestManager> mock_network_manager_;
std::unique_ptr<IdentityRequestDialogController> mock_dialog_controller_;
// Helper that records FedCM UMA and UKM metrics. Initialized in the
// RequestToken() method, so all metrics must be recorded after that.
std::unique_ptr<FedCmMetrics> fedcm_metrics_;
// Populated in OnAllConfigAndWellKnownFetched().
base::flat_map<GURL, GURL> metrics_endpoints_;
// Populated by MaybeShowAccountsDialog().
base::flat_map<GURL, std::unique_ptr<IdentityProviderInfo>> idp_infos_;
raw_ptr<FederatedIdentityApiPermissionContextDelegate>
api_permission_delegate_ = nullptr;
raw_ptr<FederatedIdentityPermissionContextDelegate> permission_delegate_ =
nullptr;
// The account that was selected by the user. This is only applicable to the
// mediation flow.
std::string account_id_;
base::TimeTicks start_time_;
base::TimeTicks show_accounts_dialog_time_;
base::TimeTicks select_account_time_;
base::TimeTicks token_response_time_;
base::TimeDelta token_request_delay_;
bool errors_logged_to_console_{false};
RequestTokenCallback auth_request_callback_;
std::unique_ptr<FederatedProviderFetcher> provider_fetcher_;
base::queue<blink::mojom::LogoutRpsRequestPtr> logout_requests_;
LogoutRpsCallback logout_callback_;
// TODO(crbug.com/1361649): Refactor these member variables introduced through
// the multi IDP prototype implementation to make them less confusing.
// Set of config URLs of IDPs that have yet to be processed.
std::set<GURL> pending_idps_;
// List of config URLs of IDPs in the same order as the providers specified in
// the navigator.credentials.get call.
std::vector<GURL> idp_order_;
base::WeakPtrFactory<FederatedAuthRequestImpl> weak_ptr_factory_{this};
};
} // namespace content
#endif // CONTENT_BROWSER_WEBID_FEDERATED_AUTH_REQUEST_IMPL_H_