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" |
(...skipping 11 matching lines...) Expand all Loading... |
22 #include "chrome/common/chrome_notification_types.h" | 22 #include "chrome/common/chrome_notification_types.h" |
23 #include "content/public/browser/browser_thread.h" | 23 #include "content/public/browser/browser_thread.h" |
24 #include "content/public/browser/notification_details.h" | 24 #include "content/public/browser/notification_details.h" |
25 #include "content/public/browser/notification_source.h" | 25 #include "content/public/browser/notification_source.h" |
26 #include "google_apis/gaia/gaia_constants.h" | 26 #include "google_apis/gaia/gaia_constants.h" |
27 #include "google_apis/gaia/gaia_urls.h" | 27 #include "google_apis/gaia/gaia_urls.h" |
28 #include "google_apis/gaia/google_service_auth_error.h" | 28 #include "google_apis/gaia/google_service_auth_error.h" |
29 #include "google_apis/gaia/oauth2_access_token_consumer.h" | 29 #include "google_apis/gaia/oauth2_access_token_consumer.h" |
30 #include "google_apis/gaia/oauth2_access_token_fetcher.h" | 30 #include "google_apis/gaia/oauth2_access_token_fetcher.h" |
31 | 31 |
| 32 #if defined(OS_ANDROID) |
| 33 #include "chrome/browser/sync/profile_sync_service_android.h" |
| 34 #endif |
| 35 |
32 namespace { | 36 namespace { |
33 | 37 |
34 // Maximum number of retries in fetching an OAuth2 access token. | 38 // Maximum number of retries in fetching an OAuth2 access token. |
35 const int kMaxFetchRetryNum = 5; | 39 const int kMaxFetchRetryNum = 5; |
36 | 40 |
37 // Returns an exponential backoff in milliseconds including randomness less than | 41 // Returns an exponential backoff in milliseconds including randomness less than |
38 // 1000 ms when retrying fetching an OAuth2 access token. | 42 // 1000 ms when retrying fetching an OAuth2 access token. |
39 int64 ComputeExponentialBackOffMilliseconds(int retry_num) { | 43 int64 ComputeExponentialBackOffMilliseconds(int retry_num) { |
40 DCHECK(retry_num < kMaxFetchRetryNum); | 44 DCHECK(retry_num < kMaxFetchRetryNum); |
41 int64 exponential_backoff_in_seconds = 1 << retry_num; | 45 int64 exponential_backoff_in_seconds = 1 << retry_num; |
(...skipping 325 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
367 base::Time expiration_date) { | 371 base::Time expiration_date) { |
368 DCHECK(content::BrowserThread::CurrentlyOn(content::BrowserThread::UI)); | 372 DCHECK(content::BrowserThread::CurrentlyOn(content::BrowserThread::UI)); |
369 | 373 |
370 if (request) | 374 if (request) |
371 request->InformConsumer(error, access_token, expiration_date); | 375 request->InformConsumer(error, access_token, expiration_date); |
372 } | 376 } |
373 | 377 |
374 scoped_ptr<OAuth2TokenService::Request> OAuth2TokenService::StartRequest( | 378 scoped_ptr<OAuth2TokenService::Request> OAuth2TokenService::StartRequest( |
375 const OAuth2TokenService::ScopeSet& scopes, | 379 const OAuth2TokenService::ScopeSet& scopes, |
376 OAuth2TokenService::Consumer* consumer) { | 380 OAuth2TokenService::Consumer* consumer) { |
| 381 return InvalidateTokenAndStartRequest(scopes, consumer, std::string()); |
| 382 } |
| 383 |
| 384 scoped_ptr<OAuth2TokenService::Request> |
| 385 OAuth2TokenService::InvalidateTokenAndStartRequest( |
| 386 const OAuth2TokenService::ScopeSet& scopes, |
| 387 OAuth2TokenService::Consumer* consumer, |
| 388 const std::string& invalid_token) { |
377 DCHECK(content::BrowserThread::CurrentlyOn(content::BrowserThread::UI)); | 389 DCHECK(content::BrowserThread::CurrentlyOn(content::BrowserThread::UI)); |
378 | 390 |
379 scoped_ptr<RequestImpl> request(new RequestImpl(consumer)); | 391 scoped_ptr<RequestImpl> request(new RequestImpl(consumer)); |
380 | 392 |
| 393 #if !defined(OS_ANDROID) |
381 TokenService* token_service = TokenServiceFactory::GetForProfile(profile_); | 394 TokenService* token_service = TokenServiceFactory::GetForProfile(profile_); |
382 if (!token_service || !token_service->HasOAuthLoginToken()) { | 395 if (!token_service || !token_service->HasOAuthLoginToken()) { |
383 MessageLoop::current()->PostTask(FROM_HERE, base::Bind( | 396 MessageLoop::current()->PostTask(FROM_HERE, base::Bind( |
384 &OAuth2TokenService::InformConsumer, | 397 &OAuth2TokenService::InformConsumer, |
385 request->AsWeakPtr(), | 398 request->AsWeakPtr(), |
386 GoogleServiceAuthError(GoogleServiceAuthError::USER_NOT_SIGNED_UP), | 399 GoogleServiceAuthError(GoogleServiceAuthError::USER_NOT_SIGNED_UP), |
387 std::string(), | 400 std::string(), |
388 base::Time())); | 401 base::Time())); |
389 return request.PassAs<Request>(); | 402 return request.PassAs<Request>(); |
390 } | 403 } |
| 404 #endif |
| 405 |
| 406 if (!invalid_token.empty()) |
| 407 RemoveCacheEntry(scopes, invalid_token); |
391 | 408 |
392 const CacheEntry* cache_entry = GetCacheEntry(scopes); | 409 const CacheEntry* cache_entry = GetCacheEntry(scopes); |
393 if (cache_entry && cache_entry->access_token.length()) { | 410 if (cache_entry && cache_entry->access_token.length()) { |
394 MessageLoop::current()->PostTask(FROM_HERE, base::Bind( | 411 MessageLoop::current()->PostTask(FROM_HERE, base::Bind( |
395 &OAuth2TokenService::InformConsumer, | 412 &OAuth2TokenService::InformConsumer, |
396 request->AsWeakPtr(), | 413 request->AsWeakPtr(), |
397 GoogleServiceAuthError(GoogleServiceAuthError::NONE), | 414 GoogleServiceAuthError(GoogleServiceAuthError::NONE), |
398 cache_entry->access_token, | 415 cache_entry->access_token, |
399 cache_entry->expiration_date)); | 416 cache_entry->expiration_date)); |
400 return request.PassAs<Request>(); | 417 return request.PassAs<Request>(); |
401 } | 418 } |
402 | 419 |
| 420 #if defined(OS_ANDROID) |
| 421 DCHECK_EQ(scopes.size(), 1U); |
| 422 std::vector<std::string> scope_list(scopes.begin(), scopes.end()); |
| 423 ProfileSyncServiceAndroid* sync_service = |
| 424 ProfileSyncServiceAndroid::GetProfileSyncServiceAndroid(); |
| 425 sync_service->FetchOAuth2Token( |
| 426 scope_list.front(), |
| 427 invalid_token, |
| 428 base::Bind(&OAuth2TokenService::InformConsumer, |
| 429 request->AsWeakPtr())); |
| 430 return request.PassAs<Request>(); |
| 431 #else |
403 std::string refresh_token = token_service->GetOAuth2LoginRefreshToken(); | 432 std::string refresh_token = token_service->GetOAuth2LoginRefreshToken(); |
404 if (!refresh_token.length()) { | 433 if (!refresh_token.length()) { |
405 MessageLoop::current()->PostTask(FROM_HERE, base::Bind( | 434 MessageLoop::current()->PostTask(FROM_HERE, base::Bind( |
406 &OAuth2TokenService::InformConsumer, | 435 &OAuth2TokenService::InformConsumer, |
407 request->AsWeakPtr(), | 436 request->AsWeakPtr(), |
408 GoogleServiceAuthError( | 437 GoogleServiceAuthError( |
409 GoogleServiceAuthError::INVALID_GAIA_CREDENTIALS), | 438 GoogleServiceAuthError::INVALID_GAIA_CREDENTIALS), |
410 std::string(), | 439 std::string(), |
411 base::Time())); | 440 base::Time())); |
412 return request.PassAs<Request>(); | 441 return request.PassAs<Request>(); |
413 } | 442 } |
414 | 443 |
415 // Makes sure there is a pending fetcher for |scopes| and |refresh_token|. | 444 // Makes sure there is a pending fetcher for |scopes| and |refresh_token|. |
416 // Adds |request| to the waiting request list of this fetcher so |request| | 445 // Adds |request| to the waiting request list of this fetcher so |request| |
417 // will be called back when this fetcher finishes fetching. | 446 // will be called back when this fetcher finishes fetching. |
418 FetchParameters fetch_parameters = std::make_pair(refresh_token, scopes); | 447 FetchParameters fetch_parameters = std::make_pair(refresh_token, scopes); |
419 std::map<FetchParameters, Fetcher*>::iterator iter = | 448 std::map<FetchParameters, Fetcher*>::iterator iter = |
420 pending_fetchers_.find(fetch_parameters); | 449 pending_fetchers_.find(fetch_parameters); |
421 if (iter != pending_fetchers_.end()) { | 450 if (iter != pending_fetchers_.end()) { |
422 iter->second->AddWaitingRequest(request->AsWeakPtr()); | 451 iter->second->AddWaitingRequest(request->AsWeakPtr()); |
423 return request.PassAs<Request>(); | 452 return request.PassAs<Request>(); |
424 } | 453 } |
425 pending_fetchers_[fetch_parameters] = Fetcher::CreateAndStart( | 454 pending_fetchers_[fetch_parameters] = Fetcher::CreateAndStart( |
426 profile_, getter_, refresh_token, scopes, request->AsWeakPtr()); | 455 profile_, getter_, refresh_token, scopes, request->AsWeakPtr()); |
427 return request.PassAs<Request>(); | 456 return request.PassAs<Request>(); |
| 457 #endif // defined(OS_ANDROID) |
428 } | 458 } |
429 | 459 |
430 void OAuth2TokenService::OnFetchComplete(Fetcher* fetcher) { | 460 void OAuth2TokenService::OnFetchComplete(Fetcher* fetcher) { |
431 DCHECK(content::BrowserThread::CurrentlyOn(content::BrowserThread::UI)); | 461 DCHECK(content::BrowserThread::CurrentlyOn(content::BrowserThread::UI)); |
432 | 462 |
433 // Update the auth error state so auth errors are appropriately communicated | 463 // Update the auth error state so auth errors are appropriately communicated |
434 // to the user. | 464 // to the user. |
435 UpdateAuthError(fetcher->error()); | 465 UpdateAuthError(fetcher->error()); |
436 | 466 |
437 // Note |fetcher| is recorded in |pending_fetcher_| mapped to its refresh | 467 // Note |fetcher| is recorded in |pending_fetcher_| mapped to its refresh |
(...skipping 37 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
475 TokenCache::iterator token_iterator = token_cache_.find(scopes); | 505 TokenCache::iterator token_iterator = token_cache_.find(scopes); |
476 if (token_iterator == token_cache_.end()) | 506 if (token_iterator == token_cache_.end()) |
477 return NULL; | 507 return NULL; |
478 if (token_iterator->second.expiration_date <= base::Time::Now()) { | 508 if (token_iterator->second.expiration_date <= base::Time::Now()) { |
479 token_cache_.erase(token_iterator); | 509 token_cache_.erase(token_iterator); |
480 return NULL; | 510 return NULL; |
481 } | 511 } |
482 return &token_iterator->second; | 512 return &token_iterator->second; |
483 } | 513 } |
484 | 514 |
| 515 bool OAuth2TokenService::RemoveCacheEntry( |
| 516 const OAuth2TokenService::ScopeSet& scopes, |
| 517 const std::string& token_to_remove) { |
| 518 DCHECK(content::BrowserThread::CurrentlyOn(content::BrowserThread::UI)); |
| 519 TokenCache::iterator token_iterator = token_cache_.find(scopes); |
| 520 if (token_iterator == token_cache_.end() && |
| 521 token_iterator->second.access_token == token_to_remove) { |
| 522 token_cache_.erase(token_iterator); |
| 523 return true; |
| 524 } |
| 525 return false; |
| 526 } |
| 527 |
485 void OAuth2TokenService::RegisterCacheEntry( | 528 void OAuth2TokenService::RegisterCacheEntry( |
486 const std::string& refresh_token, | 529 const std::string& refresh_token, |
487 const OAuth2TokenService::ScopeSet& scopes, | 530 const OAuth2TokenService::ScopeSet& scopes, |
488 const std::string& access_token, | 531 const std::string& access_token, |
489 const base::Time& expiration_date) { | 532 const base::Time& expiration_date) { |
490 DCHECK(content::BrowserThread::CurrentlyOn(content::BrowserThread::UI)); | 533 DCHECK(content::BrowserThread::CurrentlyOn(content::BrowserThread::UI)); |
491 | 534 |
| 535 #if !defined(OS_ANDROID) |
492 // Only register OAuth2 access tokens for the refresh token held by | 536 // Only register OAuth2 access tokens for the refresh token held by |
493 // TokenService. | 537 // TokenService. |
494 TokenService* token_service = TokenServiceFactory::GetForProfile(profile_); | 538 TokenService* token_service = TokenServiceFactory::GetForProfile(profile_); |
495 if (!token_service || | 539 if (!token_service || |
496 !token_service->HasOAuthLoginToken() || | 540 !token_service->HasOAuthLoginToken() || |
497 token_service->GetOAuth2LoginRefreshToken().compare(refresh_token) != 0) { | 541 token_service->GetOAuth2LoginRefreshToken().compare(refresh_token) != 0) { |
498 DLOG(INFO) << | 542 DLOG(INFO) << |
499 "Received a token with a refresh token not maintained by TokenService."; | 543 "Received a token with a refresh token not maintained by TokenService."; |
500 return; | 544 return; |
501 } | 545 } |
| 546 #endif |
502 | 547 |
503 CacheEntry& token = token_cache_[scopes]; | 548 CacheEntry& token = token_cache_[scopes]; |
504 token.access_token = access_token; | 549 token.access_token = access_token; |
505 token.expiration_date = expiration_date; | 550 token.expiration_date = expiration_date; |
506 } | 551 } |
507 | 552 |
508 void OAuth2TokenService::Observe(int type, | 553 void OAuth2TokenService::Observe(int type, |
509 const content::NotificationSource& source, | 554 const content::NotificationSource& source, |
510 const content::NotificationDetails& details) { | 555 const content::NotificationDetails& details) { |
511 DCHECK(type == chrome::NOTIFICATION_TOKENS_CLEARED || | 556 DCHECK(type == chrome::NOTIFICATION_TOKENS_CLEARED || |
(...skipping 21 matching lines...) Expand all Loading... |
533 if (error.state() != last_auth_error_.state()) { | 578 if (error.state() != last_auth_error_.state()) { |
534 last_auth_error_ = error; | 579 last_auth_error_ = error; |
535 SigninManagerFactory::GetForProfile(profile_)->signin_global_error()-> | 580 SigninManagerFactory::GetForProfile(profile_)->signin_global_error()-> |
536 AuthStatusChanged(); | 581 AuthStatusChanged(); |
537 } | 582 } |
538 } | 583 } |
539 | 584 |
540 GoogleServiceAuthError OAuth2TokenService::GetAuthStatus() const { | 585 GoogleServiceAuthError OAuth2TokenService::GetAuthStatus() const { |
541 return last_auth_error_; | 586 return last_auth_error_; |
542 } | 587 } |
OLD | NEW |