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.
5 #include "google_apis/gaia/ubertoken_fetcher.h"
9 #include "base/logging.h"
10 #include "base/metrics/histogram_macros.h"
11 #include "base/rand_util.h"
12 #include "base/time/time.h"
13 #include "google_apis/gaia/gaia_auth_fetcher.h"
14 #include "google_apis/gaia/gaia_constants.h"
15 #include "google_apis/gaia/google_service_auth_error.h"
16 #include "google_apis/gaia/oauth2_token_service.h"
19 GaiaAuthFetcher
* CreateGaiaAuthFetcher(
20 GaiaAuthConsumer
* consumer
,
21 const std::string
& source
,
22 net::URLRequestContextGetter
* request_context
) {
23 return new GaiaAuthFetcher(consumer
, source
, request_context
);
27 const int UbertokenFetcher::kMaxRetries
= 3;
29 UbertokenFetcher::UbertokenFetcher(
30 OAuth2TokenService
* token_service
,
31 UbertokenConsumer
* consumer
,
32 const std::string
& source
,
33 net::URLRequestContextGetter
* request_context
)
34 : UbertokenFetcher(token_service
,
38 base::Bind(CreateGaiaAuthFetcher
)) {
41 UbertokenFetcher::UbertokenFetcher(
42 OAuth2TokenService
* token_service
,
43 UbertokenConsumer
* consumer
,
44 const std::string
& source
,
45 net::URLRequestContextGetter
* request_context
,
46 GaiaAuthFetcherFactory factory
)
47 : OAuth2TokenService::Consumer("uber_token_fetcher"),
48 token_service_(token_service
),
51 request_context_(request_context
),
52 gaia_auth_fetcher_factory_(factory
),
54 second_access_token_request_(false) {
55 DCHECK(token_service
);
57 DCHECK(request_context
);
60 UbertokenFetcher::~UbertokenFetcher() {
63 void UbertokenFetcher::StartFetchingToken(const std::string
& account_id
) {
64 DCHECK(!account_id
.empty());
65 account_id_
= account_id
;
66 second_access_token_request_
= false;
70 void UbertokenFetcher::StartFetchingTokenWithAccessToken(
71 const std::string
& account_id
, const std::string
& access_token
) {
72 DCHECK(!account_id
.empty());
73 DCHECK(!access_token
.empty());
75 account_id_
= account_id
;
76 access_token_
= access_token
;
80 void UbertokenFetcher::OnUberAuthTokenSuccess(const std::string
& token
) {
81 consumer_
->OnUbertokenSuccess(token
);
84 void UbertokenFetcher::OnUberAuthTokenFailure(
85 const GoogleServiceAuthError
& error
) {
86 // Retry only transient errors.
88 error
.state() == GoogleServiceAuthError::CONNECTION_FAILED
||
89 error
.state() == GoogleServiceAuthError::SERVICE_UNAVAILABLE
;
91 if (retry_number_
< kMaxRetries
) {
92 // Calculate an exponential backoff with randomness of less than 1 sec.
93 double backoff
= base::RandDouble() + (1 << retry_number_
);
95 UMA_HISTOGRAM_ENUMERATION("Signin.UberTokenRetry",
96 error
.state(), GoogleServiceAuthError::NUM_STATES
);
98 retry_timer_
.Start(FROM_HERE
,
99 base::TimeDelta::FromSecondsD(backoff
),
101 &UbertokenFetcher::ExchangeTokens
);
105 // The access token is invalid. Tell the token service.
106 OAuth2TokenService::ScopeSet scopes
;
107 scopes
.insert(GaiaConstants::kOAuth1LoginScope
);
108 token_service_
->InvalidateAccessToken(account_id_
, scopes
, access_token_
);
110 // In case the access was just stale, try one more time.
111 if (!second_access_token_request_
) {
112 second_access_token_request_
= true;
113 RequestAccessToken();
118 UMA_HISTOGRAM_ENUMERATION("Signin.UberTokenFailure",
119 error
.state(), GoogleServiceAuthError::NUM_STATES
);
120 consumer_
->OnUbertokenFailure(error
);
123 void UbertokenFetcher::OnGetTokenSuccess(
124 const OAuth2TokenService::Request
* request
,
125 const std::string
& access_token
,
126 const base::Time
& expiration_time
) {
127 DCHECK(!access_token
.empty());
128 access_token_
= access_token
;
129 access_token_request_
.reset();
133 void UbertokenFetcher::OnGetTokenFailure(
134 const OAuth2TokenService::Request
* request
,
135 const GoogleServiceAuthError
& error
) {
136 access_token_request_
.reset();
137 consumer_
->OnUbertokenFailure(error
);
140 void UbertokenFetcher::RequestAccessToken() {
142 gaia_auth_fetcher_
.reset();
145 OAuth2TokenService::ScopeSet scopes
;
146 scopes
.insert(GaiaConstants::kOAuth1LoginScope
);
147 access_token_request_
=
148 token_service_
->StartRequest(account_id_
, scopes
, this);
151 void UbertokenFetcher::ExchangeTokens() {
152 gaia_auth_fetcher_
.reset(
153 gaia_auth_fetcher_factory_
.Run(this, source_
, request_context_
));
154 gaia_auth_fetcher_
->StartTokenFetchForUberAuthExchange(access_token_
);