blob: dd0b05173546b093bc40cc2b2af4f847aa2178c4 [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 "chrome/browser/policy/chrome_browser_cloud_management_controller_desktop.h"
#include "base/command_line.h"
#include "base/path_service.h"
#include "build/branding_buildflags.h"
#include "build/build_config.h"
#include "chrome/browser/browser_process.h"
#include "chrome/browser/device_identity/device_identity_provider.h"
#include "chrome/browser/device_identity/device_oauth2_token_service.h"
#include "chrome/browser/device_identity/device_oauth2_token_service_factory.h"
#include "chrome/browser/enterprise/remote_commands/cbcm_remote_commands_factory.h"
#include "chrome/browser/lifetime/application_lifetime.h"
#include "chrome/browser/net/system_network_context_manager.h"
#include "chrome/browser/policy/chrome_browser_cloud_management_register_watcher.h"
#include "chrome/browser/policy/chrome_browser_policy_connector.h"
#include "chrome/browser/policy/cloud/cloud_policy_invalidator.h"
#include "chrome/browser/policy/cloud/remote_commands_invalidator_impl.h"
#include "chrome/browser/policy/device_account_initializer.h"
#include "chrome/common/chrome_features.h"
#include "chrome/common/chrome_paths.h"
#include "components/gcm_driver/instance_id/instance_id_driver.h"
#include "components/invalidation/impl/fcm_invalidation_service.h"
#include "components/invalidation/impl/fcm_network_handler.h"
#include "components/policy/core/common/cloud/machine_level_user_cloud_policy_manager.h"
#include "components/policy/core/common/features.h"
#include "content/public/browser/network_service_instance.h"
#include "google_apis/gaia/gaia_constants.h"
#include "services/network/public/cpp/shared_url_loader_factory.h"
#if defined(OS_WIN) && BUILDFLAG(GOOGLE_CHROME_BRANDING)
#include "base/base_paths_win.h"
#include "chrome/install_static/install_modes.h"
#else
#include "chrome/common/chrome_switches.h"
#endif // defined(OS_WIN) && BUILDFLAG(GOOGLE_CHROME_BRANDING)
#if defined(OS_MAC)
#include "chrome/browser/app_controller_mac.h"
#include "chrome/browser/policy/browser_dm_token_storage_mac.h"
#endif // defined(OS_MAC)
#if defined(OS_LINUX) || defined(OS_CHROMEOS)
#include "chrome/browser/policy/browser_dm_token_storage_linux.h"
#endif // defined(OS_LINUX) || defined(OS_CHROMEOS)
#if defined(OS_WIN)
#include "chrome/browser/policy/browser_dm_token_storage_win.h"
#include "chrome/install_static/install_util.h"
#endif // defined(OS_WIN)
namespace policy {
namespace {
#if defined(OS_WIN) && BUILDFLAG(GOOGLE_CHROME_BRANDING)
constexpr base::FilePath::StringPieceType kCachedPolicyDirname =
FILE_PATH_LITERAL("Policies");
constexpr base::FilePath::StringPieceType kCachedPolicyFilename =
FILE_PATH_LITERAL("PolicyFetchResponse");
#endif
} // namespace
// A helper class to make the appropriate calls into the device account
// initializer and manage the ChromeBrowserCloudManagementRegistrar callback's
// lifetime.
class MachineLevelDeviceAccountInitializerHelper
: public DeviceAccountInitializer::Delegate {
public:
using Callback = base::OnceCallback<void(bool)>;
// |policy_client| should be registered and outlive this object.
MachineLevelDeviceAccountInitializerHelper(
policy::CloudPolicyClient* policy_client,
Callback callback,
scoped_refptr<network::SharedURLLoaderFactory> url_loader_factory)
: policy_client_(std::move(policy_client)),
callback_(std::move(callback)),
url_loader_factory_(url_loader_factory) {
DCHECK(base::FeatureList::IsEnabled(
policy::features::kCBCMPolicyInvalidations));
DCHECK(url_loader_factory_);
device_account_initializer_ =
std::make_unique<DeviceAccountInitializer>(policy_client_, this);
device_account_initializer_->FetchToken();
}
MachineLevelDeviceAccountInitializerHelper& operator=(
MachineLevelDeviceAccountInitializerHelper&) = delete;
MachineLevelDeviceAccountInitializerHelper(
MachineLevelDeviceAccountInitializerHelper&) = delete;
MachineLevelDeviceAccountInitializerHelper(
MachineLevelDeviceAccountInitializerHelper&&) = delete;
~MachineLevelDeviceAccountInitializerHelper() override = default;
// DeviceAccountInitializer::Delegate:
void OnDeviceAccountTokenFetched(bool empty_token) override {
DCHECK(base::FeatureList::IsEnabled(
policy::features::kCBCMPolicyInvalidations))
<< "DeviceAccountInitializer is active but CBCM service accounts "
"are not enabled.";
if (empty_token) {
// Not being able to obtain a token isn't a showstopper for machine
// level policies: the browser will fallback to fetching policies on a
// regular schedule and won't support remote commands. Getting a refresh
// token will be reattempted on the next successful policy fetch.
std::move(callback_).Run(false);
return;
}
device_account_initializer_->StoreToken();
}
void OnDeviceAccountTokenStored() override {
DCHECK(base::FeatureList::IsEnabled(
policy::features::kCBCMPolicyInvalidations))
<< "DeviceAccountInitializer is active but CBCM service accounts "
"are not enabled.";
std::move(callback_).Run(true);
}
void OnDeviceAccountTokenError(EnrollmentStatus status) override {
DCHECK(base::FeatureList::IsEnabled(
policy::features::kCBCMPolicyInvalidations))
<< "DeviceAccountInitializer is active but CBCM service accounts "
"are not enabled.";
std::move(callback_).Run(false);
}
void OnDeviceAccountClientError(DeviceManagementStatus status) override {
DCHECK(base::FeatureList::IsEnabled(
policy::features::kCBCMPolicyInvalidations))
<< "DeviceAccountInitializer is active but CBCM service accounts "
"are not enabled.";
std::move(callback_).Run(false);
}
enterprise_management::DeviceServiceApiAccessRequest::DeviceType
GetRobotAuthCodeDeviceType() override {
return enterprise_management::DeviceServiceApiAccessRequest::CHROME_BROWSER;
}
std::set<std::string> GetRobotOAuthScopes() override {
return {
GaiaConstants::kOAuthWrapBridgeUserInfoScope,
GaiaConstants::kFCMOAuthScope,
};
}
scoped_refptr<network::SharedURLLoaderFactory> GetURLLoaderFactory()
override {
return url_loader_factory_;
}
policy::CloudPolicyClient* policy_client_;
std::unique_ptr<DeviceAccountInitializer> device_account_initializer_;
Callback callback_;
scoped_refptr<network::SharedURLLoaderFactory> url_loader_factory_;
};
ChromeBrowserCloudManagementControllerDesktop::
ChromeBrowserCloudManagementControllerDesktop() = default;
ChromeBrowserCloudManagementControllerDesktop::
~ChromeBrowserCloudManagementControllerDesktop() = default;
void ChromeBrowserCloudManagementControllerDesktop::
SetDMTokenStorageDelegate() {
std::unique_ptr<BrowserDMTokenStorage::Delegate> storage_delegate;
#if defined(OS_MAC)
storage_delegate = std::make_unique<BrowserDMTokenStorageMac>();
#elif defined(OS_LINUX) || defined(OS_CHROMEOS)
storage_delegate = std::make_unique<BrowserDMTokenStorageLinux>();
#elif defined(OS_WIN)
storage_delegate = std::make_unique<BrowserDMTokenStorageWin>();
#else
NOT_REACHED();
#endif
BrowserDMTokenStorage::SetDelegate(std::move(storage_delegate));
}
bool ChromeBrowserCloudManagementControllerDesktop::IsEnabled() {
#if BUILDFLAG(GOOGLE_CHROME_BRANDING)
return true;
#else
return base::CommandLine::ForCurrentProcess()->HasSwitch(
switches::kEnableChromeBrowserCloudManagement);
#endif
}
int ChromeBrowserCloudManagementControllerDesktop::GetUserDataDirKey() {
return chrome::DIR_USER_DATA;
}
base::FilePath
ChromeBrowserCloudManagementControllerDesktop::GetExternalPolicyPath() {
base::FilePath external_policy_path;
#if defined(OS_WIN) && BUILDFLAG(GOOGLE_CHROME_BRANDING)
base::PathService::Get(base::DIR_PROGRAM_FILESX86, &external_policy_path);
external_policy_path =
external_policy_path.Append(install_static::kCompanyPathName)
.Append(kCachedPolicyDirname)
.AppendASCII(
policy::dm_protocol::kChromeMachineLevelUserCloudPolicyTypeBase64)
.Append(kCachedPolicyFilename);
#endif
return external_policy_path;
}
ChromeBrowserCloudManagementController::Delegate::NetworkConnectionTrackerGetter
ChromeBrowserCloudManagementControllerDesktop::
CreateNetworkConnectionTrackerGetter() {
return base::BindRepeating(&content::GetNetworkConnectionTracker);
}
void ChromeBrowserCloudManagementControllerDesktop::InitializeOAuthTokenFactory(
scoped_refptr<network::SharedURLLoaderFactory> url_loader_factory,
PrefService* local_state) {
DeviceOAuth2TokenServiceFactory::Initialize(url_loader_factory, local_state);
}
void ChromeBrowserCloudManagementControllerDesktop::StartWatchingRegistration(
ChromeBrowserCloudManagementController* controller) {
cloud_management_register_watcher_ =
std::make_unique<ChromeBrowserCloudManagementRegisterWatcher>(controller);
}
bool ChromeBrowserCloudManagementControllerDesktop::
WaitUntilPolicyEnrollmentFinished() {
if (cloud_management_register_watcher_) {
switch (cloud_management_register_watcher_
->WaitUntilCloudPolicyEnrollmentFinished()) {
case ChromeBrowserCloudManagementController::RegisterResult::
kNoEnrollmentNeeded:
case ChromeBrowserCloudManagementController::RegisterResult::
kEnrollmentSuccessBeforeDialogDisplayed:
case ChromeBrowserCloudManagementController::RegisterResult::
kEnrollmentFailedSilentlyBeforeDialogDisplayed:
return true;
case ChromeBrowserCloudManagementController::RegisterResult::
kEnrollmentSuccess:
case ChromeBrowserCloudManagementController::RegisterResult::
kEnrollmentFailedSilently:
#if defined(OS_MAC)
app_controller_mac::EnterpriseStartupDialogClosed();
#endif
return true;
case ChromeBrowserCloudManagementController::RegisterResult::
kRestartDueToFailure:
chrome::AttemptRestart();
return false;
case ChromeBrowserCloudManagementController::RegisterResult::
kQuitDueToFailure:
chrome::AttemptExit();
return false;
}
}
return true;
}
bool ChromeBrowserCloudManagementControllerDesktop::
IsEnterpriseStartupDialogShowing() {
return cloud_management_register_watcher_ &&
cloud_management_register_watcher_->IsDialogShowing();
}
void ChromeBrowserCloudManagementControllerDesktop::OnServiceAccountSet(
CloudPolicyClient* client,
const std::string& account_email) {
if (!base::FeatureList::IsEnabled(
policy::features::kCBCMPolicyInvalidations)) {
return;
}
// No need to get a refresh token if there is one present already.
if (!DeviceOAuth2TokenServiceFactory::Get()->RefreshTokenIsAvailable()) {
// If this feature is enabled, we need to ensure the device service
// account is initialized and fetch auth codes to exchange for a refresh
// token. Creating this object starts that process and the callback will
// be called from it whether it succeeds or not.
DeviceOAuth2TokenServiceFactory::Get()->SetServiceAccountEmail(
account_email);
account_initializer_helper_ = std::make_unique<
MachineLevelDeviceAccountInitializerHelper>(
std::move(client),
base::BindOnce(
&ChromeBrowserCloudManagementControllerDesktop::AccountInitCallback,
base::Unretained(this), account_email),
gaia_url_loader_factory_
? gaia_url_loader_factory_
: g_browser_process->system_network_context_manager()
->GetSharedURLLoaderFactory());
} else if (!policy_invalidator_) {
// There's already a refresh token available but no |policy_invalidator_|
// which means this is browser startup and the refresh token was retrieved
// from local storage. It's OK to start invalidations now.
StartInvalidations();
}
}
void ChromeBrowserCloudManagementControllerDesktop::ShutDown() {
if (policy_invalidator_)
policy_invalidator_->Shutdown();
}
MachineLevelUserCloudPolicyManager*
ChromeBrowserCloudManagementControllerDesktop::
GetMachineLevelUserCloudPolicyManager() {
return g_browser_process->browser_policy_connector()
->machine_level_user_cloud_policy_manager();
}
DeviceManagementService*
ChromeBrowserCloudManagementControllerDesktop::GetDeviceManagementService() {
return g_browser_process->browser_policy_connector()
->device_management_service();
}
scoped_refptr<network::SharedURLLoaderFactory>
ChromeBrowserCloudManagementControllerDesktop::GetSharedURLLoaderFactory() {
return g_browser_process->system_network_context_manager()
->GetSharedURLLoaderFactory();
}
std::unique_ptr<enterprise_reporting::ReportScheduler>
ChromeBrowserCloudManagementControllerDesktop::CreateReportScheduler(
CloudPolicyClient* client) {
auto generator = std::make_unique<enterprise_reporting::ReportGenerator>(
&reporting_delegate_factory_);
return std::make_unique<enterprise_reporting::ReportScheduler>(
client, std::move(generator), &reporting_delegate_factory_);
}
void ChromeBrowserCloudManagementControllerDesktop::SetGaiaURLLoaderFactory(
scoped_refptr<network::SharedURLLoaderFactory> url_loader_factory) {
gaia_url_loader_factory_ = url_loader_factory;
}
void ChromeBrowserCloudManagementControllerDesktop::StartInvalidations() {
DCHECK(
base::FeatureList::IsEnabled(policy::features::kCBCMPolicyInvalidations));
identity_provider_ = std::make_unique<DeviceIdentityProvider>(
DeviceOAuth2TokenServiceFactory::Get());
device_instance_id_driver_ = std::make_unique<instance_id::InstanceIDDriver>(
g_browser_process->gcm_driver());
invalidation_service_ =
std::make_unique<invalidation::FCMInvalidationService>(
identity_provider_.get(),
base::BindRepeating(&syncer::FCMNetworkHandler::Create,
g_browser_process->gcm_driver(),
device_instance_id_driver_.get()),
base::BindRepeating(
&syncer::PerUserTopicSubscriptionManager::Create,
identity_provider_.get(), g_browser_process->local_state(),
base::RetainedRef(
g_browser_process->shared_url_loader_factory())),
device_instance_id_driver_.get(), g_browser_process->local_state(),
policy::kPolicyFCMInvalidationSenderID);
invalidation_service_->Init();
policy_invalidator_ = std::make_unique<CloudPolicyInvalidator>(
PolicyInvalidationScope::kCBCM,
g_browser_process->browser_policy_connector()
->machine_level_user_cloud_policy_manager()
->core(),
base::ThreadTaskRunnerHandle::Get(), base::DefaultClock::GetInstance(),
0 /* highest_handled_invalidation_version */);
policy_invalidator_->Initialize(invalidation_service_.get());
if (base::FeatureList::IsEnabled(policy::features::kCBCMRemoteCommands)) {
g_browser_process->browser_policy_connector()
->machine_level_user_cloud_policy_manager()
->core()
->StartRemoteCommandsService(
std::make_unique<enterprise_commands::CBCMRemoteCommandsFactory>(),
PolicyInvalidationScope::kCBCM);
commands_invalidator_ = std::make_unique<RemoteCommandsInvalidatorImpl>(
g_browser_process->browser_policy_connector()
->machine_level_user_cloud_policy_manager()
->core(),
base::DefaultClock::GetInstance(), PolicyInvalidationScope::kCBCM);
commands_invalidator_->Initialize(invalidation_service_.get());
commands_invalidator_->Start();
}
}
void ChromeBrowserCloudManagementControllerDesktop::AccountInitCallback(
const std::string& account_email,
bool success) {
account_initializer_helper_.reset();
if (success)
StartInvalidations();
}
} // namespace policy