1 // Copyright (c) 2011 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/google_authenticator.h"
6
7 #include <string>
8 #include <vector>
9
10 #include "base/file_path.h"
11 #include "base/file_util.h"
12 #include "base/memory/scoped_ptr.h"
13 #include "base/message_loop.h"
14 #include "base/path_service.h"
15 #include "base/string_util.h"
16 #include "base/stringprintf.h"
17 #include "chrome/browser/chromeos/cros/mock_cryptohome_library.h"
18 #include "chrome/browser/chromeos/cros/mock_library_loader.h"
19 #include "chrome/browser/chromeos/login/client_login_response_handler.h"
20 #include "chrome/browser/chromeos/login/issue_response_handler.h"
21 #include "chrome/browser/chromeos/login/mock_auth_response_handler.h"
22 #include "chrome/browser/chromeos/login/mock_login_status_consumer.h"
23 #include "chrome/browser/chromeos/login/mock_url_fetchers.h"
24 #include "chrome/browser/chromeos/login/mock_user_manager.h"
25 #include "chrome/browser/chromeos/login/user_manager.h"
26 #include "chrome/common/chrome_paths.h"
27 #include "chrome/common/net/gaia/gaia_auth_fetcher_unittest.h"
28 #include "chrome/common/net/url_fetcher.h"
29 #include "chrome/test/testing_profile.h"
30 #include "content/browser/browser_thread.h"
31 #include "googleurl/src/gurl.h"
32 #include "net/base/net_errors.h"
33 #include "net/url_request/url_request_status.h"
34 #include "testing/gmock/include/gmock/gmock.h"
35 #include "testing/gtest/include/gtest/gtest.h"
36
37 using namespace file_util;
38 using ::testing::AnyNumber;
39 using ::testing::DoAll;
40 using ::testing::Eq;
41 using ::testing::Invoke;
42 using ::testing::Return;
43 using ::testing::SetArgumentPointee;
44 using ::testing::_;
45
46 namespace chromeos {
47
48 class GoogleAuthenticatorTest : public ::testing::Test {
49 public:
GoogleAuthenticatorTest()50 GoogleAuthenticatorTest()
51 : message_loop_ui_(MessageLoop::TYPE_UI),
52 ui_thread_(BrowserThread::UI, &message_loop_ui_),
53 username_("me@nowhere.org"),
54 password_("fakepass"),
55 result_("", "", "", ""),
56 bytes_as_ascii_("ffff"),
57 user_manager_(new MockUserManager) {
58 memset(fake_hash_, 0, sizeof(fake_hash_));
59 fake_hash_[0] = 10;
60 fake_hash_[1] = 1;
61 fake_hash_[7] = 10 << 4;
62 hash_ascii_.assign("0a010000000000a0");
63 hash_ascii_.append(std::string(16, '0'));
64
65 memset(raw_bytes_, 0xff, sizeof(raw_bytes_));
66 }
~GoogleAuthenticatorTest()67 ~GoogleAuthenticatorTest() {}
68
SetUp()69 virtual void SetUp() {
70 chromeos::CrosLibrary::TestApi* test_api =
71 chromeos::CrosLibrary::Get()->GetTestApi();
72
73 loader_ = new MockLibraryLoader();
74 ON_CALL(*loader_, Load(_))
75 .WillByDefault(Return(true));
76 EXPECT_CALL(*loader_, Load(_))
77 .Times(AnyNumber());
78
79 test_api->SetLibraryLoader(loader_, true);
80
81 mock_library_ = new MockCryptohomeLibrary();
82 test_api->SetCryptohomeLibrary(mock_library_, true);
83 }
84
85 // Tears down the test fixture.
TearDown()86 virtual void TearDown() {
87 // Prevent bogus gMock leak check from firing.
88 chromeos::CrosLibrary::TestApi* test_api =
89 chromeos::CrosLibrary::Get()->GetTestApi();
90 test_api->SetLibraryLoader(NULL, false);
91 test_api->SetCryptohomeLibrary(NULL, false);
92 }
93
PopulateTempFile(const char * data,int data_len)94 FilePath PopulateTempFile(const char* data, int data_len) {
95 FilePath out;
96 FILE* tmp_file = CreateAndOpenTemporaryFile(&out);
97 EXPECT_NE(tmp_file, static_cast<FILE*>(NULL));
98 EXPECT_EQ(WriteFile(out, data, data_len), data_len);
99 EXPECT_TRUE(CloseFile(tmp_file));
100 return out;
101 }
102
FakeLocalaccountFile(const std::string & ascii)103 FilePath FakeLocalaccountFile(const std::string& ascii) {
104 FilePath exe_dir;
105 FilePath local_account_file;
106 PathService::Get(base::DIR_EXE, &exe_dir);
107 FILE* tmp_file = CreateAndOpenTemporaryFileInDir(exe_dir,
108 &local_account_file);
109 int ascii_len = ascii.length();
110 EXPECT_NE(tmp_file, static_cast<FILE*>(NULL));
111 EXPECT_EQ(WriteFile(local_account_file, ascii.c_str(), ascii_len),
112 ascii_len);
113 EXPECT_TRUE(CloseFile(tmp_file));
114 return local_account_file;
115 }
116
ReadLocalaccountFile(GoogleAuthenticator * auth,const std::string & filename)117 void ReadLocalaccountFile(GoogleAuthenticator* auth,
118 const std::string& filename) {
119 BrowserThread file_thread(BrowserThread::FILE);
120 file_thread.Start();
121
122 BrowserThread::PostTask(
123 BrowserThread::FILE, FROM_HERE,
124 NewRunnableMethod(auth,
125 &GoogleAuthenticator::LoadLocalaccount,
126 filename));
127 }
128
PrepForLogin(GoogleAuthenticator * auth)129 void PrepForLogin(GoogleAuthenticator* auth) {
130 auth->set_password_hash(hash_ascii_);
131 auth->set_username(username_);
132 auth->set_password(password_);
133 auth->SetLocalaccount("");
134 auth->set_user_manager(user_manager_.get());
135 ON_CALL(*user_manager_.get(), IsKnownUser(username_))
136 .WillByDefault(Return(true));
137 }
138
PrepForFailedLogin(GoogleAuthenticator * auth)139 void PrepForFailedLogin(GoogleAuthenticator* auth) {
140 PrepForLogin(auth);
141 auth->set_hosted_policy(GaiaAuthFetcher::HostedAccountsAllowed);
142 }
143
CancelLogin(GoogleAuthenticator * auth)144 void CancelLogin(GoogleAuthenticator* auth) {
145 BrowserThread::PostTask(
146 BrowserThread::UI,
147 FROM_HERE,
148 NewRunnableMethod(auth,
149 &GoogleAuthenticator::CancelClientLogin));
150 }
151
152 MessageLoop message_loop_ui_;
153 BrowserThread ui_thread_;
154
155 unsigned char fake_hash_[32];
156 std::string hash_ascii_;
157 std::string username_;
158 std::string password_;
159 GaiaAuthConsumer::ClientLoginResult result_;
160 // Mocks, destroyed by CrosLibrary class.
161 MockCryptohomeLibrary* mock_library_;
162 MockLibraryLoader* loader_;
163
164 char raw_bytes_[2];
165 std::string bytes_as_ascii_;
166
167 scoped_ptr<MockUserManager> user_manager_;
168 };
169
TEST_F(GoogleAuthenticatorTest,SaltToAscii)170 TEST_F(GoogleAuthenticatorTest, SaltToAscii) {
171 unsigned char fake_salt[8] = { 0 };
172 fake_salt[0] = 10;
173 fake_salt[1] = 1;
174 fake_salt[7] = 10 << 4;
175 std::vector<unsigned char> salt_v(fake_salt, fake_salt + sizeof(fake_salt));
176
177 scoped_refptr<GoogleAuthenticator> auth(new GoogleAuthenticator(NULL));
178
179 ON_CALL(*mock_library_, GetSystemSalt())
180 .WillByDefault(Return(salt_v));
181 EXPECT_CALL(*mock_library_, GetSystemSalt())
182 .Times(1)
183 .RetiresOnSaturation();
184
185 EXPECT_EQ("0a010000000000a0", auth->SaltAsAscii());
186 }
187
TEST_F(GoogleAuthenticatorTest,ReadLocalaccount)188 TEST_F(GoogleAuthenticatorTest, ReadLocalaccount) {
189 FilePath tmp_file_path = FakeLocalaccountFile(bytes_as_ascii_);
190
191 scoped_refptr<GoogleAuthenticator> auth(new GoogleAuthenticator(NULL));
192 ReadLocalaccountFile(auth.get(), tmp_file_path.BaseName().value());
193 EXPECT_EQ(auth->localaccount_, bytes_as_ascii_);
194 Delete(tmp_file_path, false);
195 }
196
TEST_F(GoogleAuthenticatorTest,ReadLocalaccountTrailingWS)197 TEST_F(GoogleAuthenticatorTest, ReadLocalaccountTrailingWS) {
198 FilePath tmp_file_path =
199 FakeLocalaccountFile(base::StringPrintf("%s\n",
200 bytes_as_ascii_.c_str()));
201
202 scoped_refptr<GoogleAuthenticator> auth(new GoogleAuthenticator(NULL));
203 ReadLocalaccountFile(auth.get(), tmp_file_path.BaseName().value());
204 EXPECT_EQ(auth->localaccount_, bytes_as_ascii_);
205 Delete(tmp_file_path, false);
206 }
207
TEST_F(GoogleAuthenticatorTest,ReadNoLocalaccount)208 TEST_F(GoogleAuthenticatorTest, ReadNoLocalaccount) {
209 FilePath tmp_file_path = FakeLocalaccountFile(bytes_as_ascii_);
210 EXPECT_TRUE(Delete(tmp_file_path, false)); // Ensure non-existent file.
211
212 scoped_refptr<GoogleAuthenticator> auth(new GoogleAuthenticator(NULL));
213 ReadLocalaccountFile(auth.get(), tmp_file_path.BaseName().value());
214 EXPECT_EQ(auth->localaccount_, std::string());
215 }
216
TEST_F(GoogleAuthenticatorTest,OnLoginSuccess)217 TEST_F(GoogleAuthenticatorTest, OnLoginSuccess) {
218 MockConsumer consumer;
219 EXPECT_CALL(consumer, OnLoginSuccess(username_, password_, _, false))
220 .Times(1)
221 .RetiresOnSaturation();
222
223 EXPECT_CALL(*mock_library_, Mount(username_, hash_ascii_, _))
224 .WillOnce(Return(true))
225 .RetiresOnSaturation();
226
227 scoped_refptr<GoogleAuthenticator> auth(new GoogleAuthenticator(&consumer));
228 auth->set_password_hash(hash_ascii_);
229 auth->set_username(username_);
230 auth->set_password(password_);
231 auth->OnLoginSuccess(result_, false);
232 }
233
TEST_F(GoogleAuthenticatorTest,MountFailure)234 TEST_F(GoogleAuthenticatorTest, MountFailure) {
235 MockConsumer consumer;
236 EXPECT_CALL(consumer, OnLoginFailure(_))
237 .Times(1)
238 .RetiresOnSaturation();
239
240 EXPECT_CALL(*mock_library_, Mount(username_, hash_ascii_, _))
241 .WillOnce(Return(false))
242 .RetiresOnSaturation();
243
244 scoped_refptr<GoogleAuthenticator> auth(new GoogleAuthenticator(&consumer));
245 PrepForLogin(auth.get());
246 auth->OnLoginSuccess(result_, false);
247 }
248
TEST_F(GoogleAuthenticatorTest,PasswordChange)249 TEST_F(GoogleAuthenticatorTest, PasswordChange) {
250 MockConsumer consumer;
251 EXPECT_CALL(consumer, OnPasswordChangeDetected(result_))
252 .Times(1)
253 .RetiresOnSaturation();
254 EXPECT_CALL(consumer, OnLoginSuccess(username_, password_, result_, false))
255 .Times(1)
256 .RetiresOnSaturation();
257
258 EXPECT_CALL(*mock_library_, Mount(username_, hash_ascii_, _))
259 .WillOnce(
260 DoAll(SetArgumentPointee<2>(
261 chromeos::kCryptohomeMountErrorKeyFailure),
262 Return(false)))
263 .WillOnce(Return(true))
264 .RetiresOnSaturation();
265
266 EXPECT_CALL(*mock_library_, GetSystemSalt())
267 .WillOnce(Return(chromeos::CryptohomeBlob(8, 'a')))
268 .RetiresOnSaturation();
269 EXPECT_CALL(*mock_library_, MigrateKey(username_, _, hash_ascii_))
270 .WillOnce(Return(true))
271 .RetiresOnSaturation();
272
273 scoped_refptr<GoogleAuthenticator> auth(new GoogleAuthenticator(&consumer));
274 PrepForLogin(auth.get());
275 auth->OnLoginSuccess(result_, false);
276 auth->RecoverEncryptedData("whaty", result_);
277 }
278
TEST_F(GoogleAuthenticatorTest,PasswordChangeWrongPassword)279 TEST_F(GoogleAuthenticatorTest, PasswordChangeWrongPassword) {
280 MockConsumer consumer;
281 EXPECT_CALL(consumer, OnPasswordChangeDetected(result_))
282 .Times(2)
283 .RetiresOnSaturation();
284
285 EXPECT_CALL(*mock_library_, Mount(username_, hash_ascii_, _))
286 .WillOnce(
287 DoAll(SetArgumentPointee<2>(
288 chromeos::kCryptohomeMountErrorKeyFailure),
289 Return(false)))
290 .RetiresOnSaturation();
291 EXPECT_CALL(*mock_library_, GetSystemSalt())
292 .WillOnce(Return(chromeos::CryptohomeBlob(8, 'a')))
293 .RetiresOnSaturation();
294 EXPECT_CALL(*mock_library_, MigrateKey(username_, _, hash_ascii_))
295 .WillOnce(Return(false))
296 .RetiresOnSaturation();
297
298 scoped_refptr<GoogleAuthenticator> auth(new GoogleAuthenticator(&consumer));
299 PrepForLogin(auth.get());
300 auth->OnLoginSuccess(result_, false);
301 auth->RecoverEncryptedData("whaty", result_);
302 }
303
TEST_F(GoogleAuthenticatorTest,ForgetOldData)304 TEST_F(GoogleAuthenticatorTest, ForgetOldData) {
305 MockConsumer consumer;
306 EXPECT_CALL(consumer, OnPasswordChangeDetected(result_))
307 .Times(1)
308 .RetiresOnSaturation();
309 EXPECT_CALL(consumer, OnLoginSuccess(username_, password_, result_, false))
310 .Times(1)
311 .RetiresOnSaturation();
312
313 EXPECT_CALL(*mock_library_, Mount(username_, hash_ascii_, _))
314 .WillOnce(
315 DoAll(SetArgumentPointee<2>(
316 chromeos::kCryptohomeMountErrorKeyFailure),
317 Return(false)))
318 .WillOnce(Return(true))
319 .RetiresOnSaturation();
320
321 EXPECT_CALL(*mock_library_, Remove(username_))
322 .WillOnce(Return(true))
323 .RetiresOnSaturation();
324
325 scoped_refptr<GoogleAuthenticator> auth(new GoogleAuthenticator(&consumer));
326 PrepForLogin(auth.get());
327 auth->OnLoginSuccess(result_, false);
328 auth->ResyncEncryptedData(result_);
329 }
330
TEST_F(GoogleAuthenticatorTest,LoginNetFailure)331 TEST_F(GoogleAuthenticatorTest, LoginNetFailure) {
332 GoogleServiceAuthError error =
333 GoogleServiceAuthError::FromConnectionError(net::ERR_CONNECTION_RESET);
334
335 LoginFailure failure =
336 LoginFailure::FromNetworkAuthFailure(error);
337
338 MockConsumer consumer;
339 EXPECT_CALL(consumer, OnLoginFailure(failure))
340 .Times(1)
341 .RetiresOnSaturation();
342 EXPECT_CALL(*mock_library_, CheckKey(username_, hash_ascii_))
343 .WillOnce(Return(false))
344 .RetiresOnSaturation();
345
346 scoped_refptr<GoogleAuthenticator> auth(new GoogleAuthenticator(&consumer));
347 PrepForLogin(auth.get());
348 auth->OnClientLoginFailure(error);
349 message_loop_ui_.RunAllPending();
350 }
351
TEST_F(GoogleAuthenticatorTest,LoginDenied)352 TEST_F(GoogleAuthenticatorTest, LoginDenied) {
353 GoogleServiceAuthError client_error(
354 GoogleServiceAuthError::INVALID_GAIA_CREDENTIALS);
355
356 MockConsumer consumer;
357 EXPECT_CALL(consumer, OnLoginFailure(_))
358 .Times(1)
359 .RetiresOnSaturation();
360
361 scoped_refptr<GoogleAuthenticator> auth(new GoogleAuthenticator(&consumer));
362 PrepForFailedLogin(auth.get());
363 EXPECT_CALL(*user_manager_.get(), IsKnownUser(username_))
364 .WillOnce(Return(true))
365 .RetiresOnSaturation();
366 auth->OnClientLoginFailure(client_error);
367 message_loop_ui_.RunAllPending();
368 }
369
TEST_F(GoogleAuthenticatorTest,LoginAccountDisabled)370 TEST_F(GoogleAuthenticatorTest, LoginAccountDisabled) {
371 GoogleServiceAuthError client_error(
372 GoogleServiceAuthError::ACCOUNT_DISABLED);
373
374 MockConsumer consumer;
375 EXPECT_CALL(consumer, OnLoginFailure(_))
376 .Times(1)
377 .RetiresOnSaturation();
378
379 scoped_refptr<GoogleAuthenticator> auth(new GoogleAuthenticator(&consumer));
380 PrepForFailedLogin(auth.get());
381 auth->OnClientLoginFailure(client_error);
382 message_loop_ui_.RunAllPending();
383 }
384
TEST_F(GoogleAuthenticatorTest,LoginAccountDeleted)385 TEST_F(GoogleAuthenticatorTest, LoginAccountDeleted) {
386 GoogleServiceAuthError client_error(
387 GoogleServiceAuthError::ACCOUNT_DELETED);
388
389 MockConsumer consumer;
390 EXPECT_CALL(consumer, OnLoginFailure(_))
391 .Times(1)
392 .RetiresOnSaturation();
393
394 scoped_refptr<GoogleAuthenticator> auth(new GoogleAuthenticator(&consumer));
395 PrepForFailedLogin(auth.get());
396 auth->OnClientLoginFailure(client_error);
397 message_loop_ui_.RunAllPending();
398 }
399
TEST_F(GoogleAuthenticatorTest,LoginServiceUnavailable)400 TEST_F(GoogleAuthenticatorTest, LoginServiceUnavailable) {
401 GoogleServiceAuthError client_error(
402 GoogleServiceAuthError::SERVICE_UNAVAILABLE);
403
404 MockConsumer consumer;
405 EXPECT_CALL(consumer, OnLoginFailure(_))
406 .Times(1)
407 .RetiresOnSaturation();
408
409 scoped_refptr<GoogleAuthenticator> auth(new GoogleAuthenticator(&consumer));
410 PrepForFailedLogin(auth.get());
411 auth->OnClientLoginFailure(client_error);
412 message_loop_ui_.RunAllPending();
413 }
414
TEST_F(GoogleAuthenticatorTest,CaptchaErrorOutputted)415 TEST_F(GoogleAuthenticatorTest, CaptchaErrorOutputted) {
416 GoogleServiceAuthError auth_error =
417 GoogleServiceAuthError::FromCaptchaChallenge(
418 "CCTOKEN",
419 GURL("http://www.google.com/accounts/Captcha?ctoken=CCTOKEN"),
420 GURL("http://www.google.com/login/captcha"));
421
422 LoginFailure failure = LoginFailure::FromNetworkAuthFailure(auth_error);
423
424 MockConsumer consumer;
425 EXPECT_CALL(consumer, OnLoginFailure(failure))
426 .Times(1)
427 .RetiresOnSaturation();
428
429 scoped_refptr<GoogleAuthenticator> auth(new GoogleAuthenticator(&consumer));
430 PrepForFailedLogin(auth.get());
431 auth->OnClientLoginFailure(auth_error);
432 message_loop_ui_.RunAllPending();
433 }
434
TEST_F(GoogleAuthenticatorTest,OfflineLogin)435 TEST_F(GoogleAuthenticatorTest, OfflineLogin) {
436 GoogleServiceAuthError auth_error(
437 GoogleServiceAuthError::FromConnectionError(net::ERR_CONNECTION_RESET));
438
439 MockConsumer consumer;
440 EXPECT_CALL(consumer, OnLoginSuccess(username_, password_, result_, false))
441 .Times(1)
442 .RetiresOnSaturation();
443 EXPECT_CALL(*mock_library_, CheckKey(username_, hash_ascii_))
444 .WillOnce(Return(true))
445 .RetiresOnSaturation();
446 EXPECT_CALL(*mock_library_, Mount(username_, hash_ascii_, _))
447 .WillOnce(Return(true))
448 .RetiresOnSaturation();
449
450 scoped_refptr<GoogleAuthenticator> auth(new GoogleAuthenticator(&consumer));
451 PrepForLogin(auth.get());
452 auth->OnClientLoginFailure(auth_error);
453 message_loop_ui_.RunAllPending();
454 }
455
TEST_F(GoogleAuthenticatorTest,OnlineLogin)456 TEST_F(GoogleAuthenticatorTest, OnlineLogin) {
457 MockConsumer consumer;
458 EXPECT_CALL(consumer, OnLoginSuccess(username_, password_, result_, false))
459 .Times(1)
460 .RetiresOnSaturation();
461 EXPECT_CALL(*mock_library_, Mount(username_, hash_ascii_, _))
462 .WillOnce(Return(true))
463 .RetiresOnSaturation();
464
465 scoped_refptr<GoogleAuthenticator> auth(new GoogleAuthenticator(&consumer));
466 PrepForLogin(auth.get());
467 EXPECT_CALL(*user_manager_.get(), IsKnownUser(username_))
468 .WillOnce(Return(true))
469 .RetiresOnSaturation();
470 auth->OnClientLoginSuccess(result_);
471 message_loop_ui_.RunAllPending();
472 }
473
TEST_F(GoogleAuthenticatorTest,CheckLocalaccount)474 TEST_F(GoogleAuthenticatorTest, CheckLocalaccount) {
475 GURL source(AuthResponseHandler::kTokenAuthUrl);
476 net::URLRequestStatus status(net::URLRequestStatus::SUCCESS, 0);
477
478 MockConsumer consumer;
479 EXPECT_CALL(consumer, OnLoginSuccess(username_, std::string(), _, false))
480 .Times(1)
481 .RetiresOnSaturation();
482 EXPECT_CALL(*mock_library_, MountForBwsi(_))
483 .WillOnce(Return(true))
484 .RetiresOnSaturation();
485
486 scoped_refptr<GoogleAuthenticator> auth(new GoogleAuthenticator(&consumer));
487 PrepForLogin(auth.get());
488 auth->SetLocalaccount(username_);
489
490 auth->CheckLocalaccount(LoginFailure(LoginFailure::LOGIN_TIMED_OUT));
491 }
492
TEST_F(GoogleAuthenticatorTest,LocalaccountLogin)493 TEST_F(GoogleAuthenticatorTest, LocalaccountLogin) {
494 // This test checks the logic that governs asynchronously reading the
495 // localaccount name off disk and trying to authenticate against it
496 // simultaneously.
497 MockConsumer consumer;
498 EXPECT_CALL(consumer, OnLoginSuccess(username_, std::string(), _, false))
499 .WillOnce(Invoke(MockConsumer::OnSuccessQuit))
500 .RetiresOnSaturation();
501 EXPECT_CALL(*mock_library_, MountForBwsi(_))
502 .WillOnce(Return(true))
503 .RetiresOnSaturation();
504 // Enable the test to terminate (and fail), even if the login fails.
505 ON_CALL(consumer, OnLoginFailure(_))
506 .WillByDefault(Invoke(MockConsumer::OnFailQuitAndFail));
507
508 // Manually prep for login, so that localaccount isn't set for us.
509 scoped_refptr<GoogleAuthenticator> auth(new GoogleAuthenticator(&consumer));
510 auth->set_password_hash(hash_ascii_);
511 auth->set_username(username_);
512
513 // First, force a check of username_ against the localaccount -- which we
514 // haven't yet gotten off disk.
515 BrowserThread::PostTask(
516 BrowserThread::UI, FROM_HERE,
517 NewRunnableMethod(auth.get(),
518 &GoogleAuthenticator::CheckLocalaccount,
519 LoginFailure(LoginFailure::LOGIN_TIMED_OUT)));
520 message_loop_ui_.RunAllPending();
521 // The foregoing has now rescheduled itself in a few ms because we don't
522 // yet have the localaccount loaded off disk.
523
524 // Now, cause the FILE thread to go load the localaccount off disk.
525 FilePath tmp_file_path = FakeLocalaccountFile(username_);
526 ReadLocalaccountFile(auth.get(), tmp_file_path.BaseName().value());
527
528 // Run remaining events, until OnLoginSuccess or OnLoginFailure is called.
529 message_loop_ui_.Run();
530
531 // Cleanup.
532 Delete(tmp_file_path, false);
533 }
534
TEST_F(GoogleAuthenticatorTest,FullLogin)535 TEST_F(GoogleAuthenticatorTest, FullLogin) {
536 chromeos::CryptohomeBlob salt_v(fake_hash_, fake_hash_ + sizeof(fake_hash_));
537
538 MockConsumer consumer;
539 EXPECT_CALL(consumer, OnLoginSuccess(username_,
540 password_,
541 Eq(result_),
542 false))
543 .Times(1)
544 .RetiresOnSaturation();
545 EXPECT_CALL(*mock_library_, Mount(username_, _, _))
546 .WillOnce(Return(true))
547 .RetiresOnSaturation();
548
549 EXPECT_CALL(*mock_library_, GetSystemSalt())
550 .WillOnce(Return(salt_v))
551 .RetiresOnSaturation();
552
553 TestingProfile profile;
554
555 MockFactory<MockFetcher> factory;
556 URLFetcher::set_factory(&factory);
557
558 scoped_refptr<GoogleAuthenticator> auth(new GoogleAuthenticator(&consumer));
559 EXPECT_CALL(*user_manager_.get(), IsKnownUser(username_))
560 .WillOnce(Return(true))
561 .RetiresOnSaturation();
562 auth->set_user_manager(user_manager_.get());
563 auth->AuthenticateToLogin(
564 &profile, username_, password_, std::string(), std::string());
565
566 URLFetcher::set_factory(NULL);
567 message_loop_ui_.RunAllPending();
568 }
569
TEST_F(GoogleAuthenticatorTest,FullHostedLoginFailure)570 TEST_F(GoogleAuthenticatorTest, FullHostedLoginFailure) {
571 chromeos::CryptohomeBlob salt_v(fake_hash_, fake_hash_ + sizeof(fake_hash_));
572
573 LoginFailure failure_details =
574 LoginFailure::FromNetworkAuthFailure(
575 GoogleServiceAuthError(
576 GoogleServiceAuthError::HOSTED_NOT_ALLOWED));
577
578 MockConsumer consumer;
579 EXPECT_CALL(consumer, OnLoginFailure(failure_details))
580 .WillOnce(Invoke(MockConsumer::OnFailQuit))
581 .RetiresOnSaturation();
582 // A failure case, but we still want the test to finish gracefully.
583 ON_CALL(consumer, OnLoginSuccess(username_, password_, _, _))
584 .WillByDefault(Invoke(MockConsumer::OnSuccessQuitAndFail));
585
586 EXPECT_CALL(*mock_library_, GetSystemSalt())
587 .WillOnce(Return(salt_v))
588 .RetiresOnSaturation();
589
590 TestingProfile profile;
591
592 MockFactory<HostedFetcher> factory_invalid;
593 URLFetcher::set_factory(&factory_invalid);
594
595 scoped_refptr<GoogleAuthenticator> auth(new GoogleAuthenticator(&consumer));
596 auth->set_user_manager(user_manager_.get());
597 EXPECT_CALL(*user_manager_.get(), IsKnownUser(username_))
598 .WillOnce(Return(false))
599 .WillOnce(Return(false))
600 .RetiresOnSaturation();
601 auth->AuthenticateToLogin(
602 &profile, username_, hash_ascii_, std::string(), std::string());
603
604 // For when |auth| tries to load the localaccount file.
605 BrowserThread file_thread(BrowserThread::FILE);
606 file_thread.Start();
607
608 // Run the UI thread until we exit it gracefully.
609 message_loop_ui_.Run();
610 URLFetcher::set_factory(NULL);
611 }
612
TEST_F(GoogleAuthenticatorTest,CancelLogin)613 TEST_F(GoogleAuthenticatorTest, CancelLogin) {
614 chromeos::CryptohomeBlob salt_v(fake_hash_, fake_hash_ + sizeof(fake_hash_));
615
616 MockConsumer consumer;
617 // The expected case.
618 EXPECT_CALL(consumer, OnLoginFailure(_))
619 .WillOnce(Invoke(MockConsumer::OnFailQuit))
620 .RetiresOnSaturation();
621
622 // A failure case, but we still want the test to finish gracefully.
623 ON_CALL(consumer, OnLoginSuccess(username_, password_, _, _))
624 .WillByDefault(Invoke(MockConsumer::OnSuccessQuitAndFail));
625
626 // Stuff we expect to happen along the way.
627 EXPECT_CALL(*mock_library_, GetSystemSalt())
628 .WillOnce(Return(salt_v))
629 .RetiresOnSaturation();
630 EXPECT_CALL(*mock_library_, CheckKey(username_, _))
631 .WillOnce(Return(false))
632 .RetiresOnSaturation();
633
634 TestingProfile profile;
635
636 // This is how we inject fake URLFetcher objects, with a factory.
637 // This factory creates fake URLFetchers that Start() a fake fetch attempt
638 // and then come back on the UI thread after a small delay. They expect to
639 // be canceled before they come back, and the test will fail if they are not.
640 MockFactory<ExpectCanceledFetcher> factory;
641 URLFetcher::set_factory(&factory);
642
643 scoped_refptr<GoogleAuthenticator> auth(new GoogleAuthenticator(&consumer));
644 // For when |auth| tries to load the localaccount file.
645 BrowserThread file_thread(BrowserThread::FILE);
646 file_thread.Start();
647
648 // Start an authentication attempt, which will kick off a URL "fetch" that
649 // we expect to cancel before it completes.
650 auth->AuthenticateToLogin(
651 &profile, username_, hash_ascii_, std::string(), std::string());
652
653 // Post a task to cancel the login attempt.
654 CancelLogin(auth.get());
655
656 URLFetcher::set_factory(NULL);
657
658 // Run the UI thread until we exit it gracefully.
659 message_loop_ui_.Run();
660 }
661
TEST_F(GoogleAuthenticatorTest,CancelLoginAlreadyGotLocalaccount)662 TEST_F(GoogleAuthenticatorTest, CancelLoginAlreadyGotLocalaccount) {
663 chromeos::CryptohomeBlob salt_v(fake_hash_, fake_hash_ + sizeof(fake_hash_));
664
665 MockConsumer consumer;
666 // The expected case.
667 EXPECT_CALL(consumer, OnLoginFailure(_))
668 .WillOnce(Invoke(MockConsumer::OnFailQuit))
669 .RetiresOnSaturation();
670
671 // A failure case, but we still want the test to finish gracefully.
672 ON_CALL(consumer, OnLoginSuccess(username_, password_, _, _))
673 .WillByDefault(Invoke(MockConsumer::OnSuccessQuitAndFail));
674
675 // Stuff we expect to happen along the way.
676 EXPECT_CALL(*mock_library_, GetSystemSalt())
677 .WillOnce(Return(salt_v))
678 .RetiresOnSaturation();
679 EXPECT_CALL(*mock_library_, CheckKey(username_, _))
680 .WillOnce(Return(false))
681 .RetiresOnSaturation();
682
683 TestingProfile profile;
684
685 // This is how we inject fake URLFetcher objects, with a factory.
686 // This factory creates fake URLFetchers that Start() a fake fetch attempt
687 // and then come back on the UI thread after a small delay. They expect to
688 // be canceled before they come back, and the test will fail if they are not.
689 MockFactory<ExpectCanceledFetcher> factory;
690 URLFetcher::set_factory(&factory);
691
692 scoped_refptr<GoogleAuthenticator> auth(new GoogleAuthenticator(&consumer));
693 // This time, instead of allowing |auth| to go get the localaccount file
694 // itself, we simulate the case where the file is already loaded, which
695 // happens when this isn't the first login since chrome started.
696 ReadLocalaccountFile(auth.get(), "");
697
698 // Start an authentication attempt, which will kick off a URL "fetch" that
699 // we expect to cancel before it completes.
700 auth->AuthenticateToLogin(
701 &profile, username_, hash_ascii_, std::string(), std::string());
702
703 // Post a task to cancel the login attempt.
704 CancelLogin(auth.get());
705
706 URLFetcher::set_factory(NULL);
707
708 // Run the UI thread until we exit it gracefully.
709 message_loop_ui_.Run();
710 }
711
712 } // namespace chromeos
713