| // 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. |
| |
| #include "chrome/browser/policy/chrome_browser_cloud_management_controller_desktop.h" |
| |
| #include <stdint.h> |
| |
| #include <set> |
| #include <string> |
| #include <utility> |
| |
| #include "base/check_is_test.h" |
| #include "base/command_line.h" |
| #include "base/path_service.h" |
| #include "base/task/single_thread_task_runner.h" |
| #include "base/time/default_clock.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_factory.h" |
| #include "chrome/browser/enterprise/connectors/device_trust/key_management/browser/key_loader.h" |
| #include "chrome/browser/enterprise/remote_commands/cbcm_remote_commands_factory.h" |
| #include "chrome/browser/enterprise/reporting/reporting_delegate_factory_desktop.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/client_data_delegate_desktop.h" |
| #include "chrome/browser/policy/cloud/cloud_policy_invalidator.h" |
| #include "chrome/browser/policy/cloud/fm_registration_token_uploader.h" |
| #include "chrome/browser/policy/policy_util.h" |
| #include "chrome/common/chrome_features.h" |
| #include "chrome/common/chrome_paths.h" |
| #include "components/gcm_driver/gcm_driver.h" |
| #include "components/gcm_driver/instance_id/instance_id_driver.h" |
| #include "components/invalidation/invalidation_listener.h" |
| #include "components/invalidation/legacy_topics_cleaner.h" |
| #include "components/policy/core/common/cloud/machine_level_user_cloud_policy_manager.h" |
| #include "components/policy/core/common/remote_commands/remote_commands_constants.h" |
| #include "components/policy/core/common/remote_commands/remote_commands_invalidator.h" |
| #include "content/public/browser/browser_task_traits.h" |
| #include "content/public/browser/browser_thread.h" |
| #include "content/public/browser/network_service_instance.h" |
| #include "services/network/public/cpp/shared_url_loader_factory.h" |
| |
| #if BUILDFLAG(IS_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 // BUILDFLAG(IS_WIN) && BUILDFLAG(GOOGLE_CHROME_BRANDING) |
| |
| #if BUILDFLAG(IS_MAC) |
| #include "chrome/browser/app_controller_mac.h" |
| #include "chrome/browser/policy/browser_dm_token_storage_mac.h" |
| #endif // BUILDFLAG(IS_MAC) |
| |
| #if BUILDFLAG(IS_LINUX) || BUILDFLAG(IS_CHROMEOS) |
| #include "chrome/browser/policy/browser_dm_token_storage_linux.h" |
| #endif // BUILDFLAG(IS_LINUX) || BUILDFLAG(IS_CHROMEOS) |
| |
| #if BUILDFLAG(IS_WIN) |
| #include "chrome/browser/policy/browser_dm_token_storage_win.h" |
| #include "chrome/install_static/install_util.h" |
| #endif // BUILDFLAG(IS_WIN) |
| |
| #if BUILDFLAG(IS_WIN) || BUILDFLAG(IS_LINUX) || BUILDFLAG(IS_MAC) |
| #include "chrome/browser/enterprise/client_certificates/browser_context_delegate.h" |
| #include "chrome/browser/enterprise/client_certificates/cert_utils.h" |
| #include "chrome/browser/enterprise/connectors/device_trust/key_management/browser/device_trust_key_manager_impl.h" |
| #include "chrome/browser/enterprise/connectors/device_trust/key_management/browser/key_rotation_launcher.h" |
| #include "components/enterprise/client_certificates/core/browser_cloud_management_delegate.h" |
| #include "components/enterprise/client_certificates/core/certificate_provisioning_service.h" |
| #include "components/enterprise/client_certificates/core/dm_server_client.h" |
| #include "components/enterprise/client_certificates/core/key_upload_client.h" |
| #endif // BUILDFLAG(IS_WIN) || BUILDFLAG(IS_LINUX) || BUILDFLAG(IS_MAC) |
| |
| namespace policy { |
| |
| namespace { |
| |
| #if BUILDFLAG(IS_WIN) && BUILDFLAG(GOOGLE_CHROME_BRANDING) |
| constexpr base::FilePath::StringViewType kCachedPolicyDirname = |
| FILE_PATH_LITERAL("Policies"); |
| #endif |
| |
| constexpr char kInvalidationListenerLogPrefix[] = |
| "ChromeBrowserCloudManagementControllerDesktop"; |
| |
| // Returns a set of all project numbers that will be used by user. |
| std::set<int64_t> GetAllInvalidationProjectNumbers() { |
| return { |
| policy::kPolicyInvalidationProjectNumber, |
| policy::kRemoteCommandsInvalidationsProjectNumber, |
| }; |
| } |
| |
| } // namespace |
| |
| ChromeBrowserCloudManagementControllerDesktop:: |
| ChromeBrowserCloudManagementControllerDesktop() |
| : invalidations_initializer_(this) {} |
| ChromeBrowserCloudManagementControllerDesktop:: |
| ~ChromeBrowserCloudManagementControllerDesktop() = default; |
| |
| void ChromeBrowserCloudManagementControllerDesktop:: |
| SetDMTokenStorageDelegate() { |
| std::unique_ptr<BrowserDMTokenStorage::Delegate> storage_delegate; |
| |
| #if BUILDFLAG(IS_MAC) |
| storage_delegate = std::make_unique<BrowserDMTokenStorageMac>(); |
| #elif BUILDFLAG(IS_LINUX) || BUILDFLAG(IS_CHROMEOS) |
| storage_delegate = std::make_unique<BrowserDMTokenStorageLinux>(); |
| #elif BUILDFLAG(IS_WIN) |
| storage_delegate = std::make_unique<BrowserDMTokenStorageWin>(); |
| #else |
| NOTREACHED(); |
| #endif |
| |
| BrowserDMTokenStorage::SetDelegate(std::move(storage_delegate)); |
| } |
| |
| int ChromeBrowserCloudManagementControllerDesktop::GetUserDataDirKey() { |
| return chrome::DIR_USER_DATA; |
| } |
| |
| base::FilePath |
| ChromeBrowserCloudManagementControllerDesktop::GetExternalPolicyDir() { |
| base::FilePath external_policy_path; |
| #if BUILDFLAG(IS_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); |
| #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 BUILDFLAG(IS_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) { |
| invalidations_initializer_.OnServiceAccountSet(client, account_email); |
| } |
| |
| void ChromeBrowserCloudManagementControllerDesktop::ShutDown() { |
| policy_invalidator_.reset(); |
| commands_invalidator_.reset(); |
| fm_registration_token_uploaders_.clear(); |
| invalidation_listener_per_project_.clear(); |
| device_instance_id_driver_.reset(); |
| legacy_topics_cleaner_.reset(); |
| |
| // In some tests, `DCHECK_CURRENTLY_ON(content::BrowserThread::UI)` fails. |
| // Such tests have not initialized device_oauth2_token_service anyway, so |
| // skip calling Shutdown() for the service. |
| if (!content::BrowserThread::CurrentlyOn(content::BrowserThread::UI)) { |
| CHECK_IS_TEST(); |
| return; |
| } |
| DeviceOAuth2TokenServiceFactory::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(); |
| } |
| |
| scoped_refptr<base::SingleThreadTaskRunner> |
| ChromeBrowserCloudManagementControllerDesktop::GetBestEffortTaskRunner() { |
| // ChromeBrowserCloudManagementControllerDesktop is bound to BrowserThread::UI |
| // and so must its best-effort task runner. |
| DCHECK_CURRENTLY_ON(content::BrowserThread::UI); |
| return content::GetUIThreadTaskRunner({base::TaskPriority::BEST_EFFORT}); |
| } |
| |
| std::unique_ptr<enterprise_reporting::ReportingDelegateFactory> |
| ChromeBrowserCloudManagementControllerDesktop::GetReportingDelegateFactory() { |
| return std::make_unique< |
| enterprise_reporting::ReportingDelegateFactoryDesktop>(); |
| } |
| |
| void ChromeBrowserCloudManagementControllerDesktop::SetGaiaURLLoaderFactory( |
| scoped_refptr<network::SharedURLLoaderFactory> url_loader_factory) { |
| gaia_url_loader_factory_ = url_loader_factory; |
| } |
| |
| bool ChromeBrowserCloudManagementControllerDesktop:: |
| ReadyToCreatePolicyManager() { |
| return true; |
| } |
| |
| bool ChromeBrowserCloudManagementControllerDesktop::ReadyToInit() { |
| return true; |
| } |
| |
| std::unique_ptr<ClientDataDelegate> |
| ChromeBrowserCloudManagementControllerDesktop::CreateClientDataDelegate() { |
| return std::make_unique<ClientDataDelegateDesktop>(); |
| } |
| |
| std::unique_ptr<enterprise_connectors::DeviceTrustKeyManager> |
| ChromeBrowserCloudManagementControllerDesktop::CreateDeviceTrustKeyManager() { |
| #if BUILDFLAG(IS_WIN) || BUILDFLAG(IS_LINUX) || BUILDFLAG(IS_MAC) |
| auto* browser_dm_token_storage = BrowserDMTokenStorage::Get(); |
| auto* device_management_service = GetDeviceManagementService(); |
| auto shared_url_loader_factory = GetSharedURLLoaderFactory(); |
| |
| auto key_rotation_launcher = |
| enterprise_connectors::KeyRotationLauncher::Create( |
| browser_dm_token_storage, device_management_service, |
| shared_url_loader_factory); |
| auto key_loader = enterprise_connectors::KeyLoader::Create( |
| device_management_service, shared_url_loader_factory); |
| |
| return std::make_unique<enterprise_connectors::DeviceTrustKeyManagerImpl>( |
| std::move(key_rotation_launcher), std::move(key_loader)); |
| #else |
| return nullptr; |
| #endif // BUILDFLAG(IS_WIN) || BUILDFLAG(IS_LINUX) || BUILDFLAG(IS_MAC) |
| } |
| |
| std::unique_ptr<client_certificates::CertificateProvisioningService> |
| ChromeBrowserCloudManagementControllerDesktop:: |
| CreateCertificateProvisioningService() { |
| #if BUILDFLAG(IS_WIN) || BUILDFLAG(IS_LINUX) || BUILDFLAG(IS_MAC) |
| if (!certificate_store_) { |
| certificate_store_ = |
| std::make_unique<client_certificates::PrefsCertificateStore>( |
| g_browser_process->local_state(), |
| client_certificates::CreatePrivateKeyFactory()); |
| } |
| |
| auto* device_management_service = GetDeviceManagementService(); |
| auto url_loader_factory = GetSharedURLLoaderFactory(); |
| if (!url_loader_factory || !device_management_service || |
| !certificate_store_) { |
| return nullptr; |
| } |
| |
| return client_certificates::CertificateProvisioningService::Create( |
| g_browser_process->local_state(), certificate_store_.get(), |
| std::make_unique<client_certificates::BrowserContextDelegate>(), |
| client_certificates::KeyUploadClient::Create( |
| std::make_unique< |
| enterprise_attestation::BrowserCloudManagementDelegate>( |
| enterprise_attestation::DMServerClient::Create( |
| device_management_service, std::move(url_loader_factory))))); |
| #else |
| return nullptr; |
| #endif // BUILDFLAG(IS_WIN) || BUILDFLAG(IS_LINUX) || BUILDFLAG(IS_MAC) |
| } |
| |
| void ChromeBrowserCloudManagementControllerDesktop::StartInvalidations() { |
| if (IsInvalidationsServiceStarted()) { |
| NOTREACHED() << "Trying to start an invalidation service when there's " |
| "already one. Please see crbug.com/1186159."; |
| } |
| |
| device_instance_id_driver_ = std::make_unique<instance_id::InstanceIDDriver>( |
| g_browser_process->gcm_driver()); |
| |
| for (const int64_t project_number : GetAllInvalidationProjectNumbers()) { |
| invalidation_listener_per_project_[project_number] = |
| invalidation::InvalidationListener::Create( |
| g_browser_process->gcm_driver(), device_instance_id_driver_.get(), |
| project_number, kInvalidationListenerLogPrefix); |
| } |
| |
| auto* core = g_browser_process->browser_policy_connector() |
| ->machine_level_user_cloud_policy_manager() |
| ->core(); |
| |
| invalidation::InvalidationListener* policy_invalidation_listener = |
| invalidation_listener_per_project_ |
| [policy::kPolicyInvalidationProjectNumber] |
| .get(); |
| policy_invalidator_ = std::make_unique<CloudPolicyInvalidator>( |
| PolicyInvalidationScope::kCBCM, policy_invalidation_listener, core, |
| base::SingleThreadTaskRunner::GetCurrentDefault(), |
| base::DefaultClock::GetInstance()); |
| |
| core->StartRemoteCommandsService( |
| std::make_unique<enterprise_commands::CBCMRemoteCommandsFactory>(), |
| PolicyInvalidationScope::kCBCM); |
| |
| invalidation::InvalidationListener* remote_commands_invalidation_listener = |
| invalidation_listener_per_project_ |
| [policy::kRemoteCommandsInvalidationsProjectNumber] |
| .get(); |
| commands_invalidator_ = std::make_unique<RemoteCommandsInvalidator>( |
| remote_commands_invalidation_listener, core, |
| base::DefaultClock::GetInstance(), PolicyInvalidationScope::kCBCM); |
| |
| for (const auto& [project_number, invalidation_listener] : |
| invalidation_listener_per_project_) { |
| fm_registration_token_uploaders_.emplace_back( |
| std::make_unique<FmRegistrationTokenUploader>( |
| PolicyInvalidationScope::kCBCM, invalidation_listener.get(), core)); |
| } |
| |
| legacy_topics_cleaner_ = std::make_unique<invalidation::LegacyTopicsCleaner>( |
| g_browser_process->shared_url_loader_factory(), |
| std::make_unique<DeviceIdentityProvider>( |
| DeviceOAuth2TokenServiceFactory::Get()), |
| g_browser_process->local_state()); |
| } |
| |
| scoped_refptr<network::SharedURLLoaderFactory> |
| ChromeBrowserCloudManagementControllerDesktop::GetURLLoaderFactory() { |
| return gaia_url_loader_factory_; |
| } |
| |
| bool ChromeBrowserCloudManagementControllerDesktop:: |
| IsInvalidationsServiceStarted() const { |
| // This object is created when StartInvalidations is called, and stays alive |
| // thereafter. |
| return !invalidation_listener_per_project_.empty(); |
| } |
| |
| } // namespace policy |