Home | History | Annotate | Download | only in signin
      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 
     17 using content::BrowserThread;
     18 
     19 namespace {
     20 
     21 // OAuth token request max retry count.
     22 const int kMaxRequestAttemptCount = 5;
     23 // OAuth token request retry delay in milliseconds.
     24 const int kRequestRestartDelay = 3000;
     25 
     26 }  // namespace
     27 
     28 namespace chromeos {
     29 
     30 OAuth2TokenFetcher::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 
     39 OAuth2TokenFetcher::~OAuth2TokenFetcher() {
     40 }
     41 
     42 void 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 
     70 void 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 
     93 void 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 
    102 void 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 
    118 void 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