summaryrefslogtreecommitdiffstats
path: root/components/proximity_auth
diff options
context:
space:
mode:
authortengs <tengs@chromium.org>2015-07-10 19:19:47 -0700
committerCommit bot <commit-bot@chromium.org>2015-07-11 02:20:49 +0000
commit953ae68f686aa0132cfa35c7f2fca27ea043f73f (patch)
tree6ba60302e7b4e4639e1def9ca8fdb1941f49012f /components/proximity_auth
parentccab7172be7aa1053248613b5c4576e9b913f5ce (diff)
downloadchromium_src-953ae68f686aa0132cfa35c7f2fca27ea043f73f.zip
chromium_src-953ae68f686aa0132cfa35c7f2fca27ea043f73f.tar.gz
chromium_src-953ae68f686aa0132cfa35c7f2fca27ea043f73f.tar.bz2
Introduce CryptAuthGCMManager, which handles GCM interactions for CryptAuth.
BUG=420315 TEST=unit test Review URL: https://codereview.chromium.org/1228763002 Cr-Commit-Position: refs/heads/master@{#338427}
Diffstat (limited to 'components/proximity_auth')
-rw-r--r--components/proximity_auth/cryptauth/BUILD.gn7
-rw-r--r--components/proximity_auth/cryptauth/DEPS1
-rw-r--r--components/proximity_auth/cryptauth/cryptauth_gcm_manager.cc30
-rw-r--r--components/proximity_auth/cryptauth/cryptauth_gcm_manager.h64
-rw-r--r--components/proximity_auth/cryptauth/cryptauth_gcm_manager_impl.cc147
-rw-r--r--components/proximity_auth/cryptauth/cryptauth_gcm_manager_impl.h79
-rw-r--r--components/proximity_auth/cryptauth/cryptauth_gcm_manager_impl_unittest.cc197
-rw-r--r--components/proximity_auth/cryptauth/pref_names.cc4
-rw-r--r--components/proximity_auth/cryptauth/pref_names.h1
9 files changed, 530 insertions, 0 deletions
diff --git a/components/proximity_auth/cryptauth/BUILD.gn b/components/proximity_auth/cryptauth/BUILD.gn
index 12e48c8..b2e210f 100644
--- a/components/proximity_auth/cryptauth/BUILD.gn
+++ b/components/proximity_auth/cryptauth/BUILD.gn
@@ -23,6 +23,10 @@ source_set("cryptauth") {
"cryptauth_enrollment_manager.h",
"cryptauth_enrollment_utils.cc",
"cryptauth_enrollment_utils.h",
+ "cryptauth_gcm_manager.cc",
+ "cryptauth_gcm_manager.h",
+ "cryptauth_gcm_manager_impl.cc",
+ "cryptauth_gcm_manager_impl.h",
"pref_names.cc",
"pref_names.h",
"secure_message_delegate.cc",
@@ -36,6 +40,7 @@ source_set("cryptauth") {
deps = [
"//base",
"//crypto",
+ "//components/gcm_driver",
"//components/proximity_auth/logging",
"//google_apis",
"//net",
@@ -79,6 +84,7 @@ source_set("unit_tests") {
"cryptauth_device_manager_unittest.cc",
"cryptauth_enroller_impl_unittest.cc",
"cryptauth_enrollment_manager_unittest.cc",
+ "cryptauth_gcm_manager_impl_unittest.cc",
"fake_secure_message_delegate_unittest.cc",
"sync_scheduler_impl_unittest.cc",
]
@@ -88,6 +94,7 @@ source_set("unit_tests") {
":test_support",
"//base:prefs_test_support",
"//base/test:test_support",
+ "//components/gcm_driver:test_support",
"//google_apis:test_support",
"//net:test_support",
"//testing/gtest",
diff --git a/components/proximity_auth/cryptauth/DEPS b/components/proximity_auth/cryptauth/DEPS
index 1e58ca5..aa36bc0 100644
--- a/components/proximity_auth/cryptauth/DEPS
+++ b/components/proximity_auth/cryptauth/DEPS
@@ -1,5 +1,6 @@
include_rules = [
"+crypto",
+ "+components/gcm_driver",
"+google_apis",
"+net",
]
diff --git a/components/proximity_auth/cryptauth/cryptauth_gcm_manager.cc b/components/proximity_auth/cryptauth/cryptauth_gcm_manager.cc
new file mode 100644
index 0000000..3b4bbfa
--- /dev/null
+++ b/components/proximity_auth/cryptauth/cryptauth_gcm_manager.cc
@@ -0,0 +1,30 @@
+// Copyright 2015 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 "components/proximity_auth/cryptauth/cryptauth_gcm_manager.h"
+
+#include "base/prefs/pref_registry_simple.h"
+#include "components/proximity_auth/cryptauth/pref_names.h"
+
+namespace proximity_auth {
+
+CryptAuthGCMManager::Observer::~Observer() {
+}
+
+void CryptAuthGCMManager::Observer::OnGCMRegistrationResult(bool success) {
+}
+
+void CryptAuthGCMManager::Observer::OnReenrollMessage() {
+}
+
+void CryptAuthGCMManager::Observer::OnResyncMessage() {
+}
+
+// static.
+void CryptAuthGCMManager::RegisterPrefs(PrefRegistrySimple* registry) {
+ registry->RegisterStringPref(prefs::kCryptAuthGCMRegistrationId,
+ std::string());
+}
+
+} // namespace proximity_auth
diff --git a/components/proximity_auth/cryptauth/cryptauth_gcm_manager.h b/components/proximity_auth/cryptauth/cryptauth_gcm_manager.h
new file mode 100644
index 0000000..014ecf2
--- /dev/null
+++ b/components/proximity_auth/cryptauth/cryptauth_gcm_manager.h
@@ -0,0 +1,64 @@
+// Copyright 2015 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 COMPONENTS_PROXIMITY_AUTH_CRYPTAUTH_CRYPTAUTH_GCM_MANAGER_H
+#define COMPONENTS_PROXIMITY_AUTH_CRYPTAUTH_CRYPTAUTH_GCM_MANAGER_H
+
+#include <string>
+
+class PrefRegistrySimple;
+
+namespace proximity_auth {
+
+// Interface for the manager controlling GCM registrations and handling GCM push
+// messages for CryptAuth. CryptAuth sends GCM messages to request the local
+// device to re-enroll to get the freshest device state, and to notify the
+// local device to resync the remote device list when this list changes.
+class CryptAuthGCMManager {
+ public:
+ class Observer {
+ public:
+ virtual ~Observer();
+
+ // Called when a gcm registration attempt finishes with the |success| of the
+ // attempt.
+ virtual void OnGCMRegistrationResult(bool success);
+
+ // Called when a GCM message is received to re-enroll the device with
+ // CryptAuth.
+ virtual void OnReenrollMessage();
+
+ // Called when a GCM message is received to sync down new devices from
+ // CryptAuth.
+ virtual void OnResyncMessage();
+ };
+
+ virtual ~CryptAuthGCMManager() {}
+
+ // Registers the prefs used by the manager to the given |pref_service|.
+ static void RegisterPrefs(PrefRegistrySimple* registry);
+
+ // Starts listening to incoming GCM messages. If GCM registration is completed
+ // after this function is called, then messages will also be handled properly.
+ virtual void StartListening() = 0;
+
+ // Begins registration with GCM. The Observer::OnGCMRegistrationResult()
+ // observer function will be called when registration completes.
+ virtual void RegisterWithGCM() = 0;
+
+ // Returns the GCM registration id received from the last successful
+ // registration. If registration has not been performed, then an empty string
+ // will be returned.
+ virtual std::string GetRegistrationId() = 0;
+
+ // Adds an observer.
+ virtual void AddObserver(Observer* observer) = 0;
+
+ // Removes an observer.
+ virtual void RemoveObserver(Observer* observer) = 0;
+};
+
+} // namespace proximity_auth
+
+#endif // COMPONENTS_PROXIMITY_CRYPTAUTH_CRYPTAUTH_GCM_MANAGER_H
diff --git a/components/proximity_auth/cryptauth/cryptauth_gcm_manager_impl.cc b/components/proximity_auth/cryptauth/cryptauth_gcm_manager_impl.cc
new file mode 100644
index 0000000..548e9d6
--- /dev/null
+++ b/components/proximity_auth/cryptauth/cryptauth_gcm_manager_impl.cc
@@ -0,0 +1,147 @@
+// Copyright 2015 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 "components/proximity_auth/cryptauth/cryptauth_gcm_manager_impl.h"
+
+#include "base/bind.h"
+#include "base/prefs/pref_service.h"
+#include "base/strings/string_util.h"
+#include "components/gcm_driver/gcm_driver.h"
+#include "components/proximity_auth/cryptauth/pref_names.h"
+#include "components/proximity_auth/logging/logging.h"
+
+namespace proximity_auth {
+
+namespace {
+
+// The GCM app id identifies the client.
+const char kCryptAuthGCMAppId[] = "com.google.chrome.cryptauth";
+
+// The GCM sender id identifies the CryptAuth server.
+const char kCryptAuthGCMSenderId[] = "381449029288";
+
+// The 'registrationTickleType' key-value pair is present in GCM push
+// messages. The values correspond to a server-side enum.
+const char kRegistrationTickleTypeKey[] = "registrationTickleType";
+const char kRegistrationTickleTypeForceEnrollment[] = "1";
+const char kRegistrationTickleTypeUpdateEnrollment[] = "2";
+const char kRegistrationTickleTypeDevicesSync[] = "3";
+
+} // namespace
+
+CryptAuthGCMManagerImpl::CryptAuthGCMManagerImpl(gcm::GCMDriver* gcm_driver,
+ PrefService* pref_service)
+ : gcm_driver_(gcm_driver),
+ pref_service_(pref_service),
+ registration_in_progress_(false),
+ weak_ptr_factory_(this) {
+}
+
+CryptAuthGCMManagerImpl::~CryptAuthGCMManagerImpl() {
+ if (gcm_driver_->GetAppHandler(kCryptAuthGCMAppId) == this)
+ gcm_driver_->RemoveAppHandler(kCryptAuthGCMAppId);
+}
+
+void CryptAuthGCMManagerImpl::StartListening() {
+ if (gcm_driver_->GetAppHandler(kCryptAuthGCMAppId) == this) {
+ PA_LOG(INFO) << "GCM app handler already added";
+ return;
+ }
+
+ gcm_driver_->AddAppHandler(kCryptAuthGCMAppId, this);
+}
+
+void CryptAuthGCMManagerImpl::RegisterWithGCM() {
+ if (registration_in_progress_) {
+ PA_LOG(INFO) << "GCM Registration is already in progress";
+ return;
+ }
+
+ PA_LOG(INFO) << "Beginning GCM registration...";
+ registration_in_progress_ = true;
+
+ std::vector<std::string> sender_ids(1, kCryptAuthGCMSenderId);
+ gcm_driver_->Register(
+ kCryptAuthGCMAppId, sender_ids,
+ base::Bind(&CryptAuthGCMManagerImpl::OnRegistrationCompleted,
+ weak_ptr_factory_.GetWeakPtr()));
+}
+
+std::string CryptAuthGCMManagerImpl::GetRegistrationId() {
+ return pref_service_->GetString(prefs::kCryptAuthGCMRegistrationId);
+}
+
+void CryptAuthGCMManagerImpl::AddObserver(Observer* observer) {
+ observers_.AddObserver(observer);
+}
+
+void CryptAuthGCMManagerImpl::RemoveObserver(Observer* observer) {
+ observers_.RemoveObserver(observer);
+}
+
+void CryptAuthGCMManagerImpl::ShutdownHandler() {
+}
+
+void CryptAuthGCMManagerImpl::OnMessage(
+ const std::string& app_id,
+ const gcm::GCMClient::IncomingMessage& message) {
+ std::vector<std::string> fields;
+ for (const auto& kv : message.data) {
+ fields.push_back(std::string(kv.first) + ": " + std::string(kv.second));
+ }
+
+ PA_LOG(INFO) << "GCM message received:\n"
+ << " sender_id: " << message.sender_id << "\n"
+ << " collapse_key: " << message.collapse_key << "\n"
+ << " data:\n " << JoinString(fields, "\n ");
+
+ if (message.data.find(kRegistrationTickleTypeKey) == message.data.end()) {
+ PA_LOG(WARNING) << "GCM message does not contain 'registrationTickleType'.";
+ } else {
+ std::string tickle_type = message.data.at(kRegistrationTickleTypeKey);
+ if (tickle_type == kRegistrationTickleTypeForceEnrollment ||
+ tickle_type == kRegistrationTickleTypeUpdateEnrollment) {
+ // These tickle types correspond to re-enrollment messages.
+ FOR_EACH_OBSERVER(Observer, observers_, OnReenrollMessage());
+ } else if (tickle_type == kRegistrationTickleTypeDevicesSync) {
+ FOR_EACH_OBSERVER(Observer, observers_, OnResyncMessage());
+ } else {
+ PA_LOG(WARNING) << "Unknown tickle type in GCM message.";
+ }
+ }
+}
+
+void CryptAuthGCMManagerImpl::OnMessagesDeleted(const std::string& app_id) {
+}
+
+void CryptAuthGCMManagerImpl::OnSendError(
+ const std::string& app_id,
+ const gcm::GCMClient::SendErrorDetails& details) {
+ NOTREACHED();
+}
+
+void CryptAuthGCMManagerImpl::OnSendAcknowledged(
+ const std::string& app_id,
+ const std::string& message_id) {
+ NOTREACHED();
+}
+
+void CryptAuthGCMManagerImpl::OnRegistrationCompleted(
+ const std::string& registration_id,
+ gcm::GCMClient::Result result) {
+ registration_in_progress_ = false;
+ if (result != gcm::GCMClient::SUCCESS) {
+ PA_LOG(WARNING) << "GCM registration failed with result="
+ << static_cast<int>(result);
+ FOR_EACH_OBSERVER(Observer, observers_, OnGCMRegistrationResult(false));
+ return;
+ }
+
+ PA_LOG(INFO) << "GCM registration success, registration_id="
+ << registration_id;
+ pref_service_->SetString(prefs::kCryptAuthGCMRegistrationId, registration_id);
+ FOR_EACH_OBSERVER(Observer, observers_, OnGCMRegistrationResult(true));
+}
+
+} // namespace proximity_auth
diff --git a/components/proximity_auth/cryptauth/cryptauth_gcm_manager_impl.h b/components/proximity_auth/cryptauth/cryptauth_gcm_manager_impl.h
new file mode 100644
index 0000000..84ae53b
--- /dev/null
+++ b/components/proximity_auth/cryptauth/cryptauth_gcm_manager_impl.h
@@ -0,0 +1,79 @@
+// Copyright 2015 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 COMPONENTS_PROXIMITY_AUTH_CRYPTAUTH_CRYPTAUTH_GCM_MANAGER_IMPL_H
+#define COMPONENTS_PROXIMITY_AUTH_CRYPTAUTH_CRYPTAUTH_GCM_MANAGER_IMPL_H
+
+#include "base/macros.h"
+#include "base/memory/weak_ptr.h"
+#include "base/observer_list.h"
+#include "components/gcm_driver/gcm_app_handler.h"
+#include "components/gcm_driver/gcm_client.h"
+#include "components/proximity_auth/cryptauth/cryptauth_gcm_manager.h"
+
+class PrefService;
+
+namespace gcm {
+class GCMDriver;
+};
+
+namespace proximity_auth {
+
+// Implementation of CryptAuthGCMManager.
+class CryptAuthGCMManagerImpl : public CryptAuthGCMManager,
+ public gcm::GCMAppHandler {
+ public:
+ // Creates the manager:
+ // |gcm_driver|: Handles the actual GCM communications. The driver is not
+ // owned and must outlive this instance.
+ // |pref_service|: Contains preferences across browser restarts, and should
+ // have been registered through RegisterPrefs(). The service is not owned
+ // and must outlive this instance.
+ CryptAuthGCMManagerImpl(gcm::GCMDriver* gcm_deriver,
+ PrefService* pref_service);
+
+ ~CryptAuthGCMManagerImpl() override;
+
+ // CryptAuthGCMManager:
+ void StartListening() override;
+ void RegisterWithGCM() override;
+ std::string GetRegistrationId() override;
+ void AddObserver(Observer* observer) override;
+ void RemoveObserver(Observer* observer) override;
+
+ private:
+ // GCMAppHandler:
+ void ShutdownHandler() override;
+ void OnMessage(const std::string& app_id,
+ const gcm::GCMClient::IncomingMessage& message) override;
+ void OnMessagesDeleted(const std::string& app_id) override;
+ void OnSendError(const std::string& app_id,
+ const gcm::GCMClient::SendErrorDetails& details) override;
+ void OnSendAcknowledged(const std::string& app_id,
+ const std::string& message_id) override;
+
+ // Called when GCM registration completes.
+ void OnRegistrationCompleted(const std::string& registration_id,
+ gcm::GCMClient::Result result);
+
+ // Handles the communications with GCM. Not owned.
+ gcm::GCMDriver* gcm_driver_;
+
+ // Manages preferences across process restarts. Not owned.
+ PrefService* pref_service_;
+
+ // Whether a GCM registration is currently being processed.
+ bool registration_in_progress_;
+
+ // List of observers.
+ base::ObserverList<Observer> observers_;
+
+ base::WeakPtrFactory<CryptAuthGCMManagerImpl> weak_ptr_factory_;
+
+ DISALLOW_COPY_AND_ASSIGN(CryptAuthGCMManagerImpl);
+};
+
+} // namespace proximity_auth
+
+#endif // COMPONENTS_PROXIMITY_CRYPTAUTH_CRYPTAUTH_GCM_MANAGER_IMPL_H
diff --git a/components/proximity_auth/cryptauth/cryptauth_gcm_manager_impl_unittest.cc b/components/proximity_auth/cryptauth/cryptauth_gcm_manager_impl_unittest.cc
new file mode 100644
index 0000000..02b35ac
--- /dev/null
+++ b/components/proximity_auth/cryptauth/cryptauth_gcm_manager_impl_unittest.cc
@@ -0,0 +1,197 @@
+// Copyright 2015 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 "components/proximity_auth/cryptauth/cryptauth_gcm_manager_impl.h"
+
+#include "base/prefs/testing_pref_service.h"
+#include "components/gcm_driver/fake_gcm_driver.h"
+#include "components/gcm_driver/gcm_client.h"
+#include "components/proximity_auth/cryptauth/pref_names.h"
+#include "testing/gmock/include/gmock/gmock.h"
+#include "testing/gtest/include/gtest/gtest.h"
+
+using ::testing::_;
+using ::testing::SaveArg;
+
+namespace proximity_auth {
+
+namespace {
+
+const char kCryptAuthGCMAppId[] = "com.google.chrome.cryptauth";
+const char kCryptAuthGCMSenderId[] = "381449029288";
+const char kExistingGCMRegistrationId[] = "cirrus";
+const char kNewGCMRegistrationId[] = "stratus";
+const char kCryptAuthMessageCollapseKey[] =
+ "collapse_cryptauth_sync_DEVICES_SYNC";
+
+// Mock GCMDriver implementation for testing.
+class MockGCMDriver : public gcm::FakeGCMDriver {
+ public:
+ MockGCMDriver() {}
+ ~MockGCMDriver() override {}
+
+ MOCK_METHOD2(AddAppHandler,
+ void(const std::string& app_id, gcm::GCMAppHandler* handler));
+
+ MOCK_METHOD2(RegisterImpl,
+ void(const std::string& app_id,
+ const std::vector<std::string>& sender_ids));
+
+ using gcm::GCMDriver::RegisterFinished;
+
+ private:
+ DISALLOW_COPY_AND_ASSIGN(MockGCMDriver);
+};
+
+} // namespace
+
+class ProximityAuthCryptAuthGCMManagerImplTest
+ : public testing::Test,
+ public CryptAuthGCMManager::Observer {
+ protected:
+ ProximityAuthCryptAuthGCMManagerImplTest()
+ : gcm_manager_(&gcm_driver_, &pref_service_) {}
+
+ // testing::Test:
+ void SetUp() override {
+ CryptAuthGCMManager::RegisterPrefs(pref_service_.registry());
+ gcm_manager_.AddObserver(this);
+ EXPECT_CALL(gcm_driver_, AddAppHandler(kCryptAuthGCMAppId, &gcm_manager_));
+ gcm_manager_.StartListening();
+ }
+
+ void TearDown() override { gcm_manager_.RemoveObserver(this); }
+
+ void RegisterWithGCM(gcm::GCMClient::Result registration_result) {
+ std::vector<std::string> sender_ids;
+ EXPECT_CALL(gcm_driver_, RegisterImpl(kCryptAuthGCMAppId, _))
+ .WillOnce(SaveArg<1>(&sender_ids));
+ gcm_manager_.RegisterWithGCM();
+
+ ASSERT_EQ(1u, sender_ids.size());
+ EXPECT_EQ(kCryptAuthGCMSenderId, sender_ids[0]);
+
+ bool success = (registration_result == gcm::GCMClient::SUCCESS);
+ EXPECT_CALL(*this, OnGCMRegistrationResultProxy(success));
+ gcm_driver_.RegisterFinished(kCryptAuthGCMAppId, kNewGCMRegistrationId,
+ registration_result);
+ }
+
+ // CryptAuthGCMManager::Observer:
+ void OnGCMRegistrationResult(bool success) override {
+ OnGCMRegistrationResultProxy(success);
+ }
+
+ void OnReenrollMessage() override { OnReenrollMessageProxy(); }
+
+ void OnResyncMessage() override { OnResyncMessageProxy(); }
+
+ MOCK_METHOD1(OnGCMRegistrationResultProxy, void(bool));
+ MOCK_METHOD0(OnReenrollMessageProxy, void());
+ MOCK_METHOD0(OnResyncMessageProxy, void());
+
+ testing::StrictMock<MockGCMDriver> gcm_driver_;
+
+ TestingPrefServiceSimple pref_service_;
+
+ CryptAuthGCMManagerImpl gcm_manager_;
+
+ DISALLOW_COPY_AND_ASSIGN(ProximityAuthCryptAuthGCMManagerImplTest);
+};
+
+TEST_F(ProximityAuthCryptAuthGCMManagerImplTest, RegisterPrefs) {
+ TestingPrefServiceSimple pref_service;
+ CryptAuthGCMManager::RegisterPrefs(pref_service.registry());
+ EXPECT_TRUE(pref_service.FindPreference(prefs::kCryptAuthGCMRegistrationId));
+}
+
+TEST_F(ProximityAuthCryptAuthGCMManagerImplTest, RegistrationSucceeds) {
+ EXPECT_EQ(std::string(), gcm_manager_.GetRegistrationId());
+ RegisterWithGCM(gcm::GCMClient::SUCCESS);
+ EXPECT_EQ(kNewGCMRegistrationId, gcm_manager_.GetRegistrationId());
+}
+
+TEST_F(ProximityAuthCryptAuthGCMManagerImplTest,
+ RegistrationSucceedsWithExistingRegistration) {
+ pref_service_.SetString(prefs::kCryptAuthGCMRegistrationId,
+ kExistingGCMRegistrationId);
+ EXPECT_EQ(kExistingGCMRegistrationId, gcm_manager_.GetRegistrationId());
+ RegisterWithGCM(gcm::GCMClient::SUCCESS);
+ EXPECT_EQ(kNewGCMRegistrationId, gcm_manager_.GetRegistrationId());
+ EXPECT_EQ(kNewGCMRegistrationId,
+ pref_service_.GetString(prefs::kCryptAuthGCMRegistrationId));
+}
+
+TEST_F(ProximityAuthCryptAuthGCMManagerImplTest, RegisterWithGCMFails) {
+ EXPECT_EQ(std::string(), gcm_manager_.GetRegistrationId());
+ RegisterWithGCM(gcm::GCMClient::SERVER_ERROR);
+ EXPECT_EQ(std::string(), gcm_manager_.GetRegistrationId());
+ EXPECT_EQ(std::string(),
+ pref_service_.GetString(prefs::kCryptAuthGCMRegistrationId));
+}
+
+TEST_F(ProximityAuthCryptAuthGCMManagerImplTest,
+ RegisterWithGCMFailsWithExistingRegistration) {
+ pref_service_.SetString(prefs::kCryptAuthGCMRegistrationId,
+ kExistingGCMRegistrationId);
+ EXPECT_EQ(kExistingGCMRegistrationId, gcm_manager_.GetRegistrationId());
+ RegisterWithGCM(gcm::GCMClient::SERVER_ERROR);
+ EXPECT_EQ(kExistingGCMRegistrationId, gcm_manager_.GetRegistrationId());
+ EXPECT_EQ(kExistingGCMRegistrationId,
+ pref_service_.GetString(prefs::kCryptAuthGCMRegistrationId));
+}
+
+TEST_F(ProximityAuthCryptAuthGCMManagerImplTest,
+ RegistrationFailsThenSucceeds) {
+ EXPECT_EQ(std::string(), gcm_manager_.GetRegistrationId());
+ RegisterWithGCM(gcm::GCMClient::NETWORK_ERROR);
+ EXPECT_EQ(std::string(), gcm_manager_.GetRegistrationId());
+ RegisterWithGCM(gcm::GCMClient::SUCCESS);
+ EXPECT_EQ(kNewGCMRegistrationId, gcm_manager_.GetRegistrationId());
+}
+
+TEST_F(ProximityAuthCryptAuthGCMManagerImplTest, ConcurrentRegistrations) {
+ // If multiple RegisterWithGCM() calls are made concurrently, only one
+ // registration attempt should actually be made.
+ EXPECT_CALL(gcm_driver_, RegisterImpl(kCryptAuthGCMAppId, _));
+ gcm_manager_.RegisterWithGCM();
+ gcm_manager_.RegisterWithGCM();
+ gcm_manager_.RegisterWithGCM();
+
+ EXPECT_CALL(*this, OnGCMRegistrationResultProxy(true));
+ gcm_driver_.RegisterFinished(kCryptAuthGCMAppId, kNewGCMRegistrationId,
+ gcm::GCMClient::SUCCESS);
+ EXPECT_EQ(kNewGCMRegistrationId, gcm_manager_.GetRegistrationId());
+}
+
+TEST_F(ProximityAuthCryptAuthGCMManagerImplTest, ReenrollmentMessagesReceived) {
+ EXPECT_CALL(*this, OnReenrollMessageProxy()).Times(2);
+
+ gcm::GCMClient::IncomingMessage message;
+ message.data["registrationTickleType"] = "1"; // FORCE_ENROLLMENT
+ message.collapse_key = kCryptAuthMessageCollapseKey;
+ message.sender_id = kCryptAuthGCMSenderId;
+
+ gcm::GCMAppHandler* gcm_app_handler =
+ static_cast<gcm::GCMAppHandler*>(&gcm_manager_);
+ gcm_app_handler->OnMessage(kCryptAuthGCMAppId, message);
+ message.data["registrationTickleType"] = "2"; // UPDATE_ENROLLMENT
+ gcm_app_handler->OnMessage(kCryptAuthGCMAppId, message);
+}
+
+TEST_F(ProximityAuthCryptAuthGCMManagerImplTest, ResyncMessagesReceived) {
+ EXPECT_CALL(*this, OnResyncMessageProxy()).Times(2);
+
+ gcm::GCMClient::IncomingMessage message;
+ message.data["registrationTickleType"] = "3"; // DEVICES_SYNC
+ message.collapse_key = kCryptAuthMessageCollapseKey;
+ message.sender_id = kCryptAuthGCMSenderId;
+
+ gcm::GCMAppHandler* gcm_app_handler =
+ static_cast<gcm::GCMAppHandler*>(&gcm_manager_);
+ gcm_app_handler->OnMessage(kCryptAuthGCMAppId, message);
+ gcm_app_handler->OnMessage(kCryptAuthGCMAppId, message);
+}
+
+} // namespace proximity_auth
diff --git a/components/proximity_auth/cryptauth/pref_names.cc b/components/proximity_auth/cryptauth/pref_names.cc
index db06a2f..ed7d5b4 100644
--- a/components/proximity_auth/cryptauth/pref_names.cc
+++ b/components/proximity_auth/cryptauth/pref_names.cc
@@ -41,5 +41,9 @@ const char kCryptAuthEnrollmentLastEnrollmentTimeSeconds[] =
// components/proximity_auth/cryptauth/proto/cryptauth_api.proto.
extern const char kCryptAuthEnrollmentReason[] = "cryptauth.enrollment.reason";
+// The GCM registration id used for receiving push messages from CryptAuth.
+extern const char kCryptAuthGCMRegistrationId[] =
+ "cryptauth.gcm_registration_id";
+
} // namespace prefs
} // proximity_auth
diff --git a/components/proximity_auth/cryptauth/pref_names.h b/components/proximity_auth/cryptauth/pref_names.h
index 2caa187..2ef0a29 100644
--- a/components/proximity_auth/cryptauth/pref_names.h
+++ b/components/proximity_auth/cryptauth/pref_names.h
@@ -15,6 +15,7 @@ extern const char kCryptAuthDeviceSyncUnlockKeys[];
extern const char kCryptAuthEnrollmentIsRecoveringFromFailure[];
extern const char kCryptAuthEnrollmentLastEnrollmentTimeSeconds[];
extern const char kCryptAuthEnrollmentReason[];
+extern const char kCryptAuthGCMRegistrationId[];
} // namespace prefs
} // proximity_auth