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