1 // Copyright 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.
5 #include "google_apis/gaia/oauth2_token_service.h"
10 #include "base/memory/weak_ptr.h"
11 #include "base/message_loop/message_loop.h"
12 #include "base/rand_util.h"
13 #include "base/stl_util.h"
14 #include "base/time/time.h"
15 #include "base/timer/timer.h"
16 #include "google_apis/gaia/gaia_urls.h"
17 #include "google_apis/gaia/google_service_auth_error.h"
18 #include "net/url_request/url_request_context_getter.h"
20 int OAuth2TokenService::max_fetch_retry_num_ = 5;
22 OAuth2TokenService::RequestParameters::RequestParameters(
23 const std::string& client_id,
24 const std::string& account_id,
25 const ScopeSet& scopes)
26 : client_id(client_id),
27 account_id(account_id),
31 OAuth2TokenService::RequestParameters::~RequestParameters() {
34 bool OAuth2TokenService::RequestParameters::operator<(
35 const RequestParameters& p) const {
36 if (client_id < p.client_id)
38 else if (p.client_id < client_id)
41 if (account_id < p.account_id)
43 else if (p.account_id < account_id)
46 return scopes < p.scopes;
49 OAuth2TokenService::RequestImpl::RequestImpl(
50 OAuth2TokenService::Consumer* consumer)
51 : consumer_(consumer) {
54 OAuth2TokenService::RequestImpl::~RequestImpl() {
55 DCHECK(CalledOnValidThread());
58 void OAuth2TokenService::RequestImpl::InformConsumer(
59 const GoogleServiceAuthError& error,
60 const std::string& access_token,
61 const base::Time& expiration_date) {
62 DCHECK(CalledOnValidThread());
63 if (error.state() == GoogleServiceAuthError::NONE)
64 consumer_->OnGetTokenSuccess(this, access_token, expiration_date);
66 consumer_->OnGetTokenFailure(this, error);
69 // Class that fetches an OAuth2 access token for a given set of scopes and
70 // OAuth2 refresh token.
72 // Class that fetches OAuth2 access tokens for given scopes and refresh token.
74 // It aims to meet OAuth2TokenService's requirements on token fetching. Retry
75 // mechanism is used to handle failures.
77 // To use this class, call CreateAndStart() to create and start a Fetcher.
79 // The Fetcher will call back the service by calling
80 // OAuth2TokenService::OnFetchComplete() when it completes fetching, if it is
81 // not destructed before it completes fetching; if the Fetcher is destructed
82 // before it completes fetching, the service will never be called back. The
83 // Fetcher destructs itself after calling back the service when finishes
86 // Requests that are waiting for the fetching results of this Fetcher can be
87 // added to the Fetcher by calling
88 // OAuth2TokenService::Fetcher::AddWaitingRequest() before the Fetcher
89 // completes fetching.
91 // The waiting requests are taken as weak pointers and they can be deleted.
92 // The waiting requests will be called back with fetching results if they are
94 // - when the Fetcher completes fetching, if the Fetcher is not destructed
95 // before it completes fetching, or
96 // - when the Fetcher is destructed if the Fetcher is destructed before it
97 // completes fetching (in this case, the waiting requests will be called
99 class OAuth2TokenService::Fetcher : public OAuth2AccessTokenConsumer {
101 // Creates a Fetcher and starts fetching an OAuth2 access token for
102 // |refresh_token| and |scopes| in the request context obtained by |getter|.
103 // The given |oauth2_token_service| will be informed when fetching is done.
104 static Fetcher* CreateAndStart(OAuth2TokenService* oauth2_token_service,
105 const std::string& account_id,
106 net::URLRequestContextGetter* getter,
107 const std::string& client_id,
108 const std::string& client_secret,
109 const std::string& refresh_token,
110 const ScopeSet& scopes,
111 base::WeakPtr<RequestImpl> waiting_request);
114 // Add a request that is waiting for the result of this Fetcher.
115 void AddWaitingRequest(base::WeakPtr<RequestImpl> waiting_request);
117 // Returns count of waiting requests.
118 size_t GetWaitingRequestCount() const;
122 const ScopeSet& GetScopeSet() const;
123 const std::string& GetRefreshToken() const;
124 const std::string& GetClientId() const;
125 const std::string& GetAccountId() const;
127 // The error result from this fetcher.
128 const GoogleServiceAuthError& error() const { return error_; }
131 // OAuth2AccessTokenConsumer
132 virtual void OnGetTokenSuccess(const std::string& access_token,
133 const base::Time& expiration_date) OVERRIDE;
134 virtual void OnGetTokenFailure(
135 const GoogleServiceAuthError& error) OVERRIDE;
138 Fetcher(OAuth2TokenService* oauth2_token_service,
139 const std::string& account_id,
140 net::URLRequestContextGetter* getter,
141 const std::string& client_id,
142 const std::string& client_secret,
143 const std::string& refresh_token,
144 const OAuth2TokenService::ScopeSet& scopes,
145 base::WeakPtr<RequestImpl> waiting_request);
147 void InformWaitingRequests();
148 void InformWaitingRequestsAndDelete();
149 static bool ShouldRetry(const GoogleServiceAuthError& error);
150 int64 ComputeExponentialBackOffMilliseconds(int retry_num);
152 // |oauth2_token_service_| remains valid for the life of this Fetcher, since
153 // this Fetcher is destructed in the dtor of the OAuth2TokenService or is
154 // scheduled for deletion at the end of OnGetTokenFailure/OnGetTokenSuccess
155 // (whichever comes first).
156 OAuth2TokenService* const oauth2_token_service_;
157 scoped_refptr<net::URLRequestContextGetter> getter_;
158 const std::string account_id_;
159 const std::string refresh_token_;
160 const ScopeSet scopes_;
161 std::vector<base::WeakPtr<RequestImpl> > waiting_requests_;
164 base::OneShotTimer<Fetcher> retry_timer_;
165 scoped_ptr<OAuth2AccessTokenFetcher> fetcher_;
167 // Variables that store fetch results.
168 // Initialized to be GoogleServiceAuthError::SERVICE_UNAVAILABLE to handle
170 GoogleServiceAuthError error_;
171 std::string access_token_;
172 base::Time expiration_date_;
174 // OAuth2 client id and secret.
175 std::string client_id_;
176 std::string client_secret_;
178 DISALLOW_COPY_AND_ASSIGN(Fetcher);
182 OAuth2TokenService::Fetcher* OAuth2TokenService::Fetcher::CreateAndStart(
183 OAuth2TokenService* oauth2_token_service,
184 const std::string& account_id,
185 net::URLRequestContextGetter* getter,
186 const std::string& client_id,
187 const std::string& client_secret,
188 const std::string& refresh_token,
189 const OAuth2TokenService::ScopeSet& scopes,
190 base::WeakPtr<RequestImpl> waiting_request) {
191 OAuth2TokenService::Fetcher* fetcher = new Fetcher(
192 oauth2_token_service,
204 OAuth2TokenService::Fetcher::Fetcher(
205 OAuth2TokenService* oauth2_token_service,
206 const std::string& account_id,
207 net::URLRequestContextGetter* getter,
208 const std::string& client_id,
209 const std::string& client_secret,
210 const std::string& refresh_token,
211 const OAuth2TokenService::ScopeSet& scopes,
212 base::WeakPtr<RequestImpl> waiting_request)
213 : oauth2_token_service_(oauth2_token_service),
215 account_id_(account_id),
216 refresh_token_(refresh_token),
219 error_(GoogleServiceAuthError::SERVICE_UNAVAILABLE),
220 client_id_(client_id),
221 client_secret_(client_secret) {
222 DCHECK(oauth2_token_service_);
223 DCHECK(getter_.get());
224 DCHECK(refresh_token_.length());
225 waiting_requests_.push_back(waiting_request);
228 OAuth2TokenService::Fetcher::~Fetcher() {
229 // Inform the waiting requests if it has not done so.
230 if (waiting_requests_.size())
231 InformWaitingRequests();
234 void OAuth2TokenService::Fetcher::Start() {
235 fetcher_.reset(new OAuth2AccessTokenFetcher(this, getter_.get()));
236 fetcher_->Start(client_id_,
239 std::vector<std::string>(scopes_.begin(), scopes_.end()));
243 void OAuth2TokenService::Fetcher::OnGetTokenSuccess(
244 const std::string& access_token,
245 const base::Time& expiration_date) {
249 error_ = GoogleServiceAuthError::AuthErrorNone();
250 access_token_ = access_token;
251 expiration_date_ = expiration_date;
253 // Subclasses may override this method to skip caching in some cases, but
254 // we still inform all waiting Consumers of a successful token fetch below.
255 // This is intentional -- some consumers may need the token for cleanup
256 // tasks. https://chromiumcodereview.appspot.com/11312124/
257 oauth2_token_service_->RegisterCacheEntry(client_id_,
262 InformWaitingRequestsAndDelete();
265 void OAuth2TokenService::Fetcher::OnGetTokenFailure(
266 const GoogleServiceAuthError& error) {
269 if (ShouldRetry(error) && retry_number_ < max_fetch_retry_num_) {
270 int64 backoff = ComputeExponentialBackOffMilliseconds(retry_number_);
273 retry_timer_.Start(FROM_HERE,
274 base::TimeDelta::FromMilliseconds(backoff),
276 &OAuth2TokenService::Fetcher::Start);
281 InformWaitingRequestsAndDelete();
284 // Returns an exponential backoff in milliseconds including randomness less than
285 // 1000 ms when retrying fetching an OAuth2 access token.
286 int64 OAuth2TokenService::Fetcher::ComputeExponentialBackOffMilliseconds(
288 DCHECK(retry_num < max_fetch_retry_num_);
289 int64 exponential_backoff_in_seconds = 1 << retry_num;
290 // Returns a backoff with randomness < 1000ms
291 return (exponential_backoff_in_seconds + base::RandDouble()) * 1000;
295 bool OAuth2TokenService::Fetcher::ShouldRetry(
296 const GoogleServiceAuthError& error) {
297 GoogleServiceAuthError::State error_state = error.state();
298 return error_state == GoogleServiceAuthError::CONNECTION_FAILED ||
299 error_state == GoogleServiceAuthError::REQUEST_CANCELED ||
300 error_state == GoogleServiceAuthError::SERVICE_UNAVAILABLE;
303 void OAuth2TokenService::Fetcher::InformWaitingRequests() {
304 std::vector<base::WeakPtr<RequestImpl> >::const_iterator iter =
305 waiting_requests_.begin();
306 for (; iter != waiting_requests_.end(); ++iter) {
307 base::WeakPtr<RequestImpl> waiting_request = *iter;
308 if (waiting_request.get())
309 waiting_request->InformConsumer(error_, access_token_, expiration_date_);
311 waiting_requests_.clear();
314 void OAuth2TokenService::Fetcher::InformWaitingRequestsAndDelete() {
315 // Deregisters itself from the service to prevent more waiting requests to
316 // be added when it calls back the waiting requests.
317 oauth2_token_service_->OnFetchComplete(this);
318 InformWaitingRequests();
319 base::MessageLoop::current()->DeleteSoon(FROM_HERE, this);
322 void OAuth2TokenService::Fetcher::AddWaitingRequest(
323 base::WeakPtr<OAuth2TokenService::RequestImpl> waiting_request) {
324 waiting_requests_.push_back(waiting_request);
327 size_t OAuth2TokenService::Fetcher::GetWaitingRequestCount() const {
328 return waiting_requests_.size();
331 void OAuth2TokenService::Fetcher::Cancel() {
334 error_ = GoogleServiceAuthError(GoogleServiceAuthError::REQUEST_CANCELED);
335 InformWaitingRequestsAndDelete();
338 const OAuth2TokenService::ScopeSet& OAuth2TokenService::Fetcher::GetScopeSet()
343 const std::string& OAuth2TokenService::Fetcher::GetRefreshToken() const {
344 return refresh_token_;
347 const std::string& OAuth2TokenService::Fetcher::GetClientId() const {
351 const std::string& OAuth2TokenService::Fetcher::GetAccountId() const {
355 OAuth2TokenService::Request::Request() {
358 OAuth2TokenService::Request::~Request() {
361 OAuth2TokenService::Consumer::Consumer() {
364 OAuth2TokenService::Consumer::~Consumer() {
367 OAuth2TokenService::OAuth2TokenService() {
370 OAuth2TokenService::~OAuth2TokenService() {
371 // Release all the pending fetchers.
372 STLDeleteContainerPairSecondPointers(
373 pending_fetchers_.begin(), pending_fetchers_.end());
376 void OAuth2TokenService::AddObserver(Observer* observer) {
377 observer_list_.AddObserver(observer);
380 void OAuth2TokenService::RemoveObserver(Observer* observer) {
381 observer_list_.RemoveObserver(observer);
384 bool OAuth2TokenService::RefreshTokenIsAvailable(
385 const std::string& account_id) {
386 DCHECK(CalledOnValidThread());
387 return !GetRefreshToken(account_id).empty();
390 std::vector<std::string> OAuth2TokenService::GetAccounts() {
391 return std::vector<std::string>();
394 scoped_ptr<OAuth2TokenService::Request> OAuth2TokenService::StartRequest(
395 const std::string& account_id,
396 const OAuth2TokenService::ScopeSet& scopes,
397 OAuth2TokenService::Consumer* consumer) {
398 return StartRequestForClientWithContext(
401 GaiaUrls::GetInstance()->oauth2_chrome_client_id(),
402 GaiaUrls::GetInstance()->oauth2_chrome_client_secret(),
407 scoped_ptr<OAuth2TokenService::Request>
408 OAuth2TokenService::StartRequestForClient(
409 const std::string& account_id,
410 const std::string& client_id,
411 const std::string& client_secret,
412 const OAuth2TokenService::ScopeSet& scopes,
413 OAuth2TokenService::Consumer* consumer) {
414 return StartRequestForClientWithContext(
423 scoped_ptr<OAuth2TokenService::Request>
424 OAuth2TokenService::StartRequestWithContext(
425 const std::string& account_id,
426 net::URLRequestContextGetter* getter,
427 const ScopeSet& scopes,
428 Consumer* consumer) {
429 return StartRequestForClientWithContext(
432 GaiaUrls::GetInstance()->oauth2_chrome_client_id(),
433 GaiaUrls::GetInstance()->oauth2_chrome_client_secret(),
438 scoped_ptr<OAuth2TokenService::Request>
439 OAuth2TokenService::StartRequestForClientWithContext(
440 const std::string& account_id,
441 net::URLRequestContextGetter* getter,
442 const std::string& client_id,
443 const std::string& client_secret,
444 const ScopeSet& scopes,
445 Consumer* consumer) {
446 DCHECK(CalledOnValidThread());
448 scoped_ptr<RequestImpl> request = CreateRequest(consumer);
450 if (!RefreshTokenIsAvailable(account_id)) {
451 base::MessageLoop::current()->PostTask(FROM_HERE, base::Bind(
452 &RequestImpl::InformConsumer,
453 request->AsWeakPtr(),
454 GoogleServiceAuthError(GoogleServiceAuthError::USER_NOT_SIGNED_UP),
457 return request.PassAs<Request>();
460 RequestParameters request_parameters(client_id,
463 if (HasCacheEntry(request_parameters)) {
464 StartCacheLookupRequest(request.get(), request_parameters, consumer);
466 FetchOAuth2Token(request.get(),
473 return request.PassAs<Request>();
476 scoped_ptr<OAuth2TokenService::RequestImpl> OAuth2TokenService::CreateRequest(
477 Consumer* consumer) {
478 return scoped_ptr<RequestImpl>(new RequestImpl(consumer));
481 void OAuth2TokenService::FetchOAuth2Token(RequestImpl* request,
482 const std::string& account_id,
483 net::URLRequestContextGetter* getter,
484 const std::string& client_id,
485 const std::string& client_secret,
486 const ScopeSet& scopes) {
487 std::string refresh_token = GetRefreshToken(account_id);
489 // If there is already a pending fetcher for |scopes| and |account_id|,
490 // simply register this |request| for those results rather than starting
492 RequestParameters request_parameters = RequestParameters(client_id,
495 std::map<RequestParameters, Fetcher*>::iterator iter =
496 pending_fetchers_.find(request_parameters);
497 if (iter != pending_fetchers_.end()) {
498 iter->second->AddWaitingRequest(request->AsWeakPtr());
502 pending_fetchers_[request_parameters] =
503 Fetcher::CreateAndStart(this,
510 request->AsWeakPtr());
513 void OAuth2TokenService::StartCacheLookupRequest(
514 RequestImpl* request,
515 const OAuth2TokenService::RequestParameters& request_parameters,
516 OAuth2TokenService::Consumer* consumer) {
517 CHECK(HasCacheEntry(request_parameters));
518 const CacheEntry* cache_entry = GetCacheEntry(request_parameters);
519 base::MessageLoop::current()->PostTask(FROM_HERE, base::Bind(
520 &RequestImpl::InformConsumer,
521 request->AsWeakPtr(),
522 GoogleServiceAuthError(GoogleServiceAuthError::NONE),
523 cache_entry->access_token,
524 cache_entry->expiration_date));
527 void OAuth2TokenService::InvalidateToken(const std::string& account_id,
528 const ScopeSet& scopes,
529 const std::string& access_token) {
530 InvalidateOAuth2Token(account_id,
531 GaiaUrls::GetInstance()->oauth2_chrome_client_id(),
536 void OAuth2TokenService::InvalidateTokenForClient(
537 const std::string& account_id,
538 const std::string& client_id,
539 const ScopeSet& scopes,
540 const std::string& access_token) {
541 InvalidateOAuth2Token(account_id, client_id, scopes, access_token);
544 void OAuth2TokenService::InvalidateOAuth2Token(
545 const std::string& account_id,
546 const std::string& client_id,
547 const ScopeSet& scopes,
548 const std::string& access_token) {
549 DCHECK(CalledOnValidThread());
551 RequestParameters(client_id,
557 void OAuth2TokenService::OnFetchComplete(Fetcher* fetcher) {
558 DCHECK(CalledOnValidThread());
560 // Update the auth error state so auth errors are appropriately communicated
562 UpdateAuthError(fetcher->GetAccountId(), fetcher->error());
564 // Note |fetcher| is recorded in |pending_fetcher_| mapped to its refresh
565 // token and scope set. This is guaranteed as follows; here a Fetcher is said
566 // to be uncompleted if it has not finished calling back
567 // OAuth2TokenService::OnFetchComplete().
569 // (1) All the live Fetchers are created by this service.
570 // This is because (1) all the live Fetchers are created by a live
571 // service, as all the fetchers created by a service are destructed in the
574 // (2) All the uncompleted Fetchers created by this service are recorded in
575 // |pending_fetchers_|.
576 // This is because (1) all the created Fetchers are added to
577 // |pending_fetchers_| (in method StartRequest()) and (2) method
578 // OnFetchComplete() is the only place where a Fetcher is erased from
579 // |pending_fetchers_|. Note no Fetcher is erased in method
582 // (3) Each of the Fetchers recorded in |pending_fetchers_| is mapped to its
583 // refresh token and ScopeSet. This is guaranteed by Fetcher creation in
584 // method StartRequest().
586 // When this method is called, |fetcher| is alive and uncompleted.
587 // By (1), |fetcher| is created by this service.
588 // Then by (2), |fetcher| is recorded in |pending_fetchers_|.
589 // Then by (3), |fetcher_| is mapped to its refresh token and ScopeSet.
590 std::map<RequestParameters, Fetcher*>::iterator iter =
591 pending_fetchers_.find(RequestParameters(
592 fetcher->GetClientId(),
593 fetcher->GetAccountId(),
594 fetcher->GetScopeSet()));
595 DCHECK(iter != pending_fetchers_.end());
596 DCHECK_EQ(fetcher, iter->second);
597 pending_fetchers_.erase(iter);
600 bool OAuth2TokenService::HasCacheEntry(
601 const RequestParameters& request_parameters) {
602 const CacheEntry* cache_entry = GetCacheEntry(request_parameters);
603 return cache_entry && cache_entry->access_token.length();
606 const OAuth2TokenService::CacheEntry* OAuth2TokenService::GetCacheEntry(
607 const RequestParameters& request_parameters) {
608 DCHECK(CalledOnValidThread());
609 TokenCache::iterator token_iterator = token_cache_.find(request_parameters);
610 if (token_iterator == token_cache_.end())
612 if (token_iterator->second.expiration_date <= base::Time::Now()) {
613 token_cache_.erase(token_iterator);
616 return &token_iterator->second;
619 bool OAuth2TokenService::RemoveCacheEntry(
620 const RequestParameters& request_parameters,
621 const std::string& token_to_remove) {
622 DCHECK(CalledOnValidThread());
623 TokenCache::iterator token_iterator = token_cache_.find(request_parameters);
624 if (token_iterator != token_cache_.end() &&
625 token_iterator->second.access_token == token_to_remove) {
626 token_cache_.erase(token_iterator);
632 void OAuth2TokenService::RegisterCacheEntry(
633 const std::string& client_id,
634 const std::string& account_id,
635 const OAuth2TokenService::ScopeSet& scopes,
636 const std::string& access_token,
637 const base::Time& expiration_date) {
638 DCHECK(CalledOnValidThread());
640 CacheEntry& token = token_cache_[RequestParameters(client_id,
643 token.access_token = access_token;
644 token.expiration_date = expiration_date;
647 void OAuth2TokenService::UpdateAuthError(
648 const std::string& account_id,
649 const GoogleServiceAuthError& error) {
650 // Default implementation does nothing.
653 void OAuth2TokenService::ClearCache() {
654 DCHECK(CalledOnValidThread());
655 token_cache_.clear();
658 void OAuth2TokenService::ClearCacheForAccount(const std::string& account_id) {
659 DCHECK(CalledOnValidThread());
660 for (TokenCache::iterator iter = token_cache_.begin();
661 iter != token_cache_.end();
662 /* iter incremented in body */) {
663 if (iter->first.account_id == account_id) {
664 token_cache_.erase(iter++);
671 void OAuth2TokenService::CancelAllRequests() {
672 std::vector<Fetcher*> fetchers_to_cancel;
673 for (std::map<RequestParameters, Fetcher*>::iterator iter =
674 pending_fetchers_.begin();
675 iter != pending_fetchers_.end();
677 fetchers_to_cancel.push_back(iter->second);
679 CancelFetchers(fetchers_to_cancel);
682 void OAuth2TokenService::CancelRequestsForAccount(
683 const std::string& account_id) {
684 std::vector<Fetcher*> fetchers_to_cancel;
685 for (std::map<RequestParameters, Fetcher*>::iterator iter =
686 pending_fetchers_.begin();
687 iter != pending_fetchers_.end();
689 if (iter->first.account_id == account_id)
690 fetchers_to_cancel.push_back(iter->second);
692 CancelFetchers(fetchers_to_cancel);
695 void OAuth2TokenService::CancelFetchers(
696 std::vector<Fetcher*> fetchers_to_cancel) {
697 for (std::vector<OAuth2TokenService::Fetcher*>::iterator iter =
698 fetchers_to_cancel.begin();
699 iter != fetchers_to_cancel.end();
705 void OAuth2TokenService::FireRefreshTokenAvailable(
706 const std::string& account_id) {
707 FOR_EACH_OBSERVER(Observer, observer_list_,
708 OnRefreshTokenAvailable(account_id));
711 void OAuth2TokenService::FireRefreshTokenRevoked(
712 const std::string& account_id) {
713 FOR_EACH_OBSERVER(Observer, observer_list_,
714 OnRefreshTokenRevoked(account_id));
717 void OAuth2TokenService::FireRefreshTokensLoaded() {
718 FOR_EACH_OBSERVER(Observer, observer_list_, OnRefreshTokensLoaded());
721 int OAuth2TokenService::cache_size_for_testing() const {
722 return token_cache_.size();
725 void OAuth2TokenService::set_max_authorization_token_fetch_retries_for_testing(
727 DCHECK(CalledOnValidThread());
728 max_fetch_retry_num_ = max_retries;
731 size_t OAuth2TokenService::GetNumPendingRequestsForTesting(
732 const std::string& client_id,
733 const std::string& account_id,
734 const ScopeSet& scopes) const {
735 PendingFetcherMap::const_iterator iter = pending_fetchers_.find(
736 OAuth2TokenService::RequestParameters(
740 return iter == pending_fetchers_.end() ?
741 0 : iter->second->GetWaitingRequestCount();