Upstream version 5.34.104.0
[platform/framework/web/crosswalk.git] / src / chrome / browser / chromeos / login / oauth2_login_verifier.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_verifier.h"
6
7 #include <vector>
8
9 #include "base/logging.h"
10 #include "base/metrics/histogram.h"
11 #include "base/strings/string_util.h"
12 #include "base/strings/stringprintf.h"
13 #include "base/time/time.h"
14 #include "chrome/browser/chromeos/net/network_portal_detector.h"
15 #include "chrome/browser/signin/profile_oauth2_token_service.h"
16 #include "chrome/browser/signin/profile_oauth2_token_service_factory.h"
17 #include "chrome/browser/signin/signin_manager.h"
18 #include "chrome/browser/signin/signin_manager_factory.h"
19 #include "chromeos/network/network_handler.h"
20 #include "chromeos/network/network_state.h"
21 #include "chromeos/network/network_state_handler.h"
22 #include "content/public/browser/browser_thread.h"
23 #include "google_apis/gaia/gaia_constants.h"
24 #include "google_apis/gaia/gaia_urls.h"
25 #include "third_party/cros_system_api/dbus/service_constants.h"
26
27 using content::BrowserThread;
28
29 namespace {
30
31 // OAuth token request max retry count.
32 const int kMaxRequestAttemptCount = 5;
33
34 // OAuth token request retry delay in milliseconds.
35 const int kRequestRestartDelay = 3000;
36
37 // Post merge session verification delay.
38 #ifndef NDEBUG
39 const int kPostResoreVerificationDelay = 1000;
40 #else
41 const int kPostResoreVerificationDelay = 1000*60*3;
42 #endif
43
44 bool IsConnectionOrServiceError(const GoogleServiceAuthError& error) {
45   return error.state() == GoogleServiceAuthError::CONNECTION_FAILED ||
46          error.state() == GoogleServiceAuthError::SERVICE_UNAVAILABLE ||
47          error.state() == GoogleServiceAuthError::REQUEST_CANCELED;
48 }
49
50 }  // namespace
51
52 namespace chromeos {
53
54 OAuth2LoginVerifier::OAuth2LoginVerifier(
55     OAuth2LoginVerifier::Delegate* delegate,
56     net::URLRequestContextGetter* system_request_context,
57     net::URLRequestContextGetter* user_request_context,
58     const std::string& oauthlogin_access_token)
59     : OAuth2TokenService::Consumer("cros_login_verifier"),
60       delegate_(delegate),
61       system_request_context_(system_request_context),
62       user_request_context_(user_request_context),
63       access_token_(oauthlogin_access_token),
64       retry_count_(0) {
65   DCHECK(delegate);
66 }
67
68 OAuth2LoginVerifier::~OAuth2LoginVerifier() {
69 }
70
71 void OAuth2LoginVerifier::VerifyUserCookies(Profile* profile) {
72   DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
73
74   if (DelayNetworkCall(base::Bind(&OAuth2LoginVerifier::VerifyUserCookies,
75                                   AsWeakPtr(),
76                                   profile))) {
77     return;
78   }
79
80   StartAuthCookiesVerification();
81 }
82
83 void OAuth2LoginVerifier::VerifyProfileTokens(Profile* profile) {
84   DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
85
86   if (DelayNetworkCall(base::Bind(&OAuth2LoginVerifier::VerifyProfileTokens,
87                                   AsWeakPtr(),
88                                   profile))) {
89     return;
90   }
91
92   gaia_token_.clear();
93   if (access_token_.empty()) {
94     // Fetch /OAuthLogin scoped access token.
95     StartFetchingOAuthLoginAccessToken(profile);
96   } else {
97     // If OAuthLogin-scoped access token already exists (if it's generated
98     // together with freshly minted refresh token), then fetch GAIA uber token.
99     StartOAuthLoginForUberToken();
100   }
101 }
102
103 void OAuth2LoginVerifier::StartFetchingOAuthLoginAccessToken(Profile* profile) {
104   OAuth2TokenService::ScopeSet scopes;
105   scopes.insert(GaiaUrls::GetInstance()->oauth1_login_scope());
106   ProfileOAuth2TokenService* token_service =
107       ProfileOAuth2TokenServiceFactory::GetForProfile(profile);
108   SigninManagerBase* signin_manager =
109       SigninManagerFactory::GetForProfile(profile);
110   login_token_request_ = token_service->StartRequestWithContext(
111       signin_manager->GetAuthenticatedAccountId(),
112       system_request_context_.get(),
113       scopes,
114       this);
115 }
116
117 void OAuth2LoginVerifier::StartOAuthLoginForUberToken() {
118   // No service will fetch us uber auth token.
119   gaia_fetcher_.reset(
120       new GaiaAuthFetcher(this,
121                           std::string(GaiaConstants::kChromeOSSource),
122                           user_request_context_.get()));
123   gaia_fetcher_->StartTokenFetchForUberAuthExchange(access_token_);
124 }
125
126
127 void OAuth2LoginVerifier::OnUberAuthTokenSuccess(
128     const std::string& uber_token) {
129   VLOG(1) << "OAuthLogin(uber_token) successful!";
130   retry_count_ = 0;
131   gaia_token_ = uber_token;
132   StartMergeSession();
133 }
134
135 void OAuth2LoginVerifier::OnUberAuthTokenFailure(
136     const GoogleServiceAuthError& error) {
137   DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
138   LOG(WARNING) << "OAuthLogin(uber_token) failed,"
139                << " error: " << error.state();
140   RetryOnError("OAuthLoginUberToken", error,
141                base::Bind(&OAuth2LoginVerifier::StartOAuthLoginForUberToken,
142                           AsWeakPtr()),
143                base::Bind(&Delegate::OnSessionMergeFailure,
144                           base::Unretained(delegate_)));
145 }
146
147 void OAuth2LoginVerifier::StartMergeSession() {
148   DCHECK(!gaia_token_.empty());
149   gaia_fetcher_.reset(
150       new GaiaAuthFetcher(this,
151                           std::string(GaiaConstants::kChromeOSSource),
152                           user_request_context_.get()));
153   gaia_fetcher_->StartMergeSession(gaia_token_);
154 }
155
156 void OAuth2LoginVerifier::OnMergeSessionSuccess(const std::string& data) {
157   DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
158   VLOG(1) << "MergeSession successful.";
159   delegate_->OnSessionMergeSuccess();
160   // Schedule post-merge verification to analyze how many LSID/SID overruns
161   // were created by the session restore.
162   SchedulePostMergeVerification();
163 }
164
165 void OAuth2LoginVerifier::SchedulePostMergeVerification() {
166   BrowserThread::PostDelayedTask(
167       BrowserThread::UI,
168       FROM_HERE,
169       base::Bind(
170           &OAuth2LoginVerifier::StartAuthCookiesVerification, AsWeakPtr()),
171       base::TimeDelta::FromMilliseconds(kPostResoreVerificationDelay));
172 }
173
174 void OAuth2LoginVerifier::StartAuthCookiesVerification() {
175   gaia_fetcher_.reset(
176       new GaiaAuthFetcher(this,
177                           std::string(GaiaConstants::kChromeOSSource),
178                           user_request_context_.get()));
179   gaia_fetcher_->StartListAccounts();
180 }
181
182 void OAuth2LoginVerifier::OnMergeSessionFailure(
183     const GoogleServiceAuthError& error) {
184   LOG(WARNING) << "Failed MergeSession request," << " error: " << error.state();
185   // If MergeSession from GAIA service token fails, retry the session restore
186   // from OAuth2 refresh token. If that failed too, signal the delegate.
187   RetryOnError(
188       "MergeSession",
189       error,
190       base::Bind(&OAuth2LoginVerifier::StartMergeSession,
191                  AsWeakPtr()),
192       base::Bind(&Delegate::OnSessionMergeFailure,
193                  base::Unretained(delegate_)));
194 }
195
196 void OAuth2LoginVerifier::OnGetTokenSuccess(
197     const OAuth2TokenService::Request* request,
198     const std::string& access_token,
199     const base::Time& expiration_time) {
200   DCHECK_EQ(login_token_request_.get(), request);
201   login_token_request_.reset();
202
203   VLOG(1) << "Got OAuth2 access token!";
204   retry_count_ = 0;
205   access_token_ = access_token;
206   StartOAuthLoginForUberToken();
207 }
208
209 void OAuth2LoginVerifier::OnGetTokenFailure(
210     const OAuth2TokenService::Request* request,
211     const GoogleServiceAuthError& error) {
212   DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
213   DCHECK_EQ(login_token_request_.get(), request);
214   login_token_request_.reset();
215
216   LOG(WARNING) << "Failed to get OAuth2 access token, "
217                << " error: " << error.state();
218   UMA_HISTOGRAM_ENUMERATION(
219       base::StringPrintf("OAuth2Login.%sFailure", "GetOAuth2AccessToken"),
220       error.state(),
221       GoogleServiceAuthError::NUM_STATES);
222   delegate_->OnSessionMergeFailure(IsConnectionOrServiceError(error));
223 }
224
225 void OAuth2LoginVerifier::OnListAccountsSuccess(
226     const std::string& data) {
227   DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
228   VLOG(1) << "ListAccounts successful.";
229   delegate_->OnListAccountsSuccess(data);
230 }
231
232 void OAuth2LoginVerifier::OnListAccountsFailure(
233     const GoogleServiceAuthError& error) {
234   DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
235   LOG(WARNING) << "Failed to get list of session accounts, "
236                << " error: " << error.state();
237   RetryOnError(
238       "ListAccounts",
239       error,
240       base::Bind(&OAuth2LoginVerifier::StartAuthCookiesVerification,
241                  AsWeakPtr()),
242       base::Bind(&Delegate::OnListAccountsFailure,
243                  base::Unretained(delegate_)));
244 }
245
246 void OAuth2LoginVerifier::RetryOnError(const char* operation_id,
247                                        const GoogleServiceAuthError& error,
248                                        const base::Closure& task_to_retry,
249                                        const ErrorHandler& error_handler) {
250   if (IsConnectionOrServiceError(error) &&
251       retry_count_ < kMaxRequestAttemptCount) {
252     retry_count_++;
253     UMA_HISTOGRAM_ENUMERATION(
254         base::StringPrintf("OAuth2Login.%sRetry", operation_id),
255         error.state(),
256         GoogleServiceAuthError::NUM_STATES);
257     BrowserThread::PostDelayedTask(
258         BrowserThread::UI, FROM_HERE, task_to_retry,
259         base::TimeDelta::FromMilliseconds(kRequestRestartDelay));
260     return;
261   }
262
263   LOG(WARNING) << "Unrecoverable error or retry count max reached for "
264                << operation_id;
265   UMA_HISTOGRAM_ENUMERATION(
266       base::StringPrintf("OAuth2Login.%sFailure", operation_id),
267       error.state(),
268       GoogleServiceAuthError::NUM_STATES);
269
270   error_handler.Run(IsConnectionOrServiceError(error));
271 }
272
273 bool OAuth2LoginVerifier::DelayNetworkCall(const base::Closure& callback) {
274   // Delay the verification if the network is not connected or on a captive
275   // portal.
276   const NetworkState* default_network =
277       NetworkHandler::Get()->network_state_handler()->DefaultNetwork();
278   NetworkPortalDetector* detector = NetworkPortalDetector::Get();
279   if (!default_network ||
280       default_network->connection_state() == shill::kStatePortal ||
281       (detector && detector->GetCaptivePortalState(default_network).status !=
282            NetworkPortalDetector::CAPTIVE_PORTAL_STATUS_ONLINE)) {
283     // If network is offline, defer the token fetching until online.
284     LOG(WARNING) << "Network is offline. Deferring call.";
285     BrowserThread::PostDelayedTask(
286         BrowserThread::UI,
287         FROM_HERE,
288         callback,
289         base::TimeDelta::FromMilliseconds(kRequestRestartDelay));
290     return true;
291   }
292
293   return false;
294 }
295
296 }  // namespace chromeos