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. 25static const char kLSOService[] = "lso"; 26static const char kEmail[] = "user@gmail.com"; 27 28class 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 133TEST_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 195TEST_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 233TEST_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 278TEST_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 299TEST_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 313TEST_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 352TEST_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