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"
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"
27 using content::BrowserThread;
31 // OAuth token request max retry count.
32 const int kMaxRequestAttemptCount = 5;
34 // OAuth token request retry delay in milliseconds.
35 const int kRequestRestartDelay = 3000;
37 // Post merge session verification delay.
39 const int kPostResoreVerificationDelay = 1000;
41 const int kPostResoreVerificationDelay = 1000*60*3;
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;
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"),
61 system_request_context_(system_request_context),
62 user_request_context_(user_request_context),
63 access_token_(oauthlogin_access_token),
68 OAuth2LoginVerifier::~OAuth2LoginVerifier() {
71 void OAuth2LoginVerifier::VerifyUserCookies(Profile* profile) {
72 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
74 if (DelayNetworkCall(base::Bind(&OAuth2LoginVerifier::VerifyUserCookies,
80 StartAuthCookiesVerification();
83 void OAuth2LoginVerifier::VerifyProfileTokens(Profile* profile) {
84 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
86 if (DelayNetworkCall(base::Bind(&OAuth2LoginVerifier::VerifyProfileTokens,
93 if (access_token_.empty()) {
94 // Fetch /OAuthLogin scoped access token.
95 StartFetchingOAuthLoginAccessToken(profile);
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 SigninManagerBase* signin_manager =
109 SigninManagerFactory::GetForProfile(profile);
110 login_token_request_ = token_service->StartRequestWithContext(
111 signin_manager->GetAuthenticatedAccountId(),
112 system_request_context_.get(),
117 void OAuth2LoginVerifier::StartOAuthLoginForUberToken() {
118 // No service will fetch us uber auth token.
120 new GaiaAuthFetcher(this,
121 std::string(GaiaConstants::kChromeOSSource),
122 user_request_context_.get()));
123 gaia_fetcher_->StartTokenFetchForUberAuthExchange(access_token_);
127 void OAuth2LoginVerifier::OnUberAuthTokenSuccess(
128 const std::string& uber_token) {
129 VLOG(1) << "OAuthLogin(uber_token) successful!";
131 gaia_token_ = uber_token;
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,
143 base::Bind(&Delegate::OnSessionMergeFailure,
144 base::Unretained(delegate_)));
147 void OAuth2LoginVerifier::StartMergeSession() {
148 DCHECK(!gaia_token_.empty());
150 new GaiaAuthFetcher(this,
151 std::string(GaiaConstants::kChromeOSSource),
152 user_request_context_.get()));
153 gaia_fetcher_->StartMergeSession(gaia_token_);
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();
165 void OAuth2LoginVerifier::SchedulePostMergeVerification() {
166 BrowserThread::PostDelayedTask(
170 &OAuth2LoginVerifier::StartAuthCookiesVerification, AsWeakPtr()),
171 base::TimeDelta::FromMilliseconds(kPostResoreVerificationDelay));
174 void OAuth2LoginVerifier::StartAuthCookiesVerification() {
176 new GaiaAuthFetcher(this,
177 std::string(GaiaConstants::kChromeOSSource),
178 user_request_context_.get()));
179 gaia_fetcher_->StartListAccounts();
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.
190 base::Bind(&OAuth2LoginVerifier::StartMergeSession,
192 base::Bind(&Delegate::OnSessionMergeFailure,
193 base::Unretained(delegate_)));
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();
203 VLOG(1) << "Got OAuth2 access token!";
205 access_token_ = access_token;
206 StartOAuthLoginForUberToken();
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();
216 LOG(WARNING) << "Failed to get OAuth2 access token, "
217 << " error: " << error.state();
218 UMA_HISTOGRAM_ENUMERATION(
219 base::StringPrintf("OAuth2Login.%sFailure", "GetOAuth2AccessToken"),
221 GoogleServiceAuthError::NUM_STATES);
222 delegate_->OnSessionMergeFailure(IsConnectionOrServiceError(error));
225 void OAuth2LoginVerifier::OnListAccountsSuccess(
226 const std::string& data) {
227 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
228 VLOG(1) << "ListAccounts successful.";
229 delegate_->OnListAccountsSuccess(data);
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();
240 base::Bind(&OAuth2LoginVerifier::StartAuthCookiesVerification,
242 base::Bind(&Delegate::OnListAccountsFailure,
243 base::Unretained(delegate_)));
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) {
253 UMA_HISTOGRAM_ENUMERATION(
254 base::StringPrintf("OAuth2Login.%sRetry", operation_id),
256 GoogleServiceAuthError::NUM_STATES);
257 BrowserThread::PostDelayedTask(
258 BrowserThread::UI, FROM_HERE, task_to_retry,
259 base::TimeDelta::FromMilliseconds(kRequestRestartDelay));
263 LOG(WARNING) << "Unrecoverable error or retry count max reached for "
265 UMA_HISTOGRAM_ENUMERATION(
266 base::StringPrintf("OAuth2Login.%sFailure", operation_id),
268 GoogleServiceAuthError::NUM_STATES);
270 error_handler.Run(IsConnectionOrServiceError(error));
273 bool OAuth2LoginVerifier::DelayNetworkCall(const base::Closure& callback) {
274 // Delay the verification if the network is not connected or on a captive
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(
289 base::TimeDelta::FromMilliseconds(kRequestRestartDelay));
296 } // namespace chromeos