Home | History | Annotate | Download | only in identity
      1 // Copyright 2013 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/extensions/api/identity/account_tracker.h"
      6 
      7 #include "base/logging.h"
      8 #include "base/stl_util.h"
      9 #include "chrome/browser/browser_process.h"
     10 #include "chrome/browser/chrome_notification_types.h"
     11 #include "chrome/browser/extensions/extension_system.h"
     12 #include "chrome/browser/profiles/profile.h"
     13 #include "chrome/browser/signin/profile_oauth2_token_service.h"
     14 #include "chrome/browser/signin/profile_oauth2_token_service_factory.h"
     15 #include "chrome/browser/signin/signin_manager_base.h"
     16 #include "content/public/browser/notification_details.h"
     17 
     18 namespace extensions {
     19 
     20 AccountTracker::AccountTracker(Profile* profile) : profile_(profile) {
     21   registrar_.Add(this,
     22                  chrome::NOTIFICATION_GOOGLE_SIGNED_OUT,
     23                  content::Source<Profile>(profile_));
     24 
     25   ProfileOAuth2TokenServiceFactory::GetForProfile(profile_)->AddObserver(this);
     26   SigninGlobalError::GetForProfile(profile_)->AddProvider(this);
     27 }
     28 
     29 AccountTracker::~AccountTracker() {}
     30 
     31 void AccountTracker::ReportAuthError(const std::string& account_id,
     32                                      const GoogleServiceAuthError& error) {
     33   account_errors_.insert(make_pair(account_id, error));
     34   SigninGlobalError::GetForProfile(profile_)->AuthStatusChanged();
     35   UpdateSignInState(account_id, false);
     36 }
     37 
     38 void AccountTracker::Shutdown() {
     39   STLDeleteValues(&user_info_requests_);
     40   SigninGlobalError::GetForProfile(profile_)->RemoveProvider(this);
     41   ProfileOAuth2TokenServiceFactory::GetForProfile(profile_)->
     42       RemoveObserver(this);
     43 }
     44 
     45 void AccountTracker::AddObserver(Observer* observer) {
     46   observer_list_.AddObserver(observer);
     47 }
     48 
     49 void AccountTracker::RemoveObserver(Observer* observer) {
     50   observer_list_.RemoveObserver(observer);
     51 }
     52 
     53 void AccountTracker::OnRefreshTokenAvailable(const std::string& account_id) {
     54   // Ignore refresh tokens if there is no primary account ID at all.
     55   ProfileOAuth2TokenService* token_service =
     56       ProfileOAuth2TokenServiceFactory::GetForProfile(profile_);
     57   if (token_service->GetPrimaryAccountId().empty())
     58     return;
     59 
     60   DVLOG(1) << "AVAILABLE " << account_id;
     61   ClearAuthError(account_id);
     62   UpdateSignInState(account_id, true);
     63 }
     64 
     65 void AccountTracker::OnRefreshTokenRevoked(const std::string& account_id) {
     66   DVLOG(1) << "REVOKED " << account_id;
     67   UpdateSignInState(account_id, false);
     68 }
     69 
     70 void AccountTracker::Observe(int type,
     71                              const content::NotificationSource& source,
     72                              const content::NotificationDetails& details) {
     73   switch (type) {
     74     case chrome::NOTIFICATION_GOOGLE_SIGNED_OUT:
     75       StopTrackingAccount(content::Details<GoogleServiceSignoutDetails>(
     76           details)->username);
     77       break;
     78     default:
     79       NOTREACHED();
     80   }
     81 }
     82 
     83 void AccountTracker::NotifyAccountAdded(const AccountState& account) {
     84   DCHECK(!account.ids.gaia.empty());
     85   FOR_EACH_OBSERVER(
     86       Observer, observer_list_, OnAccountAdded(account.ids));
     87 }
     88 
     89 void AccountTracker::NotifyAccountRemoved(const AccountState& account) {
     90   DCHECK(!account.ids.gaia.empty());
     91   FOR_EACH_OBSERVER(
     92       Observer, observer_list_, OnAccountRemoved(account.ids));
     93 }
     94 
     95 void AccountTracker::NotifySignInChanged(const AccountState& account) {
     96   DCHECK(!account.ids.gaia.empty());
     97   FOR_EACH_OBSERVER(Observer,
     98                     observer_list_,
     99                     OnAccountSignInChanged(account.ids, account.is_signed_in));
    100 }
    101 
    102 void AccountTracker::ClearAuthError(const std::string& account_key) {
    103   account_errors_.erase(account_key);
    104   SigninGlobalError::GetForProfile(profile_)->AuthStatusChanged();
    105 }
    106 
    107 void AccountTracker::UpdateSignInState(const std::string& account_key,
    108                                        bool is_signed_in) {
    109   StartTrackingAccount(account_key);
    110   AccountState& account = accounts_[account_key];
    111   bool needs_gaia_id = account.ids.gaia.empty();
    112   bool was_signed_in = account.is_signed_in;
    113   account.is_signed_in = is_signed_in;
    114 
    115   if (needs_gaia_id && is_signed_in)
    116     StartFetchingUserInfo(account_key);
    117 
    118   if (!needs_gaia_id && (was_signed_in != is_signed_in))
    119     NotifySignInChanged(account);
    120 }
    121 
    122 void AccountTracker::StartTrackingAccount(const std::string& account_key) {
    123   if (!ContainsKey(accounts_, account_key)) {
    124     DVLOG(1) << "StartTracking " << account_key;
    125     AccountState account_state;
    126     account_state.ids.account_key = account_key;
    127     account_state.ids.email = account_key;
    128     account_state.is_signed_in = false;
    129     accounts_.insert(make_pair(account_key, account_state));
    130   }
    131 }
    132 
    133 void AccountTracker::StopTrackingAccount(const std::string& account_key) {
    134   if (ContainsKey(accounts_, account_key)) {
    135     AccountState& account = accounts_[account_key];
    136     if (!account.ids.gaia.empty()) {
    137       UpdateSignInState(account_key, false);
    138       NotifyAccountRemoved(account);
    139     }
    140     accounts_.erase(account_key);
    141   }
    142 
    143   ClearAuthError(account_key);
    144 
    145   if (ContainsKey(user_info_requests_, account_key))
    146     DeleteFetcher(user_info_requests_[account_key]);
    147 }
    148 
    149 void AccountTracker::StartFetchingUserInfo(const std::string& account_key) {
    150   if (ContainsKey(user_info_requests_, account_key))
    151     DeleteFetcher(user_info_requests_[account_key]);
    152 
    153   DVLOG(1) << "StartFetching " << account_key;
    154   AccountIdFetcher* fetcher =
    155       new AccountIdFetcher(profile_, this, account_key);
    156   user_info_requests_[account_key] = fetcher;
    157   fetcher->Start();
    158 }
    159 
    160 void AccountTracker::OnUserInfoFetchSuccess(AccountIdFetcher* fetcher,
    161                                             const std::string& gaia_id) {
    162   const std::string& account_key = fetcher->account_key();
    163   DCHECK(ContainsKey(accounts_, account_key));
    164   AccountState& account = accounts_[account_key];
    165 
    166   account.ids.gaia = gaia_id;
    167   NotifyAccountAdded(account);
    168 
    169   if (account.is_signed_in)
    170     NotifySignInChanged(account);
    171 
    172   DeleteFetcher(fetcher);
    173 }
    174 
    175 void AccountTracker::OnUserInfoFetchFailure(AccountIdFetcher* fetcher) {
    176   LOG(WARNING) << "Failed to get UserInfo for " << fetcher->account_key();
    177   std::string key = fetcher->account_key();
    178   DeleteFetcher(fetcher);
    179   StopTrackingAccount(key);
    180 }
    181 
    182 std::string AccountTracker::GetAccountId() const {
    183   if (account_errors_.size() == 0)
    184     return std::string();
    185   else
    186     return account_errors_.begin()->first;
    187 }
    188 
    189 GoogleServiceAuthError AccountTracker::GetAuthStatus() const {
    190   if (account_errors_.size() == 0)
    191     return GoogleServiceAuthError::AuthErrorNone();
    192   else
    193     return account_errors_.begin()->second;
    194 }
    195 
    196 void AccountTracker::DeleteFetcher(AccountIdFetcher* fetcher) {
    197   const std::string& account_key = fetcher->account_key();
    198   DCHECK(ContainsKey(user_info_requests_, account_key));
    199   DCHECK_EQ(fetcher, user_info_requests_[account_key]);
    200   user_info_requests_.erase(account_key);
    201   delete fetcher;
    202 }
    203 
    204 AccountIdFetcher::AccountIdFetcher(Profile* profile,
    205                                    AccountTracker* tracker,
    206                                    const std::string& account_key)
    207     : profile_(profile),
    208       tracker_(tracker),
    209       account_key_(account_key) {}
    210 
    211 AccountIdFetcher::~AccountIdFetcher() {}
    212 
    213 void AccountIdFetcher::Start() {
    214   ProfileOAuth2TokenService* service =
    215       ProfileOAuth2TokenServiceFactory::GetForProfile(profile_);
    216   login_token_request_ = service->StartRequest(
    217       account_key_, OAuth2TokenService::ScopeSet(), this);
    218 }
    219 
    220 void AccountIdFetcher::OnGetTokenSuccess(
    221     const OAuth2TokenService::Request* request,
    222     const std::string& access_token,
    223     const base::Time& expiration_time) {
    224   DCHECK_EQ(request, login_token_request_.get());
    225 
    226   gaia_oauth_client_.reset(new gaia::GaiaOAuthClient(
    227       g_browser_process->system_request_context()));
    228 
    229   const int kMaxGetUserIdRetries = 3;
    230   gaia_oauth_client_->GetUserId(access_token, kMaxGetUserIdRetries, this);
    231 }
    232 
    233 void AccountIdFetcher::OnGetTokenFailure(
    234     const OAuth2TokenService::Request* request,
    235     const GoogleServiceAuthError& error) {
    236   LOG(ERROR) << "OnGetTokenFailure: " << error.error_message();
    237   DCHECK_EQ(request, login_token_request_.get());
    238   tracker_->OnUserInfoFetchFailure(this);
    239 }
    240 
    241 void AccountIdFetcher::OnGetUserIdResponse(const std::string& gaia_id) {
    242   tracker_->OnUserInfoFetchSuccess(this, gaia_id);
    243 }
    244 
    245 void AccountIdFetcher::OnOAuthError() {
    246   LOG(ERROR) << "OnOAuthError";
    247   tracker_->OnUserInfoFetchFailure(this);
    248 }
    249 
    250 void AccountIdFetcher::OnNetworkError(int response_code) {
    251   LOG(ERROR) << "OnNetworkError " << response_code;
    252   tracker_->OnUserInfoFetchFailure(this);
    253 }
    254 
    255 }  // namespace extensions
    256