blob: 58d8a1cf9f8e64341e4ea5103b8fe2859f42a6e6 [file] [log] [blame]
[email protected]cce15bb2014-06-17 13:43:511// Copyright 2014 The Chromium Authors. All rights reserved.
[email protected]0850e842013-01-19 03:44:312// Use of this source code is governed by a BSD-style license that can be
3// found in the LICENSE file.
4
[email protected]cce15bb2014-06-17 13:43:515#include "chrome/browser/supervised_user/supervised_user_service.h"
[email protected]0850e842013-01-19 03:44:316
Caio6d256c332019-03-22 15:25:567#include <set>
dchenge73d8520c2015-12-27 01:19:098#include <utility>
9
Sebastien Marchandf1349f52019-01-25 03:16:4110#include "base/bind.h"
mamire9609642016-06-28 22:17:5411#include "base/feature_list.h"
treibdaece84f2014-09-05 12:58:1512#include "base/files/file_path.h"
treib2fd187392015-04-16 17:19:3813#include "base/files/file_util.h"
Marc Treib9d91df552018-09-27 14:55:5514#include "base/memory/scoped_refptr.h"
bratell0a7406f2017-03-28 07:46:3715#include "base/metrics/user_metrics.h"
treibd3f8b7a2015-04-10 11:41:3316#include "base/path_service.h"
treib40d3ad92015-10-20 18:15:4217#include "base/strings/stringprintf.h"
[email protected]112158af2013-06-07 23:46:1818#include "base/strings/utf_string_conversions.h"
Gabriel Charette44db1422018-08-06 11:19:3319#include "base/task/post_task.h"
treibf832a992015-03-24 18:09:2420#include "base/version.h"
avi664c07b2015-12-26 02:18:3121#include "build/build_config.h"
[email protected]5ddfade2014-02-03 10:24:5322#include "chrome/browser/browser_process.h"
bauerb4da36132014-12-26 19:53:1323#include "chrome/browser/component_updater/supervised_user_whitelist_installer.h"
[email protected]0850e842013-01-19 03:44:3124#include "chrome/browser/profiles/profile.h"
Mario Sanchez Prada77f113c2019-02-01 09:33:5525#include "chrome/browser/signin/identity_manager_factory.h"
treibe2082a0e2015-04-08 10:15:3026#include "chrome/browser/supervised_user/experimental/supervised_user_filtering_switches.h"
bauerb5f8cda92015-10-07 15:36:4427#include "chrome/browser/supervised_user/permission_request_creator.h"
[email protected]cce15bb2014-06-17 13:43:5128#include "chrome/browser/supervised_user/supervised_user_constants.h"
mamire9609642016-06-28 22:17:5429#include "chrome/browser/supervised_user/supervised_user_features.h"
30#include "chrome/browser/supervised_user/supervised_user_service_factory.h"
treibab0a39e2014-09-24 14:48:2831#include "chrome/browser/supervised_user/supervised_user_service_observer.h"
[email protected]cce15bb2014-06-17 13:43:5132#include "chrome/browser/supervised_user/supervised_user_settings_service.h"
33#include "chrome/browser/supervised_user/supervised_user_settings_service_factory.h"
[email protected]cce15bb2014-06-17 13:43:5134#include "chrome/browser/supervised_user/supervised_user_site_list.h"
bauerb4da36132014-12-26 19:53:1335#include "chrome/browser/supervised_user/supervised_user_whitelist_service.h"
[email protected]509ad1a92013-03-19 21:41:0636#include "chrome/browser/ui/browser.h"
[email protected]dfddd022013-07-10 17:29:4837#include "chrome/browser/ui/browser_list.h"
treibd3f8b7a2015-04-10 11:41:3338#include "chrome/common/chrome_paths.h"
[email protected]0850e842013-01-19 03:44:3139#include "chrome/common/pref_names.h"
[email protected]af39f002014-08-22 10:18:1840#include "chrome/grit/generated_resources.h"
Michael Giuffrida0fe58bf2018-07-26 20:40:2741#include "components/policy/core/browser/url_util.h"
[email protected]f0c8c4992014-05-15 17:37:2642#include "components/pref_registry/pref_registry_syncable.h"
brettwb1fc1b82016-02-02 00:19:0843#include "components/prefs/pref_service.h"
Mark Pilgrima8b7f432018-04-19 23:23:0044#include "content/public/browser/browser_context.h"
Mark Pilgrima8b7f432018-04-19 23:23:0045#include "content/public/browser/storage_partition.h"
Scott Violetc8240b02018-03-08 22:03:5946#include "extensions/buildflags/buildflags.h"
rhalavati5f1caa2b2017-02-25 08:22:1647#include "net/traffic_annotation/network_traffic_annotation.h"
Mario Sanchez Prada77f113c2019-02-01 09:33:5548#include "services/identity/public/cpp/accounts_mutator.h"
49#include "services/identity/public/cpp/identity_manager.h"
Mark Pilgrimb67362ed2018-05-15 15:59:4750#include "services/network/public/cpp/shared_url_loader_factory.h"
[email protected]0850e842013-01-19 03:44:3151#include "ui/base/l10n/l10n_util.h"
52
jam1c5a91492016-02-24 20:47:5353#if !defined(OS_ANDROID)
brettw9b0866f2016-12-11 02:34:0654#include "chrome/browser/themes/theme_service.h"
55#include "chrome/browser/themes/theme_service_factory.h"
thestig1b76f1a2015-09-30 22:52:3856#endif
57
[email protected]3aacc9c2013-08-08 11:19:3158#if defined(OS_CHROMEOS)
[email protected]4d390782014-08-15 09:22:5859#include "chrome/browser/chromeos/login/users/chrome_user_manager.h"
[email protected]83d82d42014-05-16 02:04:4260#include "chrome/browser/chromeos/login/users/supervised_user_manager.h"
[email protected]4d390782014-08-15 09:22:5861#include "components/user_manager/user_manager.h"
[email protected]3aacc9c2013-08-08 11:19:3162#endif
63
brettw00899e62016-11-12 02:10:1764#if BUILDFLAG(ENABLE_EXTENSIONS)
treib9e30e302015-04-15 08:12:1665#include "chrome/browser/extensions/extension_service.h"
mamir192d7882016-06-22 17:10:1666#include "chrome/browser/extensions/extension_util.h"
67#include "extensions/browser/extension_prefs.h"
mamire9609642016-06-28 22:17:5468#include "extensions/browser/extension_registry.h"
[email protected]c14a6802014-07-11 21:51:1269#include "extensions/browser/extension_system.h"
[email protected]c14a6802014-07-11 21:51:1270#endif
71
[email protected]2056c3b2014-04-07 18:08:5072using base::UserMetricsAction;
[email protected]0850e842013-01-19 03:44:3173
brettw00899e62016-11-12 02:10:1774#if BUILDFLAG(ENABLE_EXTENSIONS)
mamire9609642016-06-28 22:17:5475using extensions::Extension;
76using extensions::ExtensionPrefs;
77using extensions::ExtensionRegistry;
78using extensions::ExtensionSystem;
79#endif
80
treib22c3a042015-01-15 21:30:1381namespace {
82
treibd3f8b7a2015-04-10 11:41:3383// The URL from which to download a host blacklist if no local one exists yet.
84const char kBlacklistURL[] =
85 "https://www.gstatic.com/chrome/supervised_user/blacklist-20141001-1k.bin";
86// The filename under which we'll store the blacklist (in the user data dir).
87const char kBlacklistFilename[] = "su-blacklist.bin";
88
treib22c3a042015-01-15 21:30:1389const char* const kCustodianInfoPrefs[] = {
90 prefs::kSupervisedUserCustodianName,
91 prefs::kSupervisedUserCustodianEmail,
92 prefs::kSupervisedUserCustodianProfileImageURL,
93 prefs::kSupervisedUserCustodianProfileURL,
94 prefs::kSupervisedUserSecondCustodianName,
95 prefs::kSupervisedUserSecondCustodianEmail,
96 prefs::kSupervisedUserSecondCustodianProfileImageURL,
97 prefs::kSupervisedUserSecondCustodianProfileURL,
98};
99
Carlos IL6b784a62018-03-20 00:26:49100void CreateURLAccessRequest(const GURL& url,
101 PermissionRequestCreator* creator,
102 SupervisedUserService::SuccessCallback callback) {
103 creator->CreateURLAccessRequest(url, std::move(callback));
treib8ecc1eb52015-03-04 18:29:06104}
105
mamire9609642016-06-28 22:17:54106void CreateExtensionInstallRequest(
107 const std::string& id,
108 PermissionRequestCreator* creator,
Carlos IL6b784a62018-03-20 00:26:49109 SupervisedUserService::SuccessCallback callback) {
110 creator->CreateExtensionInstallRequest(id, std::move(callback));
mamire9609642016-06-28 22:17:54111}
112
treib8ecc1eb52015-03-04 18:29:06113void CreateExtensionUpdateRequest(
treibf832a992015-03-24 18:09:24114 const std::string& id,
treib8ecc1eb52015-03-04 18:29:06115 PermissionRequestCreator* creator,
Carlos IL6b784a62018-03-20 00:26:49116 SupervisedUserService::SuccessCallback callback) {
117 creator->CreateExtensionUpdateRequest(id, std::move(callback));
treib8ecc1eb52015-03-04 18:29:06118}
119
mamire9609642016-06-28 22:17:54120// Default callback for AddExtensionInstallRequest.
121void ExtensionInstallRequestSent(const std::string& id, bool success) {
122 VLOG_IF(1, !success) << "Failed sending install request for " << id;
123}
124
treib40d3ad92015-10-20 18:15:42125// Default callback for AddExtensionUpdateRequest.
126void ExtensionUpdateRequestSent(const std::string& id, bool success) {
127 VLOG_IF(1, !success) << "Failed sending update request for " << id;
128}
129
treibd3f8b7a2015-04-10 11:41:33130base::FilePath GetBlacklistPath() {
131 base::FilePath blacklist_dir;
Avi Drissman9098f9002018-05-04 00:11:52132 base::PathService::Get(chrome::DIR_USER_DATA, &blacklist_dir);
treibd3f8b7a2015-04-10 11:41:33133 return blacklist_dir.AppendASCII(kBlacklistFilename);
134}
135
treib22c3a042015-01-15 21:30:13136} // namespace
137
bauerb5f8cda92015-10-07 15:36:44138SupervisedUserService::~SupervisedUserService() {
139 DCHECK(!did_init_ || did_shutdown_);
mmenkedb2637ff2017-03-30 23:59:42140 url_filter_.RemoveObserver(this);
bauerb5f8cda92015-10-07 15:36:44141}
142
143// static
144void SupervisedUserService::RegisterProfilePrefs(
145 user_prefs::PrefRegistrySyncable* registry) {
mamire9609642016-06-28 22:17:54146 registry->RegisterDictionaryPref(prefs::kSupervisedUserApprovedExtensions);
bauerb5f8cda92015-10-07 15:36:44147 registry->RegisterDictionaryPref(prefs::kSupervisedUserManualHosts);
148 registry->RegisterDictionaryPref(prefs::kSupervisedUserManualURLs);
149 registry->RegisterIntegerPref(prefs::kDefaultSupervisedUserFilteringBehavior,
150 SupervisedUserURLFilter::ALLOW);
bauerb5f8cda92015-10-07 15:36:44151 registry->RegisterBooleanPref(prefs::kSupervisedUserSafeSites, true);
152 for (const char* pref : kCustodianInfoPrefs) {
153 registry->RegisterStringPref(pref, std::string());
154 }
155}
156
157void SupervisedUserService::Init() {
158 DCHECK(!did_init_);
159 did_init_ = true;
160 DCHECK(GetSettingsService()->IsReady());
161
162 pref_change_registrar_.Init(profile_->GetPrefs());
163 pref_change_registrar_.Add(
164 prefs::kSupervisedUserId,
165 base::Bind(&SupervisedUserService::OnSupervisedUserIdChanged,
166 base::Unretained(this)));
bauerb5f8cda92015-10-07 15:36:44167
bauerb5f8cda92015-10-07 15:36:44168 whitelist_service_->AddSiteListsChangedCallback(
169 base::Bind(&SupervisedUserService::OnSiteListsChanged,
170 weak_ptr_factory_.GetWeakPtr()));
171
172 SetActive(ProfileIsSupervised());
173}
174
175void SupervisedUserService::SetDelegate(Delegate* delegate) {
176 if (delegate) {
177 // Changing delegates isn't allowed.
178 DCHECK(!delegate_);
179 } else {
180 // If the delegate is removed, deactivate first to give the old delegate a
181 // chance to clean up.
182 SetActive(false);
183 }
184 delegate_ = delegate;
185}
186
mmenkedb2637ff2017-03-30 23:59:42187SupervisedUserURLFilter* SupervisedUserService::GetURLFilter() {
188 return &url_filter_;
bauerb5f8cda92015-10-07 15:36:44189}
190
191SupervisedUserWhitelistService* SupervisedUserService::GetWhitelistService() {
192 return whitelist_service_.get();
193}
194
195bool SupervisedUserService::AccessRequestsEnabled() {
196 return FindEnabledPermissionRequestCreator(0) < permissions_creators_.size();
197}
198
Carlos IL6b784a62018-03-20 00:26:49199void SupervisedUserService::AddURLAccessRequest(const GURL& url,
200 SuccessCallback callback) {
Michael Giuffrida0fe58bf2018-07-26 20:40:27201 GURL effective_url = policy::url_util::GetEmbeddedURL(url);
treib17f2e382016-10-14 11:42:53202 if (!effective_url.is_valid())
203 effective_url = url;
bauerb5f8cda92015-10-07 15:36:44204 AddPermissionRequestInternal(
Carlos IL6b784a62018-03-20 00:26:49205 base::BindRepeating(CreateURLAccessRequest,
Michael Giuffrida0fe58bf2018-07-26 20:40:27206 policy::url_util::Normalize(effective_url)),
Carlos IL6b784a62018-03-20 00:26:49207 std::move(callback), 0);
bauerb5f8cda92015-10-07 15:36:44208}
209
atanasovaac676032016-04-05 16:31:05210void SupervisedUserService::ReportURL(const GURL& url,
Carlos IL6b784a62018-03-20 00:26:49211 SuccessCallback callback) {
atanasovaac676032016-04-05 16:31:05212 if (url_reporter_)
Carlos IL6b784a62018-03-20 00:26:49213 url_reporter_->ReportUrl(url, std::move(callback));
atanasovaac676032016-04-05 16:31:05214 else
Carlos IL6b784a62018-03-20 00:26:49215 std::move(callback).Run(false);
atanasovaac676032016-04-05 16:31:05216}
217
mamire9609642016-06-28 22:17:54218void SupervisedUserService::AddExtensionInstallRequest(
219 const std::string& extension_id,
220 const base::Version& version,
Carlos IL6b784a62018-03-20 00:26:49221 SuccessCallback callback) {
mamire9609642016-06-28 22:17:54222 std::string id = GetExtensionRequestId(extension_id, version);
Carlos IL6b784a62018-03-20 00:26:49223 AddPermissionRequestInternal(
224 base::BindRepeating(CreateExtensionInstallRequest, id),
225 std::move(callback), 0);
mamire9609642016-06-28 22:17:54226}
227
228void SupervisedUserService::AddExtensionInstallRequest(
229 const std::string& extension_id,
230 const base::Version& version) {
231 std::string id = GetExtensionRequestId(extension_id, version);
Carlos IL6b784a62018-03-20 00:26:49232 AddExtensionInstallRequest(extension_id, version,
233 base::BindOnce(ExtensionInstallRequestSent, id));
mamire9609642016-06-28 22:17:54234}
235
bauerb5f8cda92015-10-07 15:36:44236void SupervisedUserService::AddExtensionUpdateRequest(
237 const std::string& extension_id,
238 const base::Version& version,
Carlos IL6b784a62018-03-20 00:26:49239 SuccessCallback callback) {
mamire9609642016-06-28 22:17:54240 std::string id = GetExtensionRequestId(extension_id, version);
bauerb5f8cda92015-10-07 15:36:44241 AddPermissionRequestInternal(
Carlos IL6b784a62018-03-20 00:26:49242 base::BindRepeating(CreateExtensionUpdateRequest, id),
243 std::move(callback), 0);
treib40d3ad92015-10-20 18:15:42244}
245
246void SupervisedUserService::AddExtensionUpdateRequest(
247 const std::string& extension_id,
248 const base::Version& version) {
mamire9609642016-06-28 22:17:54249 std::string id = GetExtensionRequestId(extension_id, version);
treib40d3ad92015-10-20 18:15:42250 AddExtensionUpdateRequest(extension_id, version,
Carlos IL6b784a62018-03-20 00:26:49251 base::BindOnce(ExtensionUpdateRequestSent, id));
treib40d3ad92015-10-20 18:15:42252}
253
254// static
mamire9609642016-06-28 22:17:54255std::string SupervisedUserService::GetExtensionRequestId(
treib40d3ad92015-10-20 18:15:42256 const std::string& extension_id,
257 const base::Version& version) {
258 return base::StringPrintf("%s:%s", extension_id.c_str(),
259 version.GetString().c_str());
bauerb5f8cda92015-10-07 15:36:44260}
261
262std::string SupervisedUserService::GetCustodianEmailAddress() const {
treib2170ea02015-10-13 14:55:12263 std::string email = profile_->GetPrefs()->GetString(
bauerb5f8cda92015-10-07 15:36:44264 prefs::kSupervisedUserCustodianEmail);
265#if defined(OS_CHROMEOS)
treib2170ea02015-10-13 14:55:12266 // |GetActiveUser()| can return null in unit tests.
267 if (email.empty() && !!user_manager::UserManager::Get()->GetActiveUser()) {
268 email = chromeos::ChromeUserManager::Get()
alemate1e3ddde2016-11-04 02:17:06269 ->GetSupervisedUserManager()
270 ->GetManagerDisplayEmail(user_manager::UserManager::Get()
271 ->GetActiveUser()
272 ->GetAccountId()
273 .GetUserEmail());
bauerb5f8cda92015-10-07 15:36:44274 }
275#endif
treib2170ea02015-10-13 14:55:12276 return email;
bauerb5f8cda92015-10-07 15:36:44277}
278
279std::string SupervisedUserService::GetCustodianName() const {
280 std::string name = profile_->GetPrefs()->GetString(
281 prefs::kSupervisedUserCustodianName);
282#if defined(OS_CHROMEOS)
treib2170ea02015-10-13 14:55:12283 // |GetActiveUser()| can return null in unit tests.
284 if (name.empty() && !!user_manager::UserManager::Get()->GetActiveUser()) {
alemate1e3ddde2016-11-04 02:17:06285 name = base::UTF16ToUTF8(
286 chromeos::ChromeUserManager::Get()
287 ->GetSupervisedUserManager()
288 ->GetManagerDisplayName(user_manager::UserManager::Get()
289 ->GetActiveUser()
290 ->GetAccountId()
291 .GetUserEmail()));
bauerb5f8cda92015-10-07 15:36:44292 }
293#endif
294 return name.empty() ? GetCustodianEmailAddress() : name;
295}
296
297std::string SupervisedUserService::GetSecondCustodianEmailAddress() const {
298 return profile_->GetPrefs()->GetString(
299 prefs::kSupervisedUserSecondCustodianEmail);
300}
301
302std::string SupervisedUserService::GetSecondCustodianName() const {
303 std::string name = profile_->GetPrefs()->GetString(
304 prefs::kSupervisedUserSecondCustodianName);
305 return name.empty() ? GetSecondCustodianEmailAddress() : name;
306}
307
treib2170ea02015-10-13 14:55:12308base::string16 SupervisedUserService::GetExtensionsLockedMessage() const {
309 return l10n_util::GetStringFUTF16(IDS_EXTENSIONS_LOCKED_SUPERVISED_USER,
310 base::UTF8ToUTF16(GetCustodianName()));
311}
312
jam1c5a91492016-02-24 20:47:53313#if !defined(OS_ANDROID)
bauerb5f8cda92015-10-07 15:36:44314void SupervisedUserService::InitSync(const std::string& refresh_token) {
Mario Sanchez Prada77f113c2019-02-01 09:33:55315 IdentityManagerFactory::GetForProfile(profile_)
316 ->GetAccountsMutator()
317 ->LegacySetRefreshTokenForSupervisedUser(refresh_token);
bauerb5f8cda92015-10-07 15:36:44318}
jam1c5a91492016-02-24 20:47:53319#endif // !defined(OS_ANDROID)
bauerb5f8cda92015-10-07 15:36:44320
bauerb5f8cda92015-10-07 15:36:44321void SupervisedUserService::AddObserver(
322 SupervisedUserServiceObserver* observer) {
323 observer_list_.AddObserver(observer);
324}
325
326void SupervisedUserService::RemoveObserver(
327 SupervisedUserServiceObserver* observer) {
328 observer_list_.RemoveObserver(observer);
329}
330
331void SupervisedUserService::AddPermissionRequestCreator(
dchengf624e472016-04-12 08:33:17332 std::unique_ptr<PermissionRequestCreator> creator) {
leon.han4ea301f2017-03-28 03:36:31333 permissions_creators_.push_back(std::move(creator));
bauerb5f8cda92015-10-07 15:36:44334}
335
atanasovaac676032016-04-05 16:31:05336void SupervisedUserService::SetSafeSearchURLReporter(
dchengf624e472016-04-12 08:33:17337 std::unique_ptr<SafeSearchURLReporter> reporter) {
atanasovaac676032016-04-05 16:31:05338 url_reporter_ = std::move(reporter);
339}
340
[email protected]cce15bb2014-06-17 13:43:51341SupervisedUserService::SupervisedUserService(Profile* profile)
Marc Treib81f6d602018-11-07 10:10:34342 : profile_(profile),
[email protected]f085fdd52014-06-11 18:09:20343 active_(false),
344 delegate_(NULL),
[email protected]dfddd022013-07-10 17:29:48345 is_profile_active_(false),
[email protected]3a276ff2014-08-12 14:22:09346 did_init_(false),
[email protected]8052b242013-11-15 16:40:55347 did_shutdown_(false),
treib9cc1b112016-01-08 10:08:01348 blacklist_state_(BlacklistLoadState::NOT_LOADED),
brettw00899e62016-11-12 02:10:17349#if BUILDFLAG(ENABLE_EXTENSIONS)
mamire9609642016-06-28 22:17:54350 registry_observer_(this),
351#endif
[email protected]8052b242013-11-15 16:40:55352 weak_ptr_factory_(this) {
mmenkedb2637ff2017-03-30 23:59:42353 url_filter_.AddObserver(this);
brettw00899e62016-11-12 02:10:17354#if BUILDFLAG(ENABLE_EXTENSIONS)
mamire9609642016-06-28 22:17:54355 registry_observer_.Add(extensions::ExtensionRegistry::Get(profile));
356#endif
Marc Treib974d8f82019-03-28 12:21:36357
358 std::string client_id = component_updater::SupervisedUserWhitelistInstaller::
359 ClientIdForProfilePath(profile_->GetPath());
360 whitelist_service_ = std::make_unique<SupervisedUserWhitelistService>(
361 profile_->GetPrefs(),
362 g_browser_process->supervised_user_whitelist_installer(), client_id);
[email protected]a243d644c2013-06-20 18:37:55363}
[email protected]0850e842013-01-19 03:44:31364
[email protected]cce15bb2014-06-17 13:43:51365void SupervisedUserService::SetActive(bool active) {
[email protected]f085fdd52014-06-11 18:09:20366 if (active_ == active)
[email protected]0850e842013-01-19 03:44:31367 return;
[email protected]f085fdd52014-06-11 18:09:20368 active_ = active;
369
370 if (!delegate_ || !delegate_->SetActive(active_)) {
371 if (active_) {
jam1c5a91492016-02-24 20:47:53372#if !defined(OS_ANDROID)
Henrique Ferreiroe27d42d2019-02-20 01:32:20373 IdentityManagerFactory::GetForProfile(profile_)
Sylvain Defresne8ee06f22019-03-08 15:01:16374 ->DeprecatedLoadCredentialsForSupervisedUser(
Henrique Ferreiroe27d42d2019-02-20 01:32:20375 supervised_users::kSupervisedUserPseudoEmail);
bauerb7f3b8542015-06-29 19:56:19376#else
377 NOTREACHED();
378#endif
[email protected]f085fdd52014-06-11 18:09:20379 }
[email protected]e861bba2013-06-17 15:20:54380 }
[email protected]0850e842013-01-19 03:44:31381
[email protected]f085fdd52014-06-11 18:09:20382 // Now activate/deactivate anything not handled by the delegate yet.
[email protected]e1480482013-09-11 11:49:58383
brettw9b0866f2016-12-11 02:34:06384#if !defined(OS_ANDROID)
[email protected]f085fdd52014-06-11 18:09:20385 // Re-set the default theme to turn the SU theme on/off.
386 ThemeService* theme_service = ThemeServiceFactory::GetForProfile(profile_);
treib9e30e302015-04-15 08:12:16387 if (theme_service->UsingDefaultTheme() || theme_service->UsingSystemTheme())
388 theme_service->UseDefaultTheme();
[email protected]f085fdd52014-06-11 18:09:20389#endif
[email protected]a19df3e2013-05-21 00:03:03390
bauerbd3a36cc42014-10-01 13:05:49391 GetSettingsService()->SetActive(active_);
[email protected]a243d644c2013-06-20 18:37:55392
brettw00899e62016-11-12 02:10:17393#if BUILDFLAG(ENABLE_EXTENSIONS)
[email protected]c14a6802014-07-11 21:51:12394 SetExtensionsActive();
395#endif
[email protected]0850e842013-01-19 03:44:31396
[email protected]f085fdd52014-06-11 18:09:20397 if (active_) {
[email protected]f085fdd52014-06-11 18:09:20398 pref_change_registrar_.Add(
[email protected]d20d0432014-06-12 17:14:05399 prefs::kDefaultSupervisedUserFilteringBehavior,
Carlos IL6b784a62018-03-20 00:26:49400 base::BindRepeating(
401 &SupervisedUserService::OnDefaultFilteringBehaviorChanged,
[email protected]f085fdd52014-06-11 18:09:20402 base::Unretained(this)));
brettw00899e62016-11-12 02:10:17403#if BUILDFLAG(ENABLE_EXTENSIONS)
mamire9609642016-06-28 22:17:54404 pref_change_registrar_.Add(
405 prefs::kSupervisedUserApprovedExtensions,
Carlos IL6b784a62018-03-20 00:26:49406 base::BindRepeating(&SupervisedUserService::UpdateApprovedExtensions,
407 base::Unretained(this)));
mamire9609642016-06-28 22:17:54408#endif
Carlos IL6b784a62018-03-20 00:26:49409 pref_change_registrar_.Add(
410 prefs::kSupervisedUserSafeSites,
411 base::BindRepeating(&SupervisedUserService::OnSafeSitesSettingChanged,
412 base::Unretained(this)));
413 pref_change_registrar_.Add(
414 prefs::kSupervisedUserManualHosts,
415 base::BindRepeating(&SupervisedUserService::UpdateManualHosts,
416 base::Unretained(this)));
417 pref_change_registrar_.Add(
418 prefs::kSupervisedUserManualURLs,
419 base::BindRepeating(&SupervisedUserService::UpdateManualURLs,
420 base::Unretained(this)));
treib22c3a042015-01-15 21:30:13421 for (const char* pref : kCustodianInfoPrefs) {
Carlos IL6b784a62018-03-20 00:26:49422 pref_change_registrar_.Add(
423 pref,
424 base::BindRepeating(&SupervisedUserService::OnCustodianInfoChanged,
425 base::Unretained(this)));
treib22c3a042015-01-15 21:30:13426 }
[email protected]f085fdd52014-06-11 18:09:20427
428 // Initialize the filter.
429 OnDefaultFilteringBehaviorChanged();
treib9cc1b112016-01-08 10:08:01430 OnSafeSitesSettingChanged();
bauerb4da36132014-12-26 19:53:13431 whitelist_service_->Init();
[email protected]f085fdd52014-06-11 18:09:20432 UpdateManualHosts();
433 UpdateManualURLs();
[email protected]0850e842013-01-19 03:44:31434
brettw00899e62016-11-12 02:10:17435#if BUILDFLAG(ENABLE_EXTENSIONS)
mamire9609642016-06-28 22:17:54436 UpdateApprovedExtensions();
437#endif
438
jam1c5a91492016-02-24 20:47:53439#if !defined(OS_ANDROID)
[email protected]f085fdd52014-06-11 18:09:20440 // TODO(bauerb): Get rid of the platform-specific #ifdef here.
441 // http://crbug.com/313377
442 BrowserList::AddObserver(this);
[email protected]975677d2013-11-14 16:15:34443#endif
[email protected]f085fdd52014-06-11 18:09:20444 } else {
bauerbd3a36cc42014-10-01 13:05:49445 permissions_creators_.clear();
atanasovaac676032016-04-05 16:31:05446 url_reporter_.reset();
[email protected]dfddd022013-07-10 17:29:48447
[email protected]d20d0432014-06-12 17:14:05448 pref_change_registrar_.Remove(
449 prefs::kDefaultSupervisedUserFilteringBehavior);
brettw00899e62016-11-12 02:10:17450#if BUILDFLAG(ENABLE_EXTENSIONS)
mamire9609642016-06-28 22:17:54451 pref_change_registrar_.Remove(prefs::kSupervisedUserApprovedExtensions);
452#endif
[email protected]d20d0432014-06-12 17:14:05453 pref_change_registrar_.Remove(prefs::kSupervisedUserManualHosts);
454 pref_change_registrar_.Remove(prefs::kSupervisedUserManualURLs);
treib22c3a042015-01-15 21:30:13455 for (const char* pref : kCustodianInfoPrefs) {
456 pref_change_registrar_.Remove(pref);
457 }
458
mmenkedb2637ff2017-03-30 23:59:42459 url_filter_.Clear();
ericwilligers8b92b052016-10-19 22:21:58460 for (SupervisedUserServiceObserver& observer : observer_list_)
461 observer.OnURLFilterChanged();
[email protected]f085fdd52014-06-11 18:09:20462
jam1c5a91492016-02-24 20:47:53463#if !defined(OS_ANDROID)
[email protected]f085fdd52014-06-11 18:09:20464 // TODO(bauerb): Get rid of the platform-specific #ifdef here.
465 // http://crbug.com/313377
466 BrowserList::RemoveObserver(this);
467#endif
468 }
[email protected]0850e842013-01-19 03:44:31469}
470
bauerb5f8cda92015-10-07 15:36:44471bool SupervisedUserService::ProfileIsSupervised() const {
472 return profile_->IsSupervised();
473}
474
475void SupervisedUserService::OnCustodianInfoChanged() {
ericwilligers8b92b052016-10-19 22:21:58476 for (SupervisedUserServiceObserver& observer : observer_list_)
477 observer.OnCustodianInfoChanged();
bauerb5f8cda92015-10-07 15:36:44478}
479
480SupervisedUserSettingsService* SupervisedUserService::GetSettingsService() {
481 return SupervisedUserSettingsServiceFactory::GetForProfile(profile_);
482}
483
484size_t SupervisedUserService::FindEnabledPermissionRequestCreator(
485 size_t start) {
486 for (size_t i = start; i < permissions_creators_.size(); ++i) {
487 if (permissions_creators_[i]->IsEnabled())
488 return i;
489 }
490 return permissions_creators_.size();
491}
492
493void SupervisedUserService::AddPermissionRequestInternal(
494 const CreatePermissionRequestCallback& create_request,
Carlos IL6b784a62018-03-20 00:26:49495 SuccessCallback callback,
bauerb5f8cda92015-10-07 15:36:44496 size_t index) {
497 // Find a permission request creator that is enabled.
498 size_t next_index = FindEnabledPermissionRequestCreator(index);
499 if (next_index >= permissions_creators_.size()) {
Carlos IL6b784a62018-03-20 00:26:49500 std::move(callback).Run(false);
bauerb5f8cda92015-10-07 15:36:44501 return;
502 }
503
504 create_request.Run(
leon.han4ea301f2017-03-28 03:36:31505 permissions_creators_[next_index].get(),
Carlos IL6b784a62018-03-20 00:26:49506 base::BindOnce(&SupervisedUserService::OnPermissionRequestIssued,
507 weak_ptr_factory_.GetWeakPtr(), create_request,
508 std::move(callback), next_index));
bauerb5f8cda92015-10-07 15:36:44509}
510
511void SupervisedUserService::OnPermissionRequestIssued(
512 const CreatePermissionRequestCallback& create_request,
Carlos IL6b784a62018-03-20 00:26:49513 SuccessCallback callback,
bauerb5f8cda92015-10-07 15:36:44514 size_t index,
515 bool success) {
516 if (success) {
Carlos IL6b784a62018-03-20 00:26:49517 std::move(callback).Run(true);
bauerb5f8cda92015-10-07 15:36:44518 return;
519 }
520
Carlos IL6b784a62018-03-20 00:26:49521 AddPermissionRequestInternal(create_request, std::move(callback), index + 1);
bauerb5f8cda92015-10-07 15:36:44522}
523
524void SupervisedUserService::OnSupervisedUserIdChanged() {
525 SetActive(ProfileIsSupervised());
526}
527
528void SupervisedUserService::OnDefaultFilteringBehaviorChanged() {
529 int behavior_value = profile_->GetPrefs()->GetInteger(
530 prefs::kDefaultSupervisedUserFilteringBehavior);
531 SupervisedUserURLFilter::FilteringBehavior behavior =
532 SupervisedUserURLFilter::BehaviorFromInt(behavior_value);
mmenkedb2637ff2017-03-30 23:59:42533 url_filter_.SetDefaultFilteringBehavior(behavior);
bauerb5f8cda92015-10-07 15:36:44534
ericwilligers8b92b052016-10-19 22:21:58535 for (SupervisedUserServiceObserver& observer : observer_list_)
536 observer.OnURLFilterChanged();
bauerb5f8cda92015-10-07 15:36:44537}
538
treib9cc1b112016-01-08 10:08:01539void SupervisedUserService::OnSafeSitesSettingChanged() {
540 bool use_blacklist = supervised_users::IsSafeSitesBlacklistEnabled(profile_);
mmenkedb2637ff2017-03-30 23:59:42541 if (use_blacklist != url_filter_.HasBlacklist()) {
treib9cc1b112016-01-08 10:08:01542 if (use_blacklist && blacklist_state_ == BlacklistLoadState::NOT_LOADED) {
543 LoadBlacklist(GetBlacklistPath(), GURL(kBlacklistURL));
544 } else if (!use_blacklist ||
545 blacklist_state_ == BlacklistLoadState::LOADED) {
546 // Either the blacklist was turned off, or it was turned on but has
547 // already been loaded previously. Just update the setting.
548 UpdateBlacklist();
549 }
550 // Else: The blacklist was enabled, but the load is already in progress.
551 // Do nothing - we'll check the setting again when the load finishes.
552 }
553
554 bool use_online_check =
555 supervised_users::IsSafeSitesOnlineCheckEnabled(profile_);
mmenkedb2637ff2017-03-30 23:59:42556 if (use_online_check != url_filter_.HasAsyncURLChecker()) {
Caio6d256c332019-03-22 15:25:56557 if (use_online_check) {
Mark Pilgrimb67362ed2018-05-15 15:59:47558 url_filter_.InitAsyncURLChecker(
559 content::BrowserContext::GetDefaultStoragePartition(profile_)
Caio6d256c332019-03-22 15:25:56560 ->GetURLLoaderFactoryForBrowserProcess(),
561 IdentityManagerFactory::GetForProfile(profile_));
562 } else {
mmenkedb2637ff2017-03-30 23:59:42563 url_filter_.ClearAsyncURLChecker();
Caio6d256c332019-03-22 15:25:56564 }
treib9cc1b112016-01-08 10:08:01565 }
566}
567
bauerb5f8cda92015-10-07 15:36:44568void SupervisedUserService::OnSiteListsChanged(
569 const std::vector<scoped_refptr<SupervisedUserSiteList> >& site_lists) {
atanasova9572aaf2016-02-26 18:08:26570 whitelists_ = site_lists;
mmenkedb2637ff2017-03-30 23:59:42571 url_filter_.LoadWhitelists(site_lists);
bauerb5f8cda92015-10-07 15:36:44572}
573
574void SupervisedUserService::LoadBlacklist(const base::FilePath& path,
575 const GURL& url) {
treib9cc1b112016-01-08 10:08:01576 DCHECK(blacklist_state_ == BlacklistLoadState::NOT_LOADED);
577 blacklist_state_ = BlacklistLoadState::LOAD_STARTED;
fdoray9afc2bc2017-04-27 15:00:00578 base::PostTaskWithTraitsAndReplyWithResult(
bauerb5f8cda92015-10-07 15:36:44579 FROM_HERE,
Gabriel Charetteb10aeebc2018-07-26 20:15:00580 {base::MayBlock(), base::TaskPriority::BEST_EFFORT,
fdoray4ad14932017-05-03 21:21:11581 base::TaskShutdownBehavior::CONTINUE_ON_SHUTDOWN},
fdoray9afc2bc2017-04-27 15:00:00582 base::BindOnce(&base::PathExists, path),
583 base::BindOnce(&SupervisedUserService::OnBlacklistFileChecked,
584 weak_ptr_factory_.GetWeakPtr(), path, url));
bauerb5f8cda92015-10-07 15:36:44585}
586
587void SupervisedUserService::OnBlacklistFileChecked(const base::FilePath& path,
588 const GURL& url,
589 bool file_exists) {
treib9cc1b112016-01-08 10:08:01590 DCHECK(blacklist_state_ == BlacklistLoadState::LOAD_STARTED);
bauerb5f8cda92015-10-07 15:36:44591 if (file_exists) {
592 LoadBlacklistFromFile(path);
593 return;
594 }
595
596 DCHECK(!blacklist_downloader_);
rhalavati5f1caa2b2017-02-25 08:22:16597
598 // Create traffic annotation tag.
599 net::NetworkTrafficAnnotationTag traffic_annotation =
600 net::DefineNetworkTrafficAnnotation("supervised_users_blacklist", R"(
601 semantics {
602 sender: "Supervised Users"
603 description:
604 "Downloads a static blacklist consisting of hostname hashes of "
605 "common inappropriate websites. This is only enabled for child "
606 "accounts and only if the corresponding setting is enabled by the "
607 "parent."
608 trigger:
609 "The file is downloaded on demand if the child account profile is "
610 "created and the setting is enabled."
611 data:
612 "No additional data is sent to the server beyond the request "
613 "itself."
614 destination: GOOGLE_OWNED_SERVICE
615 }
616 policy {
Ramin Halavati3b979782017-07-21 11:40:26617 cookies_allowed: NO
rhalavati5f1caa2b2017-02-25 08:22:16618 setting:
619 "The feature can be remotely enabled or disabled by the parent. In "
620 "addition, if sign-in is restricted to accounts from a managed "
621 "domain, those accounts are not going to be child accounts."
rhalavatieaa64e92017-04-03 09:36:43622 chrome_policy {
rhalavati5f1caa2b2017-02-25 08:22:16623 RestrictSigninToPattern {
624 policy_options {mode: MANDATORY}
rhalavatieaa64e92017-04-03 09:36:43625 RestrictSigninToPattern: "*@manageddomain.com"
rhalavati5f1caa2b2017-02-25 08:22:16626 }
627 }
628 })");
629
Mark Pilgrima8b7f432018-04-19 23:23:00630 auto factory = content::BrowserContext::GetDefaultStoragePartition(profile_)
631 ->GetURLLoaderFactoryForBrowserProcess();
bauerb5f8cda92015-10-07 15:36:44632 blacklist_downloader_.reset(new FileDownloader(
Mark Pilgrima8b7f432018-04-19 23:23:00633 url, path, false, std::move(factory),
Mark Pilgrimfa634c92018-06-19 20:01:24634 base::BindOnce(&SupervisedUserService::OnBlacklistDownloadDone,
635 base::Unretained(this), path),
rhalavati5f1caa2b2017-02-25 08:22:16636 traffic_annotation));
bauerb5f8cda92015-10-07 15:36:44637}
638
639void SupervisedUserService::LoadBlacklistFromFile(const base::FilePath& path) {
treib9cc1b112016-01-08 10:08:01640 DCHECK(blacklist_state_ == BlacklistLoadState::LOAD_STARTED);
641 blacklist_.ReadFromFile(
642 path,
643 base::Bind(&SupervisedUserService::OnBlacklistLoaded,
644 base::Unretained(this)));
bauerb5f8cda92015-10-07 15:36:44645}
646
treibf38cc252016-04-07 14:44:11647void SupervisedUserService::OnBlacklistDownloadDone(
648 const base::FilePath& path,
649 FileDownloader::Result result) {
treib9cc1b112016-01-08 10:08:01650 DCHECK(blacklist_state_ == BlacklistLoadState::LOAD_STARTED);
treibf38cc252016-04-07 14:44:11651 if (FileDownloader::IsSuccess(result)) {
bauerb5f8cda92015-10-07 15:36:44652 LoadBlacklistFromFile(path);
653 } else {
654 LOG(WARNING) << "Blacklist download failed";
treib9cc1b112016-01-08 10:08:01655 // TODO(treib): Retry downloading after some time?
bauerb5f8cda92015-10-07 15:36:44656 }
657 blacklist_downloader_.reset();
658}
659
660void SupervisedUserService::OnBlacklistLoaded() {
treib9cc1b112016-01-08 10:08:01661 DCHECK(blacklist_state_ == BlacklistLoadState::LOAD_STARTED);
662 blacklist_state_ = BlacklistLoadState::LOADED;
663 UpdateBlacklist();
664}
665
666void SupervisedUserService::UpdateBlacklist() {
667 bool use_blacklist = supervised_users::IsSafeSitesBlacklistEnabled(profile_);
mmenkedb2637ff2017-03-30 23:59:42668 url_filter_.SetBlacklist(use_blacklist ? &blacklist_ : nullptr);
ericwilligers8b92b052016-10-19 22:21:58669 for (SupervisedUserServiceObserver& observer : observer_list_)
670 observer.OnURLFilterChanged();
bauerb5f8cda92015-10-07 15:36:44671}
[email protected]acfcfbb2013-05-13 18:01:27672
[email protected]cce15bb2014-06-17 13:43:51673void SupervisedUserService::UpdateManualHosts() {
[email protected]cb1078de2013-12-23 20:04:22674 const base::DictionaryValue* dict =
[email protected]d20d0432014-06-12 17:14:05675 profile_->GetPrefs()->GetDictionary(prefs::kSupervisedUserManualHosts);
mmenkedb2637ff2017-03-30 23:59:42676 std::map<std::string, bool> host_map;
[email protected]cb1078de2013-12-23 20:04:22677 for (base::DictionaryValue::Iterator it(*dict); !it.IsAtEnd(); it.Advance()) {
[email protected]5e022292013-02-06 16:42:17678 bool allow = false;
679 bool result = it.value().GetAsBoolean(&allow);
680 DCHECK(result);
mmenkedb2637ff2017-03-30 23:59:42681 host_map[it.key()] = allow;
[email protected]5e022292013-02-06 16:42:17682 }
mmenkedb2637ff2017-03-30 23:59:42683 url_filter_.SetManualHosts(std::move(host_map));
treibab0a39e2014-09-24 14:48:28684
ericwilligers8b92b052016-10-19 22:21:58685 for (SupervisedUserServiceObserver& observer : observer_list_)
686 observer.OnURLFilterChanged();
[email protected]0850e842013-01-19 03:44:31687}
688
[email protected]cce15bb2014-06-17 13:43:51689void SupervisedUserService::UpdateManualURLs() {
[email protected]cb1078de2013-12-23 20:04:22690 const base::DictionaryValue* dict =
[email protected]d20d0432014-06-12 17:14:05691 profile_->GetPrefs()->GetDictionary(prefs::kSupervisedUserManualURLs);
mmenkedb2637ff2017-03-30 23:59:42692 std::map<GURL, bool> url_map;
[email protected]cb1078de2013-12-23 20:04:22693 for (base::DictionaryValue::Iterator it(*dict); !it.IsAtEnd(); it.Advance()) {
[email protected]5e022292013-02-06 16:42:17694 bool allow = false;
695 bool result = it.value().GetAsBoolean(&allow);
696 DCHECK(result);
mmenkedb2637ff2017-03-30 23:59:42697 url_map[GURL(it.key())] = allow;
[email protected]5e022292013-02-06 16:42:17698 }
mmenkedb2637ff2017-03-30 23:59:42699 url_filter_.SetManualURLs(std::move(url_map));
treibab0a39e2014-09-24 14:48:28700
ericwilligers8b92b052016-10-19 22:21:58701 for (SupervisedUserServiceObserver& observer : observer_list_)
702 observer.OnURLFilterChanged();
[email protected]0850e842013-01-19 03:44:31703}
[email protected]dfddd022013-07-10 17:29:48704
bauerb5f8cda92015-10-07 15:36:44705void SupervisedUserService::Shutdown() {
706 if (!did_init_)
707 return;
708 DCHECK(!did_shutdown_);
709 did_shutdown_ = true;
710 if (ProfileIsSupervised()) {
bratell0a7406f2017-03-28 07:46:37711 base::RecordAction(UserMetricsAction("ManagedUsers_QuitBrowser"));
bauerb5f8cda92015-10-07 15:36:44712 }
713 SetActive(false);
bauerb5f8cda92015-10-07 15:36:44714}
715
brettw00899e62016-11-12 02:10:17716#if BUILDFLAG(ENABLE_EXTENSIONS)
mamir192d7882016-06-22 17:10:16717SupervisedUserService::ExtensionState SupervisedUserService::GetExtensionState(
mamire9609642016-06-28 22:17:54718 const Extension& extension) const {
719 bool was_installed_by_default = extension.was_installed_by_default();
mamir192d7882016-06-22 17:10:16720#if defined(OS_CHROMEOS)
721 // On Chrome OS all external sources are controlled by us so it means that
722 // they are "default". Method was_installed_by_default returns false because
723 // extensions creation flags are ignored in case of default extensions with
724 // update URL(the flags aren't passed to OnExternalExtensionUpdateUrlFound).
725 // TODO(dpolukhin): remove this Chrome OS specific code as soon as creation
726 // flags are not ignored.
727 was_installed_by_default =
mamire9609642016-06-28 22:17:54728 extensions::Manifest::IsExternalLocation(extension.location());
mamir192d7882016-06-22 17:10:16729#endif
730 // Note: Component extensions are protected from modification/uninstallation
731 // anyway, so there's no need to enforce them again for supervised users.
732 // Also, leave policy-installed extensions alone - they have their own
733 // management; in particular we don't want to override the force-install list.
mamire9609642016-06-28 22:17:54734 if (extensions::Manifest::IsComponentLocation(extension.location()) ||
735 extensions::Manifest::IsPolicyLocation(extension.location()) ||
736 extension.is_theme() || extension.from_bookmark() ||
737 extension.is_shared_module() || was_installed_by_default) {
738 return ExtensionState::ALLOWED;
mamir192d7882016-06-22 17:10:16739 }
740
mamire9609642016-06-28 22:17:54741 if (extensions::util::WasInstalledByCustodian(extension.id(), profile_))
742 return ExtensionState::FORCED;
mamir192d7882016-06-22 17:10:16743
mamire9609642016-06-28 22:17:54744 if (!base::FeatureList::IsEnabled(
745 supervised_users::kSupervisedUserInitiatedExtensionInstall)) {
746 return ExtensionState::BLOCKED;
747 }
748
749 auto extension_it = approved_extensions_map_.find(extension.id());
750 // If the installed version is approved, then the extension is allowed,
751 // otherwise, it requires approval.
752 if (extension_it != approved_extensions_map_.end() &&
Devlin Cronin03bf2d22017-12-20 08:21:05753 extension_it->second == extension.version()) {
mamire9609642016-06-28 22:17:54754 return ExtensionState::ALLOWED;
755 }
756 return ExtensionState::REQUIRE_APPROVAL;
mamir192d7882016-06-22 17:10:16757}
758
bauerb5f8cda92015-10-07 15:36:44759std::string SupervisedUserService::GetDebugPolicyProviderName() const {
760 // Save the string space in official builds.
Will Harris72a97a32018-05-29 19:05:21761#if DCHECK_IS_ON()
bauerb5f8cda92015-10-07 15:36:44762 return "Supervised User Service";
Will Harris72a97a32018-05-29 19:05:21763#else
764 IMMEDIATE_CRASH();
bauerb5f8cda92015-10-07 15:36:44765#endif
766}
767
mamire9609642016-06-28 22:17:54768bool SupervisedUserService::UserMayLoad(const Extension* extension,
bauerb5f8cda92015-10-07 15:36:44769 base::string16* error) const {
770 DCHECK(ProfileIsSupervised());
mamire9609642016-06-28 22:17:54771 ExtensionState result = GetExtensionState(*extension);
772 bool may_load = result != ExtensionState::BLOCKED;
bauerb5f8cda92015-10-07 15:36:44773 if (!may_load && error)
treib2170ea02015-10-13 14:55:12774 *error = GetExtensionsLockedMessage();
bauerb5f8cda92015-10-07 15:36:44775 return may_load;
776}
777
mamire9609642016-06-28 22:17:54778bool SupervisedUserService::UserMayModifySettings(const Extension* extension,
779 base::string16* error) const {
bauerb5f8cda92015-10-07 15:36:44780 DCHECK(ProfileIsSupervised());
mamire9609642016-06-28 22:17:54781 ExtensionState result = GetExtensionState(*extension);
782 // While the following check allows the supervised user to modify the settings
783 // and enable or disable the extension, MustRemainDisabled properly takes care
784 // of keeping an extension disabled when required.
785 // For custodian-installed extensions, the state is always FORCED, even if
786 // it's waiting for an update approval.
787 bool may_modify = result != ExtensionState::FORCED;
bauerb5f8cda92015-10-07 15:36:44788 if (!may_modify && error)
treib2170ea02015-10-13 14:55:12789 *error = GetExtensionsLockedMessage();
bauerb5f8cda92015-10-07 15:36:44790 return may_modify;
791}
792
793// Note: Having MustRemainInstalled always say "true" for custodian-installed
794// extensions does NOT prevent remote uninstalls (which is a bit unexpected, but
795// exactly what we want).
mamire9609642016-06-28 22:17:54796bool SupervisedUserService::MustRemainInstalled(const Extension* extension,
797 base::string16* error) const {
bauerb5f8cda92015-10-07 15:36:44798 DCHECK(ProfileIsSupervised());
mamire9609642016-06-28 22:17:54799 ExtensionState result = GetExtensionState(*extension);
800 bool may_not_uninstall = result == ExtensionState::FORCED;
bauerb5f8cda92015-10-07 15:36:44801 if (may_not_uninstall && error)
treib2170ea02015-10-13 14:55:12802 *error = GetExtensionsLockedMessage();
bauerb5f8cda92015-10-07 15:36:44803 return may_not_uninstall;
804}
805
Minh X. Nguyen45479012017-08-18 21:35:36806bool SupervisedUserService::MustRemainDisabled(
807 const Extension* extension,
808 extensions::disable_reason::DisableReason* reason,
809 base::string16* error) const {
mamire9609642016-06-28 22:17:54810 DCHECK(ProfileIsSupervised());
811 ExtensionState state = GetExtensionState(*extension);
812 // Only extensions that require approval should be disabled.
813 // Blocked extensions should be not loaded at all, and are taken care of
814 // at UserMayLoad.
815 bool must_remain_disabled = state == ExtensionState::REQUIRE_APPROVAL;
816
817 if (must_remain_disabled) {
818 if (error)
treib39ecc842016-11-17 12:07:07819 *error = GetExtensionsLockedMessage();
mamire9609642016-06-28 22:17:54820 // If the extension must remain disabled due to permission increase,
821 // then the update request has been already sent at update time.
822 // We do nothing and we don't add an extra disable reason.
823 ExtensionPrefs* extension_prefs = ExtensionPrefs::Get(profile_);
824 if (extension_prefs->HasDisableReason(
Minh X. Nguyen45479012017-08-18 21:35:36825 extension->id(),
826 extensions::disable_reason::DISABLE_PERMISSIONS_INCREASE)) {
mamire9609642016-06-28 22:17:54827 if (reason)
Minh X. Nguyen45479012017-08-18 21:35:36828 *reason = extensions::disable_reason::DISABLE_PERMISSIONS_INCREASE;
mamire9609642016-06-28 22:17:54829 return true;
830 }
831 if (reason)
Minh X. Nguyen45479012017-08-18 21:35:36832 *reason = extensions::disable_reason::DISABLE_CUSTODIAN_APPROVAL_REQUIRED;
mamire9609642016-06-28 22:17:54833 if (base::FeatureList::IsEnabled(
834 supervised_users::kSupervisedUserInitiatedExtensionInstall)) {
835 // If the Extension isn't pending a custodian approval already, send
836 // an approval request.
837 if (!extension_prefs->HasDisableReason(
Minh X. Nguyen45479012017-08-18 21:35:36838 extension->id(), extensions::disable_reason::
839 DISABLE_CUSTODIAN_APPROVAL_REQUIRED)) {
mamire9609642016-06-28 22:17:54840 // MustRemainDisabled is a const method and hence cannot call
841 // AddExtensionInstallRequest directly.
842 SupervisedUserService* supervised_user_service =
843 SupervisedUserServiceFactory::GetForProfile(profile_);
844 supervised_user_service->AddExtensionInstallRequest(
Devlin Cronin03bf2d22017-12-20 08:21:05845 extension->id(), extension->version());
mamire9609642016-06-28 22:17:54846 }
847 }
848 }
849 return must_remain_disabled;
850}
851
852void SupervisedUserService::OnExtensionInstalled(
853 content::BrowserContext* browser_context,
854 const extensions::Extension* extension,
855 bool is_update) {
856 // This callback method is responsible for updating extension state and
857 // approved_extensions_map_ upon extension updates.
858 if (!is_update)
859 return;
860
861 ExtensionPrefs* extension_prefs = ExtensionPrefs::Get(profile_);
862 const std::string& id = extension->id();
Devlin Cronin03bf2d22017-12-20 08:21:05863 const base::Version& version = extension->version();
mamire9609642016-06-28 22:17:54864
865 // If an already approved extension is updated without requiring
866 // new permissions, we update the approved_version.
867 if (!extension_prefs->HasDisableReason(
Minh X. Nguyen45479012017-08-18 21:35:36868 id, extensions::disable_reason::DISABLE_PERMISSIONS_INCREASE) &&
mamire9609642016-06-28 22:17:54869 approved_extensions_map_.count(id) > 0 &&
870 approved_extensions_map_[id] < version) {
871 approved_extensions_map_[id] = version;
872
873 std::string key = SupervisedUserSettingsService::MakeSplitSettingKey(
874 supervised_users::kApprovedExtensions, id);
875 std::unique_ptr<base::Value> version_value(
jdoerrie122c4da2017-03-06 11:12:04876 new base::Value(version.GetString()));
mamire9609642016-06-28 22:17:54877 GetSettingsService()->UpdateSetting(key, std::move(version_value));
878 }
879 // Upon extension update, the approved version may (or may not) match the
880 // installed one. Therefore, a change in extension state might be required.
881 ChangeExtensionStateIfNecessary(id);
882}
883
884void SupervisedUserService::UpdateApprovedExtensions() {
885 const base::DictionaryValue* dict = profile_->GetPrefs()->GetDictionary(
886 prefs::kSupervisedUserApprovedExtensions);
887 // Keep track of currently approved extensions. We may need to disable them if
888 // they are not in the approved map anymore.
889 std::set<std::string> extensions_to_be_checked;
890 for (const auto& extension : approved_extensions_map_)
891 extensions_to_be_checked.insert(extension.first);
892
893 approved_extensions_map_.clear();
894
895 for (base::DictionaryValue::Iterator it(*dict); !it.IsAtEnd(); it.Advance()) {
896 std::string version_str;
897 bool result = it.value().GetAsString(&version_str);
898 DCHECK(result);
899 base::Version version(version_str);
900 if (version.IsValid()) {
901 approved_extensions_map_[it.key()] = version;
902 extensions_to_be_checked.insert(it.key());
903 } else {
904 LOG(WARNING) << "Invalid version number " << version_str;
905 }
906 }
907
908 for (const auto& extension_id : extensions_to_be_checked) {
909 ChangeExtensionStateIfNecessary(extension_id);
910 }
911}
912
913void SupervisedUserService::ChangeExtensionStateIfNecessary(
914 const std::string& extension_id) {
915 ExtensionRegistry* registry = ExtensionRegistry::Get(profile_);
916 const Extension* extension = registry->GetInstalledExtension(extension_id);
917 // If the extension is not installed (yet), do nothing.
918 // Things will be handled after installation.
919 if (!extension)
920 return;
921
922 ExtensionPrefs* extension_prefs = ExtensionPrefs::Get(profile_);
Devlin Cronin464a2672018-05-31 08:52:46923 extensions::ExtensionService* service =
mamire9609642016-06-28 22:17:54924 ExtensionSystem::Get(profile_)->extension_service();
925
926 ExtensionState state = GetExtensionState(*extension);
927 switch (state) {
928 // BLOCKED/FORCED extensions should be already disabled/enabled
929 // and we don't need to change their state here.
930 case ExtensionState::BLOCKED:
931 case ExtensionState::FORCED:
932 break;
933 case ExtensionState::REQUIRE_APPROVAL:
Minh X. Nguyen45479012017-08-18 21:35:36934 service->DisableExtension(
935 extension_id,
936 extensions::disable_reason::DISABLE_CUSTODIAN_APPROVAL_REQUIRED);
mamire9609642016-06-28 22:17:54937 break;
938 case ExtensionState::ALLOWED:
939 extension_prefs->RemoveDisableReason(
Minh X. Nguyen45479012017-08-18 21:35:36940 extension_id,
941 extensions::disable_reason::DISABLE_CUSTODIAN_APPROVAL_REQUIRED);
mamire9609642016-06-28 22:17:54942 extension_prefs->RemoveDisableReason(
Minh X. Nguyen45479012017-08-18 21:35:36943 extension_id,
944 extensions::disable_reason::DISABLE_PERMISSIONS_INCREASE);
mamire9609642016-06-28 22:17:54945 // If not disabled for other reasons, enable it.
946 if (extension_prefs->GetDisableReasons(extension_id) ==
Minh X. Nguyen45479012017-08-18 21:35:36947 extensions::disable_reason::DISABLE_NONE) {
mamire9609642016-06-28 22:17:54948 service->EnableExtension(extension_id);
949 }
950 break;
951 }
952}
953
bauerb5f8cda92015-10-07 15:36:44954void SupervisedUserService::SetExtensionsActive() {
955 extensions::ExtensionSystem* extension_system =
956 extensions::ExtensionSystem::Get(profile_);
957 extensions::ManagementPolicy* management_policy =
958 extension_system->management_policy();
959
960 if (management_policy) {
961 if (active_)
962 management_policy->RegisterProvider(this);
963 else
964 management_policy->UnregisterProvider(this);
965
966 // Re-check the policy to make sure any new settings get applied.
967 extension_system->extension_service()->CheckManagementPolicy();
968 }
969}
brettw00899e62016-11-12 02:10:17970#endif // BUILDFLAG(ENABLE_EXTENSIONS)
bauerb5f8cda92015-10-07 15:36:44971
Marc Treibcf85fa32018-11-19 15:28:19972syncer::ModelTypeSet SupervisedUserService::GetForcedDataTypes() const {
bauerb5f8cda92015-10-07 15:36:44973 if (!ProfileIsSupervised())
974 return syncer::ModelTypeSet();
975
976 syncer::ModelTypeSet result;
bauerb5f8cda92015-10-07 15:36:44977 result.Put(syncer::EXTENSIONS);
978 result.Put(syncer::EXTENSION_SETTINGS);
979 result.Put(syncer::APPS);
980 result.Put(syncer::APP_SETTINGS);
bauerb5f8cda92015-10-07 15:36:44981 result.Put(syncer::APP_LIST);
Maksim Moskvitin62c0e452019-04-11 12:01:00982 result.Put(syncer::ARC_PACKAGE);
bauerb5f8cda92015-10-07 15:36:44983 return result;
984}
985
Marc Treibb3bbf1d22019-03-27 15:45:39986bool SupervisedUserService::IsEncryptEverythingAllowed() const {
987 return !active_;
988}
989
jam1c5a91492016-02-24 20:47:53990#if !defined(OS_ANDROID)
bauerb5f8cda92015-10-07 15:36:44991void SupervisedUserService::OnBrowserSetLastActive(Browser* browser) {
992 bool profile_became_active = profile_->IsSameProfile(browser->profile());
993 if (!is_profile_active_ && profile_became_active)
bratell0a7406f2017-03-28 07:46:37994 base::RecordAction(UserMetricsAction("ManagedUsers_OpenProfile"));
bauerb5f8cda92015-10-07 15:36:44995 else if (is_profile_active_ && !profile_became_active)
bratell0a7406f2017-03-28 07:46:37996 base::RecordAction(UserMetricsAction("ManagedUsers_SwitchProfile"));
bauerb5f8cda92015-10-07 15:36:44997
998 is_profile_active_ = profile_became_active;
999}
jam1c5a91492016-02-24 20:47:531000#endif // !defined(OS_ANDROID)
bauerb5f8cda92015-10-07 15:36:441001
1002void SupervisedUserService::OnSiteListUpdated() {
ericwilligers8b92b052016-10-19 22:21:581003 for (SupervisedUserServiceObserver& observer : observer_list_)
1004 observer.OnURLFilterChanged();
bauerb5f8cda92015-10-07 15:36:441005}