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/path_service.h"
13 #include "base/prefs/pref_service.h"
14 #include "base/time/time.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/supervised_user_constants.h"
20 #include "chrome/browser/supervised_user/supervised_user_service.h"
21 #include "chrome/browser/supervised_user/supervised_user_service_factory.h"
22 #include "chrome/browser/supervised_user/supervised_user_settings_service.h"
23 #include "chrome/browser/supervised_user/supervised_user_settings_service_factory.h"
24 #include "chrome/browser/sync/profile_sync_service.h"
25 #include "chrome/browser/sync/profile_sync_service_factory.h"
26 #include "chrome/common/chrome_paths.h"
27 #include "chrome/common/chrome_switches.h"
28 #include "chrome/common/pref_names.h"
29 #include "components/signin/core/browser/profile_oauth2_token_service.h"
30 #include "components/signin/core/browser/signin_manager.h"
32 #if defined(OS_CHROMEOS)
33 #include "chrome/browser/chromeos/profiles/profile_helper.h"
34 #include "components/user_manager/user_manager.h"
37 const char kIsChildAccountServiceFlagName
[] = "uca";
39 ChildAccountService::ChildAccountService(Profile
* profile
)
40 : profile_(profile
), active_(false), weak_ptr_factory_(this) {}
42 ChildAccountService::~ChildAccountService() {}
44 void ChildAccountService::Init() {
45 SigninManagerFactory::GetForProfile(profile_
)->AddObserver(this);
46 SupervisedUserServiceFactory::GetForProfile(profile_
)->SetDelegate(this);
48 PropagateChildStatusToUser(IsChildAccount());
50 // If we're already signed in, fetch the flag again just to be sure.
51 // (Previously, the browser might have been closed before we got the flag.
52 // This also handles the graduation use case in a basic way.)
53 std::string account_id
= SigninManagerFactory::GetForProfile(profile_
)
54 ->GetAuthenticatedAccountId();
55 if (!account_id
.empty())
56 StartFetchingServiceFlags(account_id
);
59 void ChildAccountService::Shutdown() {
60 CancelFetchingServiceFlags();
61 SupervisedUserService
* service
=
62 SupervisedUserServiceFactory::GetForProfile(profile_
);
63 service
->SetDelegate(NULL
);
65 SigninManagerFactory::GetForProfile(profile_
)->RemoveObserver(this);
68 bool ChildAccountService::IsChildAccount() const {
69 return profile_
->GetPrefs()->GetString(prefs::kSupervisedUserId
) ==
70 supervised_users::kChildAccountSUID
;
73 bool ChildAccountService::SetActive(bool active
) {
74 if (!IsChildAccount() && !active_
)
76 if (active_
== active
)
81 // In contrast to local SUs, child account SUs must sign in.
82 scoped_ptr
<base::Value
> allow_signin(new base::FundamentalValue(true));
83 SupervisedUserSettingsService
* settings_service
=
84 SupervisedUserSettingsServiceFactory::GetForProfile(profile_
);
85 settings_service
->SetLocalSetting(supervised_users::kSigninAllowed
,
87 #if !defined(OS_CHROMEOS)
88 // This is also used by user policies (UserPolicySigninService), but since
89 // child accounts can not also be Dasher accounts, there shouldn't be any
91 SigninManagerFactory::GetForProfile(profile_
)->ProhibitSignout(true);
94 // TODO(treib): Maybe only fetch the parents on the first start, and then
95 // refresh occasionally (like once every 24h)? That's what
96 // GAIAInfoUpdateService does.
97 family_fetcher_
.reset(new FamilyInfoFetcher(
99 SigninManagerFactory::GetForProfile(profile_
)
100 ->GetAuthenticatedAccountId(),
101 ProfileOAuth2TokenServiceFactory::GetForProfile(profile_
),
102 profile_
->GetRequestContext()));
103 family_fetcher_
->StartGetFamilyMembers();
105 // Set the permission request API URL and scope, unless they have been
106 // explicitly specified on the command line.
107 CommandLine
* command_line
= CommandLine::ForCurrentProcess();
108 if (!command_line
->HasSwitch(switches::kPermissionRequestApiUrl
)) {
109 command_line
->AppendSwitchASCII(
110 switches::kPermissionRequestApiUrl
,
111 "https://www.googleapis.com/"
112 "kidsmanagement/v1/people/me/permissionRequests");
114 if (!command_line
->HasSwitch(switches::kPermissionRequestApiScope
)) {
115 command_line
->AppendSwitchASCII(
116 switches::kPermissionRequestApiScope
,
117 "https://www.googleapis.com/auth/kid.permission");
120 EnableExperimentalFiltering();
122 SupervisedUserSettingsService
* settings_service
=
123 SupervisedUserSettingsServiceFactory::GetForProfile(profile_
);
124 settings_service
->SetLocalSetting(supervised_users::kSigninAllowed
,
125 scoped_ptr
<base::Value
>());
126 #if !defined(OS_CHROMEOS)
127 SigninManagerFactory::GetForProfile(profile_
)->ProhibitSignout(false);
130 ClearFirstCustodianPrefs();
131 ClearSecondCustodianPrefs();
134 // Trigger a sync reconfig to enable/disable the right SU data types.
135 // The logic to do this lives in the SupervisedUserSyncDataTypeController.
136 ProfileSyncService
* sync_service
=
137 ProfileSyncServiceFactory::GetForProfile(profile_
);
138 if (sync_service
->HasSyncSetupCompleted())
139 sync_service
->ReconfigureDatatypeManager();
144 base::FilePath
ChildAccountService::GetBlacklistPath() const {
146 return base::FilePath();
147 base::FilePath blacklist_path
;
148 PathService::Get(chrome::DIR_USER_DATA
, &blacklist_path
);
149 blacklist_path
= blacklist_path
.AppendASCII("su-blacklist.bin");
150 return blacklist_path
;
153 GURL
ChildAccountService::GetBlacklistURL() const {
156 return GURL("https://www.gstatic.com/chrome/supervised_user/"
157 "blacklist-20141001-1k.bin");
160 std::string
ChildAccountService::GetSafeSitesCx() const {
162 return std::string();
163 return "017993620680222980993%3A1wdumejvx5i";
166 void ChildAccountService::GoogleSigninSucceeded(const std::string
& account_id
,
167 const std::string
& username
,
168 const std::string
& password
) {
169 DCHECK(!account_id
.empty());
171 StartFetchingServiceFlags(account_id
);
174 void ChildAccountService::GoogleSignedOut(const std::string
& account_id
,
175 const std::string
& username
) {
176 DCHECK(!IsChildAccount());
177 CancelFetchingServiceFlags();
180 void ChildAccountService::OnGetFamilyMembersSuccess(
181 const std::vector
<FamilyInfoFetcher::FamilyMember
>& members
) {
182 bool hoh_found
= false;
183 bool parent_found
= false;
184 for (const FamilyInfoFetcher::FamilyMember
& member
: members
) {
185 if (member
.role
== FamilyInfoFetcher::HEAD_OF_HOUSEHOLD
) {
187 SetFirstCustodianPrefs(member
);
188 } else if (member
.role
== FamilyInfoFetcher::PARENT
) {
190 SetSecondCustodianPrefs(member
);
192 if (hoh_found
&& parent_found
)
196 DLOG(WARNING
) << "GetFamilyMembers didn't return a HOH?!";
197 ClearFirstCustodianPrefs();
200 ClearSecondCustodianPrefs();
203 void ChildAccountService::OnFailure(FamilyInfoFetcher::ErrorCode error
) {
204 DLOG(WARNING
) << "GetFamilyMembers failed with code " << error
;
205 // TODO(treib): Retry after a while?
208 void ChildAccountService::StartFetchingServiceFlags(
209 const std::string
& account_id
) {
210 account_id_
= account_id
;
211 flag_fetcher_
.reset(new AccountServiceFlagFetcher(
213 ProfileOAuth2TokenServiceFactory::GetForProfile(profile_
),
214 profile_
->GetRequestContext(),
215 base::Bind(&ChildAccountService::OnFlagsFetched
,
216 weak_ptr_factory_
.GetWeakPtr())));
219 void ChildAccountService::CancelFetchingServiceFlags() {
220 flag_fetcher_
.reset();
224 void ChildAccountService::OnFlagsFetched(
225 AccountServiceFlagFetcher::ResultCode result
,
226 const std::vector
<std::string
>& flags
) {
227 // If we've been signed out again (or signed in to a different account),
228 // ignore the fetched flags.
229 const std::string
& new_account_id
=
230 SigninManagerFactory::GetForProfile(profile_
)
231 ->GetAuthenticatedAccountId();
232 if (account_id_
.empty() || account_id_
!= new_account_id
)
235 // In case of an error, retry after a while.
236 if (result
!= AccountServiceFlagFetcher::SUCCESS
) {
237 DLOG(WARNING
) << "AccountServiceFlagFetcher returned error code " << result
;
238 base::MessageLoop::current()->PostDelayedTask(
240 base::Bind(&ChildAccountService::StartFetchingServiceFlags
,
241 weak_ptr_factory_
.GetWeakPtr(),
243 base::TimeDelta::FromSeconds(10));
249 bool is_child_account
=
250 std::find(flags
.begin(), flags
.end(),
251 kIsChildAccountServiceFlagName
) != flags
.end();
252 SetIsChildAccount(is_child_account
);
255 void ChildAccountService::SetIsChildAccount(bool is_child_account
) {
256 if (IsChildAccount() == is_child_account
)
259 if (is_child_account
) {
260 profile_
->GetPrefs()->SetString(prefs::kSupervisedUserId
,
261 supervised_users::kChildAccountSUID
);
263 profile_
->GetPrefs()->ClearPref(prefs::kSupervisedUserId
);
265 PropagateChildStatusToUser(is_child_account
);
268 void ChildAccountService::PropagateChildStatusToUser(bool is_child
) {
269 #if defined(OS_CHROMEOS)
270 // TODO(merkulova,treib): Figure out why this causes tests to fail.
271 // user_manager::User* user =
272 // chromeos::ProfileHelper::Get()->GetUserByProfile(profile_);
274 // user_manager::UserManager::Get()->ChangeUserSupervisedStatus(
278 // "User instance wasn't found while setting child account flag.";
283 void ChildAccountService::SetFirstCustodianPrefs(
284 const FamilyInfoFetcher::FamilyMember
& custodian
) {
285 profile_
->GetPrefs()->SetString(prefs::kSupervisedUserCustodianName
,
286 custodian
.display_name
);
287 profile_
->GetPrefs()->SetString(prefs::kSupervisedUserCustodianEmail
,
289 profile_
->GetPrefs()->SetString(prefs::kSupervisedUserCustodianProfileURL
,
290 custodian
.profile_url
);
291 profile_
->GetPrefs()->SetString(
292 prefs::kSupervisedUserCustodianProfileImageURL
,
293 custodian
.profile_image_url
);
296 void ChildAccountService::SetSecondCustodianPrefs(
297 const FamilyInfoFetcher::FamilyMember
& custodian
) {
298 profile_
->GetPrefs()->SetString(prefs::kSupervisedUserSecondCustodianName
,
299 custodian
.display_name
);
300 profile_
->GetPrefs()->SetString(prefs::kSupervisedUserSecondCustodianEmail
,
302 profile_
->GetPrefs()->SetString(
303 prefs::kSupervisedUserSecondCustodianProfileURL
,
304 custodian
.profile_url
);
305 profile_
->GetPrefs()->SetString(
306 prefs::kSupervisedUserSecondCustodianProfileImageURL
,
307 custodian
.profile_image_url
);
310 void ChildAccountService::ClearFirstCustodianPrefs() {
311 profile_
->GetPrefs()->ClearPref(prefs::kSupervisedUserCustodianName
);
312 profile_
->GetPrefs()->ClearPref(prefs::kSupervisedUserCustodianEmail
);
313 profile_
->GetPrefs()->ClearPref(prefs::kSupervisedUserCustodianProfileURL
);
314 profile_
->GetPrefs()->ClearPref(
315 prefs::kSupervisedUserCustodianProfileImageURL
);
318 void ChildAccountService::ClearSecondCustodianPrefs() {
319 profile_
->GetPrefs()->ClearPref(prefs::kSupervisedUserSecondCustodianName
);
320 profile_
->GetPrefs()->ClearPref(prefs::kSupervisedUserSecondCustodianEmail
);
321 profile_
->GetPrefs()->ClearPref(
322 prefs::kSupervisedUserSecondCustodianProfileURL
);
323 profile_
->GetPrefs()->ClearPref(
324 prefs::kSupervisedUserSecondCustodianProfileImageURL
);
327 void ChildAccountService::EnableExperimentalFiltering() {
328 CommandLine
* command_line
= CommandLine::ForCurrentProcess();
330 // Static blacklist defaults to enabled.
331 bool has_enable_blacklist
=
332 command_line
->HasSwitch(switches::kEnableSupervisedUserBlacklist
);
333 bool has_disable_blacklist
=
334 command_line
->HasSwitch(switches::kDisableSupervisedUserBlacklist
);
335 if (!has_enable_blacklist
&& !has_disable_blacklist
)
336 command_line
->AppendSwitch(switches::kEnableSupervisedUserBlacklist
);
338 // Query-based filtering also defaults to enabled.
339 bool has_enable_safesites
=
340 command_line
->HasSwitch(switches::kEnableSupervisedUserSafeSites
);
341 bool has_disable_safesites
=
342 command_line
->HasSwitch(switches::kDisableSupervisedUserSafeSites
);
343 if (!has_enable_safesites
&& !has_disable_safesites
)
344 command_line
->AppendSwitch(switches::kEnableSupervisedUserSafeSites
);