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   DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
     45   session_index_ = session_index;
     46   // Delay the verification if the network is not connected or on a captive
     47   // portal.
     48   const NetworkState* default_network =
     49       NetworkHandler::Get()->network_state_handler()->DefaultNetwork();
     50   if (!default_network ||
     51       default_network->connection_state() == shill::kStatePortal) {
     52     // If network is offline, defer the token fetching until online.
     53     VLOG(1) << "Network is offline.  Deferring OAuth2 token fetch.";
     54     BrowserThread::PostDelayedTask(
     55         BrowserThread::UI,
     56         FROM_HERE,
     57         base::Bind(&OAuth2TokenFetcher::StartExchangeFromCookies,
     58                    AsWeakPtr(),
     59                    session_index),
     60         base::TimeDelta::FromMilliseconds(kRequestRestartDelay));
     61     return;
     62   }
     63   auth_fetcher_.StartCookieForOAuthLoginTokenExchange(session_index);
     64 }
     65 
     66 void OAuth2TokenFetcher::StartExchangeFromAuthCode(
     67     const std::string& auth_code) {
     68   DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
     69   auth_code_ = auth_code;
     70   // Delay the verification if the network is not connected or on a captive
     71   // portal.
     72   const NetworkState* default_network =
     73       NetworkHandler::Get()->network_state_handler()->DefaultNetwork();
     74   if (!default_network ||
     75       default_network->connection_state() == shill::kStatePortal) {
     76     // If network is offline, defer the token fetching until online.
     77     VLOG(1) << "Network is offline.  Deferring OAuth2 token fetch.";
     78     BrowserThread::PostDelayedTask(
     79         BrowserThread::UI, FROM_HERE,
     80         base::Bind(&OAuth2TokenFetcher::StartExchangeFromAuthCode,
     81                    AsWeakPtr(),
     82                    auth_code),
     83         base::TimeDelta::FromMilliseconds(kRequestRestartDelay));
     84     return;
     85   }
     86   auth_fetcher_.StartAuthCodeForOAuth2TokenExchange(auth_code);
     87 }
     88 
     89 void OAuth2TokenFetcher::OnClientOAuthSuccess(
     90     const GaiaAuthConsumer::ClientOAuthResult& oauth_tokens) {
     91   DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
     92   VLOG(1) << "Got OAuth2 tokens!";
     93   retry_count_ = 0;
     94   oauth_tokens_ = oauth_tokens;
     95   delegate_->OnOAuth2TokensAvailable(oauth_tokens_);
     96 }
     97 
     98 void OAuth2TokenFetcher::OnClientOAuthFailure(
     99     const GoogleServiceAuthError& error) {
    100   DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
    101   RetryOnError(error,
    102                auth_code_.empty()
    103                    ? base::Bind(&OAuth2TokenFetcher::StartExchangeFromCookies,
    104                                 AsWeakPtr(),
    105                                 session_index_)
    106                    : base::Bind(&OAuth2TokenFetcher::StartExchangeFromAuthCode,
    107                                 AsWeakPtr(),
    108                                 auth_code_),
    109                base::Bind(&Delegate::OnOAuth2TokensFetchFailed,
    110                           base::Unretained(delegate_)));
    111 }
    112 
    113 void OAuth2TokenFetcher::RetryOnError(const GoogleServiceAuthError& error,
    114                                       const base::Closure& task,
    115                                       const base::Closure& error_handler) {
    116   DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
    117   if ((error.state() == GoogleServiceAuthError::CONNECTION_FAILED ||
    118        error.state() == GoogleServiceAuthError::SERVICE_UNAVAILABLE ||
    119        error.state() == GoogleServiceAuthError::REQUEST_CANCELED) &&
    120       retry_count_ < kMaxRequestAttemptCount) {
    121     retry_count_++;
    122     BrowserThread::PostDelayedTask(
    123         BrowserThread::UI, FROM_HERE, task,
    124         base::TimeDelta::FromMilliseconds(kRequestRestartDelay));
    125     return;
    126   }
    127   LOG(ERROR) << "Unrecoverable error or retry count max reached. State: "
    128              << error.state() << ", network error: " << error.network_error()
    129              << ", message: " << error.error_message();
    130   error_handler.Run();
    131 }
    132 
    133 }  // namespace chromeos
    134