chromium/chrome/browser/ash/net/rollback_network_config/rollback_network_config_unittest.cc

// Copyright 2021 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/ash/net/rollback_network_config/rollback_network_config.h"

#include <string>
#include <utility>

#include "base/json/json_reader.h"
#include "base/test/bind.h"
#include "base/test/task_environment.h"
#include "base/test/test_future.h"
#include "base/values.h"
#include "chrome/browser/ash/net/rollback_network_config/rollback_onc_util.h"
#include "chrome/browser/ash/ownership/owner_settings_service_ash.h"
#include "chrome/browser/ash/ownership/owner_settings_service_ash_factory.h"
#include "chrome/browser/ash/policy/core/device_policy_builder.h"
#include "chrome/browser/ash/settings/cros_settings_holder.h"
#include "chrome/browser/ash/settings/device_settings_cache.h"
#include "chrome/browser/ash/settings/device_settings_service.h"
#include "chrome/test/base/testing_browser_process.h"
#include "chrome/test/base/testing_profile.h"
#include "chrome/test/base/testing_profile_manager.h"
#include "chromeos/ash/components/dbus/session_manager/fake_session_manager_client.h"
#include "chromeos/ash/components/install_attributes/stub_install_attributes.h"
#include "chromeos/ash/components/login/login_state/login_state.h"
#include "chromeos/ash/components/network/managed_network_configuration_handler.h"
#include "chromeos/ash/components/network/network_handler_test_helper.h"
#include "chromeos/ash/components/network/network_state.h"
#include "chromeos/ash/components/network/network_state_handler.h"
#include "components/onc/onc_constants.h"
#include "components/onc/onc_pref_names.h"
#include "components/ownership/mock_owner_key_util.h"
#include "components/prefs/testing_pref_service.h"
#include "components/proxy_config/pref_proxy_config_tracker_impl.h"
#include "components/sync_preferences/testing_pref_service_syncable.h"
#include "content/public/test/browser_task_environment.h"
#include "content/public/test/test_utils.h"
#include "testing/gtest/include/gtest/gtest.h"

namespace ash::rollback_network_config {

namespace {

static const char kDeviceUserHash[] = "";

static const char kDomain[] = "domain";
static const char kDomainId[] = "domain_id";

static const char kOpenWiFi[] = R"({
  "GUID": "open-network-guid",
  "Type": "WiFi",
  "Name": "WiFi",
  "WiFi": {
    "Security": "None"
  }
})";
static const char kWpaPskWiFi[] = R"({
  "GUID": "wpa-psk-network-guid",
  "Type": "WiFi",
  "Name": "WiFi",
  "WiFi": {
    "Security": "WPA-PSK",
    "Passphrase": "wpa-psk-network-passphrase"
  }
})";
static const char kWpaPskWiFiNoPass[] = R"({
  "GUID": "wpa-psk-network-guid",
  "Type": "WiFi",
  "Name": "WiFi",
  "WiFi": {
    "Security": "WPA-PSK",
    "Passphrase": ""
  }
})";
static const char kWepPskWiFi[] = R"({
  "GUID": "wep-psk-network-guid",
  "Type": "WiFi",
  "Name": "WiFi",
  "WiFi": {
    "Security": "WEP-PSK",
    "Passphrase": "wep-psk-network-passphrase"
  }
})";
static const char kPeapWiFi[] = R"({
  "GUID": "peap-network-guid",
  "Type": "WiFi",
  "Name": "WiFi",
  "WiFi": {
    "Security": "WPA-EAP",
    "EAP" : {
      "ClientCertType": "None",
      "Identity" : "peap-network-identity",
      "Inner" : "Automatic",
      "Outer" : "PEAP",
      "Password" : "peap-network-password",
      "SaveCredentials" : true
    }
  }
})";
static const char kOpenEthernet[] = R"({
  "GUID": "ethernet-guid",
  "Type": "Ethernet",
  "Name": "Ethernet",
  "Ethernet": {
    "Authentication": "None"
  }
})";
static const char kPeapEthernet[] = R"({
  "GUID": "peap-ethernet-guid",
  "Type": "Ethernet",
  "Name": "Ethernet",
  "Ethernet": {
    "Authentication": "8021X",
    "EAP" : {
        "ClientCertType": "None",
        "Identity" : "peap-ethernet-identity",
        "Inner" : "MSCHAPv2",
        "Outer" : "PEAP",
        "Password" : "peap-ethernet-password",
        "SaveCredentials" : true
    }
  }
})";
static const char kPeapWiFiRecommendedPolicyPart[] = R"({
  "GUID": "peap-network-guid",
  "Type": "WiFi",
  "Name": "WiFi",
  "WiFi": {
    "Security": "WPA-EAP",
    "EAP" : {
      "ClientCertType": "None",
      "Identity" : "peap-network-identity",
      "Inner" : "Automatic",
      "Outer" : "PEAP",
      "Password" : "peap-network-password",
      "Recommended" : ["Identity"],
      "SaveCredentials" : true
    }
  }
})";
static const char kPeapWiFiRecommendedUserPart[] = R"({
  "WiFi": {
    "EAP" : {
      "Identity" : "peap-network-recommended-identity"
    }
  }
})";

TestingPrefServiceSimple* RegisterPrefs(TestingPrefServiceSimple* local_state) {
  device_settings_cache::RegisterPrefs(local_state->registry());
  return local_state;
}

void PrintErrorAndFail(const std::string& error_name) {
  LOG(ERROR) << error_name;
  FAIL();
}

void PrintErrorAndMessageAndFail(const std::string& error_name,
                                 const std::string& error_message) {
  LOG(ERROR) << error_name << " " << error_message;
  FAIL();
}

NetworkStateHandler* network_state_handler() {
  return NetworkHandler::Get()->network_state_handler();
}

ash::ManagedNetworkConfigurationHandler*
managed_network_configuration_handler() {
  return NetworkHandler::Get()->managed_network_configuration_handler();
}

ShillServiceClient* shill_service_client() {
  return ShillServiceClient::Get();
}

const NetworkState* GetNetworkState(const std::string& guid) {
  return network_state_handler()->GetNetworkStateFromGuid(guid);
}

std::string GetServicePath(const std::string& guid) {
  return GetNetworkState(guid)->path();
}

bool NetworkExists(const std::string& guid) {
  const ash::NetworkState* network_state =
      network_state_handler()->GetNetworkStateFromGuid(guid);
  return network_state && network_state->IsInProfile();
}

void SetUpDeviceWideNetworkConfig(const base::Value& config) {
  base::test::TestFuture<const std::string&, const std::string&> result;
  managed_network_configuration_handler()->CreateConfiguration(
      kDeviceUserHash, config.GetDict(), result.GetCallback(),
      base::BindOnce(&PrintErrorAndFail));
  ASSERT_TRUE(result.Wait()) << "Failed to configure " << config;
}

void SetPropertiesForExistingNetwork(const std::string& guid,
                                     const base::Value& config) {
  ASSERT_TRUE(NetworkExists(guid));

  const ash::NetworkState* network_state =
      network_state_handler()->GetNetworkStateFromGuid(guid);

  base::test::TestFuture<void> signal;
  managed_network_configuration_handler()->SetProperties(
      network_state->path(), config.GetDict(), signal.GetCallback(),
      base::BindOnce(&PrintErrorAndFail));
  ASSERT_TRUE(signal.Wait()) << "Failed to set " << config << " for " << guid;
}

base::Value::Dict GetProperties(const std::string userhash,
                                const std::string& guid) {
  base::test::TestFuture<const std::string&, std::optional<base::Value::Dict>,
                         std::optional<std::string>>
      result;
  managed_network_configuration_handler()->GetProperties(
      userhash, GetServicePath(guid), result.GetCallback());
  std::optional<base::Value::Dict> properties = std::get<1>(result.Take());
  EXPECT_TRUE(properties.has_value());
  return std::move(properties.value());
}

base::Value::Dict GetManagedProperties(const std::string userhash,
                                       const std::string& guid) {
  base::test::TestFuture<const std::string&, std::optional<base::Value::Dict>,
                         std::optional<std::string>>
      result;
  managed_network_configuration_handler()->GetManagedProperties(
      userhash, GetServicePath(guid), result.GetCallback());

  std::optional<base::Value::Dict> properties = std::get<1>(result.Take());
  EXPECT_TRUE(properties.has_value());
  return std::move(properties.value());
}

std::string GetPskPassphrase(const std::string& guid) {
  base::test::TestFuture<const std::string&> passphrase;
  shill_service_client()->GetWiFiPassphrase(
      dbus::ObjectPath(GetServicePath(guid)), passphrase.GetCallback(),
      base::BindOnce(&PrintErrorAndMessageAndFail));
  return passphrase.Get();
}

std::string GetEapPassphrase(const std::string& guid) {
  base::test::TestFuture<const std::string&> passphrase;
  shill_service_client()->GetEapPassphrase(
      dbus::ObjectPath(GetServicePath(guid)), passphrase.GetCallback(),
      base::BindOnce(&PrintErrorAndMessageAndFail));
  return passphrase.Get();
}

void RemoveNetwork(const std::string& guid) {
  const ash::NetworkState* network_state =
      network_state_handler()->GetNetworkStateFromGuid(guid);

  base::test::TestFuture<void> signal;
  managed_network_configuration_handler()->RemoveConfiguration(
      network_state->path(), signal.GetCallback(),
      base::BindOnce(&PrintErrorAndFail));
  ASSERT_TRUE(signal.Wait()) << "Failed to remove " << guid;
}

}  // namespace

class RollbackNetworkConfigTest : public testing::Test {
 public:
  RollbackNetworkConfigTest() {
    network_handler_test_helper_.AddDefaultProfiles();
    network_handler_test_helper_.ResetDevicesAndServices();

    RegisterAndSetUpPrefs();

    rollback_network_config_ = std::make_unique<RollbackNetworkConfig>();
  }

  ~RollbackNetworkConfigTest() override { rollback_network_config_.reset(); }

  void RegisterAndSetUpPrefs() {
    PrefProxyConfigTrackerImpl::RegisterProfilePrefs(user_prefs_.registry());
    PrefProxyConfigTrackerImpl::RegisterPrefs(local_state_.registry());
    network_handler_test_helper_.RegisterPrefs(user_prefs_.registry(),
                                               local_state_.registry());

    network_handler_test_helper_.InitializePrefs(&user_prefs_, &local_state_);
  }

  void SetUp() override { SetEmptyDevicePolicy(); }

  void SetEmptyDevicePolicy() {
    managed_network_configuration_handler()->SetPolicy(
        ::onc::ONC_SOURCE_DEVICE_POLICY, kDeviceUserHash,
        /*network_configs_onc=*/base::Value::List(),
        /*global_network_config=*/base::Value::Dict());
    task_environment_.RunUntilIdle();
  }

  void SetUpDevicePolicyNetworkConfig(const base::Value& network_config) {
    base::Value::List network_configs_onc;
    base::Value::Dict global_network_config;
    network_configs_onc.Append(network_config.Clone());
    managed_network_configuration_handler()->SetPolicy(
        onc::ONC_SOURCE_DEVICE_POLICY, kDeviceUserHash, network_configs_onc,
        global_network_config);
    task_environment_.RunUntilIdle();
  }

  std::string Export() {
    base::test::TestFuture<const std::string&> config;
    rollback_network_config_->RollbackConfigExport(config.GetCallback());
    return config.Get();
  }

  void Import(const std::string& config) {
    base::test::TestFuture<bool> result;
    rollback_network_config_->RollbackConfigImport(config,
                                                   result.GetCallback());
    EXPECT_TRUE(result.Get()) << "Failed to import " << config;
  }

  // Exports network data, resets all network configuration including policies
  // and imports network data.
  void SimulateRollback() {
    const std::string config = Export();

    SetEmptyDevicePolicy();
    network_handler_test_helper_.ResetDevicesAndServices();

    Import(config);
  }

  void TakeOwnershipAsConsumer() {
    rollback_network_config_->fake_ownership_taken_for_testing();
    task_environment_.RunUntilIdle();
  }

  void TakeOwnershipEnrolled() {
    scoped_stub_install_attributes_.Get()->SetCloudManaged(kDomain, kDomainId);
    rollback_network_config_->fake_ownership_taken_for_testing();
    task_environment_.RunUntilIdle();
  }

 private:
  scoped_refptr<ownership::MockOwnerKeyUtil> owner_keys_{
      base::MakeRefCounted<ownership::MockOwnerKeyUtil>()};

  TestingPrefServiceSimple local_state_;
  sync_preferences::TestingPrefServiceSyncable user_prefs_;
  content::BrowserTaskEnvironment task_environment_{
      content::BrowserTaskEnvironment::IO_MAINLOOP};
  NetworkHandlerTestHelper network_handler_test_helper_;
  ScopedStubInstallAttributes scoped_stub_install_attributes_;
  ScopedTestDeviceSettingsService scoped_device_settings_;
  CrosSettingsHolder cros_settings_holder_{ash::DeviceSettingsService::Get(),
                                           RegisterPrefs(&local_state_)};
  policy::DevicePolicyBuilder device_policy_;

  std::unique_ptr<RollbackNetworkConfig> rollback_network_config_;
};

TEST_F(RollbackNetworkConfigTest, OpenWiFiIsPreserved) {
  base::Value network = *base::JSONReader::Read(kOpenWiFi);
  SetUpDeviceWideNetworkConfig(network);
  const std::string& guid =
      GetStringValue(network.GetDict(), onc::network_config::kGUID);

  SimulateRollback();

  ASSERT_TRUE(NetworkExists(guid));
  base::Value::Dict properties = GetProperties(kDeviceUserHash, guid);
  ASSERT_EQ(GetStringValue(properties, onc::network_config::kType),
            onc::network_type::kWiFi);
  EXPECT_EQ(OncWiFiGetSecurity(properties), onc::wifi::kSecurityNone);
  EXPECT_EQ(GetStringValue(properties, onc::network_config::kSource),
            onc::network_config::kSourceDevice);
}

TEST_F(RollbackNetworkConfigTest, PolicyOpenWiFiIsPreserved) {
  base::Value network = *base::JSONReader::Read(kOpenWiFi);
  SetUpDevicePolicyNetworkConfig(network);
  const std::string& guid =
      GetStringValue(network.GetDict(), onc::network_config::kGUID);

  SimulateRollback();
  ASSERT_TRUE(NetworkExists(guid));

  TakeOwnershipEnrolled();
  SetUpDevicePolicyNetworkConfig(network);

  ASSERT_TRUE(NetworkExists(guid));
  base::Value::Dict properties = GetProperties(kDeviceUserHash, guid);
  ASSERT_EQ(GetStringValue(properties, onc::network_config::kType),
            onc::network_type::kWiFi);
  EXPECT_EQ(OncWiFiGetSecurity(properties), onc::wifi::kSecurityNone);
  EXPECT_EQ(GetStringValue(properties, onc::network_config::kSource),
            onc::network_config::kSourceDevicePolicy);
}

TEST_F(RollbackNetworkConfigTest, WpaPskWiFiIsPreserved) {
  base::Value network = *base::JSONReader::Read(kWpaPskWiFi);
  SetUpDeviceWideNetworkConfig(network);
  const std::string& guid =
      GetStringValue(network.GetDict(), onc::network_config::kGUID);

  SimulateRollback();

  ASSERT_TRUE(NetworkExists(guid));

  EXPECT_EQ(GetPskPassphrase(guid), OncWiFiGetPassword(network.GetDict()));

  base::Value::Dict properties = GetProperties(kDeviceUserHash, guid);
  ASSERT_EQ(GetStringValue(properties, onc::network_config::kType),
            onc::network_type::kWiFi);
  EXPECT_EQ(OncWiFiGetSecurity(properties), onc::wifi::kWPA_PSK);
  EXPECT_EQ(GetStringValue(properties, onc::network_config::kSource),
            onc::network_config::kSourceDevice);
}

TEST_F(RollbackNetworkConfigTest, WpaPskWiFiWithoutPasswordIsPreserved) {
  base::Value network = *base::JSONReader::Read(kWpaPskWiFiNoPass);
  SetUpDeviceWideNetworkConfig(network);
  const std::string& guid =
      GetStringValue(network.GetDict(), onc::network_config::kGUID);

  SimulateRollback();

  ASSERT_TRUE(NetworkExists(guid));

  EXPECT_EQ(GetPskPassphrase(guid), OncWiFiGetPassword(network.GetDict()));

  base::Value::Dict properties = GetProperties(kDeviceUserHash, guid);
  ASSERT_EQ(GetStringValue(properties, onc::network_config::kType),
            onc::network_type::kWiFi);
  EXPECT_EQ(OncWiFiGetSecurity(properties), onc::wifi::kWPA_PSK);
  EXPECT_EQ(GetStringValue(properties, onc::network_config::kSource),
            onc::network_config::kSourceDevice);
}

TEST_F(RollbackNetworkConfigTest, PolicyWpaPskWiFiIsPreserved) {
  base::Value network = *base::JSONReader::Read(kWpaPskWiFi);
  SetUpDevicePolicyNetworkConfig(network);
  const std::string& guid =
      GetStringValue(network.GetDict(), onc::network_config::kGUID);

  SimulateRollback();

  ASSERT_TRUE(NetworkExists(guid));

  TakeOwnershipEnrolled();
  SetUpDevicePolicyNetworkConfig(network);

  EXPECT_EQ(GetPskPassphrase(guid), OncWiFiGetPassword(network.GetDict()));

  base::Value::Dict properties = GetProperties(kDeviceUserHash, guid);
  ASSERT_EQ(GetStringValue(properties, onc::network_config::kType),
            onc::network_type::kWiFi);
  EXPECT_EQ(OncWiFiGetSecurity(properties), onc::wifi::kWPA_PSK);
  EXPECT_EQ(GetStringValue(properties, onc::network_config::kSource),
            onc::network_config::kSourceDevicePolicy);
}

TEST_F(RollbackNetworkConfigTest, WepPskWiFiIsPreserved) {
  base::Value network = *base::JSONReader::Read(kWepPskWiFi);
  SetUpDeviceWideNetworkConfig(network);
  const std::string& guid =
      GetStringValue(network.GetDict(), onc::network_config::kGUID);

  SimulateRollback();

  ASSERT_TRUE(NetworkExists(guid));
  base::Value::Dict properties = GetProperties(kDeviceUserHash, guid);
  ASSERT_EQ(GetStringValue(properties, onc::network_config::kType),
            onc::network_type::kWiFi);
  EXPECT_EQ(OncWiFiGetSecurity(properties), onc::wifi::kWEP_PSK);
  EXPECT_EQ(GetPskPassphrase(guid), OncWiFiGetPassword(network.GetDict()));
  EXPECT_EQ(GetStringValue(properties, onc::network_config::kSource),
            onc::network_config::kSourceDevice);
}

TEST_F(RollbackNetworkConfigTest, PolicyWepPskWiFiIsPreserved) {
  base::Value network = *base::JSONReader::Read(kWepPskWiFi);
  SetUpDevicePolicyNetworkConfig(network);
  const std::string& guid =
      GetStringValue(network.GetDict(), onc::network_config::kGUID);

  SimulateRollback();

  ASSERT_TRUE(NetworkExists(guid));

  TakeOwnershipEnrolled();
  SetUpDevicePolicyNetworkConfig(network);

  ASSERT_TRUE(NetworkExists(guid));
  base::Value::Dict properties = GetProperties(kDeviceUserHash, guid);
  ASSERT_EQ(GetStringValue(properties, onc::network_config::kType),
            onc::network_type::kWiFi);
  EXPECT_EQ(OncWiFiGetSecurity(properties), onc::wifi::kWEP_PSK);
  EXPECT_EQ(GetPskPassphrase(guid), OncWiFiGetPassword(network.GetDict()));
  EXPECT_EQ(GetStringValue(properties, onc::network_config::kSource),
            onc::network_config::kSourceDevicePolicy);
}

TEST_F(RollbackNetworkConfigTest, PeapWiFiIsPreserved) {
  base::Value network = *base::JSONReader::Read(kPeapWiFi);
  SetUpDeviceWideNetworkConfig(network);
  const std::string& guid =
      GetStringValue(network.GetDict(), onc::network_config::kGUID);

  SimulateRollback();

  ASSERT_TRUE(NetworkExists(guid));

  EXPECT_EQ(GetEapPassphrase(guid), OncGetEapPassword(network.GetDict()));

  base::Value::Dict properties = GetProperties(kDeviceUserHash, guid);
  ASSERT_EQ(GetStringValue(properties, onc::network_config::kType),
            onc::network_type::kWiFi);
  EXPECT_EQ(OncWiFiGetSecurity(properties), onc::wifi::kWPA_EAP);
  EXPECT_EQ(OncGetEapIdentity(properties),
            OncGetEapIdentity(network.GetDict()));
  EXPECT_EQ(OncGetEapInner(properties), OncGetEapInner(network.GetDict()));
  EXPECT_EQ(OncGetEapOuter(properties), OncGetEapOuter(network.GetDict()));
  EXPECT_EQ(OncGetEapSaveCredentials(properties),
            OncGetEapSaveCredentials(network.GetDict()));
  EXPECT_TRUE(OncIsEapWithoutClientCertificate(properties));
}

TEST_F(RollbackNetworkConfigTest, PolicyPeapWiFiIsPreserved) {
  base::Value network = *base::JSONReader::Read(kPeapWiFi);
  SetUpDevicePolicyNetworkConfig(network);
  const std::string& guid =
      GetStringValue(network.GetDict(), onc::network_config::kGUID);

  SimulateRollback();

  ASSERT_TRUE(NetworkExists(guid));

  TakeOwnershipEnrolled();
  SetUpDevicePolicyNetworkConfig(network);

  ASSERT_TRUE(NetworkExists(guid));

  EXPECT_EQ(GetEapPassphrase(guid), OncGetEapPassword(network.GetDict()));

  base::Value::Dict properties = GetProperties(kDeviceUserHash, guid);
  ASSERT_EQ(GetStringValue(properties, onc::network_config::kType),
            onc::network_type::kWiFi);
  EXPECT_EQ(OncWiFiGetSecurity(properties), onc::wifi::kWPA_EAP);
  EXPECT_EQ(OncGetEapIdentity(properties),
            OncGetEapIdentity(network.GetDict()));
  EXPECT_EQ(OncGetEapInner(properties), OncGetEapInner(network.GetDict()));
  EXPECT_EQ(OncGetEapOuter(properties), OncGetEapOuter(network.GetDict()));
  EXPECT_EQ(OncGetEapSaveCredentials(properties),
            OncGetEapSaveCredentials(network.GetDict()));
  EXPECT_TRUE(OncIsEapWithoutClientCertificate(properties));
  EXPECT_EQ(GetStringValue(properties, onc::network_config::kSource),
            onc::network_config::kSourceDevicePolicy);
}

TEST_F(RollbackNetworkConfigTest, OpenEthernetIsPreserved) {
  base::Value network = *base::JSONReader::Read(kOpenEthernet);
  SetUpDeviceWideNetworkConfig(network);
  const std::string& guid =
      GetStringValue(network.GetDict(), onc::network_config::kGUID);

  SimulateRollback();

  ASSERT_TRUE(NetworkExists(guid));

  base::Value::Dict properties = GetProperties(kDeviceUserHash, guid);
  ASSERT_EQ(GetStringValue(properties, onc::network_config::kType),
            onc::network_type::kEthernet);
  EXPECT_TRUE(OncHasNoSecurity(properties));
}

TEST_F(RollbackNetworkConfigTest, PolicyOpenEthernetIsPreserved) {
  base::Value network = *base::JSONReader::Read(kOpenEthernet);
  SetUpDevicePolicyNetworkConfig(network);
  const std::string& guid =
      GetStringValue(network.GetDict(), onc::network_config::kGUID);

  SimulateRollback();

  ASSERT_TRUE(NetworkExists(guid));

  TakeOwnershipEnrolled();
  SetUpDevicePolicyNetworkConfig(network);

  ASSERT_TRUE(NetworkExists(guid));

  base::Value::Dict properties = GetProperties(kDeviceUserHash, guid);
  ASSERT_EQ(GetStringValue(properties, onc::network_config::kType),
            onc::network_type::kEthernet);
  EXPECT_TRUE(OncHasNoSecurity(properties));
  EXPECT_EQ(GetStringValue(properties, onc::network_config::kSource),
            onc::network_config::kSourceDevicePolicy);
}

TEST_F(RollbackNetworkConfigTest, PeapEthernetIsPreserved) {
  base::Value network = *base::JSONReader::Read(kPeapEthernet);
  SetUpDeviceWideNetworkConfig(network);
  const std::string& guid =
      GetStringValue(network.GetDict(), onc::network_config::kGUID);

  SimulateRollback();

  ASSERT_TRUE(NetworkExists(guid));

  EXPECT_EQ(GetEapPassphrase(guid), OncGetEapPassword(network.GetDict()));

  base::Value::Dict properties = GetProperties(kDeviceUserHash, guid);
  ASSERT_EQ(GetStringValue(properties, onc::network_config::kType),
            onc::network_type::kEthernet);
  EXPECT_EQ(OncEthernetGetAuthentication(properties), onc::ethernet::k8021X);
  EXPECT_EQ(OncGetEapIdentity(properties),
            OncGetEapIdentity(network.GetDict()));
  EXPECT_EQ(OncGetEapInner(properties), OncGetEapInner(network.GetDict()));
  EXPECT_EQ(OncGetEapOuter(properties), OncGetEapOuter(network.GetDict()));
  EXPECT_EQ(OncGetEapSaveCredentials(properties),
            OncGetEapSaveCredentials(network.GetDict()));
  EXPECT_TRUE(OncIsEapWithoutClientCertificate(properties));
}

TEST_F(RollbackNetworkConfigTest, PolicyPeapEthernetIsPreserved) {
  base::Value network = *base::JSONReader::Read(kPeapEthernet);
  SetUpDevicePolicyNetworkConfig(network);
  SimulateRollback();
  const std::string& guid =
      GetStringValue(network.GetDict(), onc::network_config::kGUID);

  ASSERT_TRUE(NetworkExists(guid));

  TakeOwnershipEnrolled();
  SetUpDevicePolicyNetworkConfig(network);

  ASSERT_TRUE(NetworkExists(guid));

  EXPECT_EQ(GetEapPassphrase(guid), OncGetEapPassword(network.GetDict()));

  base::Value::Dict properties = GetProperties(kDeviceUserHash, guid);
  ASSERT_EQ(GetStringValue(properties, onc::network_config::kType),
            onc::network_type::kEthernet);
  EXPECT_EQ(OncEthernetGetAuthentication(properties), onc::ethernet::k8021X);
  EXPECT_EQ(OncGetEapIdentity(properties),
            OncGetEapIdentity(network.GetDict()));
  EXPECT_EQ(OncGetEapInner(properties), OncGetEapInner(network.GetDict()));
  EXPECT_EQ(OncGetEapOuter(properties), OncGetEapOuter(network.GetDict()));
  EXPECT_EQ(OncGetEapSaveCredentials(properties),
            OncGetEapSaveCredentials(network.GetDict()));
  EXPECT_TRUE(OncIsEapWithoutClientCertificate(properties));
  EXPECT_EQ(GetStringValue(properties, onc::network_config::kSource),
            onc::network_config::kSourceDevicePolicy);
}

TEST_F(RollbackNetworkConfigTest, ConsumerOwnershipKeepsDeviceNetworks) {
  base::Value network = *base::JSONReader::Read(kOpenWiFi);
  SetUpDeviceWideNetworkConfig(network);
  const std::string& guid =
      GetStringValue(network.GetDict(), onc::network_config::kGUID);

  SimulateRollback();
  TakeOwnershipAsConsumer();

  ASSERT_TRUE(NetworkExists(guid));
  base::Value::Dict properties = GetProperties(kDeviceUserHash, guid);
  ASSERT_EQ(GetStringValue(properties, onc::network_config::kType),
            onc::network_type::kWiFi);
  EXPECT_EQ(OncWiFiGetSecurity(properties), onc::wifi::kSecurityNone);
  EXPECT_EQ(GetStringValue(properties, onc::network_config::kSource),
            onc::network_config::kSourceDevice);
}

TEST_F(RollbackNetworkConfigTest, ConsumerOwnershipDeletesPolicyNetworksWiFi) {
  base::Value network = *base::JSONReader::Read(kOpenWiFi);
  SetUpDevicePolicyNetworkConfig(network);
  const std::string& guid =
      GetStringValue(network.GetDict(), onc::network_config::kGUID);

  EXPECT_TRUE(NetworkExists(guid));
  SimulateRollback();
  EXPECT_TRUE(NetworkExists(guid));
  TakeOwnershipAsConsumer();
  EXPECT_FALSE(NetworkExists(guid));
}

TEST_F(RollbackNetworkConfigTest,
       ConsumerOwnershipDeletesPolicyNetworksEthernet) {
  base::Value network = *base::JSONReader::Read(kPeapEthernet);
  SetUpDevicePolicyNetworkConfig(network);
  const std::string& guid =
      GetStringValue(network.GetDict(), onc::network_config::kGUID);

  EXPECT_TRUE(NetworkExists(guid));
  SimulateRollback();
  EXPECT_TRUE(NetworkExists(guid));
  TakeOwnershipAsConsumer();

  // Essential properties of the configuration may be kept, but at least
  // identity and password should be deleted.
  if (NetworkExists(guid)) {
    base::Value::Dict properties = GetProperties(kDeviceUserHash, guid);
    // Shill may only delete the eap part and keep the authentication type, that
    // is okay as well.
    if (OncIsEap(properties) && OncHasEapConfiguration(properties)) {
      EXPECT_EQ(GetEapPassphrase(guid), "");
      EXPECT_EQ(OncGetEapIdentity(properties), "");
    }
  }
}

TEST_F(RollbackNetworkConfigTest, EnrollmentToSameKeepsPolicyNetworks) {
  base::Value network = *base::JSONReader::Read(kOpenWiFi);
  SetUpDevicePolicyNetworkConfig(network);
  const std::string& guid =
      GetStringValue(network.GetDict(), onc::network_config::kGUID);

  EXPECT_TRUE(NetworkExists(guid));
  SimulateRollback();
  EXPECT_TRUE(NetworkExists(guid));
  TakeOwnershipEnrolled();
  SetUpDevicePolicyNetworkConfig(network);

  base::Value managed_properties(GetManagedProperties(kDeviceUserHash, guid));
  ManagedOncCollapseToUiData(&managed_properties);

  EXPECT_TRUE(NetworkExists(guid));
}

TEST_F(RollbackNetworkConfigTest, EnrollmentToDifferentDeletesPolicyNetworks) {
  base::Value network = *base::JSONReader::Read(kOpenWiFi);
  SetUpDevicePolicyNetworkConfig(network);
  const std::string& guid =
      GetStringValue(network.GetDict(), onc::network_config::kGUID);

  EXPECT_TRUE(NetworkExists(guid));
  SimulateRollback();
  EXPECT_TRUE(NetworkExists(guid));
  TakeOwnershipEnrolled();
  SetEmptyDevicePolicy();

  EXPECT_FALSE(NetworkExists(guid));
}

// Currently, Chrome may send the signal that an empty device policy was
// applied before enrollment took place. Make sure we do not delete networks too
// early. See b/270355500.
TEST_F(RollbackNetworkConfigTest,
       PolicyApplicationWithoutOwnershipDoesNotDeleteNetworks) {
  base::Value network = *base::JSONReader::Read(kOpenWiFi);
  SetUpDevicePolicyNetworkConfig(network);
  const std::string& guid =
      GetStringValue(network.GetDict(), onc::network_config::kGUID);

  EXPECT_TRUE(NetworkExists(guid));
  SimulateRollback();
  EXPECT_TRUE(NetworkExists(guid));
  SetEmptyDevicePolicy();

  EXPECT_TRUE(NetworkExists(guid));
}

TEST_F(RollbackNetworkConfigTest, ExactlyRecommendedValuesPreserved) {
  base::Value policy_config =
      *base::JSONReader::Read(kPeapWiFiRecommendedPolicyPart);
  base::Value user_config =
      *base::JSONReader::Read(kPeapWiFiRecommendedUserPart);
  const std::string& guid =
      GetStringValue(policy_config.GetDict(), onc::network_config::kGUID);

  SetUpDevicePolicyNetworkConfig(policy_config);
  SetPropertiesForExistingNetwork(guid, user_config);

  SimulateRollback();
  TakeOwnershipEnrolled();
  SetUpDevicePolicyNetworkConfig(policy_config);

  base::Value managed_properties(GetManagedProperties(kDeviceUserHash, guid));
  ManagedOncCollapseToUiData(&managed_properties);
  EXPECT_EQ(managed_properties, user_config);
}

TEST_F(RollbackNetworkConfigTest,
       ConsumerOwnershipDeletesPolicyNetworkWithRecommendFields) {
  base::Value policy_config =
      *base::JSONReader::Read(kPeapWiFiRecommendedPolicyPart);
  base::Value user_config =
      *base::JSONReader::Read(kPeapWiFiRecommendedUserPart);
  const std::string& guid =
      GetStringValue(policy_config.GetDict(), onc::network_config::kGUID);

  SetUpDevicePolicyNetworkConfig(policy_config);
  SetPropertiesForExistingNetwork(guid, user_config);

  SimulateRollback();
  TakeOwnershipAsConsumer();
  EXPECT_FALSE(NetworkExists(guid));
}

TEST_F(RollbackNetworkConfigTest,
       DeleteDeviceNetworkBetweenImportAndConsumerOwnership) {
  base::Value network = *base::JSONReader::Read(kOpenWiFi);
  SetUpDeviceWideNetworkConfig(network);
  const std::string& guid =
      GetStringValue(network.GetDict(), onc::network_config::kGUID);

  SimulateRollback();
  RemoveNetwork(guid);

  ASSERT_FALSE(NetworkExists(guid));
  TakeOwnershipAsConsumer();
  ASSERT_FALSE(NetworkExists(guid));
}

TEST_F(RollbackNetworkConfigTest,
       DeleteDeviceNetworkBetweenImportAndEnrollment) {
  base::Value network = *base::JSONReader::Read(kOpenWiFi);
  SetUpDeviceWideNetworkConfig(network);
  const std::string& guid =
      GetStringValue(network.GetDict(), onc::network_config::kGUID);

  SimulateRollback();
  RemoveNetwork(guid);

  ASSERT_FALSE(NetworkExists(guid));
  TakeOwnershipEnrolled();
  ASSERT_FALSE(NetworkExists(guid));
}

TEST_F(RollbackNetworkConfigTest,
       DeletePolicyNetworkBetweenImportAndConsumerOwnership) {
  base::Value network = *base::JSONReader::Read(kOpenWiFi);
  SetUpDevicePolicyNetworkConfig(network);
  const std::string& guid =
      GetStringValue(network.GetDict(), onc::network_config::kGUID);

  SimulateRollback();

  RemoveNetwork(guid);

  ASSERT_FALSE(NetworkExists(guid));

  TakeOwnershipAsConsumer();

  ASSERT_FALSE(NetworkExists(guid));
}

TEST_F(RollbackNetworkConfigTest,
       DeletePolicyNetworkBetweenImportAndEnrollment) {
  base::Value network = *base::JSONReader::Read(kOpenWiFi);
  SetUpDevicePolicyNetworkConfig(network);
  const std::string& guid =
      GetStringValue(network.GetDict(), onc::network_config::kGUID);

  SimulateRollback();

  RemoveNetwork(guid);

  ASSERT_FALSE(NetworkExists(guid));

  TakeOwnershipEnrolled();
  SetUpDevicePolicyNetworkConfig(network);

  ASSERT_TRUE(NetworkExists(guid));
}

TEST_F(RollbackNetworkConfigTest, EmptyImport) {
  const std::string empty_config = "{\"NetworkConfigurations\":[]}";
  Import(empty_config);
}

TEST_F(RollbackNetworkConfigTest, EmptyExport) {
  EXPECT_EQ(Export(), "{\"NetworkConfigurations\":[]}");
}

TEST_F(RollbackNetworkConfigTest, MultipleNetworks) {
  base::Value peap_wifi = *base::JSONReader::Read(kPeapWiFi);
  SetUpDeviceWideNetworkConfig(peap_wifi);
  const std::string& peap_wifi_guid =
      GetStringValue(peap_wifi.GetDict(), onc::network_config::kGUID);

  base::Value open_wifi = *base::JSONReader::Read(kOpenWiFi);
  SetUpDeviceWideNetworkConfig(open_wifi);
  const std::string& open_wifi_guid =
      GetStringValue(open_wifi.GetDict(), onc::network_config::kGUID);

  base::Value eap_ethernet = *base::JSONReader::Read(kPeapEthernet);
  SetUpDeviceWideNetworkConfig(eap_ethernet);
  const std::string& eap_ethernet_guid =
      GetStringValue(eap_ethernet.GetDict(), onc::network_config::kGUID);

  SimulateRollback();
  TakeOwnershipEnrolled();
  SetEmptyDevicePolicy();

  EXPECT_TRUE(NetworkExists(peap_wifi_guid));
  EXPECT_TRUE(NetworkExists(open_wifi_guid));
  EXPECT_TRUE(NetworkExists(eap_ethernet_guid));
}

}  // namespace ash::rollback_network_config