• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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