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_token_fetcher.h" 6 7#include "base/logging.h" 8#include "base/strings/string_util.h" 9#include "chromeos/network/network_handler.h" 10#include "chromeos/network/network_state.h" 11#include "chromeos/network/network_state_handler.h" 12#include "content/public/browser/browser_thread.h" 13#include "google_apis/gaia/gaia_constants.h" 14#include "google_apis/gaia/google_service_auth_error.h" 15#include "third_party/cros_system_api/dbus/service_constants.h" 16 17using content::BrowserThread; 18 19namespace { 20 21// OAuth token request max retry count. 22const int kMaxRequestAttemptCount = 5; 23// OAuth token request retry delay in milliseconds. 24const int kRequestRestartDelay = 3000; 25 26} // namespace 27 28namespace chromeos { 29 30OAuth2TokenFetcher::OAuth2TokenFetcher( 31 OAuth2TokenFetcher::Delegate* delegate, 32 net::URLRequestContextGetter* context_getter) 33 : delegate_(delegate), 34 auth_fetcher_(this, GaiaConstants::kChromeSource, context_getter), 35 retry_count_(0) { 36 DCHECK(delegate); 37} 38 39OAuth2TokenFetcher::~OAuth2TokenFetcher() { 40} 41 42void OAuth2TokenFetcher::StartExchangeFromCookies( 43 const std::string& session_index, 44 const std::string& signin_scoped_device_id) { 45 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI)); 46 session_index_ = session_index; 47 signin_scoped_device_id_ = signin_scoped_device_id; 48 // Delay the verification if the network is not connected or on a captive 49 // portal. 50 const NetworkState* default_network = 51 NetworkHandler::Get()->network_state_handler()->DefaultNetwork(); 52 if (!default_network || 53 default_network->connection_state() == shill::kStatePortal) { 54 // If network is offline, defer the token fetching until online. 55 VLOG(1) << "Network is offline. Deferring OAuth2 token fetch."; 56 BrowserThread::PostDelayedTask( 57 BrowserThread::UI, 58 FROM_HERE, 59 base::Bind(&OAuth2TokenFetcher::StartExchangeFromCookies, 60 AsWeakPtr(), 61 session_index, 62 signin_scoped_device_id), 63 base::TimeDelta::FromMilliseconds(kRequestRestartDelay)); 64 return; 65 } 66 auth_fetcher_.StartCookieForOAuthLoginTokenExchangeWithDeviceId( 67 session_index, signin_scoped_device_id); 68} 69 70void OAuth2TokenFetcher::StartExchangeFromAuthCode( 71 const std::string& auth_code) { 72 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI)); 73 auth_code_ = auth_code; 74 // Delay the verification if the network is not connected or on a captive 75 // portal. 76 const NetworkState* default_network = 77 NetworkHandler::Get()->network_state_handler()->DefaultNetwork(); 78 if (!default_network || 79 default_network->connection_state() == shill::kStatePortal) { 80 // If network is offline, defer the token fetching until online. 81 VLOG(1) << "Network is offline. Deferring OAuth2 token fetch."; 82 BrowserThread::PostDelayedTask( 83 BrowserThread::UI, FROM_HERE, 84 base::Bind(&OAuth2TokenFetcher::StartExchangeFromAuthCode, 85 AsWeakPtr(), 86 auth_code), 87 base::TimeDelta::FromMilliseconds(kRequestRestartDelay)); 88 return; 89 } 90 auth_fetcher_.StartAuthCodeForOAuth2TokenExchange(auth_code); 91} 92 93void OAuth2TokenFetcher::OnClientOAuthSuccess( 94 const GaiaAuthConsumer::ClientOAuthResult& oauth_tokens) { 95 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI)); 96 VLOG(1) << "Got OAuth2 tokens!"; 97 retry_count_ = 0; 98 oauth_tokens_ = oauth_tokens; 99 delegate_->OnOAuth2TokensAvailable(oauth_tokens_); 100} 101 102void OAuth2TokenFetcher::OnClientOAuthFailure( 103 const GoogleServiceAuthError& error) { 104 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI)); 105 RetryOnError(error, 106 auth_code_.empty() 107 ? base::Bind(&OAuth2TokenFetcher::StartExchangeFromCookies, 108 AsWeakPtr(), 109 session_index_, 110 signin_scoped_device_id_) 111 : base::Bind(&OAuth2TokenFetcher::StartExchangeFromAuthCode, 112 AsWeakPtr(), 113 auth_code_), 114 base::Bind(&Delegate::OnOAuth2TokensFetchFailed, 115 base::Unretained(delegate_))); 116} 117 118void OAuth2TokenFetcher::RetryOnError(const GoogleServiceAuthError& error, 119 const base::Closure& task, 120 const base::Closure& error_handler) { 121 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI)); 122 if ((error.state() == GoogleServiceAuthError::CONNECTION_FAILED || 123 error.state() == GoogleServiceAuthError::SERVICE_UNAVAILABLE || 124 error.state() == GoogleServiceAuthError::REQUEST_CANCELED) && 125 retry_count_ < kMaxRequestAttemptCount) { 126 retry_count_++; 127 BrowserThread::PostDelayedTask( 128 BrowserThread::UI, FROM_HERE, task, 129 base::TimeDelta::FromMilliseconds(kRequestRestartDelay)); 130 return; 131 } 132 LOG(ERROR) << "Unrecoverable error or retry count max reached. State: " 133 << error.state() << ", network error: " << error.network_error() 134 << ", message: " << error.error_message(); 135 error_handler.Run(); 136} 137 138} // namespace chromeos 139