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