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