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.
5 #include "chrome/browser/extensions/api/identity/account_tracker.h"
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/profiles/profile.h"
12 #include "chrome/browser/signin/profile_oauth2_token_service_factory.h"
13 #include "chrome/browser/signin/signin_manager_factory.h"
14 #include "components/signin/core/browser/profile_oauth2_token_service.h"
15 #include "components/signin/core/browser/signin_manager.h"
16 #include "content/public/browser/notification_details.h"
17 #include "extensions/browser/extension_system.h"
19 namespace extensions {
21 AccountTracker::AccountTracker(Profile* profile) : profile_(profile) {
22 ProfileOAuth2TokenService* service =
23 ProfileOAuth2TokenServiceFactory::GetForProfile(profile_);
24 service->AddObserver(this);
25 service->signin_error_controller()->AddProvider(this);
26 SigninManagerFactory::GetForProfile(profile_)->AddObserver(this);
29 AccountTracker::~AccountTracker() {}
31 void AccountTracker::ReportAuthError(const std::string& account_id,
32 const GoogleServiceAuthError& error) {
33 account_errors_.insert(make_pair(account_id, error));
34 ProfileOAuth2TokenServiceFactory::GetForProfile(profile_)->
35 signin_error_controller()->AuthStatusChanged();
36 UpdateSignInState(account_id, false);
39 void AccountTracker::Shutdown() {
40 STLDeleteValues(&user_info_requests_);
41 SigninManagerFactory::GetForProfile(profile_)->RemoveObserver(this);
42 ProfileOAuth2TokenService* service =
43 ProfileOAuth2TokenServiceFactory::GetForProfile(profile_);
44 service->signin_error_controller()->RemoveProvider(this);
45 service->RemoveObserver(this);
48 void AccountTracker::AddObserver(Observer* observer) {
49 observer_list_.AddObserver(observer);
52 void AccountTracker::RemoveObserver(Observer* observer) {
53 observer_list_.RemoveObserver(observer);
56 void AccountTracker::OnRefreshTokenAvailable(const std::string& account_id) {
57 // Ignore refresh tokens if there is no primary account ID at all.
58 if (signin_manager_account_id().empty())
61 DVLOG(1) << "AVAILABLE " << account_id;
62 ClearAuthError(account_id);
63 UpdateSignInState(account_id, true);
66 void AccountTracker::OnRefreshTokenRevoked(const std::string& account_id) {
67 DVLOG(1) << "REVOKED " << account_id;
68 UpdateSignInState(account_id, false);
71 void AccountTracker::GoogleSigninSucceeded(const std::string& username,
72 const std::string& password) {
73 std::vector<std::string> accounts =
74 ProfileOAuth2TokenServiceFactory::GetForProfile(profile_)->GetAccounts();
76 for (std::vector<std::string>::const_iterator it = accounts.begin();
79 OnRefreshTokenAvailable(*it);
83 void AccountTracker::GoogleSignedOut(const std::string& username) {
84 if (username == signin_manager_account_id() ||
85 signin_manager_account_id().empty()) {
86 StopTrackingAllAccounts();
88 StopTrackingAccount(username);
92 const std::string AccountTracker::signin_manager_account_id() {
93 return SigninManagerFactory::GetForProfile(profile_)
94 ->GetAuthenticatedAccountId();
97 void AccountTracker::NotifyAccountAdded(const AccountState& account) {
98 DCHECK(!account.ids.gaia.empty());
100 Observer, observer_list_, OnAccountAdded(account.ids));
103 void AccountTracker::NotifyAccountRemoved(const AccountState& account) {
104 DCHECK(!account.ids.gaia.empty());
106 Observer, observer_list_, OnAccountRemoved(account.ids));
109 void AccountTracker::NotifySignInChanged(const AccountState& account) {
110 DCHECK(!account.ids.gaia.empty());
111 FOR_EACH_OBSERVER(Observer,
113 OnAccountSignInChanged(account.ids, account.is_signed_in));
116 void AccountTracker::ClearAuthError(const std::string& account_key) {
117 account_errors_.erase(account_key);
118 ProfileOAuth2TokenServiceFactory::GetForProfile(profile_)->
119 signin_error_controller()->AuthStatusChanged();
122 void AccountTracker::UpdateSignInState(const std::string& account_key,
124 StartTrackingAccount(account_key);
125 AccountState& account = accounts_[account_key];
126 bool needs_gaia_id = account.ids.gaia.empty();
127 bool was_signed_in = account.is_signed_in;
128 account.is_signed_in = is_signed_in;
130 if (needs_gaia_id && is_signed_in)
131 StartFetchingUserInfo(account_key);
133 if (!needs_gaia_id && (was_signed_in != is_signed_in))
134 NotifySignInChanged(account);
137 void AccountTracker::StartTrackingAccount(const std::string& account_key) {
138 if (!ContainsKey(accounts_, account_key)) {
139 DVLOG(1) << "StartTracking " << account_key;
140 AccountState account_state;
141 account_state.ids.account_key = account_key;
142 account_state.ids.email = account_key;
143 account_state.is_signed_in = false;
144 accounts_.insert(make_pair(account_key, account_state));
148 void AccountTracker::StopTrackingAccount(const std::string& account_key) {
149 if (ContainsKey(accounts_, account_key)) {
150 AccountState& account = accounts_[account_key];
151 if (!account.ids.gaia.empty()) {
152 UpdateSignInState(account_key, false);
153 NotifyAccountRemoved(account);
155 accounts_.erase(account_key);
158 ClearAuthError(account_key);
160 if (ContainsKey(user_info_requests_, account_key))
161 DeleteFetcher(user_info_requests_[account_key]);
164 void AccountTracker::StopTrackingAllAccounts() {
165 while (!accounts_.empty())
166 StopTrackingAccount(accounts_.begin()->first);
169 void AccountTracker::StartFetchingUserInfo(const std::string& account_key) {
170 if (ContainsKey(user_info_requests_, account_key))
171 DeleteFetcher(user_info_requests_[account_key]);
173 DVLOG(1) << "StartFetching " << account_key;
174 AccountIdFetcher* fetcher =
175 new AccountIdFetcher(profile_, this, account_key);
176 user_info_requests_[account_key] = fetcher;
180 void AccountTracker::OnUserInfoFetchSuccess(AccountIdFetcher* fetcher,
181 const std::string& gaia_id) {
182 const std::string& account_key = fetcher->account_key();
183 DCHECK(ContainsKey(accounts_, account_key));
184 AccountState& account = accounts_[account_key];
186 account.ids.gaia = gaia_id;
187 NotifyAccountAdded(account);
189 if (account.is_signed_in)
190 NotifySignInChanged(account);
192 DeleteFetcher(fetcher);
195 void AccountTracker::OnUserInfoFetchFailure(AccountIdFetcher* fetcher) {
196 LOG(WARNING) << "Failed to get UserInfo for " << fetcher->account_key();
197 std::string key = fetcher->account_key();
198 DeleteFetcher(fetcher);
199 StopTrackingAccount(key);
202 std::string AccountTracker::GetAccountId() const {
203 if (account_errors_.size() == 0)
204 return std::string();
206 return account_errors_.begin()->first;
209 GoogleServiceAuthError AccountTracker::GetAuthStatus() const {
210 if (account_errors_.size() == 0)
211 return GoogleServiceAuthError::AuthErrorNone();
213 return account_errors_.begin()->second;
216 void AccountTracker::DeleteFetcher(AccountIdFetcher* fetcher) {
217 const std::string& account_key = fetcher->account_key();
218 DCHECK(ContainsKey(user_info_requests_, account_key));
219 DCHECK_EQ(fetcher, user_info_requests_[account_key]);
220 user_info_requests_.erase(account_key);
224 AccountIdFetcher::AccountIdFetcher(Profile* profile,
225 AccountTracker* tracker,
226 const std::string& account_key)
227 : OAuth2TokenService::Consumer("extensions_account_tracker"),
230 account_key_(account_key) {}
232 AccountIdFetcher::~AccountIdFetcher() {}
234 void AccountIdFetcher::Start() {
235 ProfileOAuth2TokenService* service =
236 ProfileOAuth2TokenServiceFactory::GetForProfile(profile_);
237 login_token_request_ = service->StartRequest(
238 account_key_, OAuth2TokenService::ScopeSet(), this);
241 void AccountIdFetcher::OnGetTokenSuccess(
242 const OAuth2TokenService::Request* request,
243 const std::string& access_token,
244 const base::Time& expiration_time) {
245 DCHECK_EQ(request, login_token_request_.get());
247 gaia_oauth_client_.reset(new gaia::GaiaOAuthClient(
248 g_browser_process->system_request_context()));
250 const int kMaxGetUserIdRetries = 3;
251 gaia_oauth_client_->GetUserId(access_token, kMaxGetUserIdRetries, this);
254 void AccountIdFetcher::OnGetTokenFailure(
255 const OAuth2TokenService::Request* request,
256 const GoogleServiceAuthError& error) {
257 LOG(ERROR) << "OnGetTokenFailure: " << error.ToString();
258 DCHECK_EQ(request, login_token_request_.get());
259 tracker_->OnUserInfoFetchFailure(this);
262 void AccountIdFetcher::OnGetUserIdResponse(const std::string& gaia_id) {
263 tracker_->OnUserInfoFetchSuccess(this, gaia_id);
266 void AccountIdFetcher::OnOAuthError() {
267 LOG(ERROR) << "OnOAuthError";
268 tracker_->OnUserInfoFetchFailure(this);
271 void AccountIdFetcher::OnNetworkError(int response_code) {
272 LOG(ERROR) << "OnNetworkError " << response_code;
273 tracker_->OnUserInfoFetchFailure(this);
276 } // namespace extensions