| // 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. |
| |
| #ifndef CHROME_BROWSER_ASH_CERT_PROVISIONING_CERT_PROVISIONING_SCHEDULER_H_ |
| #define CHROME_BROWSER_ASH_CERT_PROVISIONING_CERT_PROVISIONING_SCHEDULER_H_ |
| |
| #include <vector> |
| |
| #include "base/callback_list.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/scoped_observation.h" |
| #include "base/sequence_checker.h" |
| #include "base/time/time.h" |
| #include "base/timer/timer.h" |
| #include "chrome/browser/ash/cert_provisioning/cert_provisioning_common.h" |
| #include "chrome/browser/ash/cert_provisioning/cert_provisioning_invalidator.h" |
| #include "chrome/browser/ash/cert_provisioning/cert_provisioning_platform_keys_helpers.h" |
| #include "chrome/browser/ash/platform_keys/platform_keys_service.h" |
| #include "chromeos/ash/components/network/network_state_handler_observer.h" |
| #include "chromeos/ash/components/platform_keys/platform_keys.h" |
| #include "components/prefs/pref_change_registrar.h" |
| |
| class Profile; |
| class PrefService; |
| |
| namespace invalidation { |
| class InvalidationListener; |
| } // namespace invalidation |
| |
| namespace policy { |
| class CloudPolicyClient; |
| } // namespace policy |
| |
| namespace ash { |
| |
| class NetworkStateHandler; |
| |
| namespace cert_provisioning { |
| |
| class CertProvisioningClient; |
| class CertProvisioningWorker; |
| |
| using WorkerMap = |
| std::map<CertProfileId, std::unique_ptr<CertProvisioningWorker>>; |
| |
| using CertProfileSet = base::flat_set<CertProfile, CertProfileComparator>; |
| |
| // Holds information about a worker which failed that is still useful (e.g. for |
| // UI) after the worker has been destroyed. |
| struct FailedWorkerInfo { |
| FailedWorkerInfo(); |
| ~FailedWorkerInfo(); |
| FailedWorkerInfo(const FailedWorkerInfo&); |
| FailedWorkerInfo& operator=(const FailedWorkerInfo&); |
| |
| // The ID of the certificate provisioning process. |
| std::string process_id; |
| // The state the worker had prior to switching to the failed state |
| // (CertProvisioningWorkerState::kFailed). |
| CertProvisioningWorkerState state_before_failure = |
| CertProvisioningWorkerState::kInitState; |
| // The DER-encoded X.509 SPKI. |
| std::vector<uint8_t> public_key; |
| // Human-readable certificate profile name (UTF-8). |
| std::string cert_profile_name; |
| // The time the worker was last updated, i.e. when it transferred to the |
| // failed state. |
| base::Time last_update_time; |
| // Holds a message describing the reason for the failure. |
| std::string failure_message; |
| }; |
| |
| // Interface for the scheduler for client certificate provisioning using device |
| // management. |
| class CertProvisioningScheduler { |
| public: |
| virtual ~CertProvisioningScheduler() = default; |
| |
| // Intended to be called when a user presses a button in certificate manager |
| // UI. Retries the process of provisioning a specific certificate. |
| // Returns "false" if `cert_profile_id` is not found and "true" otherwise. |
| virtual bool UpdateOneWorker(const CertProfileId& cert_profile_id) = 0; |
| virtual void UpdateAllWorkers() = 0; |
| // Resets the process of provisioning a specific certificate. |
| // Returns "false" if `cert_profile_id` is not found and "true" otherwise. |
| virtual bool ResetOneWorker(const CertProfileId& cert_profile_id) = 0; |
| |
| // Returns all certificate provisioning workers that are currently active. |
| virtual const WorkerMap& GetWorkers() const = 0; |
| |
| // Returns a |FailedWorkerInfo| for certificate provisioning processes that |
| // failed and have not been restarted (yet). |
| virtual const base::flat_map<CertProfileId, FailedWorkerInfo>& |
| GetFailedCertProfileIds() const = 0; |
| |
| // Saves the |callback| to call it when the "visible state" of the scheduler |
| // changes, i.e. |
| // (*) the list of active workers changes, |
| // (*) the list of recently failed workers changes, |
| // (*) the state of a worker changes. |
| // (As long as the returned subscription is alive.) |
| virtual base::CallbackListSubscription AddObserver( |
| base::RepeatingClosure callback) = 0; |
| }; |
| |
| // This class is a part of certificate provisioning feature. It tracks updates |
| // of |RequiredClientCertificateForUser|, |RequiredClientCertificateForDevice| |
| // policies and creates one CertProvisioningWorker for every policy entry. |
| // Should work on the UI thread because it interacts with PlatformKeysService |
| // and some methods are called from the UI to populate certificate manager |
| // settings page. |
| class CertProvisioningSchedulerImpl |
| : public CertProvisioningScheduler, |
| public NetworkStateHandlerObserver, |
| public platform_keys::PlatformKeysServiceObserver { |
| public: |
| static std::unique_ptr<CertProvisioningScheduler> |
| CreateUserCertProvisioningScheduler(Profile* profile); |
| |
| // `local_state` must be non-null, and must outlive the returned object. |
| static std::unique_ptr<CertProvisioningScheduler> |
| CreateDeviceCertProvisioningScheduler( |
| PrefService* local_state, |
| policy::CloudPolicyClient* cloud_policy_client, |
| invalidation::InvalidationListener* invalidation_listener); |
| |
| CertProvisioningSchedulerImpl( |
| CertScope cert_scope, |
| Profile* profile, |
| PrefService* pref_service, |
| std::unique_ptr<CertProvisioningClient> cert_provisioning_client, |
| platform_keys::PlatformKeysService* platform_keys_service, |
| NetworkStateHandler* network_state_handler, |
| std::unique_ptr<CertProvisioningInvalidatorFactory> invalidator_factory); |
| ~CertProvisioningSchedulerImpl() override; |
| |
| CertProvisioningSchedulerImpl(const CertProvisioningSchedulerImpl&) = delete; |
| CertProvisioningSchedulerImpl& operator=( |
| const CertProvisioningSchedulerImpl&) = delete; |
| |
| // CertProvisioningScheduler: |
| bool UpdateOneWorker(const CertProfileId& cert_profile_id) override; |
| void UpdateAllWorkers() override; |
| bool ResetOneWorker(const CertProfileId& cert_profile_id) override; |
| const WorkerMap& GetWorkers() const override; |
| const base::flat_map<CertProfileId, FailedWorkerInfo>& |
| GetFailedCertProfileIds() const override; |
| base::CallbackListSubscription AddObserver( |
| base::RepeatingClosure callback) override; |
| |
| // Invoked when the CertProvisioningWorker corresponding to |profile| reached |
| // its final state. |
| // Public so it can be called from tests. |
| void OnProfileFinished(CertProfile profile, |
| std::string process_id, |
| CertProvisioningWorkerState state); |
| |
| // Called when any state visible from the outside has changed. |
| // Public so it can be called from tests. |
| void OnVisibleStateChanged(); |
| |
| private: |
| void ScheduleInitialUpdate(); |
| void ScheduleDailyUpdate(); |
| // Posts delayed task to call UpdateOneWorkerImpl. |
| void ScheduleRetry(const CertProfileId& profile_id); |
| void ScheduleRenewal(const CertProfileId& profile_id, base::TimeDelta delay); |
| |
| void InitialUpdateCerts(); |
| void DeleteCertsWithoutPolicy(); |
| void OnDeleteCertsWithoutPolicyDone(chromeos::platform_keys::Status status); |
| void CancelWorkersWithoutPolicy(const std::vector<CertProfile>& profiles); |
| void CleanVaKeysIfIdle(); |
| void OnCleanVaKeysIfIdleDone(bool delete_result); |
| void RegisterForPrefsChanges(); |
| |
| void InitiateRenewal(const CertProfileId& cert_profile_id); |
| void UpdateOneWorkerImpl(const CertProfileId& cert_profile_id); |
| void UpdateWorkerList(std::vector<CertProfile> profiles); |
| void UpdateWorkerListWithExistingCerts( |
| std::vector<CertProfile> profiles, |
| base::flat_map<CertProfileId, scoped_refptr<net::X509Certificate>> |
| existing_certs_with_ids, |
| chromeos::platform_keys::Status status); |
| |
| void OnPrefsChange(); |
| void DailyUpdateWorkers(); |
| void DeserializeWorkers(); |
| |
| // Creates a new worker for |profile| if there is no at the moment. |
| // Recreates a worker if existing one has a different version of the profile. |
| // Continues an existing worker if it is in a waiting state. |
| void ProcessProfile(const CertProfile& profile); |
| |
| std::optional<CertProfile> GetOneCertProfile( |
| const CertProfileId& cert_profile_id); |
| std::vector<CertProfile> GetCertProfiles(); |
| |
| void CreateCertProvisioningWorker(CertProfile profile); |
| CertProvisioningWorker* FindWorker(CertProfileId profile_id); |
| // Adds |worker| to |workers_| and returns an unowned pointer to |worker|. |
| // Triggers a state change notification. |
| CertProvisioningWorker* AddWorkerToMap( |
| std::unique_ptr<CertProvisioningWorker> worker); |
| // Removes the element referenced by |worker_iter| from |workers_|. |
| // Triggers a state change notification if send_visible_state_changed_update |
| // is true. |
| void RemoveWorkerFromMap(WorkerMap::iterator worker_iter, |
| bool send_visible_state_changed_update); |
| // Removes the failed worker with `cert_profile_id` and notifies the |
| // observers. |
| void RemoveFailedWorker(const CertProfileId& cert_profile_id); |
| // Removes all failed workers and notifies the observers. |
| void ClearFailedWorkers(); |
| |
| // Returns true if the process can be continued (if it's not required to |
| // wait). |
| bool MaybeWaitForInternetConnection(); |
| void WaitForInternetConnection(); |
| void OnNetworkChange(const NetworkState* network); |
| // NetworkStateHandlerObserver |
| void DefaultNetworkChanged(const NetworkState* network) override; |
| void NetworkConnectionStateChanged(const NetworkState* network) override; |
| |
| void UpdateFailedCertProfiles(const CertProvisioningWorker& worker); |
| |
| // PlatformKeysServiceObserver |
| void OnPlatformKeysServiceShutDown() override; |
| |
| // Called by |hold_back_updates_timer_| when the notifications should be sent |
| // again. Notifies observers if there were any events during the hold back |
| // period. |
| void OnHoldBackUpdatesTimerExpired(); |
| // Notifies each observer from |observers_| that the state has changed. |
| void NotifyObserversVisibleStateChanged(); |
| |
| CertScope cert_scope_ = CertScope::kUser; |
| // |profile_| can be nullptr for the device-wide instance of |
| // CertProvisioningScheduler. |
| raw_ptr<Profile> profile_ = nullptr; |
| raw_ptr<PrefService> pref_service_ = nullptr; |
| const char* pref_name_ = nullptr; |
| std::unique_ptr<CertProvisioningClient> cert_provisioning_client_; |
| // |platform_keys_service_| can be nullptr if it has been shut down. |
| raw_ptr<platform_keys::PlatformKeysService> platform_keys_service_ = nullptr; |
| raw_ptr<NetworkStateHandler> network_state_handler_ = nullptr; |
| base::ScopedObservation<NetworkStateHandler, NetworkStateHandlerObserver> |
| network_state_handler_observer_{this}; |
| |
| PrefChangeRegistrar pref_change_registrar_; |
| WorkerMap workers_; |
| // Contains cert profile ids that will be renewed before next daily update. |
| // Helps to prevent creation of more than one delayed task for renewal. When |
| // the renewal starts for a profile id, it is removed from the set. |
| base::flat_set<CertProfileId> scheduled_renewals_; |
| // Collection of cert profile ids that failed recently. They will not be |
| // retried until next |DailyUpdateWorkers|. FailedWorkerInfo contains some |
| // extra information about the failure. Profiles that failed with |
| // kInconsistentDataError will not be stored into this collection. |
| base::flat_map<CertProfileId, FailedWorkerInfo> failed_cert_profiles_; |
| // Equals true if the last attempt to update certificates failed because there |
| // was no internet connection. |
| bool is_waiting_for_online_ = false; |
| |
| // Contains profiles that should be updated after the current update batch |
| // run, because an update for them was triggered during the current run. |
| CertProfileSet queued_profiles_to_update_; |
| |
| LatestCertsWithIdsGetter certs_with_ids_getter_; |
| CertDeleter cert_deleter_; |
| std::unique_ptr<CertProvisioningInvalidatorFactory> invalidator_factory_; |
| |
| // Observers that are observing this CertProvisioningSchedulerImpl. |
| base::RepeatingClosureList observers_; |
| // True when a task for notifying observers about a state change has been |
| // scheduled but not executed yet. |
| bool notify_observers_pending_ = false; |
| // When this timer is running, notifications should not be sent until it |
| // fires. Used to prevent spamming the observers if many events happen in |
| // rapid succession. |
| base::OneShotTimer hold_back_updates_timer_; |
| // When this is true, an update should be sent to the UI when |
| // |hold_back_updates_timer_| fires. |
| bool update_after_hold_back_ = false; |
| |
| base::ScopedObservation<platform_keys::PlatformKeysService, |
| platform_keys::PlatformKeysServiceObserver> |
| scoped_platform_keys_service_observation_{this}; |
| |
| base::WeakPtrFactory<CertProvisioningSchedulerImpl> weak_factory_{this}; |
| }; |
| |
| } // namespace cert_provisioning |
| } // namespace ash |
| |
| #endif // CHROME_BROWSER_ASH_CERT_PROVISIONING_CERT_PROVISIONING_SCHEDULER_H_ |