Upstream version 8.37.180.0
[platform/framework/web/crosswalk.git] / src / chrome / browser / chromeos / login / auth / parallel_authenticator.cc
1 // Copyright 2014 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/auth/parallel_authenticator.h"
6
7 #include "base/bind.h"
8 #include "base/command_line.h"
9 #include "base/files/file_path.h"
10 #include "base/logging.h"
11 #include "chrome/browser/chrome_notification_types.h"
12 #include "chrome/browser/chromeos/boot_times_loader.h"
13 #include "chrome/browser/chromeos/login/auth/authentication_notification_details.h"
14 #include "chrome/browser/chromeos/login/auth/key.h"
15 #include "chrome/browser/chromeos/login/auth/login_status_consumer.h"
16 #include "chrome/browser/chromeos/login/auth/user_context.h"
17 #include "chrome/browser/chromeos/login/users/user.h"
18 #include "chrome/browser/chromeos/login/users/user_manager.h"
19 #include "chrome/browser/chromeos/ownership/owner_settings_service.h"
20 #include "chrome/browser/chromeos/ownership/owner_settings_service_factory.h"
21 #include "chrome/browser/chromeos/settings/cros_settings.h"
22 #include "chrome/common/chrome_switches.h"
23 #include "chromeos/cryptohome/async_method_caller.h"
24 #include "chromeos/cryptohome/system_salt_getter.h"
25 #include "chromeos/dbus/cryptohome_client.h"
26 #include "chromeos/dbus/dbus_thread_manager.h"
27 #include "chromeos/login/login_state.h"
28 #include "content/public/browser/browser_thread.h"
29 #include "content/public/browser/notification_service.h"
30 #include "third_party/cros_system_api/dbus/service_constants.h"
31
32 using content::BrowserThread;
33
34 namespace chromeos {
35
36 namespace {
37
38 // Hashes |key| with |system_salt| if it its type is KEY_TYPE_PASSWORD_PLAIN.
39 // Returns the keys unmodified otherwise.
40 scoped_ptr<Key> TransformKeyIfNeeded(const Key& key,
41                                      const std::string& system_salt) {
42   scoped_ptr<Key> result(new Key(key));
43   if (result->GetKeyType() == Key::KEY_TYPE_PASSWORD_PLAIN)
44     result->Transform(Key::KEY_TYPE_SALTED_SHA256_TOP_HALF, system_salt);
45
46   return result.Pass();
47 }
48
49 // Records status and calls resolver->Resolve().
50 void TriggerResolve(AuthAttemptState* attempt,
51                     scoped_refptr<ParallelAuthenticator> resolver,
52                     bool success,
53                     cryptohome::MountError return_code) {
54   DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
55   attempt->RecordCryptohomeStatus(success, return_code);
56   resolver->Resolve();
57 }
58
59 // Records get hash status and calls resolver->Resolve().
60 void TriggerResolveHash(AuthAttemptState* attempt,
61                         scoped_refptr<ParallelAuthenticator> resolver,
62                         bool success,
63                         const std::string& username_hash) {
64   DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
65   if (success)
66     attempt->RecordUsernameHash(username_hash);
67   else
68     attempt->RecordUsernameHashFailed();
69   resolver->Resolve();
70 }
71
72 // Calls TriggerResolve while adding login time marker.
73 void TriggerResolveWithLoginTimeMarker(
74     const std::string& marker_name,
75     AuthAttemptState* attempt,
76     scoped_refptr<ParallelAuthenticator> resolver,
77     bool success,
78     cryptohome::MountError return_code) {
79   chromeos::BootTimesLoader::Get()->AddLoginTimeMarker(marker_name, false);
80   TriggerResolve(attempt, resolver, success, return_code);
81 }
82
83 // Calls cryptohome's mount method.
84 void Mount(AuthAttemptState* attempt,
85            scoped_refptr<ParallelAuthenticator> resolver,
86            int flags,
87            const std::string& system_salt) {
88   DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
89   chromeos::BootTimesLoader::Get()->AddLoginTimeMarker(
90       "CryptohomeMount-Start", false);
91   // Set state that username_hash is requested here so that test implementation
92   // that returns directly would not generate 2 OnLoginSucces() calls.
93   attempt->UsernameHashRequested();
94
95   scoped_ptr<Key> key =
96       TransformKeyIfNeeded(*attempt->user_context.GetKey(), system_salt);
97   cryptohome::AsyncMethodCaller::GetInstance()->AsyncMount(
98       attempt->user_context.GetUserID(),
99       key->GetSecret(),
100       flags,
101       base::Bind(&TriggerResolveWithLoginTimeMarker,
102                  "CryptohomeMount-End",
103                  attempt,
104                  resolver));
105   cryptohome::AsyncMethodCaller::GetInstance()->AsyncGetSanitizedUsername(
106       attempt->user_context.GetUserID(),
107       base::Bind(&TriggerResolveHash,
108                  attempt,
109                  resolver));
110 }
111
112 // Calls cryptohome's mount method for guest.
113 void MountGuest(AuthAttemptState* attempt,
114                 scoped_refptr<ParallelAuthenticator> resolver) {
115   DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
116   cryptohome::AsyncMethodCaller::GetInstance()->AsyncMountGuest(
117       base::Bind(&TriggerResolveWithLoginTimeMarker,
118                  "CryptohomeMount-End",
119                  attempt,
120                  resolver));
121 }
122
123 // Calls cryptohome's mount method for guest and also get the user hash from
124 // cryptohome.
125 void MountGuestAndGetHash(AuthAttemptState* attempt,
126                           scoped_refptr<ParallelAuthenticator> resolver) {
127   DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
128   attempt->UsernameHashRequested();
129   cryptohome::AsyncMethodCaller::GetInstance()->AsyncMountGuest(
130       base::Bind(&TriggerResolveWithLoginTimeMarker,
131                  "CryptohomeMount-End",
132                  attempt,
133                  resolver));
134   cryptohome::AsyncMethodCaller::GetInstance()->AsyncGetSanitizedUsername(
135       attempt->user_context.GetUserID(),
136       base::Bind(&TriggerResolveHash,
137                  attempt,
138                  resolver));
139 }
140
141 // Calls cryptohome's MountPublic method
142 void MountPublic(AuthAttemptState* attempt,
143                  scoped_refptr<ParallelAuthenticator> resolver,
144                  int flags) {
145   DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
146   cryptohome::AsyncMethodCaller::GetInstance()->AsyncMountPublic(
147       attempt->user_context.GetUserID(),
148       flags,
149       base::Bind(&TriggerResolveWithLoginTimeMarker,
150                  "CryptohomeMountPublic-End",
151                  attempt,
152                  resolver));
153   cryptohome::AsyncMethodCaller::GetInstance()->AsyncGetSanitizedUsername(
154       attempt->user_context.GetUserID(),
155       base::Bind(&TriggerResolveHash,
156                  attempt,
157                  resolver));
158 }
159
160 // Calls cryptohome's key migration method.
161 void Migrate(AuthAttemptState* attempt,
162              scoped_refptr<ParallelAuthenticator> resolver,
163              bool passing_old_hash,
164              const std::string& old_password,
165              const std::string& system_salt) {
166   DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
167   chromeos::BootTimesLoader::Get()->AddLoginTimeMarker(
168       "CryptohomeMigrate-Start", false);
169   cryptohome::AsyncMethodCaller* caller =
170       cryptohome::AsyncMethodCaller::GetInstance();
171
172   // TODO(bartfab): Retrieve the hashing algorithm and salt to use for |old_key|
173   // from cryptohomed.
174   scoped_ptr<Key> old_key =
175       TransformKeyIfNeeded(Key(old_password), system_salt);
176   scoped_ptr<Key> new_key =
177       TransformKeyIfNeeded(*attempt->user_context.GetKey(), system_salt);
178   if (passing_old_hash) {
179     caller->AsyncMigrateKey(attempt->user_context.GetUserID(),
180                             old_key->GetSecret(),
181                             new_key->GetSecret(),
182                             base::Bind(&TriggerResolveWithLoginTimeMarker,
183                                        "CryptohomeMount-End",
184                                        attempt,
185                                        resolver));
186   } else {
187     caller->AsyncMigrateKey(attempt->user_context.GetUserID(),
188                             new_key->GetSecret(),
189                             old_key->GetSecret(),
190                             base::Bind(&TriggerResolveWithLoginTimeMarker,
191                                        "CryptohomeMount-End",
192                                        attempt,
193                                        resolver));
194   }
195 }
196
197 // Calls cryptohome's remove method.
198 void Remove(AuthAttemptState* attempt,
199             scoped_refptr<ParallelAuthenticator> resolver) {
200   DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
201   chromeos::BootTimesLoader::Get()->AddLoginTimeMarker(
202       "CryptohomeRemove-Start", false);
203   cryptohome::AsyncMethodCaller::GetInstance()->AsyncRemove(
204       attempt->user_context.GetUserID(),
205       base::Bind(&TriggerResolveWithLoginTimeMarker,
206                  "CryptohomeRemove-End",
207                  attempt,
208                  resolver));
209 }
210
211 // Calls cryptohome's key check method.
212 void CheckKey(AuthAttemptState* attempt,
213               scoped_refptr<ParallelAuthenticator> resolver,
214               const std::string& system_salt) {
215   DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
216   scoped_ptr<Key> key =
217       TransformKeyIfNeeded(*attempt->user_context.GetKey(), system_salt);
218   cryptohome::AsyncMethodCaller::GetInstance()->AsyncCheckKey(
219       attempt->user_context.GetUserID(),
220       key->GetSecret(),
221       base::Bind(&TriggerResolve, attempt, resolver));
222 }
223
224 }  // namespace
225
226 ParallelAuthenticator::ParallelAuthenticator(LoginStatusConsumer* consumer)
227     : Authenticator(consumer),
228       migrate_attempted_(false),
229       remove_attempted_(false),
230       resync_attempted_(false),
231       ephemeral_mount_attempted_(false),
232       check_key_attempted_(false),
233       already_reported_success_(false),
234       owner_is_verified_(false),
235       user_can_login_(false),
236       remove_user_data_on_failure_(false),
237       delayed_login_failure_(NULL) {
238 }
239
240 void ParallelAuthenticator::AuthenticateToLogin(
241     Profile* profile,
242     const UserContext& user_context) {
243   authentication_profile_ = profile;
244   current_state_.reset(new AuthAttemptState(
245       user_context,
246       User::USER_TYPE_REGULAR,
247       false,  // unlock
248       false,  // online_complete
249       !UserManager::Get()->IsKnownUser(user_context.GetUserID())));
250   // Reset the verified flag.
251   owner_is_verified_ = false;
252
253   SystemSaltGetter::Get()->GetSystemSalt(
254       base::Bind(&Mount,
255                  current_state_.get(),
256                  scoped_refptr<ParallelAuthenticator>(this),
257                  cryptohome::MOUNT_FLAGS_NONE));
258 }
259
260 void ParallelAuthenticator::CompleteLogin(Profile* profile,
261                                           const UserContext& user_context) {
262   authentication_profile_ = profile;
263   current_state_.reset(new AuthAttemptState(
264       user_context,
265       User::USER_TYPE_REGULAR,
266       true,   // unlock
267       false,  // online_complete
268       !UserManager::Get()->IsKnownUser(user_context.GetUserID())));
269
270   // Reset the verified flag.
271   owner_is_verified_ = false;
272
273   SystemSaltGetter::Get()->GetSystemSalt(
274       base::Bind(&Mount,
275                  current_state_.get(),
276                  scoped_refptr<ParallelAuthenticator>(this),
277                  cryptohome::MOUNT_FLAGS_NONE));
278
279   // For login completion from extension, we just need to resolve the current
280   // auth attempt state, the rest of OAuth related tasks will be done in
281   // parallel.
282   BrowserThread::PostTask(
283       BrowserThread::UI, FROM_HERE,
284       base::Bind(&ParallelAuthenticator::ResolveLoginCompletionStatus, this));
285 }
286
287 void ParallelAuthenticator::AuthenticateToUnlock(
288     const UserContext& user_context) {
289   current_state_.reset(new AuthAttemptState(user_context,
290                                             User::USER_TYPE_REGULAR,
291                                             true,     // unlock
292                                             true,     // online_complete
293                                             false));  // user_is_new
294   remove_user_data_on_failure_ = false;
295   check_key_attempted_ = true;
296   SystemSaltGetter::Get()->GetSystemSalt(
297       base::Bind(&CheckKey,
298                  current_state_.get(),
299                  scoped_refptr<ParallelAuthenticator>(this)));
300 }
301
302 void ParallelAuthenticator::LoginAsLocallyManagedUser(
303     const UserContext& user_context) {
304   DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
305   // TODO(nkostylev): Pass proper value for |user_is_new| or remove (not used).
306   current_state_.reset(
307       new AuthAttemptState(user_context,
308                            User::USER_TYPE_LOCALLY_MANAGED,
309                            false,    // unlock
310                            false,    // online_complete
311                            false));  // user_is_new
312   remove_user_data_on_failure_ = false;
313   SystemSaltGetter::Get()->GetSystemSalt(
314       base::Bind(&Mount,
315                  current_state_.get(),
316                  scoped_refptr<ParallelAuthenticator>(this),
317                  cryptohome::MOUNT_FLAGS_NONE));
318 }
319
320 void ParallelAuthenticator::LoginRetailMode() {
321   DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
322   // Note: |kRetailModeUserEMail| is used in other places to identify a retail
323   // mode session.
324   current_state_.reset(new AuthAttemptState(
325       UserContext(UserManager::kRetailModeUserName),
326       User::USER_TYPE_RETAIL_MODE,
327       false,    // unlock
328       false,    // online_complete
329       false));  // user_is_new
330   remove_user_data_on_failure_ = false;
331   ephemeral_mount_attempted_ = true;
332   MountGuestAndGetHash(current_state_.get(),
333                        scoped_refptr<ParallelAuthenticator>(this));
334 }
335
336 void ParallelAuthenticator::LoginOffTheRecord() {
337   DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
338   current_state_.reset(new AuthAttemptState(
339       UserContext(UserManager::kGuestUserName),
340       User::USER_TYPE_GUEST,
341       false,    // unlock
342       false,    // online_complete
343       false));  // user_is_new
344   remove_user_data_on_failure_ = false;
345   ephemeral_mount_attempted_ = true;
346   MountGuest(current_state_.get(),
347              scoped_refptr<ParallelAuthenticator>(this));
348 }
349
350 void ParallelAuthenticator::LoginAsPublicAccount(const std::string& username) {
351   DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
352   current_state_.reset(new AuthAttemptState(UserContext(username),
353                                             User::USER_TYPE_PUBLIC_ACCOUNT,
354                                             false,    // unlock
355                                             false,    // online_complete
356                                             false));  // user_is_new
357   remove_user_data_on_failure_ = false;
358   ephemeral_mount_attempted_ = true;
359   SystemSaltGetter::Get()->GetSystemSalt(
360       base::Bind(&Mount,
361                  current_state_.get(),
362                  scoped_refptr<ParallelAuthenticator>(this),
363                  cryptohome::CREATE_IF_MISSING | cryptohome::ENSURE_EPHEMERAL));
364 }
365
366 void ParallelAuthenticator::LoginAsKioskAccount(
367     const std::string& app_user_id,
368     bool use_guest_mount) {
369   DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
370
371   const std::string user_id =
372       use_guest_mount ? UserManager::kGuestUserName : app_user_id;
373   current_state_.reset(new AuthAttemptState(UserContext(user_id),
374                                             User::USER_TYPE_KIOSK_APP,
375                                             false,    // unlock
376                                             false,    // online_complete
377                                             false));  // user_is_new
378
379   remove_user_data_on_failure_ = true;
380   if (!use_guest_mount) {
381     MountPublic(current_state_.get(),
382           scoped_refptr<ParallelAuthenticator>(this),
383           cryptohome::CREATE_IF_MISSING);
384   } else {
385     ephemeral_mount_attempted_ = true;
386     MountGuestAndGetHash(current_state_.get(),
387                          scoped_refptr<ParallelAuthenticator>(this));
388   }
389 }
390
391 void ParallelAuthenticator::OnRetailModeLoginSuccess() {
392   DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
393   VLOG(1) << "Retail mode login success";
394   // Send notification of success
395   AuthenticationNotificationDetails details(true);
396   content::NotificationService::current()->Notify(
397       chrome::NOTIFICATION_LOGIN_AUTHENTICATION,
398       content::NotificationService::AllSources(),
399       content::Details<AuthenticationNotificationDetails>(&details));
400   if (consumer_)
401     consumer_->OnRetailModeLoginSuccess(current_state_->user_context);
402 }
403
404 void ParallelAuthenticator::OnLoginSuccess() {
405   DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
406   VLOG(1) << "Login success";
407   // Send notification of success
408   AuthenticationNotificationDetails details(true);
409   content::NotificationService::current()->Notify(
410       chrome::NOTIFICATION_LOGIN_AUTHENTICATION,
411       content::NotificationService::AllSources(),
412       content::Details<AuthenticationNotificationDetails>(&details));
413   {
414     base::AutoLock for_this_block(success_lock_);
415     already_reported_success_ = true;
416   }
417   if (consumer_)
418     consumer_->OnLoginSuccess(current_state_->user_context);
419 }
420
421 void ParallelAuthenticator::OnOffTheRecordLoginSuccess() {
422   DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
423   // Send notification of success
424   AuthenticationNotificationDetails details(true);
425   content::NotificationService::current()->Notify(
426       chrome::NOTIFICATION_LOGIN_AUTHENTICATION,
427       content::NotificationService::AllSources(),
428       content::Details<AuthenticationNotificationDetails>(&details));
429   if (consumer_)
430     consumer_->OnOffTheRecordLoginSuccess();
431 }
432
433 void ParallelAuthenticator::OnPasswordChangeDetected() {
434   DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
435   if (consumer_)
436     consumer_->OnPasswordChangeDetected();
437 }
438
439 void ParallelAuthenticator::OnLoginFailure(const LoginFailure& error) {
440   DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
441
442   // OnLoginFailure will be called again with the same |error|
443   // after the cryptohome has been removed.
444   if (remove_user_data_on_failure_) {
445     delayed_login_failure_ = &error;
446     RemoveEncryptedData();
447     return;
448   }
449
450   // Send notification of failure
451   AuthenticationNotificationDetails details(false);
452   content::NotificationService::current()->Notify(
453       chrome::NOTIFICATION_LOGIN_AUTHENTICATION,
454       content::NotificationService::AllSources(),
455       content::Details<AuthenticationNotificationDetails>(&details));
456   LOG(WARNING) << "Login failed: " << error.GetErrorString();
457   if (consumer_)
458     consumer_->OnLoginFailure(error);
459 }
460
461 void ParallelAuthenticator::RecoverEncryptedData(
462     const std::string& old_password) {
463   migrate_attempted_ = true;
464   current_state_->ResetCryptohomeStatus();
465   SystemSaltGetter::Get()->GetSystemSalt(
466       base::Bind(&Migrate,
467                  current_state_.get(),
468                  scoped_refptr<ParallelAuthenticator>(this),
469                  true,
470                  old_password));
471 }
472
473 void ParallelAuthenticator::RemoveEncryptedData() {
474   remove_attempted_ = true;
475   current_state_->ResetCryptohomeStatus();
476   BrowserThread::PostTask(
477       BrowserThread::UI, FROM_HERE,
478       base::Bind(&Remove,
479                  current_state_.get(),
480                  scoped_refptr<ParallelAuthenticator>(this)));
481 }
482
483 void ParallelAuthenticator::ResyncEncryptedData() {
484   resync_attempted_ = true;
485   current_state_->ResetCryptohomeStatus();
486   BrowserThread::PostTask(
487       BrowserThread::UI, FROM_HERE,
488       base::Bind(&Remove,
489                  current_state_.get(),
490                  scoped_refptr<ParallelAuthenticator>(this)));
491 }
492
493 bool ParallelAuthenticator::VerifyOwner() {
494   if (owner_is_verified_)
495     return true;
496   // Check if policy data is fine and continue in safe mode if needed.
497   bool is_safe_mode = false;
498   CrosSettings::Get()->GetBoolean(kPolicyMissingMitigationMode, &is_safe_mode);
499   if (!is_safe_mode) {
500     // Now we can continue with the login and report mount success.
501     user_can_login_ = true;
502     owner_is_verified_ = true;
503     return true;
504   }
505
506   const std::string& user_id = current_state_->user_context.GetUserID();
507   OwnerSettingsServiceFactory::GetInstance()->SetUsername(user_id);
508
509   // This should trigger certificate loading, which is needed in order to
510   // correctly determine if the current user is the owner.
511   if (LoginState::IsInitialized()) {
512     LoginState::Get()->SetLoggedInState(LoginState::LOGGED_IN_SAFE_MODE,
513                                         LoginState::LOGGED_IN_USER_NONE);
514   }
515
516   OwnerSettingsService::IsPrivateKeyExistAsync(
517       base::Bind(&ParallelAuthenticator::OnOwnershipChecked, this));
518   return false;
519 }
520
521 void ParallelAuthenticator::OnOwnershipChecked(bool is_owner) {
522   // Now we can check if this user is the owner.
523   user_can_login_ = is_owner;
524   owner_is_verified_ = true;
525   Resolve();
526 }
527
528 void ParallelAuthenticator::Resolve() {
529   DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
530   int mount_flags = cryptohome::MOUNT_FLAGS_NONE;
531   ParallelAuthenticator::AuthState state = ResolveState();
532   VLOG(1) << "Resolved state to: " << state;
533   switch (state) {
534     case CONTINUE:
535     case POSSIBLE_PW_CHANGE:
536     case NO_MOUNT:
537       // These are intermediate states; we need more info from a request that
538       // is still pending.
539       break;
540     case FAILED_MOUNT:
541       // In this case, whether login succeeded or not, we can't log
542       // the user in because their data is horked.  So, override with
543       // the appropriate failure.
544       BrowserThread::PostTask(
545           BrowserThread::UI, FROM_HERE,
546           base::Bind(&ParallelAuthenticator::OnLoginFailure, this,
547                      LoginFailure(LoginFailure::COULD_NOT_MOUNT_CRYPTOHOME)));
548       break;
549     case FAILED_REMOVE:
550       // In this case, we tried to remove the user's old cryptohome at her
551       // request, and the remove failed.
552       remove_user_data_on_failure_ = false;
553       BrowserThread::PostTask(
554           BrowserThread::UI, FROM_HERE,
555           base::Bind(&ParallelAuthenticator::OnLoginFailure, this,
556                      LoginFailure(LoginFailure::DATA_REMOVAL_FAILED)));
557       break;
558     case FAILED_TMPFS:
559       // In this case, we tried to mount a tmpfs for guest and failed.
560       BrowserThread::PostTask(
561           BrowserThread::UI, FROM_HERE,
562           base::Bind(&ParallelAuthenticator::OnLoginFailure, this,
563                      LoginFailure(LoginFailure::COULD_NOT_MOUNT_TMPFS)));
564       break;
565     case FAILED_TPM:
566       // In this case, we tried to create/mount cryptohome and failed
567       // because of the critical TPM error.
568       // Chrome will notify user and request reboot.
569       BrowserThread::PostTask(
570           BrowserThread::UI, FROM_HERE,
571           base::Bind(&ParallelAuthenticator::OnLoginFailure, this,
572                      LoginFailure(LoginFailure::TPM_ERROR)));
573       break;
574     case FAILED_USERNAME_HASH:
575       // In this case, we failed the GetSanitizedUsername request to
576       // cryptohomed. This can happen for any login attempt.
577       BrowserThread::PostTask(
578           BrowserThread::UI, FROM_HERE,
579           base::Bind(&ParallelAuthenticator::OnLoginFailure, this,
580                      LoginFailure(LoginFailure::USERNAME_HASH_FAILED)));
581       break;
582     case REMOVED_DATA_AFTER_FAILURE:
583       remove_user_data_on_failure_ = false;
584       BrowserThread::PostTask(
585           BrowserThread::UI, FROM_HERE,
586           base::Bind(&ParallelAuthenticator::OnLoginFailure, this,
587                      *delayed_login_failure_));
588       break;
589     case CREATE_NEW:
590       mount_flags |= cryptohome::CREATE_IF_MISSING;
591     case RECOVER_MOUNT:
592       current_state_->ResetCryptohomeStatus();
593       SystemSaltGetter::Get()->GetSystemSalt(
594           base::Bind(&Mount,
595                      current_state_.get(),
596                      scoped_refptr<ParallelAuthenticator>(this),
597                      mount_flags));
598       break;
599     case NEED_OLD_PW:
600       BrowserThread::PostTask(
601           BrowserThread::UI, FROM_HERE,
602           base::Bind(&ParallelAuthenticator::OnPasswordChangeDetected, this));
603       break;
604     case ONLINE_FAILED:
605     case NEED_NEW_PW:
606     case HAVE_NEW_PW:
607       NOTREACHED() << "Using obsolete ClientLogin code path.";
608       break;
609     case OFFLINE_LOGIN:
610       VLOG(2) << "Offline login";
611       // Fall through.
612     case UNLOCK:
613       VLOG(2) << "Unlock";
614       // Fall through.
615     case ONLINE_LOGIN:
616       VLOG(2) << "Online login";
617       BrowserThread::PostTask(
618           BrowserThread::UI, FROM_HERE,
619           base::Bind(&ParallelAuthenticator::OnLoginSuccess, this));
620       break;
621     case DEMO_LOGIN:
622       VLOG(2) << "Retail mode login";
623       current_state_->user_context.SetIsUsingOAuth(false);
624       BrowserThread::PostTask(
625           BrowserThread::UI, FROM_HERE,
626           base::Bind(&ParallelAuthenticator::OnRetailModeLoginSuccess, this));
627       break;
628     case GUEST_LOGIN:
629       BrowserThread::PostTask(
630           BrowserThread::UI, FROM_HERE,
631           base::Bind(&ParallelAuthenticator::OnOffTheRecordLoginSuccess, this));
632       break;
633     case KIOSK_ACCOUNT_LOGIN:
634     case PUBLIC_ACCOUNT_LOGIN:
635       current_state_->user_context.SetIsUsingOAuth(false);
636       BrowserThread::PostTask(
637           BrowserThread::UI, FROM_HERE,
638           base::Bind(&ParallelAuthenticator::OnLoginSuccess, this));
639       break;
640     case LOCALLY_MANAGED_USER_LOGIN:
641       current_state_->user_context.SetIsUsingOAuth(false);
642       BrowserThread::PostTask(
643           BrowserThread::UI, FROM_HERE,
644           base::Bind(&ParallelAuthenticator::OnLoginSuccess, this));
645       break;
646     case LOGIN_FAILED:
647       current_state_->ResetCryptohomeStatus();
648       BrowserThread::PostTask(BrowserThread::UI,
649                               FROM_HERE,
650                               base::Bind(
651                                   &ParallelAuthenticator::OnLoginFailure,
652                                   this,
653                                   current_state_->online_outcome()));
654       break;
655     case OWNER_REQUIRED: {
656       current_state_->ResetCryptohomeStatus();
657       bool success = false;
658       DBusThreadManager::Get()->GetCryptohomeClient()->Unmount(&success);
659       if (!success) {
660         // Maybe we should reboot immediately here?
661         LOG(ERROR) << "Couldn't unmount users home!";
662       }
663       BrowserThread::PostTask(BrowserThread::UI,
664                               FROM_HERE,
665                               base::Bind(
666                                   &ParallelAuthenticator::OnLoginFailure,
667                                   this,
668                                   LoginFailure(LoginFailure::OWNER_REQUIRED)));
669       break;
670     }
671     default:
672       NOTREACHED();
673       break;
674   }
675 }
676
677 ParallelAuthenticator::~ParallelAuthenticator() {}
678
679 ParallelAuthenticator::AuthState ParallelAuthenticator::ResolveState() {
680   DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
681   // If we haven't mounted the user's home dir yet or
682   // haven't got sanitized username value, we can't be done.
683   // We never get past here if any of these two cryptohome ops is still pending.
684   // This is an important invariant.
685   if (!current_state_->cryptohome_complete() ||
686       !current_state_->username_hash_obtained()) {
687     return CONTINUE;
688   }
689
690   AuthState state = CONTINUE;
691
692   if (current_state_->cryptohome_outcome() &&
693       current_state_->username_hash_valid()) {
694     state = ResolveCryptohomeSuccessState();
695   } else {
696     state = ResolveCryptohomeFailureState();
697   }
698
699   DCHECK(current_state_->cryptohome_complete());  // Ensure invariant holds.
700   migrate_attempted_ = false;
701   remove_attempted_ = false;
702   resync_attempted_ = false;
703   ephemeral_mount_attempted_ = false;
704   check_key_attempted_ = false;
705
706   if (state != POSSIBLE_PW_CHANGE &&
707       state != NO_MOUNT &&
708       state != OFFLINE_LOGIN)
709     return state;
710
711   if (current_state_->online_complete()) {
712     if (current_state_->online_outcome().reason() == LoginFailure::NONE) {
713       // Online attempt succeeded as well, so combine the results.
714       return ResolveOnlineSuccessState(state);
715     }
716     NOTREACHED() << "Using obsolete ClientLogin code path.";
717   }
718   // if online isn't complete yet, just return the offline result.
719   return state;
720 }
721
722 ParallelAuthenticator::AuthState
723 ParallelAuthenticator::ResolveCryptohomeFailureState() {
724   DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
725   if (remove_attempted_ || resync_attempted_)
726     return FAILED_REMOVE;
727   if (ephemeral_mount_attempted_)
728     return FAILED_TMPFS;
729   if (migrate_attempted_)
730     return NEED_OLD_PW;
731   if (check_key_attempted_)
732     return LOGIN_FAILED;
733
734   if (current_state_->cryptohome_code() ==
735       cryptohome::MOUNT_ERROR_TPM_NEEDS_REBOOT) {
736     // Critical TPM error detected, reboot needed.
737     return FAILED_TPM;
738   }
739
740   // Return intermediate states in the following case:
741   // when there is an online result to use;
742   // This is the case after user finishes Gaia login;
743   if (current_state_->online_complete()) {
744     if (current_state_->cryptohome_code() ==
745         cryptohome::MOUNT_ERROR_KEY_FAILURE) {
746       // If we tried a mount but they used the wrong key, we may need to
747       // ask the user for her old password.  We'll only know once we've
748       // done the online check.
749       return POSSIBLE_PW_CHANGE;
750     }
751     if (current_state_->cryptohome_code() ==
752         cryptohome::MOUNT_ERROR_USER_DOES_NOT_EXIST) {
753       // If we tried a mount but the user did not exist, then we should wait
754       // for online login to succeed and try again with the "create" flag set.
755       return NO_MOUNT;
756     }
757   }
758
759   if (!current_state_->username_hash_valid())
760     return FAILED_USERNAME_HASH;
761
762   return FAILED_MOUNT;
763 }
764
765 ParallelAuthenticator::AuthState
766 ParallelAuthenticator::ResolveCryptohomeSuccessState() {
767   DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
768   if (resync_attempted_)
769     return CREATE_NEW;
770   if (remove_attempted_)
771     return REMOVED_DATA_AFTER_FAILURE;
772   if (migrate_attempted_)
773     return RECOVER_MOUNT;
774   if (check_key_attempted_)
775     return UNLOCK;
776
777   if (current_state_->user_type == User::USER_TYPE_GUEST)
778     return GUEST_LOGIN;
779   if (current_state_->user_type == User::USER_TYPE_RETAIL_MODE)
780     return DEMO_LOGIN;
781   if (current_state_->user_type == User::USER_TYPE_PUBLIC_ACCOUNT)
782     return PUBLIC_ACCOUNT_LOGIN;
783   if (current_state_->user_type == User::USER_TYPE_KIOSK_APP)
784     return KIOSK_ACCOUNT_LOGIN;
785   if (current_state_->user_type == User::USER_TYPE_LOCALLY_MANAGED)
786     return LOCALLY_MANAGED_USER_LOGIN;
787
788   if (!VerifyOwner())
789     return CONTINUE;
790   return user_can_login_ ? OFFLINE_LOGIN : OWNER_REQUIRED;
791 }
792
793 ParallelAuthenticator::AuthState
794 ParallelAuthenticator::ResolveOnlineSuccessState(
795     ParallelAuthenticator::AuthState offline_state) {
796   DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
797   switch (offline_state) {
798     case POSSIBLE_PW_CHANGE:
799       return NEED_OLD_PW;
800     case NO_MOUNT:
801       return CREATE_NEW;
802     case OFFLINE_LOGIN:
803       return ONLINE_LOGIN;
804     default:
805       NOTREACHED();
806       return offline_state;
807   }
808 }
809
810 void ParallelAuthenticator::ResolveLoginCompletionStatus() {
811   // Shortcut online state resolution process.
812   current_state_->RecordOnlineLoginStatus(LoginFailure::LoginFailureNone());
813   Resolve();
814 }
815
816 void ParallelAuthenticator::SetOwnerState(bool owner_check_finished,
817                                           bool check_result) {
818   owner_is_verified_ = owner_check_finished;
819   user_can_login_ = check_result;
820 }
821
822 }  // namespace chromeos