blob: 7d8530714919403c73419112d45b09e5749d8b4a [file] [log] [blame]
// Copyright 2015 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/extensions/users_private/users_private_api.h"
#include <stddef.h>
#include <memory>
#include <utility>
#include "base/bind.h"
#include "base/strings/utf_string_conversions.h"
#include "base/values.h"
#include "chrome/browser/browser_process.h"
#include "chrome/browser/browser_process_platform_part.h"
#include "chrome/browser/chromeos/extensions/users_private/users_private_delegate.h"
#include "chrome/browser/chromeos/extensions/users_private/users_private_delegate_factory.h"
#include "chrome/browser/chromeos/ownership/owner_settings_service_chromeos.h"
#include "chrome/browser/chromeos/ownership/owner_settings_service_chromeos_factory.h"
#include "chrome/browser/chromeos/policy/browser_policy_connector_chromeos.h"
#include "chrome/browser/chromeos/profiles/profile_helper.h"
#include "chrome/browser/chromeos/settings/cros_settings.h"
#include "chrome/browser/profiles/profile.h"
#include "chrome/common/extensions/api/users_private.h"
#include "chromeos/settings/cros_settings_names.h"
#include "components/session_manager/core/session_manager.h"
#include "components/user_manager/user.h"
#include "components/user_manager/user_manager.h"
#include "components/user_manager/user_names.h"
#include "extensions/browser/extension_function_registry.h"
#include "google_apis/gaia/gaia_auth_util.h"
namespace extensions {
namespace {
bool IsEnterpriseManaged() {
return g_browser_process->platform_part()
->browser_policy_connector_chromeos()
->IsEnterpriseManaged();
}
bool IsChild(Profile* profile) {
const user_manager::User* user =
chromeos::ProfileHelper::Get()->GetUserByProfile(profile);
if (!user)
return false;
return user->GetType() == user_manager::UserType::USER_TYPE_CHILD;
}
bool IsOwnerProfile(Profile* profile) {
return profile &&
chromeos::OwnerSettingsServiceChromeOSFactory::GetForBrowserContext(
profile)
->IsOwner();
}
bool CanModifyWhitelistedUsers(Profile* profile) {
return !IsEnterpriseManaged() && IsOwnerProfile(profile) && !IsChild(profile);
}
bool IsExistingWhitelistedUser(const std::string& username) {
return chromeos::CrosSettings::Get()->FindEmailInList(
chromeos::kAccountsPrefUsers, username, /*wildcard_match=*/nullptr);
}
// Creates User object for the exising user_manager::User .
api::users_private::User CreateApiUser(const std::string& email,
const user_manager::User& user) {
api::users_private::User api_user;
api_user.email = email;
api_user.display_email = user.GetDisplayEmail();
api_user.name = base::UTF16ToUTF8(user.GetDisplayName());
api_user.is_owner = user.GetAccountId() ==
user_manager::UserManager::Get()->GetOwnerAccountId();
api_user.is_supervised = user.IsSupervised();
api_user.is_child = user.IsChild();
return api_user;
}
// Creates User object for the unknown user (i.e. not on device).
api::users_private::User CreateUnknownApiUser(const std::string& email) {
api::users_private::User api_user;
api_user.email = email;
api_user.display_email = email;
api_user.name = email;
api_user.is_owner = false;
api_user.is_supervised = false;
api_user.is_child = false;
return api_user;
}
std::unique_ptr<base::ListValue> GetUsersList(Profile* profile,
content::BrowserContext* browser_context)
{
std::unique_ptr<base::ListValue> user_list(new base::ListValue);
if (!CanModifyWhitelistedUsers(profile))
return user_list;
// Create one list to set. This is needed because user white list update is
// asynchronous and sequential. Before previous write comes back, cached list
// is stale and should not be used for appending. See http://crbug.com/127215
std::unique_ptr<base::ListValue> email_list;
UsersPrivateDelegate* delegate =
UsersPrivateDelegateFactory::GetForBrowserContext(browser_context);
PrefsUtil* prefs_util = delegate->GetPrefsUtil();
std::unique_ptr<api::settings_private::PrefObject> users_pref_object =
prefs_util->GetPref(chromeos::kAccountsPrefUsers);
if (users_pref_object->value) {
const base::ListValue* existing = nullptr;
users_pref_object->value->GetAsList(&existing);
email_list.reset(existing->DeepCopy());
} else {
email_list.reset(new base::ListValue());
}
const user_manager::UserManager* user_manager =
user_manager::UserManager::Get();
// Remove all supervised users. On the next step only supervised users present
// on the device will be added back. Thus not present SU are removed.
// No need to remove usual users as they can simply login back.
for (size_t i = 0; i < email_list->GetSize(); ++i) {
std::string whitelisted_user;
email_list->GetString(i, &whitelisted_user);
if (user_manager->IsSupervisedAccountId(
AccountId::FromUserEmail(whitelisted_user))) {
email_list->Remove(i, NULL);
--i;
}
}
const user_manager::UserList& users = user_manager->GetUsers();
for (const auto* user : users) {
email_list->AppendIfNotPresent(
std::make_unique<base::Value>(user->GetAccountId().GetUserEmail()));
}
if (chromeos::OwnerSettingsServiceChromeOS* service =
chromeos::OwnerSettingsServiceChromeOSFactory::GetForBrowserContext(
profile)) {
service->Set(chromeos::kAccountsPrefUsers, *email_list.get());
}
// Now populate the list of User objects for returning to the JS.
for (size_t i = 0; i < email_list->GetSize(); ++i) {
std::string email;
email_list->GetString(i, &email);
AccountId account_id = AccountId::FromUserEmail(email);
const user_manager::User* user = user_manager->FindUser(account_id);
user_list->Append(
(user ? CreateApiUser(email, *user) : CreateUnknownApiUser(email))
.ToValue());
}
return user_list;
}
} // anonymous namespace
////////////////////////////////////////////////////////////////////////////////
// UsersPrivateGetWhitelistedUsersFunction
UsersPrivateGetWhitelistedUsersFunction::
UsersPrivateGetWhitelistedUsersFunction()
: chrome_details_(this) {
}
UsersPrivateGetWhitelistedUsersFunction::
~UsersPrivateGetWhitelistedUsersFunction() {
}
ExtensionFunction::ResponseAction
UsersPrivateGetWhitelistedUsersFunction::Run() {
Profile* profile = chrome_details_.GetProfile();
return RespondNow(OneArgument(GetUsersList(profile, browser_context())));
}
////////////////////////////////////////////////////////////////////////////////
// UsersPrivateIsWhitelistedUserFunction
UsersPrivateIsWhitelistedUserFunction::UsersPrivateIsWhitelistedUserFunction()
: chrome_details_(this) {
}
UsersPrivateIsWhitelistedUserFunction::
~UsersPrivateIsWhitelistedUserFunction() {}
ExtensionFunction::ResponseAction UsersPrivateIsWhitelistedUserFunction::Run() {
std::unique_ptr<api::users_private::IsWhitelistedUser::Params> parameters =
api::users_private::IsWhitelistedUser::Params::Create(*args_);
EXTENSION_FUNCTION_VALIDATE(parameters.get());
std::string username = gaia::CanonicalizeEmail(parameters->email);
if (IsExistingWhitelistedUser(username)) {
return RespondNow(OneArgument(std::make_unique<base::Value>(true)));
}
return RespondNow(OneArgument(std::make_unique<base::Value>(false)));
}
////////////////////////////////////////////////////////////////////////////////
// UsersPrivateAddWhitelistedUserFunction
UsersPrivateAddWhitelistedUserFunction::UsersPrivateAddWhitelistedUserFunction()
: chrome_details_(this) {
}
UsersPrivateAddWhitelistedUserFunction::
~UsersPrivateAddWhitelistedUserFunction() {
}
ExtensionFunction::ResponseAction
UsersPrivateAddWhitelistedUserFunction::Run() {
std::unique_ptr<api::users_private::AddWhitelistedUser::Params> parameters =
api::users_private::AddWhitelistedUser::Params::Create(*args_);
EXTENSION_FUNCTION_VALIDATE(parameters.get());
// Non-owners should not be able to add users.
if (!CanModifyWhitelistedUsers(chrome_details_.GetProfile())) {
return RespondNow(OneArgument(std::make_unique<base::Value>(false)));
}
std::string username = gaia::CanonicalizeEmail(parameters->email);
if (IsExistingWhitelistedUser(username)) {
return RespondNow(OneArgument(std::make_unique<base::Value>(false)));
}
base::Value username_value(username);
UsersPrivateDelegate* delegate =
UsersPrivateDelegateFactory::GetForBrowserContext(browser_context());
PrefsUtil* prefs_util = delegate->GetPrefsUtil();
bool added = prefs_util->AppendToListCrosSetting(chromeos::kAccountsPrefUsers,
username_value);
return RespondNow(OneArgument(std::make_unique<base::Value>(added)));
}
////////////////////////////////////////////////////////////////////////////////
// UsersPrivateRemoveWhitelistedUserFunction
UsersPrivateRemoveWhitelistedUserFunction::
UsersPrivateRemoveWhitelistedUserFunction()
: chrome_details_(this) {
}
UsersPrivateRemoveWhitelistedUserFunction::
~UsersPrivateRemoveWhitelistedUserFunction() {
}
ExtensionFunction::ResponseAction
UsersPrivateRemoveWhitelistedUserFunction::Run() {
std::unique_ptr<api::users_private::RemoveWhitelistedUser::Params>
parameters =
api::users_private::RemoveWhitelistedUser::Params::Create(*args_);
EXTENSION_FUNCTION_VALIDATE(parameters.get());
// Non-owners should not be able to remove users.
if (!CanModifyWhitelistedUsers(chrome_details_.GetProfile())) {
return RespondNow(OneArgument(std::make_unique<base::Value>(false)));
}
base::Value canonical_email(gaia::CanonicalizeEmail(parameters->email));
UsersPrivateDelegate* delegate =
UsersPrivateDelegateFactory::GetForBrowserContext(browser_context());
PrefsUtil* prefs_util = delegate->GetPrefsUtil();
bool removed = prefs_util->RemoveFromListCrosSetting(
chromeos::kAccountsPrefUsers, canonical_email);
user_manager::UserManager::Get()->RemoveUser(
AccountId::FromUserEmail(parameters->email), NULL);
return RespondNow(OneArgument(std::make_unique<base::Value>(removed)));
}
////////////////////////////////////////////////////////////////////////////////
// UsersPrivateIsWhitelistManagedFunction
UsersPrivateIsWhitelistManagedFunction::
UsersPrivateIsWhitelistManagedFunction() {
}
UsersPrivateIsWhitelistManagedFunction::
~UsersPrivateIsWhitelistManagedFunction() {
}
ExtensionFunction::ResponseAction
UsersPrivateIsWhitelistManagedFunction::Run() {
return RespondNow(
OneArgument(std::make_unique<base::Value>(IsEnterpriseManaged())));
}
////////////////////////////////////////////////////////////////////////////////
// UsersPrivateGetCurrentUserFunction
UsersPrivateGetCurrentUserFunction::UsersPrivateGetCurrentUserFunction()
: chrome_details_(this) {}
UsersPrivateGetCurrentUserFunction::~UsersPrivateGetCurrentUserFunction() {}
ExtensionFunction::ResponseAction UsersPrivateGetCurrentUserFunction::Run() {
const user_manager::User* user =
chromeos::ProfileHelper::Get()->GetUserByProfile(
chrome_details_.GetProfile());
return user ? RespondNow(OneArgument(
CreateApiUser(user->GetAccountId().GetUserEmail(), *user)
.ToValue()))
: RespondNow(Error("No Current User"));
}
////////////////////////////////////////////////////////////////////////////////
// UsersPrivateGetLoginStatusFunction
UsersPrivateGetLoginStatusFunction::UsersPrivateGetLoginStatusFunction() =
default;
UsersPrivateGetLoginStatusFunction::~UsersPrivateGetLoginStatusFunction() =
default;
ExtensionFunction::ResponseAction UsersPrivateGetLoginStatusFunction::Run() {
const user_manager::UserManager* user_manager =
user_manager::UserManager::Get();
const bool is_logged_in = user_manager && user_manager->IsUserLoggedIn();
const bool is_screen_locked =
session_manager::SessionManager::Get()->IsScreenLocked();
auto result = std::make_unique<base::DictionaryValue>();
result->SetKey("isLoggedIn", base::Value(is_logged_in));
result->SetKey("isScreenLocked", base::Value(is_screen_locked));
return RespondNow(OneArgument(std::move(result)));
}
} // namespace extensions