blob: b691ce905cbb90452ece8ed2740067eabd7ef8f6 [file] [log] [blame]
// Copyright 2020 The Chromium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
#include "content/browser/webid/federated_auth_request_impl.h"
#include "base/callback.h"
#include "base/ranges/algorithm.h"
#include "base/strings/string_piece.h"
#include "content/browser/bad_message.h"
#include "content/browser/renderer_host/render_frame_host_impl.h"
#include "content/browser/webid/id_token_request_callback_data.h"
#include "content/browser/webid/webid_utils.h"
#include "content/public/browser/browser_context.h"
#include "content/public/browser/federated_identity_active_session_permission_context_delegate.h"
#include "content/public/browser/federated_identity_request_permission_context_delegate.h"
#include "content/public/browser/federated_identity_sharing_permission_context_delegate.h"
#include "content/public/browser/web_contents.h"
#include "content/public/common/content_client.h"
#include "ui/accessibility/ax_mode.h"
#include "url/url_constants.h"
using blink::mojom::LogoutStatus;
using blink::mojom::RequestIdTokenStatus;
using blink::mojom::RequestMode;
using blink::mojom::RevokeStatus;
using UserApproval = content::IdentityRequestDialogController::UserApproval;
using LoginState = content::IdentityRequestAccount::LoginState;
using SignInMode = content::IdentityRequestAccount::SignInMode;
namespace content {
namespace {
std::string FormatRequestParams(const std::string& client_id,
const std::string& nonce) {
std::string query;
// 'openid' scope is required for IdPs using OpenID Connect. We hope that IdPs
// using OAuth will ignore it, although some might return errors.
query += "scope=openid profile email";
if (client_id.length() > 0) {
query += "&client_id=" + client_id;
}
if (nonce.length() > 0) {
query += "&nonce=" + nonce;
}
return query;
}
} // namespace
FederatedAuthRequestImpl::FederatedAuthRequestImpl(RenderFrameHost* host,
const url::Origin& origin)
: render_frame_host_(host), origin_(origin) {}
FederatedAuthRequestImpl::~FederatedAuthRequestImpl() {
// Ensures key data members are destructed in proper order and resolves any
// pending promise.
CompleteRequest(RequestIdTokenStatus::kError, "");
}
void FederatedAuthRequestImpl::RequestIdToken(
const GURL& provider,
const std::string& client_id,
const std::string& nonce,
RequestMode mode,
bool prefer_auto_sign_in,
blink::mojom::FederatedAuthRequest::RequestIdTokenCallback callback) {
if (HasPendingRequest()) {
std::move(callback).Run(RequestIdTokenStatus::kErrorTooManyRequests, "");
return;
}
auth_request_callback_ = std::move(callback);
provider_ = provider;
client_id_ = client_id;
nonce_ = nonce;
mode_ = mode;
prefer_auto_sign_in_ = prefer_auto_sign_in;
network_manager_ = CreateNetworkManager(provider);
if (!network_manager_) {
CompleteRequest(RequestIdTokenStatus::kError, "");
return;
}
request_dialog_controller_ = CreateDialogController();
// Skip request permission if it is already given for this IDP or if we are
// using the mediated mode in which case the permission is combined with
// account selector UI.
if (mode_ == RequestMode::kMediated ||
(GetRequestPermissionContext() &&
GetRequestPermissionContext()->HasRequestPermission(
origin_, url::Origin::Create(provider_)))) {
network_manager_->FetchIdpWellKnown(
base::BindOnce(&FederatedAuthRequestImpl::OnWellKnownFetched,
weak_ptr_factory_.GetWeakPtr()));
return;
}
DCHECK_EQ(mode_, RequestMode::kPermission);
// Use the web contents of the page that initiated the WebID request (i.e.
// the Relying Party) for showing the initial permission dialog.
WebContents* web_contents =
WebContents::FromRenderFrameHost(render_frame_host_);
request_dialog_controller_->ShowInitialPermissionDialog(
web_contents, provider_,
IdentityRequestDialogController::PermissionDialogMode::kStateful,
base::BindOnce(&FederatedAuthRequestImpl::OnSigninApproved,
weak_ptr_factory_.GetWeakPtr()));
}
void FederatedAuthRequestImpl::Revoke(
const GURL& provider,
const std::string& client_id,
const std::string& account_id,
blink::mojom::FederatedAuthRequest::RevokeCallback callback) {
if (HasPendingRequest()) {
std::move(callback).Run(RevokeStatus::kError);
return;
}
provider_ = provider;
client_id_ = client_id;
account_id_ = account_id;
revoke_callback_ = std::move(callback);
network_manager_ = CreateNetworkManager(provider);
if (!network_manager_) {
CompleteRevokeRequest(RevokeStatus::kError);
return;
}
if (!GetRequestPermissionContext() ||
!GetRequestPermissionContext()->HasRequestPermission(
origin_, url::Origin::Create(provider_))) {
CompleteRevokeRequest(RevokeStatus::kError);
return;
}
network_manager_->FetchIdpWellKnown(
base::BindOnce(&FederatedAuthRequestImpl::OnWellKnownFetchedForRevoke,
weak_ptr_factory_.GetWeakPtr()));
}
// TODO(kenrb): Depending on how this code evolves, it might make sense to
// spin session management code into its own service. The prohibition on
// making authentication requests and logout requests at the same time, while
// not problematic for any plausible use case, need not be strictly necessary
// if there is a good way to not have to resource contention between requests.
// https://crbug.com/1200581
void FederatedAuthRequestImpl::Logout(
std::vector<blink::mojom::LogoutRequestPtr> logout_requests,
blink::mojom::FederatedAuthRequest::LogoutCallback callback) {
if (HasPendingRequest()) {
std::move(callback).Run(LogoutStatus::kErrorTooManyRequests);
return;
}
DCHECK(logout_requests_.empty());
logout_callback_ = std::move(callback);
if (logout_requests.empty()) {
CompleteLogoutRequest(LogoutStatus::kError);
return;
}
if (base::ranges::any_of(logout_requests, [](auto& request) {
return !request->endpoint.is_valid();
})) {
bad_message::ReceivedBadMessage(render_frame_host_->GetProcess(),
bad_message::FARI_LOGOUT_BAD_ENDPOINT);
CompleteLogoutRequest(LogoutStatus::kError);
return;
}
for (auto& request : logout_requests) {
logout_requests_.push(std::move(request));
}
network_manager_ = CreateNetworkManager(origin_.GetURL());
if (!network_manager_) {
CompleteLogoutRequest(LogoutStatus::kError);
return;
}
// TODO(kenrb): These should be parallelized rather than being dispatched
// serially. https://crbug.com/1200581.
DispatchOneLogout();
}
bool FederatedAuthRequestImpl::HasPendingRequest() const {
return auth_request_callback_ || logout_callback_ || revoke_callback_;
}
GURL FederatedAuthRequestImpl::ResolveWellKnownUrl(
const std::string& endpoint) {
if (endpoint.empty())
return GURL();
const url::Origin& idp_origin = url::Origin::Create(provider_);
GURL well_known_url =
idp_origin.GetURL().Resolve(IdpNetworkRequestManager::kWellKnownFilePath);
return well_known_url.Resolve(endpoint);
}
void FederatedAuthRequestImpl::OnWellKnownFetched(
IdpNetworkRequestManager::FetchStatus status,
IdpNetworkRequestManager::Endpoints endpoints) {
switch (status) {
case IdpNetworkRequestManager::FetchStatus::kWebIdNotSupported: {
CompleteRequest(RequestIdTokenStatus::kErrorFedCmNotSupportedByProvider,
"");
return;
}
case IdpNetworkRequestManager::FetchStatus::kFetchError: {
CompleteRequest(RequestIdTokenStatus::kErrorFetchingWellKnown, "");
return;
}
case IdpNetworkRequestManager::FetchStatus::kInvalidResponseError: {
CompleteRequest(RequestIdTokenStatus::kErrorInvalidWellKnown, "");
return;
}
case IdpNetworkRequestManager::FetchStatus::kSuccess: {
// Intentional fall-through.
}
}
endpoints_.idp = ResolveWellKnownUrl(endpoints.idp);
endpoints_.token = ResolveWellKnownUrl(endpoints.token);
endpoints_.accounts = ResolveWellKnownUrl(endpoints.accounts);
endpoints_.client_id_metadata =
ResolveWellKnownUrl(endpoints.client_id_metadata);
switch (mode_) {
case RequestMode::kMediated: {
// For Mediated mode we require accounts, token and client ID endpoints.
if (endpoints_.token.is_empty() || endpoints_.accounts.is_empty() ||
endpoints_.client_id_metadata.is_empty()) {
CompleteRequest(RequestIdTokenStatus::kErrorInvalidWellKnown, "");
return;
}
// TODO(kenrb): This has to be same-origin with the provider.
// https://crbug.com/1141125
if (!IdpUrlIsValid(endpoints_.token) ||
!IdpUrlIsValid(endpoints_.accounts) ||
!IdpUrlIsValid(endpoints_.client_id_metadata)) {
CompleteRequest(RequestIdTokenStatus::kError, "");
return;
}
network_manager_->FetchClientIdMetadata(
endpoints_.client_id_metadata, client_id_,
base::BindOnce(
&FederatedAuthRequestImpl::OnClientIdMetadataResponseReceived,
weak_ptr_factory_.GetWeakPtr()));
break;
}
case RequestMode::kPermission: {
// For Permission mode we require both accounts and token endpoints.
if (endpoints_.idp.is_empty()) {
CompleteRequest(RequestIdTokenStatus::kErrorInvalidWellKnown, "");
return;
}
// TODO(kenrb): This has to be same-origin with the provider.
// https://crbug.com/1141125
if (!IdpUrlIsValid(endpoints_.idp)) {
CompleteRequest(RequestIdTokenStatus::kError, "");
return;
}
network_manager_->SendSigninRequest(
endpoints_.idp, FormatRequestParams(client_id_, nonce_),
base::BindOnce(&FederatedAuthRequestImpl::OnSigninResponseReceived,
weak_ptr_factory_.GetWeakPtr()));
break;
}
}
}
void FederatedAuthRequestImpl::OnWellKnownFetchedForRevoke(
IdpNetworkRequestManager::FetchStatus status,
IdpNetworkRequestManager::Endpoints endpoints) {
if (status != IdpNetworkRequestManager::FetchStatus::kSuccess) {
CompleteRevokeRequest(RevokeStatus::kError);
return;
}
GURL revoke_url = ResolveWellKnownUrl(endpoints.revoke);
// TODO(kenrb): This has to be same-origin with the provider.
// https://crbug.com/1141125
if (!IdpUrlIsValid(revoke_url)) {
CompleteRevokeRequest(RevokeStatus::kError);
return;
}
network_manager_->SendRevokeRequest(
revoke_url, client_id_, account_id_,
base::BindOnce(&FederatedAuthRequestImpl::OnRevokeResponse,
weak_ptr_factory_.GetWeakPtr()));
}
void FederatedAuthRequestImpl::OnRevokeResponse(
IdpNetworkRequestManager::RevokeResponse response) {
RevokeStatus status =
response == IdpNetworkRequestManager::RevokeResponse::kSuccess
? RevokeStatus::kSuccess
: RevokeStatus::kError;
if (status == RevokeStatus::kSuccess) {
url::Origin idp_origin{url::Origin::Create(provider_)};
// Since the account is now deleted, revoke the permission.
if (GetRequestPermissionContext()) {
GetRequestPermissionContext()->RevokeRequestPermission(origin_,
idp_origin);
}
if (GetSharingPermissionContext()) {
GetSharingPermissionContext()->RevokeSharingPermissionForAccount(
idp_origin, origin_, account_id_);
}
if (GetActiveSessionPermissionContext()) {
GetActiveSessionPermissionContext()->RevokeActiveSession(
origin_, idp_origin, account_id_);
}
}
CompleteRevokeRequest(status);
}
void FederatedAuthRequestImpl::CompleteRevokeRequest(RevokeStatus status) {
network_manager_.reset();
provider_ = GURL();
account_id_ = std::string();
client_id_ = std::string();
if (revoke_callback_)
std::move(revoke_callback_).Run(status);
}
void FederatedAuthRequestImpl::OnClientIdMetadataResponseReceived(
IdpNetworkRequestManager::FetchStatus status,
IdpNetworkRequestManager::ClientIdMetadata data) {
// TODO(cbiesinger): check status argument to make sure fetching/parsing
// succeeded?
client_id_metadata_ = data;
network_manager_->SendAccountsRequest(
endpoints_.accounts,
base::BindOnce(&FederatedAuthRequestImpl::OnAccountsResponseReceived,
weak_ptr_factory_.GetWeakPtr()));
}
void FederatedAuthRequestImpl::OnSigninApproved(
IdentityRequestDialogController::UserApproval approval) {
if (approval != IdentityRequestDialogController::UserApproval::kApproved) {
CompleteRequest(RequestIdTokenStatus::kApprovalDeclined, "");
return;
}
if (GetRequestPermissionContext()) {
GetRequestPermissionContext()->GrantRequestPermission(
origin_, url::Origin::Create(provider_));
}
network_manager_->FetchIdpWellKnown(
base::BindOnce(&FederatedAuthRequestImpl::OnWellKnownFetched,
weak_ptr_factory_.GetWeakPtr()));
}
void FederatedAuthRequestImpl::OnSigninResponseReceived(
IdpNetworkRequestManager::SigninResponse status,
const std::string& url_or_token) {
// |url_or_token| is either the URL for the sign-in page or the ID token,
// depending on |status|.
switch (status) {
case IdpNetworkRequestManager::SigninResponse::kLoadIdp: {
GURL idp_signin_page_url = endpoints_.idp.Resolve(url_or_token);
if (!IdpUrlIsValid(idp_signin_page_url)) {
CompleteRequest(RequestIdTokenStatus::kError, "");
return;
}
WebContents* rp_web_contents =
WebContents::FromRenderFrameHost(render_frame_host_);
DCHECK(!idp_web_contents_);
idp_web_contents_ = CreateIdpWebContents();
request_dialog_controller_->ShowIdProviderWindow(
rp_web_contents, idp_web_contents_.get(), idp_signin_page_url,
base::BindOnce(&FederatedAuthRequestImpl::OnIdpPageClosed,
weak_ptr_factory_.GetWeakPtr()));
return;
}
case IdpNetworkRequestManager::SigninResponse::kTokenGranted: {
// TODO(kenrb): Returning success here has to be dependent on whether
// a WebID flow has succeeded in the past, otherwise jump to
// the token permission dialog.
CompleteRequest(RequestIdTokenStatus::kSuccess, url_or_token);
return;
}
case IdpNetworkRequestManager::SigninResponse::kSigninError: {
CompleteRequest(RequestIdTokenStatus::kErrorFetchingSignin, "");
return;
}
case IdpNetworkRequestManager::SigninResponse::kInvalidResponseError: {
CompleteRequest(RequestIdTokenStatus::kErrorInvalidSigninResponse, "");
return;
}
}
}
void FederatedAuthRequestImpl::OnTokenProvided(const std::string& id_token) {
id_token_ = id_token;
// Close the IDP window which leads to OnIdpPageClosed which is our common.
//
// TODO(majidvp): Consider if we should not wait on the IDP window closing and
// instead should directly call `OnIdpPageClosed` here.
request_dialog_controller_->CloseIdProviderWindow();
// Note that we always process the token on `OnIdpPageClosed()`.
// It is possible to get there either via:
// (a) IDP providing a token as shown below, or
// (b) User closing the sign-in window.
//
// +-----------------------+ +-------------------+ +-----------------+
// | FederatedAuthRequest | | DialogController | | IDPWebContents |
// +-----------------------+ +-------------------+ +-----------------+
// | | |
// | ShowIdProviderWindow() | |
// |-------------------------->| |
// | | |
// | | navigate to idp.com |
// | |----------------------->|
// | | |
// | | OnTokenProvided(token)|
// |<---------------------------------------------------|
// | | |
// | CloseIdProviderWindow() | |
// |-------------------------->| |
// | | |
// | closed | |
// |<--------------------------| |
// | | |
// OnIdpPageClosed() | |
// | | |
//
}
void FederatedAuthRequestImpl::OnIdpPageClosed() {
// This could happen if provider didn't provide any token or user closed the
// IdP window before it could.
if (id_token_.empty()) {
CompleteRequest(RequestIdTokenStatus::kError, "");
return;
}
WebContents* rp_web_contents =
WebContents::FromRenderFrameHost(render_frame_host_);
if (GetSharingPermissionContext() &&
GetSharingPermissionContext()->HasSharingPermission(
url::Origin::Create(provider_), origin_)) {
CompleteRequest(RequestIdTokenStatus::kSuccess, id_token_);
return;
}
request_dialog_controller_->ShowTokenExchangePermissionDialog(
rp_web_contents, provider_,
base::BindOnce(&FederatedAuthRequestImpl::OnTokenProvisionApproved,
weak_ptr_factory_.GetWeakPtr()));
}
void FederatedAuthRequestImpl::OnTokenProvisionApproved(
IdentityRequestDialogController::UserApproval approval) {
if (approval != IdentityRequestDialogController::UserApproval::kApproved) {
CompleteRequest(RequestIdTokenStatus::kApprovalDeclined, "");
return;
}
if (GetSharingPermissionContext()) {
// Grant sharing permission for RP/IDP pair without a specific account.
GetSharingPermissionContext()->GrantSharingPermission(
url::Origin::Create(provider_), origin_);
}
CompleteRequest(RequestIdTokenStatus::kSuccess, id_token_);
}
void FederatedAuthRequestImpl::OnAccountsResponseReceived(
IdpNetworkRequestManager::AccountsResponse status,
IdpNetworkRequestManager::AccountList accounts,
content::IdentityProviderMetadata idp_metadata) {
switch (status) {
case IdpNetworkRequestManager::AccountsResponse::kNetError: {
CompleteRequest(RequestIdTokenStatus::kError, "");
return;
}
case IdpNetworkRequestManager::AccountsResponse::kInvalidResponseError: {
CompleteRequest(RequestIdTokenStatus::kErrorInvalidAccountsResponse, "");
return;
}
case IdpNetworkRequestManager::AccountsResponse::kSuccess: {
WebContents* rp_web_contents =
WebContents::FromRenderFrameHost(render_frame_host_);
DCHECK(!idp_web_contents_);
// Populate the accounts login state.
for (auto& account : accounts) {
LoginState login_state = LoginState::kSignUp;
// Consider this a sign-in if we have seen a successful sign-up for
// this account before.
if (GetSharingPermissionContext() &&
GetSharingPermissionContext()->HasSharingPermissionForAccount(
url::Origin::Create(provider_), origin_, account.sub)) {
login_state = LoginState::kSignIn;
}
account.login_state = login_state;
}
idp_web_contents_ = CreateIdpWebContents();
bool screen_reader_is_on =
rp_web_contents->GetAccessibilityMode().has_mode(
ui::AXMode::kScreenReader);
// Auto signs in returning users if they have a single account and are
// signing in.
// TODO(yigu): Add additional controls for RP/IDP/User for this flow.
// https://crbug.com/1236678.
bool is_auto_sign_in = prefer_auto_sign_in_ && accounts.size() == 1 &&
accounts[0].login_state == LoginState::kSignIn &&
!screen_reader_is_on;
ClientIdData data{endpoints_.client_id_metadata.Resolve(
client_id_metadata_.terms_of_service_url),
endpoints_.client_id_metadata.Resolve(
client_id_metadata_.privacy_policy_url)};
request_dialog_controller_->ShowAccountsDialog(
rp_web_contents, idp_web_contents_.get(), provider_, accounts,
idp_metadata, data,
is_auto_sign_in ? SignInMode::kAuto : SignInMode::kExplicit,
base::BindOnce(&FederatedAuthRequestImpl::OnAccountSelected,
weak_ptr_factory_.GetWeakPtr()));
return;
}
}
}
void FederatedAuthRequestImpl::OnAccountSelected(
const std::string& account_id) {
// This could happen if user didn't select any accounts.
if (account_id.empty()) {
CompleteRequest(RequestIdTokenStatus::kError, "");
return;
}
// Account selection is considered sufficient for granting request permission
// (which also implies the logout permission).
if (GetRequestPermissionContext()) {
GetRequestPermissionContext()->GrantRequestPermission(
origin_, url::Origin::Create(provider_));
}
account_id_ = account_id;
network_manager_->SendTokenRequest(
endpoints_.token, account_id_, FormatRequestParams(client_id_, nonce_),
base::BindOnce(&FederatedAuthRequestImpl::OnTokenResponseReceived,
weak_ptr_factory_.GetWeakPtr()));
}
void FederatedAuthRequestImpl::OnTokenResponseReceived(
IdpNetworkRequestManager::TokenResponse status,
const std::string& id_token) {
switch (status) {
case IdpNetworkRequestManager::TokenResponse::kNetError: {
CompleteRequest(RequestIdTokenStatus::kError, "");
return;
}
case IdpNetworkRequestManager::TokenResponse::kInvalidRequestError: {
CompleteRequest(RequestIdTokenStatus::kErrorInvalidTokenResponse, "");
return;
}
case IdpNetworkRequestManager::TokenResponse::kInvalidResponseError: {
CompleteRequest(RequestIdTokenStatus::kErrorInvalidTokenResponse, "");
return;
}
case IdpNetworkRequestManager::TokenResponse::kSuccess: {
if (GetSharingPermissionContext()) {
DCHECK_EQ(mode_, RequestMode::kMediated);
// Grant sharing permission specific to *this account*.
//
// TODO(majidvp): But wait which account?
// 1) The account that user selected in our UI (i.e., account_id_) or
// 2) The one for which the IDP generated a token.
//
// Ideally these are one and the same but currently there is no
// enforcement for that equality so they could be different. In the
// future we may want to enforce that the token account (aka subject)
// matches the user selected account. But for now these questions are
// moot since we don't actually inspect the returned idtoken.
// https://crbug.com/1199088
CHECK(!account_id_.empty());
GetSharingPermissionContext()->GrantSharingPermissionForAccount(
url::Origin::Create(provider_), origin_, account_id_);
}
if (GetActiveSessionPermissionContext()) {
GetActiveSessionPermissionContext()->GrantActiveSession(
origin_, url::Origin::Create(provider_), account_id_);
}
id_token_ = id_token;
CompleteRequest(RequestIdTokenStatus::kSuccess, id_token_);
return;
}
}
}
void FederatedAuthRequestImpl::DispatchOneLogout() {
auto logout_request = std::move(logout_requests_.front());
DCHECK(logout_request->endpoint.is_valid());
std::string account_id = logout_request->account_id;
auto endpoint_origin = url::Origin::Create(logout_request->endpoint);
logout_requests_.pop();
if (!GetActiveSessionPermissionContext()) {
CompleteLogoutRequest(LogoutStatus::kError);
return;
}
if (GetActiveSessionPermissionContext()->HasActiveSession(
endpoint_origin, origin_, account_id)) {
network_manager_->SendLogout(
logout_request->endpoint,
base::BindOnce(&FederatedAuthRequestImpl::OnLogoutCompleted,
weak_ptr_factory_.GetWeakPtr()));
GetActiveSessionPermissionContext()->RevokeActiveSession(
endpoint_origin, origin_, account_id);
} else {
if (logout_requests_.empty()) {
CompleteLogoutRequest(LogoutStatus::kSuccess);
return;
}
DispatchOneLogout();
}
}
void FederatedAuthRequestImpl::OnLogoutCompleted() {
if (logout_requests_.empty()) {
CompleteLogoutRequest(LogoutStatus::kSuccess);
return;
}
DispatchOneLogout();
}
std::unique_ptr<WebContents> FederatedAuthRequestImpl::CreateIdpWebContents() {
auto idp_web_contents = content::WebContents::Create(
WebContents::CreateParams(render_frame_host_->GetBrowserContext()));
// Store the callback on the provider web contents so that it can be
// used later.
IdTokenRequestCallbackData::Set(
idp_web_contents.get(),
base::BindOnce(&FederatedAuthRequestImpl::OnTokenProvided,
weak_ptr_factory_.GetWeakPtr()));
return idp_web_contents;
}
void FederatedAuthRequestImpl::CompleteRequest(
blink::mojom::RequestIdTokenStatus status,
const std::string& id_token) {
DCHECK(status == RequestIdTokenStatus::kSuccess || id_token.empty());
request_dialog_controller_.reset();
network_manager_.reset();
// Given that |request_dialog_controller_| has reference to this web content
// instance we destroy that first.
idp_web_contents_.reset();
account_id_ = std::string();
if (auth_request_callback_)
std::move(auth_request_callback_).Run(status, id_token);
}
void FederatedAuthRequestImpl::CompleteLogoutRequest(
blink::mojom::LogoutStatus status) {
network_manager_.reset();
base::queue<blink::mojom::LogoutRequestPtr>().swap(logout_requests_);
if (logout_callback_)
std::move(logout_callback_).Run(status);
}
std::unique_ptr<IdpNetworkRequestManager>
FederatedAuthRequestImpl::CreateNetworkManager(const GURL& provider) {
if (mock_network_manager_)
return std::move(mock_network_manager_);
return IdpNetworkRequestManager::Create(provider, render_frame_host_);
}
std::unique_ptr<IdentityRequestDialogController>
FederatedAuthRequestImpl::CreateDialogController() {
if (mock_dialog_controller_)
return std::move(mock_dialog_controller_);
return GetContentClient()->browser()->CreateIdentityRequestDialogController();
}
void FederatedAuthRequestImpl::SetNetworkManagerForTests(
std::unique_ptr<IdpNetworkRequestManager> manager) {
mock_network_manager_ = std::move(manager);
}
void FederatedAuthRequestImpl::SetDialogControllerForTests(
std::unique_ptr<IdentityRequestDialogController> controller) {
mock_dialog_controller_ = std::move(controller);
}
void FederatedAuthRequestImpl::SetActiveSessionPermissionDelegateForTests(
FederatedIdentityActiveSessionPermissionContextDelegate*
active_session_permission_delegate) {
active_session_permission_delegate_ = active_session_permission_delegate;
}
void FederatedAuthRequestImpl::SetRequestPermissionDelegateForTests(
FederatedIdentityRequestPermissionContextDelegate*
request_permission_delegate) {
request_permission_delegate_ = request_permission_delegate;
}
void FederatedAuthRequestImpl::SetSharingPermissionDelegateForTests(
FederatedIdentitySharingPermissionContextDelegate*
sharing_permission_delegate) {
sharing_permission_delegate_ = sharing_permission_delegate;
}
FederatedIdentityActiveSessionPermissionContextDelegate*
FederatedAuthRequestImpl::GetActiveSessionPermissionContext() {
if (!active_session_permission_delegate_) {
active_session_permission_delegate_ =
render_frame_host_->GetBrowserContext()
->GetFederatedIdentityActiveSessionPermissionContext();
}
return active_session_permission_delegate_;
}
FederatedIdentityRequestPermissionContextDelegate*
FederatedAuthRequestImpl::GetRequestPermissionContext() {
if (!request_permission_delegate_) {
request_permission_delegate_ =
render_frame_host_->GetBrowserContext()
->GetFederatedIdentityRequestPermissionContext();
}
return request_permission_delegate_;
}
FederatedIdentitySharingPermissionContextDelegate*
FederatedAuthRequestImpl::GetSharingPermissionContext() {
if (!sharing_permission_delegate_) {
sharing_permission_delegate_ =
render_frame_host_->GetBrowserContext()
->GetFederatedIdentitySharingPermissionContext();
}
return sharing_permission_delegate_;
}
} // namespace content