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