910e62b5创建于 1月15日历史提交
// 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/enterprise/connectors/connectors_service.h"

#include <memory>
#include <string_view>
#include <utility>

#include "base/json/json_reader.h"
#include "base/path_service.h"
#include "build/build_config.h"
#include "chrome/browser/browser_process.h"
#include "chrome/browser/enterprise/connectors/common.h"
#include "chrome/browser/enterprise/connectors/test/deep_scanning_browsertest_base.h"
#include "chrome/browser/enterprise/connectors/test/deep_scanning_test_utils.h"
#include "chrome/browser/policy/chrome_browser_policy_connector.h"
#include "chrome/browser/policy/dm_token_utils.h"
#include "chrome/browser/profiles/reporting_util.h"
#include "chrome/browser/ui/browser.h"
#include "chrome/test/base/testing_profile.h"
#include "components/enterprise/browser/controller/fake_browser_dm_token_storage.h"
#include "components/enterprise/browser/enterprise_switches.h"
#include "components/enterprise/buildflags/buildflags.h"
#include "components/enterprise/connectors/core/connectors_prefs.h"
#include "components/policy/core/common/cloud/machine_level_user_cloud_policy_manager.h"
#include "components/policy/core/common/cloud/mock_cloud_policy_client.h"
#include "components/policy/core/common/cloud/reporting_job_configuration_base.h"
#include "components/policy/core/common/cloud/user_cloud_policy_manager.h"
#include "components/policy/core/common/features.h"
#include "components/policy/core/common/policy_switches.h"
#include "components/safe_browsing/core/common/features.h"
#include "components/safe_browsing/core/common/safe_browsing_prefs.h"
#include "components/version_info/version_info.h"
#include "content/public/test/browser_test.h"
#include "google_apis/gaia/gaia_id.h"

#if BUILDFLAG(IS_CHROMEOS)
#include "chrome/browser/ash/policy/core/user_cloud_policy_manager_ash.h"
#include "components/account_id/account_id.h"
#include "components/user_manager/user_manager.h"
#endif

namespace enterprise_connectors {

namespace {

constexpr char kNormalCloudAnalysisSettingsPref[] = R"([
  {
    "service_provider": "google",
    "enable": [
      {"url_list": ["*"], "tags": ["dlp", "malware"]}
    ]
  }
])";

constexpr char kNormalLocalAnalysisSettingsPref[] = R"([
  {
    "service_provider": "local_user_agent",
    "enable": [
      {"url_list": ["*"], "tags": ["dlp"]}
    ]
  }
])";

constexpr char kNormalReportingSettingsPref[] = R"([
  {
    "service_provider": "google"
  }
])";

#if !BUILDFLAG(IS_CHROMEOS)
constexpr char kAffiliationId2[] = "affiliation-id-2";
constexpr char kFakeEnrollmentToken[] = "fake-enrollment-token";
constexpr char kUsername1[] = "user@domain1.com";
constexpr char kUsername2[] = "admin@domain2.com";
constexpr char kDomain2[] = "domain2.com";
#endif

constexpr char kFakeBrowserDMToken[] = "fake-browser-dm-token";
constexpr char kFakeProfileDMToken[] = "fake-profile-dm-token";
constexpr char kFakeBrowserClientId[] = "fake-browser-client-id";
constexpr char kFakeProfileClientId[] = "fake-profile-client-id";
constexpr char kAffiliationId1[] = "affiliation-id-1";
constexpr char kDomain1[] = "domain1.com";
constexpr char kTestUrl[] = "https://foo.com";

std::string ExpectedOsPlatform() {
#if BUILDFLAG(IS_WIN)
  return "Windows";
#elif BUILDFLAG(IS_MAC)
  return "Mac OS X";
#elif BUILDFLAG(IS_CHROMEOS)
#if BUILDFLAG(GOOGLE_CHROME_BRANDING)
  return "ChromeOS";
#else
  return "ChromiumOS";
#endif
#elif BUILDFLAG(IS_LINUX)
  return "Linux";
#endif
}

// We want a way to check whether or not any metadata was set, but the profile
// metadata will always contain the `is_chrome_os_managed_guest_session` field
// so we check another field (which should always be set if any actual metadata
// was provided).
bool ContainsClientId(const AnalysisSettings& settings) {
  return settings.client_metadata && settings.client_metadata->has_device() &&
         settings.client_metadata->device().has_client_id();
}

}  // namespace

// Profile DM token tests
// These tests validate that ConnectorsService obtains the correct DM token on
// each GetAnalysisSettings/GetReportingSettings call. There are 3 mains cases
// to validate here:
//
// - Affiliated: The profile and browser are managed by the same customer. In
// this case, it is OK to get the profile DM token and apply Connector policies.
// - Unaffiliated: The profile and browser are managed by different customers.
// In this case, no profile settings should be returned.
// - Unmanaged: The profile is managed by a customer while the browser is
// unmanaged. In this case, it is OK to get the profile DM token and apply
// Connector policies.
//
// The exception to the above rules is CrOS. Even when the policies are applied
// at a user scope, only the browser DM token should be returned.

enum class ManagementStatus { kAffiliated, kUnaffiliated, kUnmanaged };

class ConnectorsServiceProfileBrowserTest
    : public test::DeepScanningBrowserTestBase {
 public:
  explicit ConnectorsServiceProfileBrowserTest(
      ManagementStatus management_status)
      : management_status_(management_status) {
    if (management_status_ != ManagementStatus::kUnmanaged) {
#if BUILDFLAG(IS_CHROMEOS)
      policy::SetDMTokenForTesting(
          policy::DMToken::CreateValidToken(kFakeBrowserDMToken));
#else
      browser_dm_token_storage_ =
          std::make_unique<policy::FakeBrowserDMTokenStorage>();
      browser_dm_token_storage_->SetEnrollmentToken(kFakeEnrollmentToken);
      browser_dm_token_storage_->SetClientId(kFakeBrowserClientId);
      browser_dm_token_storage_->EnableStorage(true);
      browser_dm_token_storage_->SetDMToken(kFakeBrowserDMToken);
      policy::BrowserDMTokenStorage::SetForTesting(
          browser_dm_token_storage_.get());
#endif
    }
  }

  void SetUpOnMainThread() override {
    test::DeepScanningBrowserTestBase::SetUpOnMainThread();

    SetUpProfileData();

    if (management_status_ != ManagementStatus::kUnmanaged) {
      SetUpDeviceData();
    }
  }

  void SetUpProfileData() {
#if !BUILDFLAG(IS_CHROMEOS)
    test::SetProfileDMToken(browser()->profile(), kFakeProfileDMToken);
#endif

    enterprise_management::PolicyData profile_policy_data;
    profile_policy_data.add_user_affiliation_ids(kAffiliationId1);
    profile_policy_data.set_managed_by(kDomain1);
    profile_policy_data.set_device_id(kFakeProfileClientId);
    profile_policy_data.set_request_token(kFakeProfileDMToken);

    auto* profile_policy_manager =
#if BUILDFLAG(IS_CHROMEOS)
        browser()->profile()->GetUserCloudPolicyManagerAsh();
#else
        browser()->profile()->GetUserCloudPolicyManager();
#endif

    profile_policy_manager->core()->store()->set_policy_data_for_testing(
        std::make_unique<enterprise_management::PolicyData>(
            std::move(profile_policy_data)));
  }

  void SetUpDeviceData() {
#if BUILDFLAG(IS_CHROMEOS)
    auto* user_manager = user_manager::UserManager::Get();
    auto* user = user_manager->GetActiveUser();
    user_manager::UserManager::Get()->SetUserPolicyStatus(
        user->GetAccountId(),
        /*is_managed=*/management_status() == ManagementStatus::kUnmanaged,
        /*is_affliated=*/management_status() == ManagementStatus::kAffiliated);
#else
    auto* browser_policy_manager =
        g_browser_process->browser_policy_connector()
            ->machine_level_user_cloud_policy_manager();
    auto browser_policy_data =
        std::make_unique<enterprise_management::PolicyData>();
    browser_policy_data->add_device_affiliation_ids(
        management_status() == ManagementStatus::kAffiliated ? kAffiliationId1
                                                             : kAffiliationId2);
    browser_policy_data->set_username(
        management_status() == ManagementStatus::kAffiliated ? kUsername1
                                                             : kUsername2);
    browser_policy_manager->core()->store()->set_policy_data_for_testing(
        std::move(browser_policy_data));
#endif
  }

#if !BUILDFLAG(GOOGLE_CHROME_BRANDING) && !BUILDFLAG(IS_CHROMEOS)
  void SetUpDefaultCommandLine(base::CommandLine* command_line) override {
    InProcessBrowserTest::SetUpDefaultCommandLine(command_line);
    command_line->AppendSwitch(::switches::kEnableChromeBrowserCloudManagement);
  }
#endif

  void SetPrefs(std::string_view pref,
                std::string_view scope_pref,
                std::string_view pref_value,
                bool profile_scope = true) {
    browser()->profile()->GetPrefs()->Set(
        pref, *base::JSONReader::Read(pref_value,
                                      base::JSON_PARSE_CHROMIUM_EXTENSIONS));
    browser()->profile()->GetPrefs()->SetInteger(
        scope_pref, profile_scope ? policy::POLICY_SCOPE_USER
                                  : policy::POLICY_SCOPE_MACHINE);
  }
  void SetPrefs(std::string_view pref,
                std::string_view scope_pref,
                int pref_value,
                bool profile_scope = true) {
    browser()->profile()->GetPrefs()->SetInteger(pref, pref_value);
    browser()->profile()->GetPrefs()->SetInteger(
        scope_pref, profile_scope ? policy::POLICY_SCOPE_USER
                                  : policy::POLICY_SCOPE_MACHINE);
  }

  ManagementStatus management_status() { return management_status_; }

 protected:
  std::unique_ptr<policy::FakeBrowserDMTokenStorage> browser_dm_token_storage_;
  ManagementStatus management_status_;
};

class ConnectorsServiceReportingProfileBrowserTest
    : public ConnectorsServiceProfileBrowserTest,
      public testing::WithParamInterface<ManagementStatus> {
 public:
  ConnectorsServiceReportingProfileBrowserTest()
      : ConnectorsServiceProfileBrowserTest(GetParam()) {}
};

INSTANTIATE_TEST_SUITE_P(,
                         ConnectorsServiceReportingProfileBrowserTest,
                         testing::Values(ManagementStatus::kAffiliated,
                                         ManagementStatus::kUnaffiliated,
                                         ManagementStatus::kUnmanaged));

IN_PROC_BROWSER_TEST_P(ConnectorsServiceReportingProfileBrowserTest, Test) {
  SetPrefs(kOnSecurityEventPref, kOnSecurityEventScopePref,
           kNormalReportingSettingsPref);

  auto settings =
      ConnectorsServiceFactory::GetForBrowserContext(browser()->profile())
          ->GetReportingSettings();
#if BUILDFLAG(IS_CHROMEOS)
  if (management_status() == ManagementStatus::kUnmanaged) {
    ASSERT_FALSE(settings.has_value());
  } else {
    ASSERT_TRUE(settings.has_value());
    ASSERT_FALSE(settings.value().per_profile);
    ASSERT_EQ(kFakeBrowserDMToken, settings.value().dm_token);
  }
#else
  std::string management_domain =
      ConnectorsServiceFactory::GetForBrowserContext(browser()->profile())
          ->GetManagementDomain();
  // expected state is the same regardless of management_status() value.
  EXPECT_TRUE(settings.has_value());
  ASSERT_EQ(kFakeProfileDMToken, settings.value().dm_token);
  ASSERT_TRUE(settings.value().per_profile);
  ASSERT_EQ(kDomain1, management_domain);
#endif
}

class ConnectorsServiceAnalysisProfileBrowserTest
    : public ConnectorsServiceProfileBrowserTest,
      public testing::WithParamInterface<
          std::tuple<ManagementStatus, std::string_view, bool>> {
 public:
  ConnectorsServiceAnalysisProfileBrowserTest()
      : ConnectorsServiceProfileBrowserTest(std::get<0>(GetParam())) {
    if (enhanced_fields_enabled()) {
      scoped_feature_list_.InitWithFeatures(
          /*enabled_features=*/{safe_browsing::kEnhancedFieldsForSecOps,
                                policy::features::kEnhancedSecurityEventFields},
          /*disabled_features=*/{});
    } else {
      scoped_feature_list_.InitWithFeatures(
          /*enabled_features=*/{},
          /*disabled_features=*/{
              safe_browsing::kEnhancedFieldsForSecOps,
              policy::features::kEnhancedSecurityEventFields});
    }
  }

  std::string_view settings_value() { return std::get<1>(GetParam()); }

  bool enhanced_fields_enabled() { return std::get<2>(GetParam()); }

  bool is_cloud() {
    return settings_value() == kNormalCloudAnalysisSettingsPref;
  }

  // Returns the Value the "normal" reporting workflow uses to validate that it
  // is in sync with the information sent through analysis-reporting.
  base::Value::Dict ReportingMetadata(bool is_cloud, bool include_device_info) {
    base::Value::Dict output;
    output.Set("browser",
               policy::ReportingJobConfigurationBase::BrowserDictionaryBuilder::
                   BuildBrowserDictionary(!is_cloud || include_device_info));
    base::Value::Dict context = reporting::GetContext(browser()->profile());
    output.Merge(std::move(context));
    if (include_device_info) {
      base::Value::Dict device;
      device.Set("device", policy::ReportingJobConfigurationBase::
                               DeviceDictionaryBuilder ::BuildDeviceDictionary(
                                   kFakeBrowserDMToken, kFakeBrowserClientId));
      output.Merge(std::move(device));
    }

    return output;
  }

  void ValidateClientMetadata(const ClientMetadata& metadata,
                              bool is_cloud,
                              bool profile_reporting) {
#if BUILDFLAG(IS_CHROMEOS)
    bool includes_device_info =
        management_status() == ManagementStatus::kAffiliated;
#else
    bool includes_device_info =
        !profile_reporting ||
        (management_status() == ManagementStatus::kAffiliated && is_cloud);
#endif
    base::Value::Dict reporting_metadata =
        ReportingMetadata(is_cloud, includes_device_info);

    ASSERT_TRUE(metadata.has_browser());

    ASSERT_TRUE(metadata.browser().has_browser_id());
    ASSERT_EQ(metadata.browser().browser_id(),
              *reporting_metadata.FindStringByDottedPath("browser.browserId"));

    ASSERT_TRUE(metadata.browser().has_user_agent());
    ASSERT_EQ(metadata.browser().user_agent(),
              *reporting_metadata.FindStringByDottedPath("browser.userAgent"));

    ASSERT_TRUE(metadata.browser().has_chrome_version());
    ASSERT_EQ(metadata.browser().chrome_version(),
              version_info::GetVersionNumber());
    ASSERT_EQ(
        metadata.browser().chrome_version(),
        *reporting_metadata.FindStringByDottedPath("browser.chromeVersion"));

    if (is_cloud) {
      ASSERT_EQ(
          includes_device_info,
          !!reporting_metadata.FindStringByDottedPath("browser.machineUser"));
      if (metadata.browser().has_machine_user()) {
        ASSERT_EQ(
            metadata.browser().machine_user(),
            *reporting_metadata.FindStringByDottedPath("browser.machineUser"));
      }
    } else {
      ASSERT_TRUE(metadata.browser().has_machine_user());
    }
    // We check a field that should always be set if any device metadata was
    // provided.
    ASSERT_EQ(includes_device_info,
              metadata.has_device() && metadata.device().has_client_id());
    if (includes_device_info) {
      ASSERT_TRUE(metadata.device().has_dm_token());
      ASSERT_EQ(metadata.device().dm_token(), kFakeBrowserDMToken);
      ASSERT_TRUE(reporting_metadata.FindStringByDottedPath("device.dmToken"));
      ASSERT_EQ(metadata.device().dm_token(),
                *reporting_metadata.FindStringByDottedPath("device.dmToken"));

#if !BUILDFLAG(IS_CHROMEOS)
      ASSERT_TRUE(metadata.device().has_client_id());
      ASSERT_EQ(metadata.device().client_id(),
                *reporting_metadata.FindStringByDottedPath("device.clientId"));
#endif

      ASSERT_TRUE(metadata.device().has_os_version());
      ASSERT_EQ(metadata.device().os_version(),
                *reporting_metadata.FindStringByDottedPath("device.osVersion"));

      ASSERT_TRUE(metadata.device().has_os_platform());
      ASSERT_EQ(metadata.device().os_platform(), ExpectedOsPlatform());
      ASSERT_EQ(
          metadata.device().os_platform(),
          *reporting_metadata.FindStringByDottedPath("device.osPlatform"));

      ASSERT_TRUE(metadata.device().has_name());
      ASSERT_EQ(metadata.device().name(),
                *reporting_metadata.FindStringByDottedPath("device.name"));

      if (enhanced_fields_enabled()) {
        ASSERT_TRUE(metadata.device().has_device_fqdn());
        ASSERT_EQ(
            metadata.device().device_fqdn(),
            *reporting_metadata.FindStringByDottedPath("device.deviceFqdn"));

        ASSERT_TRUE(metadata.device().has_network_name());
        ASSERT_EQ(
            metadata.device().network_name(),
            *reporting_metadata.FindStringByDottedPath("device.networkName"));
      }
    }

    ASSERT_TRUE(metadata.has_profile());

    ASSERT_TRUE(metadata.profile().has_dm_token());
    ASSERT_EQ(metadata.profile().dm_token(), kFakeProfileDMToken);
    ASSERT_EQ(metadata.profile().dm_token(),
              *reporting_metadata.FindStringByDottedPath("profile.dmToken"));

    ASSERT_TRUE(metadata.profile().has_gaia_email());
    ASSERT_EQ(metadata.profile().gaia_email(),
              *reporting_metadata.FindStringByDottedPath("profile.gaiaEmail"));

    ASSERT_TRUE(metadata.profile().has_profile_path());
    ASSERT_EQ(
        metadata.profile().profile_path(),
        *reporting_metadata.FindStringByDottedPath("profile.profilePath"));

    ASSERT_TRUE(metadata.profile().has_profile_name());
    ASSERT_EQ(
        metadata.profile().profile_name(),
        *reporting_metadata.FindStringByDottedPath("profile.profileName"));

#if !BUILDFLAG(IS_CHROMEOS)
    ASSERT_TRUE(metadata.profile().has_client_id());
    ASSERT_EQ(metadata.profile().client_id(), kFakeProfileClientId);
    ASSERT_EQ(metadata.profile().client_id(),
              *reporting_metadata.FindStringByDottedPath("profile.clientId"));
#endif
  }
};

INSTANTIATE_TEST_SUITE_P(
    ,
    ConnectorsServiceAnalysisProfileBrowserTest,
    testing::Combine(testing::Values(ManagementStatus::kAffiliated,
                                     ManagementStatus::kUnaffiliated,
                                     ManagementStatus::kUnmanaged),
                     testing::Values(kNormalCloudAnalysisSettingsPref,
                                     kNormalLocalAnalysisSettingsPref),
                     testing::Bool()));

IN_PROC_BROWSER_TEST_P(ConnectorsServiceAnalysisProfileBrowserTest,
                       DeviceReporting) {
  SetPrefs(AnalysisConnectorPref(FILE_ATTACHED),
           AnalysisConnectorScopePref(FILE_ATTACHED), settings_value(),
           /*profile_scope*/ false);
  SetPrefs(kOnSecurityEventPref, kOnSecurityEventScopePref, settings_value(),
           /*profile_scope*/ false);
  auto settings =
      ConnectorsServiceFactory::GetForBrowserContext(browser()->profile())
          ->GetAnalysisSettings(GURL(kTestUrl), FILE_ATTACHED);

  // Expect no local analysis settings on platforms where it is unsupported.
#if !BUILDFLAG(ENTERPRISE_LOCAL_CONTENT_ANALYSIS)
  if (settings_value() == kNormalLocalAnalysisSettingsPref) {
    ASSERT_FALSE(settings.has_value());
    return;
  }
#endif

  if (management_status() == ManagementStatus::kUnmanaged) {
    if (settings_value() == kNormalLocalAnalysisSettingsPref) {
      ASSERT_TRUE(settings.has_value());
      ASSERT_TRUE(settings.value().cloud_or_local_settings.is_local_analysis());
      ASSERT_EQ("path_user",
                settings.value().cloud_or_local_settings.local_path());
      ASSERT_TRUE(settings.value().cloud_or_local_settings.user_specific());
    } else {
      ASSERT_FALSE(settings.has_value());
    }
  } else {
    ASSERT_TRUE(settings.has_value());
    if (settings.value().cloud_or_local_settings.is_cloud_analysis()) {
      ASSERT_EQ(kFakeBrowserDMToken,
                settings.value().cloud_or_local_settings.dm_token());
      ValidateClientMetadata(*settings.value().client_metadata, is_cloud(),
                             /*profile_reporting*/ false);
    }
    ASSERT_FALSE(settings.value().per_profile);
  }

#if !BUILDFLAG(IS_CHROMEOS)
  ASSERT_EQ((management_status() == ManagementStatus::kUnaffiliated) ? kDomain2
                                                                     : kDomain1,
            ConnectorsServiceFactory::GetForBrowserContext(browser()->profile())
                ->GetManagementDomain());
#endif
}

IN_PROC_BROWSER_TEST_P(ConnectorsServiceAnalysisProfileBrowserTest,
                       ProfileReporting) {
  SetPrefs(AnalysisConnectorPref(FILE_DOWNLOADED),
           AnalysisConnectorScopePref(FILE_DOWNLOADED), settings_value());
  SetPrefs(kOnSecurityEventPref, kOnSecurityEventScopePref,
           kNormalReportingSettingsPref);
  auto settings =
      ConnectorsServiceFactory::GetForBrowserContext(browser()->profile())
          ->GetAnalysisSettings(GURL(kTestUrl), FILE_DOWNLOADED);

  // Expect no local analysis settings on platforms where it is unsupported.
#if !BUILDFLAG(ENTERPRISE_LOCAL_CONTENT_ANALYSIS)
  if (settings_value() == kNormalLocalAnalysisSettingsPref) {
    ASSERT_FALSE(settings.has_value());
    return;
  }
#endif

#if BUILDFLAG(IS_CHROMEOS)
  if (management_status() == ManagementStatus::kUnmanaged) {
    if (settings_value() == kNormalLocalAnalysisSettingsPref) {
      ASSERT_TRUE(settings.has_value());
      // TODO(b/238216275): Verify the metadata has the expected values.
    } else {
      ASSERT_FALSE(settings.has_value());
    }
  } else {
    ASSERT_TRUE(settings.has_value());
    if (settings.value().cloud_or_local_settings.is_cloud_analysis()) {
      ASSERT_EQ(kFakeBrowserDMToken,
                settings.value().cloud_or_local_settings.dm_token());
      ValidateClientMetadata(*settings.value().client_metadata, is_cloud(),
                             /*profile_reporting*/ false);
    }
    ASSERT_FALSE(settings.value().per_profile);
  }
#else
  std::string management_domain =
      ConnectorsServiceFactory::GetForBrowserContext(browser()->profile())
          ->GetManagementDomain();
  switch (management_status()) {
    case ManagementStatus::kUnaffiliated:
      if (settings_value() == kNormalLocalAnalysisSettingsPref) {
        ASSERT_TRUE(settings.has_value());
        ASSERT_TRUE(
            settings.value().cloud_or_local_settings.is_local_analysis());
        ASSERT_EQ("path_user",
                  settings.value().cloud_or_local_settings.local_path());
        ASSERT_TRUE(settings.value().cloud_or_local_settings.user_specific());
        ASSERT_FALSE(management_domain.empty());
      } else {
        EXPECT_TRUE(settings.has_value());
        ASSERT_TRUE(
            settings.value().cloud_or_local_settings.is_cloud_analysis());
        ASSERT_EQ(kFakeProfileDMToken,
                  settings.value().cloud_or_local_settings.dm_token());
        ValidateClientMetadata(*settings.value().client_metadata, is_cloud(),
                               /*profile_reporting*/ true);
        ASSERT_TRUE(settings.value().per_profile);
        ASSERT_EQ(kDomain1, management_domain);
      }
      break;
    case ManagementStatus::kAffiliated:
      EXPECT_TRUE(settings.has_value());
      if (settings.value().cloud_or_local_settings.is_cloud_analysis()) {
        ASSERT_EQ(kFakeProfileDMToken,
                  settings.value().cloud_or_local_settings.dm_token());
        ValidateClientMetadata(*settings.value().client_metadata, is_cloud(),
                               /*profile_reporting*/ true);
      }
      ASSERT_TRUE(settings.value().per_profile);
      ASSERT_EQ(kDomain1, management_domain);
      break;
    case ManagementStatus::kUnmanaged:
      EXPECT_TRUE(settings.has_value());
      ASSERT_TRUE(settings.value().client_metadata);
      if (settings.value().cloud_or_local_settings.is_cloud_analysis()) {
        ASSERT_EQ(kFakeProfileDMToken,
                  settings.value().cloud_or_local_settings.dm_token());
        ValidateClientMetadata(*settings.value().client_metadata, is_cloud(),
                               /*profile_reporting*/ true);
        ASSERT_TRUE(settings.value().per_profile);
      } else {
        EXPECT_EQ("path_user",
                  settings.value().cloud_or_local_settings.local_path());
        EXPECT_TRUE(settings.value().cloud_or_local_settings.user_specific());
        ValidateClientMetadata(*settings.value().client_metadata, is_cloud(),
                               /*profile_reporting*/ true);
      }
      ASSERT_EQ(kDomain1, management_domain);
      break;
  }
#endif
}

IN_PROC_BROWSER_TEST_P(ConnectorsServiceAnalysisProfileBrowserTest,
                       NoReporting) {
  SetPrefs(AnalysisConnectorPref(PRINT), AnalysisConnectorScopePref(PRINT),
           settings_value());
  auto settings =
      ConnectorsServiceFactory::GetForBrowserContext(browser()->profile())
          ->GetAnalysisSettings(GURL(kTestUrl), PRINT);

  // Expect no local analysis settings on platforms where it is unsupported.
#if !BUILDFLAG(ENTERPRISE_LOCAL_CONTENT_ANALYSIS)
  if (settings_value() == kNormalLocalAnalysisSettingsPref) {
    ASSERT_FALSE(settings.has_value());
    return;
  }
#endif

#if BUILDFLAG(IS_CHROMEOS)
  if (management_status() == ManagementStatus::kUnmanaged) {
    ASSERT_FALSE(settings.has_value());
  } else {
    ASSERT_TRUE(settings.has_value());
    ASSERT_TRUE(settings.value().cloud_or_local_settings.is_cloud_analysis());
    ASSERT_EQ(kFakeBrowserDMToken,
              settings.value().cloud_or_local_settings.dm_token());
    ASSERT_FALSE(ContainsClientId(settings.value()));
    ASSERT_TRUE(settings.value().client_metadata);
    ASSERT_FALSE(settings.value().per_profile);
  }
#else
  std::string management_domain =
      ConnectorsServiceFactory::GetForBrowserContext(browser()->profile())
          ->GetManagementDomain();
  switch (management_status()) {
    case ManagementStatus::kUnaffiliated:
      if (settings_value() == kNormalLocalAnalysisSettingsPref) {
        ASSERT_TRUE(settings.has_value());
        ASSERT_TRUE(
            settings.value().cloud_or_local_settings.is_local_analysis());
        ASSERT_EQ("path_user",
                  settings.value().cloud_or_local_settings.local_path());
        ASSERT_TRUE(settings.value().cloud_or_local_settings.user_specific());
        ASSERT_NE(management_domain.empty(), true);
      } else {
        EXPECT_TRUE(settings.has_value());
        ASSERT_EQ(kFakeProfileDMToken,
                  settings.value().cloud_or_local_settings.dm_token());
        ASSERT_FALSE(ContainsClientId(settings.value()));
        ASSERT_TRUE(settings.value().client_metadata);
        ASSERT_EQ(management_domain, kDomain1);
      }
      break;
    case ManagementStatus::kAffiliated:
      EXPECT_TRUE(settings.has_value());
      if (settings.value().cloud_or_local_settings.is_cloud_analysis()) {
        ASSERT_EQ(kFakeProfileDMToken,
                  settings.value().cloud_or_local_settings.dm_token());
        ASSERT_FALSE(ContainsClientId(settings.value()));
        ASSERT_TRUE(settings.value().client_metadata);
        ASSERT_FALSE(
            settings.value().client_metadata->profile().dm_token().empty());
        ASSERT_FALSE(
            settings.value().client_metadata->device().dm_token().empty());
      } else {
        ASSERT_EQ("path_user",
                  settings.value().cloud_or_local_settings.local_path());
        ASSERT_TRUE(settings.value().cloud_or_local_settings.user_specific());
        ASSERT_TRUE(settings.value().client_metadata);
      }
      ASSERT_TRUE(settings.value().per_profile);
      ASSERT_EQ(kDomain1, management_domain);
      break;
    case ManagementStatus::kUnmanaged:
      EXPECT_TRUE(settings.has_value());
      if (settings.value().cloud_or_local_settings.is_cloud_analysis()) {
        ASSERT_EQ(kFakeProfileDMToken,
                  settings.value().cloud_or_local_settings.dm_token());
        ASSERT_FALSE(ContainsClientId(settings.value()));
        ASSERT_TRUE(settings.value().client_metadata);
        ASSERT_FALSE(
            settings.value().client_metadata->profile().dm_token().empty());
        ASSERT_TRUE(
            settings.value().client_metadata->device().dm_token().empty());

      } else {
        ASSERT_EQ("path_user",
                  settings.value().cloud_or_local_settings.local_path());
        ASSERT_TRUE(settings.value().cloud_or_local_settings.user_specific());
        ASSERT_TRUE(settings.value().client_metadata);
      }
      ASSERT_TRUE(settings.value().per_profile);
      ASSERT_EQ(kDomain1, management_domain);
      break;
  }
#endif
}

IN_PROC_BROWSER_TEST_P(ConnectorsServiceAnalysisProfileBrowserTest,
                       Affiliation) {
  SetPrefs(AnalysisConnectorPref(BULK_DATA_ENTRY),
           AnalysisConnectorScopePref(BULK_DATA_ENTRY), settings_value());
  auto settings =
      ConnectorsServiceFactory::GetForBrowserContext(browser()->profile())
          ->GetAnalysisSettings(GURL(kTestUrl), BULK_DATA_ENTRY);

  if (settings_value() == kNormalLocalAnalysisSettingsPref) {
    // Expect no local analysis settings on platforms where it is unsupported.
#if !BUILDFLAG(ENTERPRISE_LOCAL_CONTENT_ANALYSIS)
    ASSERT_FALSE(settings.has_value());
#else
    // Since they don't use anything tied to DM tokens and rely on a separately
    // installed agent, local analysis policies are always returned regardless
    // of the management status.
    ASSERT_TRUE(settings.has_value());
    ASSERT_TRUE(settings.value().cloud_or_local_settings.is_local_analysis());
    ASSERT_TRUE(settings.value().per_profile);
    ASSERT_EQ("path_user",
              settings.value().cloud_or_local_settings.local_path());
    ASSERT_TRUE(settings.value().cloud_or_local_settings.user_specific());
#endif
  } else {
#if BUILDFLAG(IS_CHROMEOS)
    if (management_status() == ManagementStatus::kUnmanaged) {
      ASSERT_FALSE(settings.has_value());
    } else {
      ASSERT_TRUE(settings.has_value());
      ASSERT_TRUE(settings.value().cloud_or_local_settings.is_cloud_analysis());
      ASSERT_EQ(kFakeBrowserDMToken,
                settings.value().cloud_or_local_settings.dm_token());
      ASSERT_FALSE(settings.value().per_profile);
    }
#else
    switch (management_status()) {
      case ManagementStatus::kUnaffiliated:
      case ManagementStatus::kAffiliated:
        EXPECT_TRUE(settings.has_value());
        ASSERT_TRUE(
            settings.value().cloud_or_local_settings.is_cloud_analysis());
        ASSERT_EQ(kFakeProfileDMToken,
                  settings.value().cloud_or_local_settings.dm_token());
        ASSERT_FALSE(ContainsClientId(settings.value()));
        ASSERT_TRUE(settings.value().client_metadata);
        ASSERT_TRUE(settings.value().per_profile);
        break;
      case ManagementStatus::kUnmanaged:
        EXPECT_TRUE(settings.has_value());
        ASSERT_EQ(kFakeProfileDMToken,
                  settings.value().cloud_or_local_settings.dm_token());
        ASSERT_FALSE(ContainsClientId(settings.value()));
        ASSERT_TRUE(settings.value().client_metadata);
        ASSERT_TRUE(settings.value().per_profile);
        break;
    }
#endif
  }
}

class ConnectorsServiceRealtimeURLCheckProfileBrowserTest
    : public ConnectorsServiceProfileBrowserTest,
      public testing::WithParamInterface<ManagementStatus> {
 public:
  ConnectorsServiceRealtimeURLCheckProfileBrowserTest()
      : ConnectorsServiceProfileBrowserTest(GetParam()) {}
};

INSTANTIATE_TEST_SUITE_P(,
                         ConnectorsServiceRealtimeURLCheckProfileBrowserTest,
                         testing::Values(ManagementStatus::kAffiliated,
                                         ManagementStatus::kUnaffiliated,
                                         ManagementStatus::kUnmanaged));

IN_PROC_BROWSER_TEST_P(ConnectorsServiceRealtimeURLCheckProfileBrowserTest,
                       Test) {
  SetPrefs(kEnterpriseRealTimeUrlCheckMode, kEnterpriseRealTimeUrlCheckScope,
           1);
  auto maybe_dm_token =
      ConnectorsServiceFactory::GetForBrowserContext(browser()->profile())
          ->GetDMTokenForRealTimeUrlCheck();
  EnterpriseRealTimeUrlCheckMode url_check_pref =
      ConnectorsServiceFactory::GetForBrowserContext(browser()->profile())
          ->GetAppliedRealTimeUrlCheck();

#if BUILDFLAG(IS_CHROMEOS)
  if (management_status() == ManagementStatus::kUnmanaged) {
    ASSERT_FALSE(maybe_dm_token.has_value());
    ASSERT_EQ(
        maybe_dm_token.error(),
        ConnectorsServiceBase::NoDMTokenForRealTimeUrlCheckReason::kNoDmToken);
    ASSERT_EQ(REAL_TIME_CHECK_DISABLED, url_check_pref);
  } else {
    ASSERT_TRUE(maybe_dm_token.has_value());
    ASSERT_EQ(kFakeBrowserDMToken, maybe_dm_token.value());
    ASSERT_EQ(REAL_TIME_CHECK_FOR_MAINFRAME_ENABLED, url_check_pref);
  }
#else
  std::string management_domain =
      ConnectorsServiceFactory::GetForBrowserContext(browser()->profile())
          ->GetManagementDomain();
  // expected state is the same regardless of management_status() value.
  ASSERT_TRUE(maybe_dm_token.has_value());
  ASSERT_EQ(kFakeProfileDMToken, maybe_dm_token.value());
  ASSERT_EQ(REAL_TIME_CHECK_FOR_MAINFRAME_ENABLED, url_check_pref);
  ASSERT_EQ(kDomain1, management_domain);
#endif
}

}  // namespace enterprise_connectors