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 "components/signin/core/browser/account_tracker_service.h" 6 7 #include "base/debug/trace_event.h" 8 #include "base/prefs/pref_service.h" 9 #include "base/prefs/scoped_user_pref_update.h" 10 #include "base/strings/utf_string_conversions.h" 11 #include "components/signin/core/browser/signin_manager.h" 12 #include "components/signin/core/common/signin_pref_names.h" 13 #include "google_apis/gaia/gaia_auth_util.h" 14 #include "google_apis/gaia/gaia_constants.h" 15 #include "google_apis/gaia/gaia_oauth_client.h" 16 #include "google_apis/gaia/oauth2_token_service.h" 17 #include "net/url_request/url_request_context_getter.h" 18 19 namespace { 20 21 const char kAccountKeyPath[] = "account_id"; 22 const char kAccountEmailPath[] = "email"; 23 const char kAccountGaiaPath[] = "gaia"; 24 25 } 26 27 class AccountInfoFetcher : public OAuth2TokenService::Consumer, 28 public gaia::GaiaOAuthClient::Delegate { 29 public: 30 AccountInfoFetcher(OAuth2TokenService* token_service, 31 net::URLRequestContextGetter* request_context_getter, 32 AccountTrackerService* service, 33 const std::string& account_id); 34 virtual ~AccountInfoFetcher(); 35 36 const std::string& account_id() { return account_id_; } 37 38 void Start(); 39 40 // OAuth2TokenService::Consumer implementation. 41 virtual void OnGetTokenSuccess(const OAuth2TokenService::Request* request, 42 const std::string& access_token, 43 const base::Time& expiration_time) OVERRIDE; 44 virtual void OnGetTokenFailure(const OAuth2TokenService::Request* request, 45 const GoogleServiceAuthError& error) OVERRIDE; 46 47 // gaia::GaiaOAuthClient::Delegate implementation. 48 virtual void OnGetUserInfoResponse( 49 scoped_ptr<base::DictionaryValue> user_info) OVERRIDE; 50 virtual void OnOAuthError() OVERRIDE; 51 virtual void OnNetworkError(int response_code) OVERRIDE; 52 53 private: 54 OAuth2TokenService* token_service_; 55 net::URLRequestContextGetter* request_context_getter_; 56 AccountTrackerService* service_; 57 const std::string account_id_; 58 59 scoped_ptr<OAuth2TokenService::Request> login_token_request_; 60 scoped_ptr<gaia::GaiaOAuthClient> gaia_oauth_client_; 61 }; 62 63 AccountInfoFetcher::AccountInfoFetcher( 64 OAuth2TokenService* token_service, 65 net::URLRequestContextGetter* request_context_getter, 66 AccountTrackerService* service, 67 const std::string& account_id) 68 : OAuth2TokenService::Consumer("gaia_account_tracker"), 69 token_service_(token_service), 70 request_context_getter_(request_context_getter), 71 service_(service), 72 account_id_(account_id) { 73 TRACE_EVENT_ASYNC_BEGIN1( 74 "AccountTrackerService", "AccountIdFetcher", this, 75 "account_id", account_id); 76 } 77 78 AccountInfoFetcher::~AccountInfoFetcher() { 79 TRACE_EVENT_ASYNC_END0("AccountTrackerService", "AccountIdFetcher", this); 80 } 81 82 void AccountInfoFetcher::Start() { 83 OAuth2TokenService::ScopeSet scopes; 84 scopes.insert(GaiaConstants::kGoogleUserInfoEmail); 85 scopes.insert(GaiaConstants::kGoogleUserInfoProfile); 86 login_token_request_ = token_service_->StartRequest( 87 account_id_, scopes, this); 88 } 89 90 void AccountInfoFetcher::OnGetTokenSuccess( 91 const OAuth2TokenService::Request* request, 92 const std::string& access_token, 93 const base::Time& expiration_time) { 94 TRACE_EVENT_ASYNC_STEP_PAST0( 95 "AccountTrackerService", "AccountIdFetcher", this, "OnGetTokenSuccess"); 96 DCHECK_EQ(request, login_token_request_.get()); 97 98 gaia_oauth_client_.reset(new gaia::GaiaOAuthClient(request_context_getter_)); 99 100 const int kMaxRetries = 3; 101 gaia_oauth_client_->GetUserInfo(access_token, kMaxRetries, this); 102 } 103 104 void AccountInfoFetcher::OnGetTokenFailure( 105 const OAuth2TokenService::Request* request, 106 const GoogleServiceAuthError& error) { 107 TRACE_EVENT_ASYNC_STEP_PAST1("AccountTrackerService", 108 "AccountIdFetcher", 109 this, 110 "OnGetTokenFailure", 111 "google_service_auth_error", 112 error.ToString()); 113 LOG(ERROR) << "OnGetTokenFailure: " << error.ToString(); 114 DCHECK_EQ(request, login_token_request_.get()); 115 service_->OnUserInfoFetchFailure(this); 116 } 117 118 void AccountInfoFetcher::OnGetUserInfoResponse( 119 scoped_ptr<base::DictionaryValue> user_info) { 120 TRACE_EVENT_ASYNC_STEP_PAST1("AccountTrackerService", 121 "AccountIdFetcher", 122 this, 123 "OnGetUserInfoResponse", 124 "account_id", 125 account_id_); 126 service_->OnUserInfoFetchSuccess(this, user_info.get()); 127 } 128 129 void AccountInfoFetcher::OnOAuthError() { 130 TRACE_EVENT_ASYNC_STEP_PAST0( 131 "AccountTrackerService", "AccountIdFetcher", this, "OnOAuthError"); 132 LOG(ERROR) << "OnOAuthError"; 133 service_->OnUserInfoFetchFailure(this); 134 } 135 136 void AccountInfoFetcher::OnNetworkError(int response_code) { 137 TRACE_EVENT_ASYNC_STEP_PAST1("AccountTrackerService", 138 "AccountIdFetcher", 139 this, 140 "OnNetworkError", 141 "response_code", 142 response_code); 143 LOG(ERROR) << "OnNetworkError " << response_code; 144 service_->OnUserInfoFetchFailure(this); 145 } 146 147 148 const char AccountTrackerService::kAccountInfoPref[] = "account_info"; 149 150 AccountTrackerService::AccountTrackerService() 151 : token_service_(NULL), 152 pref_service_(NULL), 153 shutdown_called_(false) { 154 } 155 156 AccountTrackerService::~AccountTrackerService() { 157 DCHECK(shutdown_called_); 158 } 159 160 void AccountTrackerService::Initialize( 161 OAuth2TokenService* token_service, 162 PrefService* pref_service, 163 net::URLRequestContextGetter* request_context_getter) { 164 DCHECK(token_service); 165 DCHECK(!token_service_); 166 DCHECK(pref_service); 167 DCHECK(!pref_service_); 168 token_service_ = token_service; 169 pref_service_ = pref_service; 170 request_context_getter_ = request_context_getter; 171 token_service_->AddObserver(this); 172 LoadFromPrefs(); 173 LoadFromTokenService(); 174 } 175 176 void AccountTrackerService::Shutdown() { 177 shutdown_called_ = true; 178 STLDeleteValues(&user_info_requests_); 179 token_service_->RemoveObserver(this); 180 } 181 182 void AccountTrackerService::AddObserver(Observer* observer) { 183 observer_list_.AddObserver(observer); 184 } 185 186 void AccountTrackerService::RemoveObserver(Observer* observer) { 187 observer_list_.RemoveObserver(observer); 188 } 189 190 bool AccountTrackerService::IsAllUserInfoFetched() const { 191 return user_info_requests_.empty(); 192 } 193 194 std::vector<AccountTrackerService::AccountInfo> 195 AccountTrackerService::GetAccounts() const { 196 std::vector<AccountInfo> accounts; 197 198 for (std::map<std::string, AccountState>::const_iterator it = 199 accounts_.begin(); 200 it != accounts_.end(); 201 ++it) { 202 const AccountState& state = it->second; 203 accounts.push_back(state.info); 204 } 205 return accounts; 206 } 207 208 AccountTrackerService::AccountInfo AccountTrackerService::GetAccountInfo( 209 const std::string& account_id) { 210 if (ContainsKey(accounts_, account_id)) 211 return accounts_[account_id].info; 212 213 return AccountInfo(); 214 } 215 216 AccountTrackerService::AccountInfo 217 AccountTrackerService::FindAccountInfoByGaiaId( 218 const std::string& gaia_id) { 219 for (std::map<std::string, AccountState>::const_iterator it = 220 accounts_.begin(); 221 it != accounts_.end(); 222 ++it) { 223 const AccountState& state = it->second; 224 if (state.info.gaia == gaia_id) 225 return state.info; 226 } 227 228 return AccountInfo(); 229 } 230 231 AccountTrackerService::AccountInfo 232 AccountTrackerService::FindAccountInfoByEmail( 233 const std::string& email) { 234 for (std::map<std::string, AccountState>::const_iterator it = 235 accounts_.begin(); 236 it != accounts_.end(); 237 ++it) { 238 const AccountState& state = it->second; 239 if (gaia::AreEmailsSame(state.info.email, email)) 240 return state.info; 241 } 242 243 return AccountInfo(); 244 } 245 246 AccountTrackerService::AccountIdMigrationState 247 AccountTrackerService::GetMigrationState() { 248 return GetMigrationState(pref_service_); 249 } 250 251 // static 252 AccountTrackerService::AccountIdMigrationState 253 AccountTrackerService::GetMigrationState(PrefService* pref_service) { 254 return static_cast<AccountTrackerService::AccountIdMigrationState>( 255 pref_service->GetInteger(prefs::kAccountIdMigrationState)); 256 } 257 258 void AccountTrackerService::OnRefreshTokenAvailable( 259 const std::string& account_id) { 260 TRACE_EVENT1("AccountTrackerService", 261 "AccountTracker::OnRefreshTokenAvailable", 262 "account_id", 263 account_id); 264 DVLOG(1) << "AVAILABLE " << account_id; 265 266 StartTrackingAccount(account_id); 267 AccountState& state = accounts_[account_id]; 268 269 if (state.info.gaia.empty()) 270 StartFetchingUserInfo(account_id); 271 } 272 273 void AccountTrackerService::OnRefreshTokenRevoked( 274 const std::string& account_id) { 275 TRACE_EVENT1("AccountTrackerService", 276 "AccountTracker::OnRefreshTokenRevoked", 277 "account_id", 278 account_id); 279 280 DVLOG(1) << "REVOKED " << account_id; 281 StopTrackingAccount(account_id); 282 } 283 284 void AccountTrackerService::NotifyAccountUpdated(const AccountState& state) { 285 DCHECK(!state.info.gaia.empty()); 286 FOR_EACH_OBSERVER( 287 Observer, observer_list_, OnAccountUpdated(state.info)); 288 } 289 290 void AccountTrackerService::NotifyAccountRemoved(const AccountState& state) { 291 DCHECK(!state.info.gaia.empty()); 292 FOR_EACH_OBSERVER( 293 Observer, observer_list_, OnAccountRemoved(state.info)); 294 } 295 296 void AccountTrackerService::StartTrackingAccount( 297 const std::string& account_id) { 298 if (!ContainsKey(accounts_, account_id)) { 299 DVLOG(1) << "StartTracking " << account_id; 300 AccountState state; 301 state.info.account_id = account_id; 302 accounts_.insert(make_pair(account_id, state)); 303 } 304 } 305 306 void AccountTrackerService::StopTrackingAccount(const std::string& account_id) { 307 DVLOG(1) << "StopTracking " << account_id; 308 if (ContainsKey(accounts_, account_id)) { 309 AccountState& state = accounts_[account_id]; 310 RemoveFromPrefs(state); 311 if (!state.info.gaia.empty()) 312 NotifyAccountRemoved(state); 313 314 accounts_.erase(account_id); 315 } 316 317 if (ContainsKey(user_info_requests_, account_id)) 318 DeleteFetcher(user_info_requests_[account_id]); 319 } 320 321 void AccountTrackerService::StartFetchingUserInfo( 322 const std::string& account_id) { 323 if (ContainsKey(user_info_requests_, account_id)) 324 DeleteFetcher(user_info_requests_[account_id]); 325 326 DVLOG(1) << "StartFetching " << account_id; 327 AccountInfoFetcher* fetcher = 328 new AccountInfoFetcher(token_service_, 329 request_context_getter_.get(), 330 this, 331 account_id); 332 user_info_requests_[account_id] = fetcher; 333 fetcher->Start(); 334 } 335 336 void AccountTrackerService::OnUserInfoFetchSuccess( 337 AccountInfoFetcher* fetcher, 338 const base::DictionaryValue* user_info) { 339 const std::string& account_id = fetcher->account_id(); 340 DCHECK(ContainsKey(accounts_, account_id)); 341 AccountState& state = accounts_[account_id]; 342 343 std::string gaia_id; 344 std::string email; 345 if (user_info->GetString("id", &gaia_id) && 346 user_info->GetString("email", &email)) { 347 state.info.gaia = gaia_id; 348 state.info.email = email; 349 350 NotifyAccountUpdated(state); 351 SaveToPrefs(state); 352 } 353 DeleteFetcher(fetcher); 354 } 355 356 void AccountTrackerService::OnUserInfoFetchFailure( 357 AccountInfoFetcher* fetcher) { 358 LOG(WARNING) << "Failed to get UserInfo for " << fetcher->account_id(); 359 DeleteFetcher(fetcher); 360 // TODO(rogerta): figure out when to retry. 361 } 362 363 void AccountTrackerService::DeleteFetcher(AccountInfoFetcher* fetcher) { 364 DVLOG(1) << "DeleteFetcher " << fetcher->account_id(); 365 const std::string& account_id = fetcher->account_id(); 366 DCHECK(ContainsKey(user_info_requests_, account_id)); 367 DCHECK_EQ(fetcher, user_info_requests_[account_id]); 368 user_info_requests_.erase(account_id); 369 delete fetcher; 370 } 371 372 void AccountTrackerService::LoadFromPrefs() { 373 const base::ListValue* list = pref_service_->GetList(kAccountInfoPref); 374 for (size_t i = 0; i < list->GetSize(); ++i) { 375 const base::DictionaryValue* dict; 376 if (list->GetDictionary(i, &dict)) { 377 base::string16 value; 378 if (dict->GetString(kAccountKeyPath, &value)) { 379 std::string account_id = base::UTF16ToUTF8(value); 380 StartTrackingAccount(account_id); 381 AccountState& state = accounts_[account_id]; 382 383 if (dict->GetString(kAccountGaiaPath, &value)) 384 state.info.gaia = base::UTF16ToUTF8(value); 385 if (dict->GetString(kAccountEmailPath, &value)) 386 state.info.email = base::UTF16ToUTF8(value); 387 388 if (!state.info.gaia.empty()) 389 NotifyAccountUpdated(state); 390 } 391 } 392 } 393 } 394 395 void AccountTrackerService::SaveToPrefs(const AccountState& state) { 396 if (!pref_service_) 397 return; 398 399 base::DictionaryValue* dict = NULL; 400 base::string16 account_id_16 = base::UTF8ToUTF16(state.info.account_id); 401 ListPrefUpdate update(pref_service_, kAccountInfoPref); 402 for(size_t i = 0; i < update->GetSize(); ++i, dict = NULL) { 403 if (update->GetDictionary(i, &dict)) { 404 base::string16 value; 405 if (dict->GetString(kAccountKeyPath, &value) && value == account_id_16) 406 break; 407 } 408 } 409 410 if (!dict) { 411 dict = new base::DictionaryValue(); 412 update->Append(dict); // |update| takes ownership. 413 dict->SetString(kAccountKeyPath, account_id_16); 414 } 415 416 dict->SetString(kAccountEmailPath, state.info.email); 417 dict->SetString(kAccountGaiaPath, state.info.gaia); 418 } 419 420 void AccountTrackerService::RemoveFromPrefs(const AccountState& state) { 421 if (!pref_service_) 422 return; 423 424 base::string16 account_id_16 = base::UTF8ToUTF16(state.info.account_id); 425 ListPrefUpdate update(pref_service_, kAccountInfoPref); 426 for(size_t i = 0; i < update->GetSize(); ++i) { 427 base::DictionaryValue* dict = NULL; 428 if (update->GetDictionary(i, &dict)) { 429 base::string16 value; 430 if (dict->GetString(kAccountKeyPath, &value) && value == account_id_16) { 431 update->Remove(i, NULL); 432 break; 433 } 434 } 435 } 436 } 437 438 void AccountTrackerService::LoadFromTokenService() { 439 std::vector<std::string> accounts = token_service_->GetAccounts(); 440 for (std::vector<std::string>::const_iterator it = accounts.begin(); 441 it != accounts.end(); ++it) { 442 OnRefreshTokenAvailable(*it); 443 } 444 } 445