Update To 11.40.268.0
[platform/framework/web/crosswalk.git] / src / chrome / browser / chromeos / login / signin / oauth2_login_manager.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 "chrome/browser/chromeos/login/signin/oauth2_login_manager.h"
6
7 #include <utility>
8 #include <vector>
9
10 #include "base/command_line.h"
11 #include "base/metrics/histogram.h"
12 #include "base/prefs/pref_service.h"
13 #include "base/strings/string_util.h"
14 #include "chrome/browser/browser_process.h"
15 #include "chrome/browser/profiles/profile.h"
16 #include "chrome/browser/signin/account_tracker_service_factory.h"
17 #include "chrome/browser/signin/chrome_signin_client_factory.h"
18 #include "chrome/browser/signin/profile_oauth2_token_service_factory.h"
19 #include "chrome/browser/signin/signin_manager_factory.h"
20 #include "chrome/common/chrome_switches.h"
21 #include "chromeos/chromeos_switches.h"
22 #include "components/signin/core/browser/account_tracker_service.h"
23 #include "components/signin/core/browser/profile_oauth2_token_service.h"
24 #include "components/signin/core/browser/signin_client.h"
25 #include "components/signin/core/browser/signin_manager.h"
26 #include "components/user_manager/user_manager.h"
27 #include "google_apis/gaia/gaia_auth_util.h"
28 #include "google_apis/gaia/gaia_constants.h"
29 #include "google_apis/gaia/gaia_urls.h"
30 #include "net/url_request/url_request_context_getter.h"
31
32 namespace chromeos {
33
34 namespace {
35
36 static const char kServiceScopeGetUserInfo[] =
37     "https://www.googleapis.com/auth/userinfo.email";
38 static const int kMaxRetries = 5;
39
40 }  // namespace
41
42 OAuth2LoginManager::OAuth2LoginManager(Profile* user_profile)
43     : user_profile_(user_profile),
44       restore_strategy_(RESTORE_FROM_COOKIE_JAR),
45       state_(SESSION_RESTORE_NOT_STARTED) {
46   GetTokenService()->AddObserver(this);
47
48   // For telemetry, we mark session restore completed to avoid warnings from
49   // MergeSessionThrottle.
50   if (CommandLine::ForCurrentProcess()->
51           HasSwitch(chromeos::switches::kDisableGaiaServices)) {
52     SetSessionRestoreState(SESSION_RESTORE_DONE);
53   }
54 }
55
56 OAuth2LoginManager::~OAuth2LoginManager() {
57 }
58
59 void OAuth2LoginManager::AddObserver(OAuth2LoginManager::Observer* observer) {
60   observer_list_.AddObserver(observer);
61 }
62
63 void OAuth2LoginManager::RemoveObserver(
64     OAuth2LoginManager::Observer* observer) {
65   observer_list_.RemoveObserver(observer);
66 }
67
68 void OAuth2LoginManager::RestoreSession(
69     net::URLRequestContextGetter* auth_request_context,
70     SessionRestoreStrategy restore_strategy,
71     const std::string& oauth2_refresh_token,
72     const std::string& auth_code) {
73   DCHECK(user_profile_);
74   auth_request_context_ = auth_request_context;
75   restore_strategy_ = restore_strategy;
76   refresh_token_ = oauth2_refresh_token;
77   oauthlogin_access_token_ = std::string();
78   auth_code_ = auth_code;
79   session_restore_start_ = base::Time::Now();
80   SetSessionRestoreState(OAuth2LoginManager::SESSION_RESTORE_PREPARING);
81   ContinueSessionRestore();
82 }
83
84 void OAuth2LoginManager::ContinueSessionRestore() {
85   if (restore_strategy_ == RESTORE_FROM_COOKIE_JAR ||
86       restore_strategy_ == RESTORE_FROM_AUTH_CODE) {
87     FetchOAuth2Tokens();
88     return;
89   }
90
91   // Save passed OAuth2 refresh token.
92   if (restore_strategy_ == RESTORE_FROM_PASSED_OAUTH2_REFRESH_TOKEN) {
93     DCHECK(!refresh_token_.empty());
94     restore_strategy_ = RESTORE_FROM_SAVED_OAUTH2_REFRESH_TOKEN;
95     StoreOAuth2Token();
96     return;
97   }
98
99   DCHECK(restore_strategy_ == RESTORE_FROM_SAVED_OAUTH2_REFRESH_TOKEN);
100   RestoreSessionFromSavedTokens();
101 }
102
103 void OAuth2LoginManager::RestoreSessionFromSavedTokens() {
104   ProfileOAuth2TokenService* token_service = GetTokenService();
105   const std::string& primary_account_id = GetPrimaryAccountId();
106   if (token_service->RefreshTokenIsAvailable(primary_account_id)) {
107     VLOG(1) << "OAuth2 refresh token is already loaded.";
108     VerifySessionCookies();
109   } else {
110     VLOG(1) << "Loading OAuth2 refresh token from database.";
111
112     // Flag user with unknown token status in case there are no saved tokens
113     // and OnRefreshTokenAvailable is not called. Flagging it here would
114     // cause user to go through Gaia in next login to obtain a new refresh
115     // token.
116     user_manager::UserManager::Get()->SaveUserOAuthStatus(
117         primary_account_id, user_manager::User::OAUTH_TOKEN_STATUS_UNKNOWN);
118
119     token_service->LoadCredentials(primary_account_id);
120   }
121 }
122
123 void OAuth2LoginManager::Stop() {
124   oauth2_token_fetcher_.reset();
125   login_verifier_.reset();
126 }
127
128 bool OAuth2LoginManager::ShouldBlockTabLoading() {
129   return state_ == SESSION_RESTORE_PREPARING ||
130          state_ == SESSION_RESTORE_IN_PROGRESS;
131 }
132
133 void OAuth2LoginManager::OnRefreshTokenAvailable(
134     const std::string& account_id) {
135   VLOG(1) << "OnRefreshTokenAvailable";
136
137   if (state_ == SESSION_RESTORE_NOT_STARTED)
138     return;
139
140   // TODO(fgorski): Once ProfileOAuth2TokenService supports multi-login, make
141   // sure to restore session cookies in the context of the correct account_id.
142
143   // Do not validate tokens for supervised users, as they don't actually have
144   // oauth2 token.
145   if (user_manager::UserManager::Get()->IsLoggedInAsSupervisedUser()) {
146     VLOG(1) << "Logged in as supervised user, skip token validation.";
147     return;
148   }
149   // Only restore session cookies for the primary account in the profile.
150   if (GetPrimaryAccountId() == account_id) {
151     // Token is loaded. Undo the flagging before token loading.
152     user_manager::UserManager::Get()->SaveUserOAuthStatus(
153         account_id, user_manager::User::OAUTH2_TOKEN_STATUS_VALID);
154     VerifySessionCookies();
155   }
156 }
157
158 ProfileOAuth2TokenService* OAuth2LoginManager::GetTokenService() {
159   return ProfileOAuth2TokenServiceFactory::GetForProfile(user_profile_);
160 }
161
162 const std::string& OAuth2LoginManager::GetPrimaryAccountId() {
163   SigninManagerBase* signin_manager =
164       SigninManagerFactory::GetForProfile(user_profile_);
165   return signin_manager->GetAuthenticatedAccountId();
166 }
167
168 void OAuth2LoginManager::StoreOAuth2Token() {
169   const std::string& primary_account_id = GetPrimaryAccountId();
170   if (primary_account_id.empty()) {
171     GetAccountInfoOfRefreshToken(refresh_token_);
172     return;
173   }
174
175   UpdateCredentials(primary_account_id);
176 }
177
178 void OAuth2LoginManager::GetAccountInfoOfRefreshToken(
179     const std::string& refresh_token) {
180   gaia::OAuthClientInfo client_info;
181   GaiaUrls* gaia_urls = GaiaUrls::GetInstance();
182   client_info.client_id = gaia_urls->oauth2_chrome_client_id();
183   client_info.client_secret = gaia_urls->oauth2_chrome_client_secret();
184
185   account_info_fetcher_.reset(new gaia::GaiaOAuthClient(
186       auth_request_context_.get()));
187   account_info_fetcher_->RefreshToken(client_info, refresh_token,
188       std::vector<std::string>(1, kServiceScopeGetUserInfo), kMaxRetries,
189       this);
190 }
191
192 void OAuth2LoginManager::UpdateCredentials(const std::string& account_id) {
193   DCHECK(!account_id.empty());
194   DCHECK(!refresh_token_.empty());
195   // |account_id| is assumed to be already canonicalized if it's an email.
196   GetTokenService()->UpdateCredentials(account_id, refresh_token_);
197
198   FOR_EACH_OBSERVER(Observer, observer_list_,
199                     OnNewRefreshTokenAvaiable(user_profile_));
200 }
201
202 void OAuth2LoginManager::OnRefreshTokenResponse(
203     const std::string& access_token,
204     int expires_in_seconds) {
205   account_info_fetcher_->GetUserInfo(access_token, kMaxRetries, this);
206 }
207
208 void OAuth2LoginManager::OnGetUserInfoResponse(
209     scoped_ptr<base::DictionaryValue> user_info) {
210   account_info_fetcher_.reset();
211
212   std::string gaia_id;
213   std::string email;
214   user_info->GetString("id", &gaia_id);
215   user_info->GetString("email", &email);
216
217   AccountTrackerService* account_tracker =
218       AccountTrackerServiceFactory::GetForProfile(user_profile_);
219   account_tracker->SeedAccountInfo(gaia_id, email);
220   UpdateCredentials(account_tracker->PickAccountIdForAccount(gaia_id, email));
221 }
222
223 void OAuth2LoginManager::OnOAuthError() {
224   account_info_fetcher_.reset();
225   LOG(ERROR) << "Account info fetch failed!";
226   SetSessionRestoreState(OAuth2LoginManager::SESSION_RESTORE_FAILED);
227 }
228
229 void OAuth2LoginManager::OnNetworkError(int response_code) {
230   account_info_fetcher_.reset();
231   LOG(ERROR) << "Account info fetch failed! response_code=" << response_code;
232   SetSessionRestoreState(OAuth2LoginManager::SESSION_RESTORE_FAILED);
233 }
234
235 void OAuth2LoginManager::FetchOAuth2Tokens() {
236   DCHECK(auth_request_context_.get());
237   // If we have authenticated cookie jar, get OAuth1 token first, then fetch
238   // SID/LSID cookies through OAuthLogin call.
239   if (restore_strategy_ == RESTORE_FROM_COOKIE_JAR) {
240     SigninClient* signin_client =
241         ChromeSigninClientFactory::GetForProfile(user_profile_);
242     std::string signin_scoped_device_id =
243         signin_client->GetSigninScopedDeviceId();
244
245     oauth2_token_fetcher_.reset(
246         new OAuth2TokenFetcher(this, auth_request_context_.get()));
247     oauth2_token_fetcher_->StartExchangeFromCookies(std::string(),
248                                                     signin_scoped_device_id);
249   } else if (restore_strategy_ == RESTORE_FROM_AUTH_CODE) {
250     DCHECK(!auth_code_.empty());
251     oauth2_token_fetcher_.reset(
252         new OAuth2TokenFetcher(this,
253                                g_browser_process->system_request_context()));
254     oauth2_token_fetcher_->StartExchangeFromAuthCode(auth_code_);
255   } else {
256     NOTREACHED();
257     SetSessionRestoreState(OAuth2LoginManager::SESSION_RESTORE_FAILED);
258   }
259 }
260
261 void OAuth2LoginManager::OnOAuth2TokensAvailable(
262     const GaiaAuthConsumer::ClientOAuthResult& oauth2_tokens) {
263   VLOG(1) << "OAuth2 tokens fetched";
264   DCHECK(refresh_token_.empty());
265   refresh_token_.assign(oauth2_tokens.refresh_token);
266   oauthlogin_access_token_ = oauth2_tokens.access_token;
267   StoreOAuth2Token();
268 }
269
270 void OAuth2LoginManager::OnOAuth2TokensFetchFailed() {
271   LOG(ERROR) << "OAuth2 tokens fetch failed!";
272   RecordSessionRestoreOutcome(SESSION_RESTORE_TOKEN_FETCH_FAILED,
273                               SESSION_RESTORE_FAILED);
274 }
275
276 void OAuth2LoginManager::VerifySessionCookies() {
277   DCHECK(!login_verifier_.get());
278   login_verifier_.reset(
279       new OAuth2LoginVerifier(this,
280                               g_browser_process->system_request_context(),
281                               user_profile_->GetRequestContext(),
282                               oauthlogin_access_token_));
283
284   if (restore_strategy_ == RESTORE_FROM_SAVED_OAUTH2_REFRESH_TOKEN) {
285     login_verifier_->VerifyUserCookies(user_profile_);
286     return;
287   }
288
289   RestoreSessionCookies();
290 }
291
292 void OAuth2LoginManager::RestoreSessionCookies() {
293   SetSessionRestoreState(SESSION_RESTORE_IN_PROGRESS);
294   login_verifier_->VerifyProfileTokens(user_profile_);
295 }
296
297 void OAuth2LoginManager::Shutdown() {
298   GetTokenService()->RemoveObserver(this);
299   login_verifier_.reset();
300   oauth2_token_fetcher_.reset();
301 }
302
303 void OAuth2LoginManager::OnSessionMergeSuccess() {
304   VLOG(1) << "OAuth2 refresh and/or GAIA token verification succeeded.";
305   RecordSessionRestoreOutcome(SESSION_RESTORE_SUCCESS,
306                               SESSION_RESTORE_DONE);
307 }
308
309 void OAuth2LoginManager::OnSessionMergeFailure(bool connection_error) {
310   LOG(ERROR) << "OAuth2 refresh and GAIA token verification failed!"
311              << " connection_error: " << connection_error;
312   RecordSessionRestoreOutcome(SESSION_RESTORE_MERGE_SESSION_FAILED,
313                               connection_error ?
314                                   SESSION_RESTORE_CONNECTION_FAILED :
315                                   SESSION_RESTORE_FAILED);
316 }
317
318 void OAuth2LoginManager::OnListAccountsSuccess(const std::string& data) {
319   MergeVerificationOutcome outcome = POST_MERGE_SUCCESS;
320   // Let's analyze which accounts we see logged in here:
321   std::vector<std::pair<std::string, bool> > accounts;
322   gaia::ParseListAccountsData(data, &accounts);
323   std::string user_email = gaia::CanonicalizeEmail(GetPrimaryAccountId());
324   if (!accounts.empty()) {
325     bool found = false;
326     bool first = true;
327     for (std::vector<std::pair<std::string, bool> >::const_iterator iter =
328              accounts.begin();
329          iter != accounts.end(); ++iter) {
330       if (gaia::CanonicalizeEmail(iter->first) == user_email) {
331         found = iter->second;
332         break;
333       }
334
335       first = false;
336     }
337
338     if (!found)
339       outcome = POST_MERGE_MISSING_PRIMARY_ACCOUNT;
340     else if (!first)
341       outcome = POST_MERGE_PRIMARY_NOT_FIRST_ACCOUNT;
342
343   } else {
344     outcome = POST_MERGE_NO_ACCOUNTS;
345   }
346
347   bool is_pre_merge = (state_ == SESSION_RESTORE_PREPARING);
348   RecordCookiesCheckOutcome(is_pre_merge, outcome);
349   // If the primary account is missing during the initial cookie freshness
350   // check, try to restore GAIA session cookies form the OAuth2 tokens.
351   if (is_pre_merge) {
352     if (outcome != POST_MERGE_SUCCESS &&
353         outcome != POST_MERGE_PRIMARY_NOT_FIRST_ACCOUNT) {
354       RestoreSessionCookies();
355     } else {
356       // We are done with this account, it's GAIA cookies are legit.
357       RecordSessionRestoreOutcome(SESSION_RESTORE_NOT_NEEDED,
358                                   SESSION_RESTORE_DONE);
359     }
360   }
361 }
362
363 void OAuth2LoginManager::OnListAccountsFailure(bool connection_error) {
364   bool is_pre_merge = (state_ == SESSION_RESTORE_PREPARING);
365   RecordCookiesCheckOutcome(
366       is_pre_merge,
367       connection_error ? POST_MERGE_CONNECTION_FAILED :
368                          POST_MERGE_VERIFICATION_FAILED);
369   if (is_pre_merge) {
370     if (!connection_error) {
371       // If we failed to get account list, our cookies might be stale so we
372       // need to attempt to restore them.
373       RestoreSessionCookies();
374     } else {
375       RecordSessionRestoreOutcome(SESSION_RESTORE_LISTACCOUNTS_FAILED,
376                                   SESSION_RESTORE_CONNECTION_FAILED);
377     }
378   }
379 }
380
381 void OAuth2LoginManager::RecordSessionRestoreOutcome(
382     SessionRestoreOutcome outcome,
383     OAuth2LoginManager::SessionRestoreState state) {
384   UMA_HISTOGRAM_ENUMERATION("OAuth2Login.SessionRestore",
385                             outcome,
386                             SESSION_RESTORE_COUNT);
387   SetSessionRestoreState(state);
388 }
389
390 // static
391 void OAuth2LoginManager::RecordCookiesCheckOutcome(
392     bool is_pre_merge,
393     MergeVerificationOutcome outcome) {
394   if (is_pre_merge) {
395     UMA_HISTOGRAM_ENUMERATION("OAuth2Login.PreMergeVerification",
396                               outcome,
397                               POST_MERGE_COUNT);
398   } else {
399     UMA_HISTOGRAM_ENUMERATION("OAuth2Login.PostMergeVerification",
400                               outcome,
401                               POST_MERGE_COUNT);
402   }
403 }
404
405 void OAuth2LoginManager::SetSessionRestoreState(
406     OAuth2LoginManager::SessionRestoreState state) {
407   if (state_ == state)
408     return;
409
410   state_ = state;
411   if (state == OAuth2LoginManager::SESSION_RESTORE_FAILED) {
412     UMA_HISTOGRAM_TIMES("OAuth2Login.SessionRestoreTimeToFailure",
413                         base::Time::Now() - session_restore_start_);
414   } else if (state == OAuth2LoginManager::SESSION_RESTORE_DONE) {
415     UMA_HISTOGRAM_TIMES("OAuth2Login.SessionRestoreTimeToSuccess",
416                         base::Time::Now() - session_restore_start_);
417   }
418
419   FOR_EACH_OBSERVER(Observer, observer_list_,
420                     OnSessionRestoreStateChanged(user_profile_, state_));
421 }
422
423 void OAuth2LoginManager::SetSessionRestoreStartForTesting(
424     const base::Time& time) {
425   session_restore_start_ = time;
426 }
427
428 }  // namespace chromeos