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