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