Revert "[M120 Migration]Fix for crash during chrome exit"
[platform/framework/web/chromium-efl.git] / ash / login / login_screen_controller.cc
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.
4
5 #include "ash/login/login_screen_controller.h"
6
7 #include <utility>
8
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"
39
40 namespace ash {
41
42 namespace {
43
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.
48 };
49
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();
56     if (!status_area) {
57       continue;
58     }
59     if (window_controller == primary_window_controller) {
60       status_area->SetSystemTrayVisibility(
61           visibility == SystemTrayVisibility::kPrimary ||
62           visibility == SystemTrayVisibility::kAll);
63     } else {
64       status_area->SetSystemTrayVisibility(visibility ==
65                                            SystemTrayVisibility::kAll);
66     }
67   }
68 }
69
70 }  // namespace
71
72 LoginScreenController::LoginScreenController(
73     SystemTrayNotifier* system_tray_notifier)
74     : system_tray_notifier_(system_tray_notifier) {
75   system_tray_notifier_->AddSystemTrayObserver(this);
76 }
77
78 LoginScreenController::~LoginScreenController() {
79   system_tray_notifier_->RemoveSystemTrayObserver(this);
80 }
81
82 // static
83 void LoginScreenController::RegisterProfilePrefs(PrefRegistrySimple* registry,
84                                                  bool for_test) {
85   if (for_test) {
86     // There is no remote pref service, so pretend that ash owns the pref.
87     registry->RegisterStringPref(prefs::kQuickUnlockPinSalt, "");
88     return;
89   }
90 }
91
92 bool LoginScreenController::IsAuthenticating() const {
93   return authentication_stage_ != AuthenticationStage::kIdle;
94 }
95
96 bool LoginScreenController::IsAuthenticationCallbackExecuting() const {
97   return authentication_stage_ == AuthenticationStage::kUserCallback;
98 }
99
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
106   // progress.
107   LOG_IF(FATAL, IsAuthenticating())
108       << "Duplicate authentication attempt; current authentication stage is "
109       << static_cast<int>(authentication_stage_);
110
111   if (!client_) {
112     std::move(callback).Run(absl::nullopt);
113     return;
114   }
115
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:
120       break;
121     case ForceFailAuth::kImmediate:
122       OnAuthenticateComplete(std::move(callback), false /*success*/);
123       return;
124     case ForceFailAuth::kDelayed:
125       // Set a dummy authentication stage so that |IsAuthenticating| returns
126       // true.
127       LOG(WARNING) << "crbug.com/1339004 : Dummy auth state";
128       authentication_stage_ = AuthenticationStage::kDoAuthenticate;
129       base::SingleThreadTaskRunner::GetCurrentDefault()->PostDelayedTask(
130           FROM_HERE,
131           base::BindOnce(&LoginScreenController::OnAuthenticateComplete,
132                          weak_factory_.GetWeakPtr(), std::move(callback),
133                          false),
134           base::Seconds(1));
135       return;
136   }
137
138   LOG(WARNING) << "crbug.com/1339004 : started authentication";
139   authentication_stage_ = AuthenticationStage::kDoAuthenticate;
140
141   if (authenticated_by_pin) {
142     DCHECK(base::ContainsOnlyChars(password, "0123456789"));
143   }
144
145   client_->AuthenticateUserWithPasswordOrPin(
146       account_id, password, authenticated_by_pin,
147       base::BindOnce(&LoginScreenController::OnAuthenticateComplete,
148                      weak_factory_.GetWeakPtr(), std::move(callback)));
149 }
150
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.
155   if (!client_) {
156     return;
157   }
158   client_->AuthenticateUserWithEasyUnlock(account_id);
159 }
160
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_);
167
168   if (!client_) {
169     std::move(callback).Run(/*success=*/absl::nullopt);
170     return;
171   }
172
173   authentication_stage_ = AuthenticationStage::kDoAuthenticate;
174   client_->AuthenticateUserWithChallengeResponse(
175       account_id,
176       base::BindOnce(&LoginScreenController::OnAuthenticateComplete,
177                      weak_factory_.GetWeakPtr(), std::move(callback)));
178 }
179
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());
185
186   if (!client_) {
187     return ParentCodeValidationResult::kInternalError;
188   }
189
190   return client_->ValidateParentAccessCode(account_id, code, validation_time);
191 }
192
193 bool LoginScreenController::GetSecurityTokenPinRequestCanceled() const {
194   return security_token_request_controller_.request_canceled();
195 }
196
197 void LoginScreenController::OnFocusPod(const AccountId& account_id) {
198   GetModel()->NotifyFocusPod(account_id);
199   if (!client_) {
200     return;
201   }
202   client_->OnFocusPod(account_id);
203 }
204
205 void LoginScreenController::CancelAddUser() {
206   if (!client_) {
207     return;
208   }
209   client_->CancelAddUser();
210 }
211
212 void LoginScreenController::ShowGuestTosScreen() {
213   if (!client_) {
214     return;
215   }
216   client_->ShowGuestTosScreen();
217 }
218
219 void LoginScreenController::OnMaxIncorrectPasswordAttempted(
220     const AccountId& account_id) {
221   if (!client_) {
222     return;
223   }
224   client_->OnMaxIncorrectPasswordAttempted(account_id);
225 }
226
227 void LoginScreenController::FocusLockScreenApps(bool reverse) {
228   if (!client_) {
229     return;
230   }
231   client_->FocusLockScreenApps(reverse);
232 }
233
234 void LoginScreenController::ShowGaiaSignin(const AccountId& prefilled_account) {
235   if (!client_) {
236     return;
237   }
238   client_->ShowGaiaSignin(prefilled_account);
239 }
240
241 void LoginScreenController::ShowOsInstallScreen() {
242   if (!client_) {
243     return;
244   }
245   client_->ShowOsInstallScreen();
246 }
247
248 void LoginScreenController::OnRemoveUserWarningShown() {
249   if (!client_) {
250     return;
251   }
252   client_->OnRemoveUserWarningShown();
253 }
254
255 void LoginScreenController::RemoveUser(const AccountId& account_id) {
256   if (!client_) {
257     return;
258   }
259   client_->RemoveUser(account_id);
260 }
261
262 void LoginScreenController::LaunchPublicSession(
263     const AccountId& account_id,
264     const std::string& locale,
265     const std::string& input_method) {
266   if (!client_) {
267     return;
268   }
269   client_->LaunchPublicSession(account_id, locale, input_method);
270 }
271
272 void LoginScreenController::RequestPublicSessionKeyboardLayouts(
273     const AccountId& account_id,
274     const std::string& locale) {
275   if (!client_) {
276     return;
277   }
278   client_->RequestPublicSessionKeyboardLayouts(account_id, locale);
279 }
280
281 void LoginScreenController::SetClient(LoginScreenClient* client) {
282   client_ = client;
283 }
284
285 LoginScreenModel* LoginScreenController::GetModel() {
286   return &login_data_dispatcher_;
287 }
288
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));
295 }
296
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);
316     } else {
317       shelf->shelf_widget()->set_default_last_focusable_child(reverse);
318       Shell::Get()->focus_cycler()->FocusWidget(shelf->shelf_widget());
319     }
320   } else {
321     // No elements to focus on the shelf.
322     //
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();
327   }
328 }
329
330 bool LoginScreenController::IsReadyForPassword() {
331   return LockScreen::HasInstance() && !IsAuthenticating();
332 }
333
334 void LoginScreenController::EnableAddUserButton(bool enable) {
335   Shelf::ForWindow(Shell::Get()->GetPrimaryRootWindow())
336       ->shelf_widget()
337       ->GetLoginShelfView()
338       ->SetAddUserButtonEnabled(enable);
339 }
340
341 void LoginScreenController::EnableShutdownButton(bool enable) {
342   Shelf::ForWindow(Shell::Get()->GetPrimaryRootWindow())
343       ->shelf_widget()
344       ->GetLoginShelfView()
345       ->SetShutdownButtonEnabled(enable);
346 }
347
348 void LoginScreenController::EnableShelfButtons(bool enable) {
349   Shelf::ForWindow(Shell::Get()->GetPrimaryRootWindow())
350       ->shelf_widget()
351       ->GetLoginShelfView()
352       ->SetButtonEnabled(enable);
353 }
354
355 void LoginScreenController::SetIsFirstSigninStep(bool is_first) {
356   Shelf::ForWindow(Shell::Get()->GetPrimaryRootWindow())
357       ->shelf_widget()
358       ->GetLoginShelfView()
359       ->SetIsFirstSigninStep(is_first);
360 }
361
362 void LoginScreenController::ShowParentAccessButton(bool show) {
363   Shelf::ForWindow(Shell::Get()->GetPrimaryRootWindow())
364       ->shelf_widget()
365       ->GetLoginShelfView()
366       ->ShowParentAccessButton(show);
367 }
368
369 void LoginScreenController::SetAllowLoginAsGuest(bool allow_guest) {
370   Shelf::ForWindow(Shell::Get()->GetPrimaryRootWindow())
371       ->shelf_widget()
372       ->GetLoginShelfView()
373       ->SetAllowLoginAsGuest(allow_guest);
374 }
375
376 std::unique_ptr<ScopedGuestButtonBlocker>
377 LoginScreenController::GetScopedGuestButtonBlocker() {
378   return Shelf::ForWindow(Shell::Get()->GetPrimaryRootWindow())
379       ->shelf_widget()
380       ->GetLoginShelfView()
381       ->GetScopedGuestButtonBlocker();
382 }
383
384 void LoginScreenController::RequestSecurityTokenPin(
385     SecurityTokenPinRequest request) {
386   security_token_request_controller_.SetPinUiState(std::move(request));
387 }
388
389 void LoginScreenController::ClearSecurityTokenPinRequest() {
390   security_token_request_controller_.ClosePinUi();
391 }
392
393 views::Widget* LoginScreenController::GetLoginWindowWidget() {
394   return client_ ? client_->GetLoginWindowWidget() : nullptr;
395 }
396
397 void LoginScreenController::ShowLockScreen() {
398   CHECK(!LockScreen::HasInstance());
399   OnShow();
400   LockScreen::Show(LockScreen::ScreenType::kLock);
401 }
402
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);
412
413   OnShow();
414   // TODO(jdufault): rename LockScreen to LoginScreen.
415   LockScreen::Show(LockScreen::ScreenType::kLogin);
416 }
417
418 void LoginScreenController::SetKioskApps(
419     const std::vector<KioskAppMenuEntry>& kiosk_apps) {
420   Shelf::ForWindow(Shell::Get()->GetPrimaryRootWindow())
421       ->shelf_widget()
422       ->GetLoginShelfView()
423       ->SetKioskApps(kiosk_apps);
424 }
425
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())
430       ->shelf_widget()
431       ->GetLoginShelfView()
432       ->ConfigureKioskCallbacks(launch_app, on_show_menu);
433 }
434
435 void LoginScreenController::HandleAccelerator(
436     ash::LoginAcceleratorAction action) {
437   if (!client_) {
438     return;
439   }
440   client_->HandleAccelerator(action);
441 }
442
443 void LoginScreenController::ShowAccountAccessHelpApp(
444     gfx::NativeWindow parent_window) {
445   client_->ShowAccountAccessHelpApp(parent_window);
446 }
447
448 void LoginScreenController::ShowParentAccessHelpApp() {
449   client_->ShowParentAccessHelpApp();
450 }
451
452 void LoginScreenController::ShowLockScreenNotificationSettings() {
453   client_->ShowLockScreenNotificationSettings();
454 }
455
456 void LoginScreenController::FocusOobeDialog() {
457   if (!client_) {
458     return;
459   }
460   client_->FocusOobeDialog();
461 }
462
463 void LoginScreenController::OnAuthenticateComplete(
464     OnAuthenticateCallback callback,
465     bool success) {
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;
471
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
475   // displayed again.
476   security_token_request_controller_.ResetRequestCanceled();
477 }
478
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_);
486   }
487 }
488
489 void LoginScreenController::OnFocusLeavingSystemTray(bool reverse) {
490   if (!client_) {
491     return;
492   }
493   client_->OnFocusLeavingSystemTray(reverse);
494 }
495
496 void LoginScreenController::OnSystemTrayBubbleShown() {
497   if (!client_) {
498     return;
499   }
500   client_->OnSystemTrayBubbleShown();
501 }
502
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_;
509   }
510
511   // Still handle it to avoid crashes during Login/Lock/Unlock flows.
512   authentication_stage_ = AuthenticationStage::kIdle;
513   SetSystemTrayVisibility(SystemTrayVisibility::kAll);
514 }
515
516 void LoginScreenController::NotifyLoginScreenShown() {
517   if (!client_) {
518     return;
519   }
520   client_->OnLoginScreenShown();
521 }
522
523 std::ostream& operator<<(std::ostream& ostream,
524                          LoginScreenController::AuthenticationStage stage) {
525   switch (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";
532   }
533 }
534
535 }  // namespace ash