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