1 // Copyright 2013 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.
4
5 #include "chrome/browser/chromeos/login/multi_profile_user_controller.h"
6
7 #include "base/bind.h"
8 #include "base/command_line.h"
9 #include "base/memory/scoped_ptr.h"
10 #include "base/prefs/pref_change_registrar.h"
11 #include "base/prefs/pref_registry_simple.h"
12 #include "base/prefs/pref_service.h"
13 #include "base/prefs/scoped_user_pref_update.h"
14 #include "chrome/browser/chromeos/login/multi_profile_user_controller_delegate.h"
15 #include "chrome/browser/chromeos/login/user.h"
16 #include "chrome/browser/chromeos/login/user_manager.h"
17 #include "chrome/browser/chromeos/policy/policy_cert_service.h"
18 #include "chrome/browser/chromeos/policy/policy_cert_service_factory.h"
19 #include "chrome/browser/prefs/pref_service_syncable.h"
20 #include "chrome/browser/profiles/profile.h"
21 #include "chrome/common/pref_names.h"
22 #include "chromeos/chromeos_switches.h"
23 #include "google_apis/gaia/gaia_auth_util.h"
24
25 namespace chromeos {
26
27 namespace {
28
SanitizeBehaviorValue(const std::string & value)29 std::string SanitizeBehaviorValue(const std::string& value) {
30 if (value == MultiProfileUserController::kBehaviorUnrestricted ||
31 value == MultiProfileUserController::kBehaviorPrimaryOnly ||
32 value == MultiProfileUserController::kBehaviorNotAllowed) {
33 return value;
34 }
35
36 return std::string(MultiProfileUserController::kBehaviorUnrestricted);
37 }
38
39 } // namespace
40
41 // static
42 const char MultiProfileUserController::kBehaviorUnrestricted[] = "unrestricted";
43 const char MultiProfileUserController::kBehaviorPrimaryOnly[] = "primary-only";
44 const char MultiProfileUserController::kBehaviorNotAllowed[] = "not-allowed";
45
MultiProfileUserController(MultiProfileUserControllerDelegate * delegate,PrefService * local_state)46 MultiProfileUserController::MultiProfileUserController(
47 MultiProfileUserControllerDelegate* delegate,
48 PrefService* local_state)
49 : delegate_(delegate),
50 local_state_(local_state) {
51 }
52
~MultiProfileUserController()53 MultiProfileUserController::~MultiProfileUserController() {}
54
55 // static
RegisterPrefs(PrefRegistrySimple * registry)56 void MultiProfileUserController::RegisterPrefs(
57 PrefRegistrySimple* registry) {
58 registry->RegisterDictionaryPref(prefs::kCachedMultiProfileUserBehavior);
59 }
60
61 // static
RegisterProfilePrefs(user_prefs::PrefRegistrySyncable * registry)62 void MultiProfileUserController::RegisterProfilePrefs(
63 user_prefs::PrefRegistrySyncable* registry) {
64 // Use "disabled" default if there is no user manager or no logged in user.
65 // This is true for signin proflie (where the value does not matter) or
66 // for the primary user's profile. This essentially disables multiprofile
67 // unless the primary user has a policy to say otherwise.
68 const bool use_disable_default =
69 !CommandLine::ForCurrentProcess()->HasSwitch(
70 switches::kForceMultiProfileInTests) &&
71 (!UserManager::IsInitialized() ||
72 UserManager::Get()->GetLoggedInUsers().size() == 1);
73 registry->RegisterStringPref(
74 prefs::kMultiProfileUserBehavior,
75 use_disable_default ? kBehaviorNotAllowed : kBehaviorUnrestricted,
76 user_prefs::PrefRegistrySyncable::UNSYNCABLE_PREF);
77 }
78
IsUserAllowedInSession(const std::string & user_email) const79 bool MultiProfileUserController::IsUserAllowedInSession(
80 const std::string& user_email) const {
81 UserManager* user_manager = UserManager::Get();
82 CHECK(user_manager);
83
84 const User* primary_user = user_manager->GetPrimaryUser();
85 std::string primary_user_email;
86 if (primary_user)
87 primary_user_email = primary_user->email();
88
89 // Always allow if there is no primary user or user being checked is the
90 // primary user.
91 if (primary_user_email.empty() || primary_user_email == user_email)
92 return true;
93
94 // Owner is not allowed to be secondary user.
95 if (user_manager->GetOwnerEmail() == user_email)
96 return false;
97
98 // Don't allow profiles potentially tainted by data fetched with policy-pushed
99 // certificates to join a multiprofile session.
100 if (policy::PolicyCertServiceFactory::UsedPolicyCertificates(user_email))
101 return false;
102
103 // Don't allow any secondary profiles if the primary profile is tainted.
104 if (policy::PolicyCertServiceFactory::UsedPolicyCertificates(
105 primary_user_email)) {
106 // Check directly in local_state before checking if the primary user has
107 // a PolicyCertService. His profile may have been tainted previously though
108 // he didn't get a PolicyCertService created for this session.
109 return false;
110 }
111
112 // If the primary profile already has policy certificates installed but hasn't
113 // used them yet then it can become tainted at any time during this session;
114 // disable secondary profiles in this case too.
115 Profile* primary_user_profile =
116 primary_user ? user_manager->GetProfileByUser(primary_user) : NULL;
117 policy::PolicyCertService* service =
118 primary_user_profile ? policy::PolicyCertServiceFactory::GetForProfile(
119 primary_user_profile)
120 : NULL;
121 if (service && service->has_policy_certificates())
122 return false;
123
124 // No user is allowed if the primary user policy forbids it.
125 const std::string primary_user_behavior =
126 primary_user_profile->GetPrefs()->GetString(
127 prefs::kMultiProfileUserBehavior);
128 if (primary_user_behavior == kBehaviorNotAllowed)
129 return false;
130
131 // The user must have 'unrestricted' policy to be a secondary user.
132 const std::string behavior = GetCachedValue(user_email);
133 return behavior == kBehaviorUnrestricted;
134 }
135
StartObserving(Profile * user_profile)136 void MultiProfileUserController::StartObserving(Profile* user_profile) {
137 // Profile name could be empty during tests.
138 if (user_profile->GetProfileName().empty())
139 return;
140
141 scoped_ptr<PrefChangeRegistrar> registrar(new PrefChangeRegistrar);
142 registrar->Init(user_profile->GetPrefs());
143 registrar->Add(
144 prefs::kMultiProfileUserBehavior,
145 base::Bind(&MultiProfileUserController::OnUserPrefChanged,
146 base::Unretained(this),
147 user_profile));
148 pref_watchers_.push_back(registrar.release());
149
150 OnUserPrefChanged(user_profile);
151 }
152
RemoveCachedValues(const std::string & user_email)153 void MultiProfileUserController::RemoveCachedValues(
154 const std::string& user_email) {
155 DictionaryPrefUpdate update(local_state_,
156 prefs::kCachedMultiProfileUserBehavior);
157 update->RemoveWithoutPathExpansion(user_email, NULL);
158 policy::PolicyCertServiceFactory::ClearUsedPolicyCertificates(user_email);
159 }
160
GetCachedValue(const std::string & user_email) const161 std::string MultiProfileUserController::GetCachedValue(
162 const std::string& user_email) const {
163 const DictionaryValue* dict =
164 local_state_->GetDictionary(prefs::kCachedMultiProfileUserBehavior);
165 std::string value;
166 if (dict && dict->GetStringWithoutPathExpansion(user_email, &value))
167 return SanitizeBehaviorValue(value);
168
169 return std::string(kBehaviorUnrestricted);
170 }
171
SetCachedValue(const std::string & user_email,const std::string & behavior)172 void MultiProfileUserController::SetCachedValue(
173 const std::string& user_email,
174 const std::string& behavior) {
175 DictionaryPrefUpdate update(local_state_,
176 prefs::kCachedMultiProfileUserBehavior);
177 update->SetStringWithoutPathExpansion(user_email,
178 SanitizeBehaviorValue(behavior));
179 }
180
CheckSessionUsers()181 void MultiProfileUserController::CheckSessionUsers() {
182 const UserList& users = UserManager::Get()->GetLoggedInUsers();
183 for (UserList::const_iterator it = users.begin(); it != users.end(); ++it) {
184 if (!IsUserAllowedInSession((*it)->email())) {
185 delegate_->OnUserNotAllowed();
186 return;
187 }
188 }
189 }
190
OnUserPrefChanged(Profile * user_profile)191 void MultiProfileUserController::OnUserPrefChanged(
192 Profile* user_profile) {
193 std::string user_email = user_profile->GetProfileName();
194 CHECK(!user_email.empty());
195 user_email = gaia::CanonicalizeEmail(user_email);
196
197 PrefService* prefs = user_profile->GetPrefs();
198 if (prefs->FindPreference(prefs::kMultiProfileUserBehavior)
199 ->IsDefaultValue()) {
200 // Migration code to clear cached default behavior.
201 // TODO(xiyuan): Remove this after M35.
202 DictionaryPrefUpdate update(local_state_,
203 prefs::kCachedMultiProfileUserBehavior);
204 update->RemoveWithoutPathExpansion(user_email, NULL);
205 } else {
206 const std::string behavior =
207 prefs->GetString(prefs::kMultiProfileUserBehavior);
208 SetCachedValue(user_email, behavior);
209 }
210
211 CheckSessionUsers();
212 }
213
214 } // namespace chromeos
215