chromium/chrome/browser/policy/profile_policy_connector.cc

// Copyright 2013 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/profile_policy_connector.h"

#include <memory>
#include <optional>
#include <utility>

#include "base/check.h"
#include "base/check_op.h"
#include "base/functional/bind.h"
#include "base/logging.h"
#include "base/memory/raw_ptr.h"
#include "base/metrics/histogram_functions.h"
#include "base/ranges/algorithm.h"
#include "base/task/sequenced_task_runner.h"
#include "base/task/single_thread_task_runner.h"
#include "base/time/time.h"
#include "base/timer/timer.h"
#include "base/values.h"
#include "build/build_config.h"
#include "build/chromeos_buildflags.h"
#include "chrome/browser/browser_process.h"
#include "chrome/browser/browser_switcher/browser_switcher_policy_migrator.h"
#include "chrome/browser/enterprise/util/affiliation.h"
#include "chrome/browser/infobars/simple_alert_infobar_creator.h"
#include "chrome/browser/policy/chrome_browser_policy_connector.h"
#include "components/infobars/content/content_infobar_manager.h"
#include "components/infobars/core/infobar.h"
#include "components/infobars/core/infobar_delegate.h"
#include "components/policy/core/browser/browser_policy_connector.h"
#include "components/policy/core/common/cloud/cloud_policy_core.h"
#include "components/policy/core/common/cloud/cloud_policy_manager.h"
#include "components/policy/core/common/cloud/cloud_policy_store.h"
#include "components/policy/core/common/cloud/machine_level_user_cloud_policy_manager.h"
#include "components/policy/core/common/configuration_policy_provider.h"
#include "components/policy/core/common/local_test_policy_provider.h"
#include "components/policy/core/common/policy_bundle.h"
#include "components/policy/core/common/policy_map.h"
#include "components/policy/core/common/policy_namespace.h"
#include "components/policy/core/common/policy_service_impl.h"
#include "components/policy/core/common/policy_types.h"
#include "components/policy/core/common/proxy_policy_provider.h"
#include "components/policy/core/common/schema_registry_tracking_policy_provider.h"
#include "components/policy/policy_constants.h"
#include "components/strings/grit/components_strings.h"
#include "content/public/browser/browser_thread.h"
#include "content/public/browser/web_contents.h"
#include "ui/base/l10n/l10n_util.h"

#if BUILDFLAG(IS_CHROMEOS)
#include "chrome/browser/policy/restricted_mgs_policy_provider.h"
#endif

#if BUILDFLAG(IS_CHROMEOS_ASH)
#include "chrome/browser/ash/policy/core/browser_policy_connector_ash.h"
#include "chrome/browser/ash/policy/core/device_cloud_policy_manager_ash.h"
#include "chrome/browser/ash/policy/core/device_local_account.h"
#include "chrome/browser/ash/policy/core/device_local_account_policy_provider.h"
#include "chrome/browser/ash/policy/login/login_profile_policy_provider.h"
#include "chrome/browser/browser_process_platform_part.h"
#include "components/user_manager/user.h"
#include "components/user_manager/user_manager.h"
#include "components/user_manager/user_type.h"
#endif

#if BUILDFLAG(IS_CHROMEOS_LACROS)
#include "chrome/browser/profiles/profile_manager.h"
#include "components/user_manager/user_manager.h"
#endif

#if BUILDFLAG(IS_ANDROID)
#include "chrome/browser/android/tab_android.h"
#include "chrome/browser/ui/android/tab_model/tab_model.h"
#include "chrome/browser/ui/android/tab_model/tab_model_list.h"
#else
#include "chrome/browser/ui/browser.h"
#include "chrome/browser/ui/browser_finder.h"
#include "chrome/browser/ui/browser_list.h"
#endif

namespace policy {

namespace internal {
#if BUILDFLAG(IS_CHROMEOS_ASH)
// This class allows observing a |device_wide_policy_service| for policy updates
// during which the |source_policy_provider| has already been initialized.
// It is used to know when propagation of primary user policies proxied to the
// device-wide PolicyService has finished.
class ProxiedPoliciesPropagatedWatcher : PolicyService::ProviderUpdateObserver {
 public:
  ProxiedPoliciesPropagatedWatcher(
      PolicyService* device_wide_policy_service,
      ProxyPolicyProvider* proxy_policy_provider,
      ConfigurationPolicyProvider* source_policy_provider,
      base::OnceClosure proxied_policies_propagated_callback)
      : device_wide_policy_service_(device_wide_policy_service),
        proxy_policy_provider_(proxy_policy_provider),
        source_policy_provider_(source_policy_provider),
        proxied_policies_propagated_callback_(
            std::move(proxied_policies_propagated_callback)) {
    device_wide_policy_service->AddProviderUpdateObserver(this);

    timeout_timer_.Start(
        FROM_HERE, base::Seconds(kProxiedPoliciesPropagationTimeoutInSeconds),
        this,
        &ProxiedPoliciesPropagatedWatcher::OnProviderUpdatePropagationTimedOut);
  }

  ProxiedPoliciesPropagatedWatcher(const ProxiedPoliciesPropagatedWatcher&) =
      delete;
  ProxiedPoliciesPropagatedWatcher& operator=(
      const ProxiedPoliciesPropagatedWatcher&) = delete;
  ~ProxiedPoliciesPropagatedWatcher() override {
    device_wide_policy_service_->RemoveProviderUpdateObserver(this);
  }

  // PolicyService::Observer:
  void OnProviderUpdatePropagated(
      ConfigurationPolicyProvider* provider) override {
    if (!proxied_policies_propagated_callback_)
      return;
    if (provider != proxy_policy_provider_)
      return;

    if (!source_policy_provider_->IsInitializationComplete(
            POLICY_DOMAIN_CHROME)) {
      return;
    }

    ReportTimeUma();
    std::move(proxied_policies_propagated_callback_).Run();
  }

  void OnProviderUpdatePropagationTimedOut() {
    if (!proxied_policies_propagated_callback_)
      return;
    LOG(WARNING) << "Waiting for proxied policies to propagate timed out.";
    ReportTimeUma();
    std::move(proxied_policies_propagated_callback_).Run();
  }

 private:
  static constexpr int kProxiedPoliciesPropagationTimeoutInSeconds = 5;

  void ReportTimeUma() const {
    UmaHistogramTimes("Enterprise.TimeToUnthrottlePolicyInit",
                      base::TimeTicks::Now() - construction_time_);
  }

  const raw_ptr<PolicyService> device_wide_policy_service_;
  const raw_ptr<const ProxyPolicyProvider> proxy_policy_provider_;
  const raw_ptr<const ConfigurationPolicyProvider> source_policy_provider_;
  const base::TimeTicks construction_time_ = base::TimeTicks::Now();
  base::OnceClosure proxied_policies_propagated_callback_;
  base::OneShotTimer timeout_timer_;
};
#endif
// Class responsible for showing infobar when test policies are set from
// the chrome://policy/test page
class LocalTestInfoBarVisibilityManager :
#if BUILDFLAG(IS_ANDROID)
    public TabModelObserver
#else
    public BrowserListObserver,
    public TabStripModelObserver
#endif  // BUILDFLAG(IS_ANDROID)
{};
}  // namespace internal

#if BUILDFLAG(IS_CHROMEOS_ASH)
namespace {
// Returns the PolicyService that holds device-wide policies.
PolicyService* GetDeviceWidePolicyService() {
  BrowserPolicyConnectorAsh* browser_policy_connector =
      g_browser_process->platform_part()->browser_policy_connector_ash();
  return browser_policy_connector->GetPolicyService();
}

// Returns the ProxyPolicyProvider which is used to forward primary Profile
// policies into the device-wide PolicyService.
ProxyPolicyProvider* GetProxyPolicyProvider() {
  BrowserPolicyConnectorAsh* browser_policy_connector =
      g_browser_process->platform_part()->browser_policy_connector_ash();
  return browser_policy_connector->GetGlobalUserCloudPolicyProvider();
}
}  // namespace

#endif  // BUILDFLAG(IS_CHROMEOS_ASH)

ProfilePolicyConnector::ProfilePolicyConnector() = default;

ProfilePolicyConnector::~ProfilePolicyConnector() {}

void ProfilePolicyConnector::Init(
    const user_manager::User* user,
    SchemaRegistry* schema_registry,
    ConfigurationPolicyProvider* configuration_policy_provider,
    const CloudPolicyStore* policy_store,
    policy::ChromeBrowserPolicyConnector* connector,
    bool force_immediate_load) {}

void ProfilePolicyConnector::InitForTesting(
    std::unique_ptr<PolicyService> service) {}

void ProfilePolicyConnector::OverrideIsManagedForTesting(bool is_managed) {}

void ProfilePolicyConnector::Shutdown() {}

bool ProfilePolicyConnector::IsManaged() const {}

#if BUILDFLAG(IS_CHROMEOS_LACROS)
bool ProfilePolicyConnector::IsMainProfile() const {
  // If there is only a single profile or this connector object is owned by the
  // main profile, it must be the main profile.
  // TODO(crbug.com/40788404): Remove this once Lacros only uses mirror.
  ProfileManager* profile_manager = g_browser_process->profile_manager();
  if (profile_manager->GetNumberOfProfiles() <= 1)
    return true;

  auto profiles = profile_manager->GetLoadedProfiles();
  const auto main_it = base::ranges::find_if(profiles, &Profile::IsMainProfile);
  if (main_it == profiles.end())
    return false;
  return (*main_it)->GetProfilePolicyConnector() == this;
}
#endif

bool ProfilePolicyConnector::IsProfilePolicy(const char* policy_key) const {}

#if BUILDFLAG(IS_CHROMEOS_ASH)
void ProfilePolicyConnector::TriggerProxiedPoliciesWaitTimeoutForTesting() {
  CHECK(proxied_policies_propagated_watcher_);
  proxied_policies_propagated_watcher_->OnProviderUpdatePropagationTimedOut();
}
#endif  // BUILDFLAG(IS_CHROMEOS_ASH)

base::flat_set<std::string> ProfilePolicyConnector::user_affiliation_ids()
    const {}

void ProfilePolicyConnector::SetUserAffiliationIdsForTesting(
    const base::flat_set<std::string>& user_affiliation_ids) {}

void ProfilePolicyConnector::OnPolicyServiceInitialized(PolicyDomain domain) {}

void ProfilePolicyConnector::DoPostInit() {}

const CloudPolicyStore* ProfilePolicyConnector::GetActualPolicyStore() const {}

const ConfigurationPolicyProvider*
ProfilePolicyConnector::DeterminePolicyProviderForPolicy(
    const char* policy_key) const {}

void ProfilePolicyConnector::AppendPolicyProviderWithSchemaTracking(
    ConfigurationPolicyProvider* policy_provider,
    SchemaRegistry* schema_registry) {}

std::string ProfilePolicyConnector::GetTimeToFirstPolicyLoadMetricSuffix()
    const {}

void ProfilePolicyConnector::UseLocalTestPolicyProvider() {}

void ProfilePolicyConnector::RevertUseLocalTestPolicyProvider() {}

bool ProfilePolicyConnector::IsUsingLocalTestPolicyProvider() const {}

void ProfilePolicyConnector::RecordAffiliationMetrics() {}

#if BUILDFLAG(IS_CHROMEOS_ASH)
std::unique_ptr<PolicyService>
ProfilePolicyConnector::CreatePolicyServiceWithInitializationThrottled(
    const std::vector<raw_ptr<ConfigurationPolicyProvider, VectorExperimental>>&
        policy_providers,
    std::vector<std::unique_ptr<PolicyMigrator>> migrators,
    ConfigurationPolicyProvider* user_policy_delegate) {
  DCHECK(user_policy_delegate);

  auto policy_service = PolicyServiceImpl::CreateWithThrottledInitialization(
      policy_providers, PolicyServiceImpl::ScopeForMetrics::kUser,
      std::move(migrators));

  // base::Unretained is OK for |this| because
  // |proxied_policies_propagated_watcher_| is guaranteed not to call its
  // callback after it has been destroyed. base::Unretained is also OK for
  // |policy_service.get()| because it will be owned by |*this| and is never
  // explicitly destroyed.
  proxied_policies_propagated_watcher_ =
      std::make_unique<internal::ProxiedPoliciesPropagatedWatcher>(
          GetDeviceWidePolicyService(), GetProxyPolicyProvider(),
          user_policy_delegate,
          base::BindOnce(&ProfilePolicyConnector::OnProxiedPoliciesPropagated,
                         base::Unretained(this),
                         base::Unretained(policy_service.get())));
  return std::move(policy_service);
}

void ProfilePolicyConnector::OnProxiedPoliciesPropagated(
    PolicyServiceImpl* policy_service) {
  policy_service->UnthrottleInitialization();
  // Do not delete |proxied_policies_propagated_watcher_| synchronously, as the
  // PolicyService it is observing is expected to be iterating its observer
  // list.
  base::SingleThreadTaskRunner::GetCurrentDefault()->DeleteSoon(
      FROM_HERE, std::move(proxied_policies_propagated_watcher_));
}
#endif

}  // namespace policy