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. 4 5#include "chrome/browser/chromeos/login/screens/user_selection_screen.h" 6 7#include "ash/shell.h" 8#include "base/location.h" 9#include "base/logging.h" 10#include "base/prefs/pref_service.h" 11#include "base/values.h" 12#include "chrome/browser/browser_process.h" 13#include "chrome/browser/browser_process_platform_part.h" 14#include "chrome/browser/chromeos/login/ui/login_display_host_impl.h" 15#include "chrome/browser/chromeos/login/users/chrome_user_manager.h" 16#include "chrome/browser/chromeos/login/users/multi_profile_user_controller.h" 17#include "chrome/browser/chromeos/policy/browser_policy_connector_chromeos.h" 18#include "chrome/browser/signin/screenlock_bridge.h" 19#include "chrome/browser/ui/webui/chromeos/login/l10n_util.h" 20#include "chrome/browser/ui/webui/chromeos/login/signin_screen_handler.h" 21#include "chrome/common/pref_names.h" 22#include "components/user_manager/user_manager.h" 23#include "components/user_manager/user_type.h" 24#include "ui/wm/core/user_activity_detector.h" 25 26namespace chromeos { 27 28namespace { 29 30// User dictionary keys. 31const char kKeyUsername[] = "username"; 32const char kKeyDisplayName[] = "displayName"; 33const char kKeyEmailAddress[] = "emailAddress"; 34const char kKeyEnterpriseDomain[] = "enterpriseDomain"; 35const char kKeyPublicAccount[] = "publicAccount"; 36const char kKeySupervisedUser[] = "supervisedUser"; 37const char kKeySignedIn[] = "signedIn"; 38const char kKeyCanRemove[] = "canRemove"; 39const char kKeyIsOwner[] = "isOwner"; 40const char kKeyInitialAuthType[] = "initialAuthType"; 41const char kKeyMultiProfilesAllowed[] = "isMultiProfilesAllowed"; 42const char kKeyMultiProfilesPolicy[] = "multiProfilesPolicy"; 43const char kKeyInitialLocales[] = "initialLocales"; 44const char kKeyInitialLocale[] = "initialLocale"; 45const char kKeyInitialMultipleRecommendedLocales[] = 46 "initialMultipleRecommendedLocales"; 47const char kKeyInitialKeyboardLayout[] = "initialKeyboardLayout"; 48 49// Max number of users to show. 50// Please keep synced with one in signin_userlist_unittest.cc. 51const size_t kMaxUsers = 18; 52 53const int kPasswordClearTimeoutSec = 60; 54 55void AddPublicSessionDetailsToUserDictionaryEntry( 56 base::DictionaryValue* user_dict, 57 const std::vector<std::string>* public_session_recommended_locales) { 58 policy::BrowserPolicyConnectorChromeOS* policy_connector = 59 g_browser_process->platform_part()->browser_policy_connector_chromeos(); 60 61 if (policy_connector->IsEnterpriseManaged()) { 62 user_dict->SetString(kKeyEnterpriseDomain, 63 policy_connector->GetEnterpriseDomain()); 64 } 65 66 std::vector<std::string> kEmptyRecommendedLocales; 67 const std::vector<std::string>& recommended_locales = 68 public_session_recommended_locales ? 69 *public_session_recommended_locales : kEmptyRecommendedLocales; 70 71 // Construct the list of available locales. This list consists of the 72 // recommended locales, followed by all others. 73 scoped_ptr<base::ListValue> available_locales = 74 GetUILanguageList(&recommended_locales, std::string()); 75 76 // Select the the first recommended locale that is actually available or the 77 // current UI locale if none of them are available. 78 const std::string selected_locale = FindMostRelevantLocale( 79 recommended_locales, 80 *available_locales.get(), 81 g_browser_process->GetApplicationLocale()); 82 83 // Set |kKeyInitialLocales| to the list of available locales. 84 user_dict->Set(kKeyInitialLocales, available_locales.release()); 85 86 // Set |kKeyInitialLocale| to the initially selected locale. 87 user_dict->SetString(kKeyInitialLocale, selected_locale); 88 89 // Set |kKeyInitialMultipleRecommendedLocales| to indicate whether the list 90 // of recommended locales contains at least two entries. This is used to 91 // decide whether the public session pod expands to its basic form (for zero 92 // or one recommended locales) or the advanced form (two or more recommended 93 // locales). 94 user_dict->SetBoolean(kKeyInitialMultipleRecommendedLocales, 95 recommended_locales.size() >= 2); 96 97 // Set |kKeyInitialKeyboardLayout| to the current keyboard layout. This 98 // value will be used temporarily only because the UI immediately requests a 99 // list of keyboard layouts suitable for the currently selected locale. 100 user_dict->Set(kKeyInitialKeyboardLayout, 101 GetCurrentKeyboardLayout().release()); 102} 103 104} // namespace 105 106UserSelectionScreen::UserSelectionScreen() : handler_(NULL) { 107} 108 109UserSelectionScreen::~UserSelectionScreen() { 110#if !defined(USE_ATHENA) 111 // TODO(dpolukhin): crbug.com/408752 112 wm::UserActivityDetector* activity_detector = 113 ash::Shell::GetInstance()->user_activity_detector(); 114 if (activity_detector->HasObserver(this)) 115 activity_detector->RemoveObserver(this); 116#endif 117} 118 119// static 120void UserSelectionScreen::FillUserDictionary( 121 user_manager::User* user, 122 bool is_owner, 123 bool is_signin_to_add, 124 ScreenlockBridge::LockHandler::AuthType auth_type, 125 const std::vector<std::string>* public_session_recommended_locales, 126 base::DictionaryValue* user_dict) { 127 const std::string& user_id = user->email(); 128 const bool is_public_session = 129 user->GetType() == user_manager::USER_TYPE_PUBLIC_ACCOUNT; 130 const bool is_supervised_user = 131 user->GetType() == user_manager::USER_TYPE_SUPERVISED; 132 133 user_dict->SetString(kKeyUsername, user_id); 134 user_dict->SetString(kKeyEmailAddress, user->display_email()); 135 user_dict->SetString(kKeyDisplayName, user->GetDisplayName()); 136 user_dict->SetBoolean(kKeyPublicAccount, is_public_session); 137 user_dict->SetBoolean(kKeySupervisedUser, is_supervised_user); 138 user_dict->SetInteger(kKeyInitialAuthType, auth_type); 139 user_dict->SetBoolean(kKeySignedIn, user->is_logged_in()); 140 user_dict->SetBoolean(kKeyIsOwner, is_owner); 141 142 // Fill in multi-profiles related fields. 143 if (is_signin_to_add) { 144 MultiProfileUserController* multi_profile_user_controller = 145 ChromeUserManager::Get()->GetMultiProfileUserController(); 146 MultiProfileUserController::UserAllowedInSessionReason isUserAllowedReason; 147 bool isUserAllowed = multi_profile_user_controller->IsUserAllowedInSession( 148 user_id, &isUserAllowedReason); 149 user_dict->SetBoolean(kKeyMultiProfilesAllowed, isUserAllowed); 150 151 std::string behavior; 152 switch (isUserAllowedReason) { 153 case MultiProfileUserController::NOT_ALLOWED_OWNER_AS_SECONDARY: 154 behavior = MultiProfileUserController::kBehaviorOwnerPrimaryOnly; 155 break; 156 default: 157 behavior = multi_profile_user_controller->GetCachedValue(user_id); 158 } 159 user_dict->SetString(kKeyMultiProfilesPolicy, behavior); 160 } else { 161 user_dict->SetBoolean(kKeyMultiProfilesAllowed, true); 162 } 163 164 if (is_public_session) { 165 AddPublicSessionDetailsToUserDictionaryEntry( 166 user_dict, 167 public_session_recommended_locales); 168 } 169} 170 171// static 172bool UserSelectionScreen::ShouldForceOnlineSignIn( 173 const user_manager::User* user) { 174 // Public sessions are always allowed to log in offline. 175 // Supervised user are allowed to log in offline if their OAuth token status 176 // is unknown or valid. 177 // For all other users, force online sign in if: 178 // * The flag to force online sign-in is set for the user. 179 // * The user's OAuth token is invalid. 180 // * The user's OAuth token status is unknown (except supervised users, 181 // see above). 182 if (user->is_logged_in()) 183 return false; 184 185 const user_manager::User::OAuthTokenStatus token_status = 186 user->oauth_token_status(); 187 const bool is_supervised_user = 188 user->GetType() == user_manager::USER_TYPE_SUPERVISED; 189 const bool is_public_session = 190 user->GetType() == user_manager::USER_TYPE_PUBLIC_ACCOUNT; 191 192 if (is_supervised_user && 193 token_status == user_manager::User::OAUTH_TOKEN_STATUS_UNKNOWN) { 194 return false; 195 } 196 197 if (is_public_session) 198 return false; 199 200 return user->force_online_signin() || 201 (token_status == user_manager::User::OAUTH2_TOKEN_STATUS_INVALID) || 202 (token_status == user_manager::User::OAUTH_TOKEN_STATUS_UNKNOWN); 203} 204 205void UserSelectionScreen::SetHandler(LoginDisplayWebUIHandler* handler) { 206 handler_ = handler; 207} 208 209void UserSelectionScreen::Init(const user_manager::UserList& users, 210 bool show_guest) { 211 users_ = users; 212 show_guest_ = show_guest; 213 214#if !defined(USE_ATHENA) 215 // TODO(dpolukhin): crbug.com/408752 216 wm::UserActivityDetector* activity_detector = 217 ash::Shell::GetInstance()->user_activity_detector(); 218 if (!activity_detector->HasObserver(this)) 219 activity_detector->AddObserver(this); 220#endif 221} 222 223void UserSelectionScreen::OnBeforeUserRemoved(const std::string& username) { 224 for (user_manager::UserList::iterator it = users_.begin(); it != users_.end(); 225 ++it) { 226 if ((*it)->email() == username) { 227 users_.erase(it); 228 break; 229 } 230 } 231} 232 233void UserSelectionScreen::OnUserRemoved(const std::string& username) { 234 if (!handler_) 235 return; 236 237 handler_->OnUserRemoved(username); 238} 239 240void UserSelectionScreen::OnUserImageChanged(const user_manager::User& user) { 241 if (!handler_) 242 return; 243 handler_->OnUserImageChanged(user); 244 // TODO(antrim) : updateUserImage(user.email()) 245} 246 247const user_manager::UserList& UserSelectionScreen::GetUsers() const { 248 return users_; 249} 250 251void UserSelectionScreen::OnPasswordClearTimerExpired() { 252 if (handler_) 253 handler_->ClearUserPodPassword(); 254} 255 256void UserSelectionScreen::OnUserActivity(const ui::Event* event) { 257 if (!password_clear_timer_.IsRunning()) { 258 password_clear_timer_.Start( 259 FROM_HERE, 260 base::TimeDelta::FromSeconds(kPasswordClearTimeoutSec), 261 this, 262 &UserSelectionScreen::OnPasswordClearTimerExpired); 263 } 264 password_clear_timer_.Reset(); 265} 266 267// static 268const user_manager::UserList UserSelectionScreen::PrepareUserListForSending( 269 const user_manager::UserList& users, 270 std::string owner, 271 bool is_signin_to_add) { 272 user_manager::UserList users_to_send; 273 bool has_owner = owner.size() > 0; 274 size_t max_non_owner_users = has_owner ? kMaxUsers - 1 : kMaxUsers; 275 size_t non_owner_count = 0; 276 277 for (user_manager::UserList::const_iterator it = users.begin(); 278 it != users.end(); 279 ++it) { 280 const std::string& user_id = (*it)->email(); 281 bool is_owner = (user_id == owner); 282 bool is_public_account = 283 ((*it)->GetType() == user_manager::USER_TYPE_PUBLIC_ACCOUNT); 284 285 if ((is_public_account && !is_signin_to_add) || is_owner || 286 (!is_public_account && non_owner_count < max_non_owner_users)) { 287 288 if (!is_owner) 289 ++non_owner_count; 290 if (is_owner && users_to_send.size() > kMaxUsers) { 291 // Owner is always in the list. 292 users_to_send.insert(users_to_send.begin() + (kMaxUsers - 1), *it); 293 while (users_to_send.size() > kMaxUsers) 294 users_to_send.erase(users_to_send.begin() + kMaxUsers); 295 } else if (users_to_send.size() < kMaxUsers) { 296 users_to_send.push_back(*it); 297 } 298 } 299 } 300 return users_to_send; 301} 302 303void UserSelectionScreen::SendUserList() { 304 base::ListValue users_list; 305 const user_manager::UserList& users = GetUsers(); 306 307 // TODO(nkostylev): Move to a separate method in UserManager. 308 // http://crbug.com/230852 309 bool single_user = users.size() == 1; 310 bool is_signin_to_add = LoginDisplayHostImpl::default_host() && 311 user_manager::UserManager::Get()->IsUserLoggedIn(); 312 std::string owner; 313 chromeos::CrosSettings::Get()->GetString(chromeos::kDeviceOwner, &owner); 314 315 policy::BrowserPolicyConnectorChromeOS* connector = 316 g_browser_process->platform_part()->browser_policy_connector_chromeos(); 317 bool is_enterprise_managed = connector->IsEnterpriseManaged(); 318 319 const user_manager::UserList users_to_send = 320 PrepareUserListForSending(users, owner, is_signin_to_add); 321 322 user_auth_type_map_.clear(); 323 324 const std::vector<std::string> kEmptyRecommendedLocales; 325 for (user_manager::UserList::const_iterator it = users_to_send.begin(); 326 it != users_to_send.end(); 327 ++it) { 328 const std::string& user_id = (*it)->email(); 329 bool is_owner = (user_id == owner); 330 const bool is_public_account = 331 ((*it)->GetType() == user_manager::USER_TYPE_PUBLIC_ACCOUNT); 332 const ScreenlockBridge::LockHandler::AuthType initial_auth_type = 333 is_public_account 334 ? ScreenlockBridge::LockHandler::EXPAND_THEN_USER_CLICK 335 : (ShouldForceOnlineSignIn(*it) 336 ? ScreenlockBridge::LockHandler::ONLINE_SIGN_IN 337 : ScreenlockBridge::LockHandler::OFFLINE_PASSWORD); 338 user_auth_type_map_[user_id] = initial_auth_type; 339 340 base::DictionaryValue* user_dict = new base::DictionaryValue(); 341 const std::vector<std::string>* public_session_recommended_locales = 342 public_session_recommended_locales_.find(user_id) == 343 public_session_recommended_locales_.end() ? 344 &kEmptyRecommendedLocales : 345 &public_session_recommended_locales_[user_id]; 346 FillUserDictionary(*it, 347 is_owner, 348 is_signin_to_add, 349 initial_auth_type, 350 public_session_recommended_locales, 351 user_dict); 352 bool signed_in = (*it)->is_logged_in(); 353 // Single user check here is necessary because owner info might not be 354 // available when running into login screen on first boot. 355 // See http://crosbug.com/12723 356 bool can_remove_user = 357 ((!single_user || is_enterprise_managed) && !user_id.empty() && 358 !is_owner && !is_public_account && !signed_in && !is_signin_to_add); 359 user_dict->SetBoolean(kKeyCanRemove, can_remove_user); 360 users_list.Append(user_dict); 361 } 362 363 handler_->LoadUsers(users_list, show_guest_); 364} 365 366void UserSelectionScreen::HandleGetUsers() { 367 SendUserList(); 368} 369 370void UserSelectionScreen::SetAuthType( 371 const std::string& username, 372 ScreenlockBridge::LockHandler::AuthType auth_type) { 373 DCHECK(GetAuthType(username) != 374 ScreenlockBridge::LockHandler::FORCE_OFFLINE_PASSWORD || 375 auth_type == ScreenlockBridge::LockHandler::FORCE_OFFLINE_PASSWORD); 376 user_auth_type_map_[username] = auth_type; 377} 378 379ScreenlockBridge::LockHandler::AuthType UserSelectionScreen::GetAuthType( 380 const std::string& username) const { 381 if (user_auth_type_map_.find(username) == user_auth_type_map_.end()) 382 return ScreenlockBridge::LockHandler::OFFLINE_PASSWORD; 383 return user_auth_type_map_.find(username)->second; 384} 385 386} // namespace chromeos 387