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