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/policy/policy_cert_service.h" 15#include "chrome/browser/chromeos/policy/policy_cert_service_factory.h" 16#include "chrome/browser/chromeos/profiles/profile_helper.h" 17#include "chrome/browser/prefs/pref_service_syncable.h" 18#include "chrome/browser/profiles/profile.h" 19#include "chrome/common/pref_names.h" 20#include "components/user_manager/user.h" 21#include "components/user_manager/user_manager.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 90// static 91MultiProfileUserController::UserAllowedInSessionReason 92MultiProfileUserController::GetPrimaryUserPolicy() { 93 user_manager::UserManager* user_manager = user_manager::UserManager::Get(); 94 CHECK(user_manager); 95 96 const user_manager::User* user = user_manager->GetPrimaryUser(); 97 if (!user) 98 return ALLOWED; 99 100 // Don't allow any secondary profiles if the primary profile is tainted. 101 if (policy::PolicyCertServiceFactory::UsedPolicyCertificates(user->email())) { 102 // Check directly in local_state before checking if the primary user has 103 // a PolicyCertService. His profile may have been tainted previously though 104 // he didn't get a PolicyCertService created for this session. 105 return NOT_ALLOWED_PRIMARY_POLICY_CERT_TAINTED; 106 } 107 108 Profile* profile = ProfileHelper::Get()->GetProfileByUser(user); 109 if (!profile) 110 return ALLOWED; 111 112 // If the primary profile already has policy certificates installed but 113 // hasn't used them yet then it can become tainted at any time during this 114 // session disable secondary profiles in this case too. 115 policy::PolicyCertService* service = 116 policy::PolicyCertServiceFactory::GetForProfile(profile); 117 if (service && service->has_policy_certificates()) 118 return NOT_ALLOWED_PRIMARY_POLICY_CERT_TAINTED; 119 120 // No user is allowed if the primary user policy forbids it. 121 const std::string behavior = profile->GetPrefs()->GetString( 122 prefs::kMultiProfileUserBehavior); 123 if (behavior == kBehaviorNotAllowed) 124 return NOT_ALLOWED_PRIMARY_USER_POLICY_FORBIDS; 125 126 return ALLOWED; 127} 128 129bool MultiProfileUserController::IsUserAllowedInSession( 130 const std::string& user_email, 131 MultiProfileUserController::UserAllowedInSessionReason* reason) const { 132 user_manager::UserManager* user_manager = user_manager::UserManager::Get(); 133 CHECK(user_manager); 134 135 const user_manager::User* primary_user = user_manager->GetPrimaryUser(); 136 std::string primary_user_email; 137 if (primary_user) 138 primary_user_email = primary_user->email(); 139 140 // Always allow if there is no primary user or user being checked is the 141 // primary user. 142 if (primary_user_email.empty() || primary_user_email == user_email) 143 return SetUserAllowedReason(reason, ALLOWED); 144 145 // Owner is not allowed to be secondary user. 146 if (user_manager->GetOwnerEmail() == user_email) 147 return SetUserAllowedReason(reason, NOT_ALLOWED_OWNER_AS_SECONDARY); 148 149 // Don't allow profiles potentially tainted by data fetched with policy-pushed 150 // certificates to join a multiprofile session. 151 if (policy::PolicyCertServiceFactory::UsedPolicyCertificates(user_email)) 152 return SetUserAllowedReason(reason, NOT_ALLOWED_POLICY_CERT_TAINTED); 153 154 UserAllowedInSessionReason primary_user_policy = GetPrimaryUserPolicy(); 155 if (primary_user_policy != ALLOWED) 156 return SetUserAllowedReason(reason, primary_user_policy); 157 158 // The user must have 'unrestricted' policy to be a secondary user. 159 const std::string behavior = GetCachedValue(user_email); 160 return SetUserAllowedReason( 161 reason, 162 behavior == kBehaviorUnrestricted ? ALLOWED : NOT_ALLOWED_POLICY_FORBIDS); 163} 164 165void MultiProfileUserController::StartObserving(Profile* user_profile) { 166 // Profile name could be empty during tests. 167 if (user_profile->GetProfileName().empty()) 168 return; 169 170 scoped_ptr<PrefChangeRegistrar> registrar(new PrefChangeRegistrar); 171 registrar->Init(user_profile->GetPrefs()); 172 registrar->Add( 173 prefs::kMultiProfileUserBehavior, 174 base::Bind(&MultiProfileUserController::OnUserPrefChanged, 175 base::Unretained(this), 176 user_profile)); 177 pref_watchers_.push_back(registrar.release()); 178 179 OnUserPrefChanged(user_profile); 180} 181 182void MultiProfileUserController::RemoveCachedValues( 183 const std::string& user_email) { 184 DictionaryPrefUpdate update(local_state_, 185 prefs::kCachedMultiProfileUserBehavior); 186 update->RemoveWithoutPathExpansion(user_email, NULL); 187 policy::PolicyCertServiceFactory::ClearUsedPolicyCertificates(user_email); 188} 189 190std::string MultiProfileUserController::GetCachedValue( 191 const std::string& user_email) const { 192 const base::DictionaryValue* dict = 193 local_state_->GetDictionary(prefs::kCachedMultiProfileUserBehavior); 194 std::string value; 195 if (dict && dict->GetStringWithoutPathExpansion(user_email, &value)) 196 return SanitizeBehaviorValue(value); 197 198 return std::string(kBehaviorUnrestricted); 199} 200 201void MultiProfileUserController::SetCachedValue( 202 const std::string& user_email, 203 const std::string& behavior) { 204 DictionaryPrefUpdate update(local_state_, 205 prefs::kCachedMultiProfileUserBehavior); 206 update->SetStringWithoutPathExpansion(user_email, 207 SanitizeBehaviorValue(behavior)); 208} 209 210void MultiProfileUserController::CheckSessionUsers() { 211 const user_manager::UserList& users = 212 user_manager::UserManager::Get()->GetLoggedInUsers(); 213 for (user_manager::UserList::const_iterator it = users.begin(); 214 it != users.end(); 215 ++it) { 216 if (!IsUserAllowedInSession((*it)->email(), NULL)) { 217 delegate_->OnUserNotAllowed((*it)->email()); 218 return; 219 } 220 } 221} 222 223void MultiProfileUserController::OnUserPrefChanged( 224 Profile* user_profile) { 225 std::string user_email = user_profile->GetProfileName(); 226 CHECK(!user_email.empty()); 227 user_email = gaia::CanonicalizeEmail(user_email); 228 229 PrefService* prefs = user_profile->GetPrefs(); 230 if (prefs->FindPreference(prefs::kMultiProfileUserBehavior) 231 ->IsDefaultValue()) { 232 // Migration code to clear cached default behavior. 233 // TODO(xiyuan): Remove this after M35. 234 DictionaryPrefUpdate update(local_state_, 235 prefs::kCachedMultiProfileUserBehavior); 236 update->RemoveWithoutPathExpansion(user_email, NULL); 237 } else { 238 const std::string behavior = 239 prefs->GetString(prefs::kMultiProfileUserBehavior); 240 SetCachedValue(user_email, behavior); 241 } 242 243 CheckSessionUsers(); 244} 245 246} // namespace chromeos 247