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