summaryrefslogtreecommitdiffstats
path: root/chrome/browser/signin
diff options
context:
space:
mode:
authordavidroche@chromium.org <davidroche@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98>2013-04-18 06:02:18 +0000
committerdavidroche@chromium.org <davidroche@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98>2013-04-18 06:02:18 +0000
commita28c45a97e2ae3e1d11f9b1b6ba1716c6b99302c (patch)
treebc21fb3353deb9c81f4715707fbee6aa58e67840 /chrome/browser/signin
parent29a093b64c932d9b7a61bab0906fe208de0e27c6 (diff)
downloadchromium_src-a28c45a97e2ae3e1d11f9b1b6ba1716c6b99302c.zip
chromium_src-a28c45a97e2ae3e1d11f9b1b6ba1716c6b99302c.tar.gz
chromium_src-a28c45a97e2ae3e1d11f9b1b6ba1716c6b99302c.tar.bz2
Refactor OAuth2TokenService to have profile- and device-based implementations.
OAuth2TokenService was refactored into an abstract base class without dependencies on Profile and the TokenService's OAuth2 login refresh token. Added ProfileOAuth2TokenService as an implementation of OAuth2TokenService that requires a Profile and the user's login refresh token from TokenService. Migrated the existing OAuth2TokenServiceFactory and OAuth2TokenServiceRequest to Profile* varients that use this new class. Added DeviceOAuth2TokenService that serves up API access tokens for enterprise enrolled devices (via a robot account with an any-api refresh token). These tokens are global to all accounts on the device including Public Accounts, and hence don't depend on a particular profile's login credentials. BUG=164606 Review URL: https://chromiumcodereview.appspot.com/12647008 git-svn-id: svn://svn.chromium.org/chrome/trunk/src@194796 0039d316-1c4b-4281-b951-d872f2087c98
Diffstat (limited to 'chrome/browser/signin')
-rw-r--r--chrome/browser/signin/android_profile_oauth2_token_service.cc62
-rw-r--r--chrome/browser/signin/android_profile_oauth2_token_service.h51
-rw-r--r--chrome/browser/signin/oauth2_token_service.cc260
-rw-r--r--chrome/browser/signin/oauth2_token_service.h160
-rw-r--r--chrome/browser/signin/oauth2_token_service_factory.cc38
-rw-r--r--chrome/browser/signin/oauth2_token_service_factory.h40
-rw-r--r--chrome/browser/signin/oauth2_token_service_request.h51
-rw-r--r--chrome/browser/signin/oauth2_token_service_test_util.cc40
-rw-r--r--chrome/browser/signin/oauth2_token_service_test_util.h38
-rw-r--r--chrome/browser/signin/oauth2_token_service_unittest.cc270
-rw-r--r--chrome/browser/signin/profile_oauth2_token_service.cc131
-rw-r--r--chrome/browser/signin/profile_oauth2_token_service.h101
-rw-r--r--chrome/browser/signin/profile_oauth2_token_service_factory.cc50
-rw-r--r--chrome/browser/signin/profile_oauth2_token_service_factory.h42
-rw-r--r--chrome/browser/signin/profile_oauth2_token_service_request.cc (renamed from chrome/browser/signin/oauth2_token_service_request.cc)72
-rw-r--r--chrome/browser/signin/profile_oauth2_token_service_request.h47
-rw-r--r--chrome/browser/signin/profile_oauth2_token_service_request_unittest.cc (renamed from chrome/browser/signin/oauth2_token_service_request_unittest.cc)99
-rw-r--r--chrome/browser/signin/profile_oauth2_token_service_unittest.cc97
-rw-r--r--chrome/browser/signin/token_service_unittest.cc3
19 files changed, 1005 insertions, 647 deletions
diff --git a/chrome/browser/signin/android_profile_oauth2_token_service.cc b/chrome/browser/signin/android_profile_oauth2_token_service.cc
new file mode 100644
index 0000000..698ee44
--- /dev/null
+++ b/chrome/browser/signin/android_profile_oauth2_token_service.cc
@@ -0,0 +1,62 @@
+// Copyright 2013 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "chrome/browser/signin/android_profile_oauth2_token_service.h"
+
+#include "base/bind.h"
+#include "chrome/browser/sync/profile_sync_service_android.h"
+#include "content/public/browser/browser_thread.h"
+#include "net/url_request/url_request_context_getter.h"
+
+AndroidProfileOAuth2TokenService::AndroidProfileOAuth2TokenService(
+ net::URLRequestContextGetter* getter)
+ : ProfileOAuth2TokenService(getter) {
+}
+
+AndroidProfileOAuth2TokenService::~AndroidProfileOAuth2TokenService() {
+}
+
+scoped_ptr<OAuth2TokenService::Request>
+ AndroidProfileOAuth2TokenService::StartRequest(
+ const OAuth2TokenService::ScopeSet& scopes,
+ OAuth2TokenService::Consumer* consumer) {
+ DCHECK(content::BrowserThread::CurrentlyOn(content::BrowserThread::UI));
+
+ if (HasCacheEntry(scopes))
+ return StartCacheLookupRequest(scopes, consumer);
+
+ scoped_ptr<RequestImpl> request(new RequestImpl(consumer));
+ DCHECK_EQ(scopes.size(), 1U);
+ std::vector<std::string> scope_list(scopes.begin(), scopes.end());
+ ProfileSyncServiceAndroid* sync_service =
+ ProfileSyncServiceAndroid::GetProfileSyncServiceAndroid();
+ sync_service->FetchOAuth2Token(
+ scope_list.front(),
+ base::Bind(&OAuth2TokenService::InformConsumer,
+ request->AsWeakPtr()));
+ return request.PassAs<Request>();
+}
+
+void AndroidProfileOAuth2TokenService::InvalidateToken(
+ const ScopeSet& scopes,
+ const std::string& invalid_token) {
+ OAuth2TokenService::InvalidateToken(scopes, invalid_token);
+
+ DCHECK_EQ(scopes.size(), 1U);
+ std::vector<std::string> scope_list(scopes.begin(), scopes.end());
+ ProfileSyncServiceAndroid* sync_service =
+ ProfileSyncServiceAndroid::GetProfileSyncServiceAndroid();
+ sync_service->InvalidateOAuth2Token(
+ scope_list.front(),
+ invalid_token);
+}
+
+bool AndroidProfileOAuth2TokenService::ShouldCacheForRefreshToken(
+ TokenService *token_service,
+ const std::string& refresh_token) {
+ // The parent class skips caching if the TokenService login token is stale,
+ // but on Android the user is always logged in to exactly one profile, so
+ // this concept doesn't exist and we can simply always cache.
+ return true;
+}
diff --git a/chrome/browser/signin/android_profile_oauth2_token_service.h b/chrome/browser/signin/android_profile_oauth2_token_service.h
new file mode 100644
index 0000000..14556c03
--- /dev/null
+++ b/chrome/browser/signin/android_profile_oauth2_token_service.h
@@ -0,0 +1,51 @@
+// Copyright 2013 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef CHROME_BROWSER_SIGNIN_ANDROID_PROFILE_OAUTH2_TOKEN_SERVICE_H_
+#define CHROME_BROWSER_SIGNIN_ANDROID_PROFILE_OAUTH2_TOKEN_SERVICE_H_
+
+#include <string>
+
+#include "chrome/browser/signin/profile_oauth2_token_service.h"
+
+namespace net {
+class URLRequestContextGetter;
+}
+
+class TokenService;
+
+// A specialization of ProfileOAuth2TokenService that will be returned by
+// ProfileOAuth2TokenServiceFactory for OS_ANDROID. This instance uses
+// native Android features to lookup OAuth2 tokens.
+//
+// See |ProfileOAuth2TokenService| for usage details.
+//
+// Note: requests should be started from the UI thread. To start a
+// request from other thread, please use ProfileOAuth2TokenServiceRequest.
+class AndroidProfileOAuth2TokenService : public ProfileOAuth2TokenService {
+ public:
+ // Start the OAuth2 access token for the given scopes using
+ // ProfileSyncServiceAndroid.
+ virtual scoped_ptr<OAuth2TokenService::Request> StartRequest(
+ const OAuth2TokenService::ScopeSet& scopes,
+ OAuth2TokenService::Consumer* consumer) OVERRIDE;
+
+ virtual void InvalidateToken(const ScopeSet& scopes,
+ const std::string& invalid_token) OVERRIDE;
+
+ protected:
+ friend class ProfileOAuth2TokenServiceFactory;
+ explicit AndroidProfileOAuth2TokenService(
+ net::URLRequestContextGetter* getter);
+ virtual ~AndroidProfileOAuth2TokenService();
+
+ // Takes injected TokenService for testing.
+ bool ShouldCacheForRefreshToken(TokenService *token_service,
+ const std::string& refresh_token);
+
+ private:
+ DISALLOW_COPY_AND_ASSIGN(AndroidProfileOAuth2TokenService);
+};
+
+#endif // CHROME_BROWSER_SIGNIN_ANDROID_PROFILE_OAUTH2_TOKEN_SERVICE_H_
diff --git a/chrome/browser/signin/oauth2_token_service.cc b/chrome/browser/signin/oauth2_token_service.cc
index 7886054..abddb4e 100644
--- a/chrome/browser/signin/oauth2_token_service.cc
+++ b/chrome/browser/signin/oauth2_token_service.cc
@@ -13,25 +13,12 @@
#include "base/stl_util.h"
#include "base/time.h"
#include "base/timer.h"
-#include "chrome/browser/profiles/profile.h"
-#include "chrome/browser/signin/oauth2_token_service_factory.h"
-#include "chrome/browser/signin/signin_manager.h"
-#include "chrome/browser/signin/signin_manager_factory.h"
-#include "chrome/browser/signin/token_service.h"
-#include "chrome/browser/signin/token_service_factory.h"
-#include "chrome/common/chrome_notification_types.h"
#include "content/public/browser/browser_thread.h"
-#include "content/public/browser/notification_details.h"
-#include "content/public/browser/notification_source.h"
-#include "google_apis/gaia/gaia_constants.h"
#include "google_apis/gaia/gaia_urls.h"
#include "google_apis/gaia/google_service_auth_error.h"
#include "google_apis/gaia/oauth2_access_token_consumer.h"
#include "google_apis/gaia/oauth2_access_token_fetcher.h"
-
-#if defined(OS_ANDROID)
-#include "chrome/browser/sync/profile_sync_service_android.h"
-#endif
+#include "net/url_request/url_request_context_getter.h"
namespace {
@@ -49,26 +36,6 @@ int64 ComputeExponentialBackOffMilliseconds(int retry_num) {
} // namespace
-// Implements a cancelable |OAuth2TokenService::Request|, which should be
-// operated on the UI thread.
-class OAuth2TokenService::RequestImpl
- : public base::SupportsWeakPtr<RequestImpl>,
- public OAuth2TokenService::Request {
- public:
- // |consumer| is required to outlive this.
- explicit RequestImpl(OAuth2TokenService::Consumer* consumer);
- virtual ~RequestImpl();
-
- // Informs |consumer_| that this request is completed.
- void InformConsumer(const GoogleServiceAuthError& error,
- const std::string& access_token,
- const base::Time& expiration_date);
-
- private:
- // |consumer_| to call back when this request completes.
- OAuth2TokenService::Consumer* const consumer_;
-};
-
OAuth2TokenService::RequestImpl::RequestImpl(
OAuth2TokenService::Consumer* consumer)
: consumer_(consumer) {
@@ -85,9 +52,9 @@ void OAuth2TokenService::RequestImpl::InformConsumer(
const base::Time& expiration_date) {
DCHECK(content::BrowserThread::CurrentlyOn(content::BrowserThread::UI));
if (error.state() == GoogleServiceAuthError::NONE)
- consumer_-> OnGetTokenSuccess(this, access_token, expiration_date);
+ consumer_->OnGetTokenSuccess(this, access_token, expiration_date);
else
- consumer_-> OnGetTokenFailure(this, error);
+ consumer_->OnGetTokenFailure(this, error);
}
// Class that fetches OAuth2 access tokens for given scopes and refresh token.
@@ -121,8 +88,8 @@ class OAuth2TokenService::Fetcher : public OAuth2AccessTokenConsumer {
public:
// Creates a Fetcher and starts fetching an OAuth2 access token for
// |refresh_token| and |scopes| in the request context obtained by |getter|.
- // |profile|'s OAuth2TokenService will be informed when fetching is done.
- static Fetcher* CreateAndStart(Profile* profile,
+ // The given |oauth2_token_service| will be informed when fetching is done.
+ static Fetcher* CreateAndStart(OAuth2TokenService* oauth2_token_service,
net::URLRequestContextGetter* getter,
const std::string& refresh_token,
const OAuth2TokenService::ScopeSet& scopes,
@@ -145,7 +112,7 @@ class OAuth2TokenService::Fetcher : public OAuth2AccessTokenConsumer {
virtual void OnGetTokenFailure(const GoogleServiceAuthError& error) OVERRIDE;
private:
- Fetcher(Profile* profile,
+ Fetcher(OAuth2TokenService* oauth2_token_service,
net::URLRequestContextGetter* getter,
const std::string& refresh_token,
const OAuth2TokenService::ScopeSet& scopes,
@@ -154,7 +121,11 @@ class OAuth2TokenService::Fetcher : public OAuth2AccessTokenConsumer {
void InformWaitingRequests();
static bool ShouldRetry(const GoogleServiceAuthError& error);
- Profile* const profile_;
+ // |oauth2_token_service_| remains valid for the life of this Fetcher, since
+ // this Fetcher is destructed in the dtor of the OAuth2TokenService or is
+ // scheduled for deletion at the end of OnGetTokenFailure/OnGetTokenSuccess
+ // (whichever comes first).
+ OAuth2TokenService* const oauth2_token_service_;
scoped_refptr<net::URLRequestContextGetter> getter_;
const std::string refresh_token_;
const OAuth2TokenService::ScopeSet scopes_;
@@ -176,30 +147,30 @@ class OAuth2TokenService::Fetcher : public OAuth2AccessTokenConsumer {
// static
OAuth2TokenService::Fetcher* OAuth2TokenService::Fetcher::CreateAndStart(
- Profile* profile,
+ OAuth2TokenService* oauth2_token_service,
net::URLRequestContextGetter* getter,
const std::string& refresh_token,
const OAuth2TokenService::ScopeSet& scopes,
base::WeakPtr<RequestImpl> waiting_request) {
OAuth2TokenService::Fetcher* fetcher = new Fetcher(
- profile, getter, refresh_token, scopes, waiting_request);
+ oauth2_token_service, getter, refresh_token, scopes, waiting_request);
fetcher->Start();
return fetcher;
}
OAuth2TokenService::Fetcher::Fetcher(
- Profile* profile,
+ OAuth2TokenService* oauth2_token_service,
net::URLRequestContextGetter* getter,
const std::string& refresh_token,
const OAuth2TokenService::ScopeSet& scopes,
base::WeakPtr<RequestImpl> waiting_request)
- : profile_(profile),
+ : oauth2_token_service_(oauth2_token_service),
getter_(getter),
refresh_token_(refresh_token),
scopes_(scopes),
retry_number_(0),
error_(GoogleServiceAuthError::SERVICE_UNAVAILABLE) {
- DCHECK(profile_);
+ DCHECK(oauth2_token_service_);
DCHECK(getter_);
DCHECK(refresh_token_.length());
waiting_requests_.push_back(waiting_request);
@@ -226,24 +197,21 @@ void OAuth2TokenService::Fetcher::OnGetTokenSuccess(
fetcher_.reset();
// Fetch completes.
- error_ = GoogleServiceAuthError(GoogleServiceAuthError::NONE);
+ error_ = GoogleServiceAuthError::AuthErrorNone();
access_token_ = access_token;
expiration_date_ = expiration_date;
- // |oauth2_token_service| should not be NULL as this Fetcher is destructed in
- // the dtor of the OAuth2TokenService that creates it if it is not scheduled
- // to be destructed here and in OnGetTokenFailure().
- OAuth2TokenService* oauth2_token_service =
- OAuth2TokenServiceFactory::GetForProfile(profile_);
- DCHECK(oauth2_token_service);
-
- oauth2_token_service->RegisterCacheEntry(refresh_token_,
- scopes_,
- access_token_,
- expiration_date_);
+ // Subclasses may override this method to skip caching in some cases, but
+ // we still inform all waiting Consumers of a successful token fetch below.
+ // This is intentional -- some consumers may need the token for cleanup
+ // tasks. https://chromiumcodereview.appspot.com/11312124/
+ oauth2_token_service_->RegisterCacheEntry(refresh_token_,
+ scopes_,
+ access_token_,
+ expiration_date_);
// Deregisters itself from the service to prevent more waiting requests to
// be added when it calls back the waiting requests.
- oauth2_token_service->OnFetchComplete(this);
+ oauth2_token_service_->OnFetchComplete(this);
InformWaitingRequests();
MessageLoop::current()->DeleteSoon(FROM_HERE, this);
}
@@ -266,15 +234,9 @@ void OAuth2TokenService::Fetcher::OnGetTokenFailure(
// Fetch completes.
error_ = error;
- // |oauth2_token_service| should not be NULL as this Fetcher is destructed in
- // the dtor of the OAuth2TokenService that creates it if it is not scheduled
- // to be destructed here and in OnGetTokenSuccess().
- OAuth2TokenService* oauth2_token_service =
- OAuth2TokenServiceFactory::GetForProfile(profile_);
- DCHECK(oauth2_token_service);
// Deregisters itself from the service to prevent more waiting requests to be
// added when it calls back the waiting requests.
- oauth2_token_service->OnFetchComplete(this);
+ oauth2_token_service_->OnFetchComplete(this);
InformWaitingRequests();
MessageLoop::current()->DeleteSoon(FROM_HERE, this);
}
@@ -325,44 +287,22 @@ OAuth2TokenService::Consumer::Consumer() {
OAuth2TokenService::Consumer::~Consumer() {
}
-OAuth2TokenService::OAuth2TokenService()
- : profile_(NULL),
- last_auth_error_(GoogleServiceAuthError::NONE) {
+OAuth2TokenService::OAuth2TokenService(net::URLRequestContextGetter* getter)
+ : request_context_getter_(getter) {
}
OAuth2TokenService::~OAuth2TokenService() {
+ DCHECK(content::BrowserThread::CurrentlyOn(content::BrowserThread::UI));
// Release all the pending fetchers.
STLDeleteContainerPairSecondPointers(
pending_fetchers_.begin(), pending_fetchers_.end());
}
-void OAuth2TokenService::Initialize(Profile* profile) {
+bool OAuth2TokenService::RefreshTokenIsAvailable() {
DCHECK(content::BrowserThread::CurrentlyOn(content::BrowserThread::UI));
-
- DCHECK(profile);
- DCHECK(!profile_);
- profile_ = profile;
- getter_ = profile->GetRequestContext();
- content::Source<TokenService> token_service_source(
- TokenServiceFactory::GetForProfile(profile));
- registrar_.Add(this,
- chrome::NOTIFICATION_TOKENS_CLEARED,
- token_service_source);
- registrar_.Add(this,
- chrome::NOTIFICATION_TOKEN_AVAILABLE,
- token_service_source);
- SigninManagerFactory::GetForProfile(profile_)->signin_global_error()->
- AddProvider(this);
-}
-
-void OAuth2TokenService::Shutdown() {
- if (profile_) {
- SigninManagerFactory::GetForProfile(profile_)->signin_global_error()->
- RemoveProvider(this);
- }
+ return !GetRefreshToken().empty();
}
-
// static
void OAuth2TokenService::InformConsumer(
base::WeakPtr<OAuth2TokenService::RequestImpl> request,
@@ -382,53 +322,21 @@ scoped_ptr<OAuth2TokenService::Request> OAuth2TokenService::StartRequest(
scoped_ptr<RequestImpl> request(new RequestImpl(consumer));
-#if !defined(OS_ANDROID)
- TokenService* token_service = TokenServiceFactory::GetForProfile(profile_);
- if (!token_service || !token_service->HasOAuthLoginToken()) {
- MessageLoop::current()->PostTask(FROM_HERE, base::Bind(
- &OAuth2TokenService::InformConsumer,
- request->AsWeakPtr(),
- GoogleServiceAuthError(GoogleServiceAuthError::USER_NOT_SIGNED_UP),
- std::string(),
- base::Time()));
- return request.PassAs<Request>();
- }
-#endif
-
- const CacheEntry* cache_entry = GetCacheEntry(scopes);
- if (cache_entry && cache_entry->access_token.length()) {
- MessageLoop::current()->PostTask(FROM_HERE, base::Bind(
- &OAuth2TokenService::InformConsumer,
- request->AsWeakPtr(),
- GoogleServiceAuthError(GoogleServiceAuthError::NONE),
- cache_entry->access_token,
- cache_entry->expiration_date));
- return request.PassAs<Request>();
- }
-
-#if defined(OS_ANDROID)
- DCHECK_EQ(scopes.size(), 1U);
- std::vector<std::string> scope_list(scopes.begin(), scopes.end());
- ProfileSyncServiceAndroid* sync_service =
- ProfileSyncServiceAndroid::GetProfileSyncServiceAndroid();
- sync_service->FetchOAuth2Token(
- scope_list.front(),
- base::Bind(&OAuth2TokenService::InformConsumer,
- request->AsWeakPtr()));
- return request.PassAs<Request>();
-#else
- std::string refresh_token = token_service->GetOAuth2LoginRefreshToken();
- if (!refresh_token.length()) {
+ std::string refresh_token = GetRefreshToken();
+ if (refresh_token.empty()) {
MessageLoop::current()->PostTask(FROM_HERE, base::Bind(
&OAuth2TokenService::InformConsumer,
request->AsWeakPtr(),
GoogleServiceAuthError(
- GoogleServiceAuthError::INVALID_GAIA_CREDENTIALS),
+ GoogleServiceAuthError::USER_NOT_SIGNED_UP),
std::string(),
base::Time()));
return request.PassAs<Request>();
}
+ if (HasCacheEntry(scopes))
+ return StartCacheLookupRequest(scopes, consumer);
+
// Makes sure there is a pending fetcher for |scopes| and |refresh_token|.
// Adds |request| to the waiting request list of this fetcher so |request|
// will be called back when this fetcher finishes fetching.
@@ -440,24 +348,31 @@ scoped_ptr<OAuth2TokenService::Request> OAuth2TokenService::StartRequest(
return request.PassAs<Request>();
}
pending_fetchers_[fetch_parameters] = Fetcher::CreateAndStart(
- profile_, getter_, refresh_token, scopes, request->AsWeakPtr());
+ this, request_context_getter_, refresh_token, scopes,
+ request->AsWeakPtr());
+ return request.PassAs<Request>();
+}
+
+scoped_ptr<OAuth2TokenService::Request>
+ OAuth2TokenService::StartCacheLookupRequest(
+ const OAuth2TokenService::ScopeSet& scopes,
+ OAuth2TokenService::Consumer* consumer) {
+ CHECK(HasCacheEntry(scopes));
+ const CacheEntry* cache_entry = GetCacheEntry(scopes);
+ scoped_ptr<RequestImpl> request(new RequestImpl(consumer));
+ MessageLoop::current()->PostTask(FROM_HERE, base::Bind(
+ &OAuth2TokenService::InformConsumer,
+ request->AsWeakPtr(),
+ GoogleServiceAuthError(GoogleServiceAuthError::NONE),
+ cache_entry->access_token,
+ cache_entry->expiration_date));
return request.PassAs<Request>();
-#endif // defined(OS_ANDROID)
}
void OAuth2TokenService::InvalidateToken(const ScopeSet& scopes,
const std::string& invalid_token) {
+ DCHECK(content::BrowserThread::CurrentlyOn(content::BrowserThread::UI));
RemoveCacheEntry(scopes, invalid_token);
-
-#if defined(OS_ANDROID)
- DCHECK_EQ(scopes.size(), 1U);
- std::vector<std::string> scope_list(scopes.begin(), scopes.end());
- ProfileSyncServiceAndroid* sync_service =
- ProfileSyncServiceAndroid::GetProfileSyncServiceAndroid();
- sync_service->InvalidateOAuth2Token(
- scope_list.front(),
- invalid_token);
-#endif
}
void OAuth2TokenService::OnFetchComplete(Fetcher* fetcher) {
@@ -475,8 +390,7 @@ void OAuth2TokenService::OnFetchComplete(Fetcher* fetcher) {
// (1) All the live Fetchers are created by this service.
// This is because (1) all the live Fetchers are created by a live
// service, as all the fetchers created by a service are destructed in the
- // service's dtor, and (2) there is at most one live OAuth2TokenSevice for
- // a given profile at a time.
+ // service's dtor.
//
// (2) All the uncompleted Fetchers created by this service are recorded in
// |pending_fetchers_|.
@@ -488,7 +402,7 @@ void OAuth2TokenService::OnFetchComplete(Fetcher* fetcher) {
//
// (3) Each of the Fetchers recorded in |pending_fetchers_| is mapped to its
// refresh token and ScopeSet. This is guaranteed by Fetcher creation in
- // method StartReuest().
+ // method StartRequest().
//
// When this method is called, |fetcher| is alive and uncompleted.
// By (1), |fetcher| is created by this service.
@@ -502,6 +416,12 @@ void OAuth2TokenService::OnFetchComplete(Fetcher* fetcher) {
pending_fetchers_.erase(iter);
}
+bool OAuth2TokenService::HasCacheEntry(
+ const OAuth2TokenService::ScopeSet& scopes) {
+ const CacheEntry* cache_entry = GetCacheEntry(scopes);
+ return cache_entry && cache_entry->access_token.length();
+}
+
const OAuth2TokenService::CacheEntry* OAuth2TokenService::GetCacheEntry(
const OAuth2TokenService::ScopeSet& scopes) {
DCHECK(content::BrowserThread::CurrentlyOn(content::BrowserThread::UI));
@@ -535,56 +455,20 @@ void OAuth2TokenService::RegisterCacheEntry(
const base::Time& expiration_date) {
DCHECK(content::BrowserThread::CurrentlyOn(content::BrowserThread::UI));
-#if !defined(OS_ANDROID)
- // Only register OAuth2 access tokens for the refresh token held by
- // TokenService.
- TokenService* token_service = TokenServiceFactory::GetForProfile(profile_);
- if (!token_service ||
- !token_service->HasOAuthLoginToken() ||
- token_service->GetOAuth2LoginRefreshToken().compare(refresh_token) != 0) {
- DLOG(INFO) <<
- "Received a token with a refresh token not maintained by TokenService.";
- return;
- }
-#endif
-
CacheEntry& token = token_cache_[scopes];
token.access_token = access_token;
token.expiration_date = expiration_date;
}
-void OAuth2TokenService::Observe(int type,
- const content::NotificationSource& source,
- const content::NotificationDetails& details) {
- DCHECK(type == chrome::NOTIFICATION_TOKENS_CLEARED ||
- type == chrome::NOTIFICATION_TOKEN_AVAILABLE);
- if (type == chrome::NOTIFICATION_TOKEN_AVAILABLE) {
- TokenService::TokenAvailableDetails* tok_details =
- content::Details<TokenService::TokenAvailableDetails>(details).ptr();
- if (tok_details->service() != GaiaConstants::kGaiaOAuth2LoginRefreshToken)
- return;
- }
- // The GaiaConstants::kGaiaOAuth2LoginRefreshToken token is used to create
- // OAuth2 access tokens. If this token either changes or is cleared, any
- // available tokens must be invalidated.
- token_cache_.clear();
- UpdateAuthError(GoogleServiceAuthError::AuthErrorNone());
-}
-
void OAuth2TokenService::UpdateAuthError(const GoogleServiceAuthError& error) {
- // Do not report connection errors as these are not actually auth errors.
- // We also want to avoid masking a "real" auth error just because we
- // subsequently get a transient network error.
- if (error.state() == GoogleServiceAuthError::CONNECTION_FAILED)
- return;
+ // Default implementation does nothing.
+}
- if (error.state() != last_auth_error_.state()) {
- last_auth_error_ = error;
- SigninManagerFactory::GetForProfile(profile_)->signin_global_error()->
- AuthStatusChanged();
- }
+void OAuth2TokenService::ClearCache() {
+ DCHECK(content::BrowserThread::CurrentlyOn(content::BrowserThread::UI));
+ token_cache_.clear();
}
-GoogleServiceAuthError OAuth2TokenService::GetAuthStatus() const {
- return last_auth_error_;
+int OAuth2TokenService::cache_size_for_testing() const {
+ return token_cache_.size();
}
diff --git a/chrome/browser/signin/oauth2_token_service.h b/chrome/browser/signin/oauth2_token_service.h
index 71ddcb2..9260f41 100644
--- a/chrome/browser/signin/oauth2_token_service.h
+++ b/chrome/browser/signin/oauth2_token_service.h
@@ -9,23 +9,27 @@
#include <set>
#include <string>
+#include "base/basictypes.h"
#include "base/memory/ref_counted.h"
#include "base/memory/scoped_ptr.h"
#include "base/memory/weak_ptr.h"
#include "base/time.h"
-#include "chrome/browser/profiles/profile_keyed_service.h"
-#include "chrome/browser/signin/signin_global_error.h"
-#include "content/public/browser/notification_observer.h"
-#include "content/public/browser/notification_registrar.h"
-#include "net/url_request/url_request_context_getter.h"
+
+namespace base {
+class Time;
+}
+
+namespace net {
+class URLRequestContextGetter;
+}
class GoogleServiceAuthError;
-class OAuth2AccessTokenConsumer;
-class Profile;
-// OAuth2TokenService is a ProfileKeyedService that retrieves OAuth2 access
-// tokens for a given set of scopes using the OAuth2 refresh token maintained by
-// TokenService. All calls are expected from the UI thread.
+// Abstract base class for a service that fetches and caches OAuth2 access
+// tokens. Concrete subclasses should implement GetRefreshToken to return
+// the appropriate refresh token.
+//
+// All calls are expected from the UI thread.
//
// To use this service, call StartRequest() with a given set of scopes and a
// consumer of the request results. The consumer is required to outlive the
@@ -43,12 +47,7 @@ class Profile;
//
// The caller of StartRequest() owns the returned request and is responsible to
// delete the request even once the callback has been invoked.
-//
-// Note the request should be started from the UI thread. To start a request
-// from other thread, please use OAuth2TokenServiceRequest.
-class OAuth2TokenService : public content::NotificationObserver,
- public SigninGlobalError::AuthStatusProvider,
- public ProfileKeyedService {
+class OAuth2TokenService {
public:
// Class representing a request that fetches an OAuth2 access token.
class Request {
@@ -76,58 +75,90 @@ class OAuth2TokenService : public content::NotificationObserver,
// A set of scopes in OAuth2 authentication.
typedef std::set<std::string> ScopeSet;
- OAuth2TokenService();
+ explicit OAuth2TokenService(net::URLRequestContextGetter* getter);
virtual ~OAuth2TokenService();
- // Initializes this token service with the profile.
- void Initialize(Profile* profile);
-
- // ProfileKeyedService implementation.
- virtual void Shutdown() OVERRIDE;
-
- // Starts a request for an OAuth2 access token using the OAuth2 refresh token
- // maintained by TokenService. The caller owns the returned Request. |scopes|
- // is the set of scopes to get an access token for, |consumer| is the object
- // that will be called back with results if the returned request is not
- // deleted.
- // Note the refresh token has been collected from TokenService when this
- // method returns, and the request can continue even if TokenService clears
- // its tokens after this method returns. This means that outstanding
- // StartRequest actions will still complete even if the user signs out in the
- // meantime.
- virtual scoped_ptr<Request> StartRequest(
- const ScopeSet& scopes,
- OAuth2TokenService::Consumer* consumer);
+ // Checks in the cache for a valid access token, and if not found starts
+ // a request for an OAuth2 access token using the OAuth2 refresh token
+ // maintained by this instance. The caller owns the returned Request.
+ // |scopes| is the set of scopes to get an access token for, |consumer| is
+ // the object that will be called back with results if the returned request
+ // is not deleted.
+ virtual scoped_ptr<Request> StartRequest(const ScopeSet& scopes,
+ Consumer* consumer);
+
+ // Returns true if a refresh token exists. If false, calls to
+ // |StartRequest| will result in a Consumer::OnGetTokenFailure callback.
+ bool RefreshTokenIsAvailable();
// Mark an OAuth2 access token as invalid. This should be done if the token
// was received from this class, but was not accepted by the server (e.g.,
// the server returned 401 Unauthorized). The token will be removed from the
// cache for the given scopes.
- void InvalidateToken(const ScopeSet& scopes,
- const std::string& invalid_token);
-
- // content::NotificationObserver
- virtual void Observe(int type,
- const content::NotificationSource& source,
- const content::NotificationDetails& details) OVERRIDE;
+ virtual void InvalidateToken(const ScopeSet& scopes,
+ const std::string& invalid_token);
+
+ // Return the current number of entries in the cache.
+ int cache_size_for_testing() const;
+
+ protected:
+ // Subclasses should return the refresh token maintained.
+ // If no token is available, return an empty string.
+ virtual std::string GetRefreshToken() = 0;
+
+ // Subclasses can override if they want to report errors to the user.
+ virtual void UpdateAuthError(const GoogleServiceAuthError& error);
+
+ // Add a new entry to the cache.
+ // Subclasses can override if there are implementation-specific reasons
+ // that an access token should ever not be cached.
+ virtual void RegisterCacheEntry(const std::string& refresh_token,
+ const ScopeSet& scopes,
+ const std::string& access_token,
+ const base::Time& expiration_date);
+
+ // Returns true if GetCacheEntry would return a valid cache entry for the
+ // given scopes.
+ bool HasCacheEntry(const ScopeSet& scopes);
+
+ // Posts a task to fire the Consumer callback with the cached token. Must
+ // only be called if HasCacheEntry() returns true.
+ scoped_ptr<Request> StartCacheLookupRequest(const ScopeSet& scopes,
+ Consumer* consumer);
+
+ // Clears the internal token cache.
+ void ClearCache();
+
+ // Implements a cancelable |OAuth2TokenService::Request|, which should be
+ // operated on the UI thread.
+ class RequestImpl : public base::SupportsWeakPtr<RequestImpl>,
+ public Request {
+ public:
+ // |consumer| is required to outlive this.
+ explicit RequestImpl(Consumer* consumer);
+ virtual ~RequestImpl();
+
+ // Informs |consumer_| that this request is completed.
+ void InformConsumer(const GoogleServiceAuthError& error,
+ const std::string& access_token,
+ const base::Time& expiration_date);
+
+ private:
+ // |consumer_| to call back when this request completes.
+ Consumer* const consumer_;
+ };
- // SigninGlobalError::AuthStatusProvider implementation.
- virtual GoogleServiceAuthError GetAuthStatus() const OVERRIDE;
+ // Informs the consumer of |request| fetch results.
+ static void InformConsumer(base::WeakPtr<RequestImpl> request,
+ const GoogleServiceAuthError& error,
+ const std::string& access_token,
+ const base::Time& expiration_date);
private:
// Class that fetches an OAuth2 access token for a given set of scopes and
// OAuth2 refresh token.
class Fetcher;
friend class Fetcher;
- // Implementation of Request.
- class RequestImpl;
-
- // Informs the consumer of |request| fetch results.
- static void InformConsumer(
- base::WeakPtr<OAuth2TokenService::RequestImpl> request,
- const GoogleServiceAuthError& error,
- const std::string& access_token,
- const base::Time& expiration_date);
// Struct that contains the information of an OAuth2 access token.
struct CacheEntry {
@@ -141,12 +172,6 @@ class OAuth2TokenService : public content::NotificationObserver,
// returned entry is done.
const CacheEntry* GetCacheEntry(const ScopeSet& scopes);
- // Registers a new access token in the cache if |refresh_token| is the one
- // currently held by TokenService.
- void RegisterCacheEntry(const std::string& refresh_token,
- const ScopeSet& scopes,
- const std::string& access_token,
- const base::Time& expiration_date);
// Removes an access token for the given set of scopes from the cache.
// Returns true if the entry was removed, otherwise false.
@@ -157,18 +182,8 @@ class OAuth2TokenService : public content::NotificationObserver,
// Called when |fetcher| finishes fetching.
void OnFetchComplete(Fetcher* fetcher);
- // Updates the internal cache of the result from the most-recently-completed
- // auth request (used for reporting errors to the user).
- void UpdateAuthError(const GoogleServiceAuthError& error);
-
- // The profile with which this instance was initialized, or NULL.
- Profile* profile_;
-
- // The auth status from the most-recently-completed request.
- GoogleServiceAuthError last_auth_error_;
-
// Getter to use for fetchers.
- scoped_refptr<net::URLRequestContextGetter> getter_;
+ scoped_refptr<net::URLRequestContextGetter> request_context_getter_;
// The cache of currently valid tokens.
typedef std::map<ScopeSet, CacheEntry> TokenCache;
@@ -181,9 +196,6 @@ class OAuth2TokenService : public content::NotificationObserver,
// token using these parameters.
std::map<FetchParameters, Fetcher*> pending_fetchers_;
- // Registrar for notifications from the TokenService.
- content::NotificationRegistrar registrar_;
-
DISALLOW_COPY_AND_ASSIGN(OAuth2TokenService);
};
diff --git a/chrome/browser/signin/oauth2_token_service_factory.cc b/chrome/browser/signin/oauth2_token_service_factory.cc
deleted file mode 100644
index c0ca0be..0000000
--- a/chrome/browser/signin/oauth2_token_service_factory.cc
+++ /dev/null
@@ -1,38 +0,0 @@
-// Copyright (c) 2012 The Chromium Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-#include "chrome/browser/signin/oauth2_token_service_factory.h"
-
-#include "chrome/browser/profiles/profile_dependency_manager.h"
-#include "chrome/browser/signin/oauth2_token_service.h"
-#include "chrome/browser/signin/signin_manager_factory.h"
-#include "chrome/browser/signin/token_service_factory.h"
-
-OAuth2TokenServiceFactory::OAuth2TokenServiceFactory()
- : ProfileKeyedServiceFactory("OAuth2TokenService",
- ProfileDependencyManager::GetInstance()) {
- DependsOn(SigninManagerFactory::GetInstance());
- DependsOn(TokenServiceFactory::GetInstance());
-}
-
-OAuth2TokenServiceFactory::~OAuth2TokenServiceFactory() {
-}
-
-// static
-OAuth2TokenService* OAuth2TokenServiceFactory::GetForProfile(Profile* profile) {
- return static_cast<OAuth2TokenService*>(
- GetInstance()->GetServiceForProfile(profile, true));
-}
-
-// static
-OAuth2TokenServiceFactory* OAuth2TokenServiceFactory::GetInstance() {
- return Singleton<OAuth2TokenServiceFactory>::get();
-}
-
-ProfileKeyedService* OAuth2TokenServiceFactory::BuildServiceInstanceFor(
- Profile* profile) const {
- OAuth2TokenService* service = new OAuth2TokenService();
- service->Initialize(profile);
- return service;
-}
diff --git a/chrome/browser/signin/oauth2_token_service_factory.h b/chrome/browser/signin/oauth2_token_service_factory.h
deleted file mode 100644
index 155f0e3..0000000
--- a/chrome/browser/signin/oauth2_token_service_factory.h
+++ /dev/null
@@ -1,40 +0,0 @@
-// Copyright 2012 The Chromium Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-#ifndef CHROME_BROWSER_SIGNIN_OAUTH2_TOKEN_SERVICE_FACTORY_H_
-#define CHROME_BROWSER_SIGNIN_OAUTH2_TOKEN_SERVICE_FACTORY_H_
-
-#include "base/memory/singleton.h"
-#include "chrome/browser/profiles/profile_keyed_service_factory.h"
-
-class OAuth2TokenService;
-class Profile;
-
-// Singleton that owns all OAuth2TokenServices and associates them with
-// Profiles. Listens for the Profile's destruction notification and cleans up
-// the associated OAuth2TokenService.
-class OAuth2TokenServiceFactory : public ProfileKeyedServiceFactory {
- public:
- // Returns the instance of OAuth2TokenService associated with this profile
- // (creating one if none exists). Returns NULL if this profile cannot have a
- // OAuth2TokenService (for example, if |profile| is incognito).
- static OAuth2TokenService* GetForProfile(Profile* profile);
-
- // Returns an instance of the OAuth2TokenServiceFactory singleton.
- static OAuth2TokenServiceFactory* GetInstance();
-
- private:
- friend struct DefaultSingletonTraits<OAuth2TokenServiceFactory>;
-
- OAuth2TokenServiceFactory();
- virtual ~OAuth2TokenServiceFactory();
-
- // ProfileKeyedServiceFactory implementation.
- virtual ProfileKeyedService* BuildServiceInstanceFor(
- Profile* profile) const OVERRIDE;
-
- DISALLOW_COPY_AND_ASSIGN(OAuth2TokenServiceFactory);
-};
-
-#endif // CHROME_BROWSER_SIGNIN_OAUTH2_TOKEN_SERVICE_FACTORY_H_
diff --git a/chrome/browser/signin/oauth2_token_service_request.h b/chrome/browser/signin/oauth2_token_service_request.h
deleted file mode 100644
index 8ab4b79..0000000
--- a/chrome/browser/signin/oauth2_token_service_request.h
+++ /dev/null
@@ -1,51 +0,0 @@
-// Copyright 2012 The Chromium Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-#ifndef CHROME_BROWSER_SIGNIN_OAUTH2_TOKEN_SERVICE_REQUEST_H_
-#define CHROME_BROWSER_SIGNIN_OAUTH2_TOKEN_SERVICE_REQUEST_H_
-
-#include <set>
-#include <string>
-
-#include "base/memory/ref_counted.h"
-#include "base/threading/non_thread_safe.h"
-#include "base/time.h"
-#include "chrome/browser/signin/oauth2_token_service.h"
-#include "google_apis/gaia/google_service_auth_error.h"
-
-class Profile;
-
-// OAuth2TokenServiceRequest represents a request to fetch an OAuth2 access
-// token for a given set of |scopes| by calling |profile|'s
-// OAuth2TokenService. A request can be created and started from any thread
-// with an object |consumer| that will be called back on the same thread when
-// fetching completes.
-// If the request is destructed before |consumer| is called, |consumer| will
-// never be called back. (Note the actual network activities are not canceled
-// and the cache in OAuth2TokenService will be populated with the fetched
-// results.)
-class OAuth2TokenServiceRequest : public OAuth2TokenService::Request,
- public base::NonThreadSafe {
- public:
- static OAuth2TokenServiceRequest* CreateAndStart(
- Profile* profile,
- const OAuth2TokenService::ScopeSet& scopes,
- OAuth2TokenService::Consumer* consumer);
-
- virtual ~OAuth2TokenServiceRequest();
-
- private:
- class Core;
- friend class Core;
-
- OAuth2TokenServiceRequest(Profile* profile,
- const OAuth2TokenService::ScopeSet& scopes,
- OAuth2TokenService::Consumer* consumer);
- OAuth2TokenService::Consumer* const consumer_;
- scoped_refptr<Core> core_;
-
- DISALLOW_COPY_AND_ASSIGN(OAuth2TokenServiceRequest);
-};
-
-#endif // CHROME_BROWSER_SIGNIN_OAUTH2_TOKEN_SERVICE_REQUEST_H_
diff --git a/chrome/browser/signin/oauth2_token_service_test_util.cc b/chrome/browser/signin/oauth2_token_service_test_util.cc
new file mode 100644
index 0000000..dd03199
--- /dev/null
+++ b/chrome/browser/signin/oauth2_token_service_test_util.cc
@@ -0,0 +1,40 @@
+// Copyright 2013 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "chrome/browser/signin/oauth2_token_service_test_util.h"
+
+const char kValidTokenResponse[] =
+ "{"
+ " \"access_token\": \"%s\","
+ " \"expires_in\": %d,"
+ " \"token_type\": \"Bearer\""
+ "}";
+
+std::string GetValidTokenResponse(std::string token, int expiration) {
+ return base::StringPrintf(kValidTokenResponse, token.c_str(), expiration);
+}
+
+TestingOAuth2TokenServiceConsumer::TestingOAuth2TokenServiceConsumer()
+ : number_of_successful_tokens_(0),
+ last_error_(GoogleServiceAuthError::AuthErrorNone()),
+ number_of_errors_(0) {
+}
+
+TestingOAuth2TokenServiceConsumer::~TestingOAuth2TokenServiceConsumer() {
+}
+
+void TestingOAuth2TokenServiceConsumer::OnGetTokenSuccess(
+ const OAuth2TokenService::Request* request,
+ const std::string& token,
+ const base::Time& expiration_date) {
+ last_token_ = token;
+ ++number_of_successful_tokens_;
+}
+
+void TestingOAuth2TokenServiceConsumer::OnGetTokenFailure(
+ const OAuth2TokenService::Request* request,
+ const GoogleServiceAuthError& error) {
+ last_error_ = error;
+ ++number_of_errors_;
+}
diff --git a/chrome/browser/signin/oauth2_token_service_test_util.h b/chrome/browser/signin/oauth2_token_service_test_util.h
new file mode 100644
index 0000000..f99fab3
--- /dev/null
+++ b/chrome/browser/signin/oauth2_token_service_test_util.h
@@ -0,0 +1,38 @@
+// Copyright 2013 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef CHROME_BROWSER_SIGNIN_OAUTH2_TOKEN_SERVICE_TEST_UTIL_H_
+#define CHROME_BROWSER_SIGNIN_OAUTH2_TOKEN_SERVICE_TEST_UTIL_H_
+
+#include "chrome/browser/signin/oauth2_token_service.h"
+
+#include <string>
+
+#include "base/stringprintf.h"
+#include "google_apis/gaia/google_service_auth_error.h"
+
+extern const char kValidTokenResponse[];
+
+std::string GetValidTokenResponse(std::string token, int expiration);
+
+// A simple testing consumer.
+class TestingOAuth2TokenServiceConsumer : public OAuth2TokenService::Consumer {
+ public:
+ TestingOAuth2TokenServiceConsumer();
+ virtual ~TestingOAuth2TokenServiceConsumer();
+
+ // OAuth2TokenService::Consumer overrides.
+ virtual void OnGetTokenSuccess(const OAuth2TokenService::Request* request,
+ const std::string& token,
+ const base::Time& expiration_date) OVERRIDE;
+ virtual void OnGetTokenFailure(const OAuth2TokenService::Request* request,
+ const GoogleServiceAuthError& error) OVERRIDE;
+
+ std::string last_token_;
+ int number_of_successful_tokens_;
+ GoogleServiceAuthError last_error_;
+ int number_of_errors_;
+};
+
+#endif // CHROME_BROWSER_SIGNIN_OAUTH2_TOKEN_SERVICE_TEST_UTIL_H_
diff --git a/chrome/browser/signin/oauth2_token_service_unittest.cc b/chrome/browser/signin/oauth2_token_service_unittest.cc
index 7095b43..8f96f13 100644
--- a/chrome/browser/signin/oauth2_token_service_unittest.cc
+++ b/chrome/browser/signin/oauth2_token_service_unittest.cc
@@ -2,108 +2,78 @@
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
+#include <string>
+
#include "base/stringprintf.h"
#include "chrome/browser/signin/oauth2_token_service.h"
-#include "chrome/browser/signin/oauth2_token_service_factory.h"
+#include "chrome/browser/signin/oauth2_token_service_test_util.h"
#include "chrome/browser/signin/token_service_factory.h"
#include "chrome/browser/signin/token_service_unittest.h"
#include "chrome/common/chrome_notification_types.h"
-#include "content/public/browser/browser_thread.h"
+#include "chrome/test/base/testing_browser_process.h"
#include "google_apis/gaia/gaia_constants.h"
#include "google_apis/gaia/google_service_auth_error.h"
#include "google_apis/gaia/oauth2_access_token_consumer.h"
#include "net/http/http_status_code.h"
#include "net/url_request/test_url_fetcher_factory.h"
#include "net/url_request/url_request_status.h"
+#include "net/url_request/url_request_test_util.h"
#include "testing/gtest/include/gtest/gtest.h"
using content::BrowserThread;
-static const char kValidTokenResponse[] =
- "{"
- " \"access_token\": \"%s\","
- " \"expires_in\": %d,"
- " \"token_type\": \"Bearer\""
- "}";
-
-std::string GetValidTokenResponse(std::string token, int expiration) {
- return base::StringPrintf(kValidTokenResponse, token.c_str(), expiration);
-}
-
-// A simple testing consumer.
-class TestingOAuth2TokenServiceConsumer : public OAuth2TokenService::Consumer {
- public:
- TestingOAuth2TokenServiceConsumer()
- : number_of_correct_tokens_(0),
- last_error_(GoogleServiceAuthError::AuthErrorNone()),
- number_of_errors_(0) {}
- virtual ~TestingOAuth2TokenServiceConsumer() {}
-
- virtual void OnGetTokenSuccess(const OAuth2TokenService::Request* request,
- const std::string& token,
- const base::Time& expiration_date) OVERRIDE {
- last_token_ = token;
- ++number_of_correct_tokens_;
- }
-
- virtual void OnGetTokenFailure(const OAuth2TokenService::Request* request,
- const GoogleServiceAuthError& error) OVERRIDE {
- last_error_ = error;
- ++number_of_errors_;
- }
-
- std::string last_token_;
- int number_of_correct_tokens_;
- GoogleServiceAuthError last_error_;
- int number_of_errors_;
-};
-
// A testing consumer that retries on error.
class RetryingTestingOAuth2TokenServiceConsumer
- : public OAuth2TokenService::Consumer {
+ : public TestingOAuth2TokenServiceConsumer {
public:
RetryingTestingOAuth2TokenServiceConsumer(
OAuth2TokenService* oauth2_service)
- : oauth2_service_(oauth2_service),
- number_of_correct_tokens_(0),
- last_error_(GoogleServiceAuthError::AuthErrorNone()),
- number_of_errors_(0) {}
+ : oauth2_service_(oauth2_service) {}
virtual ~RetryingTestingOAuth2TokenServiceConsumer() {}
- virtual void OnGetTokenSuccess(const OAuth2TokenService::Request* request,
- const std::string& token,
- const base::Time& expiration_date) OVERRIDE {
- last_token_ = token;
- ++number_of_correct_tokens_;
- }
-
virtual void OnGetTokenFailure(const OAuth2TokenService::Request* request,
const GoogleServiceAuthError& error) OVERRIDE {
- last_error_ = error;
- ++number_of_errors_;
+ TestingOAuth2TokenServiceConsumer::OnGetTokenFailure(request, error);
request_.reset(oauth2_service_->StartRequest(
std::set<std::string>(), this).release());
}
OAuth2TokenService* oauth2_service_;
scoped_ptr<OAuth2TokenService::Request> request_;
- std::string last_token_;
- int number_of_correct_tokens_;
- GoogleServiceAuthError last_error_;
- int number_of_errors_;
+};
+
+class TestOAuth2TokenService : public OAuth2TokenService {
+ public:
+ explicit TestOAuth2TokenService(net::URLRequestContextGetter* getter)
+ : OAuth2TokenService(getter) {
+ }
+
+ // For testing: set the refresh token to be used.
+ void set_refresh_token(const std::string& refresh_token) {
+ refresh_token_ = refresh_token;
+ }
+
+ protected:
+ std::string GetRefreshToken() OVERRIDE {
+ return refresh_token_;
+ }
+
+ private:
+ std::string refresh_token_;
};
class OAuth2TokenServiceTest : public TokenServiceTestHarness {
public:
- OAuth2TokenServiceTest() {}
+ OAuth2TokenServiceTest()
+ : request_context_getter_(new net::TestURLRequestContextGetter(
+ message_loop_.message_loop_proxy())) {
+ }
virtual void SetUp() OVERRIDE {
TokenServiceTestHarness::SetUp();
io_thread_.reset(new content::TestBrowserThread(content::BrowserThread::IO,
&message_loop_));
- service_->UpdateCredentials(credentials_);
- profile_->CreateRequestContext();
- oauth2_service_ = OAuth2TokenServiceFactory::GetForProfile(profile_.get());
+ oauth2_service_.reset(new TestOAuth2TokenService(request_context_getter_));
}
virtual void TearDown() OVERRIDE {
@@ -112,8 +82,9 @@ class OAuth2TokenServiceTest : public TokenServiceTestHarness {
protected:
scoped_ptr<content::TestBrowserThread> io_thread_;
+ scoped_refptr<net::TestURLRequestContextGetter> request_context_getter_;
net::TestURLFetcherFactory factory_;
- OAuth2TokenService* oauth2_service_;
+ scoped_ptr<TestOAuth2TokenService> oauth2_service_;
TestingOAuth2TokenServiceConsumer consumer_;
};
@@ -122,44 +93,42 @@ TEST_F(OAuth2TokenServiceTest, NoOAuth2RefreshToken) {
oauth2_service_->StartRequest(std::set<std::string>(), &consumer_));
message_loop_.RunUntilIdle();
- EXPECT_EQ(0, consumer_.number_of_correct_tokens_);
+ EXPECT_EQ(0, consumer_.number_of_successful_tokens_);
EXPECT_EQ(1, consumer_.number_of_errors_);
}
TEST_F(OAuth2TokenServiceTest, FailureShouldNotRetry) {
- service_->IssueAuthTokenForTest(GaiaConstants::kGaiaOAuth2LoginRefreshToken,
- "refreshToken");
- scoped_ptr<OAuth2TokenService::Request> request(oauth2_service_->StartRequest(
- std::set<std::string>(), &consumer_));
+ oauth2_service_->set_refresh_token("refreshToken");
+ scoped_ptr<OAuth2TokenService::Request> request(
+ oauth2_service_->StartRequest(std::set<std::string>(), &consumer_));
message_loop_.RunUntilIdle();
- EXPECT_EQ(0, consumer_.number_of_correct_tokens_);
+ EXPECT_EQ(0, consumer_.number_of_successful_tokens_);
EXPECT_EQ(0, consumer_.number_of_errors_);
net::TestURLFetcher* fetcher = factory_.GetFetcherByID(0);
EXPECT_TRUE(fetcher);
fetcher->set_response_code(net::HTTP_UNAUTHORIZED);
fetcher->SetResponseString(std::string());
fetcher->delegate()->OnURLFetchComplete(fetcher);
- EXPECT_EQ(0, consumer_.number_of_correct_tokens_);
+ EXPECT_EQ(0, consumer_.number_of_successful_tokens_);
EXPECT_EQ(1, consumer_.number_of_errors_);
EXPECT_EQ(fetcher, factory_.GetFetcherByID(0));
}
TEST_F(OAuth2TokenServiceTest, SuccessWithoutCaching) {
- service_->IssueAuthTokenForTest(GaiaConstants::kGaiaOAuth2LoginRefreshToken,
- "refreshToken");
- scoped_ptr<OAuth2TokenService::Request> request(oauth2_service_->StartRequest(
- std::set<std::string>(), &consumer_));
+ oauth2_service_->set_refresh_token("refreshToken");
+ scoped_ptr<OAuth2TokenService::Request> request(
+ oauth2_service_->StartRequest(std::set<std::string>(), &consumer_));
message_loop_.RunUntilIdle();
- EXPECT_EQ(0, consumer_.number_of_correct_tokens_);
+ EXPECT_EQ(0, consumer_.number_of_successful_tokens_);
EXPECT_EQ(0, consumer_.number_of_errors_);
net::TestURLFetcher* fetcher = factory_.GetFetcherByID(0);
EXPECT_TRUE(fetcher);
fetcher->set_response_code(net::HTTP_OK);
fetcher->SetResponseString(GetValidTokenResponse("token", 3600));
fetcher->delegate()->OnURLFetchComplete(fetcher);
- EXPECT_EQ(1, consumer_.number_of_correct_tokens_);
+ EXPECT_EQ(1, consumer_.number_of_successful_tokens_);
EXPECT_EQ(0, consumer_.number_of_errors_);
EXPECT_EQ("token", consumer_.last_token_);
}
@@ -174,22 +143,21 @@ TEST_F(OAuth2TokenServiceTest, SuccessWithCaching) {
std::set<std::string> scopes2;
scopes2.insert("s3");
- service_->IssueAuthTokenForTest(GaiaConstants::kGaiaOAuth2LoginRefreshToken,
- "refreshToken");
+ oauth2_service_->set_refresh_token("refreshToken");
// First request.
scoped_ptr<OAuth2TokenService::Request> request(oauth2_service_->StartRequest(
scopes1, &consumer_));
message_loop_.RunUntilIdle();
- EXPECT_EQ(0, consumer_.number_of_correct_tokens_);
+ EXPECT_EQ(0, consumer_.number_of_successful_tokens_);
EXPECT_EQ(0, consumer_.number_of_errors_);
net::TestURLFetcher* fetcher = factory_.GetFetcherByID(0);
EXPECT_TRUE(fetcher);
fetcher->set_response_code(net::HTTP_OK);
fetcher->SetResponseString(GetValidTokenResponse("token", 3600));
fetcher->delegate()->OnURLFetchComplete(fetcher);
- EXPECT_EQ(1, consumer_.number_of_correct_tokens_);
+ EXPECT_EQ(1, consumer_.number_of_successful_tokens_);
EXPECT_EQ(0, consumer_.number_of_errors_);
EXPECT_EQ("token", consumer_.last_token_);
@@ -201,7 +169,7 @@ TEST_F(OAuth2TokenServiceTest, SuccessWithCaching) {
// No new network fetcher.
EXPECT_EQ(fetcher, factory_.GetFetcherByID(0));
- EXPECT_EQ(2, consumer_.number_of_correct_tokens_);
+ EXPECT_EQ(2, consumer_.number_of_successful_tokens_);
EXPECT_EQ(0, consumer_.number_of_errors_);
EXPECT_EQ("token", consumer_.last_token_);
@@ -209,34 +177,33 @@ TEST_F(OAuth2TokenServiceTest, SuccessWithCaching) {
scoped_ptr<OAuth2TokenService::Request> request3(
oauth2_service_->StartRequest(scopes2, &consumer_));
message_loop_.RunUntilIdle();
- EXPECT_EQ(2, consumer_.number_of_correct_tokens_);
+ EXPECT_EQ(2, consumer_.number_of_successful_tokens_);
EXPECT_EQ(0, consumer_.number_of_errors_);
fetcher = factory_.GetFetcherByID(0);
EXPECT_TRUE(fetcher);
fetcher->set_response_code(net::HTTP_OK);
fetcher->SetResponseString(GetValidTokenResponse("token2", 3600));
fetcher->delegate()->OnURLFetchComplete(fetcher);
- EXPECT_EQ(3, consumer_.number_of_correct_tokens_);
+ EXPECT_EQ(3, consumer_.number_of_successful_tokens_);
EXPECT_EQ(0, consumer_.number_of_errors_);
EXPECT_EQ("token2", consumer_.last_token_);
}
TEST_F(OAuth2TokenServiceTest, SuccessAndExpirationAndFailure) {
- service_->IssueAuthTokenForTest(GaiaConstants::kGaiaOAuth2LoginRefreshToken,
- "refreshToken");
+ oauth2_service_->set_refresh_token("refreshToken");
// First request.
scoped_ptr<OAuth2TokenService::Request> request(oauth2_service_->StartRequest(
std::set<std::string>(), &consumer_));
message_loop_.RunUntilIdle();
- EXPECT_EQ(0, consumer_.number_of_correct_tokens_);
+ EXPECT_EQ(0, consumer_.number_of_successful_tokens_);
EXPECT_EQ(0, consumer_.number_of_errors_);
net::TestURLFetcher* fetcher = factory_.GetFetcherByID(0);
EXPECT_TRUE(fetcher);
fetcher->set_response_code(net::HTTP_OK);
fetcher->SetResponseString(GetValidTokenResponse("token", 0));
fetcher->delegate()->OnURLFetchComplete(fetcher);
- EXPECT_EQ(1, consumer_.number_of_correct_tokens_);
+ EXPECT_EQ(1, consumer_.number_of_successful_tokens_);
EXPECT_EQ(0, consumer_.number_of_errors_);
EXPECT_EQ("token", consumer_.last_token_);
@@ -244,7 +211,7 @@ TEST_F(OAuth2TokenServiceTest, SuccessAndExpirationAndFailure) {
scoped_ptr<OAuth2TokenService::Request> request2(
oauth2_service_->StartRequest(std::set<std::string>(), &consumer_));
message_loop_.RunUntilIdle();
- EXPECT_EQ(1, consumer_.number_of_correct_tokens_);
+ EXPECT_EQ(1, consumer_.number_of_successful_tokens_);
EXPECT_EQ(0, consumer_.number_of_errors_);
// Network failure.
@@ -253,26 +220,25 @@ TEST_F(OAuth2TokenServiceTest, SuccessAndExpirationAndFailure) {
fetcher->set_response_code(net::HTTP_UNAUTHORIZED);
fetcher->SetResponseString(std::string());
fetcher->delegate()->OnURLFetchComplete(fetcher);
- EXPECT_EQ(1, consumer_.number_of_correct_tokens_);
+ EXPECT_EQ(1, consumer_.number_of_successful_tokens_);
EXPECT_EQ(1, consumer_.number_of_errors_);
}
TEST_F(OAuth2TokenServiceTest, SuccessAndExpirationAndSuccess) {
- service_->IssueAuthTokenForTest(GaiaConstants::kGaiaOAuth2LoginRefreshToken,
- "refreshToken");
+ oauth2_service_->set_refresh_token("refreshToken");
// First request.
scoped_ptr<OAuth2TokenService::Request> request(oauth2_service_->StartRequest(
std::set<std::string>(), &consumer_));
message_loop_.RunUntilIdle();
- EXPECT_EQ(0, consumer_.number_of_correct_tokens_);
+ EXPECT_EQ(0, consumer_.number_of_successful_tokens_);
EXPECT_EQ(0, consumer_.number_of_errors_);
net::TestURLFetcher* fetcher = factory_.GetFetcherByID(0);
EXPECT_TRUE(fetcher);
fetcher->set_response_code(net::HTTP_OK);
fetcher->SetResponseString(GetValidTokenResponse("token", 0));
fetcher->delegate()->OnURLFetchComplete(fetcher);
- EXPECT_EQ(1, consumer_.number_of_correct_tokens_);
+ EXPECT_EQ(1, consumer_.number_of_successful_tokens_);
EXPECT_EQ(0, consumer_.number_of_errors_);
EXPECT_EQ("token", consumer_.last_token_);
@@ -280,7 +246,7 @@ TEST_F(OAuth2TokenServiceTest, SuccessAndExpirationAndSuccess) {
scoped_ptr<OAuth2TokenService::Request> request2(
oauth2_service_->StartRequest(std::set<std::string>(), &consumer_));
message_loop_.RunUntilIdle();
- EXPECT_EQ(1, consumer_.number_of_correct_tokens_);
+ EXPECT_EQ(1, consumer_.number_of_successful_tokens_);
EXPECT_EQ(0, consumer_.number_of_errors_);
fetcher = factory_.GetFetcherByID(0);
@@ -288,19 +254,18 @@ TEST_F(OAuth2TokenServiceTest, SuccessAndExpirationAndSuccess) {
fetcher->set_response_code(net::HTTP_OK);
fetcher->SetResponseString(GetValidTokenResponse("another token", 0));
fetcher->delegate()->OnURLFetchComplete(fetcher);
- EXPECT_EQ(2, consumer_.number_of_correct_tokens_);
+ EXPECT_EQ(2, consumer_.number_of_successful_tokens_);
EXPECT_EQ(0, consumer_.number_of_errors_);
EXPECT_EQ("another token", consumer_.last_token_);
}
TEST_F(OAuth2TokenServiceTest, RequestDeletedBeforeCompletion) {
- service_->IssueAuthTokenForTest(GaiaConstants::kGaiaOAuth2LoginRefreshToken,
- "refreshToken");
+ oauth2_service_->set_refresh_token("refreshToken");
scoped_ptr<OAuth2TokenService::Request> request(oauth2_service_->StartRequest(
std::set<std::string>(), &consumer_));
message_loop_.RunUntilIdle();
- EXPECT_EQ(0, consumer_.number_of_correct_tokens_);
+ EXPECT_EQ(0, consumer_.number_of_successful_tokens_);
EXPECT_EQ(0, consumer_.number_of_errors_);
net::TestURLFetcher* fetcher = factory_.GetFetcherByID(0);
EXPECT_TRUE(fetcher);
@@ -310,13 +275,12 @@ TEST_F(OAuth2TokenServiceTest, RequestDeletedBeforeCompletion) {
fetcher->set_response_code(net::HTTP_OK);
fetcher->SetResponseString(GetValidTokenResponse("token", 3600));
fetcher->delegate()->OnURLFetchComplete(fetcher);
- EXPECT_EQ(0, consumer_.number_of_correct_tokens_);
+ EXPECT_EQ(0, consumer_.number_of_successful_tokens_);
EXPECT_EQ(0, consumer_.number_of_errors_);
}
TEST_F(OAuth2TokenServiceTest, RequestDeletedAfterCompletion) {
- service_->IssueAuthTokenForTest(GaiaConstants::kGaiaOAuth2LoginRefreshToken,
- "refreshToken");
+ oauth2_service_->set_refresh_token("refreshToken");
scoped_ptr<OAuth2TokenService::Request> request(oauth2_service_->StartRequest(
std::set<std::string>(), &consumer_));
@@ -325,20 +289,19 @@ TEST_F(OAuth2TokenServiceTest, RequestDeletedAfterCompletion) {
fetcher->set_response_code(net::HTTP_OK);
fetcher->SetResponseString(GetValidTokenResponse("token", 3600));
fetcher->delegate()->OnURLFetchComplete(fetcher);
- EXPECT_EQ(1, consumer_.number_of_correct_tokens_);
+ EXPECT_EQ(1, consumer_.number_of_successful_tokens_);
EXPECT_EQ(0, consumer_.number_of_errors_);
EXPECT_EQ("token", consumer_.last_token_);
request.reset();
- EXPECT_EQ(1, consumer_.number_of_correct_tokens_);
+ EXPECT_EQ(1, consumer_.number_of_successful_tokens_);
EXPECT_EQ(0, consumer_.number_of_errors_);
EXPECT_EQ("token", consumer_.last_token_);
}
TEST_F(OAuth2TokenServiceTest, MultipleRequestsForTheSameScopesWithOneDeleted) {
- service_->IssueAuthTokenForTest(GaiaConstants::kGaiaOAuth2LoginRefreshToken,
- "refreshToken");
+ oauth2_service_->set_refresh_token("refreshToken");
scoped_ptr<OAuth2TokenService::Request> request(oauth2_service_->StartRequest(
std::set<std::string>(), &consumer_));
@@ -353,14 +316,13 @@ TEST_F(OAuth2TokenServiceTest, MultipleRequestsForTheSameScopesWithOneDeleted) {
fetcher->set_response_code(net::HTTP_OK);
fetcher->SetResponseString(GetValidTokenResponse("token", 3600));
fetcher->delegate()->OnURLFetchComplete(fetcher);
- EXPECT_EQ(1, consumer_.number_of_correct_tokens_);
+ EXPECT_EQ(1, consumer_.number_of_successful_tokens_);
EXPECT_EQ(0, consumer_.number_of_errors_);
}
-TEST_F(OAuth2TokenServiceTest, SuccessAndSignOutAndRequest) {
- service_->IssueAuthTokenForTest(GaiaConstants::kGaiaOAuth2LoginRefreshToken,
- "refreshToken");
-
+TEST_F(OAuth2TokenServiceTest, ClearedRefreshTokenFailsSubsequentRequests) {
+ // We have a valid refresh token; the first request is successful.
+ oauth2_service_->set_refresh_token("refreshToken");
scoped_ptr<OAuth2TokenService::Request> request(oauth2_service_->StartRequest(
std::set<std::string>(), &consumer_));
message_loop_.RunUntilIdle();
@@ -368,61 +330,22 @@ TEST_F(OAuth2TokenServiceTest, SuccessAndSignOutAndRequest) {
fetcher->set_response_code(net::HTTP_OK);
fetcher->SetResponseString(GetValidTokenResponse("token", 3600));
fetcher->delegate()->OnURLFetchComplete(fetcher);
- EXPECT_EQ(1, consumer_.number_of_correct_tokens_);
+ EXPECT_EQ(1, consumer_.number_of_successful_tokens_);
EXPECT_EQ(0, consumer_.number_of_errors_);
EXPECT_EQ("token", consumer_.last_token_);
- // Signs out
- service_->IssueAuthTokenForTest(GaiaConstants::kGaiaOAuth2LoginRefreshToken,
- std::string());
- service_->EraseTokensFromDB();
-
+ // The refresh token is no longer available; subsequent requests fail.
+ oauth2_service_->set_refresh_token("");
request = oauth2_service_->StartRequest(std::set<std::string>(), &consumer_);
message_loop_.RunUntilIdle();
EXPECT_EQ(fetcher, factory_.GetFetcherByID(0));
- EXPECT_EQ(1, consumer_.number_of_correct_tokens_);
+ EXPECT_EQ(1, consumer_.number_of_successful_tokens_);
EXPECT_EQ(1, consumer_.number_of_errors_);
}
-TEST_F(OAuth2TokenServiceTest, SuccessAndSignOutAndSignInAndSuccess) {
- service_->IssueAuthTokenForTest(GaiaConstants::kGaiaOAuth2LoginRefreshToken,
- "refreshToken");
- std::set<std::string> scopes;
- scopes.insert("s1");
- scopes.insert("s2");
-
- scoped_ptr<OAuth2TokenService::Request> request(oauth2_service_->StartRequest(
- scopes, &consumer_));
- message_loop_.RunUntilIdle();
- net::TestURLFetcher* fetcher = factory_.GetFetcherByID(0);
- fetcher->set_response_code(net::HTTP_OK);
- fetcher->SetResponseString(GetValidTokenResponse("token", 3600));
- fetcher->delegate()->OnURLFetchComplete(fetcher);
- EXPECT_EQ(1, consumer_.number_of_correct_tokens_);
- EXPECT_EQ(0, consumer_.number_of_errors_);
- EXPECT_EQ("token", consumer_.last_token_);
-
- // Signs out and signs in
- service_->IssueAuthTokenForTest(GaiaConstants::kGaiaOAuth2LoginRefreshToken,
- std::string());
- service_->EraseTokensFromDB();
- service_->IssueAuthTokenForTest(GaiaConstants::kGaiaOAuth2LoginRefreshToken,
- "refreshToken");
-
- request = oauth2_service_->StartRequest(scopes, &consumer_);
- message_loop_.RunUntilIdle();
- fetcher = factory_.GetFetcherByID(0);
- fetcher->set_response_code(net::HTTP_OK);
- fetcher->SetResponseString(GetValidTokenResponse("another token", 3600));
- fetcher->delegate()->OnURLFetchComplete(fetcher);
- EXPECT_EQ(2, consumer_.number_of_correct_tokens_);
- EXPECT_EQ(0, consumer_.number_of_errors_);
- EXPECT_EQ("another token", consumer_.last_token_);
-}
-
-TEST_F(OAuth2TokenServiceTest, PendingAndSignOutAndSignInAndSuccess) {
- service_->IssueAuthTokenForTest(GaiaConstants::kGaiaOAuth2LoginRefreshToken,
- "first refreshToken");
+TEST_F(OAuth2TokenServiceTest,
+ ChangedRefreshTokenDoesNotAffectInFlightRequests) {
+ oauth2_service_->set_refresh_token("first refreshToken");
std::set<std::string> scopes;
scopes.insert("s1");
scopes.insert("s2");
@@ -432,11 +355,11 @@ TEST_F(OAuth2TokenServiceTest, PendingAndSignOutAndSignInAndSuccess) {
message_loop_.RunUntilIdle();
net::TestURLFetcher* fetcher1 = factory_.GetFetcherByID(0);
- // Note |request| is still pending.
- service_->EraseTokensFromDB();
- service_->IssueAuthTokenForTest(GaiaConstants::kGaiaOAuth2LoginRefreshToken,
- "second refreshToken");
+ // Note |request| is still pending when the refresh token changes.
+ oauth2_service_->set_refresh_token("second refreshToken");
+ // A 2nd request (using the new refresh token) that occurs and completes
+ // while the 1st request is in flight is successful.
TestingOAuth2TokenServiceConsumer consumer2;
scoped_ptr<OAuth2TokenService::Request> request2(
oauth2_service_->StartRequest(scopes, &consumer2));
@@ -446,41 +369,40 @@ TEST_F(OAuth2TokenServiceTest, PendingAndSignOutAndSignInAndSuccess) {
fetcher2->set_response_code(net::HTTP_OK);
fetcher2->SetResponseString(GetValidTokenResponse("second token", 3600));
fetcher2->delegate()->OnURLFetchComplete(fetcher2);
- EXPECT_EQ(1, consumer2.number_of_correct_tokens_);
+ EXPECT_EQ(1, consumer2.number_of_successful_tokens_);
EXPECT_EQ(0, consumer2.number_of_errors_);
EXPECT_EQ("second token", consumer2.last_token_);
fetcher1->set_response_code(net::HTTP_OK);
fetcher1->SetResponseString(GetValidTokenResponse("first token", 3600));
fetcher1->delegate()->OnURLFetchComplete(fetcher1);
- EXPECT_EQ(1, consumer_.number_of_correct_tokens_);
+ EXPECT_EQ(1, consumer_.number_of_successful_tokens_);
EXPECT_EQ(0, consumer_.number_of_errors_);
EXPECT_EQ("first token", consumer_.last_token_);
}
TEST_F(OAuth2TokenServiceTest, ServiceShutDownBeforeFetchComplete) {
- service_->IssueAuthTokenForTest(GaiaConstants::kGaiaOAuth2LoginRefreshToken,
- "refreshToken");
+ oauth2_service_->set_refresh_token("refreshToken");
scoped_ptr<OAuth2TokenService::Request> request(oauth2_service_->StartRequest(
std::set<std::string>(), &consumer_));
message_loop_.RunUntilIdle();
- EXPECT_EQ(0, consumer_.number_of_correct_tokens_);
+ EXPECT_EQ(0, consumer_.number_of_successful_tokens_);
EXPECT_EQ(0, consumer_.number_of_errors_);
- profile_.reset();
+ // The destructor should cancel all in-flight fetchers.
+ oauth2_service_.reset(NULL);
- EXPECT_EQ(0, consumer_.number_of_correct_tokens_);
+ EXPECT_EQ(0, consumer_.number_of_successful_tokens_);
EXPECT_EQ(1, consumer_.number_of_errors_);
}
TEST_F(OAuth2TokenServiceTest, RetryingConsumer) {
- service_->IssueAuthTokenForTest(GaiaConstants::kGaiaOAuth2LoginRefreshToken,
- "refreshToken");
- RetryingTestingOAuth2TokenServiceConsumer consumer(oauth2_service_);
+ oauth2_service_->set_refresh_token("refreshToken");
+ RetryingTestingOAuth2TokenServiceConsumer consumer(oauth2_service_.get());
scoped_ptr<OAuth2TokenService::Request> request(oauth2_service_->StartRequest(
std::set<std::string>(), &consumer));
message_loop_.RunUntilIdle();
- EXPECT_EQ(0, consumer.number_of_correct_tokens_);
+ EXPECT_EQ(0, consumer.number_of_successful_tokens_);
EXPECT_EQ(0, consumer.number_of_errors_);
net::TestURLFetcher* fetcher = factory_.GetFetcherByID(0);
@@ -488,7 +410,7 @@ TEST_F(OAuth2TokenServiceTest, RetryingConsumer) {
fetcher->set_response_code(net::HTTP_UNAUTHORIZED);
fetcher->SetResponseString(std::string());
fetcher->delegate()->OnURLFetchComplete(fetcher);
- EXPECT_EQ(0, consumer.number_of_correct_tokens_);
+ EXPECT_EQ(0, consumer.number_of_successful_tokens_);
EXPECT_EQ(1, consumer.number_of_errors_);
fetcher = factory_.GetFetcherByID(0);
@@ -496,6 +418,6 @@ TEST_F(OAuth2TokenServiceTest, RetryingConsumer) {
fetcher->set_response_code(net::HTTP_UNAUTHORIZED);
fetcher->SetResponseString(std::string());
fetcher->delegate()->OnURLFetchComplete(fetcher);
- EXPECT_EQ(0, consumer.number_of_correct_tokens_);
+ EXPECT_EQ(0, consumer.number_of_successful_tokens_);
EXPECT_EQ(2, consumer.number_of_errors_);
}
diff --git a/chrome/browser/signin/profile_oauth2_token_service.cc b/chrome/browser/signin/profile_oauth2_token_service.cc
new file mode 100644
index 0000000..7d34b2d
--- /dev/null
+++ b/chrome/browser/signin/profile_oauth2_token_service.cc
@@ -0,0 +1,131 @@
+// Copyright 2013 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "chrome/browser/signin/profile_oauth2_token_service.h"
+
+#include "base/bind.h"
+#include "base/message_loop.h"
+#include "base/stl_util.h"
+#include "base/time.h"
+#include "chrome/browser/profiles/profile.h"
+#include "chrome/browser/signin/signin_manager.h"
+#include "chrome/browser/signin/signin_manager_factory.h"
+#include "chrome/browser/signin/token_service.h"
+#include "chrome/browser/signin/token_service_factory.h"
+#include "chrome/common/chrome_notification_types.h"
+#include "content/public/browser/browser_thread.h"
+#include "content/public/browser/notification_details.h"
+#include "content/public/browser/notification_source.h"
+#include "google_apis/gaia/gaia_constants.h"
+#include "google_apis/gaia/google_service_auth_error.h"
+#include "net/url_request/url_request_context_getter.h"
+
+ProfileOAuth2TokenService::ProfileOAuth2TokenService(
+ net::URLRequestContextGetter* getter)
+ : OAuth2TokenService(getter),
+ profile_(NULL),
+ last_auth_error_(GoogleServiceAuthError::NONE) {
+}
+
+ProfileOAuth2TokenService::~ProfileOAuth2TokenService() {
+}
+
+void ProfileOAuth2TokenService::Initialize(Profile* profile) {
+ DCHECK(content::BrowserThread::CurrentlyOn(content::BrowserThread::UI));
+
+ DCHECK(profile);
+ DCHECK(!profile_);
+ profile_ = profile;
+
+ content::Source<TokenService> token_service_source(
+ TokenServiceFactory::GetForProfile(profile));
+ registrar_.Add(this,
+ chrome::NOTIFICATION_TOKENS_CLEARED,
+ token_service_source);
+ registrar_.Add(this,
+ chrome::NOTIFICATION_TOKEN_AVAILABLE,
+ token_service_source);
+ SigninManagerFactory::GetForProfile(profile_)->signin_global_error()->
+ AddProvider(this);
+}
+
+void ProfileOAuth2TokenService::Shutdown() {
+ if (profile_) {
+ SigninManagerFactory::GetForProfile(profile_)->signin_global_error()->
+ RemoveProvider(this);
+ }
+}
+
+std::string ProfileOAuth2TokenService::GetRefreshToken() {
+ TokenService* token_service = TokenServiceFactory::GetForProfile(profile_);
+ if (!token_service || !token_service->HasOAuthLoginToken()) {
+ return std::string();
+ }
+ return token_service->GetOAuth2LoginRefreshToken();
+}
+
+void ProfileOAuth2TokenService::UpdateAuthError(
+ const GoogleServiceAuthError& error) {
+ // Do not report connection errors as these are not actually auth errors.
+ // We also want to avoid masking a "real" auth error just because we
+ // subsequently get a transient network error.
+ if (error.state() == GoogleServiceAuthError::CONNECTION_FAILED)
+ return;
+
+ if (error.state() != last_auth_error_.state()) {
+ last_auth_error_ = error;
+ SigninManagerFactory::GetForProfile(profile_)->signin_global_error()->
+ AuthStatusChanged();
+ }
+}
+
+void ProfileOAuth2TokenService::Observe(
+ int type,
+ const content::NotificationSource& source,
+ const content::NotificationDetails& details) {
+ DCHECK(type == chrome::NOTIFICATION_TOKENS_CLEARED ||
+ type == chrome::NOTIFICATION_TOKEN_AVAILABLE);
+ if (type == chrome::NOTIFICATION_TOKEN_AVAILABLE) {
+ TokenService::TokenAvailableDetails* tok_details =
+ content::Details<TokenService::TokenAvailableDetails>(details).ptr();
+ if (tok_details->service() != GaiaConstants::kGaiaOAuth2LoginRefreshToken)
+ return;
+ }
+ // The GaiaConstants::kGaiaOAuth2LoginRefreshToken token is used to create
+ // OAuth2 access tokens. If this token either changes or is cleared, any
+ // available tokens must be invalidated.
+ ClearCache();
+ UpdateAuthError(GoogleServiceAuthError::AuthErrorNone());
+}
+
+GoogleServiceAuthError ProfileOAuth2TokenService::GetAuthStatus() const {
+ return last_auth_error_;
+}
+
+void ProfileOAuth2TokenService::RegisterCacheEntry(
+ const std::string& refresh_token,
+ const ScopeSet& scopes,
+ const std::string& access_token,
+ const base::Time& expiration_date) {
+ if (ShouldCacheForRefreshToken(TokenServiceFactory::GetForProfile(profile_),
+ refresh_token)) {
+ OAuth2TokenService::RegisterCacheEntry(refresh_token,
+ scopes,
+ access_token,
+ expiration_date);
+ }
+}
+
+bool ProfileOAuth2TokenService::ShouldCacheForRefreshToken(
+ TokenService *token_service,
+ const std::string& refresh_token) {
+ if (!token_service ||
+ !token_service->HasOAuthLoginToken() ||
+ token_service->GetOAuth2LoginRefreshToken().compare(refresh_token) != 0) {
+ DLOG(INFO) <<
+ "Received a token with a refresh token not maintained by TokenService.";
+ return false;
+ }
+ return true;
+}
diff --git a/chrome/browser/signin/profile_oauth2_token_service.h b/chrome/browser/signin/profile_oauth2_token_service.h
new file mode 100644
index 0000000..8804b6f
--- /dev/null
+++ b/chrome/browser/signin/profile_oauth2_token_service.h
@@ -0,0 +1,101 @@
+// Copyright 2013 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef CHROME_BROWSER_SIGNIN_PROFILE_OAUTH2_TOKEN_SERVICE_H_
+#define CHROME_BROWSER_SIGNIN_PROFILE_OAUTH2_TOKEN_SERVICE_H_
+
+#include <string>
+
+#include "base/gtest_prod_util.h"
+#include "chrome/browser/profiles/profile_keyed_service.h"
+#include "chrome/browser/signin/oauth2_token_service.h"
+#include "chrome/browser/signin/signin_global_error.h"
+#include "content/public/browser/notification_observer.h"
+#include "content/public/browser/notification_registrar.h"
+
+namespace net {
+class URLRequestContextGetter;
+}
+
+class GoogleServiceAuthError;
+class Profile;
+class TokenService;
+
+// ProfileOAuth2TokenService is a ProfileKeyedService that retrieves
+// OAuth2 access tokens for a given set of scopes using the OAuth2 login
+// refresh token maintained by TokenService.
+//
+// See |OAuth2TokenService| for usage details.
+//
+// Note: after StartRequest returns, in-flight requests will continue
+// even if the TokenService refresh token that was used to initiate
+// the request changes or is cleared. When the request completes,
+// Consumer::OnGetTokenSuccess will be invoked, but the access token
+// won't be cached.
+//
+// Note: requests should be started from the UI thread. To start a
+// request from other thread, please use ProfileOAuth2TokenServiceRequest.
+class ProfileOAuth2TokenService : public OAuth2TokenService,
+ public content::NotificationObserver,
+ public SigninGlobalError::AuthStatusProvider,
+ public ProfileKeyedService {
+ public:
+ // content::NotificationObserver listening for TokenService updates.
+ virtual void Observe(int type,
+ const content::NotificationSource& source,
+ const content::NotificationDetails& details) OVERRIDE;
+
+ // Initializes this token service with the profile.
+ virtual void Initialize(Profile* profile);
+
+ // ProfileKeyedService implementation.
+ virtual void Shutdown() OVERRIDE;
+
+ // SigninGlobalError::AuthStatusProvider implementation.
+ virtual GoogleServiceAuthError GetAuthStatus() const OVERRIDE;
+
+ // Takes injected TokenService for testing.
+ bool ShouldCacheForRefreshToken(TokenService *token_service,
+ const std::string& refresh_token);
+
+ protected:
+ friend class ProfileOAuth2TokenServiceFactory;
+ explicit ProfileOAuth2TokenService(net::URLRequestContextGetter* getter);
+ virtual ~ProfileOAuth2TokenService();
+
+ virtual std::string GetRefreshToken() OVERRIDE;
+
+ // Updates the internal cache of the result from the most-recently-completed
+ // auth request (used for reporting errors to the user).
+ virtual void UpdateAuthError(const GoogleServiceAuthError& error) OVERRIDE;
+
+ // Overridden to not cache tokens if the TokenService refresh token
+ // changes while a token fetch is in-flight. If the user logs out and
+ // logs back in with a different account, then any in-flight token
+ // fetches will be for the old account's refresh token. Therefore
+ // when they come back, they shouldn't be cached.
+ virtual void RegisterCacheEntry(const std::string& refresh_token,
+ const ScopeSet& scopes,
+ const std::string& access_token,
+ const base::Time& expiration_date) OVERRIDE;
+
+ private:
+ FRIEND_TEST_ALL_PREFIXES(ProfileOAuth2TokenServiceTest,
+ StaleRefreshTokensNotCached);
+ FRIEND_TEST_ALL_PREFIXES(ProfileOAuth2TokenServiceTest,
+ TokenServiceUpdateClearsCache);
+
+ // The profile with which this instance was initialized, or NULL.
+ Profile* profile_;
+
+ // The auth status from the most-recently-completed request.
+ GoogleServiceAuthError last_auth_error_;
+
+ // Registrar for notifications from the TokenService.
+ content::NotificationRegistrar registrar_;
+
+ DISALLOW_COPY_AND_ASSIGN(ProfileOAuth2TokenService);
+};
+
+#endif // CHROME_BROWSER_SIGNIN_PROFILE_OAUTH2_TOKEN_SERVICE_H_
diff --git a/chrome/browser/signin/profile_oauth2_token_service_factory.cc b/chrome/browser/signin/profile_oauth2_token_service_factory.cc
new file mode 100644
index 0000000..f9fb647
--- /dev/null
+++ b/chrome/browser/signin/profile_oauth2_token_service_factory.cc
@@ -0,0 +1,50 @@
+// Copyright (c) 2012 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "chrome/browser/signin/profile_oauth2_token_service_factory.h"
+
+#include "chrome/browser/profiles/profile.h"
+#include "chrome/browser/profiles/profile_dependency_manager.h"
+#include "chrome/browser/signin/profile_oauth2_token_service.h"
+#include "chrome/browser/signin/signin_manager_factory.h"
+#include "chrome/browser/signin/token_service_factory.h"
+
+#if defined(OS_ANDROID)
+#include "chrome/browser/signin/android_profile_oauth2_token_service.h"
+#endif
+
+ProfileOAuth2TokenServiceFactory::ProfileOAuth2TokenServiceFactory()
+ : ProfileKeyedServiceFactory("ProfileOAuth2TokenService",
+ ProfileDependencyManager::GetInstance()) {
+ DependsOn(SigninManagerFactory::GetInstance());
+ DependsOn(TokenServiceFactory::GetInstance());
+}
+
+ProfileOAuth2TokenServiceFactory::~ProfileOAuth2TokenServiceFactory() {
+}
+
+// static
+ProfileOAuth2TokenService* ProfileOAuth2TokenServiceFactory::GetForProfile(
+ Profile* profile) {
+ return static_cast<ProfileOAuth2TokenService*>(
+ GetInstance()->GetServiceForProfile(profile, true));
+}
+
+// static
+ProfileOAuth2TokenServiceFactory*
+ ProfileOAuth2TokenServiceFactory::GetInstance() {
+ return Singleton<ProfileOAuth2TokenServiceFactory>::get();
+}
+
+ProfileKeyedService* ProfileOAuth2TokenServiceFactory::BuildServiceInstanceFor(
+ Profile* profile) const {
+ ProfileOAuth2TokenService* service;
+#if defined(OS_ANDROID)
+ service = new AndroidProfileOAuth2TokenService(profile->GetRequestContext());
+#else
+ service = new ProfileOAuth2TokenService(profile->GetRequestContext());
+#endif
+ service->Initialize(profile);
+ return service;
+}
diff --git a/chrome/browser/signin/profile_oauth2_token_service_factory.h b/chrome/browser/signin/profile_oauth2_token_service_factory.h
new file mode 100644
index 0000000..a63e6db
--- /dev/null
+++ b/chrome/browser/signin/profile_oauth2_token_service_factory.h
@@ -0,0 +1,42 @@
+// Copyright 2012 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef CHROME_BROWSER_SIGNIN_PROFILE_OAUTH2_TOKEN_SERVICE_FACTORY_H_
+#define CHROME_BROWSER_SIGNIN_PROFILE_OAUTH2_TOKEN_SERVICE_FACTORY_H_
+
+#include "base/memory/singleton.h"
+#include "chrome/browser/profiles/profile_keyed_service_factory.h"
+
+class ProfileOAuth2TokenService;
+class Profile;
+
+// Singleton that owns all ProfileOAuth2TokenServices and associates them with
+// Profiles. Listens for the Profile's destruction notification and cleans up
+// the associated ProfileOAuth2TokenService.
+class ProfileOAuth2TokenServiceFactory : public ProfileKeyedServiceFactory {
+ public:
+ // Returns the instance of ProfileOAuth2TokenService associated with this
+ // profile (creating one if none exists). Returns NULL if this profile
+ // cannot have a ProfileOAuth2TokenService (for example, if |profile| is
+ // incognito). On Android, returns the AndroidProfileOAuth2TokenService
+ // specialization.
+ static ProfileOAuth2TokenService* GetForProfile(Profile* profile);
+
+ // Returns an instance of the ProfileOAuth2TokenServiceFactory singleton.
+ static ProfileOAuth2TokenServiceFactory* GetInstance();
+
+ private:
+ friend struct DefaultSingletonTraits<ProfileOAuth2TokenServiceFactory>;
+
+ ProfileOAuth2TokenServiceFactory();
+ virtual ~ProfileOAuth2TokenServiceFactory();
+
+ // ProfileKeyedServiceFactory implementation.
+ virtual ProfileKeyedService* BuildServiceInstanceFor(
+ Profile* profile) const OVERRIDE;
+
+ DISALLOW_COPY_AND_ASSIGN(ProfileOAuth2TokenServiceFactory);
+};
+
+#endif // CHROME_BROWSER_SIGNIN_PROFILE_OAUTH2_TOKEN_SERVICE_FACTORY_H_
diff --git a/chrome/browser/signin/oauth2_token_service_request.cc b/chrome/browser/signin/profile_oauth2_token_service_request.cc
index aad3ca4..753c2e4 100644
--- a/chrome/browser/signin/oauth2_token_service_request.cc
+++ b/chrome/browser/signin/profile_oauth2_token_service_request.cc
@@ -2,7 +2,7 @@
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
-#include "chrome/browser/signin/oauth2_token_service_request.h"
+#include "chrome/browser/signin/profile_oauth2_token_service_request.h"
#include "base/bind.h"
#include "base/memory/ref_counted.h"
@@ -10,20 +10,20 @@
#include "base/single_thread_task_runner.h"
#include "base/thread_task_runner_handle.h"
#include "chrome/browser/profiles/profile.h"
-#include "chrome/browser/signin/oauth2_token_service.h"
-#include "chrome/browser/signin/oauth2_token_service_factory.h"
+#include "chrome/browser/signin/profile_oauth2_token_service.h"
+#include "chrome/browser/signin/profile_oauth2_token_service_factory.h"
#include "content/public/browser/browser_thread.h"
#include "google_apis/gaia/google_service_auth_error.h"
#include "google_apis/gaia/oauth2_access_token_consumer.h"
-class OAuth2TokenServiceRequest::Core
- : public base::RefCountedThreadSafe<OAuth2TokenServiceRequest::Core>,
+class ProfileOAuth2TokenServiceRequest::Core
+ : public base::RefCountedThreadSafe<ProfileOAuth2TokenServiceRequest::Core>,
public OAuth2TokenService::Consumer {
public:
// Note the thread where an instance of Core is constructed is referred to as
// the "owner thread" here. This will be the thread of |owner_task_runner_|.
Core(Profile* profile,
- OAuth2TokenServiceRequest* owner);
+ ProfileOAuth2TokenServiceRequest* owner);
// Starts fetching an OAuth2 access token for |scopes|. It should be called
// on the owner thread.
void Start(const OAuth2TokenService::ScopeSet& scopes);
@@ -39,7 +39,8 @@ class OAuth2TokenServiceRequest::Core
const GoogleServiceAuthError& error) OVERRIDE;
private:
- friend class base::RefCountedThreadSafe<OAuth2TokenServiceRequest::Core>;
+ friend class
+ base::RefCountedThreadSafe<ProfileOAuth2TokenServiceRequest::Core>;
// Note this can be destructed on the owner thread or on the UI thread,
// depending on the reference count.
@@ -62,7 +63,7 @@ class OAuth2TokenServiceRequest::Core
// The object to call back when fetching completes. |owner_| should be
// called back only on the owner thread.
- OAuth2TokenServiceRequest* owner_;
+ ProfileOAuth2TokenServiceRequest* owner_;
// Task runner on which |owner_| should be called back.
scoped_refptr<base::SingleThreadTaskRunner> owner_task_runner_;
@@ -73,9 +74,9 @@ class OAuth2TokenServiceRequest::Core
DISALLOW_COPY_AND_ASSIGN(Core);
};
-OAuth2TokenServiceRequest::Core::Core(
+ProfileOAuth2TokenServiceRequest::Core::Core(
Profile* profile,
- OAuth2TokenServiceRequest* owner)
+ ProfileOAuth2TokenServiceRequest* owner)
: profile_(profile),
owner_(owner),
owner_task_runner_(base::ThreadTaskRunnerHandle::Get()) {
@@ -83,10 +84,10 @@ OAuth2TokenServiceRequest::Core::Core(
DCHECK(owner);
}
-OAuth2TokenServiceRequest::Core::~Core() {
+ProfileOAuth2TokenServiceRequest::Core::~Core() {
}
-void OAuth2TokenServiceRequest::Core::Start(
+void ProfileOAuth2TokenServiceRequest::Core::Start(
const OAuth2TokenService::ScopeSet& scopes) {
DCHECK(owner_task_runner_->BelongsToCurrentThread());
@@ -96,12 +97,12 @@ void OAuth2TokenServiceRequest::Core::Start(
content::BrowserThread::PostTask(
content::BrowserThread::UI,
FROM_HERE,
- base::Bind(&OAuth2TokenServiceRequest::Core::StartOnUIThread,
+ base::Bind(&ProfileOAuth2TokenServiceRequest::Core::StartOnUIThread,
this, scopes));
}
}
-void OAuth2TokenServiceRequest::Core::Stop() {
+void ProfileOAuth2TokenServiceRequest::Core::Stop() {
DCHECK(owner_task_runner_->BelongsToCurrentThread());
// Detaches |owner_| from this instance so |owner_| will be called back only
@@ -113,49 +114,53 @@ void OAuth2TokenServiceRequest::Core::Stop() {
content::BrowserThread::PostTask(
content::BrowserThread::UI,
FROM_HERE,
- base::Bind(&OAuth2TokenServiceRequest::Core::StopOnUIThread, this));
+ base::Bind(&ProfileOAuth2TokenServiceRequest::Core::StopOnUIThread,
+ this));
}
}
-void OAuth2TokenServiceRequest::Core::StopOnUIThread() {
+void ProfileOAuth2TokenServiceRequest::Core::StopOnUIThread() {
DCHECK(content::BrowserThread::CurrentlyOn(content::BrowserThread::UI));
request_.reset();
}
-void OAuth2TokenServiceRequest::Core::StartOnUIThread(
+void ProfileOAuth2TokenServiceRequest::Core::StartOnUIThread(
const OAuth2TokenService::ScopeSet& scopes) {
DCHECK(content::BrowserThread::CurrentlyOn(content::BrowserThread::UI));
- OAuth2TokenService* service = OAuth2TokenServiceFactory::GetForProfile(
- profile_);
+ ProfileOAuth2TokenService* service =
+ ProfileOAuth2TokenServiceFactory::GetForProfile(profile_);
DCHECK(service);
request_.reset(service->StartRequest(scopes, this).release());
}
-void OAuth2TokenServiceRequest::Core::OnGetTokenSuccess(
+void ProfileOAuth2TokenServiceRequest::Core::OnGetTokenSuccess(
const OAuth2TokenService::Request* request,
const std::string& access_token,
const base::Time& expiration_time) {
DCHECK(content::BrowserThread::CurrentlyOn(content::BrowserThread::UI));
DCHECK_EQ(request_.get(), request);
owner_task_runner_->PostTask(FROM_HERE, base::Bind(
- &OAuth2TokenServiceRequest::Core::InformOwnerOnGetTokenSuccess, this,
- access_token, expiration_time));
+ &ProfileOAuth2TokenServiceRequest::Core::InformOwnerOnGetTokenSuccess,
+ this,
+ access_token,
+ expiration_time));
request_.reset();
}
-void OAuth2TokenServiceRequest::Core::OnGetTokenFailure(
+void ProfileOAuth2TokenServiceRequest::Core::OnGetTokenFailure(
const OAuth2TokenService::Request* request,
const GoogleServiceAuthError& error) {
DCHECK(content::BrowserThread::CurrentlyOn(content::BrowserThread::UI));
DCHECK_EQ(request_.get(), request);
owner_task_runner_->PostTask(FROM_HERE, base::Bind(
- &OAuth2TokenServiceRequest::Core::InformOwnerOnGetTokenFailure, this,
+ &ProfileOAuth2TokenServiceRequest::Core::InformOwnerOnGetTokenFailure,
+ this,
error));
request_.reset();
}
-void OAuth2TokenServiceRequest::Core::InformOwnerOnGetTokenSuccess(
+void ProfileOAuth2TokenServiceRequest::Core::InformOwnerOnGetTokenSuccess(
std::string access_token,
base::Time expiration_time) {
DCHECK(owner_task_runner_->BelongsToCurrentThread());
@@ -164,7 +169,7 @@ void OAuth2TokenServiceRequest::Core::InformOwnerOnGetTokenSuccess(
owner_->consumer_->OnGetTokenSuccess(owner_, access_token, expiration_time);
}
-void OAuth2TokenServiceRequest::Core::InformOwnerOnGetTokenFailure(
+void ProfileOAuth2TokenServiceRequest::Core::InformOwnerOnGetTokenFailure(
GoogleServiceAuthError error) {
DCHECK(owner_task_runner_->BelongsToCurrentThread());
@@ -173,14 +178,15 @@ void OAuth2TokenServiceRequest::Core::InformOwnerOnGetTokenFailure(
}
// static
-OAuth2TokenServiceRequest* OAuth2TokenServiceRequest::CreateAndStart(
- Profile* profile,
- const OAuth2TokenService::ScopeSet& scopes,
- OAuth2TokenService::Consumer* consumer) {
- return new OAuth2TokenServiceRequest(profile, scopes, consumer);
+ProfileOAuth2TokenServiceRequest*
+ ProfileOAuth2TokenServiceRequest::CreateAndStart(
+ Profile* profile,
+ const OAuth2TokenService::ScopeSet& scopes,
+ OAuth2TokenService::Consumer* consumer) {
+ return new ProfileOAuth2TokenServiceRequest(profile, scopes, consumer);
}
-OAuth2TokenServiceRequest::OAuth2TokenServiceRequest(
+ProfileOAuth2TokenServiceRequest::ProfileOAuth2TokenServiceRequest(
Profile* profile,
const OAuth2TokenService::ScopeSet& scopes,
OAuth2TokenService::Consumer* consumer)
@@ -189,7 +195,7 @@ OAuth2TokenServiceRequest::OAuth2TokenServiceRequest(
core_->Start(scopes);
}
-OAuth2TokenServiceRequest::~OAuth2TokenServiceRequest() {
+ProfileOAuth2TokenServiceRequest::~ProfileOAuth2TokenServiceRequest() {
DCHECK(CalledOnValidThread());
core_->Stop();
}
diff --git a/chrome/browser/signin/profile_oauth2_token_service_request.h b/chrome/browser/signin/profile_oauth2_token_service_request.h
new file mode 100644
index 0000000..bcb1ff8
--- /dev/null
+++ b/chrome/browser/signin/profile_oauth2_token_service_request.h
@@ -0,0 +1,47 @@
+// Copyright 2012 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef CHROME_BROWSER_SIGNIN_PROFILE_OAUTH2_TOKEN_SERVICE_REQUEST_H_
+#define CHROME_BROWSER_SIGNIN_PROFILE_OAUTH2_TOKEN_SERVICE_REQUEST_H_
+
+#include <set>
+#include <string>
+
+#include "base/threading/non_thread_safe.h"
+#include "chrome/browser/signin/oauth2_token_service.h"
+
+class Profile;
+
+// ProfileOAuth2TokenServiceRequest represents a request to fetch an
+// OAuth2 access token for a given set of |scopes| by calling |profile|'s
+// ProfileOAuth2TokenService. A request can be created and started from
+// any thread with an object |consumer| that will be called back on the
+// same thread when fetching completes. If the request is destructed
+// before |consumer| is called, |consumer| will never be called back. (Note
+// the actual network activities are not canceled and the cache in
+// ProfileOAuth2TokenService will be populated with the fetched results.)
+class ProfileOAuth2TokenServiceRequest : public OAuth2TokenService::Request,
+ public base::NonThreadSafe {
+ public:
+ static ProfileOAuth2TokenServiceRequest* CreateAndStart(
+ Profile* profile,
+ const OAuth2TokenService::ScopeSet& scopes,
+ OAuth2TokenService::Consumer* consumer);
+
+ virtual ~ProfileOAuth2TokenServiceRequest();
+
+ private:
+ class Core;
+ friend class Core;
+
+ ProfileOAuth2TokenServiceRequest(Profile* profile,
+ const OAuth2TokenService::ScopeSet& scopes,
+ OAuth2TokenService::Consumer* consumer);
+ OAuth2TokenService::Consumer* const consumer_;
+ scoped_refptr<Core> core_;
+
+ DISALLOW_COPY_AND_ASSIGN(ProfileOAuth2TokenServiceRequest);
+};
+
+#endif // CHROME_BROWSER_SIGNIN_PROFILE_OAUTH2_TOKEN_SERVICE_REQUEST_H_
diff --git a/chrome/browser/signin/oauth2_token_service_request_unittest.cc b/chrome/browser/signin/profile_oauth2_token_service_request_unittest.cc
index 83b92a1..184c7b2 100644
--- a/chrome/browser/signin/oauth2_token_service_request_unittest.cc
+++ b/chrome/browser/signin/profile_oauth2_token_service_request_unittest.cc
@@ -1,14 +1,15 @@
// Copyright 2012 The Chromium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
-#include "chrome/browser/signin/oauth2_token_service_request.h"
+#include "chrome/browser/signin/profile_oauth2_token_service_request.h"
#include <set>
#include <string>
#include <vector>
#include "base/threading/thread.h"
#include "chrome/browser/signin/oauth2_token_service.h"
-#include "chrome/browser/signin/oauth2_token_service_factory.h"
+#include "chrome/browser/signin/profile_oauth2_token_service.h"
+#include "chrome/browser/signin/profile_oauth2_token_service_factory.h"
#include "chrome/browser/signin/token_service_factory.h"
#include "chrome/test/base/testing_profile.h"
#include "content/public/test/test_browser_thread.h"
@@ -29,13 +30,13 @@ class TestingOAuth2TokenServiceConsumer : public OAuth2TokenService::Consumer {
const GoogleServiceAuthError& error) OVERRIDE;
std::string last_token_;
- int number_of_correct_tokens_;
+ int number_of_successful_tokens_;
GoogleServiceAuthError last_error_;
int number_of_errors_;
};
TestingOAuth2TokenServiceConsumer::TestingOAuth2TokenServiceConsumer()
- : number_of_correct_tokens_(0),
+ : number_of_successful_tokens_(0),
last_error_(GoogleServiceAuthError::AuthErrorNone()),
number_of_errors_(0) {
}
@@ -48,7 +49,7 @@ void TestingOAuth2TokenServiceConsumer::OnGetTokenSuccess(
const std::string& token,
const base::Time& expiration_date) {
last_token_ = token;
- ++number_of_correct_tokens_;
+ ++number_of_successful_tokens_;
}
void TestingOAuth2TokenServiceConsumer::OnGetTokenFailure(
@@ -58,7 +59,7 @@ void TestingOAuth2TokenServiceConsumer::OnGetTokenFailure(
++number_of_errors_;
}
-class MockOAuth2TokenService : public OAuth2TokenService {
+class MockProfileOAuth2TokenService : public ProfileOAuth2TokenService {
public:
class Request : public OAuth2TokenService::Request,
public base::SupportsWeakPtr<Request> {
@@ -77,8 +78,8 @@ class MockOAuth2TokenService : public OAuth2TokenService {
base::Time expiration_date_;
};
- MockOAuth2TokenService();
- virtual ~MockOAuth2TokenService();
+ MockProfileOAuth2TokenService();
+ virtual ~MockProfileOAuth2TokenService();
virtual scoped_ptr<OAuth2TokenService::Request> StartRequest(
const std::set<std::string>& scopes,
@@ -88,13 +89,13 @@ class MockOAuth2TokenService : public OAuth2TokenService {
private:
static void InformConsumer(
- base::WeakPtr<MockOAuth2TokenService::Request> request);
+ base::WeakPtr<MockProfileOAuth2TokenService::Request> request);
bool success_;
std::string oauth2_access_token_;
};
-MockOAuth2TokenService::Request::Request(
+MockProfileOAuth2TokenService::Request::Request(
OAuth2TokenService::Consumer* consumer,
GoogleServiceAuthError error,
std::string access_token)
@@ -103,62 +104,64 @@ MockOAuth2TokenService::Request::Request(
access_token_(access_token) {
}
-MockOAuth2TokenService::Request::~Request() {
+MockProfileOAuth2TokenService::Request::~Request() {
}
-void MockOAuth2TokenService::Request::InformConsumer() const {
+void MockProfileOAuth2TokenService::Request::InformConsumer() const {
if (error_.state() == GoogleServiceAuthError::NONE)
consumer_->OnGetTokenSuccess(this, access_token_, expiration_date_);
else
consumer_->OnGetTokenFailure(this, error_);
}
-MockOAuth2TokenService::MockOAuth2TokenService()
- : success_(true),
+MockProfileOAuth2TokenService::MockProfileOAuth2TokenService()
+ : ProfileOAuth2TokenService(NULL /* URLRequestContextGetter */),
+ success_(true),
oauth2_access_token_(std::string("success token")) {
}
-MockOAuth2TokenService::~MockOAuth2TokenService() {
+MockProfileOAuth2TokenService::~MockProfileOAuth2TokenService() {
}
-void MockOAuth2TokenService::SetExpectation(bool success,
+void MockProfileOAuth2TokenService::SetExpectation(bool success,
std::string oauth2_access_token) {
success_ = success;
oauth2_access_token_ = oauth2_access_token;
}
// static
-void MockOAuth2TokenService::InformConsumer(
- base::WeakPtr<MockOAuth2TokenService::Request> request) {
+void MockProfileOAuth2TokenService::InformConsumer(
+ base::WeakPtr<MockProfileOAuth2TokenService::Request> request) {
if (request)
request->InformConsumer();
}
-scoped_ptr<OAuth2TokenService::Request> MockOAuth2TokenService::StartRequest(
- const std::set<std::string>& scopes,
- OAuth2TokenService::Consumer* consumer) {
+scoped_ptr<OAuth2TokenService::Request>
+ MockProfileOAuth2TokenService::StartRequest(
+ const std::set<std::string>& scopes,
+ OAuth2TokenService::Consumer* consumer) {
scoped_ptr<Request> request;
if (success_) {
- request.reset(new MockOAuth2TokenService::Request(
+ request.reset(new MockProfileOAuth2TokenService::Request(
consumer,
GoogleServiceAuthError(GoogleServiceAuthError::NONE),
oauth2_access_token_));
} else {
- request.reset(new MockOAuth2TokenService::Request(
+ request.reset(new MockProfileOAuth2TokenService::Request(
consumer,
GoogleServiceAuthError(GoogleServiceAuthError::SERVICE_UNAVAILABLE),
std::string()));
}
MessageLoop::current()->PostTask(FROM_HERE, base::Bind(
- &MockOAuth2TokenService::InformConsumer, request->AsWeakPtr()));
+ &MockProfileOAuth2TokenService::InformConsumer, request->AsWeakPtr()));
return request.PassAs<OAuth2TokenService::Request>();
}
static ProfileKeyedService* CreateOAuth2TokenService(Profile* profile) {
- return new MockOAuth2TokenService();
+ return new MockProfileOAuth2TokenService();
}
-class OAuth2TokenServiceRequestTest : public testing::Test {
+class ProfileOAuth2TokenServiceRequestTest : public testing::Test {
public:
virtual void SetUp() OVERRIDE;
@@ -168,70 +171,70 @@ class OAuth2TokenServiceRequestTest : public testing::Test {
scoped_ptr<Profile> profile_;
TestingOAuth2TokenServiceConsumer consumer_;
- MockOAuth2TokenService* oauth2_service_;
+ MockProfileOAuth2TokenService* oauth2_service_;
- scoped_ptr<OAuth2TokenServiceRequest> request_;
+ scoped_ptr<ProfileOAuth2TokenServiceRequest> request_;
};
-void OAuth2TokenServiceRequestTest::SetUp() {
+void ProfileOAuth2TokenServiceRequestTest::SetUp() {
ui_thread_.reset(new content::TestBrowserThread(content::BrowserThread::UI,
&ui_loop_));
profile_.reset(new TestingProfile());
- OAuth2TokenServiceFactory::GetInstance()->SetTestingFactory(
+ ProfileOAuth2TokenServiceFactory::GetInstance()->SetTestingFactory(
profile_.get(), &CreateOAuth2TokenService);
- oauth2_service_ = (MockOAuth2TokenService*)
- OAuth2TokenServiceFactory::GetForProfile(profile_.get());
+ oauth2_service_ = (MockProfileOAuth2TokenService*)
+ ProfileOAuth2TokenServiceFactory::GetForProfile(profile_.get());
}
-TEST_F(OAuth2TokenServiceRequestTest,
+TEST_F(ProfileOAuth2TokenServiceRequestTest,
Failure) {
oauth2_service_->SetExpectation(false, std::string());
- scoped_ptr<OAuth2TokenServiceRequest> request(
- OAuth2TokenServiceRequest::CreateAndStart(
+ scoped_ptr<ProfileOAuth2TokenServiceRequest> request(
+ ProfileOAuth2TokenServiceRequest::CreateAndStart(
profile_.get(),
std::set<std::string>(),
&consumer_));
ui_loop_.RunUntilIdle();
- EXPECT_EQ(0, consumer_.number_of_correct_tokens_);
+ EXPECT_EQ(0, consumer_.number_of_successful_tokens_);
EXPECT_EQ(1, consumer_.number_of_errors_);
}
-TEST_F(OAuth2TokenServiceRequestTest,
+TEST_F(ProfileOAuth2TokenServiceRequestTest,
Success) {
- scoped_ptr<OAuth2TokenServiceRequest> request(
- OAuth2TokenServiceRequest::CreateAndStart(
+ scoped_ptr<ProfileOAuth2TokenServiceRequest> request(
+ ProfileOAuth2TokenServiceRequest::CreateAndStart(
profile_.get(),
std::set<std::string>(),
&consumer_));
ui_loop_.RunUntilIdle();
- EXPECT_EQ(1, consumer_.number_of_correct_tokens_);
+ EXPECT_EQ(1, consumer_.number_of_successful_tokens_);
EXPECT_EQ("success token", consumer_.last_token_);
EXPECT_EQ(0, consumer_.number_of_errors_);
}
-TEST_F(OAuth2TokenServiceRequestTest,
+TEST_F(ProfileOAuth2TokenServiceRequestTest,
RequestDeletionBeforeServiceComplete) {
- scoped_ptr<OAuth2TokenServiceRequest> request(
- OAuth2TokenServiceRequest::CreateAndStart(
+ scoped_ptr<ProfileOAuth2TokenServiceRequest> request(
+ ProfileOAuth2TokenServiceRequest::CreateAndStart(
profile_.get(),
std::set<std::string>(),
&consumer_));
request.reset();
ui_loop_.RunUntilIdle();
- EXPECT_EQ(0, consumer_.number_of_correct_tokens_);
+ EXPECT_EQ(0, consumer_.number_of_successful_tokens_);
EXPECT_EQ(0, consumer_.number_of_errors_);
}
-TEST_F(OAuth2TokenServiceRequestTest,
+TEST_F(ProfileOAuth2TokenServiceRequestTest,
RequestDeletionAfterServiceComplete) {
- scoped_ptr<OAuth2TokenServiceRequest> request(
- OAuth2TokenServiceRequest::CreateAndStart(
+ scoped_ptr<ProfileOAuth2TokenServiceRequest> request(
+ ProfileOAuth2TokenServiceRequest::CreateAndStart(
profile_.get(),
std::set<std::string>(),
&consumer_));
ui_loop_.RunUntilIdle();
request.reset();
- EXPECT_EQ(1, consumer_.number_of_correct_tokens_);
+ EXPECT_EQ(1, consumer_.number_of_successful_tokens_);
EXPECT_EQ(0, consumer_.number_of_errors_);
}
diff --git a/chrome/browser/signin/profile_oauth2_token_service_unittest.cc b/chrome/browser/signin/profile_oauth2_token_service_unittest.cc
new file mode 100644
index 0000000..036a1c6
--- /dev/null
+++ b/chrome/browser/signin/profile_oauth2_token_service_unittest.cc
@@ -0,0 +1,97 @@
+// Copyright 2013 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "chrome/browser/signin/oauth2_token_service.h"
+#include "chrome/browser/signin/oauth2_token_service_test_util.h"
+#include "chrome/browser/signin/profile_oauth2_token_service.h"
+#include "chrome/browser/signin/profile_oauth2_token_service_factory.h"
+#include "chrome/browser/signin/token_service_unittest.h"
+#include "content/public/browser/browser_thread.h"
+#include "google_apis/gaia/gaia_constants.h"
+#include "net/http/http_status_code.h"
+#include "net/url_request/test_url_fetcher_factory.h"
+#include "testing/gtest/include/gtest/gtest.h"
+
+using content::BrowserThread;
+
+class ProfileOAuth2TokenServiceTest : public TokenServiceTestHarness {
+ public:
+ ProfileOAuth2TokenServiceTest() {}
+
+ virtual void SetUp() OVERRIDE {
+ TokenServiceTestHarness::SetUp();
+ io_thread_.reset(new content::TestBrowserThread(content::BrowserThread::IO,
+ &message_loop_));
+ service_->UpdateCredentials(credentials_);
+ profile_->CreateRequestContext();
+ oauth2_service_ = ProfileOAuth2TokenServiceFactory::GetForProfile(
+ profile_.get());
+ }
+
+ virtual void TearDown() OVERRIDE {
+ TokenServiceTestHarness::TearDown();
+ }
+
+ protected:
+ scoped_ptr<content::TestBrowserThread> io_thread_;
+ net::TestURLFetcherFactory factory_;
+ ProfileOAuth2TokenService* oauth2_service_;
+ TestingOAuth2TokenServiceConsumer consumer_;
+};
+
+TEST_F(ProfileOAuth2TokenServiceTest, TokenServiceUpdateClearsCache) {
+ EXPECT_EQ(0, oauth2_service_->cache_size_for_testing());
+ std::set<std::string> scope_list;
+ scope_list.insert("scope");
+ service_->IssueAuthTokenForTest(GaiaConstants::kGaiaOAuth2LoginRefreshToken,
+ "refreshToken");
+ scoped_ptr<OAuth2TokenService::Request> request(oauth2_service_->StartRequest(
+ scope_list, &consumer_));
+ message_loop_.RunUntilIdle();
+ net::TestURLFetcher* fetcher = factory_.GetFetcherByID(0);
+ fetcher->set_response_code(net::HTTP_OK);
+ fetcher->SetResponseString(GetValidTokenResponse("token", 3600));
+ fetcher->delegate()->OnURLFetchComplete(fetcher);
+ EXPECT_EQ(1, consumer_.number_of_successful_tokens_);
+ EXPECT_EQ(0, consumer_.number_of_errors_);
+ EXPECT_EQ("token", consumer_.last_token_);
+ EXPECT_EQ(1, oauth2_service_->cache_size_for_testing());
+
+ // Signs out and signs in
+ service_->IssueAuthTokenForTest(GaiaConstants::kGaiaOAuth2LoginRefreshToken,
+ "");
+ service_->EraseTokensFromDB();
+ EXPECT_EQ(0, oauth2_service_->cache_size_for_testing());
+ service_->IssueAuthTokenForTest(GaiaConstants::kGaiaOAuth2LoginRefreshToken,
+ "refreshToken");
+
+ request = oauth2_service_->StartRequest(scope_list, &consumer_);
+ message_loop_.RunUntilIdle();
+ fetcher = factory_.GetFetcherByID(0);
+ fetcher->set_response_code(net::HTTP_OK);
+ fetcher->SetResponseString(GetValidTokenResponse("another token", 3600));
+ fetcher->delegate()->OnURLFetchComplete(fetcher);
+ EXPECT_EQ(2, consumer_.number_of_successful_tokens_);
+ EXPECT_EQ(0, consumer_.number_of_errors_);
+ EXPECT_EQ("another token", consumer_.last_token_);
+ EXPECT_EQ(1, oauth2_service_->cache_size_for_testing());
+}
+
+// Android doesn't use the current profile's TokenService login refresh token.
+#if !defined(OS_ANDROID)
+TEST_F(ProfileOAuth2TokenServiceTest, StaleRefreshTokensNotCached) {
+ EXPECT_FALSE(service_->HasOAuthLoginToken());
+ EXPECT_FALSE(oauth2_service_->ShouldCacheForRefreshToken(service_, "T1"));
+
+ service_->IssueAuthTokenForTest(GaiaConstants::kGaiaOAuth2LoginRefreshToken,
+ "T1");
+ EXPECT_TRUE(oauth2_service_->ShouldCacheForRefreshToken(service_, "T1"));
+ EXPECT_FALSE(oauth2_service_->ShouldCacheForRefreshToken(service_, "T2"));
+
+ service_->IssueAuthTokenForTest(GaiaConstants::kGaiaOAuth2LoginRefreshToken,
+ "T2");
+ EXPECT_TRUE(oauth2_service_->ShouldCacheForRefreshToken(service_, "T2"));
+ EXPECT_FALSE(oauth2_service_->ShouldCacheForRefreshToken(NULL, "T2"));
+}
+#endif
diff --git a/chrome/browser/signin/token_service_unittest.cc b/chrome/browser/signin/token_service_unittest.cc
index fbe83df..198952c 100644
--- a/chrome/browser/signin/token_service_unittest.cc
+++ b/chrome/browser/signin/token_service_unittest.cc
@@ -231,7 +231,8 @@ TEST_F(TokenServiceTest, OnTokenSuccessUpdate) {
}
TEST_F(TokenServiceTest, OnOAuth2LoginTokenSuccessUpdate) {
- std::string service = GaiaConstants::kGaiaOAuth2LoginRefreshToken;
+ EXPECT_FALSE(service_->HasOAuthLoginToken());
+
service_->OnClientOAuthSuccess(
GaiaAuthConsumer::ClientOAuthResult("rt1", "at1", 3600));
EXPECT_TRUE(service_->HasOAuthLoginToken());