Home | History | Annotate | Download | only in managed
      1 // Copyright (c) 2012 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/managed/managed_user_authenticator.h"
      6 
      7 #include "base/bind.h"
      8 #include "base/strings/string_number_conversions.h"
      9 #include "base/strings/string_util.h"
     10 #include "chrome/browser/chromeos/boot_times_loader.h"
     11 #include "chrome/browser/chromeos/login/parallel_authenticator.h"
     12 #include "chromeos/cryptohome/async_method_caller.h"
     13 #include "chromeos/cryptohome/system_salt_getter.h"
     14 #include "chromeos/dbus/cryptohome_client.h"
     15 #include "chromeos/dbus/dbus_thread_manager.h"
     16 #include "content/public/browser/browser_thread.h"
     17 #include "crypto/sha2.h"
     18 #include "google_apis/gaia/gaia_auth_util.h"
     19 #include "third_party/cros_system_api/dbus/service_constants.h"
     20 
     21 using content::BrowserThread;
     22 
     23 namespace chromeos {
     24 
     25 namespace {
     26 
     27 // Records status and calls resolver->Resolve().
     28 void TriggerResolve(ManagedUserAuthenticator::AuthAttempt* attempt,
     29                     scoped_refptr<ManagedUserAuthenticator> resolver,
     30                     bool success,
     31                     cryptohome::MountError return_code) {
     32   DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
     33   attempt->RecordCryptohomeStatus(success, return_code);
     34   resolver->Resolve();
     35 }
     36 
     37 // Records status and calls resolver->Resolve().
     38 void TriggerResolveResult(ManagedUserAuthenticator::AuthAttempt* attempt,
     39                           scoped_refptr<ManagedUserAuthenticator> resolver,
     40                           bool success,
     41                           const std::string& result) {
     42   DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
     43   attempt->RecordHash(result);
     44   resolver->Resolve();
     45 }
     46 
     47 // Calls TriggerResolve while adding login time marker.
     48 void TriggerResolveWithLoginTimeMarker(
     49     const std::string& marker_name,
     50     ManagedUserAuthenticator::AuthAttempt* attempt,
     51     scoped_refptr<ManagedUserAuthenticator> resolver,
     52     bool success,
     53     cryptohome::MountError return_code) {
     54   chromeos::BootTimesLoader::Get()->AddLoginTimeMarker(marker_name, false);
     55   TriggerResolve(attempt, resolver, success, return_code);
     56 }
     57 
     58 // Calls cryptohome's mount method.
     59 void Mount(ManagedUserAuthenticator::AuthAttempt* attempt,
     60            scoped_refptr<ManagedUserAuthenticator> resolver,
     61            int flags,
     62            const std::string& system_salt) {
     63   DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
     64   chromeos::BootTimesLoader::Get()->AddLoginTimeMarker(
     65       "CryptohomeMount-LMU-Start", false);
     66   cryptohome::AsyncMethodCaller::GetInstance()->AsyncMount(
     67       attempt->username,
     68       ParallelAuthenticator::HashPassword(attempt->password, system_salt),
     69       flags,
     70       base::Bind(&TriggerResolveWithLoginTimeMarker,
     71                  "CryptohomeMount-LMU-End",
     72                  attempt,
     73                  resolver));
     74 
     75   cryptohome::AsyncMethodCaller::GetInstance()->AsyncGetSanitizedUsername(
     76       attempt->username,
     77       base::Bind(&TriggerResolveResult, attempt, resolver));
     78 }
     79 
     80 // Calls cryptohome's addKey method.
     81 void AddKey(ManagedUserAuthenticator::AuthAttempt* attempt,
     82             scoped_refptr<ManagedUserAuthenticator> resolver,
     83             const std::string& master_key,
     84             const std::string& system_salt) {
     85   DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
     86   chromeos::BootTimesLoader::Get()->AddLoginTimeMarker(
     87       "CryptohomeAddKey-LMU-Start", false);
     88   cryptohome::AsyncMethodCaller::GetInstance()->AsyncAddKey(
     89       attempt->username,
     90       ParallelAuthenticator::HashPassword(attempt->password, system_salt),
     91       ParallelAuthenticator::HashPassword(master_key, system_salt),
     92       base::Bind(&TriggerResolveWithLoginTimeMarker,
     93                  "CryptohomeAddKey-LMU-End",
     94                  attempt,
     95                  resolver));
     96 }
     97 
     98 }  // namespace
     99 
    100 ManagedUserAuthenticator::ManagedUserAuthenticator(AuthStatusConsumer* consumer)
    101     : consumer_(consumer) {}
    102 
    103 void ManagedUserAuthenticator::AuthenticateToMount(
    104     const std::string& username,
    105     const std::string& password) {
    106   std::string canonicalized = gaia::CanonicalizeEmail(username);
    107 
    108   current_state_.reset(new ManagedUserAuthenticator::AuthAttempt(
    109       canonicalized, password, false));
    110 
    111   SystemSaltGetter::Get()->GetSystemSalt(
    112       base::Bind(&Mount,
    113                  current_state_.get(),
    114                  scoped_refptr<ManagedUserAuthenticator>(this),
    115                  cryptohome::MOUNT_FLAGS_NONE));
    116 }
    117 
    118 void ManagedUserAuthenticator::AuthenticateToCreate(
    119     const std::string& username,
    120     const std::string& password) {
    121   std::string canonicalized = gaia::CanonicalizeEmail(username);
    122 
    123   current_state_.reset(new ManagedUserAuthenticator::AuthAttempt(
    124       canonicalized, password, false));
    125 
    126   SystemSaltGetter::Get()->GetSystemSalt(
    127       base::Bind(&Mount,
    128                  current_state_.get(),
    129                  scoped_refptr<ManagedUserAuthenticator>(this),
    130                  cryptohome::CREATE_IF_MISSING));
    131 }
    132 
    133 void ManagedUserAuthenticator::AddMasterKey(
    134     const std::string& username,
    135     const std::string& password,
    136     const std::string& master_key) {
    137   std::string canonicalized = gaia::CanonicalizeEmail(username);
    138 
    139   current_state_.reset(new ManagedUserAuthenticator::AuthAttempt(
    140       canonicalized, password, true));
    141 
    142   SystemSaltGetter::Get()->GetSystemSalt(
    143       base::Bind(&AddKey,
    144                  current_state_.get(),
    145                  scoped_refptr<ManagedUserAuthenticator>(this),
    146                  master_key));
    147 }
    148 
    149 void ManagedUserAuthenticator::OnAuthenticationSuccess(
    150     const std::string& mount_hash,
    151     bool add_key) {
    152   DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
    153   VLOG(1) << "Locally managed user authentication success";
    154   if (consumer_) {
    155     if (add_key)
    156       consumer_->OnAddKeySuccess();
    157     else
    158       consumer_->OnMountSuccess(mount_hash);
    159   }
    160 }
    161 
    162 void ManagedUserAuthenticator::OnAuthenticationFailure(
    163     ManagedUserAuthenticator::AuthState state) {
    164   DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
    165   LOG(WARNING) << "Locally managed user authentication failure";
    166   if (consumer_)
    167     consumer_->OnAuthenticationFailure(state);
    168 }
    169 
    170 void ManagedUserAuthenticator::Resolve() {
    171   DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
    172   ManagedUserAuthenticator::AuthState state = ResolveState();
    173   VLOG(1) << "Resolved state to: " << state;
    174   switch (state) {
    175     case CONTINUE:
    176       // These are intermediate states; we need more info from a request that
    177       // is still pending.
    178       break;
    179     case FAILED_MOUNT:
    180       // In this case, whether login succeeded or not, we can't log
    181       // the user in because their data is horked.  So, override with
    182       // the appropriate failure.
    183       BrowserThread::PostTask(
    184           BrowserThread::UI,
    185           FROM_HERE,
    186           base::Bind(
    187               &ManagedUserAuthenticator::OnAuthenticationFailure, this, state));
    188       break;
    189     case NO_MOUNT:
    190       // In this case, whether login succeeded or not, we can't log
    191       // the user in because no data exist. So, override with
    192       // the appropriate failure.
    193       BrowserThread::PostTask(
    194           BrowserThread::UI,
    195           FROM_HERE,
    196           base::Bind(
    197               &ManagedUserAuthenticator::OnAuthenticationFailure, this, state));
    198       break;
    199     case FAILED_TPM:
    200       // In this case, we tried to create/mount cryptohome and failed
    201       // because of the critical TPM error.
    202       // Chrome will notify user and request reboot.
    203       BrowserThread::PostTask(
    204           BrowserThread::UI,
    205           FROM_HERE,
    206           base::Bind(
    207               &ManagedUserAuthenticator::OnAuthenticationFailure, this, state));
    208       break;
    209     case SUCCESS:
    210       VLOG(2) << "Locally managed user login";
    211       BrowserThread::PostTask(
    212           BrowserThread::UI,
    213           FROM_HERE,
    214           base::Bind(&ManagedUserAuthenticator::OnAuthenticationSuccess,
    215                      this,
    216                      current_state_->hash(),
    217                      current_state_->add_key));
    218       break;
    219     default:
    220       NOTREACHED();
    221       break;
    222   }
    223 }
    224 
    225 ManagedUserAuthenticator::~ManagedUserAuthenticator() {}
    226 
    227 ManagedUserAuthenticator::AuthState ManagedUserAuthenticator::ResolveState() {
    228   DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
    229   // If we haven't mounted the user's home dir yet, we can't be done.
    230   // We never get past here if a cryptohome op is still pending.
    231   // This is an important invariant.
    232   if (!current_state_->cryptohome_complete())
    233     return CONTINUE;
    234   if (!current_state_->add_key && !current_state_->hash_obtained())
    235     return CONTINUE;
    236 
    237   AuthState state;
    238 
    239   if (current_state_->cryptohome_outcome())
    240     state = ResolveCryptohomeSuccessState();
    241   else
    242     state = ResolveCryptohomeFailureState();
    243 
    244   DCHECK(current_state_->cryptohome_complete());
    245   DCHECK(current_state_->hash_obtained() || current_state_->add_key);
    246   return state;
    247 }
    248 
    249 ManagedUserAuthenticator::AuthState
    250     ManagedUserAuthenticator::ResolveCryptohomeFailureState() {
    251   DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
    252   if (current_state_->cryptohome_code() ==
    253       cryptohome::MOUNT_ERROR_TPM_NEEDS_REBOOT) {
    254     // Critical TPM error detected, reboot needed.
    255     return FAILED_TPM;
    256   }
    257 
    258   if (current_state_->cryptohome_code() ==
    259       cryptohome::MOUNT_ERROR_USER_DOES_NOT_EXIST) {
    260     // If we tried a mount but the user did not exist, then we should wait
    261     // for online login to succeed and try again with the "create" flag set.
    262     return NO_MOUNT;
    263   }
    264 
    265   return FAILED_MOUNT;
    266 }
    267 
    268 ManagedUserAuthenticator::AuthState
    269     ManagedUserAuthenticator::ResolveCryptohomeSuccessState() {
    270   DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
    271   return SUCCESS;
    272 }
    273 
    274 ManagedUserAuthenticator::AuthAttempt::AuthAttempt(const std::string& username,
    275                                                    const std::string& password,
    276                                                    bool add_key_attempt)
    277     : username(username),
    278       password(password),
    279       add_key(add_key_attempt),
    280       cryptohome_complete_(false),
    281       cryptohome_outcome_(false),
    282       hash_obtained_(false),
    283       cryptohome_code_(cryptohome::MOUNT_ERROR_NONE) {}
    284 
    285 ManagedUserAuthenticator::AuthAttempt::~AuthAttempt() {}
    286 
    287 void ManagedUserAuthenticator::AuthAttempt::RecordCryptohomeStatus(
    288     bool cryptohome_outcome,
    289     cryptohome::MountError cryptohome_code) {
    290   DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
    291   cryptohome_complete_ = true;
    292   cryptohome_outcome_ = cryptohome_outcome;
    293   cryptohome_code_ = cryptohome_code;
    294 }
    295 
    296 void ManagedUserAuthenticator::AuthAttempt::RecordHash(
    297     const std::string& hash) {
    298   DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
    299   hash_obtained_ = true;
    300   hash_ = hash;
    301 }
    302 
    303 bool ManagedUserAuthenticator::AuthAttempt::cryptohome_complete() {
    304   DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
    305   return cryptohome_complete_;
    306 }
    307 
    308 bool ManagedUserAuthenticator::AuthAttempt::cryptohome_outcome() {
    309   DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
    310   return cryptohome_outcome_;
    311 }
    312 
    313 cryptohome::MountError
    314     ManagedUserAuthenticator::AuthAttempt::cryptohome_code() {
    315   DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
    316   return cryptohome_code_;
    317 }
    318 
    319 bool ManagedUserAuthenticator::AuthAttempt::hash_obtained() {
    320   DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
    321   return hash_obtained_;
    322 }
    323 
    324 std::string ManagedUserAuthenticator::AuthAttempt::hash() {
    325   DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
    326   return hash_;
    327 }
    328 
    329 }  // namespace chromeos
    330