Disable view source for Developer Tools.
[chromium-blink-merge.git] / chrome / browser / chromeos / login / oauth2_login_verifier.cc
blob78864127ab548a93ff4ab666ed3748ab71ffc164
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.
5 #include "chrome/browser/chromeos/login/oauth2_login_verifier.h"
7 #include <vector>
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 "chromeos/network/network_handler.h"
18 #include "chromeos/network/network_state.h"
19 #include "chromeos/network/network_state_handler.h"
20 #include "content/public/browser/browser_thread.h"
21 #include "google_apis/gaia/gaia_constants.h"
22 #include "google_apis/gaia/gaia_urls.h"
23 #include "third_party/cros_system_api/dbus/service_constants.h"
25 using content::BrowserThread;
27 namespace {
29 // OAuth token request max retry count.
30 const int kMaxRequestAttemptCount = 5;
32 // OAuth token request retry delay in milliseconds.
33 const int kRequestRestartDelay = 3000;
35 // Post merge session verification delay.
36 #ifndef NDEBUG
37 const int kPostResoreVerificationDelay = 1000;
38 #else
39 const int kPostResoreVerificationDelay = 1000*60*3;
40 #endif
42 bool IsConnectionOrServiceError(const GoogleServiceAuthError& error) {
43 return error.state() == GoogleServiceAuthError::CONNECTION_FAILED ||
44 error.state() == GoogleServiceAuthError::SERVICE_UNAVAILABLE ||
45 error.state() == GoogleServiceAuthError::REQUEST_CANCELED;
48 } // namespace
50 namespace chromeos {
52 OAuth2LoginVerifier::OAuth2LoginVerifier(
53 OAuth2LoginVerifier::Delegate* delegate,
54 net::URLRequestContextGetter* system_request_context,
55 net::URLRequestContextGetter* user_request_context,
56 const std::string& oauthlogin_access_token)
57 : OAuth2TokenService::Consumer("cros_login_verifier"),
58 delegate_(delegate),
59 system_request_context_(system_request_context),
60 user_request_context_(user_request_context),
61 access_token_(oauthlogin_access_token),
62 retry_count_(0) {
63 DCHECK(delegate);
66 OAuth2LoginVerifier::~OAuth2LoginVerifier() {
69 void OAuth2LoginVerifier::VerifyProfileTokens(Profile* profile) {
70 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
72 // Delay the verification if the network is not connected or on a captive
73 // portal.
74 const NetworkState* default_network =
75 NetworkHandler::Get()->network_state_handler()->DefaultNetwork();
76 NetworkPortalDetector* detector = NetworkPortalDetector::Get();
77 if (!default_network ||
78 default_network->connection_state() == shill::kStatePortal ||
79 (detector && detector->GetCaptivePortalState(default_network).status !=
80 NetworkPortalDetector::CAPTIVE_PORTAL_STATUS_ONLINE)) {
81 // If network is offline, defer the token fetching until online.
82 LOG(WARNING) << "Network is offline. Deferring OAuth2 access token fetch.";
83 BrowserThread::PostDelayedTask(
84 BrowserThread::UI,
85 FROM_HERE,
86 base::Bind(
87 &OAuth2LoginVerifier::VerifyProfileTokens, AsWeakPtr(), profile),
88 base::TimeDelta::FromMilliseconds(kRequestRestartDelay));
89 return;
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();
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 login_token_request_ = token_service->StartRequestWithContext(
109 token_service->GetPrimaryAccountId(),
110 system_request_context_.get(),
111 scopes,
112 this);
115 void OAuth2LoginVerifier::StartOAuthLoginForUberToken() {
116 // No service will fetch us uber auth token.
117 gaia_fetcher_.reset(
118 new GaiaAuthFetcher(this,
119 std::string(GaiaConstants::kChromeOSSource),
120 user_request_context_.get()));
121 gaia_fetcher_->StartTokenFetchForUberAuthExchange(access_token_);
125 void OAuth2LoginVerifier::OnUberAuthTokenSuccess(
126 const std::string& uber_token) {
127 VLOG(1) << "OAuthLogin(uber_token) successful!";
128 retry_count_ = 0;
129 gaia_token_ = uber_token;
130 StartMergeSession();
133 void OAuth2LoginVerifier::OnUberAuthTokenFailure(
134 const GoogleServiceAuthError& error) {
135 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
136 LOG(WARNING) << "OAuthLogin(uber_token) failed,"
137 << " error: " << error.state();
138 RetryOnError("OAuthLoginUberToken", error,
139 base::Bind(&OAuth2LoginVerifier::StartOAuthLoginForUberToken,
140 AsWeakPtr()),
141 base::Bind(&Delegate::OnSessionMergeFailure,
142 base::Unretained(delegate_)));
145 void OAuth2LoginVerifier::StartMergeSession() {
146 DCHECK(!gaia_token_.empty());
147 gaia_fetcher_.reset(
148 new GaiaAuthFetcher(this,
149 std::string(GaiaConstants::kChromeOSSource),
150 user_request_context_.get()));
151 gaia_fetcher_->StartMergeSession(gaia_token_);
154 void OAuth2LoginVerifier::OnMergeSessionSuccess(const std::string& data) {
155 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
156 VLOG(1) << "MergeSession successful.";
157 delegate_->OnSessionMergeSuccess();
158 // Schedule post-merge verification to analyze how many LSID/SID overruns
159 // were created by the session restore.
160 SchedulePostMergeVerification();
163 void OAuth2LoginVerifier::SchedulePostMergeVerification() {
164 BrowserThread::PostDelayedTask(
165 BrowserThread::UI,
166 FROM_HERE,
167 base::Bind(
168 &OAuth2LoginVerifier::StartPostRestoreVerification, AsWeakPtr()),
169 base::TimeDelta::FromMilliseconds(kPostResoreVerificationDelay));
172 void OAuth2LoginVerifier::StartPostRestoreVerification() {
173 gaia_fetcher_.reset(
174 new GaiaAuthFetcher(this,
175 std::string(GaiaConstants::kChromeOSSource),
176 user_request_context_.get()));
177 gaia_fetcher_->StartListAccounts();
180 void OAuth2LoginVerifier::OnMergeSessionFailure(
181 const GoogleServiceAuthError& error) {
182 LOG(WARNING) << "Failed MergeSession request," << " error: " << error.state();
183 // If MergeSession from GAIA service token fails, retry the session restore
184 // from OAuth2 refresh token. If that failed too, signal the delegate.
185 RetryOnError(
186 "MergeSession",
187 error,
188 base::Bind(&OAuth2LoginVerifier::StartMergeSession,
189 AsWeakPtr()),
190 base::Bind(&Delegate::OnSessionMergeFailure,
191 base::Unretained(delegate_)));
194 void OAuth2LoginVerifier::OnGetTokenSuccess(
195 const OAuth2TokenService::Request* request,
196 const std::string& access_token,
197 const base::Time& expiration_time) {
198 DCHECK_EQ(login_token_request_.get(), request);
199 login_token_request_.reset();
201 VLOG(1) << "Got OAuth2 access token!";
202 retry_count_ = 0;
203 access_token_ = access_token;
204 StartOAuthLoginForUberToken();
207 void OAuth2LoginVerifier::OnGetTokenFailure(
208 const OAuth2TokenService::Request* request,
209 const GoogleServiceAuthError& error) {
210 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
211 DCHECK_EQ(login_token_request_.get(), request);
212 login_token_request_.reset();
214 LOG(WARNING) << "Failed to get OAuth2 access token, "
215 << " error: " << error.state();
216 UMA_HISTOGRAM_ENUMERATION(
217 base::StringPrintf("OAuth2Login.%sFailure", "GetOAuth2AccessToken"),
218 error.state(),
219 GoogleServiceAuthError::NUM_STATES);
220 delegate_->OnSessionMergeFailure(IsConnectionOrServiceError(error));
223 void OAuth2LoginVerifier::OnListAccountsSuccess(
224 const std::string& data) {
225 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
226 VLOG(1) << "ListAccounts successful.";
227 delegate_->OnListAccountsSuccess(data);
230 void OAuth2LoginVerifier::OnListAccountsFailure(
231 const GoogleServiceAuthError& error) {
232 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
233 LOG(WARNING) << "Failed to get list of session accounts, "
234 << " error: " << error.state();
235 RetryOnError(
236 "ListAccounts",
237 error,
238 base::Bind(&OAuth2LoginVerifier::StartPostRestoreVerification,
239 AsWeakPtr()),
240 base::Bind(&Delegate::OnListAccountsFailure,
241 base::Unretained(delegate_)));
244 void OAuth2LoginVerifier::RetryOnError(const char* operation_id,
245 const GoogleServiceAuthError& error,
246 const base::Closure& task_to_retry,
247 const ErrorHandler& error_handler) {
248 if (IsConnectionOrServiceError(error) &&
249 retry_count_ < kMaxRequestAttemptCount) {
250 retry_count_++;
251 UMA_HISTOGRAM_ENUMERATION(
252 base::StringPrintf("OAuth2Login.%sRetry", operation_id),
253 error.state(),
254 GoogleServiceAuthError::NUM_STATES);
255 BrowserThread::PostDelayedTask(
256 BrowserThread::UI, FROM_HERE, task_to_retry,
257 base::TimeDelta::FromMilliseconds(kRequestRestartDelay));
258 return;
261 LOG(WARNING) << "Unrecoverable error or retry count max reached for "
262 << operation_id;
263 UMA_HISTOGRAM_ENUMERATION(
264 base::StringPrintf("OAuth2Login.%sFailure", operation_id),
265 error.state(),
266 GoogleServiceAuthError::NUM_STATES);
268 error_handler.Run(IsConnectionOrServiceError(error));
271 } // namespace chromeos