blob: 357d5389ccb1bd0d8d9002485b7eaf3c2172c733 [file] [log] [blame]
// 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_ENROLLMENT_MANAGER_IMPL_H_
#define CHROMEOS_SERVICES_DEVICE_SYNC_CRYPTAUTH_V2_ENROLLMENT_MANAGER_IMPL_H_
#include <memory>
#include <ostream>
#include <string>
#include "base/macros.h"
#include "base/memory/weak_ptr.h"
#include "base/optional.h"
#include "base/time/default_clock.h"
#include "chromeos/services/device_sync/cryptauth_enrollment_manager.h"
#include "chromeos/services/device_sync/cryptauth_enrollment_result.h"
#include "chromeos/services/device_sync/cryptauth_feature_type.h"
#include "chromeos/services/device_sync/cryptauth_gcm_manager.h"
#include "chromeos/services/device_sync/cryptauth_scheduler.h"
#include "chromeos/services/device_sync/proto/cryptauth_client_app_metadata.pb.h"
#include "chromeos/services/device_sync/proto/cryptauth_common.pb.h"
class PrefService;
class PrefRegistrySimple;
namespace base {
class OneShotTimer;
} // namespace base
namespace chromeos {
namespace device_sync {
class ClientAppMetadataProvider;
class CryptAuthClientFactory;
class CryptAuthKeyRegistry;
class CryptAuthV2Enroller;
// Implementation of CryptAuthEnrollmentManager for CryptAuth v2 Enrollment.
//
// This implementation considers three sources of enrollment requests:
// 1) The scheduler requests periodic enrollments and handles any failed
// attempts.
// 2) The enrollment manager listens to the GCM manager for re-enrollment
// requests.
// 3) The ForceEnrollmentNow() method allows for immediate requests.
//
// All flavors of enrollment attempts are guarded by timeouts. For example, an
// enrollment attempt triggered by ForceEnrollmentNow() will always
// conclude--successfully or not--in an allotted period of time.
//
// The v2 Enrollment infrastructure stores keys in a CryptAuthKeyRegistry. In
// contrast, the v1 enrollment manager implementation directly controls a set of
// prefs that store the user key pair. However, on construction of
// CryptAuthV2EnrollmentManagerImpl, any existing v1 user key pair is added to
// the v2 key registry to ensure consistency across the v1 to v2 Enrollment
// migration. The converse is not true. The v1 prefs will never be modified by
// v2 Enrollment.
class CryptAuthV2EnrollmentManagerImpl
: public CryptAuthEnrollmentManager,
public CryptAuthScheduler::EnrollmentDelegate,
public CryptAuthGCMManager::Observer {
public:
class Factory {
public:
static Factory* Get();
static void SetFactoryForTesting(Factory* test_factory);
virtual ~Factory();
virtual std::unique_ptr<CryptAuthEnrollmentManager> BuildInstance(
ClientAppMetadataProvider* client_app_metadata_provider,
CryptAuthKeyRegistry* key_registry,
CryptAuthClientFactory* client_factory,
CryptAuthGCMManager* gcm_manager,
CryptAuthScheduler* scheduler,
PrefService* pref_service,
base::Clock* clock = base::DefaultClock::GetInstance(),
std::unique_ptr<base::OneShotTimer> timer =
std::make_unique<base::OneShotTimer>());
private:
static Factory* test_factory_;
};
// Note: This should never be called with
// CryptAuthEnrollmentManagerImpl::RegisterPrefs().
static void RegisterPrefs(PrefRegistrySimple* registry);
~CryptAuthV2EnrollmentManagerImpl() override;
protected:
CryptAuthV2EnrollmentManagerImpl(
ClientAppMetadataProvider* client_app_metadata_provider,
CryptAuthKeyRegistry* key_registry,
CryptAuthClientFactory* client_factory,
CryptAuthGCMManager* gcm_manager,
CryptAuthScheduler* scheduler,
PrefService* pref_service,
base::Clock* clock,
std::unique_ptr<base::OneShotTimer> timer);
private:
enum class State {
kIdle,
kWaitingForGcmRegistration,
kWaitingForClientAppMetadata,
kWaitingForEnrollment
};
friend std::ostream& operator<<(std::ostream& stream, const State& state);
static base::Optional<base::TimeDelta> GetTimeoutForState(State state);
static base::Optional<CryptAuthEnrollmentResult::ResultCode>
ResultCodeErrorFromState(State state);
// CryptAuthEnrollmentManager:
void Start() override;
void ForceEnrollmentNow(
cryptauth::InvocationReason invocation_reason,
const base::Optional<std::string>& session_id) override;
bool IsEnrollmentValid() const override;
base::Time GetLastEnrollmentTime() const override;
base::TimeDelta GetTimeToNextAttempt() const override;
bool IsEnrollmentInProgress() const override;
bool IsRecoveringFromFailure() const override;
std::string GetUserPublicKey() const override;
std::string GetUserPrivateKey() const override;
// CryptAuthScheduler::EnrollmentDelegate:
void OnEnrollmentRequested(const cryptauthv2::ClientMetadata& client_metadata,
const base::Optional<cryptauthv2::PolicyReference>&
client_directive_policy_reference) override;
// CryptAuthGCMManager::Observer:
void OnGCMRegistrationResult(bool success) override;
void OnReenrollMessage(
const base::Optional<std::string>& session_id,
const base::Optional<CryptAuthFeatureType>& feature_type) override;
void OnClientAppMetadataFetched(
const base::Optional<cryptauthv2::ClientAppMetadata>&
client_app_metadata);
// Starts the enrollment flow if a valid GCM registration ID exists and the
// ClientAppMetadata has already been fetched; otherwise, the enrollment is
// postposed while they are retrieved.
void AttemptEnrollment();
void Enroll();
void OnEnrollmentFinished(const CryptAuthEnrollmentResult& enrollment_result);
void SetState(State state);
std::string GetV1UserPublicKey() const;
std::string GetV1UserPrivateKey() const;
// If a v1 user key-pair exists, add it to the registry as the active key in
// the kUserKeyPair key bundle.
void AddV1UserKeyPairToRegistryIfNecessary();
ClientAppMetadataProvider* client_app_metadata_provider_;
CryptAuthKeyRegistry* key_registry_;
CryptAuthClientFactory* client_factory_;
CryptAuthGCMManager* gcm_manager_;
CryptAuthScheduler* scheduler_;
PrefService* pref_service_;
base::Clock* clock_;
std::unique_ptr<base::OneShotTimer> timer_;
State state_ = State::kIdle;
base::Optional<cryptauthv2::ClientMetadata> current_client_metadata_;
base::Optional<cryptauthv2::PolicyReference>
client_directive_policy_reference_;
base::Optional<cryptauthv2::ClientAppMetadata> client_app_metadata_;
std::unique_ptr<CryptAuthV2Enroller> enroller_;
// For weak pointers used in callbacks. These weak pointers are invalidated
// when the current enrollment attempt finishes in order to cancel outstanding
// callbacks.
base::WeakPtrFactory<CryptAuthV2EnrollmentManagerImpl>
callback_weak_ptr_factory_;
// For sending a weak pointer to the scheduler, whose lifetime exceeds that of
// CryptAuthV2EnrollmentManagerImpl.
base::WeakPtrFactory<CryptAuthV2EnrollmentManagerImpl>
scheduler_weak_ptr_factory_;
DISALLOW_COPY_AND_ASSIGN(CryptAuthV2EnrollmentManagerImpl);
};
} // namespace device_sync
} // namespace chromeos
#endif // CHROMEOS_SERVICES_DEVICE_SYNC_CRYPTAUTH_V2_ENROLLMENT_MANAGER_IMPL_H_