existing_user_controller.cc revision 2a99a7e74a7f215066514fe81d2bfa6639d9eddd
1e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng// Copyright (c) 2012 The Chromium Authors. All rights reserved.
2e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng// Use of this source code is governed by a BSD-style license that can be
3e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng// found in the LICENSE file.
4e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng
5e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng#include "chrome/browser/chromeos/login/existing_user_controller.h"
6e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng
7e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng#include <vector>
8e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng
9e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng#include "base/bind.h"
10e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng#include "base/bind_helpers.h"
11e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng#include "base/callback.h"
12e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng#include "base/command_line.h"
13e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng#include "base/logging.h"
14e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng#include "base/message_loop.h"
15e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng#include "base/metrics/histogram.h"
16e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng#include "base/prefs/pref_service.h"
17e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng#include "base/string_util.h"
18e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng#include "base/stringprintf.h"
19e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng#include "base/utf_string_conversions.h"
20e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng#include "base/values.h"
21e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng#include "base/version.h"
22e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng#include "chrome/browser/browser_process.h"
23e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng#include "chrome/browser/chromeos/accessibility/accessibility_util.h"
24e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng#include "chrome/browser/chromeos/boot_times_loader.h"
25e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng#include "chrome/browser/chromeos/cros/cros_library.h"
26e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng#include "chrome/browser/chromeos/customization_document.h"
27e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng#include "chrome/browser/chromeos/kiosk_mode/kiosk_mode_settings.h"
28e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng#include "chrome/browser/chromeos/login/helper.h"
29e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng#include "chrome/browser/chromeos/login/login_display_host.h"
30e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng#include "chrome/browser/chromeos/login/login_utils.h"
31e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng#include "chrome/browser/chromeos/login/user_manager.h"
32e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng#include "chrome/browser/chromeos/login/wizard_controller.h"
33e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng#include "chrome/browser/chromeos/net/connectivity_state_helper.h"
34e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng#include "chrome/browser/chromeos/settings/cros_settings.h"
35e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng#include "chrome/browser/chromeos/settings/cros_settings_names.h"
36e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng#include "chrome/browser/chromeos/system/statistics_provider.h"
37e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng#include "chrome/browser/google/google_util.h"
38e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng#include "chrome/browser/policy/policy_service.h"
39e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng#include "chrome/browser/prefs/session_startup_pref.h"
40e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng#include "chrome/browser/profiles/profile_manager.h"
41e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng#include "chrome/common/chrome_notification_types.h"
42e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng#include "chrome/common/chrome_switches.h"
43e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng#include "chrome/common/chrome_version_info.h"
44e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng#include "chrome/common/pref_names.h"
45e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng#include "chrome/common/url_constants.h"
46e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng#include "chromeos/dbus/dbus_thread_manager.h"
47e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng#include "chromeos/dbus/power_manager_client.h"
48e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng#include "chromeos/dbus/session_manager_client.h"
49e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng#include "content/public/browser/browser_thread.h"
50e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng#include "content/public/browser/notification_service.h"
51e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng#include "content/public/browser/notification_types.h"
52e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng#include "content/public/browser/user_metrics.h"
53e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng#include "google_apis/gaia/gaia_auth_util.h"
54e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng#include "google_apis/gaia/google_service_auth_error.h"
55e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng#include "grit/generated_resources.h"
56e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng#include "net/http/http_auth_cache.h"
57e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng#include "net/http/http_network_session.h"
58e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng#include "net/http/http_transaction_factory.h"
59e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng#include "net/url_request/url_request_context.h"
60e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng#include "net/url_request/url_request_context_getter.h"
61e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng#include "ui/base/l10n/l10n_util.h"
62e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng#include "ui/views/widget/widget.h"
63e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng
64e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Chengnamespace chromeos {
65e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng
66e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Chengnamespace {
67e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng
68e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng// Major version where we still show GSG as "Release Notes" after the update.
69e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Chengconst long int kReleaseNotesTargetRelease = 19;
70e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng
71e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng// Getting started guide url, will be opened as in app window for each new
72e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng// user who logs on the device.
73e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng// It actually goes to HelpApp and get redirected to our actual server there.
74e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Chengconst char kGetStartedWebUrl[] =
75e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng#if defined(OFFICIAL_BUILD)
76e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng    "chrome-extension://honijodknafkokifofgiaalefdiedpko/gsg.html?oobe=1";
77e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng#else
78e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng    "https://gweb-gettingstartedguide.appspot.com/";
79e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng#endif  // defined(OFFICIAL_BUILD)
80e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng
81e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng// Getting started guide application window size.
82e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Chengconst char kGSGAppWindowSize[] = "820,600";
83e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng
84e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng// URL for account creation.
85e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Chengconst char kCreateAccountURL[] =
86e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng    "https://accounts.google.com/NewAccount?service=mail";
87e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng
88e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng// ChromeVox tutorial URL (used in place of "getting started" url when
89e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng// accessibility is enabled).
90e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Chengconst char kChromeVoxTutorialURLPattern[] =
91e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng    "http://www.chromevox.com/tutorial/index.html?lang=%s";
92e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng
93e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng// Delay for transferring the auth cache to the system profile.
94e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Chengconst long int kAuthCacheTransferDelayMs = 2000;
95e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng
96e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng// Delay for restarting the ui if safe-mode login has failed.
97e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Chengconst long int kSafeModeRestartUiDelayMs = 30000;
98e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng
99e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng// Delay for rebooting machine if TPM critical error was encountered.
100e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Chengconst long int kCriticalErrorRebootDelayMs = 3500;
101e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng
102e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng// Makes a call to the policy subsystem to reload the policy when we detect
103e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng// authentication change.
104e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Chengvoid RefreshPoliciesOnUIThread() {
105e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng  if (g_browser_process->policy_service())
106e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng    g_browser_process->policy_service()->RefreshPolicies(base::Closure());
107e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng}
108e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng
109e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng// Copies any authentication details that were entered in the login profile in
110e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng// the mail profile to make sure all subsystems of Chrome can access the network
111e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng// with the provided authentication which are possibly for a proxy server.
112e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Chengvoid TransferContextAuthenticationsOnIOThread(
113e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng    net::URLRequestContextGetter* default_profile_context_getter,
114e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng    net::URLRequestContextGetter* browser_process_context_getter) {
115e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng  net::HttpAuthCache* new_cache =
116e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng      browser_process_context_getter->GetURLRequestContext()->
117e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng      http_transaction_factory()->GetSession()->http_auth_cache();
118e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng  net::HttpAuthCache* old_cache =
119e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng      default_profile_context_getter->GetURLRequestContext()->
120e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng      http_transaction_factory()->GetSession()->http_auth_cache();
121e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng  new_cache->UpdateAllFrom(*old_cache);
122e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng  VLOG(1) << "Main request context populated with authentication data.";
123e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng  // Last but not least tell the policy subsystem to refresh now as it might
124e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng  // have been stuck until now too.
125e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng  content::BrowserThread::PostTask(content::BrowserThread::UI, FROM_HERE,
126e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng                                   base::Bind(&RefreshPoliciesOnUIThread));
127e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng}
128e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng
129e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng}  // namespace
130e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng
131e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng// static
132e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen ChengExistingUserController* ExistingUserController::current_controller_ = NULL;
133e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng
134e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng////////////////////////////////////////////////////////////////////////////////
135e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng// ExistingUserController, public:
136e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng
137e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen ChengExistingUserController::ExistingUserController(LoginDisplayHost* host)
138e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng    : login_status_consumer_(NULL),
139e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng      host_(host),
140e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng      login_display_(host_->CreateLoginDisplay(this)),
141e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng      num_login_attempts_(0),
142e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng      cros_settings_(CrosSettings::Get()),
143e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng      weak_factory_(this),
144e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng      offline_failed_(false),
145e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng      is_login_in_progress_(false),
146e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng      password_changed_(false),
147e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng      do_auto_enrollment_(false),
148e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng      signin_screen_ready_(false) {
149e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng  DCHECK(current_controller_ == NULL);
150e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng  current_controller_ = this;
151e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng
152e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng  registrar_.Add(this,
153e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng                 chrome::NOTIFICATION_LOGIN_USER_IMAGE_CHANGED,
154e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng                 content::NotificationService::AllSources());
155e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng  registrar_.Add(this,
156e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng                 chrome::NOTIFICATION_USER_LIST_CHANGED,
157e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng                 content::NotificationService::AllSources());
158e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng  registrar_.Add(this,
159e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng                 chrome::NOTIFICATION_AUTH_SUPPLIED,
160e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng                 content::NotificationService::AllSources());
161e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng  registrar_.Add(this,
162e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng                 chrome::NOTIFICATION_SESSION_STARTED,
163e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng                 content::NotificationService::AllSources());
164e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng  cros_settings_->AddSettingsObserver(kAccountsPrefShowUserNamesOnSignIn, this);
165e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng  cros_settings_->AddSettingsObserver(kAccountsPrefAllowNewUser, this);
166e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng  cros_settings_->AddSettingsObserver(kAccountsPrefAllowGuest, this);
167e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng  cros_settings_->AddSettingsObserver(kAccountsPrefUsers, this);
168e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng  cros_settings_->AddSettingsObserver(
169e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng      kAccountsPrefDeviceLocalAccountAutoLoginId,
170e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng      this);
171e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng  cros_settings_->AddSettingsObserver(
172e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng      kAccountsPrefDeviceLocalAccountAutoLoginDelay,
173e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng      this);
174e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng}
175e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng
176e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Chengvoid ExistingUserController::Init(const UserList& users) {
177e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng  time_init_ = base::Time::Now();
178e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng  UpdateLoginDisplay(users);
179e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng  ConfigurePublicSessionAutoLogin();
180e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng
181e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng  LoginUtils::Get()->PrewarmAuthentication();
182e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng  DBusThreadManager::Get()->GetSessionManagerClient()->EmitLoginPromptReady();
183e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng}
184e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng
185e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Chengvoid ExistingUserController::UpdateLoginDisplay(const UserList& users) {
186e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng  bool show_users_on_signin;
187e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng  UserList filtered_users;
188e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng
189e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng  cros_settings_->GetBoolean(kAccountsPrefShowUserNamesOnSignIn,
190e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng                             &show_users_on_signin);
191e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng  if (show_users_on_signin) {
192e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng    for (UserList::const_iterator it = users.begin(); it != users.end(); ++it) {
193e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng      // TODO(xiyuan): Clean user profile whose email is not in whitelist.
194e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng      if (LoginUtils::IsWhitelisted((*it)->email()) ||
195e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng          (*it)->GetType() != User::USER_TYPE_REGULAR) {
196e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng        filtered_users.push_back(*it);
197e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng      }
198e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng    }
199e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng  }
200e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng
201e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng  // If no user pods are visible, fallback to single new user pod which will
202e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng  // have guest session link.
203e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng  bool show_guest;
204e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng  cros_settings_->GetBoolean(kAccountsPrefAllowGuest, &show_guest);
205e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng  bool show_users;
206e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng  cros_settings_->GetBoolean(kAccountsPrefShowUserNamesOnSignIn, &show_users);
207e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng  show_guest &= !filtered_users.empty();
208e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng  bool show_new_user = true;
209e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng  login_display_->set_parent_window(GetNativeWindow());
210e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng  login_display_->Init(filtered_users, show_guest, show_users, show_new_user);
211e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng  host_->OnPreferencesChanged();
212e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng}
213e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng
214e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Chengvoid ExistingUserController::DoAutoEnrollment() {
215e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng  do_auto_enrollment_ = true;
216e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng}
217e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng
218e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Chengvoid ExistingUserController::ResumeLogin() {
219e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng  // This means the user signed-in, then auto-enrollment used his credentials
220e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng  // to enroll and succeeded.
221e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng  resume_login_callback_.Run();
222e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng  resume_login_callback_.Reset();
223e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng}
224e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng
225e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Chengvoid ExistingUserController::PrepareKioskAppLaunch() {
226e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng  // Disable login UI while waiting for the kiosk app launch. There is no
227e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng  // balanced UI enable call because this very login screen will not be
228e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng  // accessed again. If app is launched, it will be destroyed. If app fails to
229e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng  // launch, chrome is restarted to go back to a new login screen.
230e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng  login_display_->SetUIEnabled(false);
231e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng}
232e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng
233e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng////////////////////////////////////////////////////////////////////////////////
234e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng// ExistingUserController, content::NotificationObserver implementation:
235e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng//
236e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng
237e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Chengvoid ExistingUserController::Observe(
238e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng    int type,
239e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng    const content::NotificationSource& source,
240e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng    const content::NotificationDetails& details) {
241e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng  if (type == chrome::NOTIFICATION_SESSION_STARTED) {
242e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng    // Stop listening to any notification once session has started.
243e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng    // Sign in screen objects are marked for deletion with DeleteSoon so
244e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng    // make sure no object would be used after session has started.
245e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng    // http://crbug.com/125276
246e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng    registrar_.RemoveAll();
247e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng    return;
248e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng  }
249e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng  if (type == chrome::NOTIFICATION_SYSTEM_SETTING_CHANGED) {
250e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng    const std::string setting = *content::Details<const std::string>(
251e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng        details).ptr();
252e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng    if (setting == kAccountsPrefDeviceLocalAccountAutoLoginId ||
253e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng        setting == kAccountsPrefDeviceLocalAccountAutoLoginDelay) {
254e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng      ConfigurePublicSessionAutoLogin();
255e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng    }
256e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng  }
257e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng  if (type == chrome::NOTIFICATION_SYSTEM_SETTING_CHANGED ||
258e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng      type == chrome::NOTIFICATION_USER_LIST_CHANGED) {
259e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng    if (host_ != NULL) {
260e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng      // Signed settings or user list changed. Notify views and update them.
261e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng      UpdateLoginDisplay(chromeos::UserManager::Get()->GetUsers());
262e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng      return;
263e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng    }
264e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng  }
265e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng  if (type == chrome::NOTIFICATION_AUTH_SUPPLIED) {
266e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng    // Possibly the user has authenticated against a proxy server and we might
267e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng    // need the credentials for enrollment and other system requests from the
268e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng    // main |g_browser_process| request context (see bug
269e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng    // http://crosbug.com/24861). So we transfer any credentials to the global
270e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng    // request context here.
271e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng    // The issue we have here is that the NOTIFICATION_AUTH_SUPPLIED is sent
272e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng    // just after the UI is closed but before the new credentials were stored
273e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng    // in the profile. Therefore we have to give it some time to make sure it
274e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng    // has been updated before we copy it.
275e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng    LOG(INFO) << "Authentication was entered manually, possibly for proxyauth.";
276e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng    scoped_refptr<net::URLRequestContextGetter> browser_process_context_getter =
277e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng        g_browser_process->system_request_context();
278e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng    Profile* default_profile = ProfileManager::GetDefaultProfile();
279e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng    scoped_refptr<net::URLRequestContextGetter> default_profile_context_getter =
280e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng        default_profile->GetRequestContext();
281e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng    DCHECK(browser_process_context_getter.get());
282e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng    DCHECK(default_profile_context_getter.get());
283e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng    content::BrowserThread::PostDelayedTask(
284e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng        content::BrowserThread::IO, FROM_HERE,
285e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng        base::Bind(&TransferContextAuthenticationsOnIOThread,
286e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng                   default_profile_context_getter,
287e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng                   browser_process_context_getter),
288e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng        base::TimeDelta::FromMilliseconds(kAuthCacheTransferDelayMs));
289e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng  }
290e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng  if (type != chrome::NOTIFICATION_LOGIN_USER_IMAGE_CHANGED)
291e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng    return;
292e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng  login_display_->OnUserImageChanged(*content::Details<User>(details).ptr());
293e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng}
294e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng
295e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng////////////////////////////////////////////////////////////////////////////////
296e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng// ExistingUserController, private:
297e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng
298e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen ChengExistingUserController::~ExistingUserController() {
299e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng  LoginUtils::Get()->DelegateDeleted(this);
300e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng
301e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng  cros_settings_->RemoveSettingsObserver(kAccountsPrefShowUserNamesOnSignIn,
302e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng                                         this);
303e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng  cros_settings_->RemoveSettingsObserver(kAccountsPrefAllowNewUser, this);
304e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng  cros_settings_->RemoveSettingsObserver(kAccountsPrefAllowGuest, this);
305e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng  cros_settings_->RemoveSettingsObserver(kAccountsPrefUsers, this);
306e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng  cros_settings_->RemoveSettingsObserver(
307e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng      kAccountsPrefDeviceLocalAccountAutoLoginId,
308e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng      this);
309e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng  cros_settings_->RemoveSettingsObserver(
310e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng      kAccountsPrefDeviceLocalAccountAutoLoginDelay,
311e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng      this);
312e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng
313e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng  if (current_controller_ == this) {
314e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng    current_controller_ = NULL;
315e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng  } else {
316e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng    NOTREACHED() << "More than one controller are alive.";
317e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng  }
318e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng  DCHECK(login_display_.get());
319e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng}
320e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng
321e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng////////////////////////////////////////////////////////////////////////////////
322e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng// ExistingUserController, LoginDisplay::Delegate implementation:
323e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng//
324e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng
325e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Chengvoid ExistingUserController::CancelPasswordChangedFlow() {
326e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng  login_performer_.reset(NULL);
327e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng  login_display_->SetUIEnabled(true);
328e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng  StartPublicSessionAutoLoginTimer();
329e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng}
330e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng
331e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Chengvoid ExistingUserController::CreateAccount() {
332e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng  content::RecordAction(content::UserMetricsAction("Login.CreateAccount"));
333e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng  guest_mode_url_ =
334e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng      google_util::AppendGoogleLocaleParam(GURL(kCreateAccountURL));
335e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng  LoginAsGuest();
336e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng}
337e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng
338e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Chengvoid ExistingUserController::CreateLocallyManagedUser(
339e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng    const string16& display_name,
340e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng    const std::string& password) {
341e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng  // TODO(nkostylev): Check that policy allows creation of such account type.
342e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng  if (display_name.empty())
343e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng    return;
344e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng
345e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng  // Disable clicking on other windows.
346e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng  StopPublicSessionAutoLoginTimer();
347e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng  login_display_->SetUIEnabled(false);
348e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng
349e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng  LoginPerformer::Delegate* delegate = this;
350e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng  if (login_performer_delegate_.get())
351e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng    delegate = login_performer_delegate_.get();
352e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng  // Only one instance of LoginPerformer should exist at a time.
353e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng  login_performer_.reset(NULL);
354e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng  login_performer_.reset(new LoginPerformer(delegate));
355e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng  is_login_in_progress_ = true;
356e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng  login_performer_->
357e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng      CreateLocallyManagedUser(display_name, password);
358e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng  // TODO(nkostylev): A11y message.
359}
360
361void ExistingUserController::CompleteLogin(const UserCredentials& credentials) {
362  if (!host_) {
363    // Complete login event was generated already from UI. Ignore notification.
364    return;
365  }
366
367  // Stop the auto-login timer when attempting login.
368  StopPublicSessionAutoLoginTimer();
369
370  // Disable UI while loading user profile.
371  login_display_->SetUIEnabled(false);
372
373  if (!time_init_.is_null()) {
374    base::TimeDelta delta = base::Time::Now() - time_init_;
375    UMA_HISTOGRAM_MEDIUM_TIMES("Login.PromptToCompleteLoginTime", delta);
376    time_init_ = base::Time();  // Reset to null.
377  }
378
379  host_->OnCompleteLogin();
380
381  // Do an ownership check now to avoid auto-enrolling if the device has
382  // already been owned.
383  DeviceSettingsService::Get()->GetOwnershipStatusAsync(
384      base::Bind(&ExistingUserController::CompleteLoginInternal,
385                 weak_factory_.GetWeakPtr(),
386                 credentials));
387}
388
389void ExistingUserController::CompleteLoginInternal(
390    const UserCredentials& credentials,
391    DeviceSettingsService::OwnershipStatus ownership_status,
392    bool is_owner) {
393  // Auto-enrollment must have made a decision by now. It's too late to enroll
394  // if the protocol isn't done at this point.
395  if (do_auto_enrollment_ &&
396      ownership_status == DeviceSettingsService::OWNERSHIP_NONE) {
397    VLOG(1) << "Forcing auto-enrollment before completing login";
398    // The only way to get out of the enrollment screen from now on is to either
399    // complete enrollment, or opt-out of it. So this controller shouldn't force
400    // enrollment again if it is reused for another sign-in.
401    do_auto_enrollment_ = false;
402    auto_enrollment_username_ = credentials.username;
403    resume_login_callback_ = base::Bind(
404        &ExistingUserController::PerformLogin,
405        weak_factory_.GetWeakPtr(),
406        credentials, LoginPerformer::AUTH_MODE_EXTENSION);
407    ShowEnrollmentScreen(true, credentials.username);
408    // Enable UI for the enrollment screen. SetUIEnabled(true) will post a
409    // request to show the sign-in screen again when invoked at the sign-in
410    // screen; invoke SetUIEnabled() after navigating to the enrollment screen.
411    login_display_->SetUIEnabled(true);
412  } else {
413    PerformLogin(credentials, LoginPerformer::AUTH_MODE_EXTENSION);
414  }
415}
416
417string16 ExistingUserController::GetConnectedNetworkName() {
418  return GetCurrentNetworkName();
419}
420
421void ExistingUserController::Login(const UserCredentials& credentials) {
422  if ((credentials.username.empty() || credentials.password.empty()) &&
423      credentials.auth_code.empty())
424    return;
425
426  // Stop the auto-login timer when attempting login.
427  StopPublicSessionAutoLoginTimer();
428
429  // Disable clicking on other windows.
430  login_display_->SetUIEnabled(false);
431
432  BootTimesLoader::Get()->RecordLoginAttempted();
433
434  if (last_login_attempt_username_ != credentials.username) {
435    last_login_attempt_username_ = credentials.username;
436    num_login_attempts_ = 0;
437    // Also reset state variables, which are used to determine password change.
438    offline_failed_ = false;
439    online_succeeded_for_.clear();
440  }
441  num_login_attempts_++;
442  PerformLogin(credentials, LoginPerformer::AUTH_MODE_INTERNAL);
443}
444
445void ExistingUserController::PerformLogin(
446    const UserCredentials& credentials,
447    LoginPerformer::AuthorizationMode auth_mode) {
448  // Disable UI while loading user profile.
449  login_display_->SetUIEnabled(false);
450
451  // Use the same LoginPerformer for subsequent login as it has state
452  // such as Authenticator instance.
453  if (!login_performer_.get() || num_login_attempts_ <= 1) {
454    LoginPerformer::Delegate* delegate = this;
455    if (login_performer_delegate_.get())
456      delegate = login_performer_delegate_.get();
457    // Only one instance of LoginPerformer should exist at a time.
458    login_performer_.reset(NULL);
459    login_performer_.reset(new LoginPerformer(delegate));
460  }
461
462  is_login_in_progress_ = true;
463  if (gaia::ExtractDomainName(credentials.username) ==
464          UserManager::kLocallyManagedUserDomain) {
465    login_performer_->LoginAsLocallyManagedUser(
466        UserCredentials(credentials.username,
467                        credentials.password,
468                        std::string()));  // auth_code
469  } else {
470    login_performer_->PerformLogin(credentials, auth_mode);
471  }
472  accessibility::MaybeSpeak(
473      l10n_util::GetStringUTF8(IDS_CHROMEOS_ACC_LOGIN_SIGNING_IN));
474}
475
476void ExistingUserController::LoginAsRetailModeUser() {
477  // Stop the auto-login timer when attempting login.
478  StopPublicSessionAutoLoginTimer();
479
480  // Disable clicking on other windows.
481  login_display_->SetUIEnabled(false);
482  // TODO(rkc): Add a CHECK to make sure retail mode logins are allowed once
483  // the enterprise policy wiring is done for retail mode.
484
485  // Only one instance of LoginPerformer should exist at a time.
486  login_performer_.reset(NULL);
487  login_performer_.reset(new LoginPerformer(this));
488  is_login_in_progress_ = true;
489  login_performer_->LoginRetailMode();
490  accessibility::MaybeSpeak(
491      l10n_util::GetStringUTF8(IDS_CHROMEOS_ACC_LOGIN_SIGNIN_DEMOUSER));
492}
493
494void ExistingUserController::LoginAsGuest() {
495  // Stop the auto-login timer when attempting login.
496  StopPublicSessionAutoLoginTimer();
497
498  // Disable clicking on other windows.
499  login_display_->SetUIEnabled(false);
500
501  CrosSettingsProvider::TrustedStatus status =
502      cros_settings_->PrepareTrustedValues(
503          base::Bind(&ExistingUserController::LoginAsGuest,
504                     weak_factory_.GetWeakPtr()));
505  // Must not proceed without signature verification.
506  if (status == CrosSettingsProvider::PERMANENTLY_UNTRUSTED) {
507    login_display_->ShowError(IDS_LOGIN_ERROR_OWNER_KEY_LOST, 1,
508                              HelpAppLauncher::HELP_CANT_ACCESS_ACCOUNT);
509    // Reenable clicking on other windows and status area.
510    login_display_->SetUIEnabled(true);
511    StartPublicSessionAutoLoginTimer();
512    display_email_.clear();
513    return;
514  } else if (status != CrosSettingsProvider::TRUSTED) {
515    // Value of AllowNewUser setting is still not verified.
516    // Another attempt will be invoked after verification completion.
517    return;
518  }
519
520  bool allow_guest;
521  cros_settings_->GetBoolean(kAccountsPrefAllowGuest, &allow_guest);
522  if (!allow_guest) {
523    // Disallowed. The UI should normally not show the guest pod but if for some
524    // reason this has been made available to the user here is the time to tell
525    // this nicely.
526    login_display_->ShowError(IDS_LOGIN_ERROR_WHITELIST, 1,
527                              HelpAppLauncher::HELP_CANT_ACCESS_ACCOUNT);
528    // Reenable clicking on other windows and status area.
529    login_display_->SetUIEnabled(true);
530    StartPublicSessionAutoLoginTimer();
531    display_email_.clear();
532    return;
533  }
534
535  // Only one instance of LoginPerformer should exist at a time.
536  login_performer_.reset(NULL);
537  login_performer_.reset(new LoginPerformer(this));
538  is_login_in_progress_ = true;
539  login_performer_->LoginOffTheRecord();
540  accessibility::MaybeSpeak(
541      l10n_util::GetStringUTF8(IDS_CHROMEOS_ACC_LOGIN_SIGNIN_OFFRECORD));
542}
543
544void ExistingUserController::MigrateUserData(const std::string& old_password) {
545  // LoginPerformer instance has state of the user so it should exist.
546  if (login_performer_.get())
547    login_performer_->RecoverEncryptedData(old_password);
548}
549
550void ExistingUserController::LoginAsPublicAccount(
551    const std::string& username) {
552  // Stop the auto-login timer when attempting login.
553  StopPublicSessionAutoLoginTimer();
554
555  // Disable clicking on other windows.
556  login_display_->SetUIEnabled(false);
557
558  CrosSettingsProvider::TrustedStatus status =
559      cros_settings_->PrepareTrustedValues(
560          base::Bind(&ExistingUserController::LoginAsPublicAccount,
561                     weak_factory_.GetWeakPtr(),
562                     username));
563  // If device policy is permanently unavailable, logging into public accounts
564  // is not possible.
565  if (status == CrosSettingsProvider::PERMANENTLY_UNTRUSTED) {
566    login_display_->ShowError(IDS_LOGIN_ERROR_OWNER_KEY_LOST, 1,
567                              HelpAppLauncher::HELP_CANT_ACCESS_ACCOUNT);
568    // Re-enable clicking on other windows.
569    login_display_->SetUIEnabled(true);
570    return;
571  }
572
573  // If device policy is not verified yet, this function will be called again
574  // when verification finishes.
575  if (status != CrosSettingsProvider::TRUSTED)
576    return;
577
578  // If there is no public account with the given |username|, logging in is not
579  // possible.
580  const User* user = UserManager::Get()->FindUser(username);
581  if (!user || user->GetType() != User::USER_TYPE_PUBLIC_ACCOUNT) {
582    // Re-enable clicking on other windows.
583    login_display_->SetUIEnabled(true);
584    StartPublicSessionAutoLoginTimer();
585    return;
586  }
587
588  // Only one instance of LoginPerformer should exist at a time.
589  login_performer_.reset(NULL);
590  login_performer_.reset(new LoginPerformer(this));
591  is_login_in_progress_ = true;
592  login_performer_->LoginAsPublicAccount(username);
593  accessibility::MaybeSpeak(
594      l10n_util::GetStringUTF8(IDS_CHROMEOS_ACC_LOGIN_SIGNIN_PUBLIC_ACCOUNT));
595}
596
597void ExistingUserController::OnSigninScreenReady() {
598  signin_screen_ready_ = true;
599  StartPublicSessionAutoLoginTimer();
600}
601
602void ExistingUserController::OnUserSelected(const std::string& username) {
603  login_performer_.reset(NULL);
604  num_login_attempts_ = 0;
605}
606
607void ExistingUserController::OnStartEnterpriseEnrollment() {
608  DeviceSettingsService::Get()->GetOwnershipStatusAsync(
609      base::Bind(&ExistingUserController::OnEnrollmentOwnershipCheckCompleted,
610                 weak_factory_.GetWeakPtr()));
611}
612
613void ExistingUserController::OnStartDeviceReset() {
614  ShowResetScreen();
615}
616
617void ExistingUserController::ResyncUserData() {
618  // LoginPerformer instance has state of the user so it should exist.
619  if (login_performer_.get())
620    login_performer_->ResyncEncryptedData();
621}
622
623void ExistingUserController::SetDisplayEmail(const std::string& email) {
624  display_email_ = email;
625}
626
627void ExistingUserController::ShowWrongHWIDScreen() {
628  host_->StartWizard(WizardController::kWrongHWIDScreenName, NULL);
629  login_display_->OnFadeOut();
630}
631
632void ExistingUserController::Signout() {
633  NOTREACHED();
634}
635
636void ExistingUserController::OnEnrollmentOwnershipCheckCompleted(
637    DeviceSettingsService::OwnershipStatus status,
638    bool current_user_is_owner) {
639  if (status == DeviceSettingsService::OWNERSHIP_NONE) {
640    ShowEnrollmentScreen(false, std::string());
641  } else if (status == DeviceSettingsService::OWNERSHIP_TAKEN) {
642    // On a device that is already owned we might want to allow users to
643    // re-enroll if the policy information is invalid.
644    CrosSettingsProvider::TrustedStatus trusted_status =
645        CrosSettings::Get()->PrepareTrustedValues(
646            base::Bind(
647                &ExistingUserController::OnEnrollmentOwnershipCheckCompleted,
648                weak_factory_.GetWeakPtr(), status, current_user_is_owner));
649    if (trusted_status == CrosSettingsProvider::PERMANENTLY_UNTRUSTED)
650      ShowEnrollmentScreen(false, std::string());
651  } else {
652    // OwnershipService::GetStatusAsync is supposed to return either
653    // OWNERSHIP_NONE or OWNERSHIP_TAKEN.
654    NOTREACHED();
655  }
656}
657
658void ExistingUserController::ShowEnrollmentScreen(bool is_auto_enrollment,
659                                                  const std::string& user) {
660  DictionaryValue* params = NULL;
661  if (is_auto_enrollment) {
662    params = new DictionaryValue;
663    params->SetBoolean("is_auto_enrollment", true);
664    params->SetString("user", user);
665  }
666  host_->StartWizard(WizardController::kEnterpriseEnrollmentScreenName, params);
667  login_display_->OnFadeOut();
668}
669
670void ExistingUserController::ShowResetScreen() {
671  host_->StartWizard(WizardController::kResetScreenName, NULL);
672  login_display_->OnFadeOut();
673}
674
675void ExistingUserController::ShowTPMErrorAndScheduleReboot() {
676  login_display_->SetUIEnabled(false);
677  login_display_->ShowErrorScreen(LoginDisplay::TPM_ERROR);
678  reboot_timer_.Start(
679      FROM_HERE,
680      base::TimeDelta::FromMilliseconds(kCriticalErrorRebootDelayMs),
681      this,
682      &ExistingUserController::OnRebootTimeElapsed);
683}
684
685void ExistingUserController::OnRebootTimeElapsed() {
686  chromeos::DBusThreadManager::Get()->GetPowerManagerClient()->RequestRestart();
687}
688
689////////////////////////////////////////////////////////////////////////////////
690// ExistingUserController, LoginPerformer::Delegate implementation:
691//
692
693void ExistingUserController::OnLoginFailure(const LoginFailure& failure) {
694  is_login_in_progress_ = false;
695  offline_failed_ = true;
696
697  guest_mode_url_ = GURL::EmptyGURL();
698  std::string error = failure.GetErrorString();
699
700  if (UserManager::Get()->GetUserFlow(last_login_attempt_username_)->
701          HandleLoginFailure(failure, host_)) {
702    return;
703  }
704
705  if (failure.reason() == LoginFailure::OWNER_REQUIRED) {
706    ShowError(IDS_LOGIN_ERROR_OWNER_REQUIRED, error);
707    content::BrowserThread::PostDelayedTask(
708        content::BrowserThread::UI, FROM_HERE,
709        base::Bind(&SessionManagerClient::StopSession,
710                   base::Unretained(DBusThreadManager::Get()->
711                                    GetSessionManagerClient())),
712        base::TimeDelta::FromMilliseconds(kSafeModeRestartUiDelayMs));
713  } else if (failure.reason() == LoginFailure::TPM_ERROR) {
714    ShowTPMErrorAndScheduleReboot();
715  } else if (!online_succeeded_for_.empty()) {
716    ShowGaiaPasswordChanged(online_succeeded_for_);
717  } else {
718    // Check networking after trying to login in case user is
719    // cached locally or the local admin account.
720    bool is_known_user =
721        UserManager::Get()->IsKnownUser(last_login_attempt_username_);
722    if (!ConnectivityStateHelper::Get()->IsConnected()) {
723      if (is_known_user)
724        ShowError(IDS_LOGIN_ERROR_AUTHENTICATING, error);
725      else
726        ShowError(IDS_LOGIN_ERROR_OFFLINE_FAILED_NETWORK_NOT_CONNECTED, error);
727    } else {
728      // TODO(nkostylev): Cleanup rest of ClientLogin related code.
729      if (failure.reason() == LoginFailure::NETWORK_AUTH_FAILED &&
730          failure.error().state() ==
731              GoogleServiceAuthError::HOSTED_NOT_ALLOWED) {
732        ShowError(IDS_LOGIN_ERROR_AUTHENTICATING_HOSTED, error);
733      } else {
734        if (!is_known_user)
735          ShowError(IDS_LOGIN_ERROR_AUTHENTICATING_NEW, error);
736        else
737          ShowError(IDS_LOGIN_ERROR_AUTHENTICATING, error);
738      }
739    }
740    // Reenable clicking on other windows and status area.
741    login_display_->SetUIEnabled(true);
742    StartPublicSessionAutoLoginTimer();
743  }
744
745  // Reset user flow to default, so that special flow will not affect next
746  // attempt.
747  UserManager::Get()->ResetUserFlow(last_login_attempt_username_);
748
749  if (login_status_consumer_)
750    login_status_consumer_->OnLoginFailure(failure);
751
752  // Clear the recorded displayed email so it won't affect any future attempts.
753  display_email_.clear();
754}
755
756void ExistingUserController::OnLoginSuccess(
757    const UserCredentials& credentials,
758    bool pending_requests,
759    bool using_oauth) {
760  is_login_in_progress_ = false;
761  offline_failed_ = false;
762
763  StopPublicSessionAutoLoginTimer();
764
765  bool has_cookies =
766      login_performer_->auth_mode() == LoginPerformer::AUTH_MODE_EXTENSION &&
767      credentials.auth_code.empty();
768
769  // Login performer will be gone so cache this value to use
770  // once profile is loaded.
771  password_changed_ = login_performer_->password_changed();
772
773  // LoginPerformer instance will delete itself once online auth result is OK.
774  // In case of failure it'll bring up ScreenLock and ask for
775  // correct password/display error message.
776  // Even in case when following online,offline protocol and returning
777  // requests_pending = false, let LoginPerformer delete itself.
778  login_performer_->set_delegate(NULL);
779  ignore_result(login_performer_.release());
780
781  // Will call OnProfilePrepared() in the end.
782  LoginUtils::Get()->PrepareProfile(credentials,
783                                    display_email_,
784                                    using_oauth,
785                                    has_cookies,
786                                    this);
787
788  display_email_.clear();
789
790  // Notify LoginDisplay to allow it provide visual feedback to user.
791  login_display_->OnLoginSuccess(credentials.username);
792}
793
794void ExistingUserController::OnProfilePrepared(Profile* profile) {
795  OptionallyShowReleaseNotes(profile);
796
797  // Reenable clicking on other windows and status area.
798  login_display_->SetUIEnabled(true);
799
800  if (UserManager::Get()->IsCurrentUserNew() &&
801      !UserManager::Get()->GetCurrentUserFlow()->ShouldSkipPostLoginScreens() &&
802      !WizardController::default_controller()->skip_post_login_screens()) {
803    // Don't specify start URLs if the administrator has configured the start
804    // URLs via policy.
805    if (!SessionStartupPref::TypeIsManaged(profile->GetPrefs()))
806      InitializeStartUrls();
807#ifndef NDEBUG
808    if (CommandLine::ForCurrentProcess()->HasSwitch(
809          switches::kOobeSkipPostLogin)) {
810      LoginUtils::Get()->DoBrowserLaunch(profile, host_);
811      host_ = NULL;
812    } else {
813#endif
814      ActivateWizard(WizardController::IsDeviceRegistered() ?
815          WizardController::kTermsOfServiceScreenName :
816          WizardController::kRegistrationScreenName);
817#ifndef NDEBUG
818    }
819#endif
820  } else {
821    LoginUtils::Get()->DoBrowserLaunch(profile, host_);
822    host_ = NULL;
823  }
824  // Inform |login_status_consumer_| about successful login. Set most
825  // parameters to empty since they're not needed.
826  if (login_status_consumer_)
827    login_status_consumer_->OnLoginSuccess(UserCredentials(),
828                                           false,    // pending_requests
829                                           false);   // using_oauth
830  login_display_->OnFadeOut();
831}
832
833void ExistingUserController::OnOffTheRecordLoginSuccess() {
834  is_login_in_progress_ = false;
835  offline_failed_ = false;
836  if (WizardController::IsDeviceRegistered()) {
837    LoginUtils::Get()->CompleteOffTheRecordLogin(guest_mode_url_);
838  } else {
839    // Postpone CompleteOffTheRecordLogin until registration completion.
840    // TODO(nkostylev): Kind of hack. We have to instruct UserManager here
841    // that we're actually logged in as Guest user as we'll ask UserManager
842    // later in the code path whether we've signed in as Guest and depending
843    // on that would either show image screen or call CompleteOffTheRecordLogin.
844    UserManager::Get()->GuestUserLoggedIn();
845    ActivateWizard(WizardController::kRegistrationScreenName);
846  }
847
848  if (login_status_consumer_)
849    login_status_consumer_->OnOffTheRecordLoginSuccess();
850}
851
852void ExistingUserController::OnPasswordChangeDetected() {
853  // Must not proceed without signature verification.
854  if (CrosSettingsProvider::TRUSTED != cros_settings_->PrepareTrustedValues(
855      base::Bind(&ExistingUserController::OnPasswordChangeDetected,
856                 weak_factory_.GetWeakPtr()))) {
857    // Value of owner email is still not verified.
858    // Another attempt will be invoked after verification completion.
859    return;
860  }
861
862  if (UserManager::Get()->GetUserFlow(last_login_attempt_username_)->
863          HandlePasswordChangeDetected(host_)) {
864    return;
865  }
866
867  // True if user has already made an attempt to enter old password and failed.
868  bool show_invalid_old_password_error =
869      login_performer_->password_changed_callback_count() > 1;
870
871  // Note: We allow owner using "full sync" mode which will recreate
872  // cryptohome and deal with owner private key being lost. This also allows
873  // us to recover from a lost owner password/homedir.
874  // TODO(gspencer): We shouldn't have to erase stateful data when
875  // doing this.  See http://crosbug.com/9115 http://crosbug.com/7792
876  login_display_->ShowPasswordChangedDialog(show_invalid_old_password_error);
877
878  if (login_status_consumer_)
879    login_status_consumer_->OnPasswordChangeDetected();
880
881  display_email_.clear();
882}
883
884void ExistingUserController::WhiteListCheckFailed(const std::string& email) {
885  ShowError(IDS_LOGIN_ERROR_WHITELIST, email);
886
887  // Reenable clicking on other windows and status area.
888  login_display_->SetUIEnabled(true);
889  login_display_->ShowSigninUI(email);
890
891  if (login_status_consumer_) {
892    login_status_consumer_->OnLoginFailure(LoginFailure(
893          LoginFailure::WHITELIST_CHECK_FAILED));
894  }
895
896  display_email_.clear();
897
898  StartPublicSessionAutoLoginTimer();
899}
900
901void ExistingUserController::PolicyLoadFailed() {
902  ShowError(IDS_LOGIN_ERROR_OWNER_KEY_LOST, "");
903
904  // Reenable clicking on other windows and status area.
905  login_display_->SetUIEnabled(true);
906
907  display_email_.clear();
908
909  // Policy load failure stops login attempts -- restart the timer.
910  StartPublicSessionAutoLoginTimer();
911}
912
913void ExistingUserController::OnOnlineChecked(const std::string& username,
914                                             bool success) {
915  if (success && last_login_attempt_username_ == username) {
916    online_succeeded_for_ = username;
917    // Wait for login attempt to end, if it hasn't yet.
918    if (offline_failed_ && !is_login_in_progress_)
919      ShowGaiaPasswordChanged(username);
920  }
921}
922
923////////////////////////////////////////////////////////////////////////////////
924// ExistingUserController, private:
925
926void ExistingUserController::ActivateWizard(const std::string& screen_name) {
927  DictionaryValue* params = NULL;
928  if (chromeos::UserManager::Get()->IsLoggedInAsGuest()) {
929    params = new DictionaryValue;
930    params->SetString("start_url", guest_mode_url_.spec());
931  }
932  host_->StartWizard(screen_name, params);
933}
934
935void ExistingUserController::ConfigurePublicSessionAutoLogin() {
936  if (!cros_settings_->GetString(
937          kAccountsPrefDeviceLocalAccountAutoLoginId,
938          &public_session_auto_login_username_)) {
939    public_session_auto_login_username_.clear();
940  }
941  if (!cros_settings_->GetInteger(
942          kAccountsPrefDeviceLocalAccountAutoLoginDelay,
943          &public_session_auto_login_delay_)) {
944    public_session_auto_login_delay_ = 0;
945  }
946
947  if (!public_session_auto_login_username_.empty())
948    StartPublicSessionAutoLoginTimer();
949  else
950    StopPublicSessionAutoLoginTimer();
951}
952
953void ExistingUserController::ResetPublicSessionAutoLoginTimer() {
954  // Only restart the auto-login timer if it's already running.
955  if (auto_login_timer_ && auto_login_timer_->IsRunning()) {
956    StopPublicSessionAutoLoginTimer();
957    StartPublicSessionAutoLoginTimer();
958  }
959}
960
961void ExistingUserController::OnPublicSessionAutoLoginTimerFire() {
962  CHECK(signin_screen_ready_ &&
963        !is_login_in_progress_ &&
964        !public_session_auto_login_username_.empty());
965  LoginAsPublicAccount(public_session_auto_login_username_);
966}
967
968void ExistingUserController::StopPublicSessionAutoLoginTimer() {
969  if (auto_login_timer_)
970    auto_login_timer_->Stop();
971}
972
973void ExistingUserController::StartPublicSessionAutoLoginTimer() {
974  if (!signin_screen_ready_ ||
975      is_login_in_progress_ ||
976      public_session_auto_login_username_.empty()) {
977    return;
978  }
979
980  // Start the auto-login timer.
981  if (!auto_login_timer_)
982    auto_login_timer_.reset(new base::OneShotTimer<ExistingUserController>);
983
984  auto_login_timer_->Start(
985      FROM_HERE,
986      base::TimeDelta::FromMilliseconds(
987          public_session_auto_login_delay_),
988      base::Bind(
989          &ExistingUserController::OnPublicSessionAutoLoginTimerFire,
990          weak_factory_.GetWeakPtr()));
991}
992
993gfx::NativeWindow ExistingUserController::GetNativeWindow() const {
994  return host_->GetNativeWindow();
995}
996
997void ExistingUserController::InitializeStartUrls() const {
998  std::vector<std::string> start_urls;
999
1000  PrefService* prefs = g_browser_process->local_state();
1001  const base::ListValue *urls;
1002  bool show_getstarted_guide = false;
1003  if (UserManager::Get()->IsLoggedInAsDemoUser()) {
1004    if (CrosSettings::Get()->GetList(kStartUpUrls, &urls)) {
1005      // The retail mode user will get start URLs from a special policy if it is
1006      // set.
1007      for (base::ListValue::const_iterator it = urls->begin();
1008           it != urls->end(); ++it) {
1009        std::string url;
1010        if ((*it)->GetAsString(&url))
1011          start_urls.push_back(url);
1012      }
1013    }
1014  // Skip the default first-run behavior for public accounts.
1015  } else if (!UserManager::Get()->IsLoggedInAsPublicAccount()) {
1016    if (prefs->GetBoolean(prefs::kSpokenFeedbackEnabled)) {
1017      const char* url = kChromeVoxTutorialURLPattern;
1018      const std::string current_locale =
1019          StringToLowerASCII(prefs->GetString(prefs::kApplicationLocale));
1020      std::string vox_url = base::StringPrintf(url, current_locale.c_str());
1021      start_urls.push_back(vox_url);
1022    } else {
1023      show_getstarted_guide = true;
1024    }
1025  }
1026
1027  ServicesCustomizationDocument* customization =
1028      ServicesCustomizationDocument::GetInstance();
1029  if (!ServicesCustomizationDocument::WasApplied() &&
1030      customization->IsReady()) {
1031    // Since we don't use OEM start URL anymore, just mark as applied.
1032    customization->ApplyCustomization();
1033  }
1034
1035  if (show_getstarted_guide) {
1036    CommandLine::ForCurrentProcess()->AppendSwitchASCII(
1037        switches::kApp, kGetStartedWebUrl);
1038    CommandLine::ForCurrentProcess()->AppendSwitchASCII(
1039        switches::kAppWindowSize, kGSGAppWindowSize);
1040  } else {
1041    // We should not be adding any start URLs if guide
1042    // is defined as it launches as a standalone app window.
1043    for (size_t i = 0; i < start_urls.size(); ++i)
1044      CommandLine::ForCurrentProcess()->AppendArg(start_urls[i]);
1045  }
1046}
1047
1048void ExistingUserController::OptionallyShowReleaseNotes(
1049    Profile* profile) const {
1050  // TODO(nkostylev): Fix WizardControllerFlowTest case.
1051  if (!profile || KioskModeSettings::Get()->IsKioskModeEnabled())
1052    return;
1053  if (UserManager::Get()->GetCurrentUserFlow()->ShouldSkipPostLoginScreens())
1054    return;
1055  PrefService* prefs = profile->GetPrefs();
1056  chrome::VersionInfo version_info;
1057  // New users would get this info with default getting started guide.
1058  // In password changed case 2 options are available:
1059  // 1. Cryptohome removed, pref is gone, not yet synced, recreate
1060  //    with latest version.
1061  // 2. Cryptohome migrated, pref is available. To simplify implementation
1062  //    update version here too. Unlikely that user signs in first time on
1063  //    the machine after update with password changed.
1064  if (UserManager::Get()->IsCurrentUserNew() || password_changed_) {
1065    prefs->SetString(prefs::kChromeOSReleaseNotesVersion,
1066                     version_info.Version());
1067    return;
1068  }
1069
1070  std::string prev_version_pref =
1071      prefs->GetString(prefs::kChromeOSReleaseNotesVersion);
1072  Version prev_version(prev_version_pref);
1073  if (!prev_version.IsValid())
1074    prev_version = Version("0.0.0.0");
1075  Version current_version(version_info.Version());
1076
1077  if (!current_version.components().size()) {
1078    NOTREACHED() << "Incorrect version " << current_version.GetString();
1079    return;
1080  }
1081
1082  // No "Release Notes" content yet for upgrade from M19 to later release.
1083  if (prev_version.components()[0] >= kReleaseNotesTargetRelease)
1084    return;
1085
1086  // Otherwise, trigger on major version change.
1087  if (current_version.components()[0] > prev_version.components()[0]) {
1088    CommandLine::ForCurrentProcess()->AppendSwitchASCII(
1089        switches::kApp, kGetStartedWebUrl);
1090    CommandLine::ForCurrentProcess()->AppendSwitchASCII(
1091        switches::kAppWindowSize, kGSGAppWindowSize);
1092      prefs->SetString(prefs::kChromeOSReleaseNotesVersion,
1093                       current_version.GetString());
1094  }
1095}
1096
1097void ExistingUserController::ShowError(int error_id,
1098                                       const std::string& details) {
1099  // TODO(dpolukhin): show detailed error info. |details| string contains
1100  // low level error info that is not localized and even is not user friendly.
1101  // For now just ignore it because error_text contains all required information
1102  // for end users, developers can see details string in Chrome logs.
1103  VLOG(1) << details;
1104  HelpAppLauncher::HelpTopic help_topic_id;
1105  bool is_offline = !ConnectivityStateHelper::Get()->IsConnected();
1106  switch (login_performer_->error().state()) {
1107    case GoogleServiceAuthError::CONNECTION_FAILED:
1108      help_topic_id = HelpAppLauncher::HELP_CANT_ACCESS_ACCOUNT_OFFLINE;
1109      break;
1110    case GoogleServiceAuthError::ACCOUNT_DISABLED:
1111      help_topic_id = HelpAppLauncher::HELP_ACCOUNT_DISABLED;
1112      break;
1113    case GoogleServiceAuthError::HOSTED_NOT_ALLOWED:
1114      help_topic_id = HelpAppLauncher::HELP_HOSTED_ACCOUNT;
1115      break;
1116    default:
1117      help_topic_id = is_offline ?
1118          HelpAppLauncher::HELP_CANT_ACCESS_ACCOUNT_OFFLINE :
1119          HelpAppLauncher::HELP_CANT_ACCESS_ACCOUNT;
1120      break;
1121  }
1122
1123  login_display_->ShowError(error_id, num_login_attempts_, help_topic_id);
1124}
1125
1126void ExistingUserController::ShowGaiaPasswordChanged(
1127    const std::string& username) {
1128  // Invalidate OAuth token, since it can't be correct after password is
1129  // changed.
1130  UserManager::Get()->SaveUserOAuthStatus(
1131      username,
1132      User::OAUTH2_TOKEN_STATUS_INVALID);
1133
1134  login_display_->SetUIEnabled(true);
1135  login_display_->ShowGaiaPasswordChanged(username);
1136}
1137
1138}  // namespace chromeos
1139