Home | History | Annotate | Download | only in signin
      1 // Copyright 2013 The Chromium Authors. All rights reserved.
      2 // Use of this source code is governed by a BSD-style license that can be
      3 // found in the LICENSE file.
      4 
      5 #include "base/run_loop.h"
      6 #include "chrome/browser/signin/oauth2_token_service.h"
      7 #include "chrome/browser/signin/oauth2_token_service_test_util.h"
      8 #include "chrome/browser/signin/profile_oauth2_token_service.h"
      9 #include "chrome/browser/signin/profile_oauth2_token_service_factory.h"
     10 #include "chrome/browser/signin/token_service_unittest.h"
     11 #include "content/public/browser/browser_thread.h"
     12 #include "google_apis/gaia/gaia_constants.h"
     13 #include "net/http/http_status_code.h"
     14 #include "net/url_request/test_url_fetcher_factory.h"
     15 #include "testing/gtest/include/gtest/gtest.h"
     16 
     17 using content::BrowserThread;
     18 
     19 class ProfileOAuth2TokenServiceTest : public TokenServiceTestHarness,
     20                                       public OAuth2TokenService::Observer {
     21  public:
     22   ProfileOAuth2TokenServiceTest()
     23       : token_available_count_(0),
     24         token_revoked_count_(0),
     25         tokens_loaded_count_(0),
     26         tokens_cleared_count_(0) {
     27   }
     28 
     29   virtual void SetUp() OVERRIDE {
     30     TokenServiceTestHarness::SetUp();
     31     UpdateCredentialsOnService();
     32     oauth2_service_ = ProfileOAuth2TokenServiceFactory::GetForProfile(
     33         profile());
     34 
     35     oauth2_service_->AddObserver(this);
     36   }
     37 
     38   virtual void TearDown() OVERRIDE {
     39     oauth2_service_->RemoveObserver(this);
     40     TokenServiceTestHarness::TearDown();
     41   }
     42 
     43   // OAuth2TokenService::Observer implementation.
     44   virtual void OnRefreshTokenAvailable(const std::string& account_id) OVERRIDE {
     45     ++token_available_count_;
     46   }
     47   virtual void OnRefreshTokenRevoked(
     48       const std::string& account_id,
     49       const GoogleServiceAuthError& error) OVERRIDE {
     50     ++token_revoked_count_;
     51   }
     52   virtual void OnRefreshTokensLoaded() OVERRIDE {
     53     ++tokens_loaded_count_;
     54   }
     55   virtual void OnRefreshTokensCleared() OVERRIDE {
     56     ++tokens_cleared_count_;
     57   }
     58 
     59   void ResetObserverCounts() {
     60     token_available_count_ = 0;
     61     token_revoked_count_ = 0;
     62     tokens_loaded_count_ = 0;
     63     tokens_cleared_count_ = 0;
     64   }
     65 
     66   void ExpectNoNotifications() {
     67     EXPECT_EQ(0, token_available_count_);
     68     EXPECT_EQ(0, token_revoked_count_);
     69     EXPECT_EQ(0, tokens_loaded_count_);
     70     EXPECT_EQ(0, tokens_cleared_count_);
     71     ResetObserverCounts();
     72   }
     73 
     74   void ExpectOneTokenAvailableNotification() {
     75     EXPECT_EQ(1, token_available_count_);
     76     EXPECT_EQ(0, token_revoked_count_);
     77     EXPECT_EQ(0, tokens_loaded_count_);
     78     EXPECT_EQ(0, tokens_cleared_count_);
     79     ResetObserverCounts();
     80   }
     81 
     82   void ExpectOneTokenRevokedNotification() {
     83     EXPECT_EQ(0, token_available_count_);
     84     EXPECT_EQ(1, token_revoked_count_);
     85     EXPECT_EQ(0, tokens_loaded_count_);
     86     EXPECT_EQ(0, tokens_cleared_count_);
     87     ResetObserverCounts();
     88   }
     89 
     90   void ExpectOneTokensLoadedNotification() {
     91     EXPECT_EQ(0, token_available_count_);
     92     EXPECT_EQ(0, token_revoked_count_);
     93     EXPECT_EQ(1, tokens_loaded_count_);
     94     EXPECT_EQ(0, tokens_cleared_count_);
     95     ResetObserverCounts();
     96   }
     97 
     98   void ExpectOneTokensClearedNotification() {
     99     EXPECT_EQ(0, token_available_count_);
    100     EXPECT_EQ(0, token_revoked_count_);
    101     EXPECT_EQ(0, tokens_loaded_count_);
    102     EXPECT_EQ(1, tokens_cleared_count_);
    103     ResetObserverCounts();
    104   }
    105 
    106  protected:
    107   net::TestURLFetcherFactory factory_;
    108   ProfileOAuth2TokenService* oauth2_service_;
    109   TestingOAuth2TokenServiceConsumer consumer_;
    110   int token_available_count_;
    111   int token_revoked_count_;
    112   int tokens_loaded_count_;
    113   int tokens_cleared_count_;
    114 };
    115 
    116 TEST_F(ProfileOAuth2TokenServiceTest, Notifications) {
    117   EXPECT_EQ(0, oauth2_service_->cache_size_for_testing());
    118   service()->IssueAuthTokenForTest(GaiaConstants::kGaiaOAuth2LoginRefreshToken,
    119                                    "refreshToken");
    120   ExpectOneTokenAvailableNotification();
    121 
    122   service()->EraseTokensFromDB();
    123   service()->ResetCredentialsInMemory();
    124   ExpectOneTokensClearedNotification();
    125 }
    126 
    127 TEST_F(ProfileOAuth2TokenServiceTest, PersistenceDBUpgrade) {
    128   // No username for profile in unit tests, defaulting to empty string.
    129   std::string main_account_id;
    130   std::string main_refresh_token("old_refresh_token");
    131 
    132   // Populate DB with legacy tokens.
    133   service()->OnIssueAuthTokenSuccess(GaiaConstants::kSyncService,
    134                                      "syncServiceToken");
    135   service()->OnIssueAuthTokenSuccess(GaiaConstants::kLSOService,
    136                                      "lsoToken");
    137   service()->OnIssueAuthTokenSuccess(
    138       GaiaConstants::kGaiaOAuth2LoginRefreshToken,
    139       main_refresh_token);
    140   // Add a token using the new API.
    141   ResetObserverCounts();
    142 
    143   // Force LoadCredentials.
    144   oauth2_service_->LoadCredentials();
    145   base::RunLoop().RunUntilIdle();
    146 
    147   // Legacy tokens get discarded, but the old refresh token is kept.
    148   EXPECT_EQ(1, tokens_loaded_count_);
    149   EXPECT_EQ(1, token_available_count_);
    150   EXPECT_TRUE(oauth2_service_->RefreshTokenIsAvailable());
    151   EXPECT_EQ(1U, oauth2_service_->refresh_tokens_.size());
    152   EXPECT_EQ(main_refresh_token,
    153             oauth2_service_->refresh_tokens_[main_account_id]);
    154 
    155   // Add an old legacy token to the DB, to ensure it will not overwrite existing
    156   // credentials for main account.
    157   service()->OnIssueAuthTokenSuccess(
    158       GaiaConstants::kGaiaOAuth2LoginRefreshToken,
    159       "secondOldRefreshToken");
    160   // Add some other legacy token. (Expected to get discarded).
    161   service()->OnIssueAuthTokenSuccess(GaiaConstants::kLSOService,
    162                                      "lsoToken");
    163   // Also add a token using PO2TS.UpdateCredentials and make sure upgrade does
    164   // not wipe it.
    165   std::string other_account_id("other_account_id");
    166   std::string other_refresh_token("other_refresh_token");
    167   oauth2_service_->UpdateCredentials(other_account_id, other_refresh_token);
    168   ResetObserverCounts();
    169 
    170   // Force LoadCredentials.
    171   oauth2_service_->LoadCredentials();
    172   base::RunLoop().RunUntilIdle();
    173 
    174   // Again legacy tokens get discarded, but since the main porfile account
    175   // token is present it is not overwritten.
    176   EXPECT_EQ(2, token_available_count_);
    177   EXPECT_EQ(1, tokens_loaded_count_);
    178   EXPECT_TRUE(oauth2_service_->RefreshTokenIsAvailable());
    179   EXPECT_EQ(2U, oauth2_service_->refresh_tokens_.size());
    180   EXPECT_EQ(main_refresh_token,
    181             oauth2_service_->refresh_tokens_[main_account_id]);
    182   EXPECT_EQ(other_refresh_token,
    183             oauth2_service_->refresh_tokens_[other_account_id]);
    184 
    185   oauth2_service_->RevokeAllCredentials();
    186 }
    187 
    188 TEST_F(ProfileOAuth2TokenServiceTest, PersistenceRevokeCredentials) {
    189   std::string account_id_1 = "account_id_1";
    190   std::string refresh_token_1 = "refresh_token_1";
    191   std::string account_id_2 = "account_id_2";
    192   std::string refresh_token_2 = "refresh_token_2";
    193 
    194   // TODO(fgorski): Enable below when implemented:
    195   // EXPECT_FALSE(oauth2_servive_->RefreshTokenIsAvailable(account_id_1));
    196   // EXPECT_FALSE(oauth2_servive_->RefreshTokenIsAvailable(account_id_2));
    197 
    198   oauth2_service_->UpdateCredentials(account_id_1, refresh_token_1);
    199   oauth2_service_->UpdateCredentials(account_id_2, refresh_token_2);
    200 
    201   // TODO(fgorski): Enable below when implemented:
    202   // EXPECT_TRUE(oauth2_servive_->RefreshTokenIsAvailable(account_id_1));
    203   // EXPECT_TRUE(oauth2_service_->RefreshTokenIsAvailable(account_id_2));
    204 
    205   ResetObserverCounts();
    206   oauth2_service_->RevokeCredentials(account_id_1);
    207   ExpectOneTokenRevokedNotification();
    208 
    209   // TODO(fgorski): Enable below when implemented:
    210   // EXPECT_FALSE(oauth2_servive_->RefreshTokenIsAvailable(account_id_1));
    211   // EXPECT_TRUE(oauth2_service_->RefreshTokenIsAvailable(account_id_2));
    212 
    213   oauth2_service_->RevokeAllCredentials();
    214   EXPECT_EQ(0, token_available_count_);
    215   EXPECT_EQ(1, token_revoked_count_);
    216   EXPECT_EQ(0, tokens_loaded_count_);
    217   EXPECT_EQ(1, tokens_cleared_count_);
    218   ResetObserverCounts();
    219 }
    220 
    221 TEST_F(ProfileOAuth2TokenServiceTest, PersistenceLoadCredentials) {
    222   // Ensure DB is clean.
    223   oauth2_service_->RevokeAllCredentials();
    224   ExpectOneTokensClearedNotification();
    225   // Perform a load from an empty DB.
    226   oauth2_service_->LoadCredentials();
    227   base::RunLoop().RunUntilIdle();
    228   ExpectOneTokensLoadedNotification();
    229   EXPECT_EQ(0U, oauth2_service_->refresh_tokens_.size());
    230   // Setup a DB with tokens that don't require upgrade and clear memory.
    231   oauth2_service_->UpdateCredentials("account_id", "refresh_token");
    232   oauth2_service_->UpdateCredentials("account_id2", "refresh_token2");
    233   oauth2_service_->refresh_tokens_.clear();
    234   ResetObserverCounts();
    235 
    236   oauth2_service_->LoadCredentials();
    237   base::RunLoop().RunUntilIdle();
    238   EXPECT_EQ(2, token_available_count_);
    239   EXPECT_EQ(0, token_revoked_count_);
    240   EXPECT_EQ(1, tokens_loaded_count_);
    241   EXPECT_EQ(0, tokens_cleared_count_);
    242   ResetObserverCounts();
    243 
    244   // TODO(fgorski): Enable below when implemented:
    245   // EXPECT_TRUE(oauth2_servive_->RefreshTokenIsAvailable("account_id"));
    246   // EXPECT_TRUE(oauth2_service_->RefreshTokenIsAvailable("account_id2"));
    247 
    248   oauth2_service_->RevokeAllCredentials();
    249   EXPECT_EQ(0, token_available_count_);
    250   EXPECT_EQ(2, token_revoked_count_);
    251   EXPECT_EQ(0, tokens_loaded_count_);
    252   EXPECT_EQ(1, tokens_cleared_count_);
    253   ResetObserverCounts();
    254 }
    255 
    256 TEST_F(ProfileOAuth2TokenServiceTest, PersistanceNotifications) {
    257   EXPECT_EQ(0, oauth2_service_->cache_size_for_testing());
    258   oauth2_service_->UpdateCredentials("account_id", "refresh_token");
    259   ExpectOneTokenAvailableNotification();
    260 
    261   oauth2_service_->UpdateCredentials("account_id", "refresh_token");
    262   ExpectNoNotifications();
    263 
    264   oauth2_service_->UpdateCredentials("account_id", "refresh_token2");
    265   ExpectOneTokenAvailableNotification();
    266 
    267   oauth2_service_->RevokeCredentials("account_id");
    268   ExpectOneTokenRevokedNotification();
    269 
    270   oauth2_service_->UpdateCredentials("account_id", "refresh_token2");
    271   ExpectOneTokenAvailableNotification();
    272 
    273   oauth2_service_->RevokeAllCredentials();
    274   EXPECT_EQ(1, tokens_cleared_count_);
    275   ResetObserverCounts();
    276 }
    277 
    278 // Until the TokenService class is removed, problems fetching the LSO token
    279 // should translate to problems fetching the oauth2 refresh token.
    280 TEST_F(ProfileOAuth2TokenServiceTest, LsoNotification) {
    281   EXPECT_EQ(0, oauth2_service_->cache_size_for_testing());
    282 
    283   // Get a valid token.
    284   service()->IssueAuthTokenForTest(GaiaConstants::kGaiaOAuth2LoginRefreshToken,
    285                                    "refreshToken");
    286   ExpectOneTokenAvailableNotification();
    287 
    288   service()->OnIssueAuthTokenFailure(
    289       GaiaConstants::kLSOService,
    290       GoogleServiceAuthError(GoogleServiceAuthError::INVALID_GAIA_CREDENTIALS));
    291   ExpectOneTokenRevokedNotification();
    292 }
    293 
    294 // Until the TokenService class is removed, finish token loading in TokenService
    295 // should translate to finish token loading in ProfileOAuth2TokenService.
    296 TEST_F(ProfileOAuth2TokenServiceTest, TokensLoaded) {
    297   EXPECT_EQ(0, oauth2_service_->cache_size_for_testing());
    298   service()->LoadTokensFromDB();
    299   base::RunLoop().RunUntilIdle();
    300   ExpectOneTokensLoadedNotification();
    301 }
    302 
    303 TEST_F(ProfileOAuth2TokenServiceTest, UnknownNotificationsAreNoops) {
    304   EXPECT_EQ(0, oauth2_service_->cache_size_for_testing());
    305   service()->IssueAuthTokenForTest("foo", "toto");
    306   ExpectNoNotifications();
    307 
    308   // Get a valid token.
    309   service()->IssueAuthTokenForTest(GaiaConstants::kGaiaOAuth2LoginRefreshToken,
    310                                    "refreshToken");
    311   ExpectOneTokenAvailableNotification();
    312 
    313   service()->IssueAuthTokenForTest("bar", "baz");
    314   ExpectNoNotifications();
    315 }
    316 
    317 TEST_F(ProfileOAuth2TokenServiceTest, TokenServiceUpdateClearsCache) {
    318   EXPECT_EQ(0, oauth2_service_->cache_size_for_testing());
    319   std::set<std::string> scope_list;
    320   scope_list.insert("scope");
    321   service()->IssueAuthTokenForTest(GaiaConstants::kGaiaOAuth2LoginRefreshToken,
    322                                    "refreshToken");
    323   ExpectOneTokenAvailableNotification();
    324   scoped_ptr<OAuth2TokenService::Request> request(oauth2_service_->StartRequest(
    325       scope_list, &consumer_));
    326   base::RunLoop().RunUntilIdle();
    327   net::TestURLFetcher* fetcher = factory_.GetFetcherByID(0);
    328   fetcher->set_response_code(net::HTTP_OK);
    329   fetcher->SetResponseString(GetValidTokenResponse("token", 3600));
    330   fetcher->delegate()->OnURLFetchComplete(fetcher);
    331   EXPECT_EQ(1, consumer_.number_of_successful_tokens_);
    332   EXPECT_EQ(0, consumer_.number_of_errors_);
    333   EXPECT_EQ("token", consumer_.last_token_);
    334   EXPECT_EQ(1, oauth2_service_->cache_size_for_testing());
    335 
    336   // Signs out and signs in
    337   service()->IssueAuthTokenForTest(GaiaConstants::kGaiaOAuth2LoginRefreshToken,
    338                                   "");
    339   ExpectOneTokenAvailableNotification();
    340   service()->EraseTokensFromDB();
    341   ExpectOneTokensClearedNotification();
    342 
    343   EXPECT_EQ(0, oauth2_service_->cache_size_for_testing());
    344   service()->IssueAuthTokenForTest(GaiaConstants::kGaiaOAuth2LoginRefreshToken,
    345                                   "refreshToken");
    346   ExpectOneTokenAvailableNotification();
    347 
    348   request = oauth2_service_->StartRequest(scope_list, &consumer_);
    349   base::RunLoop().RunUntilIdle();
    350   fetcher = factory_.GetFetcherByID(0);
    351   fetcher->set_response_code(net::HTTP_OK);
    352   fetcher->SetResponseString(GetValidTokenResponse("another token", 3600));
    353   fetcher->delegate()->OnURLFetchComplete(fetcher);
    354   EXPECT_EQ(2, consumer_.number_of_successful_tokens_);
    355   EXPECT_EQ(0, consumer_.number_of_errors_);
    356   EXPECT_EQ("another token", consumer_.last_token_);
    357   EXPECT_EQ(1, oauth2_service_->cache_size_for_testing());
    358 }
    359 
    360 // Android doesn't use the current profile's TokenService login refresh token.
    361 #if !defined(OS_ANDROID)
    362 TEST_F(ProfileOAuth2TokenServiceTest, StaleRefreshTokensNotCached) {
    363   EXPECT_FALSE(service()->HasOAuthLoginToken());
    364   EXPECT_FALSE(oauth2_service_->ShouldCacheForRefreshToken(service(), "T1"));
    365 
    366   service()->IssueAuthTokenForTest(GaiaConstants::kGaiaOAuth2LoginRefreshToken,
    367                                   "T1");
    368   ExpectOneTokenAvailableNotification();
    369   EXPECT_TRUE(oauth2_service_->ShouldCacheForRefreshToken(service(), "T1"));
    370   EXPECT_FALSE(oauth2_service_->ShouldCacheForRefreshToken(service(), "T2"));
    371 
    372   service()->IssueAuthTokenForTest(GaiaConstants::kGaiaOAuth2LoginRefreshToken,
    373                                   "T2");
    374   ExpectOneTokenAvailableNotification();
    375   EXPECT_TRUE(oauth2_service_->ShouldCacheForRefreshToken(service(), "T2"));
    376   EXPECT_FALSE(oauth2_service_->ShouldCacheForRefreshToken(NULL, "T2"));
    377 }
    378 #endif
    379