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