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