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"
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.
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.
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.
70 // Don't use initial delay unless the last request was an error.
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() {}
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
))
92 if (command_line
->HasSwitch(switches::kEnableChildAccountDetection
))
95 if (group_name
== "Disabled")
100 void ChildAccountService::RegisterProfilePrefs(
101 user_prefs::PrefRegistrySyncable
* registry
) {
102 registry
->RegisterBooleanPref(
103 prefs::kChildAccountStatusKnown
,
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
)
113 if (is_child_account
) {
114 profile_
->GetPrefs()->SetString(prefs::kSupervisedUserId
,
115 supervised_users::kChildAccountSUID
);
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
);
143 SigninManagerFactory::GetForProfile(profile_
)->RemoveObserver(this);
147 void ChildAccountService::AddChildStatusReceivedCallback(
148 const base::Closure
& callback
) {
149 if (IsChildAccountStatusKnown())
152 status_received_callback_list_
.push_back(callback
);
155 bool ChildAccountService::SetActive(bool active
) {
156 if (!profile_
->IsChild() && !active_
)
158 if (active_
== 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
173 SigninManagerFactory::GetForProfile(profile_
)->ProhibitSignout(true);
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_
));
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);
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();
207 base::FilePath
ChildAccountService::GetBlacklistPath() const {
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 {
219 return GURL("https://www.gstatic.com/chrome/supervised_user/"
220 "blacklist-20141001-1k.bin");
223 std::string
ChildAccountService::GetSafeSitesCx() const {
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(),
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
) {
254 SetFirstCustodianPrefs(member
);
255 } else if (member
.role
== FamilyInfoFetcher::PARENT
) {
257 SetSecondCustodianPrefs(member
);
259 if (hoh_found
&& parent_found
)
263 DLOG(WARNING
) << "GetFamilyMembers didn't return a HOH?!";
264 ClearFirstCustodianPrefs();
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(
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);
307 account_id_
= SigninManagerFactory::GetForProfile(profile_
)
308 ->GetAuthenticatedAccountId();
309 flag_fetcher_
.reset(new AccountServiceFlagFetcher(
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();
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
)
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());
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_
)
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_
);
376 user_manager::UserManager::Get()->ChangeUserChildStatus(user
, is_child
);
379 "User instance wasn't found while setting child account flag.";
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
,
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
,
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
);