1 // Copyright 2014 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/chromeos/login/screens/user_selection_screen.h"
7 #include "base/location.h"
8 #include "base/logging.h"
9 #include "base/prefs/pref_service.h"
10 #include "base/values.h"
11 #include "chrome/browser/browser_process.h"
12 #include "chrome/browser/browser_process_platform_part.h"
13 #include "chrome/browser/chromeos/login/lock/screen_locker.h"
14 #include "chrome/browser/chromeos/login/reauth_stats.h"
15 #include "chrome/browser/chromeos/login/ui/login_display_host_impl.h"
16 #include "chrome/browser/chromeos/login/ui/views/user_board_view.h"
17 #include "chrome/browser/chromeos/login/users/chrome_user_manager.h"
18 #include "chrome/browser/chromeos/login/users/multi_profile_user_controller.h"
19 #include "chrome/browser/chromeos/policy/browser_policy_connector_chromeos.h"
20 #include "chrome/browser/chromeos/profiles/profile_helper.h"
21 #include "chrome/browser/signin/easy_unlock_service.h"
22 #include "chrome/browser/ui/webui/chromeos/login/l10n_util.h"
23 #include "chrome/browser/ui/webui/chromeos/login/signin_screen_handler.h"
24 #include "components/proximity_auth/screenlock_bridge.h"
25 #include "components/user_manager/user_id.h"
26 #include "components/user_manager/user_manager.h"
27 #include "components/user_manager/user_type.h"
28 #include "ui/base/user_activity/user_activity_detector.h"
34 // User dictionary keys.
35 const char kKeyUsername
[] = "username";
36 const char kKeyGaiaID
[] = "gaiaId";
37 const char kKeyDisplayName
[] = "displayName";
38 const char kKeyEmailAddress
[] = "emailAddress";
39 const char kKeyEnterpriseDomain
[] = "enterpriseDomain";
40 const char kKeyPublicAccount
[] = "publicAccount";
41 const char kKeyLegacySupervisedUser
[] = "legacySupervisedUser";
42 const char kKeyChildUser
[] = "childUser";
43 const char kKeyDesktopUser
[] = "isDesktopUser";
44 const char kKeySignedIn
[] = "signedIn";
45 const char kKeyCanRemove
[] = "canRemove";
46 const char kKeyIsOwner
[] = "isOwner";
47 const char kKeyInitialAuthType
[] = "initialAuthType";
48 const char kKeyMultiProfilesAllowed
[] = "isMultiProfilesAllowed";
49 const char kKeyMultiProfilesPolicy
[] = "multiProfilesPolicy";
50 const char kKeyInitialLocales
[] = "initialLocales";
51 const char kKeyInitialLocale
[] = "initialLocale";
52 const char kKeyInitialMultipleRecommendedLocales
[] =
53 "initialMultipleRecommendedLocales";
54 const char kKeyInitialKeyboardLayout
[] = "initialKeyboardLayout";
56 // Max number of users to show.
57 // Please keep synced with one in signin_userlist_unittest.cc.
58 const size_t kMaxUsers
= 18;
60 const int kPasswordClearTimeoutSec
= 60;
62 void AddPublicSessionDetailsToUserDictionaryEntry(
63 base::DictionaryValue
* user_dict
,
64 const std::vector
<std::string
>* public_session_recommended_locales
) {
65 policy::BrowserPolicyConnectorChromeOS
* policy_connector
=
66 g_browser_process
->platform_part()->browser_policy_connector_chromeos();
68 if (policy_connector
->IsEnterpriseManaged()) {
69 user_dict
->SetString(kKeyEnterpriseDomain
,
70 policy_connector
->GetEnterpriseDomain());
73 std::vector
<std::string
> kEmptyRecommendedLocales
;
74 const std::vector
<std::string
>& recommended_locales
=
75 public_session_recommended_locales
?
76 *public_session_recommended_locales
: kEmptyRecommendedLocales
;
78 // Construct the list of available locales. This list consists of the
79 // recommended locales, followed by all others.
80 scoped_ptr
<base::ListValue
> available_locales
=
81 GetUILanguageList(&recommended_locales
, std::string());
83 // Select the the first recommended locale that is actually available or the
84 // current UI locale if none of them are available.
85 const std::string selected_locale
= FindMostRelevantLocale(
87 *available_locales
.get(),
88 g_browser_process
->GetApplicationLocale());
90 // Set |kKeyInitialLocales| to the list of available locales.
91 user_dict
->Set(kKeyInitialLocales
, available_locales
.release());
93 // Set |kKeyInitialLocale| to the initially selected locale.
94 user_dict
->SetString(kKeyInitialLocale
, selected_locale
);
96 // Set |kKeyInitialMultipleRecommendedLocales| to indicate whether the list
97 // of recommended locales contains at least two entries. This is used to
98 // decide whether the public session pod expands to its basic form (for zero
99 // or one recommended locales) or the advanced form (two or more recommended
101 user_dict
->SetBoolean(kKeyInitialMultipleRecommendedLocales
,
102 recommended_locales
.size() >= 2);
104 // Set |kKeyInitialKeyboardLayout| to the current keyboard layout. This
105 // value will be used temporarily only because the UI immediately requests a
106 // list of keyboard layouts suitable for the currently selected locale.
107 user_dict
->Set(kKeyInitialKeyboardLayout
,
108 GetCurrentKeyboardLayout().release());
113 UserSelectionScreen::UserSelectionScreen(const std::string
& display_type
)
115 login_display_delegate_(nullptr),
117 display_type_(display_type
),
118 weak_factory_(this) {
121 UserSelectionScreen::~UserSelectionScreen() {
122 proximity_auth::ScreenlockBridge::Get()->SetLockHandler(nullptr);
123 ui::UserActivityDetector
* activity_detector
= ui::UserActivityDetector::Get();
124 if (activity_detector
->HasObserver(this))
125 activity_detector
->RemoveObserver(this);
128 void UserSelectionScreen::InitEasyUnlock() {
129 proximity_auth::ScreenlockBridge::Get()->SetLockHandler(this);
132 void UserSelectionScreen::SetLoginDisplayDelegate(
133 LoginDisplay::Delegate
* login_display_delegate
) {
134 login_display_delegate_
= login_display_delegate
;
138 void UserSelectionScreen::FillUserDictionary(
139 user_manager::User
* user
,
141 bool is_signin_to_add
,
143 const std::vector
<std::string
>* public_session_recommended_locales
,
144 base::DictionaryValue
* user_dict
) {
145 const user_manager::UserID user_id
= user
->email();
146 const bool is_public_session
=
147 user
->GetType() == user_manager::USER_TYPE_PUBLIC_ACCOUNT
;
148 const bool is_legacy_supervised_user
=
149 user
->GetType() == user_manager::USER_TYPE_SUPERVISED
;
150 const bool is_child_user
= user
->GetType() == user_manager::USER_TYPE_CHILD
;
152 user_dict
->SetString(kKeyUsername
, user_id
);
153 user_dict
->SetString(kKeyEmailAddress
, user
->display_email());
154 user_dict
->SetString(kKeyDisplayName
, user
->GetDisplayName());
155 user_dict
->SetBoolean(kKeyPublicAccount
, is_public_session
);
156 user_dict
->SetBoolean(kKeyLegacySupervisedUser
, is_legacy_supervised_user
);
157 user_dict
->SetBoolean(kKeyChildUser
, is_child_user
);
158 user_dict
->SetBoolean(kKeyDesktopUser
, false);
159 user_dict
->SetInteger(kKeyInitialAuthType
, auth_type
);
160 user_dict
->SetBoolean(kKeySignedIn
, user
->is_logged_in());
161 user_dict
->SetBoolean(kKeyIsOwner
, is_owner
);
163 FillMultiProfileUserPrefs(user
, user_dict
, is_signin_to_add
);
164 FillKnownUserPrefs(user
, user_dict
);
166 if (is_public_session
) {
167 AddPublicSessionDetailsToUserDictionaryEntry(
168 user_dict
, public_session_recommended_locales
);
173 void UserSelectionScreen::FillKnownUserPrefs(user_manager::User
* user
,
174 base::DictionaryValue
* user_dict
) {
176 if (user_manager::UserManager::Get()->FindGaiaID(user
->email(), &gaia_id
)) {
177 user_dict
->SetString(kKeyGaiaID
, gaia_id
);
182 void UserSelectionScreen::FillMultiProfileUserPrefs(
183 user_manager::User
* user
,
184 base::DictionaryValue
* user_dict
,
185 bool is_signin_to_add
) {
186 const std::string
& user_id
= user
->email();
188 if (is_signin_to_add
) {
189 MultiProfileUserController
* multi_profile_user_controller
=
190 ChromeUserManager::Get()->GetMultiProfileUserController();
191 MultiProfileUserController::UserAllowedInSessionReason isUserAllowedReason
;
192 bool isUserAllowed
= multi_profile_user_controller
->IsUserAllowedInSession(
193 user_id
, &isUserAllowedReason
);
194 user_dict
->SetBoolean(kKeyMultiProfilesAllowed
, isUserAllowed
);
196 std::string behavior
;
197 switch (isUserAllowedReason
) {
198 case MultiProfileUserController::NOT_ALLOWED_OWNER_AS_SECONDARY
:
199 behavior
= MultiProfileUserController::kBehaviorOwnerPrimaryOnly
;
202 behavior
= multi_profile_user_controller
->GetCachedValue(user_id
);
204 user_dict
->SetString(kKeyMultiProfilesPolicy
, behavior
);
206 user_dict
->SetBoolean(kKeyMultiProfilesAllowed
, true);
211 bool UserSelectionScreen::ShouldForceOnlineSignIn(
212 const user_manager::User
* user
) {
213 // Public sessions are always allowed to log in offline.
214 // Supervised user are allowed to log in offline if their OAuth token status
215 // is unknown or valid.
216 // For all other users, force online sign in if:
217 // * The flag to force online sign-in is set for the user.
218 // * The user's OAuth token is invalid.
219 // * The user's OAuth token status is unknown (except supervised users,
221 if (user
->is_logged_in())
224 const user_manager::User::OAuthTokenStatus token_status
=
225 user
->oauth_token_status();
226 const bool is_supervised_user
=
227 user
->GetType() == user_manager::USER_TYPE_SUPERVISED
;
228 const bool is_public_session
=
229 user
->GetType() == user_manager::USER_TYPE_PUBLIC_ACCOUNT
;
231 if (is_supervised_user
&&
232 token_status
== user_manager::User::OAUTH_TOKEN_STATUS_UNKNOWN
) {
236 if (is_public_session
)
239 // At this point the reason for invalid token should be already set. If not,
240 // this might be a leftover from an old version.
241 if (token_status
== user_manager::User::OAUTH2_TOKEN_STATUS_INVALID
)
242 RecordReauthReason(user
->email(), ReauthReason::OTHER
);
244 return user
->force_online_signin() ||
245 (token_status
== user_manager::User::OAUTH2_TOKEN_STATUS_INVALID
) ||
246 (token_status
== user_manager::User::OAUTH_TOKEN_STATUS_UNKNOWN
);
249 void UserSelectionScreen::SetHandler(LoginDisplayWebUIHandler
* handler
) {
253 void UserSelectionScreen::SetView(UserBoardView
* view
) {
257 void UserSelectionScreen::Init(const user_manager::UserList
& users
,
260 show_guest_
= show_guest
;
262 ui::UserActivityDetector
* activity_detector
= ui::UserActivityDetector::Get();
263 if (!activity_detector
->HasObserver(this))
264 activity_detector
->AddObserver(this);
267 void UserSelectionScreen::OnBeforeUserRemoved(const std::string
& username
) {
268 for (user_manager::UserList::iterator it
= users_
.begin(); it
!= users_
.end();
270 if ((*it
)->email() == username
) {
277 void UserSelectionScreen::OnUserRemoved(const std::string
& username
) {
281 handler_
->OnUserRemoved(username
);
284 void UserSelectionScreen::OnUserImageChanged(const user_manager::User
& user
) {
287 handler_
->OnUserImageChanged(user
);
288 // TODO(antrim) : updateUserImage(user.email())
291 const user_manager::UserList
& UserSelectionScreen::GetUsers() const {
295 void UserSelectionScreen::OnPasswordClearTimerExpired() {
297 handler_
->ClearUserPodPassword();
300 void UserSelectionScreen::OnUserActivity(const ui::Event
* event
) {
301 if (!password_clear_timer_
.IsRunning()) {
302 password_clear_timer_
.Start(
304 base::TimeDelta::FromSeconds(kPasswordClearTimeoutSec
),
306 &UserSelectionScreen::OnPasswordClearTimerExpired
);
308 password_clear_timer_
.Reset();
312 const user_manager::UserList
UserSelectionScreen::PrepareUserListForSending(
313 const user_manager::UserList
& users
,
315 bool is_signin_to_add
) {
316 user_manager::UserList users_to_send
;
317 bool has_owner
= owner
.size() > 0;
318 size_t max_non_owner_users
= has_owner
? kMaxUsers
- 1 : kMaxUsers
;
319 size_t non_owner_count
= 0;
321 for (user_manager::UserList::const_iterator it
= users
.begin();
324 const std::string
& user_id
= (*it
)->email();
325 bool is_owner
= (user_id
== owner
);
326 bool is_public_account
=
327 ((*it
)->GetType() == user_manager::USER_TYPE_PUBLIC_ACCOUNT
);
329 if ((is_public_account
&& !is_signin_to_add
) || is_owner
||
330 (!is_public_account
&& non_owner_count
< max_non_owner_users
)) {
334 if (is_owner
&& users_to_send
.size() > kMaxUsers
) {
335 // Owner is always in the list.
336 users_to_send
.insert(users_to_send
.begin() + (kMaxUsers
- 1), *it
);
337 while (users_to_send
.size() > kMaxUsers
)
338 users_to_send
.erase(users_to_send
.begin() + kMaxUsers
);
339 } else if (users_to_send
.size() < kMaxUsers
) {
340 users_to_send
.push_back(*it
);
344 return users_to_send
;
347 void UserSelectionScreen::SendUserList() {
348 base::ListValue users_list
;
349 const user_manager::UserList
& users
= GetUsers();
351 // TODO(nkostylev): Move to a separate method in UserManager.
352 // http://crbug.com/230852
353 bool single_user
= users
.size() == 1;
354 bool is_signin_to_add
= LoginDisplayHostImpl::default_host() &&
355 user_manager::UserManager::Get()->IsUserLoggedIn();
357 chromeos::CrosSettings::Get()->GetString(chromeos::kDeviceOwner
, &owner
);
359 policy::BrowserPolicyConnectorChromeOS
* connector
=
360 g_browser_process
->platform_part()->browser_policy_connector_chromeos();
361 bool is_enterprise_managed
= connector
->IsEnterpriseManaged();
363 const user_manager::UserList users_to_send
=
364 PrepareUserListForSending(users
, owner
, is_signin_to_add
);
366 user_auth_type_map_
.clear();
368 const std::vector
<std::string
> kEmptyRecommendedLocales
;
369 for (user_manager::UserList::const_iterator it
= users_to_send
.begin();
370 it
!= users_to_send
.end();
372 const std::string
& user_id
= (*it
)->email();
373 bool is_owner
= (user_id
== owner
);
374 const bool is_public_account
=
375 ((*it
)->GetType() == user_manager::USER_TYPE_PUBLIC_ACCOUNT
);
376 const AuthType initial_auth_type
=
377 is_public_account
? EXPAND_THEN_USER_CLICK
378 : (ShouldForceOnlineSignIn(*it
) ? ONLINE_SIGN_IN
380 user_auth_type_map_
[user_id
] = initial_auth_type
;
382 base::DictionaryValue
* user_dict
= new base::DictionaryValue();
383 const std::vector
<std::string
>* public_session_recommended_locales
=
384 public_session_recommended_locales_
.find(user_id
) ==
385 public_session_recommended_locales_
.end() ?
386 &kEmptyRecommendedLocales
:
387 &public_session_recommended_locales_
[user_id
];
388 FillUserDictionary(*it
,
392 public_session_recommended_locales
,
394 bool signed_in
= (*it
)->is_logged_in();
396 // Single user check here is necessary because owner info might not be
397 // available when running into login screen on first boot.
398 // See http://crosbug.com/12723
399 bool can_remove_user
=
400 ((!single_user
|| is_enterprise_managed
) && !user_id
.empty() &&
401 !is_owner
&& !is_public_account
&& !signed_in
&& !is_signin_to_add
);
402 user_dict
->SetBoolean(kKeyCanRemove
, can_remove_user
);
403 users_list
.Append(user_dict
);
406 handler_
->LoadUsers(users_list
, show_guest_
);
409 void UserSelectionScreen::HandleGetUsers() {
413 void UserSelectionScreen::CheckUserStatus(const std::string
& user_id
) {
414 // No checks on lock screen.
415 if (ScreenLocker::default_screen_locker())
418 if (!token_handle_util_
.get()) {
419 token_handle_util_
.reset(
420 new TokenHandleUtil(user_manager::UserManager::Get()));
423 if (token_handle_util_
->HasToken(user_id
)) {
424 token_handle_util_
->CheckToken(
425 user_id
, base::Bind(&UserSelectionScreen::OnUserStatusChecked
,
426 weak_factory_
.GetWeakPtr()));
430 void UserSelectionScreen::OnUserStatusChecked(
431 const user_manager::UserID
& user_id
,
432 TokenHandleUtil::TokenHandleStatus status
) {
433 if (status
== TokenHandleUtil::INVALID
) {
434 RecordReauthReason(user_id
, ReauthReason::INVALID_TOKEN_HANDLE
);
435 token_handle_util_
->MarkHandleInvalid(user_id
);
436 SetAuthType(user_id
, ONLINE_SIGN_IN
, base::string16());
442 void UserSelectionScreen::SetAuthType(const std::string
& user_id
,
444 const base::string16
& initial_value
) {
445 if (GetAuthType(user_id
) == FORCE_OFFLINE_PASSWORD
)
447 DCHECK(GetAuthType(user_id
) != FORCE_OFFLINE_PASSWORD
||
448 auth_type
== FORCE_OFFLINE_PASSWORD
);
449 user_auth_type_map_
[user_id
] = auth_type
;
450 view_
->SetAuthType(user_id
, auth_type
, initial_value
);
453 proximity_auth::ScreenlockBridge::LockHandler::AuthType
454 UserSelectionScreen::GetAuthType(const std::string
& username
) const {
455 if (user_auth_type_map_
.find(username
) == user_auth_type_map_
.end())
456 return OFFLINE_PASSWORD
;
457 return user_auth_type_map_
.find(username
)->second
;
460 proximity_auth::ScreenlockBridge::LockHandler::ScreenType
461 UserSelectionScreen::GetScreenType() const {
462 if (display_type_
== OobeUI::kLockDisplay
)
465 if (display_type_
== OobeUI::kLoginDisplay
)
466 return SIGNIN_SCREEN
;
471 void UserSelectionScreen::ShowBannerMessage(const base::string16
& message
) {
472 view_
->ShowBannerMessage(message
);
475 void UserSelectionScreen::ShowUserPodCustomIcon(
476 const std::string
& user_id
,
477 const proximity_auth::ScreenlockBridge::UserPodCustomIconOptions
&
479 scoped_ptr
<base::DictionaryValue
> icon
= icon_options
.ToDictionaryValue();
480 if (!icon
|| icon
->empty())
482 view_
->ShowUserPodCustomIcon(user_id
, *icon
);
485 void UserSelectionScreen::HideUserPodCustomIcon(const std::string
& user_id
) {
486 view_
->HideUserPodCustomIcon(user_id
);
489 void UserSelectionScreen::EnableInput() {
490 // If Easy Unlock fails to unlock the screen, re-enable the password input.
491 // This is only necessary on the lock screen, because the error handling for
492 // the sign-in screen uses a different code path.
493 if (ScreenLocker::default_screen_locker())
494 ScreenLocker::default_screen_locker()->EnableInput();
497 void UserSelectionScreen::Unlock(const std::string
& user_email
) {
498 DCHECK_EQ(GetScreenType(), LOCK_SCREEN
);
499 ScreenLocker::Hide();
502 void UserSelectionScreen::AttemptEasySignin(const std::string
& user_id
,
503 const std::string
& secret
,
504 const std::string
& key_label
) {
505 DCHECK_EQ(GetScreenType(), SIGNIN_SCREEN
);
507 UserContext
user_context(user_id
);
508 user_context
.SetAuthFlow(UserContext::AUTH_FLOW_EASY_UNLOCK
);
509 user_context
.SetKey(Key(secret
));
510 user_context
.GetKey()->SetLabel(key_label
);
512 login_display_delegate_
->Login(user_context
, SigninSpecifics());
515 void UserSelectionScreen::HardLockPod(const std::string
& user_id
) {
516 view_
->SetAuthType(user_id
, OFFLINE_PASSWORD
, base::string16());
517 EasyUnlockService
* service
= GetEasyUnlockServiceForUser(user_id
);
520 service
->SetHardlockState(EasyUnlockScreenlockStateHandler::USER_HARDLOCK
);
523 void UserSelectionScreen::AttemptEasyUnlock(const std::string
& user_id
) {
524 EasyUnlockService
* service
= GetEasyUnlockServiceForUser(user_id
);
527 service
->AttemptAuth(user_id
);
530 void UserSelectionScreen::RecordClickOnLockIcon(const std::string
& user_id
) {
531 EasyUnlockService
* service
= GetEasyUnlockServiceForUser(user_id
);
534 service
->RecordClickOnLockIcon();
537 EasyUnlockService
* UserSelectionScreen::GetEasyUnlockServiceForUser(
538 const std::string
& user_id
) const {
539 if (GetScreenType() == OTHER_SCREEN
)
542 const user_manager::User
* unlock_user
= nullptr;
543 for (const user_manager::User
* user
: GetUsers()) {
544 if (user
->email() == user_id
) {
552 ProfileHelper
* profile_helper
= ProfileHelper::Get();
553 Profile
* profile
= profile_helper
->GetProfileByUser(unlock_user
);
555 // The user profile should exist if and only if this is the lock screen.
556 DCHECK_EQ(!!profile
, GetScreenType() == LOCK_SCREEN
);
559 profile
= profile_helper
->GetSigninProfile();
561 return EasyUnlockService::Get(profile
);
564 } // namespace chromeos