blob: 6d949f41173bf53ba45cc393f8a8e249b44d1f96 [file] [log] [blame]
// Copyright 2014 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 "chromeos/login/auth/login_performer.h"
#include "base/bind.h"
#include "base/logging.h"
#include "base/message_loop/message_loop.h"
#include "base/metrics/histogram.h"
#include "base/metrics/user_metrics.h"
#include "base/metrics/user_metrics_action.h"
#include "base/strings/utf_string_conversions.h"
#include "base/threading/thread_restrictions.h"
#include "chromeos/dbus/dbus_thread_manager.h"
#include "chromeos/dbus/session_manager_client.h"
#include "chromeos/login/user_names.h"
#include "chromeos/login_event_recorder.h"
#include "chromeos/settings/cros_settings_names.h"
#include "components/prefs/pref_service.h"
#include "components/signin/core/account_id/account_id.h"
#include "google_apis/gaia/gaia_auth_util.h"
#include "net/cookies/cookie_monster.h"
#include "net/cookies/cookie_store.h"
#include "net/url_request/url_request_context.h"
#include "net/url_request/url_request_context_getter.h"
using base::UserMetricsAction;
namespace chromeos {
LoginPerformer::LoginPerformer(scoped_refptr<base::TaskRunner> task_runner,
Delegate* delegate)
: delegate_(delegate),
task_runner_(task_runner),
last_login_failure_(AuthFailure::AuthFailureNone()),
password_changed_(false),
password_changed_callback_count_(0),
auth_mode_(AUTH_MODE_INTERNAL),
weak_factory_(this) {}
LoginPerformer::~LoginPerformer() {
DVLOG(1) << "Deleting LoginPerformer";
if (authenticator_.get())
authenticator_->SetConsumer(NULL);
if (extended_authenticator_.get())
extended_authenticator_->SetConsumer(NULL);
}
////////////////////////////////////////////////////////////////////////////////
// LoginPerformer, AuthStatusConsumer implementation:
void LoginPerformer::OnAuthFailure(const AuthFailure& failure) {
DCHECK(task_runner_->RunsTasksOnCurrentThread());
base::RecordAction(UserMetricsAction("Login_Failure"));
UMA_HISTOGRAM_ENUMERATION("Login.FailureReason",
failure.reason(),
AuthFailure::NUM_FAILURE_REASONS);
LOG(ERROR) << "Login failure, reason=" << failure.reason()
<< ", error.state=" << failure.error().state();
last_login_failure_ = failure;
if (delegate_) {
delegate_->SetAuthFlowOffline(user_context_.GetAuthFlow() ==
UserContext::AUTH_FLOW_OFFLINE);
delegate_->OnAuthFailure(failure);
return;
} else {
// COULD_NOT_MOUNT_CRYPTOHOME, COULD_NOT_MOUNT_TMPFS:
// happens during offline auth only.
NOTREACHED();
}
}
void LoginPerformer::OnAuthSuccess(const UserContext& user_context) {
DCHECK(task_runner_->RunsTasksOnCurrentThread());
base::RecordAction(UserMetricsAction("Login_Success"));
VLOG(1) << "LoginSuccess hash: " << user_context.GetUserIDHash();
DCHECK(delegate_);
// After delegate_->OnAuthSuccess(...) is called, delegate_ releases
// LoginPerformer ownership. LP now manages it's lifetime on its own.
base::MessageLoop::current()->DeleteSoon(FROM_HERE, this);
delegate_->OnAuthSuccess(user_context);
}
void LoginPerformer::OnOffTheRecordAuthSuccess() {
DCHECK(task_runner_->RunsTasksOnCurrentThread());
base::RecordAction(UserMetricsAction("Login_GuestLoginSuccess"));
if (delegate_)
delegate_->OnOffTheRecordAuthSuccess();
else
NOTREACHED();
}
void LoginPerformer::OnPasswordChangeDetected() {
password_changed_ = true;
password_changed_callback_count_++;
if (delegate_) {
delegate_->OnPasswordChangeDetected();
} else {
NOTREACHED();
}
}
////////////////////////////////////////////////////////////////////////////////
// LoginPerformer, public:
void LoginPerformer::NotifyWhitelistCheckFailure() {
if (delegate_)
delegate_->WhiteListCheckFailed(
user_context_.GetAccountId().GetUserEmail());
else
NOTREACHED();
}
void LoginPerformer::PerformLogin(const UserContext& user_context,
AuthorizationMode auth_mode) {
auth_mode_ = auth_mode;
user_context_ = user_context;
if (RunTrustedCheck(base::Bind(&LoginPerformer::DoPerformLogin,
weak_factory_.GetWeakPtr(),
user_context_,
auth_mode))) {
return;
}
DoPerformLogin(user_context_, auth_mode);
}
void LoginPerformer::DoPerformLogin(const UserContext& user_context,
AuthorizationMode auth_mode) {
bool wildcard_match = false;
const AccountId& account_id = user_context.GetAccountId();
if (!IsUserWhitelisted(account_id, &wildcard_match)) {
NotifyWhitelistCheckFailure();
return;
}
if (user_context.GetAuthFlow() == UserContext::AUTH_FLOW_EASY_UNLOCK)
SetupEasyUnlockUserFlow(user_context.GetAccountId());
switch (auth_mode_) {
case AUTH_MODE_EXTENSION: {
RunOnlineWhitelistCheck(
account_id, wildcard_match, user_context.GetRefreshToken(),
base::Bind(&LoginPerformer::StartLoginCompletion,
weak_factory_.GetWeakPtr()),
base::Bind(&LoginPerformer::NotifyWhitelistCheckFailure,
weak_factory_.GetWeakPtr()));
break;
}
case AUTH_MODE_INTERNAL:
StartAuthentication();
break;
}
}
void LoginPerformer::LoginAsSupervisedUser(const UserContext& user_context) {
DCHECK_EQ(
chromeos::login::kSupervisedUserDomain,
gaia::ExtractDomainName(user_context.GetAccountId().GetUserEmail()));
user_context_ = user_context;
user_context_.SetUserType(user_manager::USER_TYPE_SUPERVISED);
if (RunTrustedCheck(base::Bind(&LoginPerformer::TrustedLoginAsSupervisedUser,
weak_factory_.GetWeakPtr(),
user_context_))) {
return;
}
TrustedLoginAsSupervisedUser(user_context_);
}
void LoginPerformer::TrustedLoginAsSupervisedUser(
const UserContext& user_context) {
if (!AreSupervisedUsersAllowed()) {
LOG(ERROR) << "Login attempt of supervised user detected.";
delegate_->WhiteListCheckFailed(user_context.GetAccountId().GetUserEmail());
return;
}
SetupSupervisedUserFlow(user_context.GetAccountId());
UserContext user_context_copy = TransformSupervisedKey(user_context);
if (UseExtendedAuthenticatorForSupervisedUser(user_context)) {
EnsureExtendedAuthenticator();
// TODO(antrim) : Replace empty callback with explicit method.
// http://crbug.com/351268
task_runner_->PostTask(
FROM_HERE,
base::Bind(&ExtendedAuthenticator::AuthenticateToMount,
extended_authenticator_.get(),
user_context_copy,
ExtendedAuthenticator::ResultCallback()));
} else {
EnsureAuthenticator();
task_runner_->PostTask(FROM_HERE,
base::Bind(&Authenticator::LoginAsSupervisedUser,
authenticator_.get(),
user_context_copy));
}
}
void LoginPerformer::LoginAsPublicSession(const UserContext& user_context) {
if (!CheckPolicyForUser(user_context.GetAccountId())) {
DCHECK(delegate_);
if (delegate_)
delegate_->PolicyLoadFailed();
return;
}
EnsureAuthenticator();
task_runner_->PostTask(FROM_HERE,
base::Bind(&Authenticator::LoginAsPublicSession,
authenticator_.get(),
user_context));
}
void LoginPerformer::LoginOffTheRecord() {
EnsureAuthenticator();
task_runner_->PostTask(
FROM_HERE,
base::Bind(&Authenticator::LoginOffTheRecord, authenticator_.get()));
}
void LoginPerformer::LoginAsKioskAccount(const AccountId& app_account_id,
bool use_guest_mount) {
EnsureAuthenticator();
task_runner_->PostTask(
FROM_HERE,
base::Bind(&Authenticator::LoginAsKioskAccount, authenticator_.get(),
app_account_id, use_guest_mount));
}
void LoginPerformer::RecoverEncryptedData(const std::string& old_password) {
task_runner_->PostTask(FROM_HERE,
base::Bind(&Authenticator::RecoverEncryptedData,
authenticator_.get(),
old_password));
}
void LoginPerformer::ResyncEncryptedData() {
task_runner_->PostTask(
FROM_HERE,
base::Bind(&Authenticator::ResyncEncryptedData, authenticator_.get()));
}
////////////////////////////////////////////////////////////////////////////////
// LoginPerformer, private:
void LoginPerformer::EnsureExtendedAuthenticator() {
if (extended_authenticator_.get())
extended_authenticator_->SetConsumer(NULL);
extended_authenticator_ = ExtendedAuthenticator::Create(this);
}
void LoginPerformer::StartLoginCompletion() {
VLOG(1) << "Online login completion started.";
chromeos::LoginEventRecorder::Get()->AddLoginTimeMarker("AuthStarted", false);
content::BrowserContext* browser_context = GetSigninContext();
EnsureAuthenticator();
task_runner_->PostTask(FROM_HERE,
base::Bind(&chromeos::Authenticator::CompleteLogin,
authenticator_.get(),
browser_context,
user_context_));
user_context_.ClearSecrets();
}
void LoginPerformer::StartAuthentication() {
VLOG(1) << "Offline auth started.";
chromeos::LoginEventRecorder::Get()->AddLoginTimeMarker("AuthStarted", false);
if (delegate_) {
EnsureAuthenticator();
content::BrowserContext* browser_context = GetSigninContext();
task_runner_->PostTask(FROM_HERE,
base::Bind(&Authenticator::AuthenticateToLogin,
authenticator_.get(),
base::Unretained(browser_context),
user_context_));
} else {
NOTREACHED();
}
user_context_.ClearSecrets();
}
void LoginPerformer::EnsureAuthenticator() {
authenticator_ = CreateAuthenticator();
}
} // namespace chromeos