supervised_user_service.cc revision 116680a4aac90f2aa7413d9095a592090648e557
1d0247b1b59f9c528cb6df88b4f2b9afaf80d181eTorne (Richard Coles)// Copyright 2014 The Chromium Authors. All rights reserved.
2d0247b1b59f9c528cb6df88b4f2b9afaf80d181eTorne (Richard Coles)// Use of this source code is governed by a BSD-style license that can be
3d0247b1b59f9c528cb6df88b4f2b9afaf80d181eTorne (Richard Coles)// found in the LICENSE file.
4d0247b1b59f9c528cb6df88b4f2b9afaf80d181eTorne (Richard Coles)
5d0247b1b59f9c528cb6df88b4f2b9afaf80d181eTorne (Richard Coles)#include "chrome/browser/supervised_user/supervised_user_service.h"
6d0247b1b59f9c528cb6df88b4f2b9afaf80d181eTorne (Richard Coles)
7c5cede9ae108bb15f6b7a8aea21c7e1fefa2834cBen Murdoch#include "base/command_line.h"
8c5cede9ae108bb15f6b7a8aea21c7e1fefa2834cBen Murdoch#include "base/memory/ref_counted.h"
9c5cede9ae108bb15f6b7a8aea21c7e1fefa2834cBen Murdoch#include "base/prefs/pref_service.h"
10c5cede9ae108bb15f6b7a8aea21c7e1fefa2834cBen Murdoch#include "base/strings/string_number_conversions.h"
1103b57e008b61dfcb1fbad3aea950ae0e001748b0Torne (Richard Coles)#include "base/strings/utf_string_conversions.h"
1203b57e008b61dfcb1fbad3aea950ae0e001748b0Torne (Richard Coles)#include "chrome/browser/browser_process.h"
1303b57e008b61dfcb1fbad3aea950ae0e001748b0Torne (Richard Coles)#include "chrome/browser/profiles/profile.h"
1403b57e008b61dfcb1fbad3aea950ae0e001748b0Torne (Richard Coles)#include "chrome/browser/profiles/profile_info_cache.h"
1503b57e008b61dfcb1fbad3aea950ae0e001748b0Torne (Richard Coles)#include "chrome/browser/profiles/profile_manager.h"
1603b57e008b61dfcb1fbad3aea950ae0e001748b0Torne (Richard Coles)#include "chrome/browser/signin/profile_oauth2_token_service_factory.h"
1703b57e008b61dfcb1fbad3aea950ae0e001748b0Torne (Richard Coles)#include "chrome/browser/signin/signin_manager_factory.h"
1803b57e008b61dfcb1fbad3aea950ae0e001748b0Torne (Richard Coles)#include "chrome/browser/supervised_user/custodian_profile_downloader_service.h"
1903b57e008b61dfcb1fbad3aea950ae0e001748b0Torne (Richard Coles)#include "chrome/browser/supervised_user/custodian_profile_downloader_service_factory.h"
2003b57e008b61dfcb1fbad3aea950ae0e001748b0Torne (Richard Coles)#include "chrome/browser/supervised_user/permission_request_creator_apiary.h"
2103b57e008b61dfcb1fbad3aea950ae0e001748b0Torne (Richard Coles)#include "chrome/browser/supervised_user/permission_request_creator_sync.h"
2203b57e008b61dfcb1fbad3aea950ae0e001748b0Torne (Richard Coles)#include "chrome/browser/supervised_user/supervised_user_constants.h"
2303b57e008b61dfcb1fbad3aea950ae0e001748b0Torne (Richard Coles)#include "chrome/browser/supervised_user/supervised_user_pref_mapping_service.h"
24d0247b1b59f9c528cb6df88b4f2b9afaf80d181eTorne (Richard Coles)#include "chrome/browser/supervised_user/supervised_user_pref_mapping_service_factory.h"
25d0247b1b59f9c528cb6df88b4f2b9afaf80d181eTorne (Richard Coles)#include "chrome/browser/supervised_user/supervised_user_registration_utility.h"
260f1bc08d4cfcc34181b0b5cbf065c40f687bf740Torne (Richard Coles)#include "chrome/browser/supervised_user/supervised_user_settings_service.h"
270f1bc08d4cfcc34181b0b5cbf065c40f687bf740Torne (Richard Coles)#include "chrome/browser/supervised_user/supervised_user_settings_service_factory.h"
28d0247b1b59f9c528cb6df88b4f2b9afaf80d181eTorne (Richard Coles)#include "chrome/browser/supervised_user/supervised_user_shared_settings_service_factory.h"
290f1bc08d4cfcc34181b0b5cbf065c40f687bf740Torne (Richard Coles)#include "chrome/browser/supervised_user/supervised_user_site_list.h"
30c5cede9ae108bb15f6b7a8aea21c7e1fefa2834cBen Murdoch#include "chrome/browser/supervised_user/supervised_user_sync_service.h"
31c5cede9ae108bb15f6b7a8aea21c7e1fefa2834cBen Murdoch#include "chrome/browser/supervised_user/supervised_user_sync_service_factory.h"
320f1bc08d4cfcc34181b0b5cbf065c40f687bf740Torne (Richard Coles)#include "chrome/browser/sync/profile_sync_service.h"
330f1bc08d4cfcc34181b0b5cbf065c40f687bf740Torne (Richard Coles)#include "chrome/browser/sync/profile_sync_service_factory.h"
34f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)#include "chrome/browser/ui/browser.h"
3503b57e008b61dfcb1fbad3aea950ae0e001748b0Torne (Richard Coles)#include "chrome/browser/ui/browser_list.h"
3603b57e008b61dfcb1fbad3aea950ae0e001748b0Torne (Richard Coles)#include "chrome/common/chrome_switches.h"
37d0247b1b59f9c528cb6df88b4f2b9afaf80d181eTorne (Richard Coles)#include "chrome/common/pref_names.h"
38d0247b1b59f9c528cb6df88b4f2b9afaf80d181eTorne (Richard Coles)#include "components/pref_registry/pref_registry_syncable.h"
39d0247b1b59f9c528cb6df88b4f2b9afaf80d181eTorne (Richard Coles)#include "components/signin/core/browser/profile_oauth2_token_service.h"
40d0247b1b59f9c528cb6df88b4f2b9afaf80d181eTorne (Richard Coles)#include "components/signin/core/browser/signin_manager.h"
41c5cede9ae108bb15f6b7a8aea21c7e1fefa2834cBen Murdoch#include "components/signin/core/browser/signin_manager_base.h"
4203b57e008b61dfcb1fbad3aea950ae0e001748b0Torne (Richard Coles)#include "content/public/browser/browser_thread.h"
4303b57e008b61dfcb1fbad3aea950ae0e001748b0Torne (Richard Coles)#include "content/public/browser/user_metrics.h"
4403b57e008b61dfcb1fbad3aea950ae0e001748b0Torne (Richard Coles)#include "google_apis/gaia/google_service_auth_error.h"
4503b57e008b61dfcb1fbad3aea950ae0e001748b0Torne (Richard Coles)#include "grit/generated_resources.h"
4603b57e008b61dfcb1fbad3aea950ae0e001748b0Torne (Richard Coles)#include "net/base/escape.h"
4703b57e008b61dfcb1fbad3aea950ae0e001748b0Torne (Richard Coles)#include "ui/base/l10n/l10n_util.h"
4803b57e008b61dfcb1fbad3aea950ae0e001748b0Torne (Richard Coles)
4903b57e008b61dfcb1fbad3aea950ae0e001748b0Torne (Richard Coles)#if defined(OS_CHROMEOS)
5003b57e008b61dfcb1fbad3aea950ae0e001748b0Torne (Richard Coles)#include "chrome/browser/chromeos/login/users/supervised_user_manager.h"
5103b57e008b61dfcb1fbad3aea950ae0e001748b0Torne (Richard Coles)#include "chrome/browser/chromeos/login/users/user_manager.h"
5203b57e008b61dfcb1fbad3aea950ae0e001748b0Torne (Richard Coles)#endif
5303b57e008b61dfcb1fbad3aea950ae0e001748b0Torne (Richard Coles)
5403b57e008b61dfcb1fbad3aea950ae0e001748b0Torne (Richard Coles)#if defined(ENABLE_EXTENSIONS)
5503b57e008b61dfcb1fbad3aea950ae0e001748b0Torne (Richard Coles)#include "chrome/browser/extensions/extension_service.h"
5603b57e008b61dfcb1fbad3aea950ae0e001748b0Torne (Richard Coles)#include "chrome/common/extensions/api/supervised_user_private/supervised_user_handler.h"
5703b57e008b61dfcb1fbad3aea950ae0e001748b0Torne (Richard Coles)#include "extensions/browser/extension_registry.h"
5803b57e008b61dfcb1fbad3aea950ae0e001748b0Torne (Richard Coles)#include "extensions/browser/extension_system.h"
5903b57e008b61dfcb1fbad3aea950ae0e001748b0Torne (Richard Coles)#include "extensions/common/extension_set.h"
6003b57e008b61dfcb1fbad3aea950ae0e001748b0Torne (Richard Coles)#endif
6103b57e008b61dfcb1fbad3aea950ae0e001748b0Torne (Richard Coles)
6203b57e008b61dfcb1fbad3aea950ae0e001748b0Torne (Richard Coles)#if defined(ENABLE_THEMES)
6303b57e008b61dfcb1fbad3aea950ae0e001748b0Torne (Richard Coles)#include "chrome/browser/themes/theme_service.h"
6403b57e008b61dfcb1fbad3aea950ae0e001748b0Torne (Richard Coles)#include "chrome/browser/themes/theme_service_factory.h"
6503b57e008b61dfcb1fbad3aea950ae0e001748b0Torne (Richard Coles)#endif
6603b57e008b61dfcb1fbad3aea950ae0e001748b0Torne (Richard Coles)
6703b57e008b61dfcb1fbad3aea950ae0e001748b0Torne (Richard Coles)using base::DictionaryValue;
6803b57e008b61dfcb1fbad3aea950ae0e001748b0Torne (Richard Coles)using base::UserMetricsAction;
6903b57e008b61dfcb1fbad3aea950ae0e001748b0Torne (Richard Coles)using content::BrowserThread;
7003b57e008b61dfcb1fbad3aea950ae0e001748b0Torne (Richard Coles)
7103b57e008b61dfcb1fbad3aea950ae0e001748b0Torne (Richard Coles)SupervisedUserService::URLFilterContext::URLFilterContext()
7203b57e008b61dfcb1fbad3aea950ae0e001748b0Torne (Richard Coles)    : ui_url_filter_(new SupervisedUserURLFilter),
7303b57e008b61dfcb1fbad3aea950ae0e001748b0Torne (Richard Coles)      io_url_filter_(new SupervisedUserURLFilter) {}
7403b57e008b61dfcb1fbad3aea950ae0e001748b0Torne (Richard Coles)SupervisedUserService::URLFilterContext::~URLFilterContext() {}
7503b57e008b61dfcb1fbad3aea950ae0e001748b0Torne (Richard Coles)
7603b57e008b61dfcb1fbad3aea950ae0e001748b0Torne (Richard Coles)SupervisedUserURLFilter*
7703b57e008b61dfcb1fbad3aea950ae0e001748b0Torne (Richard Coles)SupervisedUserService::URLFilterContext::ui_url_filter() const {
7803b57e008b61dfcb1fbad3aea950ae0e001748b0Torne (Richard Coles)  return ui_url_filter_.get();
7903b57e008b61dfcb1fbad3aea950ae0e001748b0Torne (Richard Coles)}
8003b57e008b61dfcb1fbad3aea950ae0e001748b0Torne (Richard Coles)
8103b57e008b61dfcb1fbad3aea950ae0e001748b0Torne (Richard Coles)SupervisedUserURLFilter*
8203b57e008b61dfcb1fbad3aea950ae0e001748b0Torne (Richard Coles)SupervisedUserService::URLFilterContext::io_url_filter() const {
8303b57e008b61dfcb1fbad3aea950ae0e001748b0Torne (Richard Coles)  return io_url_filter_.get();
8403b57e008b61dfcb1fbad3aea950ae0e001748b0Torne (Richard Coles)}
8503b57e008b61dfcb1fbad3aea950ae0e001748b0Torne (Richard Coles)
8603b57e008b61dfcb1fbad3aea950ae0e001748b0Torne (Richard Coles)void SupervisedUserService::URLFilterContext::SetDefaultFilteringBehavior(
8703b57e008b61dfcb1fbad3aea950ae0e001748b0Torne (Richard Coles)    SupervisedUserURLFilter::FilteringBehavior behavior) {
8803b57e008b61dfcb1fbad3aea950ae0e001748b0Torne (Richard Coles)  ui_url_filter_->SetDefaultFilteringBehavior(behavior);
8903b57e008b61dfcb1fbad3aea950ae0e001748b0Torne (Richard Coles)  BrowserThread::PostTask(
9003b57e008b61dfcb1fbad3aea950ae0e001748b0Torne (Richard Coles)      BrowserThread::IO,
9103b57e008b61dfcb1fbad3aea950ae0e001748b0Torne (Richard Coles)      FROM_HERE,
9203b57e008b61dfcb1fbad3aea950ae0e001748b0Torne (Richard Coles)      base::Bind(&SupervisedUserURLFilter::SetDefaultFilteringBehavior,
9303b57e008b61dfcb1fbad3aea950ae0e001748b0Torne (Richard Coles)                 io_url_filter_.get(), behavior));
9403b57e008b61dfcb1fbad3aea950ae0e001748b0Torne (Richard Coles)}
9503b57e008b61dfcb1fbad3aea950ae0e001748b0Torne (Richard Coles)
9603b57e008b61dfcb1fbad3aea950ae0e001748b0Torne (Richard Coles)void SupervisedUserService::URLFilterContext::LoadWhitelists(
9703b57e008b61dfcb1fbad3aea950ae0e001748b0Torne (Richard Coles)    ScopedVector<SupervisedUserSiteList> site_lists) {
9803b57e008b61dfcb1fbad3aea950ae0e001748b0Torne (Richard Coles)  // SupervisedUserURLFilter::LoadWhitelists takes ownership of |site_lists|,
9903b57e008b61dfcb1fbad3aea950ae0e001748b0Torne (Richard Coles)  // so we make an additional copy of it.
10003b57e008b61dfcb1fbad3aea950ae0e001748b0Torne (Richard Coles)  /// TODO(bauerb): This is kinda ugly.
10103b57e008b61dfcb1fbad3aea950ae0e001748b0Torne (Richard Coles)  ScopedVector<SupervisedUserSiteList> site_lists_copy;
10203b57e008b61dfcb1fbad3aea950ae0e001748b0Torne (Richard Coles)  for (ScopedVector<SupervisedUserSiteList>::iterator it = site_lists.begin();
10303b57e008b61dfcb1fbad3aea950ae0e001748b0Torne (Richard Coles)       it != site_lists.end(); ++it) {
10403b57e008b61dfcb1fbad3aea950ae0e001748b0Torne (Richard Coles)    site_lists_copy.push_back((*it)->Clone());
10503b57e008b61dfcb1fbad3aea950ae0e001748b0Torne (Richard Coles)  }
10603b57e008b61dfcb1fbad3aea950ae0e001748b0Torne (Richard Coles)  ui_url_filter_->LoadWhitelists(site_lists.Pass());
10703b57e008b61dfcb1fbad3aea950ae0e001748b0Torne (Richard Coles)  BrowserThread::PostTask(
10803b57e008b61dfcb1fbad3aea950ae0e001748b0Torne (Richard Coles)      BrowserThread::IO,
10903b57e008b61dfcb1fbad3aea950ae0e001748b0Torne (Richard Coles)      FROM_HERE,
11003b57e008b61dfcb1fbad3aea950ae0e001748b0Torne (Richard Coles)      base::Bind(&SupervisedUserURLFilter::LoadWhitelists,
11103b57e008b61dfcb1fbad3aea950ae0e001748b0Torne (Richard Coles)                 io_url_filter_, base::Passed(&site_lists_copy)));
11203b57e008b61dfcb1fbad3aea950ae0e001748b0Torne (Richard Coles)}
11303b57e008b61dfcb1fbad3aea950ae0e001748b0Torne (Richard Coles)
11403b57e008b61dfcb1fbad3aea950ae0e001748b0Torne (Richard Coles)void SupervisedUserService::URLFilterContext::SetManualHosts(
11503b57e008b61dfcb1fbad3aea950ae0e001748b0Torne (Richard Coles)    scoped_ptr<std::map<std::string, bool> > host_map) {
11603b57e008b61dfcb1fbad3aea950ae0e001748b0Torne (Richard Coles)  ui_url_filter_->SetManualHosts(host_map.get());
11703b57e008b61dfcb1fbad3aea950ae0e001748b0Torne (Richard Coles)  BrowserThread::PostTask(
11803b57e008b61dfcb1fbad3aea950ae0e001748b0Torne (Richard Coles)      BrowserThread::IO,
11903b57e008b61dfcb1fbad3aea950ae0e001748b0Torne (Richard Coles)      FROM_HERE,
12003b57e008b61dfcb1fbad3aea950ae0e001748b0Torne (Richard Coles)      base::Bind(&SupervisedUserURLFilter::SetManualHosts,
12103b57e008b61dfcb1fbad3aea950ae0e001748b0Torne (Richard Coles)                 io_url_filter_, base::Owned(host_map.release())));
12203b57e008b61dfcb1fbad3aea950ae0e001748b0Torne (Richard Coles)}
12303b57e008b61dfcb1fbad3aea950ae0e001748b0Torne (Richard Coles)
12403b57e008b61dfcb1fbad3aea950ae0e001748b0Torne (Richard Coles)void SupervisedUserService::URLFilterContext::SetManualURLs(
12503b57e008b61dfcb1fbad3aea950ae0e001748b0Torne (Richard Coles)    scoped_ptr<std::map<GURL, bool> > url_map) {
12603b57e008b61dfcb1fbad3aea950ae0e001748b0Torne (Richard Coles)  ui_url_filter_->SetManualURLs(url_map.get());
127c5cede9ae108bb15f6b7a8aea21c7e1fefa2834cBen Murdoch  BrowserThread::PostTask(
128c5cede9ae108bb15f6b7a8aea21c7e1fefa2834cBen Murdoch      BrowserThread::IO,
129c5cede9ae108bb15f6b7a8aea21c7e1fefa2834cBen Murdoch      FROM_HERE,
130c5cede9ae108bb15f6b7a8aea21c7e1fefa2834cBen Murdoch      base::Bind(&SupervisedUserURLFilter::SetManualURLs,
131c5cede9ae108bb15f6b7a8aea21c7e1fefa2834cBen Murdoch                 io_url_filter_, base::Owned(url_map.release())));
132c5cede9ae108bb15f6b7a8aea21c7e1fefa2834cBen Murdoch}
133c5cede9ae108bb15f6b7a8aea21c7e1fefa2834cBen Murdoch
134c5cede9ae108bb15f6b7a8aea21c7e1fefa2834cBen MurdochSupervisedUserService::SupervisedUserService(Profile* profile)
135c5cede9ae108bb15f6b7a8aea21c7e1fefa2834cBen Murdoch    : profile_(profile),
136c5cede9ae108bb15f6b7a8aea21c7e1fefa2834cBen Murdoch      active_(false),
137c5cede9ae108bb15f6b7a8aea21c7e1fefa2834cBen Murdoch      delegate_(NULL),
138c5cede9ae108bb15f6b7a8aea21c7e1fefa2834cBen Murdoch#if defined(ENABLE_EXTENSIONS)
139c5cede9ae108bb15f6b7a8aea21c7e1fefa2834cBen Murdoch      extension_registry_observer_(this),
140c5cede9ae108bb15f6b7a8aea21c7e1fefa2834cBen Murdoch#endif
141c5cede9ae108bb15f6b7a8aea21c7e1fefa2834cBen Murdoch      waiting_for_sync_initialization_(false),
142      is_profile_active_(false),
143      elevated_for_testing_(false),
144      did_shutdown_(false),
145      waiting_for_permissions_(false),
146      weak_ptr_factory_(this) {
147}
148
149SupervisedUserService::~SupervisedUserService() {
150  DCHECK(did_shutdown_);
151}
152
153void SupervisedUserService::Shutdown() {
154  did_shutdown_ = true;
155  if (ProfileIsSupervised()) {
156    content::RecordAction(UserMetricsAction("ManagedUsers_QuitBrowser"));
157  }
158  SetActive(false);
159}
160
161bool SupervisedUserService::ProfileIsSupervised() const {
162  return profile_->IsSupervised();
163}
164
165// static
166void SupervisedUserService::RegisterProfilePrefs(
167    user_prefs::PrefRegistrySyncable* registry) {
168  registry->RegisterDictionaryPref(
169      prefs::kSupervisedUserManualHosts,
170      user_prefs::PrefRegistrySyncable::UNSYNCABLE_PREF);
171  registry->RegisterDictionaryPref(
172      prefs::kSupervisedUserManualURLs,
173      user_prefs::PrefRegistrySyncable::UNSYNCABLE_PREF);
174  registry->RegisterIntegerPref(
175      prefs::kDefaultSupervisedUserFilteringBehavior,
176      SupervisedUserURLFilter::ALLOW,
177      user_prefs::PrefRegistrySyncable::UNSYNCABLE_PREF);
178  registry->RegisterStringPref(
179      prefs::kSupervisedUserCustodianEmail, std::string(),
180      user_prefs::PrefRegistrySyncable::UNSYNCABLE_PREF);
181  registry->RegisterStringPref(
182      prefs::kSupervisedUserCustodianName, std::string(),
183      user_prefs::PrefRegistrySyncable::UNSYNCABLE_PREF);
184  registry->RegisterBooleanPref(prefs::kSupervisedUserCreationAllowed, true,
185      user_prefs::PrefRegistrySyncable::UNSYNCABLE_PREF);
186}
187
188void SupervisedUserService::SetDelegate(Delegate* delegate) {
189  if (delegate_ == delegate)
190    return;
191  // If the delegate changed, deactivate first to give the old delegate a chance
192  // to clean up.
193  SetActive(false);
194  delegate_ = delegate;
195}
196
197scoped_refptr<const SupervisedUserURLFilter>
198SupervisedUserService::GetURLFilterForIOThread() {
199  return url_filter_context_.io_url_filter();
200}
201
202SupervisedUserURLFilter* SupervisedUserService::GetURLFilterForUIThread() {
203  return url_filter_context_.ui_url_filter();
204}
205
206// Items not on any list must return -1 (CATEGORY_NOT_ON_LIST in history.js).
207// Items on a list, but with no category, must return 0 (CATEGORY_OTHER).
208#define CATEGORY_NOT_ON_LIST -1;
209#define CATEGORY_OTHER 0;
210
211int SupervisedUserService::GetCategory(const GURL& url) {
212  std::vector<SupervisedUserSiteList::Site*> sites;
213  GetURLFilterForUIThread()->GetSites(url, &sites);
214  if (sites.empty())
215    return CATEGORY_NOT_ON_LIST;
216
217  return (*sites.begin())->category_id;
218}
219
220// static
221void SupervisedUserService::GetCategoryNames(CategoryList* list) {
222  SupervisedUserSiteList::GetCategoryNames(list);
223}
224
225std::string SupervisedUserService::GetCustodianEmailAddress() const {
226#if defined(OS_CHROMEOS)
227  return chromeos::UserManager::Get()->GetSupervisedUserManager()->
228      GetManagerDisplayEmail(
229          chromeos::UserManager::Get()->GetActiveUser()->email());
230#else
231  return profile_->GetPrefs()->GetString(prefs::kSupervisedUserCustodianEmail);
232#endif
233}
234
235std::string SupervisedUserService::GetCustodianName() const {
236#if defined(OS_CHROMEOS)
237  return base::UTF16ToUTF8(chromeos::UserManager::Get()->
238      GetSupervisedUserManager()->GetManagerDisplayName(
239          chromeos::UserManager::Get()->GetActiveUser()->email()));
240#else
241  std::string name = profile_->GetPrefs()->GetString(
242      prefs::kSupervisedUserCustodianName);
243  return name.empty() ? GetCustodianEmailAddress() : name;
244#endif
245}
246
247void SupervisedUserService::AddNavigationBlockedCallback(
248    const NavigationBlockedCallback& callback) {
249  navigation_blocked_callbacks_.push_back(callback);
250}
251
252void SupervisedUserService::DidBlockNavigation(
253    content::WebContents* web_contents) {
254  for (std::vector<NavigationBlockedCallback>::iterator it =
255           navigation_blocked_callbacks_.begin();
256       it != navigation_blocked_callbacks_.end(); ++it) {
257    it->Run(web_contents);
258  }
259}
260
261#if defined(ENABLE_EXTENSIONS)
262std::string SupervisedUserService::GetDebugPolicyProviderName() const {
263  // Save the string space in official builds.
264#ifdef NDEBUG
265  NOTREACHED();
266  return std::string();
267#else
268  return "Supervised User Service";
269#endif
270}
271
272bool SupervisedUserService::UserMayLoad(const extensions::Extension* extension,
273                                        base::string16* error) const {
274  base::string16 tmp_error;
275  if (ExtensionManagementPolicyImpl(extension, &tmp_error))
276    return true;
277
278  // If the extension is already loaded, we allow it, otherwise we'd unload
279  // all existing extensions.
280  ExtensionService* extension_service =
281      extensions::ExtensionSystem::Get(profile_)->extension_service();
282
283  // |extension_service| can be NULL in a unit test.
284  if (extension_service &&
285      extension_service->GetInstalledExtension(extension->id()))
286    return true;
287
288  bool was_installed_by_default = extension->was_installed_by_default();
289  bool was_installed_by_custodian = extension->was_installed_by_custodian();
290#if defined(OS_CHROMEOS)
291  // On Chrome OS all external sources are controlled by us so it means that
292  // they are "default". Method was_installed_by_default returns false because
293  // extensions creation flags are ignored in case of default extensions with
294  // update URL(the flags aren't passed to OnExternalExtensionUpdateUrlFound).
295  // TODO(dpolukhin): remove this Chrome OS specific code as soon as creation
296  // flags are not ignored.
297  was_installed_by_default =
298      extensions::Manifest::IsExternalLocation(extension->location());
299#endif
300  if (extension->location() == extensions::Manifest::COMPONENT ||
301      was_installed_by_default ||
302      was_installed_by_custodian) {
303    return true;
304  }
305
306  if (error)
307    *error = tmp_error;
308  return false;
309}
310
311bool SupervisedUserService::UserMayModifySettings(
312    const extensions::Extension* extension,
313    base::string16* error) const {
314  return ExtensionManagementPolicyImpl(extension, error);
315}
316
317void SupervisedUserService::OnExtensionLoaded(
318    content::BrowserContext* browser_context,
319    const extensions::Extension* extension) {
320  if (!extensions::SupervisedUserInfo::GetContentPackSiteList(extension)
321           .empty()) {
322    UpdateSiteLists();
323  }
324}
325void SupervisedUserService::OnExtensionUnloaded(
326    content::BrowserContext* browser_context,
327    const extensions::Extension* extension,
328    extensions::UnloadedExtensionInfo::Reason reason) {
329  if (!extensions::SupervisedUserInfo::GetContentPackSiteList(extension)
330           .empty()) {
331    UpdateSiteLists();
332  }
333}
334#endif  // defined(ENABLE_EXTENSIONS)
335
336void SupervisedUserService::OnStateChanged() {
337  ProfileSyncService* service =
338      ProfileSyncServiceFactory::GetForProfile(profile_);
339  if (waiting_for_sync_initialization_ && service->sync_initialized()) {
340    waiting_for_sync_initialization_ = false;
341    service->RemoveObserver(this);
342    FinishSetupSync();
343    return;
344  }
345
346  DLOG_IF(ERROR, service->GetAuthError().state() ==
347                     GoogleServiceAuthError::INVALID_GAIA_CREDENTIALS)
348      << "Credentials rejected";
349}
350
351void SupervisedUserService::SetupSync() {
352  StartSetupSync();
353  FinishSetupSyncWhenReady();
354}
355
356void SupervisedUserService::StartSetupSync() {
357  // Tell the sync service that setup is in progress so we don't start syncing
358  // until we've finished configuration.
359  ProfileSyncServiceFactory::GetForProfile(profile_)->SetSetupInProgress(true);
360}
361
362void SupervisedUserService::FinishSetupSyncWhenReady() {
363  // If we're already waiting for the Sync backend, there's nothing to do here.
364  if (waiting_for_sync_initialization_)
365    return;
366
367  // Continue in FinishSetupSync() once the Sync backend has been initialized.
368  ProfileSyncService* service =
369      ProfileSyncServiceFactory::GetForProfile(profile_);
370  if (service->sync_initialized()) {
371    FinishSetupSync();
372  } else {
373    service->AddObserver(this);
374    waiting_for_sync_initialization_ = true;
375  }
376}
377
378void SupervisedUserService::FinishSetupSync() {
379  ProfileSyncService* service =
380      ProfileSyncServiceFactory::GetForProfile(profile_);
381  DCHECK(service->sync_initialized());
382
383  bool sync_everything = false;
384  syncer::ModelTypeSet synced_datatypes;
385  synced_datatypes.Put(syncer::SESSIONS);
386  service->OnUserChoseDatatypes(sync_everything, synced_datatypes);
387
388  // Notify ProfileSyncService that we are done with configuration.
389  service->SetSetupInProgress(false);
390  service->SetSyncSetupCompleted();
391}
392
393#if defined(ENABLE_EXTENSIONS)
394bool SupervisedUserService::ExtensionManagementPolicyImpl(
395    const extensions::Extension* extension,
396    base::string16* error) const {
397  // |extension| can be NULL in unit_tests.
398  if (!ProfileIsSupervised() || (extension && extension->is_theme()))
399    return true;
400
401  if (elevated_for_testing_)
402    return true;
403
404  if (error)
405    *error = l10n_util::GetStringUTF16(IDS_EXTENSIONS_LOCKED_SUPERVISED_USER);
406  return false;
407}
408
409ScopedVector<SupervisedUserSiteList>
410SupervisedUserService::GetActiveSiteLists() {
411  ScopedVector<SupervisedUserSiteList> site_lists;
412  ExtensionService* extension_service =
413      extensions::ExtensionSystem::Get(profile_)->extension_service();
414  // Can be NULL in unit tests.
415  if (!extension_service)
416    return site_lists.Pass();
417
418  const extensions::ExtensionSet* extensions = extension_service->extensions();
419  for (extensions::ExtensionSet::const_iterator it = extensions->begin();
420       it != extensions->end(); ++it) {
421    const extensions::Extension* extension = it->get();
422    if (!extension_service->IsExtensionEnabled(extension->id()))
423      continue;
424
425    extensions::ExtensionResource site_list =
426        extensions::SupervisedUserInfo::GetContentPackSiteList(extension);
427    if (!site_list.empty()) {
428      site_lists.push_back(new SupervisedUserSiteList(extension->id(),
429                                                      site_list.GetFilePath()));
430    }
431  }
432
433  return site_lists.Pass();
434}
435
436void SupervisedUserService::SetExtensionsActive() {
437  extensions::ExtensionSystem* extension_system =
438      extensions::ExtensionSystem::Get(profile_);
439  extensions::ManagementPolicy* management_policy =
440      extension_system->management_policy();
441
442  if (active_) {
443    if (management_policy)
444      management_policy->RegisterProvider(this);
445
446    extension_registry_observer_.Add(
447        extensions::ExtensionRegistry::Get(profile_));
448  } else {
449    if (management_policy)
450      management_policy->UnregisterProvider(this);
451
452    extension_registry_observer_.RemoveAll();
453  }
454}
455#endif  // defined(ENABLE_EXTENSIONS)
456
457SupervisedUserSettingsService* SupervisedUserService::GetSettingsService() {
458  return SupervisedUserSettingsServiceFactory::GetForProfile(profile_);
459}
460
461void SupervisedUserService::OnSupervisedUserIdChanged() {
462  std::string supervised_user_id =
463      profile_->GetPrefs()->GetString(prefs::kSupervisedUserId);
464  SetActive(!supervised_user_id.empty());
465}
466
467void SupervisedUserService::OnDefaultFilteringBehaviorChanged() {
468  DCHECK(ProfileIsSupervised());
469
470  int behavior_value = profile_->GetPrefs()->GetInteger(
471      prefs::kDefaultSupervisedUserFilteringBehavior);
472  SupervisedUserURLFilter::FilteringBehavior behavior =
473      SupervisedUserURLFilter::BehaviorFromInt(behavior_value);
474  url_filter_context_.SetDefaultFilteringBehavior(behavior);
475}
476
477void SupervisedUserService::UpdateSiteLists() {
478#if defined(ENABLE_EXTENSIONS)
479  url_filter_context_.LoadWhitelists(GetActiveSiteLists());
480#endif
481}
482
483bool SupervisedUserService::AccessRequestsEnabled() {
484  if (waiting_for_permissions_)
485    return false;
486
487  ProfileSyncService* service =
488      ProfileSyncServiceFactory::GetForProfile(profile_);
489  GoogleServiceAuthError::State state = service->GetAuthError().state();
490  // We allow requesting access if Sync is working or has a transient error.
491  return (state == GoogleServiceAuthError::NONE ||
492          state == GoogleServiceAuthError::CONNECTION_FAILED ||
493          state == GoogleServiceAuthError::SERVICE_UNAVAILABLE);
494}
495
496void SupervisedUserService::OnPermissionRequestIssued() {
497  waiting_for_permissions_ = false;
498  // TODO(akuegel): Figure out how to show the result of issuing the permission
499  // request in the UI. Currently, we assume the permission request was created
500  // successfully.
501}
502
503void SupervisedUserService::AddAccessRequest(const GURL& url) {
504  // Normalize the URL.
505  GURL normalized_url = SupervisedUserURLFilter::Normalize(url);
506
507  // Escape the URL.
508  std::string output(net::EscapeQueryParamValue(normalized_url.spec(), true));
509
510  waiting_for_permissions_ = true;
511  permissions_creator_->CreatePermissionRequest(
512      output,
513      base::Bind(&SupervisedUserService::OnPermissionRequestIssued,
514                 weak_ptr_factory_.GetWeakPtr()));
515}
516
517SupervisedUserService::ManualBehavior
518SupervisedUserService::GetManualBehaviorForHost(
519    const std::string& hostname) {
520  const base::DictionaryValue* dict =
521      profile_->GetPrefs()->GetDictionary(prefs::kSupervisedUserManualHosts);
522  bool allow = false;
523  if (!dict->GetBooleanWithoutPathExpansion(hostname, &allow))
524    return MANUAL_NONE;
525
526  return allow ? MANUAL_ALLOW : MANUAL_BLOCK;
527}
528
529SupervisedUserService::ManualBehavior
530SupervisedUserService::GetManualBehaviorForURL(
531    const GURL& url) {
532  const base::DictionaryValue* dict =
533      profile_->GetPrefs()->GetDictionary(prefs::kSupervisedUserManualURLs);
534  GURL normalized_url = SupervisedUserURLFilter::Normalize(url);
535  bool allow = false;
536  if (!dict->GetBooleanWithoutPathExpansion(normalized_url.spec(), &allow))
537    return MANUAL_NONE;
538
539  return allow ? MANUAL_ALLOW : MANUAL_BLOCK;
540}
541
542void SupervisedUserService::GetManualExceptionsForHost(
543    const std::string& host,
544    std::vector<GURL>* urls) {
545  const base::DictionaryValue* dict =
546      profile_->GetPrefs()->GetDictionary(prefs::kSupervisedUserManualURLs);
547  for (base::DictionaryValue::Iterator it(*dict); !it.IsAtEnd(); it.Advance()) {
548    GURL url(it.key());
549    if (url.host() == host)
550      urls->push_back(url);
551  }
552}
553
554void SupervisedUserService::InitSync(const std::string& refresh_token) {
555  StartSetupSync();
556
557  ProfileOAuth2TokenService* token_service =
558      ProfileOAuth2TokenServiceFactory::GetForProfile(profile_);
559  token_service->UpdateCredentials(supervised_users::kSupervisedUserPseudoEmail,
560                                   refresh_token);
561
562  FinishSetupSyncWhenReady();
563}
564
565void SupervisedUserService::Init() {
566  DCHECK(GetSettingsService()->IsReady());
567
568  pref_change_registrar_.Init(profile_->GetPrefs());
569  pref_change_registrar_.Add(
570      prefs::kSupervisedUserId,
571      base::Bind(&SupervisedUserService::OnSupervisedUserIdChanged,
572          base::Unretained(this)));
573
574  SetActive(ProfileIsSupervised());
575}
576
577void SupervisedUserService::SetActive(bool active) {
578  if (active_ == active)
579    return;
580  active_ = active;
581
582  if (!delegate_ || !delegate_->SetActive(active_)) {
583    if (active_) {
584      SupervisedUserPrefMappingServiceFactory::GetForBrowserContext(profile_)
585          ->Init();
586
587      CommandLine* command_line = CommandLine::ForCurrentProcess();
588      if (command_line->HasSwitch(switches::kSupervisedUserSyncToken)) {
589        InitSync(
590            command_line->GetSwitchValueASCII(
591                switches::kSupervisedUserSyncToken));
592      }
593
594      ProfileOAuth2TokenService* token_service =
595          ProfileOAuth2TokenServiceFactory::GetForProfile(profile_);
596      token_service->LoadCredentials(
597          supervised_users::kSupervisedUserPseudoEmail);
598
599      SetupSync();
600    }
601  }
602
603  // Now activate/deactivate anything not handled by the delegate yet.
604
605#if defined(ENABLE_THEMES)
606  // Re-set the default theme to turn the SU theme on/off.
607  ThemeService* theme_service = ThemeServiceFactory::GetForProfile(profile_);
608  if (theme_service->UsingDefaultTheme() || theme_service->UsingSystemTheme()) {
609    ThemeServiceFactory::GetForProfile(profile_)->UseDefaultTheme();
610  }
611#endif
612
613  SupervisedUserSettingsService* settings_service = GetSettingsService();
614  settings_service->SetActive(active_);
615
616#if defined(ENABLE_EXTENSIONS)
617  SetExtensionsActive();
618#endif
619
620  if (active_) {
621    if (CommandLine::ForCurrentProcess()->HasSwitch(
622            switches::kPermissionRequestApiUrl)) {
623      permissions_creator_ =
624          PermissionRequestCreatorApiary::CreateWithProfile(profile_);
625    } else {
626      PrefService* pref_service = profile_->GetPrefs();
627      permissions_creator_.reset(new PermissionRequestCreatorSync(
628          settings_service,
629          SupervisedUserSharedSettingsServiceFactory::GetForBrowserContext(
630              profile_),
631          pref_service->GetString(prefs::kProfileName),
632          pref_service->GetString(prefs::kSupervisedUserId)));
633    }
634
635    pref_change_registrar_.Add(
636        prefs::kDefaultSupervisedUserFilteringBehavior,
637        base::Bind(&SupervisedUserService::OnDefaultFilteringBehaviorChanged,
638            base::Unretained(this)));
639    pref_change_registrar_.Add(prefs::kSupervisedUserManualHosts,
640        base::Bind(&SupervisedUserService::UpdateManualHosts,
641                   base::Unretained(this)));
642    pref_change_registrar_.Add(prefs::kSupervisedUserManualURLs,
643        base::Bind(&SupervisedUserService::UpdateManualURLs,
644                   base::Unretained(this)));
645
646    // Initialize the filter.
647    OnDefaultFilteringBehaviorChanged();
648    UpdateSiteLists();
649    UpdateManualHosts();
650    UpdateManualURLs();
651
652#if !defined(OS_ANDROID)
653    // TODO(bauerb): Get rid of the platform-specific #ifdef here.
654    // http://crbug.com/313377
655    BrowserList::AddObserver(this);
656#endif
657  } else {
658    permissions_creator_.reset();
659
660    pref_change_registrar_.Remove(
661        prefs::kDefaultSupervisedUserFilteringBehavior);
662    pref_change_registrar_.Remove(prefs::kSupervisedUserManualHosts);
663    pref_change_registrar_.Remove(prefs::kSupervisedUserManualURLs);
664
665    if (waiting_for_sync_initialization_) {
666      ProfileSyncService* sync_service =
667          ProfileSyncServiceFactory::GetForProfile(profile_);
668      sync_service->RemoveObserver(this);
669    }
670
671#if !defined(OS_ANDROID)
672    // TODO(bauerb): Get rid of the platform-specific #ifdef here.
673    // http://crbug.com/313377
674    BrowserList::RemoveObserver(this);
675#endif
676  }
677}
678
679void SupervisedUserService::RegisterAndInitSync(
680    SupervisedUserRegistrationUtility* registration_utility,
681    Profile* custodian_profile,
682    const std::string& supervised_user_id,
683    const AuthErrorCallback& callback) {
684  DCHECK(ProfileIsSupervised());
685  DCHECK(!custodian_profile->IsSupervised());
686
687  base::string16 name = base::UTF8ToUTF16(
688      profile_->GetPrefs()->GetString(prefs::kProfileName));
689  int avatar_index = profile_->GetPrefs()->GetInteger(
690      prefs::kProfileAvatarIndex);
691  SupervisedUserRegistrationInfo info(name, avatar_index);
692  registration_utility->Register(
693      supervised_user_id,
694      info,
695      base::Bind(&SupervisedUserService::OnSupervisedUserRegistered,
696                 weak_ptr_factory_.GetWeakPtr(), callback, custodian_profile));
697
698  // Fetch the custodian's profile information, to store the name.
699  // TODO(pamg): If --google-profile-info (flag: switches::kGoogleProfileInfo)
700  // is ever enabled, take the name from the ProfileInfoCache instead.
701  CustodianProfileDownloaderService* profile_downloader_service =
702      CustodianProfileDownloaderServiceFactory::GetForProfile(
703          custodian_profile);
704  profile_downloader_service->DownloadProfile(
705      base::Bind(&SupervisedUserService::OnCustodianProfileDownloaded,
706                 weak_ptr_factory_.GetWeakPtr()));
707}
708
709void SupervisedUserService::OnCustodianProfileDownloaded(
710    const base::string16& full_name) {
711  profile_->GetPrefs()->SetString(prefs::kSupervisedUserCustodianName,
712                                  base::UTF16ToUTF8(full_name));
713}
714
715void SupervisedUserService::OnSupervisedUserRegistered(
716    const AuthErrorCallback& callback,
717    Profile* custodian_profile,
718    const GoogleServiceAuthError& auth_error,
719    const std::string& token) {
720  if (auth_error.state() == GoogleServiceAuthError::NONE) {
721    InitSync(token);
722    SigninManagerBase* signin =
723        SigninManagerFactory::GetForProfile(custodian_profile);
724    profile_->GetPrefs()->SetString(prefs::kSupervisedUserCustodianEmail,
725                                    signin->GetAuthenticatedUsername());
726
727    // The supervised user profile is now ready for use.
728    ProfileManager* profile_manager = g_browser_process->profile_manager();
729    ProfileInfoCache& cache = profile_manager->GetProfileInfoCache();
730    size_t index = cache.GetIndexOfProfileWithPath(profile_->GetPath());
731    cache.SetIsOmittedProfileAtIndex(index, false);
732  } else {
733    DCHECK_EQ(std::string(), token);
734  }
735
736  callback.Run(auth_error);
737}
738
739void SupervisedUserService::UpdateManualHosts() {
740  const base::DictionaryValue* dict =
741      profile_->GetPrefs()->GetDictionary(prefs::kSupervisedUserManualHosts);
742  scoped_ptr<std::map<std::string, bool> > host_map(
743      new std::map<std::string, bool>());
744  for (base::DictionaryValue::Iterator it(*dict); !it.IsAtEnd(); it.Advance()) {
745    bool allow = false;
746    bool result = it.value().GetAsBoolean(&allow);
747    DCHECK(result);
748    (*host_map)[it.key()] = allow;
749  }
750  url_filter_context_.SetManualHosts(host_map.Pass());
751}
752
753void SupervisedUserService::UpdateManualURLs() {
754  const base::DictionaryValue* dict =
755      profile_->GetPrefs()->GetDictionary(prefs::kSupervisedUserManualURLs);
756  scoped_ptr<std::map<GURL, bool> > url_map(new std::map<GURL, bool>());
757  for (base::DictionaryValue::Iterator it(*dict); !it.IsAtEnd(); it.Advance()) {
758    bool allow = false;
759    bool result = it.value().GetAsBoolean(&allow);
760    DCHECK(result);
761    (*url_map)[GURL(it.key())] = allow;
762  }
763  url_filter_context_.SetManualURLs(url_map.Pass());
764}
765
766void SupervisedUserService::OnBrowserSetLastActive(Browser* browser) {
767  bool profile_became_active = profile_->IsSameProfile(browser->profile());
768  if (!is_profile_active_ && profile_became_active)
769    content::RecordAction(UserMetricsAction("ManagedUsers_OpenProfile"));
770  else if (is_profile_active_ && !profile_became_active)
771    content::RecordAction(UserMetricsAction("ManagedUsers_SwitchProfile"));
772
773  is_profile_active_ = profile_became_active;
774}
775