Home | History | Annotate | Download | only in browser
      1 // Copyright 2014 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 "components/signin/core/browser/mutable_profile_oauth2_token_service.h"
      6 
      7 #include "base/run_loop.h"
      8 #include "components/signin/core/browser/profile_oauth2_token_service.h"
      9 #include "components/signin/core/browser/signin_error_controller.h"
     10 #include "components/signin/core/browser/test_signin_client.h"
     11 #include "components/signin/core/browser/webdata/token_web_data.h"
     12 #include "google_apis/gaia/gaia_constants.h"
     13 #include "google_apis/gaia/gaia_urls.h"
     14 #include "google_apis/gaia/oauth2_token_service_test_util.h"
     15 #include "net/http/http_status_code.h"
     16 #include "net/url_request/test_url_fetcher_factory.h"
     17 #include "testing/gtest/include/gtest/gtest.h"
     18 
     19 #if defined(OS_MACOSX)
     20 #include "components/os_crypt/os_crypt.h"
     21 #endif
     22 
     23 // Defining constant here to handle backward compatiblity tests, but this
     24 // constant is no longer used in current versions of chrome.
     25 static const char kLSOService[] = "lso";
     26 static const char kEmail[] = "user (at) gmail.com";
     27 
     28 class MutableProfileOAuth2TokenServiceTest
     29     : public testing::Test,
     30       public OAuth2TokenService::Observer {
     31  public:
     32   MutableProfileOAuth2TokenServiceTest()
     33       : factory_(NULL),
     34         token_available_count_(0),
     35         token_revoked_count_(0),
     36         tokens_loaded_count_(0),
     37         start_batch_changes_(0),
     38         end_batch_changes_(0) {}
     39 
     40   virtual void SetUp() OVERRIDE {
     41 #if defined(OS_MACOSX)
     42     OSCrypt::UseMockKeychain(true);
     43 #endif
     44 
     45     factory_.SetFakeResponse(GaiaUrls::GetInstance()->oauth2_revoke_url(),
     46                              "",
     47                              net::HTTP_OK,
     48                              net::URLRequestStatus::SUCCESS);
     49     oauth2_service_.Initialize(&client_);
     50     // Make sure PO2TS has a chance to load itself before continuing.
     51     base::RunLoop().RunUntilIdle();
     52     oauth2_service_.AddObserver(this);
     53   }
     54 
     55   virtual void TearDown() OVERRIDE {
     56     oauth2_service_.RemoveObserver(this);
     57     oauth2_service_.Shutdown();
     58   }
     59 
     60   void AddAuthTokenManually(const std::string& service,
     61                             const std::string& value) {
     62     scoped_refptr<TokenWebData> token_web_data = client_.GetDatabase();
     63     if (token_web_data.get())
     64       token_web_data->SetTokenForService(service, value);
     65   }
     66 
     67   // OAuth2TokenService::Observer implementation.
     68   virtual void OnRefreshTokenAvailable(const std::string& account_id) OVERRIDE {
     69     ++token_available_count_;
     70   }
     71   virtual void OnRefreshTokenRevoked(const std::string& account_id) OVERRIDE {
     72     ++token_revoked_count_;
     73   }
     74   virtual void OnRefreshTokensLoaded() OVERRIDE { ++tokens_loaded_count_; }
     75 
     76   virtual void OnStartBatchChanges() OVERRIDE {
     77     ++start_batch_changes_;
     78   }
     79 
     80   virtual void OnEndBatchChanges() OVERRIDE {
     81     ++end_batch_changes_;
     82   }
     83 
     84   void ResetObserverCounts() {
     85     token_available_count_ = 0;
     86     token_revoked_count_ = 0;
     87     tokens_loaded_count_ = 0;
     88     start_batch_changes_ = 0;
     89     end_batch_changes_ = 0;
     90   }
     91 
     92   void ExpectNoNotifications() {
     93     EXPECT_EQ(0, token_available_count_);
     94     EXPECT_EQ(0, token_revoked_count_);
     95     EXPECT_EQ(0, tokens_loaded_count_);
     96     ResetObserverCounts();
     97   }
     98 
     99   void ExpectOneTokenAvailableNotification() {
    100     EXPECT_EQ(1, token_available_count_);
    101     EXPECT_EQ(0, token_revoked_count_);
    102     EXPECT_EQ(0, tokens_loaded_count_);
    103     ResetObserverCounts();
    104   }
    105 
    106   void ExpectOneTokenRevokedNotification() {
    107     EXPECT_EQ(0, token_available_count_);
    108     EXPECT_EQ(1, token_revoked_count_);
    109     EXPECT_EQ(0, tokens_loaded_count_);
    110     ResetObserverCounts();
    111   }
    112 
    113   void ExpectOneTokensLoadedNotification() {
    114     EXPECT_EQ(0, token_available_count_);
    115     EXPECT_EQ(0, token_revoked_count_);
    116     EXPECT_EQ(1, tokens_loaded_count_);
    117     ResetObserverCounts();
    118   }
    119 
    120  protected:
    121   base::MessageLoop message_loop_;
    122   net::FakeURLFetcherFactory factory_;
    123   TestSigninClient client_;
    124   MutableProfileOAuth2TokenService oauth2_service_;
    125   TestingOAuth2TokenServiceConsumer consumer_;
    126   int token_available_count_;
    127   int token_revoked_count_;
    128   int tokens_loaded_count_;
    129   int start_batch_changes_;
    130   int end_batch_changes_;
    131 };
    132 
    133 TEST_F(MutableProfileOAuth2TokenServiceTest, PersistenceDBUpgrade) {
    134   std::string main_account_id(kEmail);
    135   std::string main_refresh_token("old_refresh_token");
    136 
    137   // Populate DB with legacy tokens.
    138   AddAuthTokenManually(GaiaConstants::kSyncService, "syncServiceToken");
    139   AddAuthTokenManually(kLSOService, "lsoToken");
    140   AddAuthTokenManually(GaiaConstants::kGaiaOAuth2LoginRefreshToken,
    141                        main_refresh_token);
    142 
    143   // Force LoadCredentials.
    144   oauth2_service_.LoadCredentials(main_account_id);
    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_EQ(1, start_batch_changes_);
    151   EXPECT_EQ(1, end_batch_changes_);
    152   EXPECT_TRUE(oauth2_service_.RefreshTokenIsAvailable(main_account_id));
    153   EXPECT_EQ(1U, oauth2_service_.refresh_tokens().size());
    154   EXPECT_EQ(main_refresh_token,
    155             oauth2_service_.refresh_tokens()[main_account_id]->refresh_token());
    156 
    157   // Add an old legacy token to the DB, to ensure it will not overwrite existing
    158   // credentials for main account.
    159   AddAuthTokenManually(GaiaConstants::kGaiaOAuth2LoginRefreshToken,
    160                        "secondOldRefreshToken");
    161   // Add some other legacy token. (Expected to get discarded).
    162   AddAuthTokenManually(kLSOService, "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(main_account_id);
    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_EQ(1, start_batch_changes_);
    179   EXPECT_EQ(1, end_batch_changes_);
    180   EXPECT_TRUE(oauth2_service_.RefreshTokenIsAvailable(main_account_id));
    181   // TODO(fgorski): cover both using RefreshTokenIsAvailable() and then get the
    182   // tokens using GetRefreshToken()
    183   EXPECT_EQ(2U, oauth2_service_.refresh_tokens().size());
    184   EXPECT_EQ(main_refresh_token,
    185             oauth2_service_.refresh_tokens()[main_account_id]->refresh_token());
    186   EXPECT_EQ(
    187       other_refresh_token,
    188       oauth2_service_.refresh_tokens()[other_account_id]->refresh_token());
    189 
    190   oauth2_service_.RevokeAllCredentials();
    191   EXPECT_EQ(2, start_batch_changes_);
    192   EXPECT_EQ(2, end_batch_changes_);
    193 }
    194 
    195 TEST_F(MutableProfileOAuth2TokenServiceTest, PersistenceRevokeCredentials) {
    196   std::string account_id_1 = "account_id_1";
    197   std::string refresh_token_1 = "refresh_token_1";
    198   std::string account_id_2 = "account_id_2";
    199   std::string refresh_token_2 = "refresh_token_2";
    200 
    201   // TODO(fgorski): Enable below when implemented:
    202   // EXPECT_FALSE(oauth2_servive_->RefreshTokenIsAvailable(account_id_1));
    203   // EXPECT_FALSE(oauth2_servive_->RefreshTokenIsAvailable(account_id_2));
    204 
    205   oauth2_service_.UpdateCredentials(account_id_1, refresh_token_1);
    206   oauth2_service_.UpdateCredentials(account_id_2, refresh_token_2);
    207   EXPECT_EQ(2, start_batch_changes_);
    208   EXPECT_EQ(2, end_batch_changes_);
    209 
    210   // TODO(fgorski): Enable below when implemented:
    211   // EXPECT_TRUE(oauth2_servive_->RefreshTokenIsAvailable(account_id_1));
    212   // EXPECT_TRUE(oauth2_service_.RefreshTokenIsAvailable(account_id_2));
    213 
    214   ResetObserverCounts();
    215   oauth2_service_.RevokeCredentials(account_id_1);
    216   EXPECT_EQ(1, start_batch_changes_);
    217   EXPECT_EQ(1, end_batch_changes_);
    218   ExpectOneTokenRevokedNotification();
    219 
    220   // TODO(fgorski): Enable below when implemented:
    221   // EXPECT_FALSE(oauth2_servive_->RefreshTokenIsAvailable(account_id_1));
    222   // EXPECT_TRUE(oauth2_service_.RefreshTokenIsAvailable(account_id_2));
    223 
    224   oauth2_service_.RevokeAllCredentials();
    225   EXPECT_EQ(0, token_available_count_);
    226   EXPECT_EQ(1, token_revoked_count_);
    227   EXPECT_EQ(0, tokens_loaded_count_);
    228   EXPECT_EQ(1, start_batch_changes_);
    229   EXPECT_EQ(1, end_batch_changes_);
    230   ResetObserverCounts();
    231 }
    232 
    233 TEST_F(MutableProfileOAuth2TokenServiceTest, PersistenceLoadCredentials) {
    234   // Ensure DB is clean.
    235   oauth2_service_.RevokeAllCredentials();
    236   ResetObserverCounts();
    237   // Perform a load from an empty DB.
    238   oauth2_service_.LoadCredentials("account_id");
    239   base::RunLoop().RunUntilIdle();
    240   EXPECT_EQ(1, start_batch_changes_);
    241   EXPECT_EQ(1, end_batch_changes_);
    242   ExpectOneTokensLoadedNotification();
    243   // LoadCredentials() guarantees that the account given to it as argument
    244   // is in the refresh_token map.
    245   EXPECT_EQ(1U, oauth2_service_.refresh_tokens().size());
    246   EXPECT_TRUE(
    247       oauth2_service_.refresh_tokens()["account_id"]->refresh_token().empty());
    248   // Setup a DB with tokens that don't require upgrade and clear memory.
    249   oauth2_service_.UpdateCredentials("account_id", "refresh_token");
    250   oauth2_service_.UpdateCredentials("account_id2", "refresh_token2");
    251   oauth2_service_.refresh_tokens().clear();
    252   EXPECT_EQ(2, start_batch_changes_);
    253   EXPECT_EQ(2, end_batch_changes_);
    254   ResetObserverCounts();
    255 
    256   oauth2_service_.LoadCredentials("account_id");
    257   base::RunLoop().RunUntilIdle();
    258   EXPECT_EQ(2, token_available_count_);
    259   EXPECT_EQ(0, token_revoked_count_);
    260   EXPECT_EQ(1, tokens_loaded_count_);
    261   EXPECT_EQ(1, start_batch_changes_);
    262   EXPECT_EQ(1, end_batch_changes_);
    263   ResetObserverCounts();
    264 
    265   // TODO(fgorski): Enable below when implemented:
    266   // EXPECT_TRUE(oauth2_servive_->RefreshTokenIsAvailable("account_id"));
    267   // EXPECT_TRUE(oauth2_service_.RefreshTokenIsAvailable("account_id2"));
    268 
    269   oauth2_service_.RevokeAllCredentials();
    270   EXPECT_EQ(0, token_available_count_);
    271   EXPECT_EQ(2, token_revoked_count_);
    272   EXPECT_EQ(0, tokens_loaded_count_);
    273   EXPECT_EQ(1, start_batch_changes_);
    274   EXPECT_EQ(1, end_batch_changes_);
    275   ResetObserverCounts();
    276 }
    277 
    278 TEST_F(MutableProfileOAuth2TokenServiceTest, PersistanceNotifications) {
    279   EXPECT_EQ(0, oauth2_service_.cache_size_for_testing());
    280   oauth2_service_.UpdateCredentials("account_id", "refresh_token");
    281   ExpectOneTokenAvailableNotification();
    282 
    283   oauth2_service_.UpdateCredentials("account_id", "refresh_token");
    284   ExpectNoNotifications();
    285 
    286   oauth2_service_.UpdateCredentials("account_id", "refresh_token2");
    287   ExpectOneTokenAvailableNotification();
    288 
    289   oauth2_service_.RevokeCredentials("account_id");
    290   ExpectOneTokenRevokedNotification();
    291 
    292   oauth2_service_.UpdateCredentials("account_id", "refresh_token2");
    293   ExpectOneTokenAvailableNotification();
    294 
    295   oauth2_service_.RevokeAllCredentials();
    296   ResetObserverCounts();
    297 }
    298 
    299 TEST_F(MutableProfileOAuth2TokenServiceTest, GetAccounts) {
    300   EXPECT_TRUE(oauth2_service_.GetAccounts().empty());
    301   oauth2_service_.UpdateCredentials("account_id1", "refresh_token1");
    302   oauth2_service_.UpdateCredentials("account_id2", "refresh_token2");
    303   std::vector<std::string> accounts = oauth2_service_.GetAccounts();
    304   EXPECT_EQ(2u, accounts.size());
    305   EXPECT_EQ(1, count(accounts.begin(), accounts.end(), "account_id1"));
    306   EXPECT_EQ(1, count(accounts.begin(), accounts.end(), "account_id2"));
    307   oauth2_service_.RevokeCredentials("account_id2");
    308   accounts = oauth2_service_.GetAccounts();
    309   EXPECT_EQ(1u, oauth2_service_.GetAccounts().size());
    310   EXPECT_EQ(1, count(accounts.begin(), accounts.end(), "account_id1"));
    311 }
    312 
    313 TEST_F(MutableProfileOAuth2TokenServiceTest, TokenServiceUpdateClearsCache) {
    314   EXPECT_EQ(0, oauth2_service_.cache_size_for_testing());
    315   std::set<std::string> scope_list;
    316   scope_list.insert("scope");
    317   oauth2_service_.UpdateCredentials(kEmail, "refreshToken");
    318   ExpectOneTokenAvailableNotification();
    319   factory_.SetFakeResponse(GaiaUrls::GetInstance()->oauth2_token_url(),
    320                            GetValidTokenResponse("token", 3600),
    321                            net::HTTP_OK,
    322                            net::URLRequestStatus::SUCCESS);
    323 
    324   scoped_ptr<OAuth2TokenService::Request> request(
    325       oauth2_service_.StartRequest(kEmail, scope_list, &consumer_));
    326   base::RunLoop().RunUntilIdle();
    327   EXPECT_EQ(1, consumer_.number_of_successful_tokens_);
    328   EXPECT_EQ(0, consumer_.number_of_errors_);
    329   EXPECT_EQ("token", consumer_.last_token_);
    330   EXPECT_EQ(1, oauth2_service_.cache_size_for_testing());
    331 
    332   // Signs out and signs in
    333   oauth2_service_.RevokeCredentials(kEmail);
    334   ExpectOneTokenRevokedNotification();
    335 
    336   EXPECT_EQ(0, oauth2_service_.cache_size_for_testing());
    337   oauth2_service_.UpdateCredentials(kEmail, "refreshToken");
    338   ExpectOneTokenAvailableNotification();
    339   factory_.SetFakeResponse(GaiaUrls::GetInstance()->oauth2_token_url(),
    340                            GetValidTokenResponse("another token", 3600),
    341                            net::HTTP_OK,
    342                            net::URLRequestStatus::SUCCESS);
    343 
    344   request = oauth2_service_.StartRequest(kEmail, scope_list, &consumer_);
    345   base::RunLoop().RunUntilIdle();
    346   EXPECT_EQ(2, consumer_.number_of_successful_tokens_);
    347   EXPECT_EQ(0, consumer_.number_of_errors_);
    348   EXPECT_EQ("another token", consumer_.last_token_);
    349   EXPECT_EQ(1, oauth2_service_.cache_size_for_testing());
    350 }
    351 
    352 TEST_F(MutableProfileOAuth2TokenServiceTest, FetchTransientError) {
    353   factory_.SetFakeResponse(GaiaUrls::GetInstance()->oauth2_token_url(),
    354                            "",
    355                            net::HTTP_FORBIDDEN,
    356                            net::URLRequestStatus::FAILED);
    357 
    358   EXPECT_EQ(0, oauth2_service_.cache_size_for_testing());
    359   std::set<std::string> scope_list;
    360   scope_list.insert("scope");
    361   oauth2_service_.set_max_authorization_token_fetch_retries_for_testing(0);
    362   oauth2_service_.UpdateCredentials(kEmail, "refreshToken");
    363   ExpectOneTokenAvailableNotification();
    364 
    365   scoped_ptr<OAuth2TokenService::Request> request(
    366       oauth2_service_.StartRequest(kEmail, scope_list, &consumer_));
    367   base::RunLoop().RunUntilIdle();
    368   EXPECT_EQ(GoogleServiceAuthError::AuthErrorNone(),
    369             oauth2_service_.signin_error_controller()->auth_error());
    370 }
    371