| OLD | NEW |
| 1 // Copyright 2012 The Chromium Authors. All rights reserved. | 1 // Copyright 2012 The Chromium Authors. All rights reserved. |
| 2 // Use of this source code is governed by a BSD-style license that can be | 2 // Use of this source code is governed by a BSD-style license that can be |
| 3 // found in the LICENSE file. | 3 // found in the LICENSE file. |
| 4 | 4 |
| 5 #include "chrome/browser/signin/oauth2_token_service.h" | 5 #include "chrome/browser/signin/oauth2_token_service.h" |
| 6 | 6 |
| 7 #include <vector> | 7 #include <vector> |
| 8 | 8 |
| 9 #include "base/bind.h" | 9 #include "base/bind.h" |
| 10 #include "base/memory/weak_ptr.h" | 10 #include "base/memory/weak_ptr.h" |
| 11 #include "base/message_loop.h" | 11 #include "base/message_loop.h" |
| 12 #include "base/rand_util.h" | 12 #include "base/rand_util.h" |
| 13 #include "base/stl_util.h" | 13 #include "base/stl_util.h" |
| 14 #include "base/time.h" | 14 #include "base/time.h" |
| 15 #include "base/timer.h" | 15 #include "base/timer.h" |
| 16 #include "chrome/browser/profiles/profile.h" | |
| 17 #include "chrome/browser/signin/oauth2_token_service_factory.h" | |
| 18 #include "chrome/browser/signin/signin_manager.h" | |
| 19 #include "chrome/browser/signin/signin_manager_factory.h" | |
| 20 #include "chrome/browser/signin/token_service.h" | |
| 21 #include "chrome/browser/signin/token_service_factory.h" | |
| 22 #include "chrome/common/chrome_notification_types.h" | |
| 23 #include "content/public/browser/browser_thread.h" | 16 #include "content/public/browser/browser_thread.h" |
| 24 #include "content/public/browser/notification_details.h" | |
| 25 #include "content/public/browser/notification_source.h" | |
| 26 #include "google_apis/gaia/gaia_constants.h" | |
| 27 #include "google_apis/gaia/gaia_urls.h" | 17 #include "google_apis/gaia/gaia_urls.h" |
| 28 #include "google_apis/gaia/google_service_auth_error.h" | 18 #include "google_apis/gaia/google_service_auth_error.h" |
| 29 #include "google_apis/gaia/oauth2_access_token_consumer.h" | 19 #include "google_apis/gaia/oauth2_access_token_consumer.h" |
| 30 #include "google_apis/gaia/oauth2_access_token_fetcher.h" | 20 #include "google_apis/gaia/oauth2_access_token_fetcher.h" |
| 31 | 21 #include "net/url_request/url_request_context_getter.h" |
| 32 #if defined(OS_ANDROID) | |
| 33 #include "chrome/browser/sync/profile_sync_service_android.h" | |
| 34 #endif | |
| 35 | 22 |
| 36 namespace { | 23 namespace { |
| 37 | 24 |
| 38 // Maximum number of retries in fetching an OAuth2 access token. | 25 // Maximum number of retries in fetching an OAuth2 access token. |
| 39 const int kMaxFetchRetryNum = 5; | 26 const int kMaxFetchRetryNum = 5; |
| 40 | 27 |
| 41 // Returns an exponential backoff in milliseconds including randomness less than | 28 // Returns an exponential backoff in milliseconds including randomness less than |
| 42 // 1000 ms when retrying fetching an OAuth2 access token. | 29 // 1000 ms when retrying fetching an OAuth2 access token. |
| 43 int64 ComputeExponentialBackOffMilliseconds(int retry_num) { | 30 int64 ComputeExponentialBackOffMilliseconds(int retry_num) { |
| 44 DCHECK(retry_num < kMaxFetchRetryNum); | 31 DCHECK(retry_num < kMaxFetchRetryNum); |
| 45 int64 exponential_backoff_in_seconds = 1 << retry_num; | 32 int64 exponential_backoff_in_seconds = 1 << retry_num; |
| 46 // Returns a backoff with randomness < 1000ms | 33 // Returns a backoff with randomness < 1000ms |
| 47 return (exponential_backoff_in_seconds + base::RandDouble()) * 1000; | 34 return (exponential_backoff_in_seconds + base::RandDouble()) * 1000; |
| 48 } | 35 } |
| 49 | 36 |
| 50 } // namespace | 37 } // namespace |
| 51 | 38 |
| 52 // Implements a cancelable |OAuth2TokenService::Request|, which should be | |
| 53 // operated on the UI thread. | |
| 54 class OAuth2TokenService::RequestImpl | |
| 55 : public base::SupportsWeakPtr<RequestImpl>, | |
| 56 public OAuth2TokenService::Request { | |
| 57 public: | |
| 58 // |consumer| is required to outlive this. | |
| 59 explicit RequestImpl(OAuth2TokenService::Consumer* consumer); | |
| 60 virtual ~RequestImpl(); | |
| 61 | |
| 62 // Informs |consumer_| that this request is completed. | |
| 63 void InformConsumer(const GoogleServiceAuthError& error, | |
| 64 const std::string& access_token, | |
| 65 const base::Time& expiration_date); | |
| 66 | |
| 67 private: | |
| 68 // |consumer_| to call back when this request completes. | |
| 69 OAuth2TokenService::Consumer* const consumer_; | |
| 70 }; | |
| 71 | |
| 72 OAuth2TokenService::RequestImpl::RequestImpl( | 39 OAuth2TokenService::RequestImpl::RequestImpl( |
| 73 OAuth2TokenService::Consumer* consumer) | 40 OAuth2TokenService::Consumer* consumer) |
| 74 : consumer_(consumer) { | 41 : consumer_(consumer) { |
| 75 DCHECK(content::BrowserThread::CurrentlyOn(content::BrowserThread::UI)); | 42 DCHECK(content::BrowserThread::CurrentlyOn(content::BrowserThread::UI)); |
| 76 } | 43 } |
| 77 | 44 |
| 78 OAuth2TokenService::RequestImpl::~RequestImpl() { | 45 OAuth2TokenService::RequestImpl::~RequestImpl() { |
| 79 DCHECK(content::BrowserThread::CurrentlyOn(content::BrowserThread::UI)); | 46 DCHECK(content::BrowserThread::CurrentlyOn(content::BrowserThread::UI)); |
| 80 } | 47 } |
| 81 | 48 |
| 82 void OAuth2TokenService::RequestImpl::InformConsumer( | 49 void OAuth2TokenService::RequestImpl::InformConsumer( |
| 83 const GoogleServiceAuthError& error, | 50 const GoogleServiceAuthError& error, |
| 84 const std::string& access_token, | 51 const std::string& access_token, |
| 85 const base::Time& expiration_date) { | 52 const base::Time& expiration_date) { |
| 86 DCHECK(content::BrowserThread::CurrentlyOn(content::BrowserThread::UI)); | 53 DCHECK(content::BrowserThread::CurrentlyOn(content::BrowserThread::UI)); |
| 87 if (error.state() == GoogleServiceAuthError::NONE) | 54 if (error.state() == GoogleServiceAuthError::NONE) |
| 88 consumer_-> OnGetTokenSuccess(this, access_token, expiration_date); | 55 consumer_->OnGetTokenSuccess(this, access_token, expiration_date); |
| 89 else | 56 else |
| 90 consumer_-> OnGetTokenFailure(this, error); | 57 consumer_->OnGetTokenFailure(this, error); |
| 91 } | 58 } |
| 92 | 59 |
| 93 // Class that fetches OAuth2 access tokens for given scopes and refresh token. | 60 // Class that fetches OAuth2 access tokens for given scopes and refresh token. |
| 94 // | 61 // |
| 95 // It aims to meet OAuth2TokenService's requirements on token fetching. Retry | 62 // It aims to meet OAuth2TokenService's requirements on token fetching. Retry |
| 96 // mechanism is used to handle failures. | 63 // mechanism is used to handle failures. |
| 97 // | 64 // |
| 98 // To use this class, call CreateAndStart() to create and start a Fetcher. | 65 // To use this class, call CreateAndStart() to create and start a Fetcher. |
| 99 // | 66 // |
| 100 // The Fetcher will call back the service by calling | 67 // The Fetcher will call back the service by calling |
| (...skipping 13 matching lines...) Expand all Loading... |
| 114 // deleted | 81 // deleted |
| 115 // - when the Fetcher completes fetching, if the Fetcher is not destructed | 82 // - when the Fetcher completes fetching, if the Fetcher is not destructed |
| 116 // before it completes fetching, or | 83 // before it completes fetching, or |
| 117 // - when the Fetcher is destructed if the Fetcher is destructed before it | 84 // - when the Fetcher is destructed if the Fetcher is destructed before it |
| 118 // completes fetching (in this case, the waiting requests will be called back | 85 // completes fetching (in this case, the waiting requests will be called back |
| 119 // with error). | 86 // with error). |
| 120 class OAuth2TokenService::Fetcher : public OAuth2AccessTokenConsumer { | 87 class OAuth2TokenService::Fetcher : public OAuth2AccessTokenConsumer { |
| 121 public: | 88 public: |
| 122 // Creates a Fetcher and starts fetching an OAuth2 access token for | 89 // Creates a Fetcher and starts fetching an OAuth2 access token for |
| 123 // |refresh_token| and |scopes| in the request context obtained by |getter|. | 90 // |refresh_token| and |scopes| in the request context obtained by |getter|. |
| 124 // |profile|'s OAuth2TokenService will be informed when fetching is done. | 91 // The given |oauth2_token_service| will be informed when fetching is done. |
| 125 static Fetcher* CreateAndStart(Profile* profile, | 92 static Fetcher* CreateAndStart(OAuth2TokenService* oauth2_token_service, |
| 126 net::URLRequestContextGetter* getter, | 93 net::URLRequestContextGetter* getter, |
| 127 const std::string& refresh_token, | 94 const std::string& refresh_token, |
| 128 const OAuth2TokenService::ScopeSet& scopes, | 95 const OAuth2TokenService::ScopeSet& scopes, |
| 129 base::WeakPtr<RequestImpl> waiting_request); | 96 base::WeakPtr<RequestImpl> waiting_request); |
| 130 virtual ~Fetcher(); | 97 virtual ~Fetcher(); |
| 131 | 98 |
| 132 // Add a request that is waiting for the result of this Fetcher. | 99 // Add a request that is waiting for the result of this Fetcher. |
| 133 void AddWaitingRequest(base::WeakPtr<RequestImpl> waiting_request); | 100 void AddWaitingRequest(base::WeakPtr<RequestImpl> waiting_request); |
| 134 | 101 |
| 135 const OAuth2TokenService::ScopeSet& GetScopeSet() const; | 102 const OAuth2TokenService::ScopeSet& GetScopeSet() const; |
| 136 const std::string& GetRefreshToken() const; | 103 const std::string& GetRefreshToken() const; |
| 137 | 104 |
| 138 // The error result from this fetcher. | 105 // The error result from this fetcher. |
| 139 const GoogleServiceAuthError& error() const { return error_; } | 106 const GoogleServiceAuthError& error() const { return error_; } |
| 140 | 107 |
| 141 protected: | 108 protected: |
| 142 // OAuth2AccessTokenConsumer | 109 // OAuth2AccessTokenConsumer |
| 143 virtual void OnGetTokenSuccess(const std::string& access_token, | 110 virtual void OnGetTokenSuccess(const std::string& access_token, |
| 144 const base::Time& expiration_date) OVERRIDE; | 111 const base::Time& expiration_date) OVERRIDE; |
| 145 virtual void OnGetTokenFailure(const GoogleServiceAuthError& error) OVERRIDE; | 112 virtual void OnGetTokenFailure(const GoogleServiceAuthError& error) OVERRIDE; |
| 146 | 113 |
| 147 private: | 114 private: |
| 148 Fetcher(Profile* profile, | 115 Fetcher(OAuth2TokenService* oauth2_token_service, |
| 149 net::URLRequestContextGetter* getter, | 116 net::URLRequestContextGetter* getter, |
| 150 const std::string& refresh_token, | 117 const std::string& refresh_token, |
| 151 const OAuth2TokenService::ScopeSet& scopes, | 118 const OAuth2TokenService::ScopeSet& scopes, |
| 152 base::WeakPtr<RequestImpl> waiting_request); | 119 base::WeakPtr<RequestImpl> waiting_request); |
| 153 void Start(); | 120 void Start(); |
| 154 void InformWaitingRequests(); | 121 void InformWaitingRequests(); |
| 155 static bool ShouldRetry(const GoogleServiceAuthError& error); | 122 static bool ShouldRetry(const GoogleServiceAuthError& error); |
| 156 | 123 |
| 157 Profile* const profile_; | 124 // |oauth2_token_service_| remains valid for the life of this Fetcher, since |
| 125 // this Fetcher is destructed in the dtor of the OAuth2TokenService or is |
| 126 // scheduled for deletion at the end of OnGetTokenFailure/OnGetTokenSuccess |
| 127 // (whichever comes first). |
| 128 OAuth2TokenService* const oauth2_token_service_; |
| 158 scoped_refptr<net::URLRequestContextGetter> getter_; | 129 scoped_refptr<net::URLRequestContextGetter> getter_; |
| 159 const std::string refresh_token_; | 130 const std::string refresh_token_; |
| 160 const OAuth2TokenService::ScopeSet scopes_; | 131 const OAuth2TokenService::ScopeSet scopes_; |
| 161 std::vector<base::WeakPtr<RequestImpl> > waiting_requests_; | 132 std::vector<base::WeakPtr<RequestImpl> > waiting_requests_; |
| 162 | 133 |
| 163 int retry_number_; | 134 int retry_number_; |
| 164 base::OneShotTimer<OAuth2TokenService::Fetcher> retry_timer_; | 135 base::OneShotTimer<OAuth2TokenService::Fetcher> retry_timer_; |
| 165 scoped_ptr<OAuth2AccessTokenFetcher> fetcher_; | 136 scoped_ptr<OAuth2AccessTokenFetcher> fetcher_; |
| 166 | 137 |
| 167 // Variables that store fetch results. | 138 // Variables that store fetch results. |
| 168 // Initialized to be GoogleServiceAuthError::SERVICE_UNAVAILABLE to handle | 139 // Initialized to be GoogleServiceAuthError::SERVICE_UNAVAILABLE to handle |
| 169 // destruction. | 140 // destruction. |
| 170 GoogleServiceAuthError error_; | 141 GoogleServiceAuthError error_; |
| 171 std::string access_token_; | 142 std::string access_token_; |
| 172 base::Time expiration_date_; | 143 base::Time expiration_date_; |
| 173 | 144 |
| 174 DISALLOW_COPY_AND_ASSIGN(Fetcher); | 145 DISALLOW_COPY_AND_ASSIGN(Fetcher); |
| 175 }; | 146 }; |
| 176 | 147 |
| 177 // static | 148 // static |
| 178 OAuth2TokenService::Fetcher* OAuth2TokenService::Fetcher::CreateAndStart( | 149 OAuth2TokenService::Fetcher* OAuth2TokenService::Fetcher::CreateAndStart( |
| 179 Profile* profile, | 150 OAuth2TokenService* oauth2_token_service, |
| 180 net::URLRequestContextGetter* getter, | 151 net::URLRequestContextGetter* getter, |
| 181 const std::string& refresh_token, | 152 const std::string& refresh_token, |
| 182 const OAuth2TokenService::ScopeSet& scopes, | 153 const OAuth2TokenService::ScopeSet& scopes, |
| 183 base::WeakPtr<RequestImpl> waiting_request) { | 154 base::WeakPtr<RequestImpl> waiting_request) { |
| 184 OAuth2TokenService::Fetcher* fetcher = new Fetcher( | 155 OAuth2TokenService::Fetcher* fetcher = new Fetcher( |
| 185 profile, getter, refresh_token, scopes, waiting_request); | 156 oauth2_token_service, getter, refresh_token, scopes, waiting_request); |
| 186 fetcher->Start(); | 157 fetcher->Start(); |
| 187 return fetcher; | 158 return fetcher; |
| 188 } | 159 } |
| 189 | 160 |
| 190 OAuth2TokenService::Fetcher::Fetcher( | 161 OAuth2TokenService::Fetcher::Fetcher( |
| 191 Profile* profile, | 162 OAuth2TokenService* oauth2_token_service, |
| 192 net::URLRequestContextGetter* getter, | 163 net::URLRequestContextGetter* getter, |
| 193 const std::string& refresh_token, | 164 const std::string& refresh_token, |
| 194 const OAuth2TokenService::ScopeSet& scopes, | 165 const OAuth2TokenService::ScopeSet& scopes, |
| 195 base::WeakPtr<RequestImpl> waiting_request) | 166 base::WeakPtr<RequestImpl> waiting_request) |
| 196 : profile_(profile), | 167 : oauth2_token_service_(oauth2_token_service), |
| 197 getter_(getter), | 168 getter_(getter), |
| 198 refresh_token_(refresh_token), | 169 refresh_token_(refresh_token), |
| 199 scopes_(scopes), | 170 scopes_(scopes), |
| 200 retry_number_(0), | 171 retry_number_(0), |
| 201 error_(GoogleServiceAuthError::SERVICE_UNAVAILABLE) { | 172 error_(GoogleServiceAuthError::SERVICE_UNAVAILABLE) { |
| 202 DCHECK(profile_); | 173 DCHECK(oauth2_token_service_); |
| 203 DCHECK(getter_); | 174 DCHECK(getter_); |
| 204 DCHECK(refresh_token_.length()); | 175 DCHECK(refresh_token_.length()); |
| 205 waiting_requests_.push_back(waiting_request); | 176 waiting_requests_.push_back(waiting_request); |
| 206 } | 177 } |
| 207 | 178 |
| 208 OAuth2TokenService::Fetcher::~Fetcher() { | 179 OAuth2TokenService::Fetcher::~Fetcher() { |
| 209 // Inform the waiting requests if it has not done so. | 180 // Inform the waiting requests if it has not done so. |
| 210 if (waiting_requests_.size()) | 181 if (waiting_requests_.size()) |
| 211 InformWaitingRequests(); | 182 InformWaitingRequests(); |
| 212 } | 183 } |
| 213 | 184 |
| 214 void OAuth2TokenService::Fetcher::Start() { | 185 void OAuth2TokenService::Fetcher::Start() { |
| 215 fetcher_.reset(new OAuth2AccessTokenFetcher(this, getter_)); | 186 fetcher_.reset(new OAuth2AccessTokenFetcher(this, getter_)); |
| 216 fetcher_->Start(GaiaUrls::GetInstance()->oauth2_chrome_client_id(), | 187 fetcher_->Start(GaiaUrls::GetInstance()->oauth2_chrome_client_id(), |
| 217 GaiaUrls::GetInstance()->oauth2_chrome_client_secret(), | 188 GaiaUrls::GetInstance()->oauth2_chrome_client_secret(), |
| 218 refresh_token_, | 189 refresh_token_, |
| 219 std::vector<std::string>(scopes_.begin(), scopes_.end())); | 190 std::vector<std::string>(scopes_.begin(), scopes_.end())); |
| 220 retry_timer_.Stop(); | 191 retry_timer_.Stop(); |
| 221 } | 192 } |
| 222 | 193 |
| 223 void OAuth2TokenService::Fetcher::OnGetTokenSuccess( | 194 void OAuth2TokenService::Fetcher::OnGetTokenSuccess( |
| 224 const std::string& access_token, | 195 const std::string& access_token, |
| 225 const base::Time& expiration_date) { | 196 const base::Time& expiration_date) { |
| 226 fetcher_.reset(); | 197 fetcher_.reset(); |
| 227 | 198 |
| 228 // Fetch completes. | 199 // Fetch completes. |
| 229 error_ = GoogleServiceAuthError(GoogleServiceAuthError::NONE); | 200 error_ = GoogleServiceAuthError::AuthErrorNone(); |
| 230 access_token_ = access_token; | 201 access_token_ = access_token; |
| 231 expiration_date_ = expiration_date; | 202 expiration_date_ = expiration_date; |
| 232 | 203 |
| 233 // |oauth2_token_service| should not be NULL as this Fetcher is destructed in | 204 // Subclasses may override this method to skip caching in some cases, but |
| 234 // the dtor of the OAuth2TokenService that creates it if it is not scheduled | 205 // we still inform all waiting Consumers of a successful token fetch below. |
| 235 // to be destructed here and in OnGetTokenFailure(). | 206 // This is intentional -- some consumers may need the token for cleanup |
| 236 OAuth2TokenService* oauth2_token_service = | 207 // tasks. https://chromiumcodereview.appspot.com/11312124/ |
| 237 OAuth2TokenServiceFactory::GetForProfile(profile_); | 208 oauth2_token_service_->RegisterCacheEntry(refresh_token_, |
| 238 DCHECK(oauth2_token_service); | 209 scopes_, |
| 239 | 210 access_token_, |
| 240 oauth2_token_service->RegisterCacheEntry(refresh_token_, | 211 expiration_date_); |
| 241 scopes_, | |
| 242 access_token_, | |
| 243 expiration_date_); | |
| 244 // Deregisters itself from the service to prevent more waiting requests to | 212 // Deregisters itself from the service to prevent more waiting requests to |
| 245 // be added when it calls back the waiting requests. | 213 // be added when it calls back the waiting requests. |
| 246 oauth2_token_service->OnFetchComplete(this); | 214 oauth2_token_service_->OnFetchComplete(this); |
| 247 InformWaitingRequests(); | 215 InformWaitingRequests(); |
| 248 MessageLoop::current()->DeleteSoon(FROM_HERE, this); | 216 MessageLoop::current()->DeleteSoon(FROM_HERE, this); |
| 249 } | 217 } |
| 250 | 218 |
| 251 void OAuth2TokenService::Fetcher::OnGetTokenFailure( | 219 void OAuth2TokenService::Fetcher::OnGetTokenFailure( |
| 252 const GoogleServiceAuthError& error) { | 220 const GoogleServiceAuthError& error) { |
| 253 fetcher_.reset(); | 221 fetcher_.reset(); |
| 254 | 222 |
| 255 if (ShouldRetry(error) && retry_number_ < kMaxFetchRetryNum) { | 223 if (ShouldRetry(error) && retry_number_ < kMaxFetchRetryNum) { |
| 256 int64 backoff = ComputeExponentialBackOffMilliseconds(retry_number_); | 224 int64 backoff = ComputeExponentialBackOffMilliseconds(retry_number_); |
| 257 ++retry_number_; | 225 ++retry_number_; |
| 258 retry_timer_.Stop(); | 226 retry_timer_.Stop(); |
| 259 retry_timer_.Start(FROM_HERE, | 227 retry_timer_.Start(FROM_HERE, |
| 260 base::TimeDelta::FromMilliseconds(backoff), | 228 base::TimeDelta::FromMilliseconds(backoff), |
| 261 this, | 229 this, |
| 262 &OAuth2TokenService::Fetcher::Start); | 230 &OAuth2TokenService::Fetcher::Start); |
| 263 return; | 231 return; |
| 264 } | 232 } |
| 265 | 233 |
| 266 // Fetch completes. | 234 // Fetch completes. |
| 267 error_ = error; | 235 error_ = error; |
| 268 | 236 |
| 269 // |oauth2_token_service| should not be NULL as this Fetcher is destructed in | |
| 270 // the dtor of the OAuth2TokenService that creates it if it is not scheduled | |
| 271 // to be destructed here and in OnGetTokenSuccess(). | |
| 272 OAuth2TokenService* oauth2_token_service = | |
| 273 OAuth2TokenServiceFactory::GetForProfile(profile_); | |
| 274 DCHECK(oauth2_token_service); | |
| 275 // Deregisters itself from the service to prevent more waiting requests to be | 237 // Deregisters itself from the service to prevent more waiting requests to be |
| 276 // added when it calls back the waiting requests. | 238 // added when it calls back the waiting requests. |
| 277 oauth2_token_service->OnFetchComplete(this); | 239 oauth2_token_service_->OnFetchComplete(this); |
| 278 InformWaitingRequests(); | 240 InformWaitingRequests(); |
| 279 MessageLoop::current()->DeleteSoon(FROM_HERE, this); | 241 MessageLoop::current()->DeleteSoon(FROM_HERE, this); |
| 280 } | 242 } |
| 281 | 243 |
| 282 // static | 244 // static |
| 283 bool OAuth2TokenService::Fetcher::ShouldRetry( | 245 bool OAuth2TokenService::Fetcher::ShouldRetry( |
| 284 const GoogleServiceAuthError& error) { | 246 const GoogleServiceAuthError& error) { |
| 285 GoogleServiceAuthError::State error_state = error.state(); | 247 GoogleServiceAuthError::State error_state = error.state(); |
| 286 return error_state == GoogleServiceAuthError::CONNECTION_FAILED || | 248 return error_state == GoogleServiceAuthError::CONNECTION_FAILED || |
| 287 error_state == GoogleServiceAuthError::REQUEST_CANCELED || | 249 error_state == GoogleServiceAuthError::REQUEST_CANCELED || |
| (...skipping 30 matching lines...) Expand all Loading... |
| 318 | 280 |
| 319 OAuth2TokenService::Request::~Request() { | 281 OAuth2TokenService::Request::~Request() { |
| 320 } | 282 } |
| 321 | 283 |
| 322 OAuth2TokenService::Consumer::Consumer() { | 284 OAuth2TokenService::Consumer::Consumer() { |
| 323 } | 285 } |
| 324 | 286 |
| 325 OAuth2TokenService::Consumer::~Consumer() { | 287 OAuth2TokenService::Consumer::~Consumer() { |
| 326 } | 288 } |
| 327 | 289 |
| 328 OAuth2TokenService::OAuth2TokenService() | 290 OAuth2TokenService::OAuth2TokenService(net::URLRequestContextGetter* getter) |
| 329 : profile_(NULL), | 291 : request_context_getter_(getter) { |
| 330 last_auth_error_(GoogleServiceAuthError::NONE) { | |
| 331 } | 292 } |
| 332 | 293 |
| 333 OAuth2TokenService::~OAuth2TokenService() { | 294 OAuth2TokenService::~OAuth2TokenService() { |
| 295 DCHECK(content::BrowserThread::CurrentlyOn(content::BrowserThread::UI)); |
| 334 // Release all the pending fetchers. | 296 // Release all the pending fetchers. |
| 335 STLDeleteContainerPairSecondPointers( | 297 STLDeleteContainerPairSecondPointers( |
| 336 pending_fetchers_.begin(), pending_fetchers_.end()); | 298 pending_fetchers_.begin(), pending_fetchers_.end()); |
| 337 } | 299 } |
| 338 | 300 |
| 339 void OAuth2TokenService::Initialize(Profile* profile) { | 301 bool OAuth2TokenService::RefreshTokenIsAvailable() { |
| 340 DCHECK(content::BrowserThread::CurrentlyOn(content::BrowserThread::UI)); | 302 DCHECK(content::BrowserThread::CurrentlyOn(content::BrowserThread::UI)); |
| 341 | 303 return !GetRefreshToken().empty(); |
| 342 DCHECK(profile); | |
| 343 DCHECK(!profile_); | |
| 344 profile_ = profile; | |
| 345 getter_ = profile->GetRequestContext(); | |
| 346 content::Source<TokenService> token_service_source( | |
| 347 TokenServiceFactory::GetForProfile(profile)); | |
| 348 registrar_.Add(this, | |
| 349 chrome::NOTIFICATION_TOKENS_CLEARED, | |
| 350 token_service_source); | |
| 351 registrar_.Add(this, | |
| 352 chrome::NOTIFICATION_TOKEN_AVAILABLE, | |
| 353 token_service_source); | |
| 354 SigninManagerFactory::GetForProfile(profile_)->signin_global_error()-> | |
| 355 AddProvider(this); | |
| 356 } | 304 } |
| 357 | 305 |
| 358 void OAuth2TokenService::Shutdown() { | |
| 359 if (profile_) { | |
| 360 SigninManagerFactory::GetForProfile(profile_)->signin_global_error()-> | |
| 361 RemoveProvider(this); | |
| 362 } | |
| 363 } | |
| 364 | |
| 365 | |
| 366 // static | 306 // static |
| 367 void OAuth2TokenService::InformConsumer( | 307 void OAuth2TokenService::InformConsumer( |
| 368 base::WeakPtr<OAuth2TokenService::RequestImpl> request, | 308 base::WeakPtr<OAuth2TokenService::RequestImpl> request, |
| 369 const GoogleServiceAuthError& error, | 309 const GoogleServiceAuthError& error, |
| 370 const std::string& access_token, | 310 const std::string& access_token, |
| 371 const base::Time& expiration_date) { | 311 const base::Time& expiration_date) { |
| 372 DCHECK(content::BrowserThread::CurrentlyOn(content::BrowserThread::UI)); | 312 DCHECK(content::BrowserThread::CurrentlyOn(content::BrowserThread::UI)); |
| 373 | 313 |
| 374 if (request) | 314 if (request) |
| 375 request->InformConsumer(error, access_token, expiration_date); | 315 request->InformConsumer(error, access_token, expiration_date); |
| 376 } | 316 } |
| 377 | 317 |
| 378 scoped_ptr<OAuth2TokenService::Request> OAuth2TokenService::StartRequest( | 318 scoped_ptr<OAuth2TokenService::Request> OAuth2TokenService::StartRequest( |
| 379 const OAuth2TokenService::ScopeSet& scopes, | 319 const OAuth2TokenService::ScopeSet& scopes, |
| 380 OAuth2TokenService::Consumer* consumer) { | 320 OAuth2TokenService::Consumer* consumer) { |
| 381 DCHECK(content::BrowserThread::CurrentlyOn(content::BrowserThread::UI)); | 321 DCHECK(content::BrowserThread::CurrentlyOn(content::BrowserThread::UI)); |
| 382 | 322 |
| 383 scoped_ptr<RequestImpl> request(new RequestImpl(consumer)); | 323 scoped_ptr<RequestImpl> request(new RequestImpl(consumer)); |
| 384 | 324 |
| 385 #if !defined(OS_ANDROID) | 325 std::string refresh_token = GetRefreshToken(); |
| 386 TokenService* token_service = TokenServiceFactory::GetForProfile(profile_); | 326 if (refresh_token.empty()) { |
| 387 if (!token_service || !token_service->HasOAuthLoginToken()) { | |
| 388 MessageLoop::current()->PostTask(FROM_HERE, base::Bind( | |
| 389 &OAuth2TokenService::InformConsumer, | |
| 390 request->AsWeakPtr(), | |
| 391 GoogleServiceAuthError(GoogleServiceAuthError::USER_NOT_SIGNED_UP), | |
| 392 std::string(), | |
| 393 base::Time())); | |
| 394 return request.PassAs<Request>(); | |
| 395 } | |
| 396 #endif | |
| 397 | |
| 398 const CacheEntry* cache_entry = GetCacheEntry(scopes); | |
| 399 if (cache_entry && cache_entry->access_token.length()) { | |
| 400 MessageLoop::current()->PostTask(FROM_HERE, base::Bind( | |
| 401 &OAuth2TokenService::InformConsumer, | |
| 402 request->AsWeakPtr(), | |
| 403 GoogleServiceAuthError(GoogleServiceAuthError::NONE), | |
| 404 cache_entry->access_token, | |
| 405 cache_entry->expiration_date)); | |
| 406 return request.PassAs<Request>(); | |
| 407 } | |
| 408 | |
| 409 #if defined(OS_ANDROID) | |
| 410 DCHECK_EQ(scopes.size(), 1U); | |
| 411 std::vector<std::string> scope_list(scopes.begin(), scopes.end()); | |
| 412 ProfileSyncServiceAndroid* sync_service = | |
| 413 ProfileSyncServiceAndroid::GetProfileSyncServiceAndroid(); | |
| 414 sync_service->FetchOAuth2Token( | |
| 415 scope_list.front(), | |
| 416 base::Bind(&OAuth2TokenService::InformConsumer, | |
| 417 request->AsWeakPtr())); | |
| 418 return request.PassAs<Request>(); | |
| 419 #else | |
| 420 std::string refresh_token = token_service->GetOAuth2LoginRefreshToken(); | |
| 421 if (!refresh_token.length()) { | |
| 422 MessageLoop::current()->PostTask(FROM_HERE, base::Bind( | 327 MessageLoop::current()->PostTask(FROM_HERE, base::Bind( |
| 423 &OAuth2TokenService::InformConsumer, | 328 &OAuth2TokenService::InformConsumer, |
| 424 request->AsWeakPtr(), | 329 request->AsWeakPtr(), |
| 425 GoogleServiceAuthError( | 330 GoogleServiceAuthError( |
| 426 GoogleServiceAuthError::INVALID_GAIA_CREDENTIALS), | 331 GoogleServiceAuthError::USER_NOT_SIGNED_UP), |
| 427 std::string(), | 332 std::string(), |
| 428 base::Time())); | 333 base::Time())); |
| 429 return request.PassAs<Request>(); | 334 return request.PassAs<Request>(); |
| 430 } | 335 } |
| 431 | 336 |
| 337 if (HasCacheEntry(scopes)) |
| 338 return StartCacheLookupRequest(scopes, consumer); |
| 339 |
| 432 // Makes sure there is a pending fetcher for |scopes| and |refresh_token|. | 340 // Makes sure there is a pending fetcher for |scopes| and |refresh_token|. |
| 433 // Adds |request| to the waiting request list of this fetcher so |request| | 341 // Adds |request| to the waiting request list of this fetcher so |request| |
| 434 // will be called back when this fetcher finishes fetching. | 342 // will be called back when this fetcher finishes fetching. |
| 435 FetchParameters fetch_parameters = std::make_pair(refresh_token, scopes); | 343 FetchParameters fetch_parameters = std::make_pair(refresh_token, scopes); |
| 436 std::map<FetchParameters, Fetcher*>::iterator iter = | 344 std::map<FetchParameters, Fetcher*>::iterator iter = |
| 437 pending_fetchers_.find(fetch_parameters); | 345 pending_fetchers_.find(fetch_parameters); |
| 438 if (iter != pending_fetchers_.end()) { | 346 if (iter != pending_fetchers_.end()) { |
| 439 iter->second->AddWaitingRequest(request->AsWeakPtr()); | 347 iter->second->AddWaitingRequest(request->AsWeakPtr()); |
| 440 return request.PassAs<Request>(); | 348 return request.PassAs<Request>(); |
| 441 } | 349 } |
| 442 pending_fetchers_[fetch_parameters] = Fetcher::CreateAndStart( | 350 pending_fetchers_[fetch_parameters] = Fetcher::CreateAndStart( |
| 443 profile_, getter_, refresh_token, scopes, request->AsWeakPtr()); | 351 this, request_context_getter_, refresh_token, scopes, |
| 352 request->AsWeakPtr()); |
| 444 return request.PassAs<Request>(); | 353 return request.PassAs<Request>(); |
| 445 #endif // defined(OS_ANDROID) | 354 } |
| 355 |
| 356 scoped_ptr<OAuth2TokenService::Request> |
| 357 OAuth2TokenService::StartCacheLookupRequest( |
| 358 const OAuth2TokenService::ScopeSet& scopes, |
| 359 OAuth2TokenService::Consumer* consumer) { |
| 360 CHECK(HasCacheEntry(scopes)); |
| 361 const CacheEntry* cache_entry = GetCacheEntry(scopes); |
| 362 scoped_ptr<RequestImpl> request(new RequestImpl(consumer)); |
| 363 MessageLoop::current()->PostTask(FROM_HERE, base::Bind( |
| 364 &OAuth2TokenService::InformConsumer, |
| 365 request->AsWeakPtr(), |
| 366 GoogleServiceAuthError(GoogleServiceAuthError::NONE), |
| 367 cache_entry->access_token, |
| 368 cache_entry->expiration_date)); |
| 369 return request.PassAs<Request>(); |
| 446 } | 370 } |
| 447 | 371 |
| 448 void OAuth2TokenService::InvalidateToken(const ScopeSet& scopes, | 372 void OAuth2TokenService::InvalidateToken(const ScopeSet& scopes, |
| 449 const std::string& invalid_token) { | 373 const std::string& invalid_token) { |
| 374 DCHECK(content::BrowserThread::CurrentlyOn(content::BrowserThread::UI)); |
| 450 RemoveCacheEntry(scopes, invalid_token); | 375 RemoveCacheEntry(scopes, invalid_token); |
| 451 | |
| 452 #if defined(OS_ANDROID) | |
| 453 DCHECK_EQ(scopes.size(), 1U); | |
| 454 std::vector<std::string> scope_list(scopes.begin(), scopes.end()); | |
| 455 ProfileSyncServiceAndroid* sync_service = | |
| 456 ProfileSyncServiceAndroid::GetProfileSyncServiceAndroid(); | |
| 457 sync_service->InvalidateOAuth2Token( | |
| 458 scope_list.front(), | |
| 459 invalid_token); | |
| 460 #endif | |
| 461 } | 376 } |
| 462 | 377 |
| 463 void OAuth2TokenService::OnFetchComplete(Fetcher* fetcher) { | 378 void OAuth2TokenService::OnFetchComplete(Fetcher* fetcher) { |
| 464 DCHECK(content::BrowserThread::CurrentlyOn(content::BrowserThread::UI)); | 379 DCHECK(content::BrowserThread::CurrentlyOn(content::BrowserThread::UI)); |
| 465 | 380 |
| 466 // Update the auth error state so auth errors are appropriately communicated | 381 // Update the auth error state so auth errors are appropriately communicated |
| 467 // to the user. | 382 // to the user. |
| 468 UpdateAuthError(fetcher->error()); | 383 UpdateAuthError(fetcher->error()); |
| 469 | 384 |
| 470 // Note |fetcher| is recorded in |pending_fetcher_| mapped to its refresh | 385 // Note |fetcher| is recorded in |pending_fetcher_| mapped to its refresh |
| 471 // token and scope set. This is guaranteed as follows; here a Fetcher is said | 386 // token and scope set. This is guaranteed as follows; here a Fetcher is said |
| 472 // to be uncompleted if it has not finished calling back | 387 // to be uncompleted if it has not finished calling back |
| 473 // OAuth2TokenService::OnFetchComplete(). | 388 // OAuth2TokenService::OnFetchComplete(). |
| 474 // | 389 // |
| 475 // (1) All the live Fetchers are created by this service. | 390 // (1) All the live Fetchers are created by this service. |
| 476 // This is because (1) all the live Fetchers are created by a live | 391 // This is because (1) all the live Fetchers are created by a live |
| 477 // service, as all the fetchers created by a service are destructed in the | 392 // service, as all the fetchers created by a service are destructed in the |
| 478 // service's dtor, and (2) there is at most one live OAuth2TokenSevice for | 393 // service's dtor. |
| 479 // a given profile at a time. | |
| 480 // | 394 // |
| 481 // (2) All the uncompleted Fetchers created by this service are recorded in | 395 // (2) All the uncompleted Fetchers created by this service are recorded in |
| 482 // |pending_fetchers_|. | 396 // |pending_fetchers_|. |
| 483 // This is because (1) all the created Fetchers are added to | 397 // This is because (1) all the created Fetchers are added to |
| 484 // |pending_fetchers_| (in method StartRequest()) and (2) method | 398 // |pending_fetchers_| (in method StartRequest()) and (2) method |
| 485 // OnFetchComplete() is the only place where a Fetcher is erased from | 399 // OnFetchComplete() is the only place where a Fetcher is erased from |
| 486 // |pending_fetchers_|. Note no Fetcher is erased in method | 400 // |pending_fetchers_|. Note no Fetcher is erased in method |
| 487 // StartRequest(). | 401 // StartRequest(). |
| 488 // | 402 // |
| 489 // (3) Each of the Fetchers recorded in |pending_fetchers_| is mapped to its | 403 // (3) Each of the Fetchers recorded in |pending_fetchers_| is mapped to its |
| 490 // refresh token and ScopeSet. This is guaranteed by Fetcher creation in | 404 // refresh token and ScopeSet. This is guaranteed by Fetcher creation in |
| 491 // method StartReuest(). | 405 // method StartRequest(). |
| 492 // | 406 // |
| 493 // When this method is called, |fetcher| is alive and uncompleted. | 407 // When this method is called, |fetcher| is alive and uncompleted. |
| 494 // By (1), |fetcher| is created by this service. | 408 // By (1), |fetcher| is created by this service. |
| 495 // Then by (2), |fetcher| is recorded in |pending_fetchers_|. | 409 // Then by (2), |fetcher| is recorded in |pending_fetchers_|. |
| 496 // Then by (3), |fetcher_| is mapped to its refresh token and ScopeSet. | 410 // Then by (3), |fetcher_| is mapped to its refresh token and ScopeSet. |
| 497 std::map<FetchParameters, Fetcher*>::iterator iter = | 411 std::map<FetchParameters, Fetcher*>::iterator iter = |
| 498 pending_fetchers_.find(std::make_pair( | 412 pending_fetchers_.find(std::make_pair( |
| 499 fetcher->GetRefreshToken(), fetcher->GetScopeSet())); | 413 fetcher->GetRefreshToken(), fetcher->GetScopeSet())); |
| 500 DCHECK(iter != pending_fetchers_.end()); | 414 DCHECK(iter != pending_fetchers_.end()); |
| 501 DCHECK_EQ(fetcher, iter->second); | 415 DCHECK_EQ(fetcher, iter->second); |
| 502 pending_fetchers_.erase(iter); | 416 pending_fetchers_.erase(iter); |
| 503 } | 417 } |
| 504 | 418 |
| 419 bool OAuth2TokenService::HasCacheEntry( |
| 420 const OAuth2TokenService::ScopeSet& scopes) { |
| 421 const CacheEntry* cache_entry = GetCacheEntry(scopes); |
| 422 return cache_entry && cache_entry->access_token.length(); |
| 423 } |
| 424 |
| 505 const OAuth2TokenService::CacheEntry* OAuth2TokenService::GetCacheEntry( | 425 const OAuth2TokenService::CacheEntry* OAuth2TokenService::GetCacheEntry( |
| 506 const OAuth2TokenService::ScopeSet& scopes) { | 426 const OAuth2TokenService::ScopeSet& scopes) { |
| 507 DCHECK(content::BrowserThread::CurrentlyOn(content::BrowserThread::UI)); | 427 DCHECK(content::BrowserThread::CurrentlyOn(content::BrowserThread::UI)); |
| 508 TokenCache::iterator token_iterator = token_cache_.find(scopes); | 428 TokenCache::iterator token_iterator = token_cache_.find(scopes); |
| 509 if (token_iterator == token_cache_.end()) | 429 if (token_iterator == token_cache_.end()) |
| 510 return NULL; | 430 return NULL; |
| 511 if (token_iterator->second.expiration_date <= base::Time::Now()) { | 431 if (token_iterator->second.expiration_date <= base::Time::Now()) { |
| 512 token_cache_.erase(token_iterator); | 432 token_cache_.erase(token_iterator); |
| 513 return NULL; | 433 return NULL; |
| 514 } | 434 } |
| (...skipping 13 matching lines...) Expand all Loading... |
| 528 return false; | 448 return false; |
| 529 } | 449 } |
| 530 | 450 |
| 531 void OAuth2TokenService::RegisterCacheEntry( | 451 void OAuth2TokenService::RegisterCacheEntry( |
| 532 const std::string& refresh_token, | 452 const std::string& refresh_token, |
| 533 const OAuth2TokenService::ScopeSet& scopes, | 453 const OAuth2TokenService::ScopeSet& scopes, |
| 534 const std::string& access_token, | 454 const std::string& access_token, |
| 535 const base::Time& expiration_date) { | 455 const base::Time& expiration_date) { |
| 536 DCHECK(content::BrowserThread::CurrentlyOn(content::BrowserThread::UI)); | 456 DCHECK(content::BrowserThread::CurrentlyOn(content::BrowserThread::UI)); |
| 537 | 457 |
| 538 #if !defined(OS_ANDROID) | |
| 539 // Only register OAuth2 access tokens for the refresh token held by | |
| 540 // TokenService. | |
| 541 TokenService* token_service = TokenServiceFactory::GetForProfile(profile_); | |
| 542 if (!token_service || | |
| 543 !token_service->HasOAuthLoginToken() || | |
| 544 token_service->GetOAuth2LoginRefreshToken().compare(refresh_token) != 0) { | |
| 545 DLOG(INFO) << | |
| 546 "Received a token with a refresh token not maintained by TokenService."; | |
| 547 return; | |
| 548 } | |
| 549 #endif | |
| 550 | |
| 551 CacheEntry& token = token_cache_[scopes]; | 458 CacheEntry& token = token_cache_[scopes]; |
| 552 token.access_token = access_token; | 459 token.access_token = access_token; |
| 553 token.expiration_date = expiration_date; | 460 token.expiration_date = expiration_date; |
| 554 } | 461 } |
| 555 | 462 |
| 556 void OAuth2TokenService::Observe(int type, | 463 void OAuth2TokenService::UpdateAuthError(const GoogleServiceAuthError& error) { |
| 557 const content::NotificationSource& source, | 464 // Default implementation does nothing. |
| 558 const content::NotificationDetails& details) { | |
| 559 DCHECK(type == chrome::NOTIFICATION_TOKENS_CLEARED || | |
| 560 type == chrome::NOTIFICATION_TOKEN_AVAILABLE); | |
| 561 if (type == chrome::NOTIFICATION_TOKEN_AVAILABLE) { | |
| 562 TokenService::TokenAvailableDetails* tok_details = | |
| 563 content::Details<TokenService::TokenAvailableDetails>(details).ptr(); | |
| 564 if (tok_details->service() != GaiaConstants::kGaiaOAuth2LoginRefreshToken) | |
| 565 return; | |
| 566 } | |
| 567 // The GaiaConstants::kGaiaOAuth2LoginRefreshToken token is used to create | |
| 568 // OAuth2 access tokens. If this token either changes or is cleared, any | |
| 569 // available tokens must be invalidated. | |
| 570 token_cache_.clear(); | |
| 571 UpdateAuthError(GoogleServiceAuthError::AuthErrorNone()); | |
| 572 } | 465 } |
| 573 | 466 |
| 574 void OAuth2TokenService::UpdateAuthError(const GoogleServiceAuthError& error) { | 467 void OAuth2TokenService::ClearCache() { |
| 575 // Do not report connection errors as these are not actually auth errors. | 468 DCHECK(content::BrowserThread::CurrentlyOn(content::BrowserThread::UI)); |
| 576 // We also want to avoid masking a "real" auth error just because we | 469 token_cache_.clear(); |
| 577 // subsequently get a transient network error. | |
| 578 if (error.state() == GoogleServiceAuthError::CONNECTION_FAILED) | |
| 579 return; | |
| 580 | |
| 581 if (error.state() != last_auth_error_.state()) { | |
| 582 last_auth_error_ = error; | |
| 583 SigninManagerFactory::GetForProfile(profile_)->signin_global_error()-> | |
| 584 AuthStatusChanged(); | |
| 585 } | |
| 586 } | 470 } |
| 587 | 471 |
| 588 GoogleServiceAuthError OAuth2TokenService::GetAuthStatus() const { | 472 int OAuth2TokenService::cache_size_for_testing() const { |
| 589 return last_auth_error_; | 473 return token_cache_.size(); |
| 590 } | 474 } |
| OLD | NEW |