Index: chrome/browser/signin/oauth2_token_service.cc |
diff --git a/chrome/browser/signin/oauth2_token_service.cc b/chrome/browser/signin/oauth2_token_service.cc |
new file mode 100644 |
index 0000000000000000000000000000000000000000..e805291a8831d2d02c8343a5ff6228ae14d587d6 |
--- /dev/null |
+++ b/chrome/browser/signin/oauth2_token_service.cc |
@@ -0,0 +1,278 @@ |
+// 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.h" |
+ |
+#include "base/callback.h" |
+#include "base/time.h" |
+#include "chrome/browser/profiles/profile.h" |
+#include "chrome/browser/signin/oauth2_token_service_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" |
+ |
+using content::BrowserThread; |
+ |
+// Data structure used to communicate between the thread the request is made on |
+// and the UI thread where the TokenService is accessible. |
+struct Tokens { |
+ Tokens() : error(GoogleServiceAuthError::None()) {} |
+ GoogleServiceAuthError error; |
+ std::string refresh_token; |
+ std::string access_token; |
+ base::Time expiration_date; |
+}; |
+ |
+// Callback from the UI thread to the thread the request is made on. |
+typedef base::Callback<void(Tokens)> RequestCallbackType; |
+ |
+class OAuth2TokenService::RequestImpl : public CancelableRequestConsumer, |
+ public OAuth2TokenService::Request, |
+ public OAuth2AccessTokenConsumer { |
+ public: |
+ RequestImpl(Profile* profile, |
+ net::URLRequestContextGetter* getter, |
+ const std::set<std::string>& scopes, |
+ OAuth2AccessTokenConsumer* consumer); |
+ |
+ virtual ~RequestImpl(); |
+ |
+ // OAuth2AccessTokenConsumer implemenation; |
+ virtual void OnGetTokenSuccess(const std::string& access_token, |
+ const base::Time& expiration_date) OVERRIDE; |
+ virtual void OnGetTokenFailure(const GoogleServiceAuthError& error) OVERRIDE; |
+ |
+ private: |
+ friend class OAuth2TokenService; |
+ |
+ // This method is called on the UI thread so that it can access the profile |
+ // services and retrieve the tokens needed to solve or execute the request. |
+ static void GetTokens(CancelableRequest<RequestCallbackType>* request, |
+ Profile* profile, |
+ std::set<std::string> scopes); |
+ |
+ // Register an entry in the cache of the OAuth2TokenService associated to |
+ // |profile|. |
+ static void RegisterCacheEntry(Profile* profile, |
+ const std::set<std::string>& scopes, |
+ const std::string& access_token, |
+ const base::Time& expiration_date); |
+ |
+ // Callback on the request thread with the tokens needed to do the request. |
+ void FetchWithTokens(Tokens tokens); |
+ |
+ Profile* profile_; |
+ scoped_refptr<net::URLRequestContextGetter> getter_; |
+ std::set<std::string> scopes_; |
+ OAuth2AccessTokenConsumer* consumer_; |
+ scoped_ptr<OAuth2AccessTokenFetcher> fetcher_; |
+ |
+ DISALLOW_COPY_AND_ASSIGN(RequestImpl); |
+}; |
+ |
+OAuth2TokenService::OAuth2TokenService() { |
+} |
+ |
+OAuth2TokenService::~OAuth2TokenService() { |
+} |
+ |
+void OAuth2TokenService::Initialize(Profile* 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); |
+ registrar_.Add(this, |
+ chrome::NOTIFICATION_TOKEN_LOADING_FINISHED, |
+ token_service_source); |
+} |
+ |
+OAuth2TokenService::Request* OAuth2TokenService::StartRequest( |
+ const std::vector<std::string>& scopes, |
+ OAuth2AccessTokenConsumer* consumer) { |
+ std::set<std::string> scopes_set(scopes.begin(), scopes.end()); |
+ RequestImpl* request = |
+ new RequestImpl(profile_, getter_, scopes_set, consumer); |
+ scoped_refptr<CancelableRequest<RequestCallbackType> > cancellable_request( |
+ new CancelableRequest<RequestCallbackType>( |
+ base::Bind(&RequestImpl::FetchWithTokens, |
+ base::Unretained(request)))); |
+ AddRequest(cancellable_request, request); |
+ if (BrowserThread::CurrentlyOn(BrowserThread::UI)) { |
+ RequestImpl::GetTokens(cancellable_request, profile_, scopes_set); |
+ } else { |
+ BrowserThread::PostTask(BrowserThread::UI, |
+ FROM_HERE, |
+ base::Bind(&RequestImpl::GetTokens, |
+ cancellable_request, |
+ profile_, |
+ scopes_set)); |
+ } |
+ return request; |
+} |
+ |
+void OAuth2TokenService::ClearCache() { |
+ DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI)); |
+ tokens_cache_.clear(); |
+} |
+ |
+OAuth2TokenService::CacheEntry const* OAuth2TokenService::GetCacheEntry( |
+ const std::set<std::string>& scopes) { |
+ DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI)); |
+ TokensCache::iterator token_iterator = tokens_cache_.find(scopes); |
+ if (token_iterator == tokens_cache_.end()) |
+ return NULL; |
+ if (token_iterator->second.expiration_date <= base::Time::Now()) { |
+ tokens_cache_.erase(token_iterator); |
+ return NULL; |
+ } |
+ return &token_iterator->second; |
+} |
+ |
+void OAuth2TokenService::RegisterCacheEntry( |
+ const std::set<std::string>& scopes, |
+ const std::string& access_token, |
+ const base::Time& expiration_date) { |
+ DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI)); |
+ CacheEntry& token = tokens_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 || |
+ type == chrome::NOTIFICATION_TOKEN_LOADING_FINISHED); |
+ 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(); |
+} |
+ |
+OAuth2TokenService::RequestImpl::RequestImpl( |
+ Profile* profile, |
+ net::URLRequestContextGetter* getter, |
+ const std::set<std::string>& scopes, |
+ OAuth2AccessTokenConsumer* consumer) |
+ : profile_(profile), |
+ getter_(getter), |
+ scopes_(scopes), |
+ consumer_(consumer) { |
+} |
+ |
+OAuth2TokenService::RequestImpl::~RequestImpl() { |
+} |
+ |
+// static |
+void OAuth2TokenService::RequestImpl::GetTokens( |
+ CancelableRequest<RequestCallbackType>* request, |
+ Profile* profile, |
+ std::set<std::string> scopes) { |
+ DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI)); |
+ if (request->canceled()) |
+ return; |
+ Tokens tokens; |
+ TokenService* token_service = TokenServiceFactory::GetForProfile(profile); |
+ if (!token_service || !token_service->HasOAuthLoginToken()) { |
+ tokens.error = |
+ GoogleServiceAuthError(GoogleServiceAuthError::USER_NOT_SIGNED_UP); |
+ } else { |
+ OAuth2TokenService* oauth2_token_service = |
+ OAuth2TokenServiceFactory::GetForProfile(profile); |
+ DCHECK(oauth2_token_service); |
+ CacheEntry const* cache_entry = oauth2_token_service->GetCacheEntry(scopes); |
+ if (cache_entry) { |
+ tokens.access_token = cache_entry->access_token; |
+ tokens.expiration_date = cache_entry->expiration_date; |
+ } else { |
+ tokens.refresh_token = token_service->GetOAuth2LoginRefreshToken(); |
+ } |
+ } |
+ request->ForwardResult(tokens); |
+} |
+ |
+// static |
+void OAuth2TokenService::RequestImpl::RegisterCacheEntry( |
+ Profile* profile, |
+ const std::set<std::string>& scopes, |
+ const std::string& access_token, |
+ const base::Time& expiration_date) { |
+ OAuth2TokenService* oauth2_token_service = |
+ OAuth2TokenServiceFactory::GetForProfile(profile); |
+ if (!oauth2_token_service) |
+ return; |
+ oauth2_token_service->RegisterCacheEntry(scopes, |
+ access_token, |
+ expiration_date); |
+} |
+ |
+void OAuth2TokenService::RequestImpl::OnGetTokenSuccess( |
+ const std::string& access_token, |
+ const base::Time& expiration_date) { |
+ fetcher_.reset(); |
+ if (BrowserThread::CurrentlyOn(BrowserThread::UI)) { |
+ OAuth2TokenService* oauth2_token_service = |
+ OAuth2TokenServiceFactory::GetForProfile(profile_); |
+ if (oauth2_token_service) { |
+ oauth2_token_service->RegisterCacheEntry(scopes_, |
+ access_token, |
+ expiration_date); |
+ } |
+ } else { |
+ BrowserThread::PostTask( |
+ BrowserThread::UI, |
+ FROM_HERE, |
+ base::Bind(&OAuth2TokenService::RequestImpl::RegisterCacheEntry, |
+ base::Unretained(profile_), |
+ scopes_, |
+ access_token, |
+ expiration_date)); |
+ } |
+ consumer_->OnGetTokenSuccess(access_token, expiration_date); |
+} |
+ |
+void OAuth2TokenService::RequestImpl::OnGetTokenFailure( |
+ const GoogleServiceAuthError& error) { |
+ fetcher_.reset(); |
+ consumer_->OnGetTokenFailure(error); |
+} |
+ |
+void OAuth2TokenService::RequestImpl::FetchWithTokens(Tokens tokens) { |
+ if (tokens.error.state() != GoogleServiceAuthError::NONE) { |
+ consumer_->OnGetTokenFailure(tokens.error); |
+ return; |
+ } |
+ if (tokens.access_token.length()) { |
+ consumer_->OnGetTokenSuccess(tokens.access_token, tokens.expiration_date); |
+ return; |
+ } |
+ DCHECK(tokens.refresh_token.length()); |
+ fetcher_.reset(new OAuth2AccessTokenFetcher(this, getter_)); |
+ fetcher_->Start(GaiaUrls::GetInstance()->oauth2_chrome_client_id(), |
+ GaiaUrls::GetInstance()->oauth2_chrome_client_secret(), |
+ tokens.refresh_token, |
+ std::vector<std::string>(scopes_.begin(), scopes_.end())); |
+} |