Supervised user SafeSites: Add a field trial to turn on/off.
[chromium-blink-merge.git] / chrome / browser / supervised_user / child_accounts / child_account_service.cc
blob9c7e092e6f756b563efa907def98e805013d6a17
1 // Copyright 2014 The Chromium Authors. All rights reserved.
2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file.
5 #include "chrome/browser/supervised_user/child_accounts/child_account_service.h"
7 #include "base/callback.h"
8 #include "base/command_line.h"
9 #include "base/files/file_path.h"
10 #include "base/files/file_util.h"
11 #include "base/message_loop/message_loop.h"
12 #include "base/metrics/field_trial.h"
13 #include "base/path_service.h"
14 #include "base/prefs/pref_service.h"
15 #include "base/values.h"
16 #include "chrome/browser/profiles/profile.h"
17 #include "chrome/browser/signin/profile_oauth2_token_service_factory.h"
18 #include "chrome/browser/signin/signin_manager_factory.h"
19 #include "chrome/browser/supervised_user/child_accounts/permission_request_creator_apiary.h"
20 #include "chrome/browser/supervised_user/supervised_user_constants.h"
21 #include "chrome/browser/supervised_user/supervised_user_service.h"
22 #include "chrome/browser/supervised_user/supervised_user_service_factory.h"
23 #include "chrome/browser/supervised_user/supervised_user_settings_service.h"
24 #include "chrome/browser/supervised_user/supervised_user_settings_service_factory.h"
25 #include "chrome/browser/sync/profile_sync_service.h"
26 #include "chrome/browser/sync/profile_sync_service_factory.h"
27 #include "chrome/common/chrome_paths.h"
28 #include "chrome/common/chrome_switches.h"
29 #include "chrome/common/pref_names.h"
30 #include "components/pref_registry/pref_registry_syncable.h"
31 #include "components/signin/core/browser/profile_oauth2_token_service.h"
32 #include "components/signin/core/browser/signin_manager.h"
34 #if defined(OS_CHROMEOS)
35 #include "chrome/browser/chromeos/profiles/profile_helper.h"
36 #include "components/user_manager/user_manager.h"
37 #endif
39 const char kChildAccountDetectionFieldTrialName[] = "ChildAccountDetection";
41 const char kIsChildAccountServiceFlagName[] = "uca";
43 // Normally, re-check the child account flag and the family info once per day.
44 const int kUpdateIntervalSeconds = 60 * 60 * 24;
46 // In case of an error while getting the flag or the family info, retry with
47 // exponential backoff.
48 const net::BackoffEntry::Policy kBackoffPolicy = {
49 // Number of initial errors (in sequence) to ignore before applying
50 // exponential back-off rules.
53 // Initial delay for exponential backoff in ms.
54 2000,
56 // Factor by which the waiting time will be multiplied.
59 // Fuzzing percentage. ex: 10% will spread requests randomly
60 // between 90%-100% of the calculated time.
61 0.2, // 20%
63 // Maximum amount of time we are willing to delay our request in ms.
64 1000 * 60 * 60 * 4, // 4 hours.
66 // Time to keep an entry from being discarded even when it
67 // has no significant state, -1 to never discard.
68 -1,
70 // Don't use initial delay unless the last request was an error.
71 false,
74 ChildAccountService::ChildAccountService(Profile* profile)
75 : profile_(profile), active_(false),
76 flag_fetch_backoff_(&kBackoffPolicy),
77 family_fetch_backoff_(&kBackoffPolicy),
78 weak_ptr_factory_(this) {}
80 ChildAccountService::~ChildAccountService() {}
82 // static
83 bool ChildAccountService::IsChildAccountDetectionEnabled() {
84 // Note: It's important to query the field trial state first, to ensure that
85 // UMA reports the correct group.
86 const std::string group_name =
87 base::FieldTrialList::FindFullName(kChildAccountDetectionFieldTrialName);
89 base::CommandLine* command_line = base::CommandLine::ForCurrentProcess();
90 if (command_line->HasSwitch(switches::kDisableChildAccountDetection))
91 return false;
92 if (command_line->HasSwitch(switches::kEnableChildAccountDetection))
93 return true;
95 if (group_name == "Disabled")
96 return false;
97 return true;
100 void ChildAccountService::RegisterProfilePrefs(
101 user_prefs::PrefRegistrySyncable* registry) {
102 registry->RegisterBooleanPref(
103 prefs::kChildAccountStatusKnown,
104 false,
105 user_prefs::PrefRegistrySyncable::UNSYNCABLE_PREF);
108 void ChildAccountService::SetIsChildAccount(bool is_child_account) {
109 PropagateChildStatusToUser(is_child_account);
110 if (profile_->IsChild() == is_child_account)
111 return;
113 if (is_child_account) {
114 profile_->GetPrefs()->SetString(prefs::kSupervisedUserId,
115 supervised_users::kChildAccountSUID);
116 } else {
117 profile_->GetPrefs()->ClearPref(prefs::kSupervisedUserId);
121 void ChildAccountService::Init() {
122 SigninManagerFactory::GetForProfile(profile_)->AddObserver(this);
123 SupervisedUserServiceFactory::GetForProfile(profile_)->SetDelegate(this);
125 PropagateChildStatusToUser(profile_->IsChild());
127 // If we're already signed in, fetch the flag again just to be sure.
128 // (Previously, the browser might have been closed before we got the flag.
129 // This also handles the graduation use case in a basic way.)
130 if (SigninManagerFactory::GetForProfile(profile_)->IsAuthenticated())
131 StartFetchingServiceFlags();
134 bool ChildAccountService::IsChildAccountStatusKnown() {
135 return profile_->GetPrefs()->GetBoolean(prefs::kChildAccountStatusKnown);
138 void ChildAccountService::Shutdown() {
139 family_fetcher_.reset();
140 CancelFetchingServiceFlags();
141 SupervisedUserServiceFactory::GetForProfile(profile_)->SetDelegate(NULL);
142 DCHECK(!active_);
143 SigninManagerFactory::GetForProfile(profile_)->RemoveObserver(this);
147 void ChildAccountService::AddChildStatusReceivedCallback(
148 const base::Closure& callback) {
149 if (IsChildAccountStatusKnown())
150 callback.Run();
151 else
152 status_received_callback_list_.push_back(callback);
155 bool ChildAccountService::SetActive(bool active) {
156 if (!profile_->IsChild() && !active_)
157 return false;
158 if (active_ == active)
159 return true;
160 active_ = active;
162 if (active_) {
163 // In contrast to local SUs, child account SUs must sign in.
164 scoped_ptr<base::Value> allow_signin(new base::FundamentalValue(true));
165 SupervisedUserSettingsService* settings_service =
166 SupervisedUserSettingsServiceFactory::GetForProfile(profile_);
167 settings_service->SetLocalSetting(supervised_users::kSigninAllowed,
168 allow_signin.Pass());
169 #if !defined(OS_CHROMEOS)
170 // This is also used by user policies (UserPolicySigninService), but since
171 // child accounts can not also be Dasher accounts, there shouldn't be any
172 // problems.
173 SigninManagerFactory::GetForProfile(profile_)->ProhibitSignout(true);
174 #endif
176 // TODO(treib): Maybe store the last update time in a pref, so we don't
177 // have to re-fetch on every start.
178 StartFetchingFamilyInfo();
180 SupervisedUserService* service =
181 SupervisedUserServiceFactory::GetForProfile(profile_);
182 service->AddPermissionRequestCreator(
183 PermissionRequestCreatorApiary::CreateWithProfile(profile_));
184 } else {
185 SupervisedUserSettingsService* settings_service =
186 SupervisedUserSettingsServiceFactory::GetForProfile(profile_);
187 settings_service->SetLocalSetting(supervised_users::kSigninAllowed,
188 scoped_ptr<base::Value>());
189 #if !defined(OS_CHROMEOS)
190 SigninManagerFactory::GetForProfile(profile_)->ProhibitSignout(false);
191 #endif
193 ClearFirstCustodianPrefs();
194 ClearSecondCustodianPrefs();
197 // Trigger a sync reconfig to enable/disable the right SU data types.
198 // The logic to do this lives in the SupervisedUserSyncDataTypeController.
199 ProfileSyncService* sync_service =
200 ProfileSyncServiceFactory::GetForProfile(profile_);
201 if (sync_service->HasSyncSetupCompleted())
202 sync_service->ReconfigureDatatypeManager();
204 return true;
207 base::FilePath ChildAccountService::GetBlacklistPath() const {
208 if (!active_)
209 return base::FilePath();
210 base::FilePath blacklist_path;
211 PathService::Get(chrome::DIR_USER_DATA, &blacklist_path);
212 blacklist_path = blacklist_path.AppendASCII("su-blacklist.bin");
213 return blacklist_path;
216 GURL ChildAccountService::GetBlacklistURL() const {
217 if (!active_)
218 return GURL();
219 return GURL("https://www.gstatic.com/chrome/supervised_user/"
220 "blacklist-20141001-1k.bin");
223 std::string ChildAccountService::GetSafeSitesCx() const {
224 if (!active_)
225 return std::string();
226 return "017993620680222980993%3A1wdumejvx5i";
229 void ChildAccountService::GoogleSigninSucceeded(const std::string& account_id,
230 const std::string& username,
231 const std::string& password) {
232 DCHECK(!account_id.empty());
233 DCHECK_EQ(SigninManagerFactory::GetForProfile(profile_)
234 ->GetAuthenticatedAccountId(),
235 account_id);
237 StartFetchingServiceFlags();
240 void ChildAccountService::GoogleSignedOut(const std::string& account_id,
241 const std::string& username) {
242 DCHECK(!profile_->IsChild());
243 CancelFetchingServiceFlags();
244 CancelFetchingFamilyInfo();
247 void ChildAccountService::OnGetFamilyMembersSuccess(
248 const std::vector<FamilyInfoFetcher::FamilyMember>& members) {
249 bool hoh_found = false;
250 bool parent_found = false;
251 for (const FamilyInfoFetcher::FamilyMember& member : members) {
252 if (member.role == FamilyInfoFetcher::HEAD_OF_HOUSEHOLD) {
253 hoh_found = true;
254 SetFirstCustodianPrefs(member);
255 } else if (member.role == FamilyInfoFetcher::PARENT) {
256 parent_found = true;
257 SetSecondCustodianPrefs(member);
259 if (hoh_found && parent_found)
260 break;
262 if (!hoh_found) {
263 DLOG(WARNING) << "GetFamilyMembers didn't return a HOH?!";
264 ClearFirstCustodianPrefs();
266 if (!parent_found)
267 ClearSecondCustodianPrefs();
268 family_fetcher_.reset();
270 family_fetch_backoff_.InformOfRequest(true);
272 ScheduleNextFamilyInfoUpdate(
273 base::TimeDelta::FromSeconds(kUpdateIntervalSeconds));
276 void ChildAccountService::OnFailure(FamilyInfoFetcher::ErrorCode error) {
277 DLOG(WARNING) << "GetFamilyMembers failed with code " << error;
278 family_fetch_backoff_.InformOfRequest(false);
279 ScheduleNextFamilyInfoUpdate(family_fetch_backoff_.GetTimeUntilRelease());
282 void ChildAccountService::StartFetchingFamilyInfo() {
283 family_fetcher_.reset(new FamilyInfoFetcher(
284 this,
285 SigninManagerFactory::GetForProfile(profile_)
286 ->GetAuthenticatedAccountId(),
287 ProfileOAuth2TokenServiceFactory::GetForProfile(profile_),
288 profile_->GetRequestContext()));
289 family_fetcher_->StartGetFamilyMembers();
292 void ChildAccountService::CancelFetchingFamilyInfo() {
293 family_fetcher_.reset();
294 family_fetch_timer_.Stop();
297 void ChildAccountService::ScheduleNextFamilyInfoUpdate(base::TimeDelta delay) {
298 family_fetch_timer_.Start(
299 FROM_HERE, delay, this, &ChildAccountService::StartFetchingFamilyInfo);
302 void ChildAccountService::StartFetchingServiceFlags() {
303 if (!IsChildAccountDetectionEnabled()) {
304 SetIsChildAccount(false);
305 return;
307 account_id_ = SigninManagerFactory::GetForProfile(profile_)
308 ->GetAuthenticatedAccountId();
309 flag_fetcher_.reset(new AccountServiceFlagFetcher(
310 account_id_,
311 ProfileOAuth2TokenServiceFactory::GetForProfile(profile_),
312 profile_->GetRequestContext(),
313 base::Bind(&ChildAccountService::OnFlagsFetched,
314 weak_ptr_factory_.GetWeakPtr())));
317 void ChildAccountService::CancelFetchingServiceFlags() {
318 flag_fetcher_.reset();
319 account_id_.clear();
320 flag_fetch_timer_.Stop();
323 void ChildAccountService::OnFlagsFetched(
324 AccountServiceFlagFetcher::ResultCode result,
325 const std::vector<std::string>& flags) {
326 // If we've been signed out again (or signed in to a different account),
327 // ignore the fetched flags.
328 const std::string& new_account_id =
329 SigninManagerFactory::GetForProfile(profile_)
330 ->GetAuthenticatedAccountId();
331 if (account_id_.empty() || account_id_ != new_account_id)
332 return;
334 account_id_.clear();
336 // In case of an error, retry with exponential backoff.
337 if (result != AccountServiceFlagFetcher::SUCCESS) {
338 DLOG(WARNING) << "AccountServiceFlagFetcher returned error code " << result;
339 flag_fetch_backoff_.InformOfRequest(false);
340 ScheduleNextStatusFlagUpdate(flag_fetch_backoff_.GetTimeUntilRelease());
341 return;
344 flag_fetch_backoff_.InformOfRequest(true);
346 bool is_child_account =
347 std::find(flags.begin(), flags.end(),
348 kIsChildAccountServiceFlagName) != flags.end();
350 bool status_was_known = profile_->GetPrefs()->GetBoolean(
351 prefs::kChildAccountStatusKnown);
352 profile_->GetPrefs()->SetBoolean(prefs::kChildAccountStatusKnown, true);
354 if (!status_was_known) {
355 for (auto& callback : status_received_callback_list_)
356 callback.Run();
357 status_received_callback_list_.clear();
360 SetIsChildAccount(is_child_account);
362 ScheduleNextStatusFlagUpdate(
363 base::TimeDelta::FromSeconds(kUpdateIntervalSeconds));
366 void ChildAccountService::ScheduleNextStatusFlagUpdate(base::TimeDelta delay) {
367 flag_fetch_timer_.Start(
368 FROM_HERE, delay, this, &ChildAccountService::StartFetchingServiceFlags);
371 void ChildAccountService::PropagateChildStatusToUser(bool is_child) {
372 #if defined(OS_CHROMEOS)
373 user_manager::User* user =
374 chromeos::ProfileHelper::Get()->GetUserByProfile(profile_);
375 if (user) {
376 user_manager::UserManager::Get()->ChangeUserChildStatus(user, is_child);
377 } else {
378 LOG(WARNING) <<
379 "User instance wasn't found while setting child account flag.";
381 #endif
384 void ChildAccountService::SetFirstCustodianPrefs(
385 const FamilyInfoFetcher::FamilyMember& custodian) {
386 profile_->GetPrefs()->SetString(prefs::kSupervisedUserCustodianName,
387 custodian.display_name);
388 profile_->GetPrefs()->SetString(prefs::kSupervisedUserCustodianEmail,
389 custodian.email);
390 profile_->GetPrefs()->SetString(prefs::kSupervisedUserCustodianProfileURL,
391 custodian.profile_url);
392 profile_->GetPrefs()->SetString(
393 prefs::kSupervisedUserCustodianProfileImageURL,
394 custodian.profile_image_url);
397 void ChildAccountService::SetSecondCustodianPrefs(
398 const FamilyInfoFetcher::FamilyMember& custodian) {
399 profile_->GetPrefs()->SetString(prefs::kSupervisedUserSecondCustodianName,
400 custodian.display_name);
401 profile_->GetPrefs()->SetString(prefs::kSupervisedUserSecondCustodianEmail,
402 custodian.email);
403 profile_->GetPrefs()->SetString(
404 prefs::kSupervisedUserSecondCustodianProfileURL,
405 custodian.profile_url);
406 profile_->GetPrefs()->SetString(
407 prefs::kSupervisedUserSecondCustodianProfileImageURL,
408 custodian.profile_image_url);
411 void ChildAccountService::ClearFirstCustodianPrefs() {
412 profile_->GetPrefs()->ClearPref(prefs::kSupervisedUserCustodianName);
413 profile_->GetPrefs()->ClearPref(prefs::kSupervisedUserCustodianEmail);
414 profile_->GetPrefs()->ClearPref(prefs::kSupervisedUserCustodianProfileURL);
415 profile_->GetPrefs()->ClearPref(
416 prefs::kSupervisedUserCustodianProfileImageURL);
419 void ChildAccountService::ClearSecondCustodianPrefs() {
420 profile_->GetPrefs()->ClearPref(prefs::kSupervisedUserSecondCustodianName);
421 profile_->GetPrefs()->ClearPref(prefs::kSupervisedUserSecondCustodianEmail);
422 profile_->GetPrefs()->ClearPref(
423 prefs::kSupervisedUserSecondCustodianProfileURL);
424 profile_->GetPrefs()->ClearPref(
425 prefs::kSupervisedUserSecondCustodianProfileImageURL);