chromium/chromeos/ash/components/network/managed_network_configuration_handler_impl.h

// 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.

#ifndef CHROMEOS_ASH_COMPONENTS_NETWORK_MANAGED_NETWORK_CONFIGURATION_HANDLER_IMPL_H_
#define CHROMEOS_ASH_COMPONENTS_NETWORK_MANAGED_NETWORK_CONFIGURATION_HANDLER_IMPL_H_

#include <memory>
#include <string>
#include <string_view>

#include "base/compiler_specific.h"
#include "base/component_export.h"
#include "base/containers/flat_map.h"
#include "base/containers/flat_set.h"
#include "base/memory/raw_ptr.h"
#include "base/memory/weak_ptr.h"
#include "base/observer_list.h"
#include "chromeos/ash/components/network/client_cert_util.h"
#include "chromeos/ash/components/network/managed_network_configuration_handler.h"
#include "chromeos/ash/components/network/network_handler_callbacks.h"
#include "chromeos/ash/components/network/network_profile_observer.h"
#include "chromeos/ash/components/network/policy_applicator.h"
#include "chromeos/ash/components/network/profile_policies.h"
#include "chromeos/ash/components/network/text_message_suppression_state.h"
#include "components/prefs/pref_service.h"

class PrefService;

namespace base {
class Value;
}  // namespace base

namespace ash {

class CellularPolicyHandler;
class ManagedCellularPrefHandler;
class NetworkConfigurationHandler;
struct NetworkProfile;
class NetworkProfileHandler;
class NetworkStateHandler;
class HotspotController;

class COMPONENT_EXPORT(CHROMEOS_NETWORK) ManagedNetworkConfigurationHandlerImpl
    : public ManagedNetworkConfigurationHandler,
      public NetworkProfileObserver,
      public PolicyApplicator::ConfigurationHandler {
 public:
  ManagedNetworkConfigurationHandlerImpl(
      const ManagedNetworkConfigurationHandlerImpl&) = delete;
  ManagedNetworkConfigurationHandlerImpl& operator=(
      const ManagedNetworkConfigurationHandlerImpl&) = delete;

  ~ManagedNetworkConfigurationHandlerImpl() override;

  // ManagedNetworkConfigurationHandler overrides
  void AddObserver(NetworkPolicyObserver* observer) override;
  void RemoveObserver(NetworkPolicyObserver* observer) override;
  bool HasObserver(NetworkPolicyObserver* observer) const override;

  void GetProperties(const std::string& userhash,
                     const std::string& service_path,
                     network_handler::PropertiesCallback callback) override;

  void GetManagedProperties(
      const std::string& userhash,
      const std::string& service_path,
      network_handler::PropertiesCallback callback) override;

  void SetProperties(const std::string& service_path,
                     const base::Value::Dict& user_settings,
                     base::OnceClosure callback,
                     network_handler::ErrorCallback error_callback) override;

  void ClearShillProperties(
      const std::string& service_path,
      const std::vector<std::string>& names,
      base::OnceClosure callback,
      network_handler::ErrorCallback error_callback) override;

  void CreateConfiguration(
      const std::string& userhash,
      const base::Value::Dict& properties,
      network_handler::ServiceResultCallback callback,
      network_handler::ErrorCallback error_callback) const override;

  void ConfigurePolicyNetwork(const base::Value::Dict& shill_properties,
                              base::OnceClosure callback) const override;

  void RemoveConfiguration(
      const std::string& service_path,
      base::OnceClosure callback,
      network_handler::ErrorCallback error_callback) const override;

  void RemoveConfigurationFromCurrentProfile(
      const std::string& service_path,
      base::OnceClosure callback,
      network_handler::ErrorCallback error_callback) const override;

  void SetPolicy(::onc::ONCSource onc_source,
                 const std::string& userhash,
                 const base::Value::List& network_configs_onc,
                 const base::Value::Dict& global_network_config) override;

  bool IsAnyPolicyApplicationRunning() const override;

  void SetProfileWideVariableExpansions(
      const std::string& userhash,
      base::flat_map<std::string, std::string> expansions) override;

  bool SetResolvedClientCertificate(
      const std::string& userhash,
      const std::string& guid,
      client_cert::ResolvedCert resolved_cert) override;

  const base::Value::Dict* FindPolicyByGUID(
      const std::string userhash,
      const std::string& guid,
      ::onc::ONCSource* onc_source) const override;

  void ResetDNSProperties(const std::string& service_path) override;

  bool HasAnyPolicyNetwork(const std::string& userhash) const override;

  const base::Value::Dict* GetGlobalConfigFromPolicy(
      const std::string& userhash) const override;

  const base::Value::Dict* FindPolicyByGuidAndProfile(
      const std::string& guid,
      const std::string& profile_path,
      PolicyType policy_type,
      ::onc::ONCSource* onc_source,
      std::string* userhash) const override;

  bool IsNetworkConfiguredByPolicy(
      const std::string& guid,
      const std::string& profile_path) const override;

  bool CanRemoveNetworkConfig(const std::string& guid,
                              const std::string& profile_path) const override;

  // This method should be called when the policy has been fully applied and is
  // reflected in NetworkStateHandler, so it is safe to notify observers.
  // Notifying observers is the last step of policy application to
  // |service_path|.
  void NotifyPolicyAppliedToNetwork(
      const std::string& service_path) const override;

  void TriggerEphemeralNetworkConfigActions() override;

  void TriggerCellularPolicyApplication(
      const NetworkProfile& profile,
      const base::flat_set<std::string>& new_cellular_policy_guids);
  void OnCellularPoliciesApplied(const NetworkProfile& profile) override;

  PolicyTextMessageSuppressionState GetAllowTextMessages() const override;
  bool AllowApnModification() const override;
  bool AllowCellularSimLock() const override;
  bool AllowCellularHotspot() const override;
  bool AllowOnlyPolicyCellularNetworks() const override;
  bool AllowOnlyPolicyWiFiToConnect() const override;
  bool AllowOnlyPolicyWiFiToConnectIfAvailable() const override;
  bool AllowOnlyPolicyNetworksToAutoconnect() const override;
  bool IsProhibitedFromConfiguringVpn() const override;

  bool RecommendedValuesAreEphemeral() const override;
  bool UserCreatedNetworkConfigurationsAreEphemeral() const override;
  std::vector<std::string> GetBlockedHexSSIDs() const override;

  // NetworkProfileObserver overrides
  void OnProfileAdded(const NetworkProfile& profile) override;
  void OnProfileRemoved(const NetworkProfile& profile) override;

  // PolicyApplicator::ConfigurationHandler overrides
  void CreateConfigurationFromPolicy(const base::Value::Dict& shill_properties,
                                     base::OnceClosure callback) override;

  void UpdateExistingConfigurationWithPropertiesFromPolicy(
      const base::Value::Dict& existing_properties,
      const base::Value::Dict& new_properties,
      base::OnceClosure callback) override;

  void OnEnterpriseMonitoredWebPoliciesApplied() const override;

  void OnPoliciesApplied(
      const NetworkProfile& profile,
      const base::flat_set<std::string>& new_cellular_policy_guids) override;

  void Shutdown() override;

 private:
  friend class AutoConnectHandlerTest;
  friend class ClientCertResolverTest;
  friend class ESimPolicyLoginMetricsLoggerTest;
  friend class ManagedNetworkConfigurationHandler;
  friend class ManagedNetworkConfigurationHandlerTest;
  friend class ManagedNetworkConfigurationHandlerMockTest;
  friend class NetworkConnectionHandlerImplTest;
  friend class NetworkHandler;
  friend class ProhibitedTechnologiesHandlerTest;

  // This structure holds information about the status of ONC network policy
  // application for a shill profile.
  // ManagedNetworkConfigurationHandler maintains a map shill profile ->
  // PolicyApplicationInfo.
  struct PolicyApplicationInfo {
    PolicyApplicationInfo();
    ~PolicyApplicationInfo();

    // Moveable type
    PolicyApplicationInfo(const PolicyApplicationInfo& other) = delete;
    PolicyApplicationInfo& operator=(const PolicyApplicationInfo& other) =
        delete;
    PolicyApplicationInfo(PolicyApplicationInfo&& other);
    PolicyApplicationInfo& operator=(PolicyApplicationInfo&& other);

    bool IsRunningOrRequired() const {
      return application_required || running_policy_applicator;
    }

    // Holds the set of ONC NetworkConfiguration GUIDs which have been modified
    // since network policy has been last applied.
    base::flat_set<std::string> modified_policy_guids;
    // Additional PolicyApplicator options.
    PolicyApplicator::Options options;
    // If true, network policy application needs to happen for this shill
    // profile, i.e. there were network policy changes that have not been
    // applied yet. Note that this can be true even if |modified_policy_guids|
    // is empty, e.g. if an ONC GlobalNetworkConfiguration parameter (which
    // affects all networks in this shill profile) has changed, but the settings
    // of the individual NetworkConfigurations remained the same.
    bool application_required = false;
    // If true, a task has already been scheduled to actually apply network
    // policy for this shill profile.
    bool task_scheduled = false;
    // If present, network policy is currently being applied (which is an
    // asynchronous process). The PolicyApplicator instance is responsible for
    // applying it.
    std::unique_ptr<PolicyApplicator> running_policy_applicator;
  };

  using UserToPoliciesMap =
      base::flat_map<std::string, std::unique_ptr<ProfilePolicies>>;
  using UserToPolicyApplicationInfo =
      base::flat_map<std::string, PolicyApplicationInfo>;

  // The type of properties to send after a Get{Managed}Properties call.
  enum class PropertiesType {
    kUnmanaged,
    kManaged,
  };

  ManagedNetworkConfigurationHandlerImpl();

  // Handlers may be null in tests so long as they do not execute any paths
  // that require the handlers.
  void Init(CellularPolicyHandler* cellular_policy_handler,
            ManagedCellularPrefHandler* managed_cellular_pref_handler,
            NetworkStateHandler* network_state_handler,
            NetworkProfileHandler* network_profile_handler,
            NetworkConfigurationHandler* network_configuration_handler,
            NetworkDeviceHandler* network_device_handler,
            ProhibitedTechnologiesHandler* prohibited_technologies_handler,
            HotspotController* hotspot_controller);

  // Returns the ProfilePolicies for the given |userhash|, or the device
  // policies if |userhash| is empty. Creates the ProfilePolicies entry if it
  // does not exist yet.
  ProfilePolicies* GetOrCreatePoliciesForUser(const std::string& userhash);
  // Returns the ProfilePolicies for the given |userhash|, or the device
  // policies if |userhash| is empty.
  const ProfilePolicies* GetPoliciesForUser(const std::string& userhash) const;
  // Returns the ProfilePolicies for the given network |profile|. These could be
  // either user or device policies.
  const ProfilePolicies* GetPoliciesForProfile(
      const NetworkProfile& profile) const;

  // Called when a policy identified by |guid| has been applied to the network
  // identified by |service_path|. Notifies observers and calls |callback|.
  void OnPolicyAppliedToNetwork(base::OnceClosure callback,
                                const std::string& service_path,
                                const std::string& guid) const;

  // Helper method to append associated Device properties to |properties|.
  void GetDeviceStateProperties(const std::string& service_path,
                                base::Value::Dict* properties);

  // Callback for NetworkConfigurationHandler::GetProperties requests from
  // Get{Managed}Properties. This callback fills in properties from
  // DeviceState and may request additional Device properties.
  // Note: Requesting Device properties requires an additional fetch and
  // additional copying of data, so we only do it for Cellular networks which
  // contain a lot of necessary state in the associated Device object.
  void GetPropertiesCallback(PropertiesType properties_type,
                             const std::string& userhash,
                             network_handler::PropertiesCallback callback,
                             const std::string& service_path,
                             std::optional<base::Value::Dict> shill_properties);

  // Implemented as a callback for GetProperties, fetches Type,
  // IPAddressConfig, StaticIPConfig, and changes the
  // NameServersConfigType ONC property to be automatically set by DHCP and
  // applies it to a specific network device.
  void ResetDNSPropertiesCallback(
      const std::string& service_path,
      std::optional<base::Value::Dict> network_properties,
      std::optional<std::string> error);

  void OnGetDeviceProperties(
      PropertiesType properties_type,
      const std::string& userhash,
      const std::string& service_path,
      network_handler::PropertiesCallback callback,
      std::optional<base::Value::Dict> network_properties,
      const std::string& device_path,
      std::optional<base::Value::Dict> device_properties);

  void SendProperties(PropertiesType properties_type,
                      const std::string& userhash,
                      const std::string& service_path,
                      network_handler::PropertiesCallback callback,
                      std::optional<base::Value::Dict> shill_properties);

  // Called from SetProperties, calls NCH::SetShillProperties.
  void SetShillProperties(const std::string& service_path,
                          base::Value::Dict shill_dictionary,
                          base::OnceClosure callback,
                          network_handler::ErrorCallback error_callback);

  // Sets the active proxy values in managed network configurations depending on
  // the source of the configuration. Proxy enforced by user policy
  // (provided by kProxy preference) should have precedence over configurations
  // set by ONC policy.
  void SetManagedActiveProxyValues(const std::string& guid,
                                   base::Value::Dict* dictionary);

  // Applies policies for |userhash|.
  // |modified_policies| contains the GUIDs of the network configurations that
  // changed since the last policy application. |can_affect_other_networks|
  // should be true if the operation that led to this call may have changed
  // effective settings of network configurations that are not in the
  // |modified_policies| list, e.g. because a global network setting has
  // changed.
  void ApplyOrQueuePolicies(const std::string& userhash,
                            base::flat_set<std::string> modified_policies,
                            bool can_affect_other_networks,
                            PolicyApplicator::Options options);

  // Called in SetPolicy, sets shill DisconnectWiFiOnEthernet Manager property
  // base on value of DisconnectWiFiOnEthernet GlobalNetworkConfiguration.
  void ApplyDisconnectWiFiOnEthernetPolicy();

  void SchedulePolicyApplication(const std::string& userhash);
  void StartPolicyApplication(const std::string& userhash);

  // Based on the admin policy to allow usage of custom APNs, this method sets
  // or clears custom apn list in shill properties.
  void ModifyCustomAPNs();

  void set_ui_proxy_config_service(
      UIProxyConfigService* ui_proxy_config_service);

  void set_user_prefs(PrefService* user_prefs);

  NetworkMetadataStore* GetNetworkMetadataStore();

  void set_network_metadata_store_for_testing(
      NetworkMetadataStore* network_metadata_store_for_testing) {
    network_metadata_store_for_testing_ = network_metadata_store_for_testing;
  }

  // Returns the device policy GlobalNetworkConfiguration boolean value under
  // `key` or `std::nullopt` if such a value doesn't exist or is not of type
  // BOOLEAN.
  std::optional<bool> FindGlobalPolicyBool(std::string_view key) const;
  // Returns the device policy GlobalNetworkConfiguration List value under
  // `key` or `nullptr` if such a value doesn't exist or is not of type LIST.
  const base::Value::List* FindGlobalPolicyList(std::string_view key) const;
  // Returns the device policy GlobalNetworkConfiguration string value under
  // `key` or `nullptr` if such a value doesn't exist or is not of type STRING.
  const std::string* FindGlobalPolicyString(std::string_view key) const;

  // If present, the empty string maps to the device policy.
  UserToPoliciesMap policies_by_user_;

  // Local references to the associated handler instances.
  raw_ptr<CellularPolicyHandler, DanglingUntriaged> cellular_policy_handler_ =
      nullptr;
  raw_ptr<ManagedCellularPrefHandler, DanglingUntriaged>
      managed_cellular_pref_handler_ = nullptr;
  raw_ptr<NetworkStateHandler, DanglingUntriaged> network_state_handler_ =
      nullptr;
  raw_ptr<NetworkProfileHandler> network_profile_handler_ = nullptr;
  raw_ptr<NetworkConfigurationHandler, DanglingUntriaged>
      network_configuration_handler_ = nullptr;
  raw_ptr<NetworkDeviceHandler, DanglingUntriaged> network_device_handler_ =
      nullptr;
  raw_ptr<ProhibitedTechnologiesHandler, DanglingUntriaged>
      prohibited_technologies_handler_ = nullptr;
  raw_ptr<UIProxyConfigService, DanglingUntriaged> ui_proxy_config_service_ =
      nullptr;
  raw_ptr<HotspotController, DanglingUntriaged> hotspot_controller_ = nullptr;
  raw_ptr<NetworkMetadataStore> network_metadata_store_for_testing_ = nullptr;

  // Initialized to null and set once SetUserPrefs() is called.
  raw_ptr<PrefService> user_prefs_ = nullptr;

  UserToPolicyApplicationInfo policy_application_info_map_;

  base::ObserverList<NetworkPolicyObserver, true>::Unchecked observers_;

  bool user_policy_applied_ = false;
  bool device_policy_applied_ = false;
  // Ensure that Shutdown() gets called exactly once.
  bool did_shutdown_ = false;

  // For Shill client callbacks
  base::WeakPtrFactory<ManagedNetworkConfigurationHandlerImpl>
      weak_ptr_factory_{this};
};

}  // namespace ash

#endif  // CHROMEOS_ASH_COMPONENTS_NETWORK_MANAGED_NETWORK_CONFIGURATION_HANDLER_IMPL_H_