1 // Copyright 2017 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.
4 
5 #include "ash/login/login_screen_controller.h"
6 
7 #include <utility>
8 
9 #include "ash/focus_cycler.h"
10 #include "ash/login/security_token_request_controller.h"
11 #include "ash/login/ui/lock_screen.h"
12 #include "ash/login/ui/login_data_dispatcher.h"
13 #include "ash/public/cpp/ash_pref_names.h"
14 #include "ash/public/cpp/login_screen_client.h"
15 #include "ash/public/cpp/toast_data.h"
16 #include "ash/root_window_controller.h"
17 #include "ash/session/session_controller_impl.h"
18 #include "ash/shelf/login_shelf_view.h"
19 #include "ash/shelf/shelf.h"
20 #include "ash/shelf/shelf_widget.h"
21 #include "ash/shell.h"
22 #include "ash/system/status_area_widget.h"
23 #include "ash/system/status_area_widget_delegate.h"
24 #include "ash/system/toast/toast_manager_impl.h"
25 #include "ash/system/tray/system_tray_notifier.h"
26 #include "base/bind.h"
27 #include "base/callback.h"
28 #include "base/debug/alias.h"
29 #include "base/strings/string_util.h"
30 #include "base/strings/utf_string_conversions.h"
31 #include "components/prefs/pref_registry_simple.h"
32 #include "components/session_manager/session_manager_types.h"
33 
34 namespace ash {
35 
36 namespace {
37 
38 enum class SystemTrayVisibility {
39   kNone,     // Tray not visible anywhere.
40   kPrimary,  // Tray visible only on primary display.
41   kAll,      // Tray visible on all displays.
42 };
43 
SetSystemTrayVisibility(SystemTrayVisibility visibility)44 void SetSystemTrayVisibility(SystemTrayVisibility visibility) {
45   RootWindowController* primary_window_controller =
46       Shell::GetPrimaryRootWindowController();
47   for (RootWindowController* window_controller :
48        Shell::GetAllRootWindowControllers()) {
49     StatusAreaWidget* status_area = window_controller->GetStatusAreaWidget();
50     if (!status_area)
51       continue;
52     if (window_controller == primary_window_controller) {
53       status_area->SetSystemTrayVisibility(
54           visibility == SystemTrayVisibility::kPrimary ||
55           visibility == SystemTrayVisibility::kAll);
56     } else {
57       status_area->SetSystemTrayVisibility(visibility ==
58                                            SystemTrayVisibility::kAll);
59     }
60   }
61 }
62 
63 }  // namespace
64 
LoginScreenController(SystemTrayNotifier * system_tray_notifier)65 LoginScreenController::LoginScreenController(
66     SystemTrayNotifier* system_tray_notifier)
67     : system_tray_notifier_(system_tray_notifier) {
68   system_tray_notifier_->AddSystemTrayFocusObserver(this);
69 }
70 
~LoginScreenController()71 LoginScreenController::~LoginScreenController() {
72   system_tray_notifier_->RemoveSystemTrayFocusObserver(this);
73 }
74 
75 // static
RegisterProfilePrefs(PrefRegistrySimple * registry,bool for_test)76 void LoginScreenController::RegisterProfilePrefs(PrefRegistrySimple* registry,
77                                                  bool for_test) {
78   if (for_test) {
79     // There is no remote pref service, so pretend that ash owns the pref.
80     registry->RegisterStringPref(prefs::kQuickUnlockPinSalt, "");
81     return;
82   }
83 }
84 
IsAuthenticating() const85 bool LoginScreenController::IsAuthenticating() const {
86   return authentication_stage_ != AuthenticationStage::kIdle;
87 }
88 
AuthenticateUserWithPasswordOrPin(const AccountId & account_id,const std::string & password,bool authenticated_by_pin,OnAuthenticateCallback callback)89 void LoginScreenController::AuthenticateUserWithPasswordOrPin(
90     const AccountId& account_id,
91     const std::string& password,
92     bool authenticated_by_pin,
93     OnAuthenticateCallback callback) {
94   // It is an error to call this function while an authentication is in
95   // progress.
96   LOG_IF(FATAL, IsAuthenticating())
97       << "Duplicate authentication attempt; current authentication stage is "
98       << static_cast<int>(authentication_stage_);
99 
100   if (!client_) {
101     std::move(callback).Run(base::nullopt);
102     return;
103   }
104 
105   // If auth is disabled by the debug overlay bypass the mojo call entirely, as
106   // it will dismiss the lock screen if the password is correct.
107   switch (force_fail_auth_for_debug_overlay_) {
108     case ForceFailAuth::kOff:
109       break;
110     case ForceFailAuth::kImmediate:
111       OnAuthenticateComplete(std::move(callback), false /*success*/);
112       return;
113     case ForceFailAuth::kDelayed:
114       // Set a dummy authentication stage so that |IsAuthenticating| returns
115       // true.
116       authentication_stage_ = AuthenticationStage::kDoAuthenticate;
117       base::ThreadTaskRunnerHandle::Get()->PostDelayedTask(
118           FROM_HERE,
119           base::BindOnce(&LoginScreenController::OnAuthenticateComplete,
120                          weak_factory_.GetWeakPtr(), std::move(callback),
121                          false),
122           base::TimeDelta::FromSeconds(1));
123       return;
124   }
125 
126   authentication_stage_ = AuthenticationStage::kDoAuthenticate;
127 
128   // Checking if the password is only formed of numbers with base::StringToInt
129   // will easily fail due to numeric limits. ContainsOnlyChars is used instead.
130   const bool is_pin =
131       authenticated_by_pin && base::ContainsOnlyChars(password, "0123456789");
132   client_->AuthenticateUserWithPasswordOrPin(
133       account_id, password, is_pin,
134       base::BindOnce(&LoginScreenController::OnAuthenticateComplete,
135                      weak_factory_.GetWeakPtr(), std::move(callback)));
136 }
137 
AuthenticateUserWithEasyUnlock(const AccountId & account_id)138 void LoginScreenController::AuthenticateUserWithEasyUnlock(
139     const AccountId& account_id) {
140   // TODO(jdufault): integrate this into authenticate stage after mojom is
141   // refactored to use a callback.
142   if (!client_)
143     return;
144   client_->AuthenticateUserWithEasyUnlock(account_id);
145 }
146 
AuthenticateUserWithChallengeResponse(const AccountId & account_id,OnAuthenticateCallback callback)147 void LoginScreenController::AuthenticateUserWithChallengeResponse(
148     const AccountId& account_id,
149     OnAuthenticateCallback callback) {
150   LOG_IF(FATAL, IsAuthenticating())
151       << "Duplicate authentication attempt; current authentication stage is "
152       << static_cast<int>(authentication_stage_);
153 
154   if (!client_) {
155     std::move(callback).Run(/*success=*/base::nullopt);
156     return;
157   }
158 
159   authentication_stage_ = AuthenticationStage::kDoAuthenticate;
160   client_->AuthenticateUserWithChallengeResponse(
161       account_id,
162       base::BindOnce(&LoginScreenController::OnAuthenticateComplete,
163                      weak_factory_.GetWeakPtr(), std::move(callback)));
164 }
165 
ValidateParentAccessCode(const AccountId & account_id,base::Time validation_time,const std::string & code)166 bool LoginScreenController::ValidateParentAccessCode(
167     const AccountId& account_id,
168     base::Time validation_time,
169     const std::string& code) {
170   DCHECK(!validation_time.is_null());
171 
172   if (!client_)
173     return false;
174 
175   return client_->ValidateParentAccessCode(account_id, code, validation_time);
176 }
177 
GetSecurityTokenPinRequestCanceled() const178 bool LoginScreenController::GetSecurityTokenPinRequestCanceled() const {
179   return security_token_request_controller_.request_canceled();
180 }
181 
HardlockPod(const AccountId & account_id)182 void LoginScreenController::HardlockPod(const AccountId& account_id) {
183   if (!client_)
184     return;
185   client_->HardlockPod(account_id);
186 }
187 
OnFocusPod(const AccountId & account_id)188 void LoginScreenController::OnFocusPod(const AccountId& account_id) {
189   if (!client_)
190     return;
191   client_->OnFocusPod(account_id);
192 }
193 
OnNoPodFocused()194 void LoginScreenController::OnNoPodFocused() {
195   if (!client_)
196     return;
197   client_->OnNoPodFocused();
198 }
199 
LoadWallpaper(const AccountId & account_id)200 void LoginScreenController::LoadWallpaper(const AccountId& account_id) {
201   if (!client_)
202     return;
203   client_->LoadWallpaper(account_id);
204 }
205 
SignOutUser()206 void LoginScreenController::SignOutUser() {
207   if (!client_)
208     return;
209   client_->SignOutUser();
210 }
211 
CancelAddUser()212 void LoginScreenController::CancelAddUser() {
213   if (!client_)
214     return;
215   client_->CancelAddUser();
216 }
217 
LoginAsGuest()218 void LoginScreenController::LoginAsGuest() {
219   if (!client_)
220     return;
221   client_->LoginAsGuest();
222 }
223 
OnMaxIncorrectPasswordAttempted(const AccountId & account_id)224 void LoginScreenController::OnMaxIncorrectPasswordAttempted(
225     const AccountId& account_id) {
226   if (!client_)
227     return;
228   client_->OnMaxIncorrectPasswordAttempted(account_id);
229 }
230 
FocusLockScreenApps(bool reverse)231 void LoginScreenController::FocusLockScreenApps(bool reverse) {
232   if (!client_)
233     return;
234   client_->FocusLockScreenApps(reverse);
235 }
236 
ShowGaiaSignin(const AccountId & prefilled_account)237 void LoginScreenController::ShowGaiaSignin(const AccountId& prefilled_account) {
238   if (!client_)
239     return;
240   client_->ShowGaiaSignin(prefilled_account);
241 }
242 
OnRemoveUserWarningShown()243 void LoginScreenController::OnRemoveUserWarningShown() {
244   if (!client_)
245     return;
246   client_->OnRemoveUserWarningShown();
247 }
248 
RemoveUser(const AccountId & account_id)249 void LoginScreenController::RemoveUser(const AccountId& account_id) {
250   if (!client_)
251     return;
252   client_->RemoveUser(account_id);
253 }
254 
LaunchPublicSession(const AccountId & account_id,const std::string & locale,const std::string & input_method)255 void LoginScreenController::LaunchPublicSession(
256     const AccountId& account_id,
257     const std::string& locale,
258     const std::string& input_method) {
259   if (!client_)
260     return;
261   client_->LaunchPublicSession(account_id, locale, input_method);
262 }
263 
RequestPublicSessionKeyboardLayouts(const AccountId & account_id,const std::string & locale)264 void LoginScreenController::RequestPublicSessionKeyboardLayouts(
265     const AccountId& account_id,
266     const std::string& locale) {
267   if (!client_)
268     return;
269   client_->RequestPublicSessionKeyboardLayouts(account_id, locale);
270 }
271 
SetClient(LoginScreenClient * client)272 void LoginScreenController::SetClient(LoginScreenClient* client) {
273   client_ = client;
274 }
275 
GetModel()276 LoginScreenModel* LoginScreenController::GetModel() {
277   return &login_data_dispatcher_;
278 }
279 
ShowKioskAppError(const std::string & message)280 void LoginScreenController::ShowKioskAppError(const std::string& message) {
281   ToastData toast_data(
282       "KioskAppError", base::UTF8ToUTF16(message), -1 /*duration_ms*/,
283       base::Optional<base::string16>(base::string16()) /*dismiss_text*/,
284       true /*visible_on_lock_screen*/);
285   Shell::Get()->toast_manager()->Show(toast_data);
286 }
287 
FocusLoginShelf(bool reverse)288 void LoginScreenController::FocusLoginShelf(bool reverse) {
289   Shelf* shelf = Shelf::ForWindow(Shell::Get()->GetPrimaryRootWindow());
290   // Tell the focus direction to the status area or the shelf so they can focus
291   // the correct child view.
292   if (reverse || !shelf->shelf_widget()->login_shelf_view()->IsFocusable()) {
293     if (!Shell::GetPrimaryRootWindowController()->IsSystemTrayVisible())
294       return;
295     shelf->GetStatusAreaWidget()
296         ->status_area_widget_delegate()
297         ->set_default_last_focusable_child(reverse);
298     Shell::Get()->focus_cycler()->FocusWidget(shelf->GetStatusAreaWidget());
299   } else {
300     shelf->shelf_widget()->set_default_last_focusable_child(reverse);
301     Shell::Get()->focus_cycler()->FocusWidget(shelf->shelf_widget());
302   }
303 }
304 
IsReadyForPassword()305 bool LoginScreenController::IsReadyForPassword() {
306   return LockScreen::HasInstance() && !IsAuthenticating();
307 }
308 
EnableAddUserButton(bool enable)309 void LoginScreenController::EnableAddUserButton(bool enable) {
310   Shelf::ForWindow(Shell::Get()->GetPrimaryRootWindow())
311       ->shelf_widget()
312       ->login_shelf_view()
313       ->SetAddUserButtonEnabled(enable);
314 }
315 
EnableShutdownButton(bool enable)316 void LoginScreenController::EnableShutdownButton(bool enable) {
317   Shelf::ForWindow(Shell::Get()->GetPrimaryRootWindow())
318       ->shelf_widget()
319       ->login_shelf_view()
320       ->SetShutdownButtonEnabled(enable);
321 }
322 
SetIsFirstSigninStep(bool is_first)323 void LoginScreenController::SetIsFirstSigninStep(bool is_first) {
324   Shelf::ForWindow(Shell::Get()->GetPrimaryRootWindow())
325       ->shelf_widget()
326       ->login_shelf_view()
327       ->SetIsFirstSigninStep(is_first);
328 }
329 
ShowParentAccessButton(bool show)330 void LoginScreenController::ShowParentAccessButton(bool show) {
331   Shelf::ForWindow(Shell::Get()->GetPrimaryRootWindow())
332       ->shelf_widget()
333       ->login_shelf_view()
334       ->ShowParentAccessButton(show);
335 }
336 
SetAllowLoginAsGuest(bool allow_guest)337 void LoginScreenController::SetAllowLoginAsGuest(bool allow_guest) {
338   Shelf::ForWindow(Shell::Get()->GetPrimaryRootWindow())
339       ->shelf_widget()
340       ->login_shelf_view()
341       ->SetAllowLoginAsGuest(allow_guest);
342 }
343 
344 std::unique_ptr<ScopedGuestButtonBlocker>
GetScopedGuestButtonBlocker()345 LoginScreenController::GetScopedGuestButtonBlocker() {
346   return Shelf::ForWindow(Shell::Get()->GetPrimaryRootWindow())
347       ->shelf_widget()
348       ->login_shelf_view()
349       ->GetScopedGuestButtonBlocker();
350 }
351 
RequestSecurityTokenPin(SecurityTokenPinRequest request)352 void LoginScreenController::RequestSecurityTokenPin(
353     SecurityTokenPinRequest request) {
354   security_token_request_controller_.SetPinUiState(std::move(request));
355 }
356 
ClearSecurityTokenPinRequest()357 void LoginScreenController::ClearSecurityTokenPinRequest() {
358   security_token_request_controller_.ClosePinUi();
359 }
SetLoginShelfGestureHandler(const base::string16 & nudge_text,const base::RepeatingClosure & fling_callback,base::OnceClosure exit_callback)360 bool LoginScreenController::SetLoginShelfGestureHandler(
361     const base::string16& nudge_text,
362     const base::RepeatingClosure& fling_callback,
363     base::OnceClosure exit_callback) {
364   return Shelf::ForWindow(Shell::Get()->GetPrimaryRootWindow())
365       ->shelf_widget()
366       ->SetLoginShelfSwipeHandler(nudge_text, fling_callback,
367                                   std::move(exit_callback));
368 }
369 
ClearLoginShelfGestureHandler()370 void LoginScreenController::ClearLoginShelfGestureHandler() {
371   return Shelf::ForWindow(Shell::Get()->GetPrimaryRootWindow())
372       ->shelf_widget()
373       ->ClearLoginShelfSwipeHandler();
374 }
375 
ShowLockScreen()376 void LoginScreenController::ShowLockScreen() {
377   OnShow();
378   LockScreen::Show(LockScreen::ScreenType::kLock);
379 }
380 
ShowLoginScreen()381 void LoginScreenController::ShowLoginScreen() {
382   // Login screen can only be used during login.
383   session_manager::SessionState session_state =
384       Shell::Get()->session_controller()->GetSessionState();
385   CHECK(session_state == session_manager::SessionState::LOGIN_PRIMARY ||
386         session_state == session_manager::SessionState::LOGIN_SECONDARY)
387       << "Not showing login screen since session state is "
388       << static_cast<int>(session_state);
389 
390   OnShow();
391   // TODO(jdufault): rename LockScreen to LoginScreen.
392   LockScreen::Show(LockScreen::ScreenType::kLogin);
393 }
394 
SetKioskApps(const std::vector<KioskAppMenuEntry> & kiosk_apps,const base::RepeatingCallback<void (const KioskAppMenuEntry &)> & launch_app,const base::RepeatingClosure & on_show_menu)395 void LoginScreenController::SetKioskApps(
396     const std::vector<KioskAppMenuEntry>& kiosk_apps,
397     const base::RepeatingCallback<void(const KioskAppMenuEntry&)>& launch_app,
398     const base::RepeatingClosure& on_show_menu) {
399   Shelf::ForWindow(Shell::Get()->GetPrimaryRootWindow())
400       ->shelf_widget()
401       ->login_shelf_view()
402       ->SetKioskApps(kiosk_apps, launch_app, on_show_menu);
403 }
404 
HandleAccelerator(ash::LoginAcceleratorAction action)405 void LoginScreenController::HandleAccelerator(
406     ash::LoginAcceleratorAction action) {
407   if (!client_)
408     return;
409   client_->HandleAccelerator(action);
410 }
411 
ShowAccountAccessHelpApp(gfx::NativeWindow parent_window)412 void LoginScreenController::ShowAccountAccessHelpApp(
413     gfx::NativeWindow parent_window) {
414   client_->ShowAccountAccessHelpApp(parent_window);
415 }
416 
ShowParentAccessHelpApp(gfx::NativeWindow parent_window)417 void LoginScreenController::ShowParentAccessHelpApp(
418     gfx::NativeWindow parent_window) {
419   client_->ShowParentAccessHelpApp(parent_window);
420 }
421 
ShowLockScreenNotificationSettings()422 void LoginScreenController::ShowLockScreenNotificationSettings() {
423   client_->ShowLockScreenNotificationSettings();
424 }
425 
FocusOobeDialog()426 void LoginScreenController::FocusOobeDialog() {
427   if (!client_)
428     return;
429   client_->FocusOobeDialog();
430 }
431 
NotifyUserActivity()432 void LoginScreenController::NotifyUserActivity() {
433   if (!client_)
434     return;
435   client_->OnUserActivity();
436 }
437 
OnAuthenticateComplete(OnAuthenticateCallback callback,bool success)438 void LoginScreenController::OnAuthenticateComplete(
439     OnAuthenticateCallback callback,
440     bool success) {
441   authentication_stage_ = AuthenticationStage::kUserCallback;
442   std::move(callback).Run(base::make_optional<bool>(success));
443   authentication_stage_ = AuthenticationStage::kIdle;
444 
445   // During smart card login flow, multiple security token requests can be made.
446   // If the user cancels one, all others should also be canceled.
447   // At this point, the flow is ending and new security token requests are
448   // displayed again.
449   security_token_request_controller_.ResetRequestCanceled();
450 }
451 
OnShow()452 void LoginScreenController::OnShow() {
453   SetSystemTrayVisibility(SystemTrayVisibility::kPrimary);
454   if (authentication_stage_ != AuthenticationStage::kIdle) {
455     AuthenticationStage authentication_stage = authentication_stage_;
456     base::debug::Alias(&authentication_stage);
457     LOG(FATAL) << "Unexpected authentication stage "
458                << static_cast<int>(authentication_stage_);
459   }
460 }
461 
OnFocusLeavingSystemTray(bool reverse)462 void LoginScreenController::OnFocusLeavingSystemTray(bool reverse) {
463   if (!client_)
464     return;
465   client_->OnFocusLeavingSystemTray(reverse);
466 }
467 
NotifyLoginScreenShown()468 void LoginScreenController::NotifyLoginScreenShown() {
469   if (!client_)
470     return;
471   client_->OnLoginScreenShown();
472 }
473 
474 }  // namespace ash
475