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