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