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