1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 227 228 229 230 231 232 233 234 235 236 237 238 239 240 241 242 243 244 245 246 247 248 249 250 251 252 253 254 255 256 257 258 259 260 261 262 263 264 265 266 267 268 269 270 271 272 273 274 275 276 277 278 279 280 281 282 283 284 285 286 287 288 289 290 291 292 293
|
// 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 <variant>
#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 "chrome/browser/ash/policy/invalidation/affiliated_invalidation_service_provider.h"
#include "chrome/browser/chromeos/platform_keys/platform_keys.h"
#include "chromeos/ash/components/network/network_state_handler_observer.h"
#include "components/invalidation/invalidation_listener.h"
#include "components/prefs/pref_change_registrar.h"
class Profile;
class PrefService;
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);
static std::unique_ptr<CertProvisioningScheduler>
CreateDeviceCertProvisioningScheduler(
policy::CloudPolicyClient* cloud_policy_client,
std::variant<policy::AffiliatedInvalidationServiceProvider*,
invalidation::InvalidationListener*>
invalidation_service_provider_or_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);
// 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_
|