blob: e80dfaff606a8e486597af4936ea6574be1eea35 [file] [log] [blame]
// Copyright 2014 The Chromium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
#include "chrome/browser/chromeos/login/screens/user_selection_screen.h"
#include "ash/shell.h"
#include "base/logging.h"
#include "base/prefs/pref_service.h"
#include "chrome/browser/browser_process.h"
#include "chrome/browser/chromeos/login/ui/login_display_host_impl.h"
#include "chrome/browser/chromeos/login/users/multi_profile_user_controller.h"
#include "chrome/browser/chromeos/policy/browser_policy_connector_chromeos.h"
#include "chrome/browser/signin/screenlock_bridge.h"
#include "chrome/browser/ui/webui/chromeos/login/signin_screen_handler.h"
#include "chrome/common/pref_names.h"
#include "components/user_manager/user_type.h"
#include "ui/wm/core/user_activity_detector.h"
namespace chromeos {
namespace {
// User dictionary keys.
const char kKeyUsername[] = "username";
const char kKeyDisplayName[] = "displayName";
const char kKeyEmailAddress[] = "emailAddress";
const char kKeyEnterpriseDomain[] = "enterpriseDomain";
const char kKeyPublicAccount[] = "publicAccount";
const char kKeyLocallyManagedUser[] = "locallyManagedUser";
const char kKeySignedIn[] = "signedIn";
const char kKeyCanRemove[] = "canRemove";
const char kKeyIsOwner[] = "isOwner";
const char kKeyInitialAuthType[] = "initialAuthType";
const char kKeyMultiProfilesAllowed[] = "isMultiProfilesAllowed";
const char kKeyMultiProfilesPolicy[] = "multiProfilesPolicy";
// Max number of users to show.
// Please keep synced with one in signin_userlist_unittest.cc.
const size_t kMaxUsers = 18;
const int kPasswordClearTimeoutSec = 60;
} // namespace
UserSelectionScreen::UserSelectionScreen() : handler_(NULL) {
}
UserSelectionScreen::~UserSelectionScreen() {
wm::UserActivityDetector* activity_detector =
ash::Shell::GetInstance()->user_activity_detector();
if (activity_detector->HasObserver(this))
activity_detector->RemoveObserver(this);
}
// static
void UserSelectionScreen::FillUserDictionary(
User* user,
bool is_owner,
bool is_signin_to_add,
ScreenlockBridge::LockHandler::AuthType auth_type,
base::DictionaryValue* user_dict) {
const std::string& user_id = user->email();
const bool is_public_account =
user->GetType() == user_manager::USER_TYPE_PUBLIC_ACCOUNT;
const bool is_locally_managed_user =
user->GetType() == user_manager::USER_TYPE_LOCALLY_MANAGED;
user_dict->SetString(kKeyUsername, user_id);
user_dict->SetString(kKeyEmailAddress, user->display_email());
user_dict->SetString(kKeyDisplayName, user->GetDisplayName());
user_dict->SetBoolean(kKeyPublicAccount, is_public_account);
user_dict->SetBoolean(kKeyLocallyManagedUser, is_locally_managed_user);
user_dict->SetInteger(kKeyInitialAuthType, auth_type);
user_dict->SetBoolean(kKeySignedIn, user->is_logged_in());
user_dict->SetBoolean(kKeyIsOwner, is_owner);
// Fill in multi-profiles related fields.
if (is_signin_to_add) {
MultiProfileUserController* multi_profile_user_controller =
UserManager::Get()->GetMultiProfileUserController();
std::string behavior =
multi_profile_user_controller->GetCachedValue(user_id);
user_dict->SetBoolean(kKeyMultiProfilesAllowed,
multi_profile_user_controller->IsUserAllowedInSession(
user_id) == MultiProfileUserController::ALLOWED);
user_dict->SetString(kKeyMultiProfilesPolicy, behavior);
} else {
user_dict->SetBoolean(kKeyMultiProfilesAllowed, true);
}
if (is_public_account) {
policy::BrowserPolicyConnectorChromeOS* policy_connector =
g_browser_process->platform_part()->browser_policy_connector_chromeos();
if (policy_connector->IsEnterpriseManaged()) {
user_dict->SetString(kKeyEnterpriseDomain,
policy_connector->GetEnterpriseDomain());
}
}
}
// static
bool UserSelectionScreen::ShouldForceOnlineSignIn(const User* user) {
// Public sessions are always allowed to log in offline.
// Supervised user are allowed to log in offline if their OAuth token status
// is unknown or valid.
// For all other users, force online sign in if:
// * The flag to force online sign-in is set for the user.
// * The user's OAuth token is invalid.
// * The user's OAuth token status is unknown (except supervised users,
// see above).
if (user->is_logged_in())
return false;
const User::OAuthTokenStatus token_status = user->oauth_token_status();
const bool is_locally_managed_user =
user->GetType() == user_manager::USER_TYPE_LOCALLY_MANAGED;
const bool is_public_session =
user->GetType() == user_manager::USER_TYPE_PUBLIC_ACCOUNT;
if (is_locally_managed_user &&
token_status == User::OAUTH_TOKEN_STATUS_UNKNOWN) {
return false;
}
if (is_public_session)
return false;
return user->force_online_signin() ||
(token_status == User::OAUTH2_TOKEN_STATUS_INVALID) ||
(token_status == User::OAUTH_TOKEN_STATUS_UNKNOWN);
}
void UserSelectionScreen::SetHandler(LoginDisplayWebUIHandler* handler) {
handler_ = handler;
}
void UserSelectionScreen::Init(const UserList& users, bool show_guest) {
users_ = users;
show_guest_ = show_guest;
wm::UserActivityDetector* activity_detector =
ash::Shell::GetInstance()->user_activity_detector();
if (!activity_detector->HasObserver(this))
activity_detector->AddObserver(this);
}
void UserSelectionScreen::OnBeforeUserRemoved(const std::string& username) {
for (UserList::iterator it = users_.begin(); it != users_.end(); ++it) {
if ((*it)->email() == username) {
users_.erase(it);
break;
}
}
}
void UserSelectionScreen::OnUserRemoved(const std::string& username) {
if (!handler_)
return;
handler_->OnUserRemoved(username);
}
void UserSelectionScreen::OnUserImageChanged(const User& user) {
if (!handler_)
return;
handler_->OnUserImageChanged(user);
// TODO(antrim) : updateUserImage(user.email())
}
const UserList& UserSelectionScreen::GetUsers() const {
return users_;
}
void UserSelectionScreen::OnPasswordClearTimerExpired() {
if (handler_)
handler_->ClearUserPodPassword();
}
void UserSelectionScreen::OnUserActivity(const ui::Event* event) {
if (!password_clear_timer_.IsRunning()) {
password_clear_timer_.Start(
FROM_HERE,
base::TimeDelta::FromSeconds(kPasswordClearTimeoutSec),
this,
&UserSelectionScreen::OnPasswordClearTimerExpired);
}
password_clear_timer_.Reset();
}
// static
const UserList UserSelectionScreen::PrepareUserListForSending(
const UserList& users,
std::string owner,
bool is_signin_to_add) {
UserList users_to_send;
bool has_owner = owner.size() > 0;
size_t max_non_owner_users = has_owner ? kMaxUsers - 1 : kMaxUsers;
size_t non_owner_count = 0;
for (UserList::const_iterator it = users.begin(); it != users.end(); ++it) {
const std::string& user_id = (*it)->email();
bool is_owner = (user_id == owner);
bool is_public_account =
((*it)->GetType() == user_manager::USER_TYPE_PUBLIC_ACCOUNT);
if ((is_public_account && !is_signin_to_add) || is_owner ||
(!is_public_account && non_owner_count < max_non_owner_users)) {
if (!is_owner)
++non_owner_count;
if (is_owner && users_to_send.size() > kMaxUsers) {
// Owner is always in the list.
users_to_send.insert(users_to_send.begin() + (kMaxUsers - 1), *it);
while (users_to_send.size() > kMaxUsers)
users_to_send.erase(users_to_send.begin() + kMaxUsers);
} else if (users_to_send.size() < kMaxUsers) {
users_to_send.push_back(*it);
}
}
}
return users_to_send;
}
void UserSelectionScreen::SendUserList() {
base::ListValue users_list;
const UserList& users = GetUsers();
// TODO(nkostylev): Move to a separate method in UserManager.
// http://crbug.com/230852
bool single_user = users.size() == 1;
bool is_signin_to_add = LoginDisplayHostImpl::default_host() &&
UserManager::Get()->IsUserLoggedIn();
std::string owner;
chromeos::CrosSettings::Get()->GetString(chromeos::kDeviceOwner, &owner);
policy::BrowserPolicyConnectorChromeOS* connector =
g_browser_process->platform_part()->browser_policy_connector_chromeos();
bool is_enterprise_managed = connector->IsEnterpriseManaged();
const UserList users_to_send = PrepareUserListForSending(users,
owner,
is_signin_to_add);
user_auth_type_map_.clear();
for (UserList::const_iterator it = users_to_send.begin();
it != users_to_send.end();
++it) {
const std::string& user_id = (*it)->email();
bool is_owner = (user_id == owner);
const bool is_public_account =
((*it)->GetType() == user_manager::USER_TYPE_PUBLIC_ACCOUNT);
const ScreenlockBridge::LockHandler::AuthType initial_auth_type =
is_public_account
? ScreenlockBridge::LockHandler::EXPAND_THEN_USER_CLICK
: (ShouldForceOnlineSignIn(*it)
? ScreenlockBridge::LockHandler::ONLINE_SIGN_IN
: ScreenlockBridge::LockHandler::OFFLINE_PASSWORD);
user_auth_type_map_[user_id] = initial_auth_type;
base::DictionaryValue* user_dict = new base::DictionaryValue();
FillUserDictionary(
*it, is_owner, is_signin_to_add, initial_auth_type, user_dict);
bool signed_in = (*it)->is_logged_in();
// Single user check here is necessary because owner info might not be
// available when running into login screen on first boot.
// See http://crosbug.com/12723
bool can_remove_user =
((!single_user || is_enterprise_managed) && !user_id.empty() &&
!is_owner && !is_public_account && !signed_in && !is_signin_to_add);
user_dict->SetBoolean(kKeyCanRemove, can_remove_user);
users_list.Append(user_dict);
}
handler_->LoadUsers(users_list, show_guest_);
}
void UserSelectionScreen::HandleGetUsers() {
SendUserList();
}
void UserSelectionScreen::SetAuthType(
const std::string& username,
ScreenlockBridge::LockHandler::AuthType auth_type) {
user_auth_type_map_[username] = auth_type;
}
ScreenlockBridge::LockHandler::AuthType UserSelectionScreen::GetAuthType(
const std::string& username) const {
if (user_auth_type_map_.find(username) == user_auth_type_map_.end())
return ScreenlockBridge::LockHandler::OFFLINE_PASSWORD;
return user_auth_type_map_.find(username)->second;
}
} // namespace chromeos