Home | History | Annotate | Download | only in browser
      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