15d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)// Copyright 2014 The Chromium Authors. All rights reserved. 25821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// Use of this source code is governed by a BSD-style license that can be 35821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// found in the LICENSE file. 45821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 55d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)#include "google_apis/gaia/ubertoken_fetcher.h" 6eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch 7eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch#include <vector> 8eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch 95821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "base/logging.h" 101320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci#include "base/rand_util.h" 111320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci#include "base/time/time.h" 1258e6fbe4ee35d65e14b626c557d37565bf8ad179Ben Murdoch#include "google_apis/gaia/gaia_auth_fetcher.h" 135821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "google_apis/gaia/gaia_constants.h" 145821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "google_apis/gaia/google_service_auth_error.h" 155d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)#include "google_apis/gaia/oauth2_token_service.h" 165821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 171320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucciconst int UbertokenFetcher::kMaxRetries = 3; 181320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci 195d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)UbertokenFetcher::UbertokenFetcher( 205d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) OAuth2TokenService* token_service, 215d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) UbertokenConsumer* consumer, 225d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) net::URLRequestContextGetter* request_context) 235d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) : OAuth2TokenService::Consumer("uber_token_fetcher"), 245d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) token_service_(token_service), 255d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) consumer_(consumer), 261320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci request_context_(request_context), 271320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci retry_number_(0), 281320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci second_access_token_request_(false) { 295d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) DCHECK(token_service); 305821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) DCHECK(consumer); 315d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) DCHECK(request_context); 325821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)} 335821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 345821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)UbertokenFetcher::~UbertokenFetcher() { 355821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)} 365821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 371e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles)void UbertokenFetcher::StartFetchingToken(const std::string& account_id) { 381320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci DCHECK(!account_id.empty()); 391320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci account_id_ = account_id; 401320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci second_access_token_request_ = false; 411320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci RequestAccessToken(); 425821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)} 435821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 4458e6fbe4ee35d65e14b626c557d37565bf8ad179Ben Murdochvoid UbertokenFetcher::OnUberAuthTokenSuccess(const std::string& token) { 4558e6fbe4ee35d65e14b626c557d37565bf8ad179Ben Murdoch consumer_->OnUbertokenSuccess(token); 465821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)} 475821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 4858e6fbe4ee35d65e14b626c557d37565bf8ad179Ben Murdochvoid UbertokenFetcher::OnUberAuthTokenFailure( 4958e6fbe4ee35d65e14b626c557d37565bf8ad179Ben Murdoch const GoogleServiceAuthError& error) { 501320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci // Retry only transient errors. 511320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci bool should_retry = 521320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci error.state() == GoogleServiceAuthError::CONNECTION_FAILED || 531320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci error.state() == GoogleServiceAuthError::SERVICE_UNAVAILABLE; 541320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci if (should_retry) { 551320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci if (retry_number_ < kMaxRetries) { 561320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci // Calculate an exponential backoff with randomness of less than 1 sec. 571320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci double backoff = base::RandDouble() + (1 << retry_number_); 581320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci ++retry_number_; 591320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci retry_timer_.Stop(); 601320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci retry_timer_.Start(FROM_HERE, 611320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci base::TimeDelta::FromSecondsD(backoff), 621320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci this, 631320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci &UbertokenFetcher::ExchangeTokens); 641320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci return; 651320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci } 661320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci } else { 671320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci // The access token is invalid. Tell the token service. 681320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci OAuth2TokenService::ScopeSet scopes; 691320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci scopes.insert(GaiaConstants::kOAuth1LoginScope); 701320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci token_service_->InvalidateToken(account_id_, scopes, access_token_); 711320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci 721320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci // In case the access was just stale, try one more time. 731320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci if (!second_access_token_request_) { 741320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci second_access_token_request_ = true; 751320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci RequestAccessToken(); 761320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci return; 771320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci } 781320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci } 791320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci 8058e6fbe4ee35d65e14b626c557d37565bf8ad179Ben Murdoch consumer_->OnUbertokenFailure(error); 815821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)} 825821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 8358e6fbe4ee35d65e14b626c557d37565bf8ad179Ben Murdochvoid UbertokenFetcher::OnGetTokenSuccess( 8458e6fbe4ee35d65e14b626c557d37565bf8ad179Ben Murdoch const OAuth2TokenService::Request* request, 8558e6fbe4ee35d65e14b626c557d37565bf8ad179Ben Murdoch const std::string& access_token, 8658e6fbe4ee35d65e14b626c557d37565bf8ad179Ben Murdoch const base::Time& expiration_time) { 871320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci DCHECK(!access_token.empty()); 881320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci access_token_ = access_token; 8958e6fbe4ee35d65e14b626c557d37565bf8ad179Ben Murdoch access_token_request_.reset(); 901320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci ExchangeTokens(); 915821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)} 925821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 9358e6fbe4ee35d65e14b626c557d37565bf8ad179Ben Murdochvoid UbertokenFetcher::OnGetTokenFailure( 9458e6fbe4ee35d65e14b626c557d37565bf8ad179Ben Murdoch const OAuth2TokenService::Request* request, 955821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) const GoogleServiceAuthError& error) { 9658e6fbe4ee35d65e14b626c557d37565bf8ad179Ben Murdoch access_token_request_.reset(); 975821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) consumer_->OnUbertokenFailure(error); 985821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)} 991320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci 1001320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tuccivoid UbertokenFetcher::RequestAccessToken() { 1011320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci retry_number_ = 0; 1021320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci gaia_auth_fetcher_.reset(); 1031320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci retry_timer_.Stop(); 1041320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci 1051320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci OAuth2TokenService::ScopeSet scopes; 1061320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci scopes.insert(GaiaConstants::kOAuth1LoginScope); 1071320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci access_token_request_ = 1081320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci token_service_->StartRequest(account_id_, scopes, this); 1091320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci} 1101320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci 1111320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tuccivoid UbertokenFetcher::ExchangeTokens() { 1121320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci gaia_auth_fetcher_.reset(new GaiaAuthFetcher(this, 1131320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci GaiaConstants::kChromeSource, 1141320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci request_context_)); 1151320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci gaia_auth_fetcher_->StartTokenFetchForUberAuthExchange(access_token_); 1161320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci} 117