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