Home | History | Annotate | Download | only in gaia
      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 "google_apis/gaia/ubertoken_fetcher.h"
      6 
      7 #include <vector>
      8 
      9 #include "base/logging.h"
     10 #include "base/rand_util.h"
     11 #include "base/time/time.h"
     12 #include "google_apis/gaia/gaia_auth_fetcher.h"
     13 #include "google_apis/gaia/gaia_constants.h"
     14 #include "google_apis/gaia/google_service_auth_error.h"
     15 #include "google_apis/gaia/oauth2_token_service.h"
     16 
     17 const int UbertokenFetcher::kMaxRetries = 3;
     18 
     19 UbertokenFetcher::UbertokenFetcher(
     20     OAuth2TokenService* token_service,
     21     UbertokenConsumer* consumer,
     22     net::URLRequestContextGetter* request_context)
     23     : OAuth2TokenService::Consumer("uber_token_fetcher"),
     24       token_service_(token_service),
     25       consumer_(consumer),
     26       request_context_(request_context),
     27       retry_number_(0),
     28       second_access_token_request_(false) {
     29   DCHECK(token_service);
     30   DCHECK(consumer);
     31   DCHECK(request_context);
     32 }
     33 
     34 UbertokenFetcher::~UbertokenFetcher() {
     35 }
     36 
     37 void UbertokenFetcher::StartFetchingToken(const std::string& account_id) {
     38   DCHECK(!account_id.empty());
     39   account_id_ = account_id;
     40   second_access_token_request_ = false;
     41   RequestAccessToken();
     42 }
     43 
     44 void UbertokenFetcher::OnUberAuthTokenSuccess(const std::string& token) {
     45   consumer_->OnUbertokenSuccess(token);
     46 }
     47 
     48 void UbertokenFetcher::OnUberAuthTokenFailure(
     49     const GoogleServiceAuthError& error) {
     50   // Retry only transient errors.
     51   bool should_retry =
     52       error.state() == GoogleServiceAuthError::CONNECTION_FAILED ||
     53       error.state() == GoogleServiceAuthError::SERVICE_UNAVAILABLE;
     54   if (should_retry) {
     55     if (retry_number_ < kMaxRetries) {
     56       // Calculate an exponential backoff with randomness of less than 1 sec.
     57       double backoff = base::RandDouble() + (1 << retry_number_);
     58       ++retry_number_;
     59       retry_timer_.Stop();
     60       retry_timer_.Start(FROM_HERE,
     61                          base::TimeDelta::FromSecondsD(backoff),
     62                          this,
     63                          &UbertokenFetcher::ExchangeTokens);
     64       return;
     65     }
     66   } else {
     67     // The access token is invalid.  Tell the token service.
     68     OAuth2TokenService::ScopeSet scopes;
     69     scopes.insert(GaiaConstants::kOAuth1LoginScope);
     70     token_service_->InvalidateToken(account_id_, scopes, access_token_);
     71 
     72     // In case the access was just stale, try one more time.
     73     if (!second_access_token_request_) {
     74       second_access_token_request_ = true;
     75       RequestAccessToken();
     76       return;
     77     }
     78   }
     79 
     80   consumer_->OnUbertokenFailure(error);
     81 }
     82 
     83 void UbertokenFetcher::OnGetTokenSuccess(
     84     const OAuth2TokenService::Request* request,
     85     const std::string& access_token,
     86     const base::Time& expiration_time) {
     87   DCHECK(!access_token.empty());
     88   access_token_ = access_token;
     89   access_token_request_.reset();
     90   ExchangeTokens();
     91 }
     92 
     93 void UbertokenFetcher::OnGetTokenFailure(
     94     const OAuth2TokenService::Request* request,
     95     const GoogleServiceAuthError& error) {
     96   access_token_request_.reset();
     97   consumer_->OnUbertokenFailure(error);
     98 }
     99 
    100 void UbertokenFetcher::RequestAccessToken() {
    101   retry_number_ = 0;
    102   gaia_auth_fetcher_.reset();
    103   retry_timer_.Stop();
    104 
    105   OAuth2TokenService::ScopeSet scopes;
    106   scopes.insert(GaiaConstants::kOAuth1LoginScope);
    107   access_token_request_ =
    108       token_service_->StartRequest(account_id_, scopes, this);
    109 }
    110 
    111 void UbertokenFetcher::ExchangeTokens() {
    112   gaia_auth_fetcher_.reset(new GaiaAuthFetcher(this,
    113                                                GaiaConstants::kChromeSource,
    114                                                request_context_));
    115   gaia_auth_fetcher_->StartTokenFetchForUberAuthExchange(access_token_);
    116 }
    117