blob: f4d69340a0dc3454eede108c9f5fca58a73ab741 [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/supervised_user/supervised_user_service.h"
#include <utility>
#include "base/command_line.h"
#include "base/files/file_path.h"
#include "base/files/file_util.h"
#include "base/memory/ref_counted.h"
#include "base/path_service.h"
#include "base/prefs/pref_service.h"
#include "base/strings/stringprintf.h"
#include "base/strings/utf_string_conversions.h"
#include "base/task_runner_util.h"
#include "base/version.h"
#include "build/build_config.h"
#include "chrome/browser/browser_process.h"
#include "chrome/browser/component_updater/supervised_user_whitelist_installer.h"
#include "chrome/browser/net/file_downloader.h"
#include "chrome/browser/profiles/profile.h"
#include "chrome/browser/profiles/profile_info_cache.h"
#include "chrome/browser/profiles/profile_manager.h"
#include "chrome/browser/signin/profile_oauth2_token_service_factory.h"
#include "chrome/browser/signin/signin_manager_factory.h"
#include "chrome/browser/supervised_user/experimental/supervised_user_filtering_switches.h"
#include "chrome/browser/supervised_user/permission_request_creator.h"
#include "chrome/browser/supervised_user/supervised_user_constants.h"
#include "chrome/browser/supervised_user/supervised_user_service_observer.h"
#include "chrome/browser/supervised_user/supervised_user_settings_service.h"
#include "chrome/browser/supervised_user/supervised_user_settings_service_factory.h"
#include "chrome/browser/supervised_user/supervised_user_site_list.h"
#include "chrome/browser/supervised_user/supervised_user_whitelist_service.h"
#include "chrome/browser/sync/profile_sync_service_factory.h"
#include "chrome/browser/ui/browser.h"
#include "chrome/browser/ui/browser_list.h"
#include "chrome/common/chrome_paths.h"
#include "chrome/common/chrome_switches.h"
#include "chrome/common/pref_names.h"
#include "chrome/grit/generated_resources.h"
#include "components/browser_sync/browser/profile_sync_service.h"
#include "components/pref_registry/pref_registry_syncable.h"
#include "components/signin/core/browser/profile_oauth2_token_service.h"
#include "components/signin/core/browser/signin_manager.h"
#include "components/signin/core/browser/signin_manager_base.h"
#include "components/signin/core/common/signin_switches.h"
#include "content/public/browser/browser_thread.h"
#include "content/public/browser/user_metrics.h"
#include "ui/base/l10n/l10n_util.h"
#if !defined(OS_ANDROID) && !defined(OS_IOS)
#include "chrome/browser/supervised_user/legacy/custodian_profile_downloader_service.h"
#include "chrome/browser/supervised_user/legacy/custodian_profile_downloader_service_factory.h"
#include "chrome/browser/supervised_user/legacy/permission_request_creator_sync.h"
#include "chrome/browser/supervised_user/legacy/supervised_user_pref_mapping_service.h"
#include "chrome/browser/supervised_user/legacy/supervised_user_pref_mapping_service_factory.h"
#include "chrome/browser/supervised_user/legacy/supervised_user_registration_utility.h"
#include "chrome/browser/supervised_user/legacy/supervised_user_shared_settings_service_factory.h"
#endif
#if defined(OS_CHROMEOS)
#include "chrome/browser/chromeos/login/users/chrome_user_manager.h"
#include "chrome/browser/chromeos/login/users/supervised_user_manager.h"
#include "components/user_manager/user_manager.h"
#endif
#if defined(ENABLE_EXTENSIONS)
#include "chrome/browser/extensions/extension_service.h"
#include "extensions/browser/extension_system.h"
#endif
#if defined(ENABLE_THEMES)
#include "chrome/browser/themes/theme_service.h"
#include "chrome/browser/themes/theme_service_factory.h"
#endif
using base::DictionaryValue;
using base::UserMetricsAction;
using content::BrowserThread;
namespace {
// The URL from which to download a host blacklist if no local one exists yet.
const char kBlacklistURL[] =
"https://www.gstatic.com/chrome/supervised_user/blacklist-20141001-1k.bin";
// The filename under which we'll store the blacklist (in the user data dir).
const char kBlacklistFilename[] = "su-blacklist.bin";
const char* const kCustodianInfoPrefs[] = {
prefs::kSupervisedUserCustodianName,
prefs::kSupervisedUserCustodianEmail,
prefs::kSupervisedUserCustodianProfileImageURL,
prefs::kSupervisedUserCustodianProfileURL,
prefs::kSupervisedUserSecondCustodianName,
prefs::kSupervisedUserSecondCustodianEmail,
prefs::kSupervisedUserSecondCustodianProfileImageURL,
prefs::kSupervisedUserSecondCustodianProfileURL,
};
void CreateURLAccessRequest(
const GURL& url,
PermissionRequestCreator* creator,
const SupervisedUserService::SuccessCallback& callback) {
creator->CreateURLAccessRequest(url, callback);
}
void CreateExtensionUpdateRequest(
const std::string& id,
PermissionRequestCreator* creator,
const SupervisedUserService::SuccessCallback& callback) {
creator->CreateExtensionUpdateRequest(id, callback);
}
// Default callback for AddExtensionUpdateRequest.
void ExtensionUpdateRequestSent(const std::string& id, bool success) {
VLOG_IF(1, !success) << "Failed sending update request for " << id;
}
base::FilePath GetBlacklistPath() {
base::FilePath blacklist_dir;
PathService::Get(chrome::DIR_USER_DATA, &blacklist_dir);
return blacklist_dir.AppendASCII(kBlacklistFilename);
}
#if defined(ENABLE_EXTENSIONS)
enum ExtensionState {
EXTENSION_FORCED,
EXTENSION_BLOCKED,
EXTENSION_ALLOWED
};
ExtensionState GetExtensionState(const extensions::Extension* extension) {
bool was_installed_by_default = extension->was_installed_by_default();
#if defined(OS_CHROMEOS)
// On Chrome OS all external sources are controlled by us so it means that
// they are "default". Method was_installed_by_default returns false because
// extensions creation flags are ignored in case of default extensions with
// update URL(the flags aren't passed to OnExternalExtensionUpdateUrlFound).
// TODO(dpolukhin): remove this Chrome OS specific code as soon as creation
// flags are not ignored.
was_installed_by_default =
extensions::Manifest::IsExternalLocation(extension->location());
#endif
// Note: Component extensions are protected from modification/uninstallation
// anyway, so there's no need to enforce them again for supervised users.
// Also, leave policy-installed extensions alone - they have their own
// management; in particular we don't want to override the force-install list.
if (extensions::Manifest::IsComponentLocation(extension->location()) ||
extensions::Manifest::IsPolicyLocation(extension->location()) ||
extension->is_theme() ||
extension->from_bookmark() ||
extension->is_shared_module() ||
was_installed_by_default) {
return EXTENSION_ALLOWED;
}
if (extension->was_installed_by_custodian())
return EXTENSION_FORCED;
return EXTENSION_BLOCKED;
}
#endif
} // namespace
SupervisedUserService::~SupervisedUserService() {
DCHECK(!did_init_ || did_shutdown_);
url_filter_context_.ui_url_filter()->RemoveObserver(this);
}
// static
void SupervisedUserService::RegisterProfilePrefs(
user_prefs::PrefRegistrySyncable* registry) {
registry->RegisterDictionaryPref(prefs::kSupervisedUserManualHosts);
registry->RegisterDictionaryPref(prefs::kSupervisedUserManualURLs);
registry->RegisterIntegerPref(prefs::kDefaultSupervisedUserFilteringBehavior,
SupervisedUserURLFilter::ALLOW);
registry->RegisterBooleanPref(prefs::kSupervisedUserCreationAllowed, true);
registry->RegisterBooleanPref(prefs::kSupervisedUserSafeSites, true);
for (const char* pref : kCustodianInfoPrefs) {
registry->RegisterStringPref(pref, std::string());
}
}
void SupervisedUserService::Init() {
DCHECK(!did_init_);
did_init_ = true;
DCHECK(GetSettingsService()->IsReady());
pref_change_registrar_.Init(profile_->GetPrefs());
pref_change_registrar_.Add(
prefs::kSupervisedUserId,
base::Bind(&SupervisedUserService::OnSupervisedUserIdChanged,
base::Unretained(this)));
pref_change_registrar_.Add(
prefs::kRecordHistory,
base::Bind(&SupervisedUserService::OnHistoryRecordingStateChanged,
base::Unretained(this)));
ProfileSyncService* sync_service =
ProfileSyncServiceFactory::GetForProfile(profile_);
// Can be null in tests.
if (sync_service)
sync_service->AddPreferenceProvider(this);
std::string client_id = component_updater::SupervisedUserWhitelistInstaller::
ClientIdForProfilePath(profile_->GetPath());
whitelist_service_.reset(new SupervisedUserWhitelistService(
profile_->GetPrefs(),
g_browser_process->supervised_user_whitelist_installer(), client_id));
whitelist_service_->AddSiteListsChangedCallback(
base::Bind(&SupervisedUserService::OnSiteListsChanged,
weak_ptr_factory_.GetWeakPtr()));
SetActive(ProfileIsSupervised());
}
void SupervisedUserService::SetDelegate(Delegate* delegate) {
if (delegate) {
// Changing delegates isn't allowed.
DCHECK(!delegate_);
} else {
// If the delegate is removed, deactivate first to give the old delegate a
// chance to clean up.
SetActive(false);
}
delegate_ = delegate;
}
scoped_refptr<const SupervisedUserURLFilter>
SupervisedUserService::GetURLFilterForIOThread() {
return url_filter_context_.io_url_filter();
}
SupervisedUserURLFilter* SupervisedUserService::GetURLFilterForUIThread() {
return url_filter_context_.ui_url_filter();
}
SupervisedUserWhitelistService* SupervisedUserService::GetWhitelistService() {
return whitelist_service_.get();
}
bool SupervisedUserService::AccessRequestsEnabled() {
return FindEnabledPermissionRequestCreator(0) < permissions_creators_.size();
}
void SupervisedUserService::AddURLAccessRequest(
const GURL& url,
const SuccessCallback& callback) {
AddPermissionRequestInternal(
base::Bind(CreateURLAccessRequest,
SupervisedUserURLFilter::Normalize(url)),
callback, 0);
}
void SupervisedUserService::AddExtensionUpdateRequest(
const std::string& extension_id,
const base::Version& version,
const SuccessCallback& callback) {
std::string id = GetExtensionUpdateRequestId(extension_id, version);
AddPermissionRequestInternal(
base::Bind(CreateExtensionUpdateRequest, id), callback, 0);
}
void SupervisedUserService::AddExtensionUpdateRequest(
const std::string& extension_id,
const base::Version& version) {
std::string id = GetExtensionUpdateRequestId(extension_id, version);
AddExtensionUpdateRequest(extension_id, version,
base::Bind(ExtensionUpdateRequestSent, id));
}
// static
std::string SupervisedUserService::GetExtensionUpdateRequestId(
const std::string& extension_id,
const base::Version& version) {
return base::StringPrintf("%s:%s", extension_id.c_str(),
version.GetString().c_str());
}
std::string SupervisedUserService::GetCustodianEmailAddress() const {
std::string email = profile_->GetPrefs()->GetString(
prefs::kSupervisedUserCustodianEmail);
#if defined(OS_CHROMEOS)
// |GetActiveUser()| can return null in unit tests.
if (email.empty() && !!user_manager::UserManager::Get()->GetActiveUser()) {
email = chromeos::ChromeUserManager::Get()
->GetSupervisedUserManager()
->GetManagerDisplayEmail(
user_manager::UserManager::Get()->GetActiveUser()->email());
}
#endif
return email;
}
std::string SupervisedUserService::GetCustodianName() const {
std::string name = profile_->GetPrefs()->GetString(
prefs::kSupervisedUserCustodianName);
#if defined(OS_CHROMEOS)
// |GetActiveUser()| can return null in unit tests.
if (name.empty() && !!user_manager::UserManager::Get()->GetActiveUser()) {
name = base::UTF16ToUTF8(chromeos::ChromeUserManager::Get()
->GetSupervisedUserManager()
->GetManagerDisplayName(
user_manager::UserManager::Get()->GetActiveUser()->email()));
}
#endif
return name.empty() ? GetCustodianEmailAddress() : name;
}
std::string SupervisedUserService::GetSecondCustodianEmailAddress() const {
return profile_->GetPrefs()->GetString(
prefs::kSupervisedUserSecondCustodianEmail);
}
std::string SupervisedUserService::GetSecondCustodianName() const {
std::string name = profile_->GetPrefs()->GetString(
prefs::kSupervisedUserSecondCustodianName);
return name.empty() ? GetSecondCustodianEmailAddress() : name;
}
base::string16 SupervisedUserService::GetExtensionsLockedMessage() const {
return l10n_util::GetStringFUTF16(IDS_EXTENSIONS_LOCKED_SUPERVISED_USER,
base::UTF8ToUTF16(GetCustodianName()));
}
#if !defined(OS_ANDROID) && !defined(OS_IOS)
void SupervisedUserService::InitSync(const std::string& refresh_token) {
StartSetupSync();
ProfileOAuth2TokenService* token_service =
ProfileOAuth2TokenServiceFactory::GetForProfile(profile_);
token_service->UpdateCredentials(supervised_users::kSupervisedUserPseudoEmail,
refresh_token);
FinishSetupSyncWhenReady();
}
void SupervisedUserService::RegisterAndInitSync(
SupervisedUserRegistrationUtility* registration_utility,
Profile* custodian_profile,
const std::string& supervised_user_id,
const AuthErrorCallback& callback) {
DCHECK(ProfileIsSupervised());
DCHECK(!custodian_profile->IsSupervised());
base::string16 name = base::UTF8ToUTF16(
profile_->GetPrefs()->GetString(prefs::kProfileName));
int avatar_index = profile_->GetPrefs()->GetInteger(
prefs::kProfileAvatarIndex);
SupervisedUserRegistrationInfo info(name, avatar_index);
registration_utility->Register(
supervised_user_id,
info,
base::Bind(&SupervisedUserService::OnSupervisedUserRegistered,
weak_ptr_factory_.GetWeakPtr(), callback, custodian_profile));
// Fetch the custodian's profile information, to store the name.
// TODO(pamg): If --google-profile-info (flag: switches::kGoogleProfileInfo)
// is ever enabled, take the name from the ProfileInfoCache instead.
CustodianProfileDownloaderService* profile_downloader_service =
CustodianProfileDownloaderServiceFactory::GetForProfile(
custodian_profile);
profile_downloader_service->DownloadProfile(
base::Bind(&SupervisedUserService::OnCustodianProfileDownloaded,
weak_ptr_factory_.GetWeakPtr()));
}
#endif // !defined(OS_ANDROID) && !defined(OS_IOS)
void SupervisedUserService::AddNavigationBlockedCallback(
const NavigationBlockedCallback& callback) {
navigation_blocked_callbacks_.push_back(callback);
}
void SupervisedUserService::DidBlockNavigation(
content::WebContents* web_contents) {
for (const auto& callback : navigation_blocked_callbacks_)
callback.Run(web_contents);
}
void SupervisedUserService::AddObserver(
SupervisedUserServiceObserver* observer) {
observer_list_.AddObserver(observer);
}
void SupervisedUserService::RemoveObserver(
SupervisedUserServiceObserver* observer) {
observer_list_.RemoveObserver(observer);
}
void SupervisedUserService::AddPermissionRequestCreator(
scoped_ptr<PermissionRequestCreator> creator) {
permissions_creators_.push_back(creator.release());
}
SupervisedUserService::URLFilterContext::URLFilterContext()
: ui_url_filter_(new SupervisedUserURLFilter),
io_url_filter_(new SupervisedUserURLFilter) {}
SupervisedUserService::URLFilterContext::~URLFilterContext() {}
SupervisedUserURLFilter*
SupervisedUserService::URLFilterContext::ui_url_filter() const {
return ui_url_filter_.get();
}
SupervisedUserURLFilter*
SupervisedUserService::URLFilterContext::io_url_filter() const {
return io_url_filter_.get();
}
void SupervisedUserService::URLFilterContext::SetDefaultFilteringBehavior(
SupervisedUserURLFilter::FilteringBehavior behavior) {
ui_url_filter_->SetDefaultFilteringBehavior(behavior);
BrowserThread::PostTask(
BrowserThread::IO,
FROM_HERE,
base::Bind(&SupervisedUserURLFilter::SetDefaultFilteringBehavior,
io_url_filter_.get(), behavior));
}
void SupervisedUserService::URLFilterContext::LoadWhitelists(
const std::vector<scoped_refptr<SupervisedUserSiteList> >& site_lists) {
ui_url_filter_->LoadWhitelists(site_lists);
BrowserThread::PostTask(BrowserThread::IO, FROM_HERE,
base::Bind(&SupervisedUserURLFilter::LoadWhitelists,
io_url_filter_, site_lists));
}
void SupervisedUserService::URLFilterContext::SetBlacklist(
const SupervisedUserBlacklist* blacklist) {
ui_url_filter_->SetBlacklist(blacklist);
BrowserThread::PostTask(
BrowserThread::IO,
FROM_HERE,
base::Bind(&SupervisedUserURLFilter::SetBlacklist,
io_url_filter_,
blacklist));
}
bool SupervisedUserService::URLFilterContext::HasBlacklist() const {
return ui_url_filter_->HasBlacklist();
}
void SupervisedUserService::URLFilterContext::SetManualHosts(
scoped_ptr<std::map<std::string, bool> > host_map) {
ui_url_filter_->SetManualHosts(host_map.get());
BrowserThread::PostTask(
BrowserThread::IO,
FROM_HERE,
base::Bind(&SupervisedUserURLFilter::SetManualHosts,
io_url_filter_, base::Owned(host_map.release())));
}
void SupervisedUserService::URLFilterContext::SetManualURLs(
scoped_ptr<std::map<GURL, bool> > url_map) {
ui_url_filter_->SetManualURLs(url_map.get());
BrowserThread::PostTask(
BrowserThread::IO,
FROM_HERE,
base::Bind(&SupervisedUserURLFilter::SetManualURLs,
io_url_filter_, base::Owned(url_map.release())));
}
void SupervisedUserService::URLFilterContext::Clear() {
ui_url_filter_->Clear();
BrowserThread::PostTask(
BrowserThread::IO,
FROM_HERE,
base::Bind(&SupervisedUserURLFilter::Clear,
io_url_filter_));
}
void SupervisedUserService::URLFilterContext::InitAsyncURLChecker(
const scoped_refptr<net::URLRequestContextGetter>& context) {
ui_url_filter_->InitAsyncURLChecker(context.get());
BrowserThread::PostTask(
BrowserThread::IO,
FROM_HERE,
base::Bind(&SupervisedUserURLFilter::InitAsyncURLChecker,
io_url_filter_, context));
}
bool SupervisedUserService::URLFilterContext::HasAsyncURLChecker() const {
return ui_url_filter_->HasAsyncURLChecker();
}
void SupervisedUserService::URLFilterContext::ClearAsyncURLChecker() {
ui_url_filter_->ClearAsyncURLChecker();
BrowserThread::PostTask(
BrowserThread::IO,
FROM_HERE,
base::Bind(&SupervisedUserURLFilter::ClearAsyncURLChecker,
io_url_filter_));
}
SupervisedUserService::SupervisedUserService(Profile* profile)
: includes_sync_sessions_type_(true),
profile_(profile),
active_(false),
delegate_(NULL),
waiting_for_sync_initialization_(false),
is_profile_active_(false),
did_init_(false),
did_shutdown_(false),
blacklist_state_(BlacklistLoadState::NOT_LOADED),
weak_ptr_factory_(this) {
url_filter_context_.ui_url_filter()->AddObserver(this);
}
void SupervisedUserService::SetActive(bool active) {
if (active_ == active)
return;
active_ = active;
if (!delegate_ || !delegate_->SetActive(active_)) {
if (active_) {
#if !defined(OS_ANDROID) && !defined(OS_IOS)
SupervisedUserPrefMappingServiceFactory::GetForBrowserContext(profile_)
->Init();
base::CommandLine* command_line = base::CommandLine::ForCurrentProcess();
if (command_line->HasSwitch(switches::kSupervisedUserSyncToken)) {
InitSync(
command_line->GetSwitchValueASCII(
switches::kSupervisedUserSyncToken));
}
ProfileOAuth2TokenService* token_service =
ProfileOAuth2TokenServiceFactory::GetForProfile(profile_);
token_service->LoadCredentials(
supervised_users::kSupervisedUserPseudoEmail);
permissions_creators_.push_back(new PermissionRequestCreatorSync(
GetSettingsService(),
SupervisedUserSharedSettingsServiceFactory::GetForBrowserContext(
profile_),
ProfileSyncServiceFactory::GetForProfile(profile_),
GetSupervisedUserName(),
profile_->GetPrefs()->GetString(prefs::kSupervisedUserId)));
SetupSync();
#else
NOTREACHED();
#endif
}
}
// Now activate/deactivate anything not handled by the delegate yet.
#if defined(ENABLE_THEMES)
// Re-set the default theme to turn the SU theme on/off.
ThemeService* theme_service = ThemeServiceFactory::GetForProfile(profile_);
if (theme_service->UsingDefaultTheme() || theme_service->UsingSystemTheme())
theme_service->UseDefaultTheme();
#endif
ProfileSyncService* sync_service =
ProfileSyncServiceFactory::GetForProfile(profile_);
sync_service->SetEncryptEverythingAllowed(!active_);
GetSettingsService()->SetActive(active_);
#if defined(ENABLE_EXTENSIONS)
SetExtensionsActive();
#endif
if (active_) {
pref_change_registrar_.Add(
prefs::kDefaultSupervisedUserFilteringBehavior,
base::Bind(&SupervisedUserService::OnDefaultFilteringBehaviorChanged,
base::Unretained(this)));
pref_change_registrar_.Add(prefs::kSupervisedUserSafeSites,
base::Bind(&SupervisedUserService::OnSafeSitesSettingChanged,
base::Unretained(this)));
pref_change_registrar_.Add(prefs::kSupervisedUserManualHosts,
base::Bind(&SupervisedUserService::UpdateManualHosts,
base::Unretained(this)));
pref_change_registrar_.Add(prefs::kSupervisedUserManualURLs,
base::Bind(&SupervisedUserService::UpdateManualURLs,
base::Unretained(this)));
for (const char* pref : kCustodianInfoPrefs) {
pref_change_registrar_.Add(pref,
base::Bind(&SupervisedUserService::OnCustodianInfoChanged,
base::Unretained(this)));
}
// Initialize the filter.
OnDefaultFilteringBehaviorChanged();
OnSafeSitesSettingChanged();
whitelist_service_->Init();
UpdateManualHosts();
UpdateManualURLs();
#if !defined(OS_ANDROID) && !defined(OS_IOS)
// TODO(bauerb): Get rid of the platform-specific #ifdef here.
// http://crbug.com/313377
BrowserList::AddObserver(this);
#endif
} else {
permissions_creators_.clear();
pref_change_registrar_.Remove(
prefs::kDefaultSupervisedUserFilteringBehavior);
pref_change_registrar_.Remove(prefs::kSupervisedUserManualHosts);
pref_change_registrar_.Remove(prefs::kSupervisedUserManualURLs);
for (const char* pref : kCustodianInfoPrefs) {
pref_change_registrar_.Remove(pref);
}
url_filter_context_.Clear();
FOR_EACH_OBSERVER(
SupervisedUserServiceObserver, observer_list_, OnURLFilterChanged());
#if !defined(OS_ANDROID) && !defined(OS_IOS)
if (waiting_for_sync_initialization_)
ProfileSyncServiceFactory::GetForProfile(profile_)->RemoveObserver(this);
// TODO(bauerb): Get rid of the platform-specific #ifdef here.
// http://crbug.com/313377
BrowserList::RemoveObserver(this);
#endif
}
}
#if !defined(OS_ANDROID) && !defined(OS_IOS)
void SupervisedUserService::OnCustodianProfileDownloaded(
const base::string16& full_name) {
profile_->GetPrefs()->SetString(prefs::kSupervisedUserCustodianName,
base::UTF16ToUTF8(full_name));
}
void SupervisedUserService::OnSupervisedUserRegistered(
const AuthErrorCallback& callback,
Profile* custodian_profile,
const GoogleServiceAuthError& auth_error,
const std::string& token) {
if (auth_error.state() == GoogleServiceAuthError::NONE) {
InitSync(token);
SigninManagerBase* signin =
SigninManagerFactory::GetForProfile(custodian_profile);
profile_->GetPrefs()->SetString(
prefs::kSupervisedUserCustodianEmail,
signin->GetAuthenticatedAccountInfo().email);
// The supervised user profile is now ready for use.
ProfileManager* profile_manager = g_browser_process->profile_manager();
ProfileInfoCache& cache = profile_manager->GetProfileInfoCache();
size_t index = cache.GetIndexOfProfileWithPath(profile_->GetPath());
cache.SetIsOmittedProfileAtIndex(index, false);
} else {
DCHECK_EQ(std::string(), token);
}
callback.Run(auth_error);
}
void SupervisedUserService::SetupSync() {
StartSetupSync();
FinishSetupSyncWhenReady();
}
void SupervisedUserService::StartSetupSync() {
// Tell the sync service that setup is in progress so we don't start syncing
// until we've finished configuration.
ProfileSyncServiceFactory::GetForProfile(profile_)->SetSetupInProgress(true);
}
void SupervisedUserService::FinishSetupSyncWhenReady() {
// If we're already waiting for the Sync backend, there's nothing to do here.
if (waiting_for_sync_initialization_)
return;
// Continue in FinishSetupSync() once the Sync backend has been initialized.
ProfileSyncService* service =
ProfileSyncServiceFactory::GetForProfile(profile_);
if (service->IsBackendInitialized() &&
service->backend_mode() == ProfileSyncService::SYNC) {
FinishSetupSync();
} else {
service->AddObserver(this);
waiting_for_sync_initialization_ = true;
}
}
void SupervisedUserService::FinishSetupSync() {
ProfileSyncService* service =
ProfileSyncServiceFactory::GetForProfile(profile_);
DCHECK(service->IsBackendInitialized());
DCHECK(service->backend_mode() == ProfileSyncService::SYNC);
// Sync nothing (except types which are set via GetPreferredDataTypes).
bool sync_everything = false;
syncer::ModelTypeSet synced_datatypes;
service->OnUserChoseDatatypes(sync_everything, synced_datatypes);
// Notify ProfileSyncService that we are done with configuration.
service->SetSetupInProgress(false);
service->SetFirstSetupComplete();
}
#endif
bool SupervisedUserService::ProfileIsSupervised() const {
return profile_->IsSupervised();
}
void SupervisedUserService::OnCustodianInfoChanged() {
FOR_EACH_OBSERVER(
SupervisedUserServiceObserver, observer_list_, OnCustodianInfoChanged());
}
SupervisedUserSettingsService* SupervisedUserService::GetSettingsService() {
return SupervisedUserSettingsServiceFactory::GetForProfile(profile_);
}
size_t SupervisedUserService::FindEnabledPermissionRequestCreator(
size_t start) {
for (size_t i = start; i < permissions_creators_.size(); ++i) {
if (permissions_creators_[i]->IsEnabled())
return i;
}
return permissions_creators_.size();
}
void SupervisedUserService::AddPermissionRequestInternal(
const CreatePermissionRequestCallback& create_request,
const SuccessCallback& callback,
size_t index) {
// Find a permission request creator that is enabled.
size_t next_index = FindEnabledPermissionRequestCreator(index);
if (next_index >= permissions_creators_.size()) {
callback.Run(false);
return;
}
create_request.Run(
permissions_creators_[next_index],
base::Bind(&SupervisedUserService::OnPermissionRequestIssued,
weak_ptr_factory_.GetWeakPtr(), create_request,
callback, next_index));
}
void SupervisedUserService::OnPermissionRequestIssued(
const CreatePermissionRequestCallback& create_request,
const SuccessCallback& callback,
size_t index,
bool success) {
if (success) {
callback.Run(true);
return;
}
AddPermissionRequestInternal(create_request, callback, index + 1);
}
void SupervisedUserService::OnSupervisedUserIdChanged() {
SetActive(ProfileIsSupervised());
}
void SupervisedUserService::OnDefaultFilteringBehaviorChanged() {
int behavior_value = profile_->GetPrefs()->GetInteger(
prefs::kDefaultSupervisedUserFilteringBehavior);
SupervisedUserURLFilter::FilteringBehavior behavior =
SupervisedUserURLFilter::BehaviorFromInt(behavior_value);
url_filter_context_.SetDefaultFilteringBehavior(behavior);
FOR_EACH_OBSERVER(
SupervisedUserServiceObserver, observer_list_, OnURLFilterChanged());
}
void SupervisedUserService::OnSafeSitesSettingChanged() {
bool use_blacklist = supervised_users::IsSafeSitesBlacklistEnabled(profile_);
if (use_blacklist != url_filter_context_.HasBlacklist()) {
if (use_blacklist && blacklist_state_ == BlacklistLoadState::NOT_LOADED) {
LoadBlacklist(GetBlacklistPath(), GURL(kBlacklistURL));
} else if (!use_blacklist ||
blacklist_state_ == BlacklistLoadState::LOADED) {
// Either the blacklist was turned off, or it was turned on but has
// already been loaded previously. Just update the setting.
UpdateBlacklist();
}
// Else: The blacklist was enabled, but the load is already in progress.
// Do nothing - we'll check the setting again when the load finishes.
}
bool use_online_check =
supervised_users::IsSafeSitesOnlineCheckEnabled(profile_);
if (use_online_check != url_filter_context_.HasAsyncURLChecker()) {
if (use_online_check)
url_filter_context_.InitAsyncURLChecker(profile_->GetRequestContext());
else
url_filter_context_.ClearAsyncURLChecker();
}
}
void SupervisedUserService::OnSiteListsChanged(
const std::vector<scoped_refptr<SupervisedUserSiteList> >& site_lists) {
url_filter_context_.LoadWhitelists(site_lists);
}
void SupervisedUserService::LoadBlacklist(const base::FilePath& path,
const GURL& url) {
DCHECK(blacklist_state_ == BlacklistLoadState::NOT_LOADED);
blacklist_state_ = BlacklistLoadState::LOAD_STARTED;
base::PostTaskAndReplyWithResult(
BrowserThread::GetBlockingPool()->GetTaskRunnerWithShutdownBehavior(
base::SequencedWorkerPool::CONTINUE_ON_SHUTDOWN).get(),
FROM_HERE,
base::Bind(&base::PathExists, path),
base::Bind(&SupervisedUserService::OnBlacklistFileChecked,
weak_ptr_factory_.GetWeakPtr(), path, url));
}
void SupervisedUserService::OnBlacklistFileChecked(const base::FilePath& path,
const GURL& url,
bool file_exists) {
DCHECK(blacklist_state_ == BlacklistLoadState::LOAD_STARTED);
if (file_exists) {
LoadBlacklistFromFile(path);
return;
}
DCHECK(!blacklist_downloader_);
blacklist_downloader_.reset(new FileDownloader(
url,
path,
false,
profile_->GetRequestContext(),
base::Bind(&SupervisedUserService::OnBlacklistDownloadDone,
base::Unretained(this), path)));
}
void SupervisedUserService::LoadBlacklistFromFile(const base::FilePath& path) {
DCHECK(blacklist_state_ == BlacklistLoadState::LOAD_STARTED);
blacklist_.ReadFromFile(
path,
base::Bind(&SupervisedUserService::OnBlacklistLoaded,
base::Unretained(this)));
}
void SupervisedUserService::OnBlacklistDownloadDone(const base::FilePath& path,
bool success) {
DCHECK(blacklist_state_ == BlacklistLoadState::LOAD_STARTED);
if (success) {
LoadBlacklistFromFile(path);
} else {
LOG(WARNING) << "Blacklist download failed";
// TODO(treib): Retry downloading after some time?
}
blacklist_downloader_.reset();
}
void SupervisedUserService::OnBlacklistLoaded() {
DCHECK(blacklist_state_ == BlacklistLoadState::LOAD_STARTED);
blacklist_state_ = BlacklistLoadState::LOADED;
UpdateBlacklist();
}
void SupervisedUserService::UpdateBlacklist() {
bool use_blacklist = supervised_users::IsSafeSitesBlacklistEnabled(profile_);
url_filter_context_.SetBlacklist(use_blacklist ? &blacklist_ : nullptr);
FOR_EACH_OBSERVER(
SupervisedUserServiceObserver, observer_list_, OnURLFilterChanged());
}
void SupervisedUserService::UpdateManualHosts() {
const base::DictionaryValue* dict =
profile_->GetPrefs()->GetDictionary(prefs::kSupervisedUserManualHosts);
scoped_ptr<std::map<std::string, bool> > host_map(
new std::map<std::string, bool>());
for (base::DictionaryValue::Iterator it(*dict); !it.IsAtEnd(); it.Advance()) {
bool allow = false;
bool result = it.value().GetAsBoolean(&allow);
DCHECK(result);
(*host_map)[it.key()] = allow;
}
url_filter_context_.SetManualHosts(std::move(host_map));
FOR_EACH_OBSERVER(
SupervisedUserServiceObserver, observer_list_, OnURLFilterChanged());
}
void SupervisedUserService::UpdateManualURLs() {
const base::DictionaryValue* dict =
profile_->GetPrefs()->GetDictionary(prefs::kSupervisedUserManualURLs);
scoped_ptr<std::map<GURL, bool> > url_map(new std::map<GURL, bool>());
for (base::DictionaryValue::Iterator it(*dict); !it.IsAtEnd(); it.Advance()) {
bool allow = false;
bool result = it.value().GetAsBoolean(&allow);
DCHECK(result);
(*url_map)[GURL(it.key())] = allow;
}
url_filter_context_.SetManualURLs(std::move(url_map));
FOR_EACH_OBSERVER(
SupervisedUserServiceObserver, observer_list_, OnURLFilterChanged());
}
std::string SupervisedUserService::GetSupervisedUserName() const {
#if defined(OS_CHROMEOS)
// The active user can be NULL in unit tests.
if (user_manager::UserManager::Get()->GetActiveUser()) {
return UTF16ToUTF8(user_manager::UserManager::Get()->GetUserDisplayName(
user_manager::UserManager::Get()->GetActiveUser()->GetAccountId()));
}
return std::string();
#else
return profile_->GetPrefs()->GetString(prefs::kProfileName);
#endif
}
void SupervisedUserService::OnHistoryRecordingStateChanged() {
bool record_history =
profile_->GetPrefs()->GetBoolean(prefs::kRecordHistory);
includes_sync_sessions_type_ = record_history;
ProfileSyncServiceFactory::GetForProfile(profile_)
->ReconfigureDatatypeManager();
}
bool SupervisedUserService::IncludesSyncSessionsType() const {
return includes_sync_sessions_type_;
}
void SupervisedUserService::Shutdown() {
if (!did_init_)
return;
DCHECK(!did_shutdown_);
did_shutdown_ = true;
if (ProfileIsSupervised()) {
content::RecordAction(UserMetricsAction("ManagedUsers_QuitBrowser"));
}
SetActive(false);
ProfileSyncService* sync_service =
ProfileSyncServiceFactory::GetForProfile(profile_);
// Can be null in tests.
if (sync_service)
sync_service->RemovePreferenceProvider(this);
}
#if defined(ENABLE_EXTENSIONS)
std::string SupervisedUserService::GetDebugPolicyProviderName() const {
// Save the string space in official builds.
#ifdef NDEBUG
NOTREACHED();
return std::string();
#else
return "Supervised User Service";
#endif
}
bool SupervisedUserService::UserMayLoad(const extensions::Extension* extension,
base::string16* error) const {
DCHECK(ProfileIsSupervised());
ExtensionState result = GetExtensionState(extension);
bool may_load = (result != EXTENSION_BLOCKED);
if (!may_load && error)
*error = GetExtensionsLockedMessage();
return may_load;
}
bool SupervisedUserService::UserMayModifySettings(
const extensions::Extension* extension,
base::string16* error) const {
DCHECK(ProfileIsSupervised());
ExtensionState result = GetExtensionState(extension);
bool may_modify = (result == EXTENSION_ALLOWED);
if (!may_modify && error)
*error = GetExtensionsLockedMessage();
return may_modify;
}
// Note: Having MustRemainInstalled always say "true" for custodian-installed
// extensions does NOT prevent remote uninstalls (which is a bit unexpected, but
// exactly what we want).
bool SupervisedUserService::MustRemainInstalled(
const extensions::Extension* extension,
base::string16* error) const {
DCHECK(ProfileIsSupervised());
ExtensionState result = GetExtensionState(extension);
bool may_not_uninstall = (result == EXTENSION_FORCED);
if (may_not_uninstall && error)
*error = GetExtensionsLockedMessage();
return may_not_uninstall;
}
void SupervisedUserService::SetExtensionsActive() {
extensions::ExtensionSystem* extension_system =
extensions::ExtensionSystem::Get(profile_);
extensions::ManagementPolicy* management_policy =
extension_system->management_policy();
if (management_policy) {
if (active_)
management_policy->RegisterProvider(this);
else
management_policy->UnregisterProvider(this);
// Re-check the policy to make sure any new settings get applied.
extension_system->extension_service()->CheckManagementPolicy();
}
}
#endif // defined(ENABLE_EXTENSIONS)
syncer::ModelTypeSet SupervisedUserService::GetPreferredDataTypes() const {
if (!ProfileIsSupervised())
return syncer::ModelTypeSet();
syncer::ModelTypeSet result;
if (IncludesSyncSessionsType())
result.Put(syncer::SESSIONS);
result.Put(syncer::EXTENSIONS);
result.Put(syncer::EXTENSION_SETTINGS);
result.Put(syncer::APPS);
result.Put(syncer::APP_SETTINGS);
result.Put(syncer::APP_NOTIFICATIONS);
result.Put(syncer::APP_LIST);
return result;
}
#if !defined(OS_ANDROID) && !defined(OS_IOS)
void SupervisedUserService::OnStateChanged() {
ProfileSyncService* service =
ProfileSyncServiceFactory::GetForProfile(profile_);
if (waiting_for_sync_initialization_ && service->IsBackendInitialized() &&
service->backend_mode() == ProfileSyncService::SYNC) {
waiting_for_sync_initialization_ = false;
service->RemoveObserver(this);
FinishSetupSync();
return;
}
DLOG_IF(ERROR, service->GetAuthError().state() ==
GoogleServiceAuthError::INVALID_GAIA_CREDENTIALS)
<< "Credentials rejected";
}
void SupervisedUserService::OnBrowserSetLastActive(Browser* browser) {
bool profile_became_active = profile_->IsSameProfile(browser->profile());
if (!is_profile_active_ && profile_became_active)
content::RecordAction(UserMetricsAction("ManagedUsers_OpenProfile"));
else if (is_profile_active_ && !profile_became_active)
content::RecordAction(UserMetricsAction("ManagedUsers_SwitchProfile"));
is_profile_active_ = profile_became_active;
}
#endif // !defined(OS_ANDROID) && !defined(OS_IOS)
void SupervisedUserService::OnSiteListUpdated() {
FOR_EACH_OBSERVER(
SupervisedUserServiceObserver, observer_list_, OnURLFilterChanged());
}