supervised_user_registration_utility.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/supervised_user/supervised_user_registration_utility.h" 6 7#include "base/base64.h" 8#include "base/bind.h" 9#include "base/command_line.h" 10#include "base/memory/scoped_ptr.h" 11#include "base/prefs/pref_service.h" 12#include "base/rand_util.h" 13#include "base/strings/utf_string_conversions.h" 14#include "chrome/browser/profiles/profile.h" 15#include "chrome/browser/signin/chrome_signin_client_factory.h" 16#include "chrome/browser/signin/profile_oauth2_token_service_factory.h" 17#include "chrome/browser/signin/signin_manager_factory.h" 18#include "chrome/browser/supervised_user/supervised_user_constants.h" 19#include "chrome/browser/supervised_user/supervised_user_refresh_token_fetcher.h" 20#include "chrome/browser/supervised_user/supervised_user_shared_settings_service.h" 21#include "chrome/browser/supervised_user/supervised_user_shared_settings_service_factory.h" 22#include "chrome/browser/supervised_user/supervised_user_shared_settings_update.h" 23#include "chrome/browser/supervised_user/supervised_user_sync_service.h" 24#include "chrome/browser/supervised_user/supervised_user_sync_service_factory.h" 25#include "chrome/browser/sync/glue/device_info.h" 26#include "chrome/common/chrome_switches.h" 27#include "chrome/common/pref_names.h" 28#include "components/signin/core/browser/profile_oauth2_token_service.h" 29#include "components/signin/core/browser/signin_client.h" 30#include "components/signin/core/browser/signin_manager.h" 31#include "google_apis/gaia/gaia_urls.h" 32#include "google_apis/gaia/google_service_auth_error.h" 33 34using base::DictionaryValue; 35 36namespace { 37 38SupervisedUserRegistrationUtility* g_instance_for_tests = NULL; 39 40// Actual implementation of SupervisedUserRegistrationUtility. 41class SupervisedUserRegistrationUtilityImpl 42 : public SupervisedUserRegistrationUtility, 43 public SupervisedUserSyncServiceObserver { 44 public: 45 SupervisedUserRegistrationUtilityImpl( 46 PrefService* prefs, 47 scoped_ptr<SupervisedUserRefreshTokenFetcher> token_fetcher, 48 SupervisedUserSyncService* service, 49 SupervisedUserSharedSettingsService* shared_settings_service); 50 51 virtual ~SupervisedUserRegistrationUtilityImpl(); 52 53 // Registers a new supervised user with the server. |supervised_user_id| is a 54 // new unique ID for the new supervised user. If its value is the same as that 55 // of one of the existing supervised users, then the same user will be created 56 // on this machine (and if he has no avatar in sync, his avatar will be 57 // updated). |info| contains necessary information like the display name of 58 // the user and his avatar. |callback| is called with the result of the 59 // registration. We use the info here and not the profile, because on Chrome 60 // OS the profile of the supervised user does not yet exist. 61 virtual void Register(const std::string& supervised_user_id, 62 const SupervisedUserRegistrationInfo& info, 63 const RegistrationCallback& callback) OVERRIDE; 64 65 // SupervisedUserSyncServiceObserver: 66 virtual void OnSupervisedUserAcknowledged( 67 const std::string& supervised_user_id) OVERRIDE; 68 virtual void OnSupervisedUsersSyncingStopped() OVERRIDE; 69 virtual void OnSupervisedUsersChanged() OVERRIDE; 70 71 private: 72 // Fetches the supervised user token when we have the device name. 73 void FetchToken(const std::string& client_name); 74 75 // Called when we have received a token for the supervised user. 76 void OnReceivedToken(const GoogleServiceAuthError& error, 77 const std::string& token); 78 79 // Dispatches the callback and cleans up if all the conditions have been met. 80 void CompleteRegistrationIfReady(); 81 82 // Aborts any registration currently in progress. If |run_callback| is true, 83 // calls the callback specified in Register() with the given |error|. 84 void AbortPendingRegistration(bool run_callback, 85 const GoogleServiceAuthError& error); 86 87 // If |run_callback| is true, dispatches the callback with the saved token 88 // (which may be empty) and the given |error|. In any case, resets internal 89 // variables to be ready for the next registration. 90 void CompleteRegistration(bool run_callback, 91 const GoogleServiceAuthError& error); 92 93 // Cancels any registration currently in progress, without calling the 94 // callback or reporting an error. 95 void CancelPendingRegistration(); 96 97 // SupervisedUserSharedSettingsUpdate acknowledgment callback for password 98 // data in shared settings. 99 void OnPasswordChangeAcknowledged(bool success); 100 101 PrefService* prefs_; 102 scoped_ptr<SupervisedUserRefreshTokenFetcher> token_fetcher_; 103 104 // A |KeyedService| owned by the custodian profile. 105 SupervisedUserSyncService* supervised_user_sync_service_; 106 107 // A |KeyedService| owned by the custodian profile. 108 SupervisedUserSharedSettingsService* supervised_user_shared_settings_service_; 109 110 std::string pending_supervised_user_id_; 111 std::string pending_supervised_user_token_; 112 bool pending_supervised_user_acknowledged_; 113 bool is_existing_supervised_user_; 114 bool avatar_updated_; 115 RegistrationCallback callback_; 116 scoped_ptr<SupervisedUserSharedSettingsUpdate> password_update_; 117 118 base::WeakPtrFactory<SupervisedUserRegistrationUtilityImpl> weak_ptr_factory_; 119 120 DISALLOW_COPY_AND_ASSIGN(SupervisedUserRegistrationUtilityImpl); 121}; 122 123} // namespace 124 125SupervisedUserRegistrationInfo::SupervisedUserRegistrationInfo( 126 const base::string16& name, 127 int avatar_index) 128 : avatar_index(avatar_index), 129 name(name) { 130} 131 132SupervisedUserRegistrationInfo::~SupervisedUserRegistrationInfo() {} 133 134ScopedTestingSupervisedUserRegistrationUtility:: 135 ScopedTestingSupervisedUserRegistrationUtility( 136 SupervisedUserRegistrationUtility* instance) { 137 SupervisedUserRegistrationUtility::SetUtilityForTests(instance); 138} 139 140ScopedTestingSupervisedUserRegistrationUtility:: 141 ~ScopedTestingSupervisedUserRegistrationUtility() { 142 SupervisedUserRegistrationUtility::SetUtilityForTests(NULL); 143} 144 145// static 146scoped_ptr<SupervisedUserRegistrationUtility> 147SupervisedUserRegistrationUtility::Create(Profile* profile) { 148 if (g_instance_for_tests) { 149 SupervisedUserRegistrationUtility* result = g_instance_for_tests; 150 g_instance_for_tests = NULL; 151 return make_scoped_ptr(result); 152 } 153 154 ProfileOAuth2TokenService* token_service = 155 ProfileOAuth2TokenServiceFactory::GetForProfile(profile); 156 SigninManagerBase* signin_manager = 157 SigninManagerFactory::GetForProfile(profile); 158 SigninClient* signin_client = 159 ChromeSigninClientFactory::GetForProfile(profile); 160 std::string signin_scoped_device_id = 161 signin_client->GetSigninScopedDeviceId(); 162 scoped_ptr<SupervisedUserRefreshTokenFetcher> token_fetcher = 163 SupervisedUserRefreshTokenFetcher::Create( 164 token_service, 165 signin_manager->GetAuthenticatedAccountId(), 166 signin_scoped_device_id, 167 profile->GetRequestContext()); 168 SupervisedUserSyncService* supervised_user_sync_service = 169 SupervisedUserSyncServiceFactory::GetForProfile(profile); 170 SupervisedUserSharedSettingsService* supervised_user_shared_settings_service = 171 SupervisedUserSharedSettingsServiceFactory::GetForBrowserContext(profile); 172 return make_scoped_ptr(SupervisedUserRegistrationUtility::CreateImpl( 173 profile->GetPrefs(), 174 token_fetcher.Pass(), 175 supervised_user_sync_service, 176 supervised_user_shared_settings_service)); 177} 178 179// static 180std::string SupervisedUserRegistrationUtility::GenerateNewSupervisedUserId() { 181 std::string new_supervised_user_id; 182 base::Base64Encode(base::RandBytesAsString(8), &new_supervised_user_id); 183 return new_supervised_user_id; 184} 185 186// static 187void SupervisedUserRegistrationUtility::SetUtilityForTests( 188 SupervisedUserRegistrationUtility* utility) { 189 if (g_instance_for_tests) 190 delete g_instance_for_tests; 191 g_instance_for_tests = utility; 192} 193 194// static 195SupervisedUserRegistrationUtility* 196SupervisedUserRegistrationUtility::CreateImpl( 197 PrefService* prefs, 198 scoped_ptr<SupervisedUserRefreshTokenFetcher> token_fetcher, 199 SupervisedUserSyncService* service, 200 SupervisedUserSharedSettingsService* shared_settings_service) { 201 return new SupervisedUserRegistrationUtilityImpl(prefs, 202 token_fetcher.Pass(), 203 service, 204 shared_settings_service); 205} 206 207namespace { 208 209SupervisedUserRegistrationUtilityImpl::SupervisedUserRegistrationUtilityImpl( 210 PrefService* prefs, 211 scoped_ptr<SupervisedUserRefreshTokenFetcher> token_fetcher, 212 SupervisedUserSyncService* service, 213 SupervisedUserSharedSettingsService* shared_settings_service) 214 : prefs_(prefs), 215 token_fetcher_(token_fetcher.Pass()), 216 supervised_user_sync_service_(service), 217 supervised_user_shared_settings_service_(shared_settings_service), 218 pending_supervised_user_acknowledged_(false), 219 is_existing_supervised_user_(false), 220 avatar_updated_(false), 221 weak_ptr_factory_(this) { 222 supervised_user_sync_service_->AddObserver(this); 223} 224 225SupervisedUserRegistrationUtilityImpl:: 226~SupervisedUserRegistrationUtilityImpl() { 227 supervised_user_sync_service_->RemoveObserver(this); 228 CancelPendingRegistration(); 229} 230 231void SupervisedUserRegistrationUtilityImpl::Register( 232 const std::string& supervised_user_id, 233 const SupervisedUserRegistrationInfo& info, 234 const RegistrationCallback& callback) { 235 DCHECK(pending_supervised_user_id_.empty()); 236 callback_ = callback; 237 pending_supervised_user_id_ = supervised_user_id; 238 239 bool need_password_update = !info.password_data.empty(); 240 const base::DictionaryValue* dict = 241 prefs_->GetDictionary(prefs::kSupervisedUsers); 242 is_existing_supervised_user_ = dict->HasKey(supervised_user_id); 243 if (!is_existing_supervised_user_) { 244 supervised_user_sync_service_->AddSupervisedUser( 245 pending_supervised_user_id_, 246 base::UTF16ToUTF8(info.name), 247 info.master_key, 248 info.password_signature_key, 249 info.password_encryption_key, 250 info.avatar_index); 251 } else { 252 const base::DictionaryValue* value = NULL; 253 bool success = 254 dict->GetDictionaryWithoutPathExpansion(supervised_user_id, &value); 255 DCHECK(success); 256 std::string key; 257 bool need_keys = !info.password_signature_key.empty() || 258 !info.password_encryption_key.empty(); 259 bool have_keys = 260 value->GetString(SupervisedUserSyncService::kPasswordSignatureKey, 261 &key) && 262 !key.empty() && 263 value->GetString(SupervisedUserSyncService::kPasswordEncryptionKey, 264 &key) && 265 !key.empty(); 266 267 bool keys_need_update = need_keys && !have_keys; 268 269 if (keys_need_update) { 270 supervised_user_sync_service_->UpdateSupervisedUser( 271 pending_supervised_user_id_, 272 base::UTF16ToUTF8(info.name), 273 info.master_key, 274 info.password_signature_key, 275 info.password_encryption_key, 276 info.avatar_index); 277 } else { 278 // The user already exists and does not need to be updated. 279 need_password_update = false; 280 OnSupervisedUserAcknowledged(supervised_user_id); 281 } 282 avatar_updated_ = 283 supervised_user_sync_service_->UpdateSupervisedUserAvatarIfNeeded( 284 supervised_user_id, 285 info.avatar_index); 286 } 287#if defined(OS_CHROMEOS) 288 const char* kAvatarKey = supervised_users::kChromeOSAvatarIndex; 289#else 290 const char* kAvatarKey = supervised_users::kChromeAvatarIndex; 291#endif 292 supervised_user_shared_settings_service_->SetValue( 293 pending_supervised_user_id_, kAvatarKey, 294 base::FundamentalValue(info.avatar_index)); 295 if (need_password_update) { 296 password_update_.reset(new SupervisedUserSharedSettingsUpdate( 297 supervised_user_shared_settings_service_, 298 pending_supervised_user_id_, 299 supervised_users::kChromeOSPasswordData, 300 scoped_ptr<base::Value>(info.password_data.DeepCopy()), 301 base::Bind( 302 &SupervisedUserRegistrationUtilityImpl:: 303 OnPasswordChangeAcknowledged, 304 weak_ptr_factory_.GetWeakPtr()))); 305 } 306 307 browser_sync::DeviceInfo::GetClientName( 308 base::Bind(&SupervisedUserRegistrationUtilityImpl::FetchToken, 309 weak_ptr_factory_.GetWeakPtr())); 310} 311 312void SupervisedUserRegistrationUtilityImpl::CancelPendingRegistration() { 313 AbortPendingRegistration( 314 false, // Don't run the callback. The error will be ignored. 315 GoogleServiceAuthError(GoogleServiceAuthError::NONE)); 316} 317 318void SupervisedUserRegistrationUtilityImpl::OnSupervisedUserAcknowledged( 319 const std::string& supervised_user_id) { 320 DCHECK_EQ(pending_supervised_user_id_, supervised_user_id); 321 DCHECK(!pending_supervised_user_acknowledged_); 322 pending_supervised_user_acknowledged_ = true; 323 CompleteRegistrationIfReady(); 324} 325 326void SupervisedUserRegistrationUtilityImpl::OnPasswordChangeAcknowledged( 327 bool success) { 328 DCHECK(password_update_); 329 DCHECK(success); 330 password_update_.reset(); 331 CompleteRegistrationIfReady(); 332} 333 334void SupervisedUserRegistrationUtilityImpl::OnSupervisedUsersSyncingStopped() { 335 AbortPendingRegistration( 336 true, // Run the callback. 337 GoogleServiceAuthError(GoogleServiceAuthError::REQUEST_CANCELED)); 338} 339 340void SupervisedUserRegistrationUtilityImpl::OnSupervisedUsersChanged() {} 341 342void SupervisedUserRegistrationUtilityImpl::FetchToken( 343 const std::string& client_name) { 344 token_fetcher_->Start( 345 pending_supervised_user_id_, client_name, 346 base::Bind(&SupervisedUserRegistrationUtilityImpl::OnReceivedToken, 347 weak_ptr_factory_.GetWeakPtr())); 348} 349 350void SupervisedUserRegistrationUtilityImpl::OnReceivedToken( 351 const GoogleServiceAuthError& error, 352 const std::string& token) { 353 if (error.state() != GoogleServiceAuthError::NONE) { 354 CompleteRegistration(true, error); 355 return; 356 } 357 358 DCHECK(!token.empty()); 359 pending_supervised_user_token_ = token; 360 CompleteRegistrationIfReady(); 361} 362 363void SupervisedUserRegistrationUtilityImpl::CompleteRegistrationIfReady() { 364 bool skip_check = CommandLine::ForCurrentProcess()->HasSwitch( 365 switches::kNoSupervisedUserAcknowledgmentCheck); 366 367 if (!pending_supervised_user_acknowledged_ && !skip_check) 368 return; 369 if (password_update_ && !skip_check) 370 return; 371 if (pending_supervised_user_token_.empty()) 372 return; 373 374 GoogleServiceAuthError error(GoogleServiceAuthError::NONE); 375 CompleteRegistration(true, error); 376} 377 378void SupervisedUserRegistrationUtilityImpl::AbortPendingRegistration( 379 bool run_callback, 380 const GoogleServiceAuthError& error) { 381 pending_supervised_user_token_.clear(); 382 CompleteRegistration(run_callback, error); 383} 384 385void SupervisedUserRegistrationUtilityImpl::CompleteRegistration( 386 bool run_callback, 387 const GoogleServiceAuthError& error) { 388 if (callback_.is_null()) 389 return; 390 391 if (pending_supervised_user_token_.empty()) { 392 DCHECK(!pending_supervised_user_id_.empty()); 393 394 if (!is_existing_supervised_user_) { 395 // Remove the pending supervised user if we weren't successful. 396 // However, check that we are not importing a supervised user 397 // before deleting it from sync to avoid accidental deletion of 398 // existing supervised users by just canceling the registration for 399 // example. 400 supervised_user_sync_service_->DeleteSupervisedUser( 401 pending_supervised_user_id_); 402 } else if (avatar_updated_) { 403 // Canceling (or failing) a supervised user import that did set the avatar 404 // should undo this change. 405 supervised_user_sync_service_->ClearSupervisedUserAvatar( 406 pending_supervised_user_id_); 407 } 408 } 409 410 if (run_callback) 411 callback_.Run(error, pending_supervised_user_token_); 412 callback_.Reset(); 413} 414 415} // namespace 416