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.
4
5 #include "chrome/browser/chromeos/login/easy_unlock/easy_unlock_auth_attempt.h"
6
7 #include <stddef.h>
8
9 #include "base/command_line.h"
10 #include "base/stl_util.h"
11 #include "build/build_config.h"
12 #include "chrome/browser/chromeos/login/easy_unlock/easy_unlock_key_manager.h"
13 #include "chromeos/components/proximity_auth/screenlock_bridge.h"
14 #include "testing/gtest/include/gtest/gtest.h"
15
16 namespace chromeos {
17 namespace {
18
19 // Fake user ids used in tests.
20 const char kTestUser1[] = "user1";
21 const char kTestUser2[] = "user2";
22
23 const unsigned char kSecret[] = {0x7c, 0x85, 0x82, 0x7d, 0x00, 0x1f,
24 0x6a, 0x29, 0x2f, 0xc4, 0xb5, 0x60,
25 0x08, 0x9b, 0xb0, 0x5b};
26
27 const unsigned char kSessionKey[] = {0xc3, 0xd9, 0x83, 0x16, 0x52, 0xde,
28 0x99, 0xd7, 0x4e, 0x60, 0xf9, 0xec,
29 0xa8, 0x9c, 0x0e, 0xbe};
30
31 const unsigned char kWrappedSecret[] = {
32 0x3a, 0xea, 0x51, 0xd9, 0x64, 0x64, 0xe1, 0xcd, 0xd8, 0xee, 0x99,
33 0xf5, 0xb1, 0xd4, 0x9f, 0xc4, 0x28, 0xd6, 0xfd, 0x69, 0x0b, 0x9e,
34 0x06, 0x21, 0xfc, 0x40, 0x1f, 0xeb, 0x75, 0x64, 0x52, 0xd8};
35
GetSecret()36 std::string GetSecret() {
37 return std::string(reinterpret_cast<const char*>(kSecret),
38 base::size(kSecret));
39 }
40
GetWrappedSecret()41 std::string GetWrappedSecret() {
42 return std::string(reinterpret_cast<const char*>(kWrappedSecret),
43 base::size(kWrappedSecret));
44 }
45
GetSessionKey()46 std::string GetSessionKey() {
47 return std::string(reinterpret_cast<const char*>(kSessionKey),
48 base::size(kSessionKey));
49 }
50
51 // Fake lock handler to be used in these tests.
52 class TestLockHandler : public proximity_auth::ScreenlockBridge::LockHandler {
53 public:
54 // The state of unlock/signin procedure.
55 enum AuthState {
56 STATE_NONE,
57 STATE_ATTEMPTING_UNLOCK,
58 STATE_UNLOCK_CANCELED,
59 STATE_UNLOCK_DONE,
60 STATE_ATTEMPTING_SIGNIN,
61 STATE_SIGNIN_CANCELED,
62 STATE_SIGNIN_DONE
63 };
64
TestLockHandler(const AccountId & account_id)65 explicit TestLockHandler(const AccountId& account_id)
66 : state_(STATE_NONE),
67 auth_type_(proximity_auth::mojom::AuthType::USER_CLICK),
68 account_id_(account_id) {}
69
~TestLockHandler()70 ~TestLockHandler() override {}
71
set_state(AuthState value)72 void set_state(AuthState value) { state_ = value; }
state() const73 AuthState state() const { return state_; }
74
75 // Sets the secret that is expected to be sent to `AttemptEasySignin`
set_expected_secret(const std::string & value)76 void set_expected_secret(const std::string& value) {
77 expected_secret_ = value;
78 }
79
80 // Not using `SetAuthType` to make sure it's not called during tests.
set_auth_type(proximity_auth::mojom::AuthType value)81 void set_auth_type(proximity_auth::mojom::AuthType value) {
82 auth_type_ = value;
83 }
84
85 // proximity_auth::ScreenlockBridge::LockHandler implementation:
ShowBannerMessage(const base::string16 & message,bool is_warning)86 void ShowBannerMessage(const base::string16& message,
87 bool is_warning) override {
88 ADD_FAILURE() << "Should not be reached.";
89 }
90
ShowUserPodCustomIcon(const AccountId & account_id,const proximity_auth::ScreenlockBridge::UserPodCustomIconOptions & icon)91 void ShowUserPodCustomIcon(
92 const AccountId& account_id,
93 const proximity_auth::ScreenlockBridge::UserPodCustomIconOptions& icon)
94 override {
95 ADD_FAILURE() << "Should not be reached.";
96 }
97
HideUserPodCustomIcon(const AccountId & account_id)98 void HideUserPodCustomIcon(const AccountId& account_id) override {
99 ADD_FAILURE() << "Should not be reached.";
100 }
101
EnableInput()102 void EnableInput() override {
103 ASSERT_EQ(STATE_ATTEMPTING_UNLOCK, state_);
104 state_ = STATE_UNLOCK_CANCELED;
105 }
106
SetAuthType(const AccountId & account_id,proximity_auth::mojom::AuthType auth_type,const base::string16 & auth_value)107 void SetAuthType(const AccountId& account_id,
108 proximity_auth::mojom::AuthType auth_type,
109 const base::string16& auth_value) override {
110 ADD_FAILURE() << "Should not be reached.";
111 }
112
GetAuthType(const AccountId & account_id) const113 proximity_auth::mojom::AuthType GetAuthType(
114 const AccountId& account_id) const override {
115 return auth_type_;
116 }
117
GetScreenType() const118 ScreenType GetScreenType() const override {
119 // Return an arbitrary value; this is not used by the test code.
120 return LOCK_SCREEN;
121 }
122
Unlock(const AccountId & account_id)123 void Unlock(const AccountId& account_id) override {
124 ASSERT_TRUE(account_id_ == account_id)
125 << "account_id_=" << account_id_.Serialize()
126 << " != " << account_id.Serialize();
127 ASSERT_EQ(STATE_ATTEMPTING_UNLOCK, state_);
128 state_ = STATE_UNLOCK_DONE;
129 }
130
AttemptEasySignin(const AccountId & account_id,const std::string & secret,const std::string & key_label)131 void AttemptEasySignin(const AccountId& account_id,
132 const std::string& secret,
133 const std::string& key_label) override {
134 ASSERT_TRUE(account_id_ == account_id)
135 << "account_id_=" << account_id_.Serialize()
136 << " != " << account_id.Serialize();
137
138 ASSERT_EQ(STATE_ATTEMPTING_SIGNIN, state_);
139 if (secret.empty()) {
140 state_ = STATE_SIGNIN_CANCELED;
141 } else {
142 ASSERT_EQ(expected_secret_, secret);
143 ASSERT_EQ(EasyUnlockKeyManager::GetKeyLabel(0u), key_label);
144 state_ = STATE_SIGNIN_DONE;
145 }
146 }
147
148 private:
149 AuthState state_;
150 proximity_auth::mojom::AuthType auth_type_;
151 const AccountId account_id_;
152 std::string expected_secret_;
153
154 DISALLOW_COPY_AND_ASSIGN(TestLockHandler);
155 };
156
157 class EasyUnlockAuthAttemptUnlockTest : public testing::Test {
158 public:
EasyUnlockAuthAttemptUnlockTest()159 EasyUnlockAuthAttemptUnlockTest() {}
~EasyUnlockAuthAttemptUnlockTest()160 ~EasyUnlockAuthAttemptUnlockTest() override {}
161
SetUp()162 void SetUp() override {
163 auth_attempt_.reset(new EasyUnlockAuthAttempt(
164 test_account_id1_, EasyUnlockAuthAttempt::TYPE_UNLOCK));
165 }
166
TearDown()167 void TearDown() override {
168 proximity_auth::ScreenlockBridge::Get()->SetLockHandler(NULL);
169 auth_attempt_.reset();
170 }
171
172 protected:
InitScreenLock()173 void InitScreenLock() {
174 lock_handler_.reset(new TestLockHandler(test_account_id1_));
175 lock_handler_->set_state(TestLockHandler::STATE_ATTEMPTING_UNLOCK);
176 proximity_auth::ScreenlockBridge::Get()->SetLockHandler(
177 lock_handler_.get());
178 }
179
180 std::unique_ptr<EasyUnlockAuthAttempt> auth_attempt_;
181 std::unique_ptr<TestLockHandler> lock_handler_;
182
183 const AccountId test_account_id1_ = AccountId::FromUserEmail(kTestUser1);
184 const AccountId test_account_id2_ = AccountId::FromUserEmail(kTestUser2);
185
186 private:
187 DISALLOW_COPY_AND_ASSIGN(EasyUnlockAuthAttemptUnlockTest);
188 };
189
TEST_F(EasyUnlockAuthAttemptUnlockTest,StartWhenNotLocked)190 TEST_F(EasyUnlockAuthAttemptUnlockTest, StartWhenNotLocked) {
191 ASSERT_FALSE(proximity_auth::ScreenlockBridge::Get()->IsLocked());
192
193 EXPECT_FALSE(auth_attempt_->Start());
194 }
195
TEST_F(EasyUnlockAuthAttemptUnlockTest,StartWhenAuthTypeIsPassword)196 TEST_F(EasyUnlockAuthAttemptUnlockTest, StartWhenAuthTypeIsPassword) {
197 InitScreenLock();
198 ASSERT_TRUE(proximity_auth::ScreenlockBridge::Get()->IsLocked());
199 ASSERT_EQ(TestLockHandler::STATE_ATTEMPTING_UNLOCK, lock_handler_->state());
200
201 lock_handler_->set_auth_type(
202 proximity_auth::mojom::AuthType::OFFLINE_PASSWORD);
203
204 EXPECT_FALSE(auth_attempt_->Start());
205
206 EXPECT_EQ(TestLockHandler::STATE_UNLOCK_CANCELED, lock_handler_->state());
207 }
208
TEST_F(EasyUnlockAuthAttemptUnlockTest,ResetBeforeFinalizeUnlock)209 TEST_F(EasyUnlockAuthAttemptUnlockTest, ResetBeforeFinalizeUnlock) {
210 InitScreenLock();
211 ASSERT_TRUE(proximity_auth::ScreenlockBridge::Get()->IsLocked());
212 ASSERT_EQ(TestLockHandler::STATE_ATTEMPTING_UNLOCK, lock_handler_->state());
213
214 ASSERT_TRUE(auth_attempt_->Start());
215
216 EXPECT_EQ(TestLockHandler::STATE_ATTEMPTING_UNLOCK, lock_handler_->state());
217
218 auth_attempt_.reset();
219
220 EXPECT_EQ(TestLockHandler::STATE_UNLOCK_CANCELED, lock_handler_->state());
221 }
222
TEST_F(EasyUnlockAuthAttemptUnlockTest,FinalizeUnlockFailure)223 TEST_F(EasyUnlockAuthAttemptUnlockTest, FinalizeUnlockFailure) {
224 InitScreenLock();
225 ASSERT_TRUE(proximity_auth::ScreenlockBridge::Get()->IsLocked());
226 ASSERT_EQ(TestLockHandler::STATE_ATTEMPTING_UNLOCK, lock_handler_->state());
227
228 ASSERT_TRUE(auth_attempt_->Start());
229
230 EXPECT_EQ(TestLockHandler::STATE_ATTEMPTING_UNLOCK, lock_handler_->state());
231
232 auth_attempt_->FinalizeUnlock(test_account_id1_, false);
233
234 EXPECT_EQ(TestLockHandler::STATE_UNLOCK_CANCELED, lock_handler_->state());
235 }
236
TEST_F(EasyUnlockAuthAttemptUnlockTest,FinalizeSigninCalled)237 TEST_F(EasyUnlockAuthAttemptUnlockTest, FinalizeSigninCalled) {
238 InitScreenLock();
239 ASSERT_TRUE(proximity_auth::ScreenlockBridge::Get()->IsLocked());
240 ASSERT_EQ(TestLockHandler::STATE_ATTEMPTING_UNLOCK, lock_handler_->state());
241
242 ASSERT_TRUE(auth_attempt_->Start());
243
244 EXPECT_EQ(TestLockHandler::STATE_ATTEMPTING_UNLOCK, lock_handler_->state());
245
246 // Wrapped secret and key should be irrelevant in this case.
247 auth_attempt_->FinalizeSignin(test_account_id1_, GetWrappedSecret(),
248 GetSessionKey());
249
250 EXPECT_EQ(TestLockHandler::STATE_UNLOCK_CANCELED, lock_handler_->state());
251 }
252
TEST_F(EasyUnlockAuthAttemptUnlockTest,UnlockSucceeds)253 TEST_F(EasyUnlockAuthAttemptUnlockTest, UnlockSucceeds) {
254 InitScreenLock();
255 ASSERT_TRUE(proximity_auth::ScreenlockBridge::Get()->IsLocked());
256 ASSERT_EQ(TestLockHandler::STATE_ATTEMPTING_UNLOCK, lock_handler_->state());
257
258 ASSERT_TRUE(auth_attempt_->Start());
259
260 EXPECT_EQ(TestLockHandler::STATE_ATTEMPTING_UNLOCK, lock_handler_->state());
261
262 auth_attempt_->FinalizeUnlock(test_account_id1_, true);
263
264 ASSERT_EQ(TestLockHandler::STATE_UNLOCK_DONE, lock_handler_->state());
265 }
266
TEST_F(EasyUnlockAuthAttemptUnlockTest,FinalizeUnlockCalledForWrongUser)267 TEST_F(EasyUnlockAuthAttemptUnlockTest, FinalizeUnlockCalledForWrongUser) {
268 InitScreenLock();
269 ASSERT_TRUE(proximity_auth::ScreenlockBridge::Get()->IsLocked());
270 ASSERT_EQ(TestLockHandler::STATE_ATTEMPTING_UNLOCK, lock_handler_->state());
271
272 ASSERT_TRUE(auth_attempt_->Start());
273
274 EXPECT_EQ(TestLockHandler::STATE_ATTEMPTING_UNLOCK, lock_handler_->state());
275
276 auth_attempt_->FinalizeUnlock(test_account_id2_, true);
277
278 // If FinalizeUnlock is called for an incorrect user, it should be ignored
279 // rather than cancelling the authentication.
280 ASSERT_EQ(TestLockHandler::STATE_ATTEMPTING_UNLOCK, lock_handler_->state());
281
282 // When FinalizeUnlock is called for the correct user, it should work as
283 // expected.
284 auth_attempt_->FinalizeUnlock(test_account_id1_, true);
285
286 ASSERT_EQ(TestLockHandler::STATE_UNLOCK_DONE, lock_handler_->state());
287 }
288
289 class EasyUnlockAuthAttemptSigninTest : public testing::Test {
290 public:
EasyUnlockAuthAttemptSigninTest()291 EasyUnlockAuthAttemptSigninTest() {}
~EasyUnlockAuthAttemptSigninTest()292 ~EasyUnlockAuthAttemptSigninTest() override {}
293
SetUp()294 void SetUp() override {
295 auth_attempt_.reset(new EasyUnlockAuthAttempt(
296 test_account_id1_, EasyUnlockAuthAttempt::TYPE_SIGNIN));
297 }
298
TearDown()299 void TearDown() override {
300 proximity_auth::ScreenlockBridge::Get()->SetLockHandler(NULL);
301 auth_attempt_.reset();
302 }
303
304 protected:
InitScreenLock()305 void InitScreenLock() {
306 lock_handler_.reset(new TestLockHandler(test_account_id1_));
307 lock_handler_->set_state(TestLockHandler::STATE_ATTEMPTING_SIGNIN);
308 proximity_auth::ScreenlockBridge::Get()->SetLockHandler(
309 lock_handler_.get());
310 }
311
312 std::unique_ptr<EasyUnlockAuthAttempt> auth_attempt_;
313 std::unique_ptr<TestLockHandler> lock_handler_;
314
315 const AccountId test_account_id1_ = AccountId::FromUserEmail(kTestUser1);
316 const AccountId test_account_id2_ = AccountId::FromUserEmail(kTestUser2);
317
318 private:
319 DISALLOW_COPY_AND_ASSIGN(EasyUnlockAuthAttemptSigninTest);
320 };
321
TEST_F(EasyUnlockAuthAttemptSigninTest,StartWhenNotLocked)322 TEST_F(EasyUnlockAuthAttemptSigninTest, StartWhenNotLocked) {
323 ASSERT_FALSE(proximity_auth::ScreenlockBridge::Get()->IsLocked());
324
325 EXPECT_FALSE(auth_attempt_->Start());
326 }
327
TEST_F(EasyUnlockAuthAttemptSigninTest,StartWhenAuthTypeIsPassword)328 TEST_F(EasyUnlockAuthAttemptSigninTest, StartWhenAuthTypeIsPassword) {
329 InitScreenLock();
330 ASSERT_TRUE(proximity_auth::ScreenlockBridge::Get()->IsLocked());
331 ASSERT_EQ(TestLockHandler::STATE_ATTEMPTING_SIGNIN, lock_handler_->state());
332
333 lock_handler_->set_auth_type(
334 proximity_auth::mojom::AuthType::OFFLINE_PASSWORD);
335
336 EXPECT_FALSE(auth_attempt_->Start());
337
338 EXPECT_EQ(TestLockHandler::STATE_SIGNIN_CANCELED, lock_handler_->state());
339 }
340
TEST_F(EasyUnlockAuthAttemptSigninTest,ResetBeforeFinalizeSignin)341 TEST_F(EasyUnlockAuthAttemptSigninTest, ResetBeforeFinalizeSignin) {
342 InitScreenLock();
343 ASSERT_TRUE(proximity_auth::ScreenlockBridge::Get()->IsLocked());
344 ASSERT_EQ(TestLockHandler::STATE_ATTEMPTING_SIGNIN, lock_handler_->state());
345
346 ASSERT_TRUE(auth_attempt_->Start());
347
348 EXPECT_EQ(TestLockHandler::STATE_ATTEMPTING_SIGNIN, lock_handler_->state());
349
350 auth_attempt_.reset();
351
352 EXPECT_EQ(TestLockHandler::STATE_SIGNIN_CANCELED, lock_handler_->state());
353 }
354
TEST_F(EasyUnlockAuthAttemptSigninTest,FinalizeSigninWithEmtpySecret)355 TEST_F(EasyUnlockAuthAttemptSigninTest, FinalizeSigninWithEmtpySecret) {
356 InitScreenLock();
357 ASSERT_TRUE(proximity_auth::ScreenlockBridge::Get()->IsLocked());
358 ASSERT_EQ(TestLockHandler::STATE_ATTEMPTING_SIGNIN, lock_handler_->state());
359
360 ASSERT_TRUE(auth_attempt_->Start());
361
362 EXPECT_EQ(TestLockHandler::STATE_ATTEMPTING_SIGNIN, lock_handler_->state());
363
364 auth_attempt_->FinalizeSignin(test_account_id1_, "", GetSessionKey());
365
366 EXPECT_EQ(TestLockHandler::STATE_SIGNIN_CANCELED, lock_handler_->state());
367 }
368
TEST_F(EasyUnlockAuthAttemptSigninTest,FinalizeSigninWithEmtpyKey)369 TEST_F(EasyUnlockAuthAttemptSigninTest, FinalizeSigninWithEmtpyKey) {
370 InitScreenLock();
371 ASSERT_TRUE(proximity_auth::ScreenlockBridge::Get()->IsLocked());
372 ASSERT_EQ(TestLockHandler::STATE_ATTEMPTING_SIGNIN, lock_handler_->state());
373
374 ASSERT_TRUE(auth_attempt_->Start());
375
376 EXPECT_EQ(TestLockHandler::STATE_ATTEMPTING_SIGNIN, lock_handler_->state());
377
378 auth_attempt_->FinalizeSignin(test_account_id1_, GetWrappedSecret(), "");
379
380 EXPECT_EQ(TestLockHandler::STATE_SIGNIN_CANCELED, lock_handler_->state());
381 }
382
TEST_F(EasyUnlockAuthAttemptSigninTest,SigninSuccess)383 TEST_F(EasyUnlockAuthAttemptSigninTest, SigninSuccess) {
384 InitScreenLock();
385 ASSERT_TRUE(proximity_auth::ScreenlockBridge::Get()->IsLocked());
386 ASSERT_EQ(TestLockHandler::STATE_ATTEMPTING_SIGNIN, lock_handler_->state());
387
388 ASSERT_TRUE(auth_attempt_->Start());
389
390 EXPECT_EQ(TestLockHandler::STATE_ATTEMPTING_SIGNIN, lock_handler_->state());
391
392 lock_handler_->set_expected_secret(GetSecret());
393 auth_attempt_->FinalizeSignin(test_account_id1_, GetWrappedSecret(),
394 GetSessionKey());
395
396 EXPECT_EQ(TestLockHandler::STATE_SIGNIN_DONE, lock_handler_->state());
397 }
398
TEST_F(EasyUnlockAuthAttemptSigninTest,WrongWrappedSecret)399 TEST_F(EasyUnlockAuthAttemptSigninTest, WrongWrappedSecret) {
400 InitScreenLock();
401 ASSERT_TRUE(proximity_auth::ScreenlockBridge::Get()->IsLocked());
402 ASSERT_EQ(TestLockHandler::STATE_ATTEMPTING_SIGNIN, lock_handler_->state());
403
404 ASSERT_TRUE(auth_attempt_->Start());
405
406 EXPECT_EQ(TestLockHandler::STATE_ATTEMPTING_SIGNIN, lock_handler_->state());
407
408 auth_attempt_->FinalizeSignin(test_account_id1_, "wrong_secret",
409 GetSessionKey());
410
411 EXPECT_EQ(TestLockHandler::STATE_SIGNIN_CANCELED, lock_handler_->state());
412 }
413
TEST_F(EasyUnlockAuthAttemptSigninTest,InvalidSessionKey)414 TEST_F(EasyUnlockAuthAttemptSigninTest, InvalidSessionKey) {
415 InitScreenLock();
416 ASSERT_TRUE(proximity_auth::ScreenlockBridge::Get()->IsLocked());
417 ASSERT_EQ(TestLockHandler::STATE_ATTEMPTING_SIGNIN, lock_handler_->state());
418
419 ASSERT_TRUE(auth_attempt_->Start());
420
421 EXPECT_EQ(TestLockHandler::STATE_ATTEMPTING_SIGNIN, lock_handler_->state());
422
423 auth_attempt_->FinalizeSignin(test_account_id1_, GetWrappedSecret(),
424 "invalid_key");
425
426 EXPECT_EQ(TestLockHandler::STATE_SIGNIN_CANCELED, lock_handler_->state());
427 }
428
TEST_F(EasyUnlockAuthAttemptSigninTest,FinalizeUnlockCalled)429 TEST_F(EasyUnlockAuthAttemptSigninTest, FinalizeUnlockCalled) {
430 InitScreenLock();
431 ASSERT_TRUE(proximity_auth::ScreenlockBridge::Get()->IsLocked());
432 ASSERT_EQ(TestLockHandler::STATE_ATTEMPTING_SIGNIN, lock_handler_->state());
433
434 ASSERT_TRUE(auth_attempt_->Start());
435
436 EXPECT_EQ(TestLockHandler::STATE_ATTEMPTING_SIGNIN, lock_handler_->state());
437
438 auth_attempt_->FinalizeUnlock(test_account_id1_, true);
439
440 EXPECT_EQ(TestLockHandler::STATE_SIGNIN_CANCELED, lock_handler_->state());
441 }
442
TEST_F(EasyUnlockAuthAttemptSigninTest,FinalizeSigninCalledForWrongUser)443 TEST_F(EasyUnlockAuthAttemptSigninTest, FinalizeSigninCalledForWrongUser) {
444 InitScreenLock();
445 ASSERT_TRUE(proximity_auth::ScreenlockBridge::Get()->IsLocked());
446 ASSERT_EQ(TestLockHandler::STATE_ATTEMPTING_SIGNIN, lock_handler_->state());
447
448 ASSERT_TRUE(auth_attempt_->Start());
449
450 EXPECT_EQ(TestLockHandler::STATE_ATTEMPTING_SIGNIN, lock_handler_->state());
451
452 lock_handler_->set_expected_secret(GetSecret());
453
454 auth_attempt_->FinalizeSignin(test_account_id2_, GetWrappedSecret(),
455 GetSessionKey());
456
457 EXPECT_EQ(TestLockHandler::STATE_ATTEMPTING_SIGNIN, lock_handler_->state());
458
459 auth_attempt_->FinalizeSignin(test_account_id1_, GetWrappedSecret(),
460 GetSessionKey());
461
462 EXPECT_EQ(TestLockHandler::STATE_SIGNIN_DONE, lock_handler_->state());
463 }
464
465 } // namespace
466 } // namespace chromeos
467