chromium/chrome/browser/policy/networking/policy_cert_service_factory.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/networking/policy_cert_service_factory.h"

#include "base/containers/contains.h"
#include "base/no_destructor.h"
#include "build/chromeos_buildflags.h"
#include "chrome/browser/browser_process.h"
#include "chrome/browser/browser_process_platform_part.h"
#include "chrome/browser/policy/networking/policy_cert_service.h"
#include "chrome/browser/policy/networking/user_network_configuration_updater.h"
#include "chrome/browser/policy/networking/user_network_configuration_updater_factory.h"
#include "chrome/browser/profiles/profile.h"
#include "chrome/common/pref_names.h"
#include "components/prefs/scoped_user_pref_update.h"

#if BUILDFLAG(IS_CHROMEOS_ASH)
#include "chrome/browser/ash/policy/core/browser_policy_connector_ash.h"
#include "chrome/browser/ash/profiles/profile_helper.h"
#include "chrome/browser/policy/networking/device_network_configuration_updater_ash.h"
#include "chrome/browser/profiles/profile_manager.h"
#include "components/user_manager/user_manager.h"
#endif  // BUILDFLAG(IS_CHROMEOS_ASH)

#if BUILDFLAG(IS_CHROMEOS_LACROS)
#include "chrome/browser/profiles/incognito_helpers.h"
#endif

namespace policy {
namespace {

#if BUILDFLAG(IS_CHROMEOS_ASH)
// Returns the PolicyCertificateProvider that should be used for |profile|.
// May return nullptr, which should be treated as no policy-provided
// certificates set.
ash::PolicyCertificateProvider* GetPolicyCertificateProvider(Profile* profile) {
  if (ash::ProfileHelper::Get()->IsSigninProfile(profile)) {
    return g_browser_process->platform_part()
        ->browser_policy_connector_ash()
        ->GetDeviceNetworkConfigurationUpdater();
  }

  // The lock screen profile has access to the policy provided CA certs from the
  // primary profile.
  if (ash::ProfileHelper::Get()->IsLockScreenProfile(profile)) {
    return UserNetworkConfigurationUpdaterFactory::GetForBrowserContext(
        ProfileManager::GetPrimaryUserProfile());
  }

  return UserNetworkConfigurationUpdaterFactory::GetForBrowserContext(profile);
}

std::unique_ptr<KeyedService> BuildServiceInstanceAsh(
    content::BrowserContext* context) {
  Profile* profile = Profile::FromBrowserContext(context);

  ash::PolicyCertificateProvider* policy_certificate_provider =
      GetPolicyCertificateProvider(profile);
  if (!policy_certificate_provider)
    return nullptr;

  if (ash::ProfileHelper::Get()->IsSigninProfile(profile)) {
    return std::make_unique<PolicyCertService>(
        profile, policy_certificate_provider,
        /*may_use_profile_wide_trust_anchors=*/false);
  }

  if (ash::ProfileHelper::Get()->IsLockScreenProfile(profile)) {
    return std::make_unique<PolicyCertService>(
        profile, policy_certificate_provider,
        /*may_use_profile_wide_trust_anchors=*/true);
  }

  // Don't allow policy-provided certificates for "special" Profiles except the
  // one listed above.
  user_manager::UserManager* user_manager = user_manager::UserManager::Get();
  const user_manager::User* user = ash::ProfileHelper::Get()->GetUserByProfile(
      profile->GetOriginalProfile());
  if (!user)
    return nullptr;

  // Only allow trusted policy-provided certificates for non-guest primary
  // users. Guest users don't have user policy, but set
  // `may_use_profile_wide_trust_anchors`=false for them out of caution against
  // future changes.
  bool may_use_profile_wide_trust_anchors =
      user == user_manager->GetPrimaryUser() &&
      user->GetType() != user_manager::UserType::kGuest;

  return std::make_unique<PolicyCertService>(
      profile, policy_certificate_provider, may_use_profile_wide_trust_anchors);
}

#endif  // BUILDFLAG(IS_CHROMEOS_ASH)

#if BUILDFLAG(IS_CHROMEOS_LACROS)
std::unique_ptr<KeyedService> BuildServiceInstanceLacros(
    content::BrowserContext* context) {
  Profile* profile = Profile::FromBrowserContext(context);

  ash::PolicyCertificateProvider* policy_certificate_provider =
      UserNetworkConfigurationUpdaterFactory::GetForBrowserContext(profile);
  if (!policy_certificate_provider)
    return nullptr;

  Profile* original_profile = Profile::FromBrowserContext(
      chrome::GetBrowserContextRedirectedInIncognito(profile));
  // Only allow trusted policy-provided certificates for non-guest primary
  // users. Guest users don't have user policy, but set
  // `may_use_profile_wide_trust_anchors`=false for them out of caution against
  // future changes.
  bool may_use_profile_wide_trust_anchors =
      original_profile->IsMainProfile() && !original_profile->IsGuestSession();

  return std::make_unique<PolicyCertService>(
      profile, policy_certificate_provider, may_use_profile_wide_trust_anchors);
}
#endif  // BUILDFLAG(IS_CHROMEOS_LACROS)

}  // namespace

// static
PolicyCertService* PolicyCertServiceFactory::GetForProfile(Profile* profile) {
  return static_cast<PolicyCertService*>(
      GetInstance()->GetServiceForBrowserContext(profile, false));
}

// static
bool PolicyCertServiceFactory::CreateAndStartObservingForProfile(
    Profile* profile) {
  // Note that this can be called multiple times if the network process crashes.
  return GetInstance()->GetServiceForBrowserContext(profile, true) != nullptr;
}

// static
PolicyCertServiceFactory* PolicyCertServiceFactory::GetInstance() {
  static base::NoDestructor<PolicyCertServiceFactory> instance;
  return instance.get();
}

PolicyCertServiceFactory::PolicyCertServiceFactory()
    : ProfileKeyedServiceFactory(
          "PolicyCertService",
          ProfileSelections::Builder()
              .WithRegular(ProfileSelection::kOwnInstance)
              // TODO(crbug.com/40257657): Check if this service is needed in
              // Guest mode.
              .WithGuest(ProfileSelection::kOwnInstance)
              // TODO(crbug.com/41488885): Check if this service is needed for
              // Ash Internals.
              .WithAshInternals(ProfileSelection::kOwnInstance)
              .Build()) {
  DependsOn(UserNetworkConfigurationUpdaterFactory::GetInstance());
}

PolicyCertServiceFactory::~PolicyCertServiceFactory() = default;

std::unique_ptr<KeyedService>
PolicyCertServiceFactory::BuildServiceInstanceForBrowserContext(
    content::BrowserContext* context) const {
#if BUILDFLAG(IS_CHROMEOS_ASH)
  return BuildServiceInstanceAsh(context);
#endif  // BUILDFLAG(IS_CHROMEOS_ASH)

#if BUILDFLAG(IS_CHROMEOS_LACROS)
  return BuildServiceInstanceLacros(context);
#endif  // BUILDFLAG(IS_CHROMEOS_LACROS)
}

bool PolicyCertServiceFactory::ServiceIsNULLWhileTesting() const {
  return true;
}

}  // namespace policy