root/chrome/browser/chromeos/login/managed/managed_user_authenticator.cc

/* [<][>][^][v][top][bottom][index][help] */

DEFINITIONS

This source file includes following definitions.
  1. TriggerResolve
  2. TriggerResolveResult
  3. TriggerResolveWithLoginTimeMarker
  4. Mount
  5. AddKey
  6. AuthenticateToMount
  7. AuthenticateToCreate
  8. AddMasterKey
  9. OnAuthenticationSuccess
  10. OnAuthenticationFailure
  11. Resolve
  12. ResolveState
  13. ResolveCryptohomeFailureState
  14. ResolveCryptohomeSuccessState
  15. cryptohome_code_
  16. RecordCryptohomeStatus
  17. RecordHash
  18. cryptohome_complete
  19. cryptohome_outcome
  20. cryptohome_code
  21. hash_obtained
  22. hash

// Copyright (c) 2012 The Chromium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.

#include "chrome/browser/chromeos/login/managed/managed_user_authenticator.h"

#include "base/bind.h"
#include "base/strings/string_number_conversions.h"
#include "base/strings/string_util.h"
#include "chrome/browser/chromeos/boot_times_loader.h"
#include "chrome/browser/chromeos/login/parallel_authenticator.h"
#include "chromeos/cryptohome/async_method_caller.h"
#include "chromeos/cryptohome/cryptohome_parameters.h"
#include "chromeos/cryptohome/system_salt_getter.h"
#include "chromeos/dbus/cryptohome_client.h"
#include "chromeos/dbus/dbus_thread_manager.h"
#include "content/public/browser/browser_thread.h"
#include "crypto/sha2.h"
#include "google_apis/gaia/gaia_auth_util.h"
#include "third_party/cros_system_api/dbus/service_constants.h"

using content::BrowserThread;

namespace chromeos {

namespace {

// Records status and calls resolver->Resolve().
void TriggerResolve(ManagedUserAuthenticator::AuthAttempt* attempt,
                    scoped_refptr<ManagedUserAuthenticator> resolver,
                    bool success,
                    cryptohome::MountError return_code) {
  DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
  attempt->RecordCryptohomeStatus(success, return_code);
  resolver->Resolve();
}

// Records status and calls resolver->Resolve().
void TriggerResolveResult(ManagedUserAuthenticator::AuthAttempt* attempt,
                          scoped_refptr<ManagedUserAuthenticator> resolver,
                          bool success,
                          const std::string& result) {
  DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
  attempt->RecordHash(result);
  resolver->Resolve();
}

// Calls TriggerResolve while adding login time marker.
void TriggerResolveWithLoginTimeMarker(
    const std::string& marker_name,
    ManagedUserAuthenticator::AuthAttempt* attempt,
    scoped_refptr<ManagedUserAuthenticator> resolver,
    bool success,
    cryptohome::MountError return_code) {
  chromeos::BootTimesLoader::Get()->AddLoginTimeMarker(marker_name, false);
  TriggerResolve(attempt, resolver, success, return_code);
}

// Calls cryptohome's mount method.
void Mount(ManagedUserAuthenticator::AuthAttempt* attempt,
           scoped_refptr<ManagedUserAuthenticator> resolver,
           int flags,
           const std::string& system_salt) {
  DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
  chromeos::BootTimesLoader::Get()->AddLoginTimeMarker(
      "CryptohomeMount-LMU-Start", false);
  cryptohome::AsyncMethodCaller::GetInstance()->AsyncMount(
      attempt->username,
      ParallelAuthenticator::HashPassword(attempt->password, system_salt),
      flags,
      base::Bind(&TriggerResolveWithLoginTimeMarker,
                 "CryptohomeMount-LMU-End",
                 attempt,
                 resolver));

  cryptohome::AsyncMethodCaller::GetInstance()->AsyncGetSanitizedUsername(
      attempt->username,
      base::Bind(&TriggerResolveResult, attempt, resolver));
}

// Calls cryptohome's addKey method.
void AddKey(ManagedUserAuthenticator::AuthAttempt* attempt,
            scoped_refptr<ManagedUserAuthenticator> resolver,
            const std::string& master_key,
            const std::string& system_salt) {
  DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
  chromeos::BootTimesLoader::Get()->AddLoginTimeMarker(
      "CryptohomeAddKey-LMU-Start", false);
  cryptohome::AsyncMethodCaller::GetInstance()->AsyncAddKey(
      attempt->username,
      ParallelAuthenticator::HashPassword(attempt->password, system_salt),
      ParallelAuthenticator::HashPassword(master_key, system_salt),
      base::Bind(&TriggerResolveWithLoginTimeMarker,
                 "CryptohomeAddKey-LMU-End",
                 attempt,
                 resolver));
}

}  // namespace

ManagedUserAuthenticator::ManagedUserAuthenticator(AuthStatusConsumer* consumer)
    : consumer_(consumer) {}

void ManagedUserAuthenticator::AuthenticateToMount(
    const std::string& username,
    const std::string& password) {
  std::string canonicalized = gaia::CanonicalizeEmail(username);

  current_state_.reset(new ManagedUserAuthenticator::AuthAttempt(
      canonicalized, password, false));

  SystemSaltGetter::Get()->GetSystemSalt(
      base::Bind(&Mount,
                 current_state_.get(),
                 scoped_refptr<ManagedUserAuthenticator>(this),
                 cryptohome::MOUNT_FLAGS_NONE));
}

void ManagedUserAuthenticator::AuthenticateToCreate(
    const std::string& username,
    const std::string& password) {
  std::string canonicalized = gaia::CanonicalizeEmail(username);

  current_state_.reset(new ManagedUserAuthenticator::AuthAttempt(
      canonicalized, password, false));

  SystemSaltGetter::Get()->GetSystemSalt(
      base::Bind(&Mount,
                 current_state_.get(),
                 scoped_refptr<ManagedUserAuthenticator>(this),
                 cryptohome::CREATE_IF_MISSING));
}

void ManagedUserAuthenticator::AddMasterKey(
    const std::string& username,
    const std::string& password,
    const std::string& master_key) {
  std::string canonicalized = gaia::CanonicalizeEmail(username);

  current_state_.reset(new ManagedUserAuthenticator::AuthAttempt(
      canonicalized, password, true));

  SystemSaltGetter::Get()->GetSystemSalt(
      base::Bind(&AddKey,
                 current_state_.get(),
                 scoped_refptr<ManagedUserAuthenticator>(this),
                 master_key));
}

void ManagedUserAuthenticator::OnAuthenticationSuccess(
    const std::string& mount_hash,
    bool add_key) {
  DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
  VLOG(1) << "Locally managed user authentication success";
  if (consumer_) {
    if (add_key)
      consumer_->OnAddKeySuccess();
    else
      consumer_->OnMountSuccess(mount_hash);
  }
}

void ManagedUserAuthenticator::OnAuthenticationFailure(
    ManagedUserAuthenticator::AuthState state) {
  DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
  LOG(WARNING) << "Locally managed user authentication failure";
  if (consumer_)
    consumer_->OnAuthenticationFailure(state);
}

void ManagedUserAuthenticator::Resolve() {
  DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
  ManagedUserAuthenticator::AuthState state = ResolveState();
  VLOG(1) << "Resolved state to: " << state;
  switch (state) {
    case CONTINUE:
      // These are intermediate states; we need more info from a request that
      // is still pending.
      break;
    case FAILED_MOUNT:
      // In this case, whether login succeeded or not, we can't log
      // the user in because their data is horked.  So, override with
      // the appropriate failure.
      BrowserThread::PostTask(
          BrowserThread::UI,
          FROM_HERE,
          base::Bind(
              &ManagedUserAuthenticator::OnAuthenticationFailure, this, state));
      break;
    case NO_MOUNT:
      // In this case, whether login succeeded or not, we can't log
      // the user in because no data exist. So, override with
      // the appropriate failure.
      BrowserThread::PostTask(
          BrowserThread::UI,
          FROM_HERE,
          base::Bind(
              &ManagedUserAuthenticator::OnAuthenticationFailure, this, state));
      break;
    case FAILED_TPM:
      // In this case, we tried to create/mount cryptohome and failed
      // because of the critical TPM error.
      // Chrome will notify user and request reboot.
      BrowserThread::PostTask(
          BrowserThread::UI,
          FROM_HERE,
          base::Bind(
              &ManagedUserAuthenticator::OnAuthenticationFailure, this, state));
      break;
    case SUCCESS:
      VLOG(2) << "Locally managed user login";
      BrowserThread::PostTask(
          BrowserThread::UI,
          FROM_HERE,
          base::Bind(&ManagedUserAuthenticator::OnAuthenticationSuccess,
                     this,
                     current_state_->hash(),
                     current_state_->add_key));
      break;
    default:
      NOTREACHED();
      break;
  }
}

ManagedUserAuthenticator::~ManagedUserAuthenticator() {}

ManagedUserAuthenticator::AuthState ManagedUserAuthenticator::ResolveState() {
  DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
  // If we haven't mounted the user's home dir yet, we can't be done.
  // We never get past here if a cryptohome op is still pending.
  // This is an important invariant.
  if (!current_state_->cryptohome_complete())
    return CONTINUE;
  if (!current_state_->add_key && !current_state_->hash_obtained())
    return CONTINUE;

  AuthState state;

  if (current_state_->cryptohome_outcome())
    state = ResolveCryptohomeSuccessState();
  else
    state = ResolveCryptohomeFailureState();

  DCHECK(current_state_->cryptohome_complete());
  DCHECK(current_state_->hash_obtained() || current_state_->add_key);
  return state;
}

ManagedUserAuthenticator::AuthState
    ManagedUserAuthenticator::ResolveCryptohomeFailureState() {
  DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
  if (current_state_->cryptohome_code() ==
      cryptohome::MOUNT_ERROR_TPM_NEEDS_REBOOT) {
    // Critical TPM error detected, reboot needed.
    return FAILED_TPM;
  }

  if (current_state_->cryptohome_code() ==
      cryptohome::MOUNT_ERROR_USER_DOES_NOT_EXIST) {
    // If we tried a mount but the user did not exist, then we should wait
    // for online login to succeed and try again with the "create" flag set.
    return NO_MOUNT;
  }

  return FAILED_MOUNT;
}

ManagedUserAuthenticator::AuthState
    ManagedUserAuthenticator::ResolveCryptohomeSuccessState() {
  DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
  return SUCCESS;
}

ManagedUserAuthenticator::AuthAttempt::AuthAttempt(const std::string& username,
                                                   const std::string& password,
                                                   bool add_key_attempt)
    : username(username),
      password(password),
      add_key(add_key_attempt),
      cryptohome_complete_(false),
      cryptohome_outcome_(false),
      hash_obtained_(false),
      cryptohome_code_(cryptohome::MOUNT_ERROR_NONE) {}

ManagedUserAuthenticator::AuthAttempt::~AuthAttempt() {}

void ManagedUserAuthenticator::AuthAttempt::RecordCryptohomeStatus(
    bool cryptohome_outcome,
    cryptohome::MountError cryptohome_code) {
  DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
  cryptohome_complete_ = true;
  cryptohome_outcome_ = cryptohome_outcome;
  cryptohome_code_ = cryptohome_code;
}

void ManagedUserAuthenticator::AuthAttempt::RecordHash(
    const std::string& hash) {
  DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
  hash_obtained_ = true;
  hash_ = hash;
}

bool ManagedUserAuthenticator::AuthAttempt::cryptohome_complete() {
  DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
  return cryptohome_complete_;
}

bool ManagedUserAuthenticator::AuthAttempt::cryptohome_outcome() {
  DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
  return cryptohome_outcome_;
}

cryptohome::MountError
    ManagedUserAuthenticator::AuthAttempt::cryptohome_code() {
  DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
  return cryptohome_code_;
}

bool ManagedUserAuthenticator::AuthAttempt::hash_obtained() {
  DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
  return hash_obtained_;
}

std::string ManagedUserAuthenticator::AuthAttempt::hash() {
  DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
  return hash_;
}

}  // namespace chromeos

/* [<][>][^][v][top][bottom][index][help] */