1 // Copyright 2017 The Chromium Authors
2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file.
5 #include "ash/login/login_screen_controller.h"
9 #include "ash/constants/ash_pref_names.h"
10 #include "ash/constants/notifier_catalogs.h"
11 #include "ash/focus_cycler.h"
12 #include "ash/login/security_token_request_controller.h"
13 #include "ash/login/ui/lock_screen.h"
14 #include "ash/login/ui/login_data_dispatcher.h"
15 #include "ash/public/cpp/child_accounts/parent_access_controller.h"
16 #include "ash/public/cpp/login_screen_client.h"
17 #include "ash/public/cpp/system/toast_data.h"
18 #include "ash/root_window_controller.h"
19 #include "ash/session/session_controller_impl.h"
20 #include "ash/shelf/login_shelf_view.h"
21 #include "ash/shelf/login_shelf_widget.h"
22 #include "ash/shelf/shelf.h"
23 #include "ash/shelf/shelf_widget.h"
24 #include "ash/shell.h"
25 #include "ash/system/status_area_widget.h"
26 #include "ash/system/status_area_widget_delegate.h"
27 #include "ash/system/toast/toast_manager_impl.h"
28 #include "ash/system/tray/system_tray_notifier.h"
29 #include "base/debug/alias.h"
30 #include "base/debug/dump_without_crashing.h"
31 #include "base/functional/bind.h"
32 #include "base/functional/callback.h"
33 #include "base/strings/string_util.h"
34 #include "base/strings/utf_string_conversions.h"
35 #include "base/task/single_thread_task_runner.h"
36 #include "components/account_id/account_id.h"
37 #include "components/prefs/pref_registry_simple.h"
38 #include "components/session_manager/session_manager_types.h"
44 enum class SystemTrayVisibility {
45 kNone, // Tray not visible anywhere.
46 kPrimary, // Tray visible only on primary display.
47 kAll, // Tray visible on all displays.
50 void SetSystemTrayVisibility(SystemTrayVisibility visibility) {
51 RootWindowController* primary_window_controller =
52 Shell::GetPrimaryRootWindowController();
53 for (RootWindowController* window_controller :
54 Shell::GetAllRootWindowControllers()) {
55 StatusAreaWidget* status_area = window_controller->GetStatusAreaWidget();
59 if (window_controller == primary_window_controller) {
60 status_area->SetSystemTrayVisibility(
61 visibility == SystemTrayVisibility::kPrimary ||
62 visibility == SystemTrayVisibility::kAll);
64 status_area->SetSystemTrayVisibility(visibility ==
65 SystemTrayVisibility::kAll);
72 LoginScreenController::LoginScreenController(
73 SystemTrayNotifier* system_tray_notifier)
74 : system_tray_notifier_(system_tray_notifier) {
75 system_tray_notifier_->AddSystemTrayObserver(this);
78 LoginScreenController::~LoginScreenController() {
79 system_tray_notifier_->RemoveSystemTrayObserver(this);
83 void LoginScreenController::RegisterProfilePrefs(PrefRegistrySimple* registry,
86 // There is no remote pref service, so pretend that ash owns the pref.
87 registry->RegisterStringPref(prefs::kQuickUnlockPinSalt, "");
92 bool LoginScreenController::IsAuthenticating() const {
93 return authentication_stage_ != AuthenticationStage::kIdle;
96 bool LoginScreenController::IsAuthenticationCallbackExecuting() const {
97 return authentication_stage_ == AuthenticationStage::kUserCallback;
100 void LoginScreenController::AuthenticateUserWithPasswordOrPin(
101 const AccountId& account_id,
102 const std::string& password,
103 bool authenticated_by_pin,
104 OnAuthenticateCallback callback) {
105 // It is an error to call this function while an authentication is in
107 LOG_IF(FATAL, IsAuthenticating())
108 << "Duplicate authentication attempt; current authentication stage is "
109 << static_cast<int>(authentication_stage_);
112 std::move(callback).Run(absl::nullopt);
116 // If auth is disabled by the debug overlay bypass the mojo call entirely, as
117 // it will dismiss the lock screen if the password is correct.
118 switch (force_fail_auth_for_debug_overlay_) {
119 case ForceFailAuth::kOff:
121 case ForceFailAuth::kImmediate:
122 OnAuthenticateComplete(std::move(callback), false /*success*/);
124 case ForceFailAuth::kDelayed:
125 // Set a dummy authentication stage so that |IsAuthenticating| returns
127 LOG(WARNING) << "crbug.com/1339004 : Dummy auth state";
128 authentication_stage_ = AuthenticationStage::kDoAuthenticate;
129 base::SingleThreadTaskRunner::GetCurrentDefault()->PostDelayedTask(
131 base::BindOnce(&LoginScreenController::OnAuthenticateComplete,
132 weak_factory_.GetWeakPtr(), std::move(callback),
138 LOG(WARNING) << "crbug.com/1339004 : started authentication";
139 authentication_stage_ = AuthenticationStage::kDoAuthenticate;
141 if (authenticated_by_pin) {
142 DCHECK(base::ContainsOnlyChars(password, "0123456789"));
145 client_->AuthenticateUserWithPasswordOrPin(
146 account_id, password, authenticated_by_pin,
147 base::BindOnce(&LoginScreenController::OnAuthenticateComplete,
148 weak_factory_.GetWeakPtr(), std::move(callback)));
151 void LoginScreenController::AuthenticateUserWithEasyUnlock(
152 const AccountId& account_id) {
153 // TODO(jdufault): integrate this into authenticate stage after mojom is
154 // refactored to use a callback.
158 client_->AuthenticateUserWithEasyUnlock(account_id);
161 void LoginScreenController::AuthenticateUserWithChallengeResponse(
162 const AccountId& account_id,
163 OnAuthenticateCallback callback) {
164 LOG_IF(FATAL, IsAuthenticating())
165 << "Duplicate authentication attempt; current authentication stage is "
166 << static_cast<int>(authentication_stage_);
169 std::move(callback).Run(/*success=*/absl::nullopt);
173 authentication_stage_ = AuthenticationStage::kDoAuthenticate;
174 client_->AuthenticateUserWithChallengeResponse(
176 base::BindOnce(&LoginScreenController::OnAuthenticateComplete,
177 weak_factory_.GetWeakPtr(), std::move(callback)));
180 ParentCodeValidationResult LoginScreenController::ValidateParentAccessCode(
181 const AccountId& account_id,
182 base::Time validation_time,
183 const std::string& code) {
184 DCHECK(!validation_time.is_null());
187 return ParentCodeValidationResult::kInternalError;
190 return client_->ValidateParentAccessCode(account_id, code, validation_time);
193 bool LoginScreenController::GetSecurityTokenPinRequestCanceled() const {
194 return security_token_request_controller_.request_canceled();
197 void LoginScreenController::OnFocusPod(const AccountId& account_id) {
198 GetModel()->NotifyFocusPod(account_id);
202 client_->OnFocusPod(account_id);
205 void LoginScreenController::CancelAddUser() {
209 client_->CancelAddUser();
212 void LoginScreenController::ShowGuestTosScreen() {
216 client_->ShowGuestTosScreen();
219 void LoginScreenController::OnMaxIncorrectPasswordAttempted(
220 const AccountId& account_id) {
224 client_->OnMaxIncorrectPasswordAttempted(account_id);
227 void LoginScreenController::FocusLockScreenApps(bool reverse) {
231 client_->FocusLockScreenApps(reverse);
234 void LoginScreenController::ShowGaiaSignin(const AccountId& prefilled_account) {
238 client_->ShowGaiaSignin(prefilled_account);
241 void LoginScreenController::ShowOsInstallScreen() {
245 client_->ShowOsInstallScreen();
248 void LoginScreenController::OnRemoveUserWarningShown() {
252 client_->OnRemoveUserWarningShown();
255 void LoginScreenController::RemoveUser(const AccountId& account_id) {
259 client_->RemoveUser(account_id);
262 void LoginScreenController::LaunchPublicSession(
263 const AccountId& account_id,
264 const std::string& locale,
265 const std::string& input_method) {
269 client_->LaunchPublicSession(account_id, locale, input_method);
272 void LoginScreenController::RequestPublicSessionKeyboardLayouts(
273 const AccountId& account_id,
274 const std::string& locale) {
278 client_->RequestPublicSessionKeyboardLayouts(account_id, locale);
281 void LoginScreenController::SetClient(LoginScreenClient* client) {
285 LoginScreenModel* LoginScreenController::GetModel() {
286 return &login_data_dispatcher_;
289 void LoginScreenController::ShowKioskAppError(const std::string& message) {
290 ToastData toast_data("KioskAppError", ToastCatalogName::kKioskAppError,
291 base::UTF8ToUTF16(message), ToastData::kInfiniteDuration,
292 /*visible_on_lock_screen=*/true,
293 /*has_dismiss_button=*/true);
294 Shell::Get()->toast_manager()->Show(std::move(toast_data));
297 void LoginScreenController::FocusLoginShelf(bool reverse) {
298 Shelf* shelf = Shelf::ForWindow(Shell::Get()->GetPrimaryRootWindow());
299 // Tell the focus direction to the status area or the shelf so they can focus
300 // the correct child view.
301 if (Shell::GetPrimaryRootWindowController()->IsSystemTrayVisible() &&
302 (reverse || !shelf->shelf_widget()->GetLoginShelfView()->IsFocusable())) {
303 // Focus goes to system tray (status area) if one of the following is true:
304 // - system tray is visible and tab is in reverse order;
305 // - system tray is visible and there is no visible shelf buttons before.
306 shelf->GetStatusAreaWidget()
307 ->status_area_widget_delegate()
308 ->set_default_last_focusable_child(reverse);
309 Shell::Get()->focus_cycler()->FocusWidget(shelf->GetStatusAreaWidget());
310 } else if (shelf->shelf_widget()->GetLoginShelfView()->IsFocusable()) {
311 // Otherwise focus goes to login shelf buttons when there is any.
312 if (features::IsUseLoginShelfWidgetEnabled()) {
313 LoginShelfWidget* login_shelf_widget = shelf->login_shelf_widget();
314 login_shelf_widget->SetDefaultLastFocusableChild(reverse);
315 Shell::Get()->focus_cycler()->FocusWidget(login_shelf_widget);
317 shelf->shelf_widget()->set_default_last_focusable_child(reverse);
318 Shell::Get()->focus_cycler()->FocusWidget(shelf->shelf_widget());
321 // No elements to focus on the shelf.
323 // TODO(b/261774910): This is reachable apparently.
324 // Reaching this and not doing anything probably means that no view element
325 // is focused, but this is preferable to crashing via NOTREACHED().
326 base::debug::DumpWithoutCrashing();
330 bool LoginScreenController::IsReadyForPassword() {
331 return LockScreen::HasInstance() && !IsAuthenticating();
334 void LoginScreenController::EnableAddUserButton(bool enable) {
335 Shelf::ForWindow(Shell::Get()->GetPrimaryRootWindow())
337 ->GetLoginShelfView()
338 ->SetAddUserButtonEnabled(enable);
341 void LoginScreenController::EnableShutdownButton(bool enable) {
342 Shelf::ForWindow(Shell::Get()->GetPrimaryRootWindow())
344 ->GetLoginShelfView()
345 ->SetShutdownButtonEnabled(enable);
348 void LoginScreenController::EnableShelfButtons(bool enable) {
349 Shelf::ForWindow(Shell::Get()->GetPrimaryRootWindow())
351 ->GetLoginShelfView()
352 ->SetButtonEnabled(enable);
355 void LoginScreenController::SetIsFirstSigninStep(bool is_first) {
356 Shelf::ForWindow(Shell::Get()->GetPrimaryRootWindow())
358 ->GetLoginShelfView()
359 ->SetIsFirstSigninStep(is_first);
362 void LoginScreenController::ShowParentAccessButton(bool show) {
363 Shelf::ForWindow(Shell::Get()->GetPrimaryRootWindow())
365 ->GetLoginShelfView()
366 ->ShowParentAccessButton(show);
369 void LoginScreenController::SetAllowLoginAsGuest(bool allow_guest) {
370 Shelf::ForWindow(Shell::Get()->GetPrimaryRootWindow())
372 ->GetLoginShelfView()
373 ->SetAllowLoginAsGuest(allow_guest);
376 std::unique_ptr<ScopedGuestButtonBlocker>
377 LoginScreenController::GetScopedGuestButtonBlocker() {
378 return Shelf::ForWindow(Shell::Get()->GetPrimaryRootWindow())
380 ->GetLoginShelfView()
381 ->GetScopedGuestButtonBlocker();
384 void LoginScreenController::RequestSecurityTokenPin(
385 SecurityTokenPinRequest request) {
386 security_token_request_controller_.SetPinUiState(std::move(request));
389 void LoginScreenController::ClearSecurityTokenPinRequest() {
390 security_token_request_controller_.ClosePinUi();
393 views::Widget* LoginScreenController::GetLoginWindowWidget() {
394 return client_ ? client_->GetLoginWindowWidget() : nullptr;
397 void LoginScreenController::ShowLockScreen() {
398 CHECK(!LockScreen::HasInstance());
400 LockScreen::Show(LockScreen::ScreenType::kLock);
403 void LoginScreenController::ShowLoginScreen() {
404 CHECK(!LockScreen::HasInstance());
405 // Login screen can only be used during login.
406 session_manager::SessionState session_state =
407 Shell::Get()->session_controller()->GetSessionState();
408 CHECK(session_state == session_manager::SessionState::LOGIN_PRIMARY ||
409 session_state == session_manager::SessionState::LOGIN_SECONDARY)
410 << "Not showing login screen since session state is "
411 << static_cast<int>(session_state);
414 // TODO(jdufault): rename LockScreen to LoginScreen.
415 LockScreen::Show(LockScreen::ScreenType::kLogin);
418 void LoginScreenController::SetKioskApps(
419 const std::vector<KioskAppMenuEntry>& kiosk_apps) {
420 Shelf::ForWindow(Shell::Get()->GetPrimaryRootWindow())
422 ->GetLoginShelfView()
423 ->SetKioskApps(kiosk_apps);
426 void LoginScreenController::ConfigureKioskCallbacks(
427 const base::RepeatingCallback<void(const KioskAppMenuEntry&)>& launch_app,
428 const base::RepeatingClosure& on_show_menu) {
429 Shelf::ForWindow(Shell::Get()->GetPrimaryRootWindow())
431 ->GetLoginShelfView()
432 ->ConfigureKioskCallbacks(launch_app, on_show_menu);
435 void LoginScreenController::HandleAccelerator(
436 ash::LoginAcceleratorAction action) {
440 client_->HandleAccelerator(action);
443 void LoginScreenController::ShowAccountAccessHelpApp(
444 gfx::NativeWindow parent_window) {
445 client_->ShowAccountAccessHelpApp(parent_window);
448 void LoginScreenController::ShowParentAccessHelpApp() {
449 client_->ShowParentAccessHelpApp();
452 void LoginScreenController::ShowLockScreenNotificationSettings() {
453 client_->ShowLockScreenNotificationSettings();
456 void LoginScreenController::FocusOobeDialog() {
460 client_->FocusOobeDialog();
463 void LoginScreenController::OnAuthenticateComplete(
464 OnAuthenticateCallback callback,
466 LOG(WARNING) << "crbug.com/1339004 : authentication complete";
467 authentication_stage_ = AuthenticationStage::kUserCallback;
468 std::move(callback).Run(absl::make_optional<bool>(success));
469 LOG(WARNING) << "crbug.com/1339004 : triggered callback";
470 authentication_stage_ = AuthenticationStage::kIdle;
472 // During smart card login flow, multiple security token requests can be made.
473 // If the user cancels one, all others should also be canceled.
474 // At this point, the flow is ending and new security token requests are
476 security_token_request_controller_.ResetRequestCanceled();
479 void LoginScreenController::OnShow() {
480 SetSystemTrayVisibility(SystemTrayVisibility::kPrimary);
481 if (authentication_stage_ != AuthenticationStage::kIdle) {
482 AuthenticationStage authentication_stage = authentication_stage_;
483 base::debug::Alias(&authentication_stage);
484 LOG(FATAL) << "Unexpected authentication stage "
485 << static_cast<int>(authentication_stage_);
489 void LoginScreenController::OnFocusLeavingSystemTray(bool reverse) {
493 client_->OnFocusLeavingSystemTray(reverse);
496 void LoginScreenController::OnSystemTrayBubbleShown() {
500 client_->OnSystemTrayBubbleShown();
503 void LoginScreenController::OnLockScreenDestroyed() {
504 // TODO(b/280250064): Make sure allowing this condition won't break
505 // LoginScreenController logic.
506 if (authentication_stage_ != AuthenticationStage::kIdle) {
507 LOG(WARNING) << "Lock screen is destroyed while the authentication stage: "
508 << authentication_stage_;
511 // Still handle it to avoid crashes during Login/Lock/Unlock flows.
512 authentication_stage_ = AuthenticationStage::kIdle;
513 SetSystemTrayVisibility(SystemTrayVisibility::kAll);
516 void LoginScreenController::NotifyLoginScreenShown() {
520 client_->OnLoginScreenShown();
523 std::ostream& operator<<(std::ostream& ostream,
524 LoginScreenController::AuthenticationStage stage) {
526 case LoginScreenController::AuthenticationStage::kIdle:
527 return ostream << "kIdle";
528 case LoginScreenController::AuthenticationStage::kDoAuthenticate:
529 return ostream << "kDoAuthenticate";
530 case LoginScreenController::AuthenticationStage::kUserCallback:
531 return ostream << "kUserCallback";