1 // Copyright (c) 2013 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.
5 #include "chrome/browser/ui/webui/chromeos/login/signin_screen_handler.h"
10 #include "base/bind_helpers.h"
11 #include "base/command_line.h"
12 #include "base/debug/trace_event.h"
13 #include "base/location.h"
14 #include "base/logging.h"
15 #include "base/metrics/histogram.h"
16 #include "base/prefs/pref_registry_simple.h"
17 #include "base/prefs/pref_service.h"
18 #include "base/prefs/scoped_user_pref_update.h"
19 #include "base/strings/string16.h"
20 #include "base/strings/string_util.h"
21 #include "base/strings/stringprintf.h"
22 #include "base/strings/utf_string_conversions.h"
23 #include "chrome/browser/browser_process.h"
24 #include "chrome/browser/browser_process_platform_part_chromeos.h"
25 #include "chrome/browser/browser_shutdown.h"
26 #include "chrome/browser/chrome_notification_types.h"
27 #include "chrome/browser/chromeos/app_mode/kiosk_app_manager.h"
28 #include "chrome/browser/chromeos/boot_times_loader.h"
29 #include "chrome/browser/chromeos/input_method/input_method_util.h"
30 #include "chrome/browser/chromeos/kiosk_mode/kiosk_mode_settings.h"
31 #include "chrome/browser/chromeos/login/hwid_checker.h"
32 #include "chrome/browser/chromeos/login/login_display_host.h"
33 #include "chrome/browser/chromeos/login/login_display_host_impl.h"
34 #include "chrome/browser/chromeos/login/multi_profile_user_controller.h"
35 #include "chrome/browser/chromeos/login/screen_locker.h"
36 #include "chrome/browser/chromeos/login/screens/core_oobe_actor.h"
37 #include "chrome/browser/chromeos/login/user.h"
38 #include "chrome/browser/chromeos/login/wallpaper_manager.h"
39 #include "chrome/browser/chromeos/login/webui_login_display.h"
40 #include "chrome/browser/chromeos/login/wizard_controller.h"
41 #include "chrome/browser/chromeos/net/network_portal_detector.h"
42 #include "chrome/browser/chromeos/policy/browser_policy_connector_chromeos.h"
43 #include "chrome/browser/chromeos/profiles/profile_helper.h"
44 #include "chrome/browser/chromeos/settings/cros_settings.h"
45 #include "chrome/browser/io_thread.h"
46 #include "chrome/browser/profiles/profile.h"
47 #include "chrome/browser/ui/webui/chromeos/login/authenticated_user_email_retriever.h"
48 #include "chrome/browser/ui/webui/chromeos/login/error_screen_handler.h"
49 #include "chrome/browser/ui/webui/chromeos/login/native_window_delegate.h"
50 #include "chrome/browser/ui/webui/chromeos/login/network_state_informer.h"
51 #include "chrome/browser/ui/webui/chromeos/login/oobe_ui.h"
52 #include "chrome/common/chrome_switches.h"
53 #include "chrome/common/pref_names.h"
54 #include "chrome/common/url_constants.h"
55 #include "chromeos/chromeos_switches.h"
56 #include "chromeos/dbus/dbus_thread_manager.h"
57 #include "chromeos/dbus/power_manager_client.h"
58 #include "chromeos/ime/ime_keyboard.h"
59 #include "chromeos/ime/input_method_manager.h"
60 #include "chromeos/network/network_state.h"
61 #include "chromeos/network/network_state_handler.h"
62 #include "content/public/browser/browser_thread.h"
63 #include "content/public/browser/render_frame_host.h"
64 #include "content/public/browser/web_contents.h"
65 #include "google_apis/gaia/gaia_auth_util.h"
66 #include "grit/chromium_strings.h"
67 #include "grit/generated_resources.h"
68 #include "net/url_request/url_request_context_getter.h"
69 #include "third_party/cros_system_api/dbus/service_constants.h"
72 #include "ash/shell.h"
73 #include "ash/wm/lock_state_controller.h"
76 using content::BrowserThread;
80 // User dictionary keys.
81 const char kKeyUsername[] = "username";
82 const char kKeyDisplayName[] = "displayName";
83 const char kKeyEmailAddress[] = "emailAddress";
84 const char kKeyEnterpriseDomain[] = "enterpriseDomain";
85 const char kKeyPublicAccount[] = "publicAccount";
86 const char kKeyLocallyManagedUser[] = "locallyManagedUser";
87 const char kKeySignedIn[] = "signedIn";
88 const char kKeyCanRemove[] = "canRemove";
89 const char kKeyIsOwner[] = "isOwner";
90 const char kKeyInitialAuthType[] = "initialAuthType";
91 const char kKeyMultiProfilesAllowed[] = "isMultiProfilesAllowed";
92 const char kKeyMultiProfilesPolicy[] = "multiProfilesPolicy";
94 // Max number of users to show.
95 const size_t kMaxUsers = 18;
97 // Timeout to delay first notification about offline state for a
99 const int kOfflineTimeoutSec = 5;
101 // Timeout used to prevent infinite connecting to a flaky network.
102 const int kConnectingTimeoutSec = 60;
104 // Type of the login screen UI that is currently presented to user.
105 const char kSourceGaiaSignin[] = "gaia-signin";
106 const char kSourceAccountPicker[] = "account-picker";
108 // The Task posted to PostTaskAndReply in StartClearingDnsCache on the IO
110 void ClearDnsCache(IOThread* io_thread) {
111 DCHECK_CURRENTLY_ON(BrowserThread::IO);
112 if (browser_shutdown::IsTryingToQuit())
115 io_thread->ClearHostCache();
118 static bool Contains(const std::vector<std::string>& container,
119 const std::string& value) {
120 return std::find(container.begin(), container.end(), value) !=
130 bool IsOnline(NetworkStateInformer::State state,
131 ErrorScreenActor::ErrorReason reason) {
132 return state == NetworkStateInformer::ONLINE &&
133 reason != ErrorScreenActor::ERROR_REASON_PORTAL_DETECTED &&
134 reason != ErrorScreenActor::ERROR_REASON_LOADING_TIMEOUT;
137 bool IsBehindCaptivePortal(NetworkStateInformer::State state,
138 ErrorScreenActor::ErrorReason reason) {
139 return state == NetworkStateInformer::CAPTIVE_PORTAL ||
140 reason == ErrorScreenActor::ERROR_REASON_PORTAL_DETECTED;
143 bool IsProxyError(NetworkStateInformer::State state,
144 ErrorScreenActor::ErrorReason reason,
145 net::Error frame_error) {
146 return state == NetworkStateInformer::PROXY_AUTH_REQUIRED ||
147 reason == ErrorScreenActor::ERROR_REASON_PROXY_AUTH_CANCELLED ||
148 reason == ErrorScreenActor::ERROR_REASON_PROXY_CONNECTION_FAILED ||
149 (reason == ErrorScreenActor::ERROR_REASON_FRAME_ERROR &&
150 (frame_error == net::ERR_PROXY_CONNECTION_FAILED ||
151 frame_error == net::ERR_TUNNEL_CONNECTION_FAILED));
154 bool IsSigninScreen(const OobeUI::Screen screen) {
155 return screen == OobeUI::SCREEN_GAIA_SIGNIN ||
156 screen == OobeUI::SCREEN_ACCOUNT_PICKER;
159 bool IsSigninScreenError(ErrorScreen::ErrorState error_state) {
160 return error_state == ErrorScreen::ERROR_STATE_PORTAL ||
161 error_state == ErrorScreen::ERROR_STATE_OFFLINE ||
162 error_state == ErrorScreen::ERROR_STATE_PROXY ||
163 error_state == ErrorScreen::ERROR_STATE_AUTH_EXT_TIMEOUT;
166 // Returns network name by service path.
167 std::string GetNetworkName(const std::string& service_path) {
168 const NetworkState* network = NetworkHandler::Get()->network_state_handler()->
169 GetNetworkState(service_path);
171 return std::string();
172 return network->name();
175 static bool SetUserInputMethodImpl(
176 const std::string& username,
177 chromeos::input_method::InputMethodManager* manager) {
178 PrefService* const local_state = g_browser_process->local_state();
180 const base::DictionaryValue* users_lru_input_methods =
181 local_state->GetDictionary(prefs::kUsersLRUInputMethod);
183 if (users_lru_input_methods == NULL) {
184 DLOG(WARNING) << "SetUserInputMethod('" << username
185 << "'): no kUsersLRUInputMethod";
189 std::string input_method;
191 if (!users_lru_input_methods->GetStringWithoutPathExpansion(username,
193 DVLOG(0) << "SetUserInputMethod('" << username
194 << "'): no input method for this user";
198 if (input_method.empty())
201 if (!manager->IsLoginKeyboard(input_method)) {
202 LOG(WARNING) << "SetUserInputMethod('" << username
203 << "'): stored user LRU input method '" << input_method
204 << "' is no longer Full Latin Keyboard Language"
205 << " (entry dropped). Use hardware default instead.";
207 DictionaryPrefUpdate updater(local_state, prefs::kUsersLRUInputMethod);
209 base::DictionaryValue* const users_lru_input_methods = updater.Get();
210 if (users_lru_input_methods != NULL) {
211 users_lru_input_methods->SetStringWithoutPathExpansion(username, "");
216 if (!Contains(manager->GetActiveInputMethodIds(), input_method)) {
217 if (!manager->EnableInputMethod(input_method)) {
218 DLOG(ERROR) << "SigninScreenHandler::SetUserInputMethod('" << username
219 << "'): user input method '" << input_method
220 << "' is not enabled and enabling failed (ignored!).";
223 manager->ChangeInputMethod(input_method);
228 void RecordSAMLScrapingVerificationResultInHistogram(bool success) {
229 UMA_HISTOGRAM_BOOLEAN("ChromeOS.SAML.Scraping.VerificationResult", success);
232 bool ShouldForceOnlineSignIn(const User* user) {
233 // Public sessions are always allowed to log in offline.
234 // Supervised user are allowed to log in offline if their OAuth token status
235 // is unknown or valid.
236 // For all other users, force online sign in if:
237 // * The flag to force online sign-in is set for the user.
238 // * The user's OAuth token is invalid.
239 // * The user's OAuth token status is unknown (except supervised users,
241 if (user->is_logged_in())
244 const User::OAuthTokenStatus token_status = user->oauth_token_status();
245 const bool is_locally_managed_user =
246 user->GetType() == User::USER_TYPE_LOCALLY_MANAGED;
247 const bool is_public_session =
248 user->GetType() == User::USER_TYPE_PUBLIC_ACCOUNT;
250 if (is_locally_managed_user &&
251 token_status == User::OAUTH_TOKEN_STATUS_UNKNOWN) {
255 if (is_public_session)
258 return user->force_online_signin() ||
259 (token_status == User::OAUTH2_TOKEN_STATUS_INVALID) ||
260 (token_status == User::OAUTH_TOKEN_STATUS_UNKNOWN);
265 // LoginScreenContext implementation ------------------------------------------
267 LoginScreenContext::LoginScreenContext() {
271 LoginScreenContext::LoginScreenContext(const base::ListValue* args) {
274 if (!args || args->GetSize() == 0)
277 if (args->GetString(0, &email))
281 void LoginScreenContext::Init() {
285 // SigninScreenHandler implementation ------------------------------------------
287 SigninScreenHandler::SigninScreenHandler(
288 const scoped_refptr<NetworkStateInformer>& network_state_informer,
289 ErrorScreenActor* error_screen_actor,
290 CoreOobeActor* core_oobe_actor,
291 GaiaScreenHandler* gaia_screen_handler)
292 : ui_state_(UI_STATE_UNKNOWN),
294 native_window_delegate_(NULL),
295 show_on_init_(false),
297 focus_stolen_(false),
298 gaia_silent_load_(false),
299 is_account_picker_showing_first_time_(false),
301 dns_clear_task_running_(false),
302 cookies_cleared_(false),
303 network_state_informer_(network_state_informer),
304 using_saml_api_(false),
305 test_expects_complete_login_(false),
307 webui_visible_(false),
308 preferences_changed_delayed_(false),
309 error_screen_actor_(error_screen_actor),
310 core_oobe_actor_(core_oobe_actor),
311 is_first_update_state_call_(true),
312 offline_login_active_(false),
313 last_network_state_(NetworkStateInformer::UNKNOWN),
314 has_pending_auth_ui_(false),
315 caps_lock_enabled_(false),
316 gaia_screen_handler_(gaia_screen_handler) {
317 DCHECK(network_state_informer_.get());
318 DCHECK(error_screen_actor_);
319 DCHECK(core_oobe_actor_);
320 DCHECK(gaia_screen_handler_);
321 gaia_screen_handler_->SetSigninScreenHandler(this);
322 network_state_informer_->AddObserver(this);
323 allow_new_user_subscription_ = CrosSettings::Get()->AddSettingsObserver(
324 kAccountsPrefAllowNewUser,
325 base::Bind(&SigninScreenHandler::UserSettingsChanged,
326 base::Unretained(this)));
327 allow_guest_subscription_ = CrosSettings::Get()->AddSettingsObserver(
328 kAccountsPrefAllowGuest,
329 base::Bind(&SigninScreenHandler::UserSettingsChanged,
330 base::Unretained(this)));
333 chrome::NOTIFICATION_AUTH_NEEDED,
334 content::NotificationService::AllSources());
336 chrome::NOTIFICATION_AUTH_SUPPLIED,
337 content::NotificationService::AllSources());
339 chrome::NOTIFICATION_AUTH_CANCELLED,
340 content::NotificationService::AllSources());
343 SigninScreenHandler::~SigninScreenHandler() {
344 ash::Shell::GetInstance()->RemovePreTargetHandler(this);
345 weak_factory_.InvalidateWeakPtrs();
347 delegate_->SetWebUIHandler(NULL);
348 network_state_informer_->RemoveObserver(this);
351 void SigninScreenHandler::DeclareLocalizedValues(
352 LocalizedValuesBuilder* builder) {
353 builder->Add("passwordHint", IDS_LOGIN_POD_EMPTY_PASSWORD_TEXT);
354 builder->Add("podMenuButtonAccessibleName",
355 IDS_LOGIN_POD_MENU_BUTTON_ACCESSIBLE_NAME);
356 builder->Add("podMenuRemoveItemAccessibleName",
357 IDS_LOGIN_POD_MENU_REMOVE_ITEM_ACCESSIBLE_NAME);
358 builder->Add("passwordFieldAccessibleName",
359 IDS_LOGIN_POD_PASSWORD_FIELD_ACCESSIBLE_NAME);
360 builder->Add("signedIn", IDS_SCREEN_LOCK_ACTIVE_USER);
361 builder->Add("signinButton", IDS_LOGIN_BUTTON);
362 builder->Add("launchAppButton", IDS_LAUNCH_APP_BUTTON);
363 builder->Add("shutDown", IDS_SHUTDOWN_BUTTON);
364 builder->Add("addUser", IDS_ADD_USER_BUTTON);
365 builder->Add("browseAsGuest", IDS_GO_INCOGNITO_BUTTON);
366 builder->Add("cancel", IDS_CANCEL);
367 builder->Add("signOutUser", IDS_SCREEN_LOCK_SIGN_OUT);
368 builder->Add("offlineLogin", IDS_OFFLINE_LOGIN_HTML);
369 builder->Add("ownerUserPattern", IDS_LOGIN_POD_OWNER_USER);
370 builder->Add("removeUser", IDS_LOGIN_POD_REMOVE_USER);
371 builder->Add("errorTpmFailureTitle", IDS_LOGIN_ERROR_TPM_FAILURE_TITLE);
372 builder->Add("errorTpmFailureReboot", IDS_LOGIN_ERROR_TPM_FAILURE_REBOOT);
373 builder->Add("errorTpmFailureRebootButton",
374 IDS_LOGIN_ERROR_TPM_FAILURE_REBOOT_BUTTON);
376 policy::BrowserPolicyConnectorChromeOS* connector =
377 g_browser_process->platform_part()->browser_policy_connector_chromeos();
378 builder->Add("disabledAddUserTooltip",
379 connector->IsEnterpriseManaged()
380 ? IDS_DISABLED_ADD_USER_TOOLTIP_ENTERPRISE
381 : IDS_DISABLED_ADD_USER_TOOLTIP);
383 builder->Add("supervisedUserExpiredTokenWarning",
384 IDS_SUPERVISED_USER_EXPIRED_TOKEN_WARNING);
385 builder->Add("signinBannerText", IDS_LOGIN_USER_ADDING_BANNER);
387 // Multi-profiles related strings.
388 builder->Add("multiProfilesRestrictedPolicyTitle",
389 IDS_MULTI_PROFILES_RESTRICTED_POLICY_TITLE);
390 builder->Add("multiProfilesNotAllowedPolicyMsg",
391 IDS_MULTI_PROFILES_NOT_ALLOWED_POLICY_MSG);
392 builder->Add("multiProfilesPrimaryOnlyPolicyMsg",
393 IDS_MULTI_PROFILES_PRIMARY_ONLY_POLICY_MSG);
395 // Strings used by password changed dialog.
396 builder->Add("passwordChangedTitle", IDS_LOGIN_PASSWORD_CHANGED_TITLE);
397 builder->Add("passwordChangedDesc", IDS_LOGIN_PASSWORD_CHANGED_DESC);
398 builder->AddF("passwordChangedMoreInfo",
399 IDS_LOGIN_PASSWORD_CHANGED_MORE_INFO,
400 IDS_SHORT_PRODUCT_OS_NAME);
402 builder->Add("oldPasswordHint", IDS_LOGIN_PASSWORD_CHANGED_OLD_PASSWORD_HINT);
403 builder->Add("oldPasswordIncorrect",
404 IDS_LOGIN_PASSWORD_CHANGED_INCORRECT_OLD_PASSWORD);
405 builder->Add("passwordChangedCantRemember",
406 IDS_LOGIN_PASSWORD_CHANGED_CANT_REMEMBER);
407 builder->Add("passwordChangedBackButton",
408 IDS_LOGIN_PASSWORD_CHANGED_BACK_BUTTON);
409 builder->Add("passwordChangedsOkButton", IDS_OK);
410 builder->Add("passwordChangedProceedAnyway",
411 IDS_LOGIN_PASSWORD_CHANGED_PROCEED_ANYWAY);
412 builder->Add("proceedAnywayButton",
413 IDS_LOGIN_PASSWORD_CHANGED_PROCEED_ANYWAY_BUTTON);
414 builder->Add("publicAccountInfoFormat", IDS_LOGIN_PUBLIC_ACCOUNT_INFO_FORMAT);
415 builder->Add("publicAccountReminder",
416 IDS_LOGIN_PUBLIC_ACCOUNT_SIGNOUT_REMINDER);
417 builder->Add("publicAccountEnter", IDS_LOGIN_PUBLIC_ACCOUNT_ENTER);
418 builder->Add("publicAccountEnterAccessibleName",
419 IDS_LOGIN_PUBLIC_ACCOUNT_ENTER_ACCESSIBLE_NAME);
420 builder->AddF("removeUserWarningText",
421 IDS_LOGIN_POD_USER_REMOVE_WARNING,
422 base::UTF8ToUTF16(chrome::kSupervisedUserManagementDisplayURL));
423 builder->Add("removeUserWarningButtonTitle",
424 IDS_LOGIN_POD_USER_REMOVE_WARNING_BUTTON);
426 builder->Add("samlNotice", IDS_LOGIN_SAML_NOTICE);
428 builder->Add("confirmPasswordTitle", IDS_LOGIN_CONFIRM_PASSWORD_TITLE);
429 builder->Add("confirmPasswordLabel", IDS_LOGIN_CONFIRM_PASSWORD_LABEL);
430 builder->Add("confirmPasswordConfirmButton",
431 IDS_LOGIN_CONFIRM_PASSWORD_CONFIRM_BUTTON);
432 builder->Add("confirmPasswordText", IDS_LOGIN_CONFIRM_PASSWORD_TEXT);
433 builder->Add("confirmPasswordErrorText",
434 IDS_LOGIN_CONFIRM_PASSWORD_ERROR_TEXT);
435 builder->Add("easyUnlockTooltip",
436 IDS_LOGIN_EASY_UNLOCK_TOOLTIP);
438 builder->Add("fatalEnrollmentError",
439 IDS_ENTERPRISE_ENROLLMENT_AUTH_FATAL_ERROR);
440 builder->Add("insecureURLEnrollmentError",
441 IDS_ENTERPRISE_ENROLLMENT_AUTH_INSECURE_URL_ERROR);
443 if (chromeos::KioskModeSettings::Get()->IsKioskModeEnabled())
444 builder->Add("demoLoginMessage", IDS_KIOSK_MODE_LOGIN_MESSAGE);
446 builder->Add("runType", CommandLine::ForCurrentProcess()->HasSwitch(
447 switches::kFirstExecAfterBoot) ? "firstExecAfterBoot" :
448 "notFirstExecAfterBoot");
451 void SigninScreenHandler::Show(const LoginScreenContext& context) {
454 // Just initialize internal fields from context and call ShowImpl().
455 oobe_ui_ = context.oobe_ui();
456 if (!context.email().empty())
457 email_ = context.email();
463 void SigninScreenHandler::ShowRetailModeLoginSpinner() {
464 CallJS("showLoginSpinner");
467 void SigninScreenHandler::SetDelegate(SigninScreenHandlerDelegate* delegate) {
468 delegate_ = delegate;
470 delegate_->SetWebUIHandler(this);
472 auto_enrollment_progress_subscription_.reset();
475 void SigninScreenHandler::SetNativeWindowDelegate(
476 NativeWindowDelegate* native_window_delegate) {
477 native_window_delegate_ = native_window_delegate;
480 void SigninScreenHandler::OnNetworkReady() {
481 LOG(WARNING) << "OnNetworkReady() call.";
482 MaybePreloadAuthExtension();
485 void SigninScreenHandler::UpdateState(ErrorScreenActor::ErrorReason reason) {
486 UpdateStateInternal(reason, false);
489 // SigninScreenHandler, private: -----------------------------------------------
491 void SigninScreenHandler::ShowImpl() {
492 if (!page_is_ready()) {
493 show_on_init_ = true;
498 // Shows new user sign-in for OOBE.
499 OnShowAddUser(email_);
501 // Populates account picker. Animation is turned off for now until we
502 // figure out how to make it fast enough.
505 // Reset Caps Lock state when login screen is shown.
506 input_method::InputMethodManager::Get()
508 ->SetCapsLockEnabled(false);
510 base::DictionaryValue params;
511 params.SetBoolean("disableAddUser", AllWhitelistedUsersPresent());
512 UpdateUIState(UI_STATE_ACCOUNT_PICKER, ¶ms);
516 void SigninScreenHandler::UpdateUIState(UIState ui_state,
517 base::DictionaryValue* params) {
519 case UI_STATE_GAIA_SIGNIN:
520 ui_state_ = UI_STATE_GAIA_SIGNIN;
521 ShowScreen(OobeUI::kScreenGaiaSignin, params);
523 case UI_STATE_ACCOUNT_PICKER:
524 ui_state_ = UI_STATE_ACCOUNT_PICKER;
525 ShowScreen(OobeUI::kScreenAccountPicker, params);
533 // TODO (ygorshenin@): split this method into small parts.
534 // TODO (ygorshenin@): move this logic to GaiaScreenHandler.
535 void SigninScreenHandler::UpdateStateInternal(
536 ErrorScreenActor::ErrorReason reason,
538 // Do nothing once user has signed in or sign in is in progress.
539 // TODO(ygorshenin): We will end up here when processing network state
540 // notification but no ShowSigninScreen() was called so delegate_ will be
541 // NULL. Network state processing logic does not belong here.
543 (delegate_->IsUserSigninCompleted() || delegate_->IsSigninInProgress())) {
547 NetworkStateInformer::State state = network_state_informer_->state();
548 const std::string network_path = network_state_informer_->network_path();
549 const std::string network_name = GetNetworkName(network_path);
551 // Skip "update" notification about OFFLINE state from
552 // NetworkStateInformer if previous notification already was
554 if ((state == NetworkStateInformer::OFFLINE || has_pending_auth_ui_) &&
555 !force_update && !update_state_closure_.IsCancelled()) {
559 // TODO (ygorshenin@): switch log level to INFO once signin screen
560 // will be tested well.
561 LOG(WARNING) << "SigninScreenHandler::UpdateStateInternal(): "
562 << "state=" << NetworkStateInformer::StatusString(state) << ", "
563 << "network_name=" << network_name << ", "
564 << "reason=" << ErrorScreenActor::ErrorReasonString(reason)
565 << ", force_update=" << force_update;
566 update_state_closure_.Cancel();
568 if ((state == NetworkStateInformer::OFFLINE && !force_update) ||
569 has_pending_auth_ui_) {
570 update_state_closure_.Reset(
571 base::Bind(&SigninScreenHandler::UpdateStateInternal,
572 weak_factory_.GetWeakPtr(),
575 base::MessageLoop::current()->PostDelayedTask(
577 update_state_closure_.callback(),
578 base::TimeDelta::FromSeconds(kOfflineTimeoutSec));
582 // Don't show or hide error screen if we're in connecting state.
583 if (state == NetworkStateInformer::CONNECTING && !force_update) {
584 if (connecting_closure_.IsCancelled()) {
585 // First notification about CONNECTING state.
586 connecting_closure_.Reset(
587 base::Bind(&SigninScreenHandler::UpdateStateInternal,
588 weak_factory_.GetWeakPtr(),
591 base::MessageLoop::current()->PostDelayedTask(
593 connecting_closure_.callback(),
594 base::TimeDelta::FromSeconds(kConnectingTimeoutSec));
598 connecting_closure_.Cancel();
600 const bool is_online = IsOnline(state, reason);
601 const bool is_behind_captive_portal = IsBehindCaptivePortal(state, reason);
602 const bool is_gaia_loading_timeout =
603 (reason == ErrorScreenActor::ERROR_REASON_LOADING_TIMEOUT);
604 const bool is_gaia_error =
605 FrameError() != net::OK && FrameError() != net::ERR_NETWORK_CHANGED;
606 const bool is_gaia_signin = IsGaiaVisible() || IsGaiaHiddenByError();
607 const bool error_screen_should_overlay =
608 !offline_login_active_ && IsGaiaVisible();
609 const bool from_not_online_to_online_transition =
610 is_online && last_network_state_ != NetworkStateInformer::ONLINE;
611 last_network_state_ = state;
613 if (is_online || !is_behind_captive_portal)
614 error_screen_actor_->HideCaptivePortal();
616 // Hide offline message (if needed) and return if current screen is
618 if (!is_gaia_signin) {
619 if (!IsSigninScreenHiddenByError())
620 HideOfflineMessage(state, reason);
624 // Reload frame if network state is changed from {!ONLINE} -> ONLINE state.
625 if (reason == ErrorScreenActor::ERROR_REASON_NETWORK_STATE_CHANGED &&
626 from_not_online_to_online_transition) {
627 // Schedules a immediate retry.
628 LOG(WARNING) << "Retry page load since network has been changed.";
632 if (reason == ErrorScreenActor::ERROR_REASON_PROXY_CONFIG_CHANGED &&
633 error_screen_should_overlay) {
634 // Schedules a immediate retry.
635 LOG(WARNING) << "Retry page load since proxy settings has been changed.";
639 if (reason == ErrorScreenActor::ERROR_REASON_FRAME_ERROR &&
640 !IsProxyError(state, reason, FrameError())) {
641 LOG(WARNING) << "Retry page load due to reason: "
642 << ErrorScreenActor::ErrorReasonString(reason);
646 if ((!is_online || is_gaia_loading_timeout || is_gaia_error) &&
647 !offline_login_active_) {
648 SetupAndShowOfflineMessage(state, reason);
650 HideOfflineMessage(state, reason);
654 void SigninScreenHandler::SetupAndShowOfflineMessage(
655 NetworkStateInformer:: State state,
656 ErrorScreenActor::ErrorReason reason) {
657 const std::string network_path = network_state_informer_->network_path();
658 const bool is_behind_captive_portal = IsBehindCaptivePortal(state, reason);
659 const bool is_proxy_error = IsProxyError(state, reason, FrameError());
660 const bool is_gaia_loading_timeout =
661 (reason == ErrorScreenActor::ERROR_REASON_LOADING_TIMEOUT);
663 if (is_proxy_error) {
664 error_screen_actor_->SetErrorState(ErrorScreen::ERROR_STATE_PROXY,
666 } else if (is_behind_captive_portal) {
667 // Do not bother a user with obsessive captive portal showing. This
668 // check makes captive portal being shown only once: either when error
669 // screen is shown for the first time or when switching from another
670 // error screen (offline, proxy).
671 if (IsGaiaVisible() ||
672 (error_screen_actor_->error_state() !=
673 ErrorScreen::ERROR_STATE_PORTAL)) {
674 error_screen_actor_->FixCaptivePortal();
676 const std::string network_name = GetNetworkName(network_path);
677 error_screen_actor_->SetErrorState(ErrorScreen::ERROR_STATE_PORTAL,
679 } else if (is_gaia_loading_timeout) {
680 error_screen_actor_->SetErrorState(
681 ErrorScreen::ERROR_STATE_AUTH_EXT_TIMEOUT, std::string());
683 error_screen_actor_->SetErrorState(ErrorScreen::ERROR_STATE_OFFLINE,
687 const bool guest_signin_allowed = IsGuestSigninAllowed() &&
688 IsSigninScreenError(error_screen_actor_->error_state());
689 error_screen_actor_->AllowGuestSignin(guest_signin_allowed);
691 const bool offline_login_allowed = IsOfflineLoginAllowed() &&
692 IsSigninScreenError(error_screen_actor_->error_state()) &&
693 error_screen_actor_->error_state() !=
694 ErrorScreen::ERROR_STATE_AUTH_EXT_TIMEOUT;
695 error_screen_actor_->AllowOfflineLogin(offline_login_allowed);
697 if (GetCurrentScreen() != OobeUI::SCREEN_ERROR_MESSAGE) {
698 base::DictionaryValue params;
699 const std::string network_type = network_state_informer_->network_type();
700 params.SetString("lastNetworkType", network_type);
701 error_screen_actor_->SetUIState(ErrorScreen::UI_STATE_SIGNIN);
702 error_screen_actor_->Show(OobeUI::SCREEN_GAIA_SIGNIN, ¶ms);
706 void SigninScreenHandler::HideOfflineMessage(
707 NetworkStateInformer::State state,
708 ErrorScreenActor::ErrorReason reason) {
709 if (!IsSigninScreenHiddenByError())
712 error_screen_actor_->Hide();
714 // Forces a reload for Gaia screen on hiding error message.
715 if (IsGaiaVisible() || IsGaiaHiddenByError())
719 void SigninScreenHandler::ReloadGaiaScreen() {
720 gaia_screen_handler_->ReloadGaia();
723 void SigninScreenHandler::Initialize() {
724 // If delegate_ is NULL here (e.g. WebUIScreenLocker has been destroyed),
725 // don't do anything, just return.
729 // Make sure the event is processed by this before the IME.
730 ash::Shell::GetInstance()->PrependPreTargetHandler(this);
733 show_on_init_ = false;
738 gfx::NativeWindow SigninScreenHandler::GetNativeWindow() {
739 if (native_window_delegate_)
740 return native_window_delegate_->GetNativeWindow();
744 void SigninScreenHandler::RegisterMessages() {
745 AddCallback("usingSAMLAPI", &SigninScreenHandler::HandleUsingSAMLAPI);
746 AddCallback("scrapedPasswordCount",
747 &SigninScreenHandler::HandleScrapedPasswordCount);
748 AddCallback("scrapedPasswordVerificationFailed",
749 &SigninScreenHandler::HandleScrapedPasswordVerificationFailed);
750 AddCallback("authenticateUser", &SigninScreenHandler::HandleAuthenticateUser);
751 AddCallback("completeLogin", &SigninScreenHandler::HandleCompleteLogin);
752 AddCallback("completeAuthentication",
753 &SigninScreenHandler::HandleCompleteAuthentication);
754 AddCallback("getUsers", &SigninScreenHandler::HandleGetUsers);
755 AddCallback("launchDemoUser", &SigninScreenHandler::HandleLaunchDemoUser);
756 AddCallback("launchIncognito", &SigninScreenHandler::HandleLaunchIncognito);
757 AddCallback("showLocallyManagedUserCreationScreen",
758 &SigninScreenHandler::HandleShowLocallyManagedUserCreationScreen);
759 AddCallback("launchPublicAccount",
760 &SigninScreenHandler::HandleLaunchPublicAccount);
761 AddRawCallback("offlineLogin", &SigninScreenHandler::HandleOfflineLogin);
762 AddCallback("rebootSystem", &SigninScreenHandler::HandleRebootSystem);
763 AddRawCallback("showAddUser", &SigninScreenHandler::HandleShowAddUser);
764 AddCallback("shutdownSystem", &SigninScreenHandler::HandleShutdownSystem);
765 AddCallback("loadWallpaper", &SigninScreenHandler::HandleLoadWallpaper);
766 AddCallback("removeUser", &SigninScreenHandler::HandleRemoveUser);
767 AddCallback("toggleEnrollmentScreen",
768 &SigninScreenHandler::HandleToggleEnrollmentScreen);
769 AddCallback("toggleKioskEnableScreen",
770 &SigninScreenHandler::HandleToggleKioskEnableScreen);
771 AddCallback("createAccount", &SigninScreenHandler::HandleCreateAccount);
772 AddCallback("accountPickerReady",
773 &SigninScreenHandler::HandleAccountPickerReady);
774 AddCallback("wallpaperReady", &SigninScreenHandler::HandleWallpaperReady);
775 AddCallback("loginWebuiReady", &SigninScreenHandler::HandleLoginWebuiReady);
776 AddCallback("signOutUser", &SigninScreenHandler::HandleSignOutUser);
777 AddCallback("openProxySettings",
778 &SigninScreenHandler::HandleOpenProxySettings);
779 AddCallback("loginVisible", &SigninScreenHandler::HandleLoginVisible);
780 AddCallback("cancelPasswordChangedFlow",
781 &SigninScreenHandler::HandleCancelPasswordChangedFlow);
782 AddCallback("cancelUserAdding",
783 &SigninScreenHandler::HandleCancelUserAdding);
784 AddCallback("migrateUserData", &SigninScreenHandler::HandleMigrateUserData);
785 AddCallback("resyncUserData", &SigninScreenHandler::HandleResyncUserData);
786 AddCallback("loginUIStateChanged",
787 &SigninScreenHandler::HandleLoginUIStateChanged);
788 AddCallback("unlockOnLoginSuccess",
789 &SigninScreenHandler::HandleUnlockOnLoginSuccess);
790 AddCallback("showLoadingTimeoutError",
791 &SigninScreenHandler::HandleShowLoadingTimeoutError);
792 AddCallback("updateOfflineLogin",
793 &SigninScreenHandler::HandleUpdateOfflineLogin);
794 AddCallback("focusPod", &SigninScreenHandler::HandleFocusPod);
795 AddCallback("customButtonClicked",
796 &SigninScreenHandler::HandleCustomButtonClicked);
797 AddCallback("retrieveAuthenticatedUserEmail",
798 &SigninScreenHandler::HandleRetrieveAuthenticatedUserEmail);
800 // This message is sent by the kiosk app menu, but is handled here
801 // so we can tell the delegate to launch the app.
802 AddCallback("launchKioskApp", &SigninScreenHandler::HandleLaunchKioskApp);
805 void SigninScreenHandler::RegisterPrefs(PrefRegistrySimple* registry) {
806 registry->RegisterDictionaryPref(prefs::kUsersLRUInputMethod);
809 void SigninScreenHandler::HandleGetUsers() {
813 void SigninScreenHandler::ClearAndEnablePassword() {
814 core_oobe_actor_->ResetSignInUI(false);
817 void SigninScreenHandler::ClearUserPodPassword() {
818 core_oobe_actor_->ClearUserPodPassword();
821 void SigninScreenHandler::RefocusCurrentPod() {
822 core_oobe_actor_->RefocusCurrentPod();
825 void SigninScreenHandler::OnLoginSuccess(const std::string& username) {
826 core_oobe_actor_->OnLoginSuccess(username);
829 void SigninScreenHandler::OnUserRemoved(const std::string& username) {
830 CallJS("login.AccountPickerScreen.removeUser", username);
831 if (delegate_->GetUsers().empty())
835 void SigninScreenHandler::OnUserImageChanged(const User& user) {
837 CallJS("login.AccountPickerScreen.updateUserImage", user.email());
840 void SigninScreenHandler::OnPreferencesChanged() {
841 // Make sure that one of the login UI is fully functional now, otherwise
842 // preferences update would be picked up next time it will be shown.
843 if (!webui_visible_) {
844 LOG(WARNING) << "Login UI is not active - postponed prefs change.";
845 preferences_changed_delayed_ = true;
849 if (delegate_ && !delegate_->IsShowUsers()) {
850 HandleShowAddUser(NULL);
853 UpdateUIState(UI_STATE_ACCOUNT_PICKER, NULL);
855 preferences_changed_delayed_ = false;
858 void SigninScreenHandler::ResetSigninScreenHandlerDelegate() {
862 void SigninScreenHandler::ShowBannerMessage(const std::string& message) {
863 CallJS("login.AccountPickerScreen.showBannerMessage", message);
866 void SigninScreenHandler::ShowUserPodButton(
867 const std::string& username,
868 const std::string& iconURL,
869 const base::Closure& click_callback) {
870 user_pod_button_callback_map_[username] = click_callback;
871 CallJS("login.AccountPickerScreen.showUserPodButton", username, iconURL);
873 // TODO(tengs): Move this code once we move unlocking to native code.
874 if (ScreenLocker::default_screen_locker()) {
875 UserManager* user_manager = UserManager::Get();
876 const User* user = user_manager->FindUser(username);
879 PrefService* profile_prefs =
880 user_manager->GetProfileByUser(user)->GetPrefs();
881 if (profile_prefs->GetBoolean(prefs::kEasyUnlockShowTutorial)) {
882 CallJS("login.AccountPickerScreen.showEasyUnlockBubble");
883 profile_prefs->SetBoolean(prefs::kEasyUnlockShowTutorial, false);
888 void SigninScreenHandler::HideUserPodButton(const std::string& username) {
889 CallJS("login.AccountPickerScreen.hideUserPodButton", username);
892 void SigninScreenHandler::SetAuthType(const std::string& username,
893 LoginDisplay::AuthType auth_type,
894 const std::string& initial_value) {
895 user_auth_type_map_[username] = auth_type;
896 CallJS("login.AccountPickerScreen.setAuthType",
898 static_cast<int>(auth_type),
899 base::StringValue(initial_value));
902 LoginDisplay::AuthType SigninScreenHandler::GetAuthType(
903 const std::string& username) const {
904 if (user_auth_type_map_.find(username) == user_auth_type_map_.end())
905 return LoginDisplay::OFFLINE_PASSWORD;
906 return user_auth_type_map_.find(username)->second;
909 void SigninScreenHandler::ShowError(int login_attempts,
910 const std::string& error_text,
911 const std::string& help_link_text,
912 HelpAppLauncher::HelpTopic help_topic_id) {
913 core_oobe_actor_->ShowSignInError(login_attempts, error_text, help_link_text,
917 void SigninScreenHandler::ShowErrorScreen(LoginDisplay::SigninError error_id) {
919 case LoginDisplay::TPM_ERROR:
920 core_oobe_actor_->ShowTpmError();
923 NOTREACHED() << "Unknown sign in error";
928 void SigninScreenHandler::ShowSigninUI(const std::string& email) {
929 core_oobe_actor_->ShowSignInUI(email);
932 void SigninScreenHandler::ShowControlBar(bool show) {
933 core_oobe_actor_->ShowControlBar(show);
936 void SigninScreenHandler::ShowGaiaPasswordChanged(const std::string& username) {
938 password_changed_for_.insert(email_);
939 core_oobe_actor_->ShowSignInUI(email_);
940 CallJS("login.setAuthType",
942 static_cast<int>(LoginDisplay::ONLINE_SIGN_IN),
943 base::StringValue(""));
946 void SigninScreenHandler::ShowPasswordChangedDialog(bool show_password_error) {
947 core_oobe_actor_->ShowPasswordChangedScreen(show_password_error);
950 void SigninScreenHandler::ShowSigninScreenForCreds(
951 const std::string& username,
952 const std::string& password) {
953 VLOG(2) << "ShowSigninScreenForCreds for user " << username
954 << ", frame_state=" << FrameState();
956 test_user_ = username;
957 test_pass_ = password;
958 test_expects_complete_login_ = true;
960 // Submit login form for test if gaia is ready. If gaia is loading, login
961 // will be attempted in HandleLoginWebuiReady after gaia is ready. Otherwise,
962 // reload gaia then follow the loading case.
963 if (FrameState() == GaiaScreenHandler::FRAME_STATE_LOADED)
964 SubmitLoginFormForTest();
965 else if (FrameState() != GaiaScreenHandler::FRAME_STATE_LOADING)
966 HandleShowAddUser(NULL);
969 void SigninScreenHandler::OnCookiesCleared(base::Closure on_clear_callback) {
970 DCHECK_CURRENTLY_ON(BrowserThread::UI);
971 cookies_cleared_ = true;
972 on_clear_callback.Run();
975 void SigninScreenHandler::OnKeyEvent(ui::KeyEvent* key) {
976 if (key->type() == ui::ET_KEY_PRESSED &&
977 key->key_code() == ui::VKEY_CAPITAL) {
978 caps_lock_enabled_ = !caps_lock_enabled_;
980 CallJS("login.AccountPickerScreen.setCapsLockState", caps_lock_enabled_);
984 void SigninScreenHandler::Observe(int type,
985 const content::NotificationSource& source,
986 const content::NotificationDetails& details) {
988 case chrome::NOTIFICATION_AUTH_NEEDED: {
989 has_pending_auth_ui_ = true;
992 case chrome::NOTIFICATION_AUTH_SUPPLIED:
993 has_pending_auth_ui_ = false;
994 // Reload auth extension as proxy credentials are supplied.
995 if (!IsSigninScreenHiddenByError() && ui_state_ == UI_STATE_GAIA_SIGNIN)
997 update_state_closure_.Cancel();
999 case chrome::NOTIFICATION_AUTH_CANCELLED: {
1000 // Don't reload auth extension if proxy auth dialog was cancelled.
1001 has_pending_auth_ui_ = false;
1002 update_state_closure_.Cancel();
1006 NOTREACHED() << "Unexpected notification " << type;
1010 void SigninScreenHandler::OnDnsCleared() {
1011 DCHECK_CURRENTLY_ON(BrowserThread::UI);
1012 dns_clear_task_running_ = false;
1013 dns_cleared_ = true;
1014 ShowSigninScreenIfReady();
1017 // Update keyboard layout to least recently used by the user.
1018 void SigninScreenHandler::SetUserInputMethod(const std::string& username) {
1019 UserManager* user_manager = UserManager::Get();
1020 if (user_manager->IsUserLoggedIn()) {
1021 // We are on sign-in screen inside user session (adding new user to
1022 // the session or on lock screen), don't switch input methods in this case.
1023 // TODO(dpolukhin): adding user and sign-in should be consistent
1028 chromeos::input_method::InputMethodManager* const manager =
1029 chromeos::input_method::InputMethodManager::Get();
1031 const bool succeed = SetUserInputMethodImpl(username, manager);
1033 // This is also a case when LRU layout is set only for a few local users,
1034 // thus others need to be switched to default locale.
1035 // Otherwise they will end up using another user's locale to log in.
1037 DVLOG(0) << "SetUserInputMethod('" << username
1038 << "'): failed to set user layout. Switching to default.";
1040 manager->SetInputMethodLoginDefault();
1044 void SigninScreenHandler::ShowSigninScreenIfReady() {
1045 LOG(WARNING) << "ShowSigninScreenIfReady() call.";
1047 if (!dns_cleared_ || !cookies_cleared_ || !delegate_)
1050 std::string active_network_path = network_state_informer_->network_path();
1051 if (gaia_silent_load_ &&
1052 (network_state_informer_->state() != NetworkStateInformer::ONLINE ||
1053 gaia_silent_load_network_ != active_network_path)) {
1054 // Network has changed. Force Gaia reload.
1055 gaia_silent_load_ = false;
1056 // Gaia page will be realoded, so focus isn't stolen anymore.
1057 focus_stolen_ = false;
1060 // Note that LoadAuthExtension clears |email_|.
1062 delegate_->LoadSigninWallpaper();
1064 delegate_->LoadWallpaper(email_);
1066 // Set Least Recently Used input method for the user.
1067 if (!email_.empty())
1068 SetUserInputMethod(email_);
1070 LoadAuthExtension(!gaia_silent_load_, false, false);
1071 UpdateUIState(UI_STATE_GAIA_SIGNIN, NULL);
1073 if (gaia_silent_load_) {
1074 // The variable is assigned to false because silently loaded Gaia page was
1076 gaia_silent_load_ = false;
1078 HandleLoginWebuiReady();
1081 UpdateState(ErrorScreenActor::ERROR_REASON_UPDATE);
1084 void SigninScreenHandler::LoadAuthExtension(
1085 bool force, bool silent_load, bool offline) {
1086 GaiaContext context;
1087 context.force_reload = force;
1088 context.is_local = offline;
1089 context.password_changed =
1090 !email_.empty() && password_changed_for_.count(email_);
1092 context.show_users = delegate_->IsShowUsers();
1093 context.use_offline = offline;
1095 context.has_users = !delegate_->GetUsers().empty();
1096 context.email = email_;
1100 DCHECK(gaia_screen_handler_);
1101 gaia_screen_handler_->LoadGaia(context);
1104 void SigninScreenHandler::UserSettingsChanged() {
1105 DCHECK(gaia_screen_handler_);
1106 GaiaContext context;
1108 context.has_users = !delegate_->GetUsers().empty();
1109 gaia_screen_handler_->UpdateGaia(context);
1110 UpdateAddButtonStatus();
1113 void SigninScreenHandler::UpdateAddButtonStatus() {
1114 CallJS("cr.ui.login.DisplayManager.updateAddUserButtonStatus",
1115 AllWhitelistedUsersPresent());
1118 void SigninScreenHandler::HandleUsingSAMLAPI() {
1119 SetSAMLPrincipalsAPIUsed(true);
1122 void SigninScreenHandler::HandleScrapedPasswordCount(int password_count) {
1123 SetSAMLPrincipalsAPIUsed(false);
1124 // Use a histogram that has 11 buckets, one for each of the values in [0, 9]
1125 // and an overflow bucket at the end.
1126 UMA_HISTOGRAM_ENUMERATION(
1127 "ChromeOS.SAML.Scraping.PasswordCount", std::min(password_count, 10), 11);
1128 if (password_count == 0)
1129 HandleScrapedPasswordVerificationFailed();
1132 void SigninScreenHandler::HandleScrapedPasswordVerificationFailed() {
1133 RecordSAMLScrapingVerificationResultInHistogram(false);
1136 void SigninScreenHandler::HandleCompleteLogin(const std::string& typed_email,
1137 const std::string& password,
1142 if (using_saml && !using_saml_api_)
1143 RecordSAMLScrapingVerificationResultInHistogram(true);
1145 const std::string sanitized_email = gaia::SanitizeEmail(typed_email);
1146 delegate_->SetDisplayEmail(sanitized_email);
1147 delegate_->CompleteLogin(UserContext(
1150 std::string(), // auth_code
1151 std::string(), // username_hash
1152 true, // using_oauth
1153 using_saml ? UserContext::AUTH_FLOW_GAIA_WITH_SAML
1154 : UserContext::AUTH_FLOW_GAIA_WITHOUT_SAML));
1156 if (test_expects_complete_login_) {
1157 VLOG(2) << "Complete test login for " << typed_email
1158 << ", requested=" << test_user_;
1160 test_expects_complete_login_ = false;
1166 void SigninScreenHandler::HandleCompleteAuthentication(
1167 const std::string& email,
1168 const std::string& password,
1169 const std::string& auth_code) {
1172 const std::string sanitized_email = gaia::SanitizeEmail(email);
1173 delegate_->SetDisplayEmail(sanitized_email);
1174 delegate_->CompleteLogin(UserContext(sanitized_email, password, auth_code));
1177 void SigninScreenHandler::HandleAuthenticateUser(const std::string& username,
1178 const std::string& password) {
1181 delegate_->Login(UserContext(gaia::SanitizeEmail(username),
1183 std::string())); // auth_code
1186 void SigninScreenHandler::HandleLaunchDemoUser() {
1188 delegate_->LoginAsRetailModeUser();
1191 void SigninScreenHandler::HandleLaunchIncognito() {
1193 delegate_->LoginAsGuest();
1196 void SigninScreenHandler::HandleShowLocallyManagedUserCreationScreen() {
1197 if (!UserManager::Get()->AreLocallyManagedUsersAllowed()) {
1198 LOG(ERROR) << "Managed users not allowed.";
1201 scoped_ptr<base::DictionaryValue> params(new base::DictionaryValue());
1202 LoginDisplayHostImpl::default_host()->
1203 StartWizard(WizardController::kLocallyManagedUserCreationScreenName,
1207 void SigninScreenHandler::HandleLaunchPublicAccount(
1208 const std::string& username) {
1210 delegate_->LoginAsPublicAccount(username);
1213 void SigninScreenHandler::HandleOfflineLogin(const base::ListValue* args) {
1214 if (!delegate_ || delegate_->IsShowUsers()) {
1218 if (!args->GetString(0, &email_))
1220 // Load auth extension. Parameters are: force reload, do not load extension in
1221 // background, use offline version.
1222 LoadAuthExtension(true, false, true);
1223 UpdateUIState(UI_STATE_GAIA_SIGNIN, NULL);
1226 void SigninScreenHandler::HandleShutdownSystem() {
1227 ash::Shell::GetInstance()->lock_state_controller()->RequestShutdown();
1230 void SigninScreenHandler::HandleLoadWallpaper(const std::string& email) {
1232 delegate_->LoadWallpaper(email);
1235 void SigninScreenHandler::HandleRebootSystem() {
1236 chromeos::DBusThreadManager::Get()->GetPowerManagerClient()->RequestRestart();
1239 void SigninScreenHandler::HandleRemoveUser(const std::string& email) {
1242 delegate_->RemoveUser(email);
1243 UpdateAddButtonStatus();
1246 void SigninScreenHandler::HandleShowAddUser(const base::ListValue* args) {
1247 TRACE_EVENT_ASYNC_STEP_INTO0("ui",
1249 LoginDisplayHostImpl::kShowLoginWebUIid,
1252 // |args| can be null if it's OOBE.
1254 args->GetString(0, &email);
1255 OnShowAddUser(email);
1258 void SigninScreenHandler::HandleToggleEnrollmentScreen() {
1260 delegate_->ShowEnterpriseEnrollmentScreen();
1263 void SigninScreenHandler::HandleToggleKioskEnableScreen() {
1264 policy::BrowserPolicyConnectorChromeOS* connector =
1265 g_browser_process->platform_part()->browser_policy_connector_chromeos();
1267 !auto_enrollment_progress_subscription_ &&
1268 !connector->IsEnterpriseManaged() &&
1269 LoginDisplayHostImpl::default_host()) {
1270 AutoEnrollmentController* auto_enrollment_controller =
1271 LoginDisplayHostImpl::default_host()->GetAutoEnrollmentController();
1272 auto_enrollment_progress_subscription_ =
1273 auto_enrollment_controller->RegisterProgressCallback(
1274 base::Bind(&SigninScreenHandler::ContinueKioskEnableFlow,
1275 weak_factory_.GetWeakPtr()));
1276 ContinueKioskEnableFlow(auto_enrollment_controller->state());
1280 void SigninScreenHandler::HandleToggleKioskAutolaunchScreen() {
1281 policy::BrowserPolicyConnectorChromeOS* connector =
1282 g_browser_process->platform_part()->browser_policy_connector_chromeos();
1283 if (delegate_ && !connector->IsEnterpriseManaged())
1284 delegate_->ShowKioskAutolaunchScreen();
1287 void SigninScreenHandler::FillUserDictionary(User* user,
1289 bool is_signin_to_add,
1290 LoginDisplay::AuthType auth_type,
1291 base::DictionaryValue* user_dict) {
1292 const std::string& email = user->email();
1293 const bool is_public_account =
1294 user->GetType() == User::USER_TYPE_PUBLIC_ACCOUNT;
1295 const bool is_locally_managed_user =
1296 user->GetType() == User::USER_TYPE_LOCALLY_MANAGED;
1298 user_dict->SetString(kKeyUsername, email);
1299 user_dict->SetString(kKeyEmailAddress, user->display_email());
1300 user_dict->SetString(kKeyDisplayName, user->GetDisplayName());
1301 user_dict->SetBoolean(kKeyPublicAccount, is_public_account);
1302 user_dict->SetBoolean(kKeyLocallyManagedUser, is_locally_managed_user);
1303 user_dict->SetInteger(kKeyInitialAuthType, auth_type);
1304 user_dict->SetBoolean(kKeySignedIn, user->is_logged_in());
1305 user_dict->SetBoolean(kKeyIsOwner, is_owner);
1307 // Fill in multi-profiles related fields.
1308 if (is_signin_to_add) {
1309 MultiProfileUserController* multi_profile_user_controller =
1310 UserManager::Get()->GetMultiProfileUserController();
1311 std::string behavior = multi_profile_user_controller->
1312 GetCachedValue(user->email());
1313 user_dict->SetBoolean(kKeyMultiProfilesAllowed,
1314 multi_profile_user_controller->IsUserAllowedInSession(email) ==
1315 MultiProfileUserController::ALLOWED);
1316 user_dict->SetString(kKeyMultiProfilesPolicy, behavior);
1318 user_dict->SetBoolean(kKeyMultiProfilesAllowed, true);
1321 if (is_public_account) {
1322 policy::BrowserPolicyConnectorChromeOS* policy_connector =
1323 g_browser_process->platform_part()->browser_policy_connector_chromeos();
1325 if (policy_connector->IsEnterpriseManaged()) {
1326 user_dict->SetString(kKeyEnterpriseDomain,
1327 policy_connector->GetEnterpriseDomain());
1332 void SigninScreenHandler::SendUserList(bool animated) {
1335 TRACE_EVENT_ASYNC_STEP_INTO0("ui",
1337 LoginDisplayHostImpl::kShowLoginWebUIid,
1339 BootTimesLoader::Get()->RecordCurrentStats("login-send-user-list");
1341 base::ListValue users_list;
1342 const UserList& users = delegate_->GetUsers();
1344 // TODO(nkostylev): Move to a separate method in UserManager.
1345 // http://crbug.com/230852
1346 bool is_signin_to_add = LoginDisplayHostImpl::default_host() &&
1347 UserManager::Get()->IsUserLoggedIn();
1349 user_pod_button_callback_map_.clear();
1350 user_auth_type_map_.clear();
1352 bool single_user = users.size() == 1;
1354 chromeos::CrosSettings::Get()->GetString(chromeos::kDeviceOwner, &owner);
1355 bool has_owner = owner.size() > 0;
1356 size_t max_non_owner_users = has_owner ? kMaxUsers - 1 : kMaxUsers;
1357 size_t non_owner_count = 0;
1358 policy::BrowserPolicyConnectorChromeOS* connector =
1359 g_browser_process->platform_part()->
1360 browser_policy_connector_chromeos();
1361 bool is_enterprise_managed = connector->IsEnterpriseManaged();
1364 for (UserList::const_iterator it = users.begin(); it != users.end(); ++it) {
1365 const std::string& email = (*it)->email();
1366 bool is_owner = (email == owner);
1367 bool is_public_account =
1368 ((*it)->GetType() == User::USER_TYPE_PUBLIC_ACCOUNT);
1370 if ((is_public_account && !is_signin_to_add) ||
1372 (!is_public_account && non_owner_count < max_non_owner_users)) {
1373 LoginDisplay::AuthType initial_auth_type =
1374 ShouldForceOnlineSignIn(*it) ? LoginDisplay::ONLINE_SIGN_IN
1375 : LoginDisplay::OFFLINE_PASSWORD;
1376 user_auth_type_map_[email] = initial_auth_type;
1378 base::DictionaryValue* user_dict = new base::DictionaryValue();
1380 *it, is_owner, is_signin_to_add, initial_auth_type, user_dict);
1381 bool signed_in = (*it)->is_logged_in();
1382 // Single user check here is necessary because owner info might not be
1383 // available when running into login screen on first boot.
1384 // See http://crosbug.com/12723
1385 bool can_remove_user = ((!single_user || is_enterprise_managed) &&
1386 !email.empty() && !is_owner && !is_public_account &&
1387 !signed_in && !is_signin_to_add);
1388 user_dict->SetBoolean(kKeyCanRemove, can_remove_user);
1392 if (is_owner && users_list.GetSize() > kMaxUsers) {
1393 // Owner is always in the list.
1394 users_list.Insert(kMaxUsers - 1, user_dict);
1396 users_list.Append(user_dict);
1400 while (users_list.GetSize() > kMaxUsers)
1401 users_list.Remove(kMaxUsers, NULL);
1403 CallJS("login.AccountPickerScreen.loadUsers", users_list, animated,
1404 delegate_->IsShowGuest());
1407 void SigninScreenHandler::HandleAccountPickerReady() {
1408 VLOG(0) << "Login WebUI >> AccountPickerReady";
1410 if (delegate_ && !ScreenLocker::default_screen_locker() &&
1411 !chromeos::IsMachineHWIDCorrect() &&
1413 delegate_->ShowWrongHWIDScreen();
1417 PrefService* prefs = g_browser_process->local_state();
1418 if (prefs->GetBoolean(prefs::kFactoryResetRequested)) {
1419 if (core_oobe_actor_)
1420 core_oobe_actor_->ShowDeviceResetScreen();
1424 is_account_picker_showing_first_time_ = true;
1425 MaybePreloadAuthExtension();
1427 if (ScreenLocker::default_screen_locker())
1428 ScreenLocker::default_screen_locker()->delegate()->OnLockWebUIReady();
1431 delegate_->OnSigninScreenReady();
1434 void SigninScreenHandler::HandleWallpaperReady() {
1435 if (ScreenLocker::default_screen_locker()) {
1436 ScreenLocker::default_screen_locker()->delegate()->
1437 OnLockBackgroundDisplayed();
1441 void SigninScreenHandler::HandleLoginWebuiReady() {
1442 if (focus_stolen_) {
1443 // Set focus to the Gaia page.
1444 // TODO(altimofeev): temporary solution, until focus parameters are
1445 // implemented on the Gaia side.
1446 // Do this only once. Any subsequent call would relod GAIA frame.
1447 focus_stolen_ = false;
1449 "if (typeof gWindowOnLoad != 'undefined') gWindowOnLoad();";
1450 content::RenderFrameHost* frame =
1451 LoginDisplayHostImpl::GetGaiaAuthIframe(web_ui()->GetWebContents());
1452 frame->ExecuteJavaScript(base::ASCIIToUTF16(code));
1454 if (gaia_silent_load_) {
1455 focus_stolen_ = true;
1456 // Prevent focus stealing by the Gaia page.
1457 // TODO(altimofeev): temporary solution, until focus parameters are
1458 // implemented on the Gaia side.
1459 const char code[] = "var gWindowOnLoad = window.onload; "
1460 "window.onload=function() {};";
1461 content::RenderFrameHost* frame =
1462 LoginDisplayHostImpl::GetGaiaAuthIframe(web_ui()->GetWebContents());
1463 frame->ExecuteJavaScript(base::ASCIIToUTF16(code));
1464 // As we could miss and window.onload could already be called, restore
1465 // focus to current pod (see crbug/175243).
1466 RefocusCurrentPod();
1468 DCHECK(gaia_screen_handler_);
1469 gaia_screen_handler_->HandleFrameLoadingCompleted(0);
1471 if (test_expects_complete_login_)
1472 SubmitLoginFormForTest();
1475 void SigninScreenHandler::HandleSignOutUser() {
1477 delegate_->Signout();
1480 void SigninScreenHandler::HandleCreateAccount() {
1482 delegate_->CreateAccount();
1485 void SigninScreenHandler::HandleOpenProxySettings() {
1486 LoginDisplayHostImpl::default_host()->OpenProxySettings();
1489 void SigninScreenHandler::HandleLoginVisible(const std::string& source) {
1490 LOG(WARNING) << "Login WebUI >> loginVisible, src: " << source << ", "
1491 << "webui_visible_: " << webui_visible_;
1492 if (!webui_visible_) {
1493 // There might be multiple messages from OOBE UI so send notifications after
1494 // the first one only.
1495 content::NotificationService::current()->Notify(
1496 chrome::NOTIFICATION_LOGIN_OR_LOCK_WEBUI_VISIBLE,
1497 content::NotificationService::AllSources(),
1498 content::NotificationService::NoDetails());
1499 TRACE_EVENT_ASYNC_END0(
1500 "ui", "ShowLoginWebUI", LoginDisplayHostImpl::kShowLoginWebUIid);
1502 webui_visible_ = true;
1503 if (preferences_changed_delayed_)
1504 OnPreferencesChanged();
1507 void SigninScreenHandler::HandleCancelPasswordChangedFlow() {
1508 StartClearingCookies(base::Bind(
1509 &SigninScreenHandler::CancelPasswordChangedFlowInternal,
1510 weak_factory_.GetWeakPtr()));
1513 void SigninScreenHandler::HandleCancelUserAdding() {
1515 delegate_->CancelUserAdding();
1518 void SigninScreenHandler::HandleMigrateUserData(
1519 const std::string& old_password) {
1521 delegate_->MigrateUserData(old_password);
1524 void SigninScreenHandler::HandleResyncUserData() {
1526 delegate_->ResyncUserData();
1529 void SigninScreenHandler::HandleLoginUIStateChanged(const std::string& source,
1531 VLOG(0) << "Login WebUI >> active: " << new_value << ", "
1532 << "source: " << source;
1534 if (!KioskAppManager::Get()->GetAutoLaunchApp().empty() &&
1535 KioskAppManager::Get()->IsAutoLaunchRequested()) {
1536 VLOG(0) << "Showing auto-launch warning";
1537 // On slow devices, the wallpaper animation is not shown initially, so we
1538 // must explicitly load the wallpaper. This is also the case for the
1539 // account-picker and gaia-signin UI states.
1540 delegate_->LoadSigninWallpaper();
1541 HandleToggleKioskAutolaunchScreen();
1545 if (source == kSourceGaiaSignin) {
1546 ui_state_ = UI_STATE_GAIA_SIGNIN;
1547 } else if (source == kSourceAccountPicker) {
1548 ui_state_ = UI_STATE_ACCOUNT_PICKER;
1555 void SigninScreenHandler::HandleUnlockOnLoginSuccess() {
1556 DCHECK(UserManager::Get()->IsUserLoggedIn());
1557 if (ScreenLocker::default_screen_locker())
1558 ScreenLocker::default_screen_locker()->UnlockOnLoginSuccess();
1561 void SigninScreenHandler::HandleShowLoadingTimeoutError() {
1562 UpdateState(ErrorScreenActor::ERROR_REASON_LOADING_TIMEOUT);
1565 void SigninScreenHandler::HandleUpdateOfflineLogin(bool offline_login_active) {
1566 offline_login_active_ = offline_login_active;
1569 void SigninScreenHandler::HandleFocusPod(const std::string& user_id) {
1570 SetUserInputMethod(user_id);
1571 WallpaperManager::Get()->SetUserWallpaperDelayed(user_id);
1574 void SigninScreenHandler::HandleCustomButtonClicked(
1575 const std::string& username) {
1576 if (user_pod_button_callback_map_.find(username)
1577 == user_pod_button_callback_map_.end()) {
1578 LOG(WARNING) << "User pod custom button clicked but no callback found";
1581 user_pod_button_callback_map_[username].Run();
1584 void SigninScreenHandler::HandleRetrieveAuthenticatedUserEmail(
1585 double attempt_token) {
1586 email_retriever_.reset(new AuthenticatedUserEmailRetriever(
1587 base::Bind(&SigninScreenHandler::CallJS<double, std::string>,
1588 base::Unretained(this),
1589 "login.GaiaSigninScreen.setAuthenticatedUserEmail",
1591 Profile::FromWebUI(web_ui())->GetRequestContext()));
1594 void SigninScreenHandler::HandleLaunchKioskApp(const std::string& app_id,
1595 bool diagnostic_mode) {
1596 delegate_->LoginAsKioskApp(app_id, diagnostic_mode);
1599 void SigninScreenHandler::StartClearingDnsCache() {
1600 if (dns_clear_task_running_ || !g_browser_process->io_thread())
1603 dns_cleared_ = false;
1604 BrowserThread::PostTaskAndReply(
1605 BrowserThread::IO, FROM_HERE,
1606 base::Bind(&ClearDnsCache, g_browser_process->io_thread()),
1607 base::Bind(&SigninScreenHandler::OnDnsCleared,
1608 weak_factory_.GetWeakPtr()));
1609 dns_clear_task_running_ = true;
1612 void SigninScreenHandler::StartClearingCookies(
1613 const base::Closure& on_clear_callback) {
1614 cookies_cleared_ = false;
1615 ProfileHelper* profile_helper =
1616 g_browser_process->platform_part()->profile_helper();
1618 Profile::FromWebUI(web_ui()) == profile_helper->GetSigninProfile());
1619 profile_helper->ClearSigninProfile(base::Bind(
1620 &SigninScreenHandler::OnCookiesCleared,
1621 weak_factory_.GetWeakPtr(), on_clear_callback));
1624 void SigninScreenHandler::MaybePreloadAuthExtension() {
1625 LOG(WARNING) << "MaybePreloadAuthExtension() call.";
1627 // Fetching of the extension is not started before account picker page is
1628 // loaded because it can affect the loading speed. Also if cookies clearing
1629 // was initiated or |dns_clear_task_running_| then auth extension showing has
1630 // already been initiated and preloading is senseless.
1631 // Do not load the extension for the screen locker, see crosbug.com/25018.
1632 if (is_account_picker_showing_first_time_ &&
1633 !gaia_silent_load_ &&
1634 !ScreenLocker::default_screen_locker() &&
1635 !cookies_cleared_ &&
1636 !dns_clear_task_running_ &&
1637 network_state_informer_->state() == NetworkStateInformer::ONLINE) {
1638 gaia_silent_load_ = true;
1639 gaia_silent_load_network_ = network_state_informer_->network_path();
1640 LoadAuthExtension(true, true, false);
1644 bool SigninScreenHandler::AllWhitelistedUsersPresent() {
1645 CrosSettings* cros_settings = CrosSettings::Get();
1646 bool allow_new_user = false;
1647 cros_settings->GetBoolean(kAccountsPrefAllowNewUser, &allow_new_user);
1650 UserManager* user_manager = UserManager::Get();
1651 const UserList& users = user_manager->GetUsers();
1652 if (!delegate_ || users.size() > kMaxUsers) {
1655 const base::ListValue* whitelist = NULL;
1656 if (!cros_settings->GetList(kAccountsPrefUsers, &whitelist) || !whitelist)
1658 for (size_t i = 0; i < whitelist->GetSize(); ++i) {
1659 std::string whitelisted_user;
1660 // NB: Wildcards in the whitelist are also detected as not present here.
1661 if (!whitelist->GetString(i, &whitelisted_user) ||
1662 !user_manager->IsKnownUser(whitelisted_user)) {
1669 void SigninScreenHandler::CancelPasswordChangedFlowInternal() {
1672 delegate_->CancelPasswordChangedFlow();
1676 OobeUI::Screen SigninScreenHandler::GetCurrentScreen() const {
1677 OobeUI::Screen screen = OobeUI::SCREEN_UNKNOWN;
1678 OobeUI* oobe_ui = static_cast<OobeUI*>(web_ui()->GetController());
1680 screen = oobe_ui->current_screen();
1684 bool SigninScreenHandler::IsGaiaVisible() const {
1685 return IsSigninScreen(GetCurrentScreen()) &&
1686 ui_state_ == UI_STATE_GAIA_SIGNIN;
1689 bool SigninScreenHandler::IsGaiaHiddenByError() const {
1690 return IsSigninScreenHiddenByError() &&
1691 ui_state_ == UI_STATE_GAIA_SIGNIN;
1694 bool SigninScreenHandler::IsSigninScreenHiddenByError() const {
1695 return (GetCurrentScreen() == OobeUI::SCREEN_ERROR_MESSAGE) &&
1696 (IsSigninScreen(error_screen_actor_->parent_screen()));
1699 bool SigninScreenHandler::IsGuestSigninAllowed() const {
1700 CrosSettings* cros_settings = CrosSettings::Get();
1704 cros_settings->GetBoolean(kAccountsPrefAllowGuest, &allow_guest);
1708 bool SigninScreenHandler::IsOfflineLoginAllowed() const {
1709 CrosSettings* cros_settings = CrosSettings::Get();
1713 // Offline login is allowed only when user pods are hidden.
1715 cros_settings->GetBoolean(kAccountsPrefShowUserNamesOnSignIn, &show_pods);
1719 void SigninScreenHandler::SubmitLoginFormForTest() {
1720 VLOG(2) << "Submit login form for test, user=" << test_user_;
1723 code += "document.getElementById('Email').value = '" + test_user_ + "';";
1724 code += "document.getElementById('Passwd').value = '" + test_pass_ + "';";
1725 code += "document.getElementById('signIn').click();";
1727 content::RenderFrameHost* frame =
1728 LoginDisplayHostImpl::GetGaiaAuthIframe(web_ui()->GetWebContents());
1729 frame->ExecuteJavaScript(base::ASCIIToUTF16(code));
1731 // Test properties are cleared in HandleCompleteLogin because the form
1732 // submission might fail and login will not be attempted after reloading
1733 // if they are cleared here.
1736 void SigninScreenHandler::ContinueKioskEnableFlow(
1737 policy::AutoEnrollmentState state) {
1738 // Do not proceed with kiosk enable when auto enroll will be enforced.
1739 // TODO(xiyuan): Add an error UI feedkback so user knows what happens.
1741 case policy::AUTO_ENROLLMENT_STATE_IDLE:
1742 case policy::AUTO_ENROLLMENT_STATE_PENDING:
1743 case policy::AUTO_ENROLLMENT_STATE_CONNECTION_ERROR:
1744 // Wait for the next callback.
1746 case policy::AUTO_ENROLLMENT_STATE_TRIGGER_ENROLLMENT:
1747 // Auto-enrollment is on.
1748 LOG(WARNING) << "Kiosk enable flow aborted because auto enrollment is "
1749 "going to be enforced.";
1750 if (!kiosk_enable_flow_aborted_callback_for_test_.is_null())
1751 kiosk_enable_flow_aborted_callback_for_test_.Run();
1753 case policy::AUTO_ENROLLMENT_STATE_SERVER_ERROR:
1754 case policy::AUTO_ENROLLMENT_STATE_NO_ENROLLMENT:
1755 // Auto-enrollment not applicable.
1757 delegate_->ShowKioskEnableScreen();
1760 auto_enrollment_progress_subscription_.reset();
1763 void SigninScreenHandler::OnShowAddUser(const std::string& email) {
1765 is_account_picker_showing_first_time_ = false;
1767 if (gaia_silent_load_ && email_.empty()) {
1768 dns_cleared_ = true;
1769 cookies_cleared_ = true;
1770 ShowSigninScreenIfReady();
1772 StartClearingDnsCache();
1773 StartClearingCookies(base::Bind(
1774 &SigninScreenHandler::ShowSigninScreenIfReady,
1775 weak_factory_.GetWeakPtr()));
1779 void SigninScreenHandler::SetSAMLPrincipalsAPIUsed(bool api_used) {
1780 using_saml_api_ = api_used;
1781 UMA_HISTOGRAM_BOOLEAN("ChromeOS.SAML.APIUsed", api_used);
1784 GaiaScreenHandler::FrameState SigninScreenHandler::FrameState() const {
1785 DCHECK(gaia_screen_handler_);
1786 return gaia_screen_handler_->frame_state();
1789 net::Error SigninScreenHandler::FrameError() const {
1790 DCHECK(gaia_screen_handler_);
1791 return gaia_screen_handler_->frame_error();
1794 } // namespace chromeos