Upstream version 10.39.225.0
[platform/framework/web/crosswalk.git] / src / components / signin / core / browser / account_tracker_service.cc
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 }