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