blob: 3050a06ede78959178e9e6540eee608142c0a737 [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_IDP_NETWORK_REQUEST_MANAGER_H_
#define CONTENT_BROWSER_WEBID_IDP_NETWORK_REQUEST_MANAGER_H_
#include <memory>
#include <string>
#include <vector>
#include "base/functional/callback.h"
#include "content/common/content_export.h"
#include "content/public/browser/identity_request_account.h"
#include "content/public/browser/identity_request_dialog_controller.h"
#include "content/public/browser/web_contents.h"
#include "services/data_decoder/public/cpp/data_decoder.h"
#include "services/network/public/cpp/shared_url_loader_factory.h"
#include "services/network/public/mojom/client_security_state.mojom-forward.h"
#include "third_party/abseil-cpp/absl/types/optional.h"
#include "url/gurl.h"
#include "url/origin.h"
namespace net {
enum class ReferrerPolicy;
}
namespace network {
class SimpleURLLoader;
}
namespace content {
class RenderFrameHostImpl;
// Manages network requests and maintains relevant state for interaction with
// the Identity Provider across a FedCM transaction. Owned by
// FederatedAuthRequestImpl and has a lifetime limited to a single identity
// transaction between an RP and an IDP.
//
// Diagram of the permission-based data flows between the browser and the IDP:
// .-------. .---.
// |Browser| |IDP|
// '-------' '---'
// | |
// | GET /fedcm.json |
// |-------------------------------->|
// | |
// | JSON{idp_url} |
// |<--------------------------------|
// | |
// | POST /idp_url with OIDC request |
// |-------------------------------->|
// | |
// | token or signin_url |
// |<--------------------------------|
// .-------. .---.
// |Browser| |IDP|
// '-------' '---'
//
// If the IDP returns an token, the sequence finishes. If it returns a
// signin_url, that URL is loaded as a rendered Document into a new window for
// the user to interact with the IDP.
class CONTENT_EXPORT IdpNetworkRequestManager {
public:
enum class ParseStatus {
kSuccess,
kHttpNotFoundError,
kNoResponseError,
kInvalidResponseError,
// ParseStatus::kEmptyListError only applies to well known and account list
// responses. It is used to classify a successful response where the list in
// the response is empty.
kEmptyListError,
};
struct FetchStatus {
ParseStatus parse_status;
// The HTTP response code, if one was received, otherwise the net error. It
// is possible to distinguish which it is since HTTP response codes are
// positive and net errors are negative.
int response_code;
};
enum class LogoutResponse {
kSuccess,
kError,
};
struct CONTENT_EXPORT Endpoints {
Endpoints();
~Endpoints();
Endpoints(const Endpoints&);
GURL token;
GURL accounts;
GURL client_metadata;
GURL metrics;
};
struct ClientMetadata {
GURL privacy_policy_url;
GURL terms_of_service_url;
};
// Error codes sent to the metrics endpoint.
// Enum is part of public FedCM API. Do not renumber error codes.
// The error codes are not consecutive to make adding error codes easier in
// the future.
enum class MetricsEndpointErrorCode {
kNone = 0, // Success
kOther = 1,
// Errors triggered by how RP calls FedCM API.
kRpFailure = 100,
// User Failures.
kUserFailure = 200,
// Generic IDP Failures.
kIdpServerInvalidResponse = 300,
kIdpServerUnavailable = 301,
kManifestError = 302,
// Specific IDP Failures.
kAccountsEndpointInvalidResponse = 401,
kTokenEndpointInvalidResponse = 402,
};
using AccountList = std::vector<IdentityRequestAccount>;
using AccountsRequestCallback =
base::OnceCallback<void(FetchStatus, AccountList)>;
using DownloadCallback =
base::OnceCallback<void(std::unique_ptr<std::string> response_body,
int response_code)>;
using FetchWellKnownCallback =
base::OnceCallback<void(FetchStatus, const std::set<GURL>&)>;
using FetchConfigCallback = base::OnceCallback<
void(FetchStatus, Endpoints, IdentityProviderMetadata)>;
using FetchClientMetadataCallback =
base::OnceCallback<void(FetchStatus, ClientMetadata)>;
using LogoutCallback = base::OnceCallback<void()>;
using ParseJsonCallback =
base::OnceCallback<void(FetchStatus,
data_decoder::DataDecoder::ValueOrError)>;
using TokenRequestCallback =
base::OnceCallback<void(FetchStatus, const std::string&)>;
static std::unique_ptr<IdpNetworkRequestManager> Create(
RenderFrameHostImpl* host);
IdpNetworkRequestManager(
const url::Origin& relying_party,
scoped_refptr<network::SharedURLLoaderFactory> loader_factory,
network::mojom::ClientSecurityStatePtr client_security_state);
virtual ~IdpNetworkRequestManager();
IdpNetworkRequestManager(const IdpNetworkRequestManager&) = delete;
IdpNetworkRequestManager& operator=(const IdpNetworkRequestManager&) = delete;
// Computes the well-known URL from the identity provider URL.
static absl::optional<GURL> ComputeWellKnownUrl(const GURL& url);
// Fetch the well-known file. This is the /.well-known/web-identity file on
// the eTLD+1 calculated from the provider URL, used to check that the
// provider URL is valid for this eTLD+1.
virtual void FetchWellKnown(const GURL& provider, FetchWellKnownCallback);
// Attempt to fetch the IDP's FedCM parameters from the config file.
virtual void FetchConfig(const GURL& provider,
int idp_brand_icon_ideal_size,
int idp_brand_icon_minimum_size,
FetchConfigCallback);
virtual void FetchClientMetadata(const GURL& endpoint,
const std::string& client_id,
FetchClientMetadataCallback);
// Fetch accounts list for this user from the IDP.
virtual void SendAccountsRequest(const GURL& accounts_url,
const std::string& client_id,
AccountsRequestCallback callback);
// Request a new token for this user account and RP from the IDP.
virtual void SendTokenRequest(const GURL& token_url,
const std::string& account,
const std::string& url_encoded_post_data,
TokenRequestCallback callback);
// Sends metrics to metrics endpoint after a token was successfully generated.
virtual void SendSuccessfulTokenRequestMetrics(
const GURL& metrics_endpoint_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);
// Sends error code to metrics endpoint when token generation fails.
virtual void SendFailedTokenRequestMetrics(
const GURL& metrics_endpoint_url,
MetricsEndpointErrorCode error_code);
// Send logout request to a single target.
virtual void SendLogout(const GURL& logout_url, LogoutCallback);
private:
// Starts download request using `url_loader`. Calls `parse_json_callback`
// when the download result has been parsed.
void DownloadJsonAndParse(
std::unique_ptr<network::ResourceRequest> resource_request,
absl::optional<std::string> url_encoded_post_data,
ParseJsonCallback parse_json_callback,
size_t max_download_size);
// Starts download result using `url_loader`. Calls `download_callback` when
// the download completes.
void DownloadUrl(std::unique_ptr<network::ResourceRequest> resource_request,
absl::optional<std::string> url_encoded_post_data,
DownloadCallback download_callback,
size_t max_download_size);
// Called when download initiated by DownloadUrl() completes.
void OnDownloadedUrl(std::unique_ptr<network::SimpleURLLoader> url_loader,
DownloadCallback callback,
std::unique_ptr<std::string> response_body);
std::unique_ptr<network::ResourceRequest> CreateUncredentialedResourceRequest(
const GURL& target_url,
bool send_origin,
bool follow_redirects = false) const;
std::unique_ptr<network::ResourceRequest> CreateCredentialedResourceRequest(
const GURL& target_url,
bool send_origin) const;
url::Origin relying_party_origin_;
scoped_refptr<network::SharedURLLoaderFactory> loader_factory_;
network::mojom::ClientSecurityStatePtr client_security_state_;
base::WeakPtrFactory<IdpNetworkRequestManager> weak_ptr_factory_{this};
};
} // namespace content
#endif // CONTENT_BROWSER_WEBID_IDP_NETWORK_REQUEST_MANAGER_H_