#include "chrome/browser/ash/arc/auth/arc_auth_service.h"
#include <optional>
#include <utility>
#include <vector>
#include "ash/constants/ash_switches.h"
#include "ash/webui/settings/public/constants/routes.mojom.h"
#include "base/check_deref.h"
#include "base/command_line.h"
#include "base/containers/flat_set.h"
#include "base/functional/bind.h"
#include "base/memory/singleton.h"
#include "base/metrics/histogram_functions.h"
#include "base/strings/utf_string_conversions.h"
#include "base/time/time.h"
#include "chrome/browser/ash/account_manager/account_apps_availability_factory.h"
#include "chrome/browser/ash/account_manager/account_manager_util.h"
#include "chrome/browser/ash/app_list/arc/arc_data_removal_dialog.h"
#include "chrome/browser/ash/arc/arc_optin_uma.h"
#include "chrome/browser/ash/arc/arc_util.h"
#include "chrome/browser/ash/arc/auth/arc_background_auth_code_fetcher.h"
#include "chrome/browser/ash/arc/auth/arc_robot_auth_code_fetcher.h"
#include "chrome/browser/ash/arc/policy/arc_policy_util.h"
#include "chrome/browser/ash/arc/session/arc_provisioning_result.h"
#include "chrome/browser/ash/arc/session/arc_session_manager.h"
#include "chrome/browser/ash/login/demo_mode/demo_session.h"
#include "chrome/browser/ash/profiles/profile_helper.h"
#include "chrome/browser/lifetime/application_lifetime.h"
#include "chrome/browser/profiles/profile.h"
#include "chrome/browser/signin/identity_manager_factory.h"
#include "chrome/browser/signin/signin_ui_util.h"
#include "chrome/browser/ui/webui/signin/ash/inline_login_dialog.h"
#include "chrome/common/webui_url_constants.h"
#include "chromeos/ash/components/account_manager/account_manager_factory.h"
#include "chromeos/ash/components/browser_context_helper/browser_context_helper.h"
#include "chromeos/ash/experiences/arc/arc_browser_context_keyed_service_factory_base.h"
#include "chromeos/ash/experiences/arc/arc_features.h"
#include "chromeos/ash/experiences/arc/arc_prefs.h"
#include "chromeos/ash/experiences/arc/arc_util.h"
#include "chromeos/ash/experiences/arc/mojom/auth.mojom-shared.h"
#include "chromeos/ash/experiences/arc/session/arc_bridge_service.h"
#include "chromeos/ash/experiences/arc/session/arc_management_transition.h"
#include "chromeos/ash/experiences/arc/session/arc_service_manager.h"
#include "chromeos/ash/experiences/settings_ui/settings_app_manager.h"
#include "components/account_manager_core/account_manager_facade.h"
#include "components/prefs/pref_service.h"
#include "components/signin/public/base/consent_level.h"
#include "components/user_manager/user_manager.h"
#include "content/public/browser/browser_context.h"
#include "content/public/browser/browser_thread.h"
#include "content/public/browser/storage_partition.h"
#include "google_apis/gaia/gaia_id.h"
#include "services/network/public/cpp/shared_url_loader_factory.h"
#undef ENABLED_VLOG_LEVEL
#define ENABLED_VLOG_LEVEL 1
namespace arc {
namespace {
class ArcAuthServiceFactory
: public internal::ArcBrowserContextKeyedServiceFactoryBase<
ArcAuthService,
ArcAuthServiceFactory> {
public:
static constexpr const char* kName = "ArcAuthServiceFactory";
static ArcAuthServiceFactory* GetInstance() {
return base::Singleton<ArcAuthServiceFactory>::get();
}
private:
friend struct base::DefaultSingletonTraits<ArcAuthServiceFactory>;
ArcAuthServiceFactory() {
DependsOn(IdentityManagerFactory::GetInstance());
DependsOn(ash::AccountAppsAvailabilityFactory::GetInstance());
}
~ArcAuthServiceFactory() override = default;
};
class ArcAuthServiceDelegateImpl : public ArcAuthService::Delegate {
public:
explicit ArcAuthServiceDelegateImpl(user_manager::User* user)
: user_(CHECK_DEREF(user)) {}
void OpenSettingsAppWithPeopleSection() override {
ash::SettingsAppManager::Get()->Open(
*user_, {.sub_page = chromeos::settings::mojom::kPeopleSectionPath});
}
private:
const raw_ref<user_manager::User> user_;
};
mojom::ChromeAccountType GetAccountType(const Profile* profile) {
base::CommandLine* command_line = base::CommandLine::ForCurrentProcess();
DCHECK(command_line);
if (command_line->HasSwitch(
ash::switches::kDemoModeForceArcOfflineProvision)) {
return mojom::ChromeAccountType::OFFLINE_DEMO_ACCOUNT;
}
if (profile->IsChild()) {
return mojom::ChromeAccountType::CHILD_ACCOUNT;
}
auto* demo_session = ash::DemoSession::Get();
if (demo_session && demo_session->started()) {
DCHECK(IsRobotOrOfflineDemoAccountMode());
return mojom::ChromeAccountType::ROBOT_ACCOUNT;
}
return IsRobotOrOfflineDemoAccountMode()
? mojom::ChromeAccountType::ROBOT_ACCOUNT
: mojom::ChromeAccountType::USER_ACCOUNT;
}
mojom::AccountInfoPtr CreateAccountInfo(bool is_enforced,
const std::string& auth_info,
const std::string& account_name,
mojom::ChromeAccountType account_type,
bool is_managed) {
mojom::AccountInfoPtr account_info = mojom::AccountInfo::New();
account_info->account_name = account_name;
if (!is_enforced) {
account_info->auth_code = std::nullopt;
} else {
account_info->auth_code = auth_info;
}
account_info->account_type = account_type;
account_info->is_managed = is_managed;
return account_info;
}
bool IsPrimaryGaiaAccount(const GaiaId& gaia_id) {
const user_manager::User* user =
user_manager::UserManager::Get()->GetPrimaryUser();
DCHECK(user);
return user->GetAccountId().GetAccountType() == AccountType::GOOGLE &&
user->GetAccountId().GetGaiaId() == gaia_id;
}
bool IsPrimaryOrDeviceLocalAccount(
const signin::IdentityManager* identity_manager,
const std::string& account_name) {
const user_manager::User* user =
user_manager::UserManager::Get()->GetPrimaryUser();
DCHECK(user);
if (user->IsDeviceLocalAccount()) {
return true;
}
const AccountInfo account_info =
identity_manager->FindExtendedAccountInfoByEmailAddress(account_name);
if (account_info.IsEmpty()) {
return false;
}
DCHECK(!account_info.gaia.empty());
return IsPrimaryGaiaAccount(account_info.gaia);
}
std::string GetAccountName(Profile* profile) {
switch (GetAccountType(profile)) {
case mojom::ChromeAccountType::USER_ACCOUNT:
[[fallthrough]];
case mojom::ChromeAccountType::CHILD_ACCOUNT:
return ash::ProfileHelper::Get()
->GetUserByProfile(profile)
->GetDisplayEmail();
case mojom::ChromeAccountType::ROBOT_ACCOUNT:
[[fallthrough]];
case mojom::ChromeAccountType::OFFLINE_DEMO_ACCOUNT:
return std::string();
case mojom::ChromeAccountType::UNKNOWN:
NOTREACHED();
}
}
void OnFetchPrimaryAccountInfoCompleted(
ArcAuthService::RequestAccountInfoCallback callback,
bool persistent_error,
mojom::ArcAuthCodeStatus status,
mojom::AccountInfoPtr account_info) {
std::move(callback).Run(std::move(status), std::move(account_info),
persistent_error);
}
void CompleteFetchPrimaryAccountInfoWithMetrics(
ArcAuthService::RequestPrimaryAccountInfoCallback callback,
mojom::ArcAuthCodeStatus status,
mojom::AccountInfoPtr account_info) {
base::UmaHistogramEnumeration(
kArcAuthRequestAccountInfoResultPrimaryHistogramName, status);
std::move(callback).Run(std::move(status), std::move(account_info));
}
void CompleteFetchSecondaryAccountInfoWithMetrics(
ArcAuthService::RequestAccountInfoCallback callback,
mojom::ArcAuthCodeStatus status,
mojom::AccountInfoPtr account_info,
bool persistent_error) {
base::UmaHistogramEnumeration(
kArcAuthRequestAccountInfoResultSecondaryHistogramName, status);
std::move(callback).Run(std::move(status), std::move(account_info),
persistent_error);
}
}
const char ArcAuthService::kArcServiceName[] = "arc::ArcAuthService";
ArcAuthService* ArcAuthService::GetForBrowserContext(
content::BrowserContext* context) {
return ArcAuthServiceFactory::GetForBrowserContext(context);
}
ArcAuthService::ArcAuthService(content::BrowserContext* browser_context,
ArcBridgeService* arc_bridge_service)
: delegate_(std::make_unique<ArcAuthServiceDelegateImpl>(
ash::BrowserContextHelper::Get()->GetUserByBrowserContext(
browser_context))),
profile_(Profile::FromBrowserContext(browser_context)),
identity_manager_(IdentityManagerFactory::GetForProfile(profile_)),
arc_bridge_service_(arc_bridge_service),
url_loader_factory_(profile_->GetDefaultStoragePartition()
->GetURLLoaderFactoryForBrowserProcess()) {
arc_bridge_service_->auth()->SetHost(this);
arc_bridge_service_->auth()->AddObserver(this);
ArcSessionManager::Get()->AddObserver(this);
identity_manager_->AddObserver(this);
if (ash::IsAccountManagerAvailable(profile_)) {
account_apps_availability_ =
ash::AccountAppsAvailabilityFactory::GetForProfile(profile_);
account_apps_availability_->AddObserver(this);
}
}
ArcAuthService::~ArcAuthService() {
ArcSessionManager::Get()->RemoveObserver(this);
arc_bridge_service_->auth()->RemoveObserver(this);
arc_bridge_service_->auth()->SetHost(nullptr);
}
void ArcAuthService::GetGoogleAccountsInArc(
GetGoogleAccountsInArcCallback callback) {
DCHECK_CURRENTLY_ON(content::BrowserThread::UI);
DCHECK(pending_get_arc_accounts_callback_.is_null())
<< "Cannot have more than one pending GetGoogleAccountsInArc request";
if (!arc::IsArcProvisioned(profile_)) {
std::move(callback).Run(std::vector<mojom::ArcAccountInfoPtr>());
return;
}
if (!arc_bridge_service_->auth()->IsConnected()) {
pending_get_arc_accounts_callback_ = std::move(callback);
return;
}
DispatchAccountsInArc(std::move(callback));
}
void ArcAuthService::RequestPrimaryAccount(
RequestPrimaryAccountCallback callback) {
std::move(callback).Run(GetAccountName(profile_), GetAccountType(profile_));
}
void ArcAuthService::OnConnectionReady() {
if (arc::IsArcProvisioned(profile_)) {
TriggerAccountsPushToArc(false );
}
if (pending_get_arc_accounts_callback_) {
DispatchAccountsInArc(std::move(pending_get_arc_accounts_callback_));
}
if (!IsArcProvisioned(profile_)) {
return;
}
auto* instance = ARC_GET_INSTANCE_FOR_METHOD(arc_bridge_service_->auth(),
GetMainAccountResolutionStatus);
if (!instance) {
return;
}
instance->GetMainAccountResolutionStatus(
base::BindOnce(&ArcAuthService::OnMainAccountResolutionStatus,
weak_ptr_factory_.GetWeakPtr()));
}
void ArcAuthService::OnConnectionClosed() {
DCHECK_CURRENTLY_ON(content::BrowserThread::UI);
pending_token_requests_.clear();
}
void ArcAuthService::OnAuthorizationResult(mojom::ArcSignInResultPtr result,
mojom::ArcSignInAccountPtr account) {
ArcProvisioningResult provisioning_result(std::move(result));
if (account->is_initial_signin()) {
ArcSessionManager::Get()->OnProvisioningFinished(provisioning_result);
return;
}
if (!user_manager::UserManager::Get()->IsLoggedInAsUserWithGaiaAccount()) {
NOTREACHED() << "Shouldn't re-auth for non-Gaia accounts";
}
const ProvisioningStatus status = GetProvisioningStatus(provisioning_result);
if (!account->is_account_name() || !account->get_account_name() ||
account->get_account_name().value().empty() ||
IsPrimaryOrDeviceLocalAccount(identity_manager_,
account->get_account_name().value())) {
UpdateReauthorizationResultUMA(status, profile_);
} else {
UpdateSecondarySigninResultUMA(status);
}
}
void ArcAuthService::ReportMetrics(mojom::MetricsType metrics_type,
int32_t value) {
switch (metrics_type) {
case mojom::MetricsType::NETWORK_WAITING_TIME_MILLISECONDS:
UpdateAuthTiming("Arc.Auth.NetworkWait.TimeDelta",
base::Milliseconds(value), profile_);
break;
case mojom::MetricsType::CHECKIN_ATTEMPTS:
UpdateAuthCheckinAttempts(value, profile_);
break;
case mojom::MetricsType::CHECKIN_TIME_MILLISECONDS:
UpdateAuthTiming("Arc.Auth.Checkin.TimeDelta", base::Milliseconds(value),
profile_);
break;
case mojom::MetricsType::SIGNIN_TIME_MILLISECONDS:
UpdateAuthTiming("Arc.Auth.SignIn.TimeDelta", base::Milliseconds(value),
profile_);
break;
case mojom::MetricsType::ACCOUNT_CHECK_MILLISECONDS:
UpdateAuthTiming("Arc.Auth.AccountCheck.TimeDelta",
base::Milliseconds(value), profile_);
break;
}
}
void ArcAuthService::ReportAccountCheckStatus(
mojom::AccountCheckStatus status) {
UpdateAuthAccountCheckStatus(status, profile_);
}
void ArcAuthService::ReportAccountReauthReason(mojom::ReauthReason reason) {
UpdateAccountReauthReason(reason, profile_);
}
void ArcAuthService::ReportManagementChangeStatus(
mojom::ManagementChangeStatus status) {
UpdateSupervisionTransitionResultUMA(status);
switch (status) {
case mojom::ManagementChangeStatus::CLOUD_DPC_DISABLED:
case mojom::ManagementChangeStatus::CLOUD_DPC_ALREADY_DISABLED:
case mojom::ManagementChangeStatus::CLOUD_DPC_ENABLED:
case mojom::ManagementChangeStatus::CLOUD_DPC_ALREADY_ENABLED:
profile_->GetPrefs()->SetInteger(
prefs::kArcManagementTransition,
static_cast<int>(ArcManagementTransition::NO_TRANSITION));
break;
case mojom::ManagementChangeStatus::CLOUD_DPC_DISABLING_FAILED:
case mojom::ManagementChangeStatus::CLOUD_DPC_ENABLING_FAILED:
LOG(ERROR) << "Management transition failed: " << status;
ShowDataRemovalConfirmationDialog(
profile_, base::BindOnce(&ArcAuthService::OnDataRemovalAccepted,
weak_ptr_factory_.GetWeakPtr()));
break;
case mojom::ManagementChangeStatus::INVALID_MANAGEMENT_STATE:
NOTREACHED() << "Invalid status of management transition: " << status;
}
}
void ArcAuthService::RequestPrimaryAccountInfo(
RequestPrimaryAccountInfoCallback callback) {
FetchPrimaryAccountInfo(
true ,
base::BindOnce(&CompleteFetchPrimaryAccountInfoWithMetrics,
std::move(callback)));
}
void ArcAuthService::RequestAccountInfo(const std::string& account_name,
RequestAccountInfoCallback callback) {
if (!IsPrimaryOrDeviceLocalAccount(identity_manager_, account_name)) {
FetchSecondaryAccountInfo(
account_name,
base::BindOnce(&CompleteFetchSecondaryAccountInfoWithMetrics,
std::move(callback)));
return;
}
FetchPrimaryAccountInfo(
false ,
base::BindOnce(
&CompleteFetchPrimaryAccountInfoWithMetrics,
base::BindOnce(&OnFetchPrimaryAccountInfoCompleted,
std::move(callback), false )));
}
void ArcAuthService::FetchPrimaryAccountInfo(
bool initial_signin,
RequestPrimaryAccountInfoCallback callback) {
const mojom::ChromeAccountType account_type = GetAccountType(profile_);
if (IsArcOptInVerificationDisabled()) {
std::move(callback).Run(
mojom::ArcAuthCodeStatus::SUCCESS,
CreateAccountInfo(false ,
std::string() ,
std::string() , account_type,
policy_util::IsAccountManaged(profile_)));
return;
}
if (account_type == mojom::ChromeAccountType::OFFLINE_DEMO_ACCOUNT) {
std::move(callback).Run(
mojom::ArcAuthCodeStatus::SUCCESS,
CreateAccountInfo(true , std::string() ,
std::string() , account_type,
true ));
return;
}
std::unique_ptr<ArcAuthCodeFetcher> auth_code_fetcher;
if (account_type == mojom::ChromeAccountType::ROBOT_ACCOUNT) {
auth_code_fetcher = std::make_unique<ArcRobotAuthCodeFetcher>();
if (url_loader_factory_for_testing_set_) {
static_cast<ArcRobotAuthCodeFetcher*>(auth_code_fetcher.get())
->SetURLLoaderFactoryForTesting(url_loader_factory_);
}
} else {
DCHECK(identity_manager_->HasPrimaryAccount(signin::ConsentLevel::kSignin));
auth_code_fetcher = CreateArcBackgroundAuthCodeFetcher(
identity_manager_->GetPrimaryAccountId(signin::ConsentLevel::kSignin),
initial_signin);
}
auto* auth_code_fetcher_ptr = auth_code_fetcher.get();
pending_token_requests_.emplace_back(std::move(auth_code_fetcher));
auth_code_fetcher_ptr->Fetch(
base::BindOnce(&ArcAuthService::OnPrimaryAccountAuthCodeFetched,
weak_ptr_factory_.GetWeakPtr(), auth_code_fetcher_ptr,
std::move(callback)));
}
void ArcAuthService::IsAccountManagerAvailable(
IsAccountManagerAvailableCallback callback) {
std::move(callback).Run(ash::IsAccountManagerAvailable(profile_));
}
void ArcAuthService::HandleAddAccountRequest() {
DCHECK(ash::IsAccountManagerAvailable(profile_));
ash::AccountManagerFactory::Get()
->GetAccountManagerFacade(profile_->GetPath().value())
->ShowAddAccountDialog(
account_manager::AccountManagerFacade::AccountAdditionSource::kArc);
}
void ArcAuthService::HandleRemoveAccountRequest(const std::string& email) {
DCHECK(ash::IsAccountManagerAvailable(profile_));
delegate_->OpenSettingsAppWithPeopleSection();
}
void ArcAuthService::HandleUpdateCredentialsRequest(const std::string& email) {
DCHECK(ash::IsAccountManagerAvailable(profile_));
ash::AccountManagerFactory::Get()
->GetAccountManagerFacade(profile_->GetPath().value())
->ShowReauthAccountDialog(
account_manager::AccountManagerFacade::AccountAdditionSource::kArc,
email, base::DoNothing());
}
void ArcAuthService::SetDelegateForTesting(std::unique_ptr<Delegate> delegate) {
delegate_ = std::move(delegate);
}
void ArcAuthService::OnRefreshTokenUpdatedForAccount(
const CoreAccountInfo& account_info) {}
void ArcAuthService::OnExtendedAccountInfoRemoved(
const AccountInfo& account_info) {}
void ArcAuthService::OnAccountAvailableInArc(
const account_manager::Account& account) {
DCHECK_CURRENTLY_ON(content::BrowserThread::UI);
DCHECK(ash::IsAccountManagerAvailable(profile_));
CoreAccountInfo account_info =
identity_manager_->FindExtendedAccountInfoByEmailAddress(
account.raw_email);
if (account_info.IsEmpty()) {
VLOG(1) << "Ignoring account update because CoreAccountInfo is empty for "
"account: "
<< account.raw_email;
return;
}
UpsertAccountToArc(account_info);
}
void ArcAuthService::OnAccountUnavailableInArc(
const account_manager::Account& account) {
DCHECK_CURRENTLY_ON(content::BrowserThread::UI);
DCHECK(ash::IsAccountManagerAvailable(profile_));
DCHECK(!IsPrimaryGaiaAccount(GaiaId(account.key.id())));
RemoveAccountFromArc(account.raw_email);
}
void ArcAuthService::OnArcInitialStart() {
TriggerAccountsPushToArc(true );
}
void ArcAuthService::Shutdown() {
identity_manager_->RemoveObserver(this);
if (account_apps_availability_) {
account_apps_availability_->RemoveObserver(this);
}
}
void ArcAuthService::UpsertAccountToArc(const CoreAccountInfo& account_info) {
DCHECK_CURRENTLY_ON(content::BrowserThread::UI);
if (!ash::IsAccountManagerAvailable(profile_)) {
return;
}
if (!arc::IsArcProvisioned(profile_)) {
return;
}
if (identity_manager_->HasAccountWithRefreshTokenInPersistentErrorState(
account_info.account_id)) {
VLOG(1) << "Ignoring account update due to lack of a valid token: "
<< account_info.email;
return;
}
auto* instance = ARC_GET_INSTANCE_FOR_METHOD(arc_bridge_service_->auth(),
OnAccountUpdated);
if (!instance) {
return;
}
const std::string account_name = account_info.email;
DCHECK(!account_name.empty());
instance->OnAccountUpdated(account_name, mojom::AccountUpdateType::UPSERT);
}
void ArcAuthService::RemoveAccountFromArc(const std::string& email) {
DCHECK_CURRENTLY_ON(content::BrowserThread::UI);
if (!ash::IsAccountManagerAvailable(profile_)) {
return;
}
if (!arc::IsArcProvisioned(profile_)) {
return;
}
auto* instance = ARC_GET_INSTANCE_FOR_METHOD(arc_bridge_service_->auth(),
OnAccountUpdated);
if (!instance) {
return;
}
DCHECK(!email.empty());
instance->OnAccountUpdated(email, mojom::AccountUpdateType::REMOVAL);
}
void ArcAuthService::OnPrimaryAccountAuthCodeFetched(
ArcAuthCodeFetcher* fetcher,
RequestPrimaryAccountInfoCallback callback,
bool success,
const std::string& auth_code) {
DCHECK_CURRENTLY_ON(content::BrowserThread::UI);
DeletePendingTokenRequest(fetcher);
if (success) {
const std::string& full_account_id = GetAccountName(profile_);
std::move(callback).Run(
mojom::ArcAuthCodeStatus::SUCCESS,
CreateAccountInfo(!IsArcOptInVerificationDisabled(), auth_code,
full_account_id, GetAccountType(profile_),
policy_util::IsAccountManaged(profile_)));
} else if (ash::DemoSession::Get() && ash::DemoSession::Get()->started()) {
std::move(callback).Run(
mojom::ArcAuthCodeStatus::SUCCESS,
CreateAccountInfo(true , std::string() ,
std::string() ,
mojom::ChromeAccountType::OFFLINE_DEMO_ACCOUNT,
true ));
} else {
std::move(callback).Run(
mojom::ArcAuthCodeStatus::CHROME_SERVER_COMMUNICATION_ERROR, nullptr);
}
}
void ArcAuthService::FetchSecondaryAccountInfo(
const std::string& account_name,
RequestAccountInfoCallback callback) {
DCHECK_CURRENTLY_ON(content::BrowserThread::UI);
AccountInfo account_info =
identity_manager_->FindExtendedAccountInfoByEmailAddress(account_name);
if (account_info.IsEmpty()) {
std::move(callback).Run(mojom::ArcAuthCodeStatus::CHROME_ACCOUNT_NOT_FOUND,
nullptr ,
true );
return;
}
const CoreAccountId& account_id = account_info.account_id;
DCHECK(!account_id.empty());
if (identity_manager_->HasAccountWithRefreshTokenInPersistentErrorState(
account_id)) {
std::move(callback).Run(
mojom::ArcAuthCodeStatus::CHROME_SERVER_COMMUNICATION_ERROR,
nullptr , true );
return;
}
std::unique_ptr<ArcBackgroundAuthCodeFetcher> fetcher =
CreateArcBackgroundAuthCodeFetcher(account_id,
false );
auto* fetcher_ptr = fetcher.get();
pending_token_requests_.emplace_back(std::move(fetcher));
fetcher_ptr->Fetch(
base::BindOnce(&ArcAuthService::OnSecondaryAccountAuthCodeFetched,
weak_ptr_factory_.GetWeakPtr(), account_name, fetcher_ptr,
std::move(callback)));
}
void ArcAuthService::OnSecondaryAccountAuthCodeFetched(
const std::string& account_name,
ArcBackgroundAuthCodeFetcher* fetcher,
RequestAccountInfoCallback callback,
bool success,
const std::string& auth_code) {
DeletePendingTokenRequest(fetcher);
if (success) {
std::move(callback).Run(
mojom::ArcAuthCodeStatus::SUCCESS,
CreateAccountInfo(true , auth_code, account_name,
mojom::ChromeAccountType::USER_ACCOUNT,
false ),
false );
return;
}
AccountInfo account_info =
identity_manager_->FindExtendedAccountInfoByEmailAddress(account_name);
if (!account_info.IsEmpty()) {
const bool is_persistent_error =
identity_manager_->HasAccountWithRefreshTokenInPersistentErrorState(
account_info.account_id);
std::move(callback).Run(
mojom::ArcAuthCodeStatus::CHROME_SERVER_COMMUNICATION_ERROR,
nullptr , is_persistent_error);
return;
}
std::move(callback).Run(mojom::ArcAuthCodeStatus::CHROME_ACCOUNT_NOT_FOUND,
nullptr , true);
}
void ArcAuthService::DeletePendingTokenRequest(ArcFetcherBase* fetcher) {
DCHECK_CURRENTLY_ON(content::BrowserThread::UI);
for (auto it = pending_token_requests_.begin();
it != pending_token_requests_.end(); ++it) {
if (it->get() == fetcher) {
pending_token_requests_.erase(it);
return;
}
}
NOTREACHED();
}
void ArcAuthService::SetURLLoaderFactoryForTesting(
scoped_refptr<network::SharedURLLoaderFactory> url_loader_factory) {
url_loader_factory_ = std::move(url_loader_factory);
url_loader_factory_for_testing_set_ = true;
}
void ArcAuthService::OnDataRemovalAccepted(bool accepted) {
if (!accepted) {
return;
}
if (!IsArcPlayStoreEnabledForProfile(profile_)) {
return;
}
VLOG(1)
<< "Request for data removal on child transition failure is confirmed";
ArcSessionManager::Get()->RequestArcDataRemoval();
ArcSessionManager::Get()->StopAndEnableArc();
}
std::unique_ptr<ArcBackgroundAuthCodeFetcher>
ArcAuthService::CreateArcBackgroundAuthCodeFetcher(
const CoreAccountId& account_id,
bool initial_signin) {
const AccountInfo account_info =
identity_manager_->FindExtendedAccountInfoByAccountId(account_id);
DCHECK(!account_info.IsEmpty());
auto fetcher = std::make_unique<ArcBackgroundAuthCodeFetcher>(
url_loader_factory_, profile_, account_id, initial_signin,
IsPrimaryGaiaAccount(account_info.gaia));
return fetcher;
}
void ArcAuthService::TriggerAccountsPushToArc(bool filter_primary_account) {
if (!ash::IsAccountManagerAvailable(profile_)) {
return;
}
VLOG(1) << "Pushing accounts to ARC "
<< (filter_primary_account ? "without primary account"
: "with primary account");
VLOG(1) << "Using AccountAppsAvailability to get available accounts";
account_apps_availability_->GetAccountsAvailableInArc(
base::BindOnce(&ArcAuthService::CompleteAccountsPushToArc,
weak_ptr_factory_.GetWeakPtr(), filter_primary_account));
}
void ArcAuthService::CompleteAccountsPushToArc(
bool filter_primary_account,
const base::flat_set<account_manager::Account>& accounts) {
std::vector<mojom::ArcAccountInfoPtr> arc_accounts =
std::vector<mojom::ArcAccountInfoPtr>();
for (const auto& account : accounts) {
DCHECK(account.key.account_type() == account_manager::AccountType::kGaia);
if (filter_primary_account &&
IsPrimaryGaiaAccount(GaiaId(account.key.id()))) {
continue;
}
arc_accounts.emplace_back(mojom::ArcAccountInfo::New(
account.raw_email, account.key.id()));
}
auto* instance =
ARC_GET_INSTANCE_FOR_METHOD(arc_bridge_service_->auth(), SetAccounts);
if (!instance) {
VLOG(1) << "SetAccounts API is not available in ARC. Fallback to "
"OnAccountAvailableInArc";
for (const auto& account : accounts) {
DCHECK(account.key.account_type() == account_manager::AccountType::kGaia);
if (filter_primary_account &&
IsPrimaryGaiaAccount(GaiaId(account.key.id()))) {
continue;
}
OnAccountAvailableInArc(account);
}
return;
}
instance->SetAccounts(std::move(arc_accounts));
}
void ArcAuthService::DispatchAccountsInArc(
GetGoogleAccountsInArcCallback callback) {
auto* instance = ARC_GET_INSTANCE_FOR_METHOD(arc_bridge_service_->auth(),
GetGoogleAccounts);
if (!instance) {
std::move(callback).Run(std::vector<mojom::ArcAccountInfoPtr>());
return;
}
instance->GetGoogleAccounts(std::move(callback));
}
void ArcAuthService::OnMainAccountResolutionStatus(
mojom::MainAccountResolutionStatus status) {
UpdateMainAccountResolutionStatus(profile_, status);
}
void ArcAuthService::EnsureFactoryBuilt() {
ArcAuthServiceFactory::GetInstance();
}
}