1 // Copyright 2015 The Chromium Authors. All rights reserved.
2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file.
5 #include "components/proximity_auth/cryptauth/cryptauth_enrollment_manager.h"
7 #include "base/memory/weak_ptr.h"
8 #include "base/prefs/testing_pref_service.h"
9 #include "base/test/simple_test_clock.h"
10 #include "base/time/clock.h"
11 #include "base/time/time.h"
12 #include "components/proximity_auth/cryptauth/base64url.h"
13 #include "components/proximity_auth/cryptauth/cryptauth_enroller.h"
14 #include "components/proximity_auth/cryptauth/fake_cryptauth_gcm_manager.h"
15 #include "components/proximity_auth/cryptauth/fake_secure_message_delegate.h"
16 #include "components/proximity_auth/cryptauth/mock_sync_scheduler.h"
17 #include "components/proximity_auth/cryptauth/pref_names.h"
18 #include "testing/gmock/include/gmock/gmock.h"
19 #include "testing/gtest/include/gtest/gtest.h"
22 using ::testing::NiceMock
;
23 using ::testing::Return
;
24 using ::testing::SaveArg
;
26 namespace proximity_auth
{
30 // The GCM registration id from a successful registration.
31 const char kGCMRegistrationId
[] = "new gcm registration id";
33 // The user's persistent public key identifying the local device.
34 const char kUserPublicKey
[] = "user public key";
36 // The initial "Now" time for testing.
37 const double kInitialTimeNowSeconds
= 20000000;
39 // A later "Now" time for testing.
40 const double kLaterTimeNow
= kInitialTimeNowSeconds
+ 30;
42 // The timestamp of a last successful enrollment that is still valid.
43 const double kLastEnrollmentTimeSeconds
=
44 kInitialTimeNowSeconds
- (60 * 60 * 24 * 15);
46 // The timestamp of a last successful enrollment that is expired.
47 const double kLastExpiredEnrollmentTimeSeconds
=
48 kInitialTimeNowSeconds
- (60 * 60 * 24 * 100);
50 // Mocks out the actual enrollment flow.
51 class MockCryptAuthEnroller
: public CryptAuthEnroller
{
53 MockCryptAuthEnroller() {}
54 ~MockCryptAuthEnroller() override
{}
57 void(const std::string
& user_public_key
,
58 const std::string
& user_private_key
,
59 const cryptauth::GcmDeviceInfo
& device_info
,
60 cryptauth::InvocationReason invocation_reason
,
61 const EnrollmentFinishedCallback
& callback
));
64 DISALLOW_COPY_AND_ASSIGN(MockCryptAuthEnroller
);
67 // Creates MockCryptAuthEnroller instances, and allows expecations to be set
68 // before they are returned.
69 class MockCryptAuthEnrollerFactory
: public CryptAuthEnrollerFactory
{
71 MockCryptAuthEnrollerFactory()
72 : next_cryptauth_enroller_(new NiceMock
<MockCryptAuthEnroller
>()) {}
73 ~MockCryptAuthEnrollerFactory() override
{}
75 // CryptAuthEnrollerFactory:
76 scoped_ptr
<CryptAuthEnroller
> CreateInstance() override
{
77 auto passed_cryptauth_enroller
= next_cryptauth_enroller_
.Pass();
78 next_cryptauth_enroller_
.reset(new NiceMock
<MockCryptAuthEnroller
>());
79 return passed_cryptauth_enroller
.Pass();
82 MockCryptAuthEnroller
* next_cryptauth_enroller() {
83 return next_cryptauth_enroller_
.get();
87 // Stores the next CryptAuthEnroller to be created.
88 // Ownership is passed to the caller of |CreateInstance()|.
89 scoped_ptr
<MockCryptAuthEnroller
> next_cryptauth_enroller_
;
91 DISALLOW_COPY_AND_ASSIGN(MockCryptAuthEnrollerFactory
);
94 // Harness for testing CryptAuthEnrollmentManager.
95 class TestCryptAuthEnrollmentManager
: public CryptAuthEnrollmentManager
{
97 TestCryptAuthEnrollmentManager(
98 scoped_ptr
<base::Clock
> clock
,
99 scoped_ptr
<CryptAuthEnrollerFactory
> enroller_factory
,
100 scoped_ptr
<SecureMessageDelegate
> secure_message_delegate
,
101 const cryptauth::GcmDeviceInfo
& device_info
,
102 CryptAuthGCMManager
* gcm_manager
,
103 PrefService
* pref_service
)
104 : CryptAuthEnrollmentManager(clock
.Pass(),
105 enroller_factory
.Pass(),
106 secure_message_delegate
.Pass(),
110 scoped_sync_scheduler_(new NiceMock
<MockSyncScheduler
>()),
111 weak_sync_scheduler_factory_(scoped_sync_scheduler_
.get()) {}
113 ~TestCryptAuthEnrollmentManager() override
{}
115 scoped_ptr
<SyncScheduler
> CreateSyncScheduler() override
{
116 EXPECT_TRUE(scoped_sync_scheduler_
);
117 return scoped_sync_scheduler_
.Pass();
120 base::WeakPtr
<MockSyncScheduler
> GetSyncScheduler() {
121 return weak_sync_scheduler_factory_
.GetWeakPtr();
125 // Ownership is passed to |CryptAuthEnrollmentManager| super class when
126 // |CreateSyncScheduler()| is called.
127 scoped_ptr
<MockSyncScheduler
> scoped_sync_scheduler_
;
129 // Stores the pointer of |scoped_sync_scheduler_| after ownership is passed to
131 // This should be safe because the life-time this SyncScheduler will always be
132 // within the life of the TestCryptAuthEnrollmentManager object.
133 base::WeakPtrFactory
<MockSyncScheduler
> weak_sync_scheduler_factory_
;
135 DISALLOW_COPY_AND_ASSIGN(TestCryptAuthEnrollmentManager
);
140 class ProximityAuthCryptAuthEnrollmentManagerTest
141 : public testing::Test
,
142 public CryptAuthEnrollmentManager::Observer
{
144 ProximityAuthCryptAuthEnrollmentManagerTest()
145 : public_key_(kUserPublicKey
),
146 clock_(new base::SimpleTestClock()),
147 enroller_factory_(new MockCryptAuthEnrollerFactory()),
148 secure_message_delegate_(new FakeSecureMessageDelegate()),
149 gcm_manager_(kGCMRegistrationId
),
150 enrollment_manager_(make_scoped_ptr(clock_
),
151 make_scoped_ptr(enroller_factory_
),
152 make_scoped_ptr(secure_message_delegate_
),
158 void SetUp() override
{
159 clock_
->SetNow(base::Time::FromDoubleT(kInitialTimeNowSeconds
));
160 enrollment_manager_
.AddObserver(this);
163 secure_message_delegate_
->GetPrivateKeyForPublicKey(public_key_
);
164 secure_message_delegate_
->set_next_public_key(public_key_
);
166 CryptAuthEnrollmentManager::RegisterPrefs(pref_service_
.registry());
167 pref_service_
.SetUserPref(
168 prefs::kCryptAuthEnrollmentIsRecoveringFromFailure
,
169 new base::FundamentalValue(false));
170 pref_service_
.SetUserPref(
171 prefs::kCryptAuthEnrollmentLastEnrollmentTimeSeconds
,
172 new base::FundamentalValue(kLastEnrollmentTimeSeconds
));
173 pref_service_
.SetUserPref(
174 prefs::kCryptAuthEnrollmentReason
,
175 new base::FundamentalValue(cryptauth::INVOCATION_REASON_UNKNOWN
));
177 std::string public_key_b64
, private_key_b64
;
178 Base64UrlEncode(public_key_
, &public_key_b64
);
179 Base64UrlEncode(private_key_
, &private_key_b64
);
180 pref_service_
.SetString(prefs::kCryptAuthEnrollmentUserPublicKey
,
182 pref_service_
.SetString(prefs::kCryptAuthEnrollmentUserPrivateKey
,
185 ON_CALL(*sync_scheduler(), GetStrategy())
186 .WillByDefault(Return(SyncScheduler::Strategy::PERIODIC_REFRESH
));
189 void TearDown() override
{ enrollment_manager_
.RemoveObserver(this); }
191 // CryptAuthEnrollmentManager::Observer:
192 void OnEnrollmentStarted() override
{ OnEnrollmentStartedProxy(); }
194 void OnEnrollmentFinished(bool success
) override
{
195 // Simulate the scheduler changing strategies based on success or failure.
196 SyncScheduler::Strategy new_strategy
=
197 SyncScheduler::Strategy::AGGRESSIVE_RECOVERY
;
198 ON_CALL(*sync_scheduler(), GetStrategy())
199 .WillByDefault(Return(new_strategy
));
201 OnEnrollmentFinishedProxy(success
);
204 MOCK_METHOD0(OnEnrollmentStartedProxy
, void());
205 MOCK_METHOD1(OnEnrollmentFinishedProxy
, void(bool success
));
207 // Simulates firing the SyncScheduler to trigger an enrollment attempt.
208 CryptAuthEnroller::EnrollmentFinishedCallback
FireSchedulerForEnrollment(
209 cryptauth::InvocationReason expected_invocation_reason
) {
210 CryptAuthEnroller::EnrollmentFinishedCallback completion_callback
;
212 *next_cryptauth_enroller(),
213 Enroll(public_key_
, private_key_
, _
, expected_invocation_reason
, _
))
214 .WillOnce(SaveArg
<4>(&completion_callback
));
216 auto sync_request
= make_scoped_ptr(
217 new SyncScheduler::SyncRequest(enrollment_manager_
.GetSyncScheduler()));
218 EXPECT_CALL(*this, OnEnrollmentStartedProxy());
220 SyncScheduler::Delegate
* delegate
=
221 static_cast<SyncScheduler::Delegate
*>(&enrollment_manager_
);
222 delegate
->OnSyncRequested(sync_request
.Pass());
224 return completion_callback
;
227 MockSyncScheduler
* sync_scheduler() {
228 return enrollment_manager_
.GetSyncScheduler().get();
231 MockCryptAuthEnroller
* next_cryptauth_enroller() {
232 return enroller_factory_
->next_cryptauth_enroller();
235 // The expected persistent keypair.
236 std::string public_key_
;
237 std::string private_key_
;
239 // Owned by |enrollment_manager_|.
240 base::SimpleTestClock
* clock_
;
242 // Owned by |enrollment_manager_|.
243 MockCryptAuthEnrollerFactory
* enroller_factory_
;
245 // Ownered by |enrollment_manager_|.
246 FakeSecureMessageDelegate
* secure_message_delegate_
;
248 cryptauth::GcmDeviceInfo device_info_
;
250 TestingPrefServiceSimple pref_service_
;
252 FakeCryptAuthGCMManager gcm_manager_
;
254 TestCryptAuthEnrollmentManager enrollment_manager_
;
256 DISALLOW_COPY_AND_ASSIGN(ProximityAuthCryptAuthEnrollmentManagerTest
);
259 TEST_F(ProximityAuthCryptAuthEnrollmentManagerTest
, RegisterPrefs
) {
260 TestingPrefServiceSimple pref_service
;
261 CryptAuthEnrollmentManager::RegisterPrefs(pref_service
.registry());
262 EXPECT_TRUE(pref_service
.FindPreference(
263 prefs::kCryptAuthEnrollmentLastEnrollmentTimeSeconds
));
264 EXPECT_TRUE(pref_service
.FindPreference(
265 prefs::kCryptAuthEnrollmentIsRecoveringFromFailure
));
266 EXPECT_TRUE(pref_service
.FindPreference(prefs::kCryptAuthEnrollmentReason
));
269 TEST_F(ProximityAuthCryptAuthEnrollmentManagerTest
, GetEnrollmentState
) {
270 enrollment_manager_
.Start();
272 ON_CALL(*sync_scheduler(), GetStrategy())
273 .WillByDefault(Return(SyncScheduler::Strategy::PERIODIC_REFRESH
));
274 EXPECT_FALSE(enrollment_manager_
.IsRecoveringFromFailure());
276 ON_CALL(*sync_scheduler(), GetStrategy())
277 .WillByDefault(Return(SyncScheduler::Strategy::AGGRESSIVE_RECOVERY
));
278 EXPECT_TRUE(enrollment_manager_
.IsRecoveringFromFailure());
280 base::TimeDelta time_to_next_sync
= base::TimeDelta::FromMinutes(60);
281 ON_CALL(*sync_scheduler(), GetTimeToNextSync())
282 .WillByDefault(Return(time_to_next_sync
));
283 EXPECT_EQ(time_to_next_sync
, enrollment_manager_
.GetTimeToNextAttempt());
285 ON_CALL(*sync_scheduler(), GetSyncState())
286 .WillByDefault(Return(SyncScheduler::SyncState::SYNC_IN_PROGRESS
));
287 EXPECT_TRUE(enrollment_manager_
.IsEnrollmentInProgress());
289 ON_CALL(*sync_scheduler(), GetSyncState())
290 .WillByDefault(Return(SyncScheduler::SyncState::WAITING_FOR_REFRESH
));
291 EXPECT_FALSE(enrollment_manager_
.IsEnrollmentInProgress());
294 TEST_F(ProximityAuthCryptAuthEnrollmentManagerTest
, InitWithDefaultPrefs
) {
295 scoped_ptr
<base::SimpleTestClock
> clock(new base::SimpleTestClock());
296 clock
->SetNow(base::Time::FromDoubleT(kInitialTimeNowSeconds
));
297 base::TimeDelta elapsed_time
= clock
->Now() - base::Time::FromDoubleT(0);
299 TestingPrefServiceSimple pref_service
;
300 CryptAuthEnrollmentManager::RegisterPrefs(pref_service
.registry());
302 TestCryptAuthEnrollmentManager
enrollment_manager(
303 clock
.Pass(), make_scoped_ptr(new MockCryptAuthEnrollerFactory()),
304 make_scoped_ptr(new FakeSecureMessageDelegate()), device_info_
,
305 &gcm_manager_
, &pref_service
);
308 *enrollment_manager
.GetSyncScheduler(),
309 Start(elapsed_time
, SyncScheduler::Strategy::AGGRESSIVE_RECOVERY
));
310 enrollment_manager
.Start();
312 EXPECT_FALSE(enrollment_manager
.IsEnrollmentValid());
313 EXPECT_TRUE(enrollment_manager
.GetLastEnrollmentTime().is_null());
316 TEST_F(ProximityAuthCryptAuthEnrollmentManagerTest
, InitWithExistingPrefs
) {
319 Start(clock_
->Now() - base::Time::FromDoubleT(kLastEnrollmentTimeSeconds
),
320 SyncScheduler::Strategy::PERIODIC_REFRESH
));
322 enrollment_manager_
.Start();
323 EXPECT_TRUE(enrollment_manager_
.IsEnrollmentValid());
324 EXPECT_EQ(base::Time::FromDoubleT(kLastEnrollmentTimeSeconds
),
325 enrollment_manager_
.GetLastEnrollmentTime());
328 TEST_F(ProximityAuthCryptAuthEnrollmentManagerTest
, InitWithExpiredEnrollment
) {
329 pref_service_
.SetUserPref(
330 prefs::kCryptAuthEnrollmentLastEnrollmentTimeSeconds
,
331 new base::FundamentalValue(kLastExpiredEnrollmentTimeSeconds
));
333 EXPECT_CALL(*sync_scheduler(),
334 Start(clock_
->Now() - base::Time::FromDoubleT(
335 kLastExpiredEnrollmentTimeSeconds
),
336 SyncScheduler::Strategy::AGGRESSIVE_RECOVERY
));
338 enrollment_manager_
.Start();
339 EXPECT_FALSE(enrollment_manager_
.IsEnrollmentValid());
340 EXPECT_EQ(base::Time::FromDoubleT(kLastExpiredEnrollmentTimeSeconds
),
341 enrollment_manager_
.GetLastEnrollmentTime());
344 TEST_F(ProximityAuthCryptAuthEnrollmentManagerTest
, ForceEnrollment
) {
345 enrollment_manager_
.Start();
347 EXPECT_CALL(*sync_scheduler(), ForceSync());
348 enrollment_manager_
.ForceEnrollmentNow(
349 cryptauth::INVOCATION_REASON_SERVER_INITIATED
);
351 auto completion_callback
=
352 FireSchedulerForEnrollment(cryptauth::INVOCATION_REASON_SERVER_INITIATED
);
354 clock_
->SetNow(base::Time::FromDoubleT(kLaterTimeNow
));
355 EXPECT_CALL(*this, OnEnrollmentFinishedProxy(true));
356 completion_callback
.Run(true);
357 EXPECT_EQ(clock_
->Now(), enrollment_manager_
.GetLastEnrollmentTime());
360 TEST_F(ProximityAuthCryptAuthEnrollmentManagerTest
,
361 EnrollmentFailsThenSucceeds
) {
362 enrollment_manager_
.Start();
363 base::Time old_enrollment_time
= enrollment_manager_
.GetLastEnrollmentTime();
365 // The first periodic enrollment fails.
366 ON_CALL(*sync_scheduler(), GetStrategy())
367 .WillByDefault(Return(SyncScheduler::Strategy::PERIODIC_REFRESH
));
368 auto completion_callback
=
369 FireSchedulerForEnrollment(cryptauth::INVOCATION_REASON_PERIODIC
);
370 clock_
->SetNow(base::Time::FromDoubleT(kLaterTimeNow
));
371 EXPECT_CALL(*this, OnEnrollmentFinishedProxy(false));
372 completion_callback
.Run(false);
373 EXPECT_EQ(old_enrollment_time
, enrollment_manager_
.GetLastEnrollmentTime());
374 EXPECT_TRUE(pref_service_
.GetBoolean(
375 prefs::kCryptAuthEnrollmentIsRecoveringFromFailure
));
377 // The second recovery enrollment succeeds.
378 ON_CALL(*sync_scheduler(), GetStrategy())
379 .WillByDefault(Return(SyncScheduler::Strategy::AGGRESSIVE_RECOVERY
));
380 completion_callback
=
381 FireSchedulerForEnrollment(cryptauth::INVOCATION_REASON_FAILURE_RECOVERY
);
382 clock_
->SetNow(base::Time::FromDoubleT(kLaterTimeNow
+ 30));
383 EXPECT_CALL(*this, OnEnrollmentFinishedProxy(true));
384 completion_callback
.Run(true);
385 EXPECT_EQ(clock_
->Now(), enrollment_manager_
.GetLastEnrollmentTime());
386 EXPECT_FALSE(pref_service_
.GetBoolean(
387 prefs::kCryptAuthEnrollmentIsRecoveringFromFailure
));
390 TEST_F(ProximityAuthCryptAuthEnrollmentManagerTest
,
391 EnrollmentSucceedsForFirstTime
) {
392 // Initialize |enrollment_manager_|.
393 ON_CALL(*sync_scheduler(), GetStrategy())
394 .WillByDefault(Return(SyncScheduler::Strategy::PERIODIC_REFRESH
));
395 gcm_manager_
.set_registration_id(std::string());
396 pref_service_
.ClearPref(prefs::kCryptAuthEnrollmentUserPublicKey
);
397 pref_service_
.ClearPref(prefs::kCryptAuthEnrollmentUserPrivateKey
);
398 pref_service_
.ClearPref(prefs::kCryptAuthEnrollmentLastEnrollmentTimeSeconds
);
399 enrollment_manager_
.Start();
400 EXPECT_FALSE(enrollment_manager_
.IsEnrollmentValid());
402 // Trigger a sync request.
403 EXPECT_CALL(*this, OnEnrollmentStartedProxy());
404 auto sync_request
= make_scoped_ptr(
405 new SyncScheduler::SyncRequest(enrollment_manager_
.GetSyncScheduler()));
406 static_cast<SyncScheduler::Delegate
*>(&enrollment_manager_
)
407 ->OnSyncRequested(sync_request
.Pass());
409 // Complete GCM registration successfully, and expect an enrollment.
410 CryptAuthEnroller::EnrollmentFinishedCallback enrollment_callback
;
411 EXPECT_CALL(*next_cryptauth_enroller(),
412 Enroll(public_key_
, private_key_
, _
,
413 cryptauth::INVOCATION_REASON_INITIALIZATION
, _
))
414 .WillOnce(SaveArg
<4>(&enrollment_callback
));
415 ASSERT_TRUE(gcm_manager_
.registration_in_progress());
416 gcm_manager_
.CompleteRegistration(kGCMRegistrationId
);
418 // Complete CryptAuth enrollment.
419 ASSERT_FALSE(enrollment_callback
.is_null());
420 clock_
->SetNow(base::Time::FromDoubleT(kLaterTimeNow
));
421 EXPECT_CALL(*this, OnEnrollmentFinishedProxy(true));
422 enrollment_callback
.Run(true);
423 EXPECT_EQ(clock_
->Now(), enrollment_manager_
.GetLastEnrollmentTime());
424 EXPECT_TRUE(enrollment_manager_
.IsEnrollmentValid());
426 // Check that CryptAuthEnrollmentManager returns the expected key-pair.
427 EXPECT_EQ(public_key_
, enrollment_manager_
.GetUserPublicKey());
428 EXPECT_EQ(private_key_
, enrollment_manager_
.GetUserPrivateKey());
431 TEST_F(ProximityAuthCryptAuthEnrollmentManagerTest
, GCMRegistrationFails
) {
432 // Initialize |enrollment_manager_|.
433 ON_CALL(*sync_scheduler(), GetStrategy())
434 .WillByDefault(Return(SyncScheduler::Strategy::PERIODIC_REFRESH
));
435 gcm_manager_
.set_registration_id(std::string());
436 enrollment_manager_
.Start();
438 // Trigger a sync request.
439 EXPECT_CALL(*this, OnEnrollmentStartedProxy());
440 auto sync_request
= make_scoped_ptr(
441 new SyncScheduler::SyncRequest(enrollment_manager_
.GetSyncScheduler()));
442 static_cast<SyncScheduler::Delegate
*>(&enrollment_manager_
)
443 ->OnSyncRequested(sync_request
.Pass());
445 // Complete GCM registration with failure.
446 EXPECT_CALL(*this, OnEnrollmentFinishedProxy(false));
447 gcm_manager_
.CompleteRegistration(std::string());
450 TEST_F(ProximityAuthCryptAuthEnrollmentManagerTest
, ReenrollOnGCMPushMessage
) {
451 enrollment_manager_
.Start();
453 // Simulate receiving a GCM push message, forcing the device to re-enroll.
454 gcm_manager_
.PushReenrollMessage();
455 auto completion_callback
=
456 FireSchedulerForEnrollment(cryptauth::INVOCATION_REASON_SERVER_INITIATED
);
458 EXPECT_CALL(*this, OnEnrollmentFinishedProxy(true));
459 completion_callback
.Run(true);
462 } // namespace proximity_auth