• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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 
AccountTracker(Profile * profile)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 
~AccountTracker()29 AccountTracker::~AccountTracker() {}
30 
ReportAuthError(const std::string & account_id,const GoogleServiceAuthError & error)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 
Shutdown()38 void AccountTracker::Shutdown() {
39   STLDeleteValues(&user_info_requests_);
40   SigninGlobalError::GetForProfile(profile_)->RemoveProvider(this);
41   ProfileOAuth2TokenServiceFactory::GetForProfile(profile_)->
42       RemoveObserver(this);
43 }
44 
AddObserver(Observer * observer)45 void AccountTracker::AddObserver(Observer* observer) {
46   observer_list_.AddObserver(observer);
47 }
48 
RemoveObserver(Observer * observer)49 void AccountTracker::RemoveObserver(Observer* observer) {
50   observer_list_.RemoveObserver(observer);
51 }
52 
OnRefreshTokenAvailable(const std::string & account_id)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 
OnRefreshTokenRevoked(const std::string & account_id)65 void AccountTracker::OnRefreshTokenRevoked(const std::string& account_id) {
66   DVLOG(1) << "REVOKED " << account_id;
67   UpdateSignInState(account_id, false);
68 }
69 
Observe(int type,const content::NotificationSource & source,const content::NotificationDetails & details)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 
NotifyAccountAdded(const AccountState & account)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 
NotifyAccountRemoved(const AccountState & account)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 
NotifySignInChanged(const AccountState & account)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 
ClearAuthError(const std::string & account_key)102 void AccountTracker::ClearAuthError(const std::string& account_key) {
103   account_errors_.erase(account_key);
104   SigninGlobalError::GetForProfile(profile_)->AuthStatusChanged();
105 }
106 
UpdateSignInState(const std::string & account_key,bool is_signed_in)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 
StartTrackingAccount(const std::string & account_key)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 
StopTrackingAccount(const std::string & account_key)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 
StartFetchingUserInfo(const std::string & account_key)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 
OnUserInfoFetchSuccess(AccountIdFetcher * fetcher,const std::string & gaia_id)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 
OnUserInfoFetchFailure(AccountIdFetcher * fetcher)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 
GetAccountId() const182 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 
GetAuthStatus() const189 GoogleServiceAuthError AccountTracker::GetAuthStatus() const {
190   if (account_errors_.size() == 0)
191     return GoogleServiceAuthError::AuthErrorNone();
192   else
193     return account_errors_.begin()->second;
194 }
195 
DeleteFetcher(AccountIdFetcher * fetcher)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 
AccountIdFetcher(Profile * profile,AccountTracker * tracker,const std::string & account_key)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 
~AccountIdFetcher()211 AccountIdFetcher::~AccountIdFetcher() {}
212 
Start()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 
OnGetTokenSuccess(const OAuth2TokenService::Request * request,const std::string & access_token,const base::Time & expiration_time)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 
OnGetTokenFailure(const OAuth2TokenService::Request * request,const GoogleServiceAuthError & error)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 
OnGetUserIdResponse(const std::string & gaia_id)241 void AccountIdFetcher::OnGetUserIdResponse(const std::string& gaia_id) {
242   tracker_->OnUserInfoFetchSuccess(this, gaia_id);
243 }
244 
OnOAuthError()245 void AccountIdFetcher::OnOAuthError() {
246   LOG(ERROR) << "OnOAuthError";
247   tracker_->OnUserInfoFetchFailure(this);
248 }
249 
OnNetworkError(int response_code)250 void AccountIdFetcher::OnNetworkError(int response_code) {
251   LOG(ERROR) << "OnNetworkError " << response_code;
252   tracker_->OnUserInfoFetchFailure(this);
253 }
254 
255 }  // namespace extensions
256