Commit 2bfd4c13 authored by Josh Nohle's avatar Josh Nohle Committed by Commit Bot

[DeviceSync v2] Add CryptAuthV2DeviceManager

Adds the abstract base class CryptAuthV2DeviceManager as well as a
skeleton implementation, CryptAuthV2DeviceManagerImpl. These are
top-level classes that coordinate CryptAuth v2 DeviceSync requests and
local data storage between the CryptAuthScheduler,
CryptAuthDeviceRegistry, CryptAuthKeyRegistry, and CryptAuthGCMManager.
They also provide a top-level API for retrieving synced devices, forcing
v2 DeviceSyncs, and accessing v2 DeviceSync request data such as last
success time.

The actual logic needed to perform the CryptAuth v2 DeviceSync flow will
be delegated to a CryptAuthDeviceSyncer class that is not yet
implemented.

This class will operate in parallel with its CryptAuth v1 DeviceSync
analog, CryptAuthDeviceManager. The CryptAuth v2 Enrollment analog is
CryptAuthV2EnrollmentManagerImpl.

Bug: 951969
Change-Id: I033c9f14102573cd3e057938b28882aa2edba12c
Reviewed-on: https://chromium-review.googlesource.com/c/chromium/src/+/1638351
Commit-Queue: Josh Nohle <nohle@chromium.org>
Reviewed-by: default avatarKyle Horimoto <khorimoto@chromium.org>
Cr-Commit-Position: refs/heads/master@{#667283}
parent 4f5cdcf5
...@@ -63,6 +63,10 @@ static_library("device_sync") { ...@@ -63,6 +63,10 @@ static_library("device_sync") {
"cryptauth_scheduler.h", "cryptauth_scheduler.h",
"cryptauth_scheduler_impl.cc", "cryptauth_scheduler_impl.cc",
"cryptauth_scheduler_impl.h", "cryptauth_scheduler_impl.h",
"cryptauth_v2_device_manager.cc",
"cryptauth_v2_device_manager.h",
"cryptauth_v2_device_manager_impl.cc",
"cryptauth_v2_device_manager_impl.h",
"cryptauth_v2_enroller.cc", "cryptauth_v2_enroller.cc",
"cryptauth_v2_enroller.h", "cryptauth_v2_enroller.h",
"cryptauth_v2_enroller_impl.cc", "cryptauth_v2_enroller_impl.cc",
......
...@@ -15,10 +15,8 @@ namespace chromeos { ...@@ -15,10 +15,8 @@ namespace chromeos {
namespace device_sync { namespace device_sync {
// Information about the result of a CryptAuth v2 DeviceSync attempt. // Information about the result of a CryptAuth v2 DeviceSync attempt.
// // TODO(nohle): Add a HaveDevicesChanged() function that returns true if the
// These values are persisted to logs. Entries should not be renumbered and // synced-device registry changes.
// numeric values should never be reused. If entries are added, kMaxValue should
// be updated.
class CryptAuthDeviceSyncResult { class CryptAuthDeviceSyncResult {
public: public:
// Enum class to denote the result of a CryptAuth v2 DeviceSync attempt. // Enum class to denote the result of a CryptAuth v2 DeviceSync attempt.
......
...@@ -45,10 +45,9 @@ class CryptAuthEnrollmentManager { ...@@ -45,10 +45,9 @@ class CryptAuthEnrollmentManager {
// Begins scheduling periodic enrollment attempts. // Begins scheduling periodic enrollment attempts.
virtual void Start() = 0; virtual void Start() = 0;
// Skips the waiting period and forces an enrollment immediately. If an // Skips the waiting period and requests an immediate enrollment.
// enrollment is already in progress, this function does nothing.
// |invocation_reason|: Specifies the reason that the enrollment was // |invocation_reason|: Specifies the reason that the enrollment was
// triggered, which is upload to the server. // triggered, which is uploaded to the server.
// |session_id|: The session ID sent by CryptAuth v2 in a GCM message // |session_id|: The session ID sent by CryptAuth v2 in a GCM message
// requesting enrollment. Null if enrollment was not triggered // requesting enrollment. Null if enrollment was not triggered
// by a GCM message or if no session ID was included in the GCM // by a GCM message or if no session ID was included in the GCM
......
// Copyright 2019 The Chromium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
#include "chromeos/services/device_sync/cryptauth_v2_device_manager.h"
namespace chromeos {
namespace device_sync {
CryptAuthV2DeviceManager::CryptAuthV2DeviceManager() = default;
CryptAuthV2DeviceManager::~CryptAuthV2DeviceManager() = default;
void CryptAuthV2DeviceManager::AddObserver(Observer* observer) {
observers_.AddObserver(observer);
}
void CryptAuthV2DeviceManager::RemoveObserver(Observer* observer) {
observers_.RemoveObserver(observer);
}
void CryptAuthV2DeviceManager::NotifyDeviceSyncStarted(
const cryptauthv2::ClientMetadata& client_metadata) {
for (auto& observer : observers_)
observer.OnDeviceSyncStarted(client_metadata);
}
void CryptAuthV2DeviceManager::NotifyDeviceSyncFinished(
const CryptAuthDeviceSyncResult& device_sync_result) {
for (auto& observer : observers_)
observer.OnDeviceSyncFinished(device_sync_result);
}
} // namespace device_sync
} // namespace chromeos
// Copyright 2019 The Chromium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
#ifndef CHROMEOS_SERVICES_DEVICE_SYNC_CRYPTAUTH_V2_DEVICE_MANAGER_H_
#define CHROMEOS_SERVICES_DEVICE_SYNC_CRYPTAUTH_V2_DEVICE_MANAGER_H_
#include <string>
#include "base/macros.h"
#include "base/observer_list.h"
#include "base/observer_list_types.h"
#include "base/optional.h"
#include "base/time/time.h"
#include "chromeos/services/device_sync/cryptauth_device.h"
#include "chromeos/services/device_sync/cryptauth_device_registry.h"
#include "chromeos/services/device_sync/cryptauth_device_sync_result.h"
#include "chromeos/services/device_sync/proto/cryptauth_common.pb.h"
namespace chromeos {
namespace device_sync {
// Manages syncing the user's devices that are registered with CryptAuth v2's
// "DeviceSync:BetterTogether" group.
class CryptAuthV2DeviceManager {
public:
class Observer : public base::CheckedObserver {
public:
virtual void OnDeviceSyncStarted(
const cryptauthv2::ClientMetadata& client_metadata) {}
virtual void OnDeviceSyncFinished(
const CryptAuthDeviceSyncResult& device_sync_result) {}
};
virtual ~CryptAuthV2DeviceManager();
void AddObserver(Observer* observer);
void RemoveObserver(Observer* observer);
// Starts DeviceSync v2 scheduling. Should only be called once.
virtual void Start() = 0;
// Returns a map from Instance ID to CryptAuthDevice of synced devices. This
// method makes no calls to CryptAuth, instead returning the local cache of
// devices from the most recent DeviceSync.
virtual const CryptAuthDeviceRegistry::InstanceIdToDeviceMap&
GetSyncedDevices() const = 0;
// Requests an immediate v2 DeviceSync.
// |invocation_reason|: Specifies the reason that the DeviceSync was
// triggered, which is uploaded to the server.
// |session_id|: The session ID sent by CryptAuth v2 in a GCM message
// requesting a DeviceSync. Null if DeviceSync was not triggered
// by a GCM message or if no session ID was included in the GCM
// message.
virtual void ForceDeviceSyncNow(
const cryptauthv2::ClientMetadata::InvocationReason&,
const base::Optional<std::string>& session_id) = 0;
// Returns true if a v2 DeviceSync attempt is currently in progress.
virtual bool IsDeviceSyncInProgress() const = 0;
// Returns true if the last v2 DeviceSync attempt failed.
virtual bool IsRecoveringFromFailure() const = 0;
// Returns the time of the last successful v2 DeviceSync. Returns null if no
// successful v2 DeviceSync has ever occurred.
virtual base::Optional<base::Time> GetLastDeviceSyncTime() const = 0;
// Returns the time until the next scheduled v2 DeviceSync request. Returns
// null if there is no request scheduled.
virtual base::Optional<base::TimeDelta> GetTimeToNextAttempt() const = 0;
protected:
CryptAuthV2DeviceManager();
void NotifyDeviceSyncStarted(
const cryptauthv2::ClientMetadata& client_metadata);
void NotifyDeviceSyncFinished(
const CryptAuthDeviceSyncResult& device_sync_result);
private:
base::ObserverList<Observer> observers_;
DISALLOW_COPY_AND_ASSIGN(CryptAuthV2DeviceManager);
};
} // namespace device_sync
} // namespace chromeos
#endif // CHROMEOS_SERVICES_DEVICE_SYNC_CRYPTAUTH_V2_DEVICE_MANAGER_H_
// Copyright 2019 The Chromium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
#include "chromeos/services/device_sync/cryptauth_v2_device_manager_impl.h"
#include "base/memory/ptr_util.h"
#include "base/no_destructor.h"
#include "chromeos/components/multidevice/logging/logging.h"
#include "chromeos/services/device_sync/cryptauth_client.h"
#include "chromeos/services/device_sync/cryptauth_key_registry.h"
namespace chromeos {
namespace device_sync {
// static
CryptAuthV2DeviceManagerImpl::Factory*
CryptAuthV2DeviceManagerImpl::Factory::test_factory_ = nullptr;
// static
CryptAuthV2DeviceManagerImpl::Factory*
CryptAuthV2DeviceManagerImpl::Factory::Get() {
if (test_factory_)
return test_factory_;
static base::NoDestructor<CryptAuthV2DeviceManagerImpl::Factory> factory;
return factory.get();
}
// static
void CryptAuthV2DeviceManagerImpl::Factory::SetFactoryForTesting(
Factory* test_factory) {
test_factory_ = test_factory;
}
CryptAuthV2DeviceManagerImpl::Factory::~Factory() = default;
std::unique_ptr<CryptAuthV2DeviceManager>
CryptAuthV2DeviceManagerImpl::Factory::BuildInstance(
CryptAuthDeviceRegistry* device_registry,
CryptAuthKeyRegistry* key_registry,
CryptAuthClientFactory* client_factory,
CryptAuthGCMManager* gcm_manager,
CryptAuthScheduler* scheduler) {
return base::WrapUnique(new CryptAuthV2DeviceManagerImpl(
device_registry, key_registry, client_factory, gcm_manager, scheduler));
}
CryptAuthV2DeviceManagerImpl::CryptAuthV2DeviceManagerImpl(
CryptAuthDeviceRegistry* device_registry,
CryptAuthKeyRegistry* key_registry,
CryptAuthClientFactory* client_factory,
CryptAuthGCMManager* gcm_manager,
CryptAuthScheduler* scheduler)
: device_registry_(device_registry),
gcm_manager_(gcm_manager),
scheduler_(scheduler),
scheduler_weak_ptr_factory_(this) {
gcm_manager_->AddObserver(this);
}
CryptAuthV2DeviceManagerImpl::~CryptAuthV2DeviceManagerImpl() {
gcm_manager_->RemoveObserver(this);
}
void CryptAuthV2DeviceManagerImpl::Start() {
scheduler_->StartDeviceSyncScheduling(
scheduler_weak_ptr_factory_.GetWeakPtr());
}
const CryptAuthDeviceRegistry::InstanceIdToDeviceMap&
CryptAuthV2DeviceManagerImpl::GetSyncedDevices() const {
return device_registry_->instance_id_to_device_map();
}
void CryptAuthV2DeviceManagerImpl::ForceDeviceSyncNow(
const cryptauthv2::ClientMetadata::InvocationReason& invocation_reason,
const base::Optional<std::string>& session_id) {
scheduler_->RequestDeviceSync(invocation_reason, session_id);
}
base::Optional<base::Time> CryptAuthV2DeviceManagerImpl::GetLastDeviceSyncTime()
const {
return scheduler_->GetLastSuccessfulDeviceSyncTime();
}
base::Optional<base::TimeDelta>
CryptAuthV2DeviceManagerImpl::GetTimeToNextAttempt() const {
return scheduler_->GetTimeToNextDeviceSyncRequest();
}
bool CryptAuthV2DeviceManagerImpl::IsDeviceSyncInProgress() const {
return scheduler_->IsWaitingForDeviceSyncResult();
}
bool CryptAuthV2DeviceManagerImpl::IsRecoveringFromFailure() const {
return scheduler_->GetNumConsecutiveDeviceSyncFailures() > 0;
}
void CryptAuthV2DeviceManagerImpl::OnDeviceSyncRequested(
const cryptauthv2::ClientMetadata& client_metadata) {
NotifyDeviceSyncStarted(client_metadata);
current_client_metadata_ = client_metadata;
// TODO(nohle): Log invocation reason metric.
// TODO(nohle): Start DeviceSync flow here.
}
void CryptAuthV2DeviceManagerImpl::OnResyncMessage(
const base::Optional<std::string>& session_id,
const base::Optional<CryptAuthFeatureType>& feature_type) {
PA_LOG(VERBOSE) << "Received GCM message to re-sync devices (session ID: "
<< session_id.value_or("[No session ID]") << ")";
ForceDeviceSyncNow(cryptauthv2::ClientMetadata::SERVER_INITIATED, session_id);
}
void CryptAuthV2DeviceManagerImpl::OnDeviceSyncFinished(
const CryptAuthDeviceSyncResult& device_sync_result) {
// TODO(nohle): Invalidate callback weak pointers, if applicable, and reset
// the DeviceSyncer instance.
if (device_sync_result.IsSuccess()) {
PA_LOG(INFO) << "DeviceSync attempt with invocation reason "
<< current_client_metadata_->invocation_reason()
<< " succeeded with result code "
<< device_sync_result.result_code();
// TODO(nohle): Log if the devices changed.
} else {
PA_LOG(WARNING) << "DeviceSync attempt with invocation reason "
<< current_client_metadata_->invocation_reason()
<< " failed with result code "
<< device_sync_result.result_code();
}
current_client_metadata_.reset();
// TODO(nohle): Log DeviceSync result metrics: success, result code, and if
// devices changed.
scheduler_->HandleDeviceSyncResult(device_sync_result);
base::Optional<base::TimeDelta> time_to_next_attempt = GetTimeToNextAttempt();
if (time_to_next_attempt) {
PA_LOG(INFO) << "Time until next DeviceSync attempt: "
<< *time_to_next_attempt;
} else {
PA_LOG(INFO) << "No future DeviceSync requests currently scheduled";
}
if (!device_sync_result.IsSuccess()) {
PA_LOG(INFO) << "Number of consecutive Enrollment failures: "
<< scheduler_->GetNumConsecutiveEnrollmentFailures();
}
NotifyDeviceSyncFinished(device_sync_result);
}
} // namespace device_sync
} // namespace chromeos
// Copyright 2019 The Chromium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
#ifndef CHROMEOS_SERVICES_DEVICE_SYNC_CRYPTAUTH_V2_DEVICE_MANAGER_IMPL_H_
#define CHROMEOS_SERVICES_DEVICE_SYNC_CRYPTAUTH_V2_DEVICE_MANAGER_IMPL_H_
#include <memory>
#include <string>
#include "base/macros.h"
#include "base/memory/weak_ptr.h"
#include "base/optional.h"
#include "base/time/time.h"
#include "chromeos/services/device_sync/cryptauth_device_registry.h"
#include "chromeos/services/device_sync/cryptauth_device_sync_result.h"
#include "chromeos/services/device_sync/cryptauth_gcm_manager.h"
#include "chromeos/services/device_sync/cryptauth_scheduler.h"
#include "chromeos/services/device_sync/cryptauth_v2_device_manager.h"
#include "chromeos/services/device_sync/proto/cryptauth_common.pb.h"
namespace chromeos {
namespace device_sync {
class CryptAuthClientFactory;
class CryptAuthKeyRegistry;
// Implementation of CryptAuthV2DeviceManager that considers three sources of
// DeviceSync requests:
// 1) The scheduler requests a DeviceSync to recover from a failed attempt or
// after receiving an InvokeNext instruction from CryptAuth in a
// ClientDirective.
// 2) The device manager listens to the GCM manager for re-sync requests.
// 3) The ForceDeviceSyncNow() method allows for immediate requests.
class CryptAuthV2DeviceManagerImpl
: public CryptAuthV2DeviceManager,
public CryptAuthScheduler::DeviceSyncDelegate,
public CryptAuthGCMManager::Observer {
public:
class Factory {
public:
static Factory* Get();
static void SetFactoryForTesting(Factory* test_factory);
virtual ~Factory();
virtual std::unique_ptr<CryptAuthV2DeviceManager> BuildInstance(
CryptAuthDeviceRegistry* device_registry,
CryptAuthKeyRegistry* key_registry,
CryptAuthClientFactory* client_factory,
CryptAuthGCMManager* gcm_manager,
CryptAuthScheduler* scheduler);
private:
static Factory* test_factory_;
};
~CryptAuthV2DeviceManagerImpl() override;
protected:
CryptAuthV2DeviceManagerImpl(CryptAuthDeviceRegistry* device_registry,
CryptAuthKeyRegistry* key_registry,
CryptAuthClientFactory* client_factory,
CryptAuthGCMManager* gcm_manager,
CryptAuthScheduler* scheduler);
private:
// CryptAuthV2DeviceManager:
void Start() override;
const CryptAuthDeviceRegistry::InstanceIdToDeviceMap& GetSyncedDevices()
const override;
void ForceDeviceSyncNow(
const cryptauthv2::ClientMetadata::InvocationReason&,
const base::Optional<std::string>& session_id) override;
bool IsDeviceSyncInProgress() const override;
bool IsRecoveringFromFailure() const override;
base::Optional<base::Time> GetLastDeviceSyncTime() const override;
base::Optional<base::TimeDelta> GetTimeToNextAttempt() const override;
// CryptAuthScheduler::DeviceSyncDelegate:
void OnDeviceSyncRequested(
const cryptauthv2::ClientMetadata& client_metadata) override;
// CryptAuthGCMManager::Observer:
void OnResyncMessage(
const base::Optional<std::string>& session_id,
const base::Optional<CryptAuthFeatureType>& feature_type) override;
void OnDeviceSyncFinished(
const CryptAuthDeviceSyncResult& device_sync_result);
CryptAuthDeviceRegistry* device_registry_ = nullptr;
CryptAuthGCMManager* gcm_manager_ = nullptr;
CryptAuthScheduler* scheduler_ = nullptr;
base::Optional<cryptauthv2::ClientMetadata> current_client_metadata_;
// For sending a weak pointer to the scheduler, whose lifetime exceeds that of
// CryptAuthV2DeviceManagerImpl.
base::WeakPtrFactory<CryptAuthV2DeviceManagerImpl>
scheduler_weak_ptr_factory_;
DISALLOW_COPY_AND_ASSIGN(CryptAuthV2DeviceManagerImpl);
};
} // namespace device_sync
} // namespace chromeos
#endif // CHROMEOS_SERVICES_DEVICE_SYNC_CRYPTAUTH_V2_DEVICE_MANAGER_IMPL_H_
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment