1 // Copyright (c) 2012 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 <set> 6 #include <string> 7 #include <vector> 8 9 #include "base/command_line.h" 10 #include "base/prefs/pref_service.h" 11 #include "base/strings/string_util.h" 12 #include "base/strings/stringprintf.h" 13 #include "base/values.h" 14 #include "chrome/browser/chrome_notification_types.h" 15 #include "chrome/browser/extensions/api/identity/identity_api.h" 16 #include "chrome/browser/extensions/component_loader.h" 17 #include "chrome/browser/extensions/extension_apitest.h" 18 #include "chrome/browser/extensions/extension_browsertest.h" 19 #include "chrome/browser/extensions/extension_function_test_utils.h" 20 #include "chrome/browser/extensions/extension_service.h" 21 #include "chrome/browser/profiles/profile.h" 22 #include "chrome/browser/signin/account_reconcilor_factory.h" 23 #include "chrome/browser/signin/fake_account_reconcilor.h" 24 #include "chrome/browser/signin/fake_profile_oauth2_token_service.h" 25 #include "chrome/browser/signin/fake_profile_oauth2_token_service_builder.h" 26 #include "chrome/browser/signin/fake_signin_manager.h" 27 #include "chrome/browser/signin/profile_oauth2_token_service_factory.h" 28 #include "chrome/browser/signin/signin_manager_factory.h" 29 #include "chrome/browser/ui/browser.h" 30 #include "chrome/browser/ui/browser_window.h" 31 #include "chrome/common/chrome_switches.h" 32 #include "chrome/common/extensions/api/identity.h" 33 #include "chrome/common/extensions/api/identity/oauth2_manifest_handler.h" 34 #include "chrome/test/base/in_process_browser_test.h" 35 #include "chrome/test/base/test_switches.h" 36 #include "components/crx_file/id_util.h" 37 #include "components/signin/core/browser/signin_manager.h" 38 #include "components/signin/core/common/profile_management_switches.h" 39 #include "components/signin/core/common/signin_pref_names.h" 40 #include "content/public/browser/notification_service.h" 41 #include "content/public/browser/notification_source.h" 42 #include "content/public/test/test_utils.h" 43 #include "extensions/browser/guest_view/guest_view_base.h" 44 #include "extensions/common/test_util.h" 45 #include "google_apis/gaia/google_service_auth_error.h" 46 #include "google_apis/gaia/oauth2_mint_token_flow.h" 47 #include "net/test/spawned_test_server/spawned_test_server.h" 48 #include "testing/gmock/include/gmock/gmock.h" 49 #include "testing/gtest/include/gtest/gtest.h" 50 #include "url/gurl.h" 51 52 using testing::_; 53 using testing::Return; 54 using testing::ReturnRef; 55 56 namespace extensions { 57 58 namespace { 59 60 namespace errors = identity_constants; 61 namespace utils = extension_function_test_utils; 62 63 static const char kAccessToken[] = "auth_token"; 64 static const char kExtensionId[] = "ext_id"; 65 66 // This helps us be able to wait until an UIThreadExtensionFunction calls 67 // SendResponse. 68 class SendResponseDelegate 69 : public UIThreadExtensionFunction::DelegateForTests { 70 public: 71 SendResponseDelegate() : should_post_quit_(false) {} 72 73 virtual ~SendResponseDelegate() {} 74 75 void set_should_post_quit(bool should_quit) { 76 should_post_quit_ = should_quit; 77 } 78 79 bool HasResponse() { 80 return response_.get() != NULL; 81 } 82 83 bool GetResponse() { 84 EXPECT_TRUE(HasResponse()); 85 return *response_.get(); 86 } 87 88 virtual void OnSendResponse(UIThreadExtensionFunction* function, 89 bool success, 90 bool bad_message) OVERRIDE { 91 ASSERT_FALSE(bad_message); 92 ASSERT_FALSE(HasResponse()); 93 response_.reset(new bool); 94 *response_ = success; 95 if (should_post_quit_) { 96 base::MessageLoopForUI::current()->Quit(); 97 } 98 } 99 100 private: 101 scoped_ptr<bool> response_; 102 bool should_post_quit_; 103 }; 104 105 class AsyncExtensionBrowserTest : public ExtensionBrowserTest { 106 protected: 107 // Asynchronous function runner allows tests to manipulate the browser window 108 // after the call happens. 109 void RunFunctionAsync( 110 UIThreadExtensionFunction* function, 111 const std::string& args) { 112 response_delegate_.reset(new SendResponseDelegate); 113 function->set_test_delegate(response_delegate_.get()); 114 scoped_ptr<base::ListValue> parsed_args(utils::ParseList(args)); 115 EXPECT_TRUE(parsed_args.get()) << 116 "Could not parse extension function arguments: " << args; 117 function->SetArgs(parsed_args.get()); 118 119 if (!function->extension()) { 120 scoped_refptr<Extension> empty_extension( 121 test_util::CreateEmptyExtension()); 122 function->set_extension(empty_extension.get()); 123 } 124 125 function->set_browser_context(browser()->profile()); 126 function->set_has_callback(true); 127 function->Run()->Execute(); 128 } 129 130 std::string WaitForError(UIThreadExtensionFunction* function) { 131 RunMessageLoopUntilResponse(); 132 EXPECT_FALSE(function->GetResultList()) << "Did not expect a result"; 133 return function->GetError(); 134 } 135 136 base::Value* WaitForSingleResult(UIThreadExtensionFunction* function) { 137 RunMessageLoopUntilResponse(); 138 EXPECT_TRUE(function->GetError().empty()) << "Unexpected error: " 139 << function->GetError(); 140 const base::Value* single_result = NULL; 141 if (function->GetResultList() != NULL && 142 function->GetResultList()->Get(0, &single_result)) { 143 return single_result->DeepCopy(); 144 } 145 return NULL; 146 } 147 148 private: 149 void RunMessageLoopUntilResponse() { 150 // If the RunAsync of |function| didn't already call SendResponse, run the 151 // message loop until they do. 152 if (!response_delegate_->HasResponse()) { 153 response_delegate_->set_should_post_quit(true); 154 content::RunMessageLoop(); 155 } 156 EXPECT_TRUE(response_delegate_->HasResponse()); 157 } 158 159 scoped_ptr<SendResponseDelegate> response_delegate_; 160 }; 161 162 class TestHangOAuth2MintTokenFlow : public OAuth2MintTokenFlow { 163 public: 164 TestHangOAuth2MintTokenFlow() 165 : OAuth2MintTokenFlow(NULL, NULL, OAuth2MintTokenFlow::Parameters()) {} 166 167 virtual void Start() OVERRIDE { 168 // Do nothing, simulating a hanging network call. 169 } 170 }; 171 172 class TestOAuth2MintTokenFlow : public OAuth2MintTokenFlow { 173 public: 174 enum ResultType { 175 ISSUE_ADVICE_SUCCESS, 176 MINT_TOKEN_SUCCESS, 177 MINT_TOKEN_FAILURE, 178 MINT_TOKEN_BAD_CREDENTIALS, 179 MINT_TOKEN_SERVICE_ERROR 180 }; 181 182 TestOAuth2MintTokenFlow(ResultType result, 183 OAuth2MintTokenFlow::Delegate* delegate) 184 : OAuth2MintTokenFlow(NULL, delegate, OAuth2MintTokenFlow::Parameters()), 185 result_(result), 186 delegate_(delegate) { 187 } 188 189 virtual void Start() OVERRIDE { 190 switch (result_) { 191 case ISSUE_ADVICE_SUCCESS: { 192 IssueAdviceInfo info; 193 delegate_->OnIssueAdviceSuccess(info); 194 break; 195 } 196 case MINT_TOKEN_SUCCESS: { 197 delegate_->OnMintTokenSuccess(kAccessToken, 3600); 198 break; 199 } 200 case MINT_TOKEN_FAILURE: { 201 GoogleServiceAuthError error(GoogleServiceAuthError::CONNECTION_FAILED); 202 delegate_->OnMintTokenFailure(error); 203 break; 204 } 205 case MINT_TOKEN_BAD_CREDENTIALS: { 206 GoogleServiceAuthError error( 207 GoogleServiceAuthError::INVALID_GAIA_CREDENTIALS); 208 delegate_->OnMintTokenFailure(error); 209 break; 210 } 211 case MINT_TOKEN_SERVICE_ERROR: { 212 GoogleServiceAuthError error = 213 GoogleServiceAuthError::FromServiceError("invalid_scope"); 214 delegate_->OnMintTokenFailure(error); 215 break; 216 } 217 } 218 } 219 220 private: 221 ResultType result_; 222 OAuth2MintTokenFlow::Delegate* delegate_; 223 }; 224 225 // Waits for a specific GURL to generate a NOTIFICATION_LOAD_STOP event and 226 // saves a pointer to the window embedding the WebContents, which can be later 227 // closed. 228 class WaitForGURLAndCloseWindow : public content::WindowedNotificationObserver { 229 public: 230 explicit WaitForGURLAndCloseWindow(GURL url) 231 : WindowedNotificationObserver( 232 content::NOTIFICATION_LOAD_STOP, 233 content::NotificationService::AllSources()), 234 url_(url) {} 235 236 // NotificationObserver: 237 virtual void Observe(int type, 238 const content::NotificationSource& source, 239 const content::NotificationDetails& details) OVERRIDE { 240 content::NavigationController* web_auth_flow_controller = 241 content::Source<content::NavigationController>(source).ptr(); 242 content::WebContents* web_contents = 243 web_auth_flow_controller->GetWebContents(); 244 245 if (web_contents->GetURL() == url_) { 246 // It is safe to keep the pointer here, because we know in a test, that 247 // the WebContents won't go away before CloseEmbedderWebContents is 248 // called. Don't copy this code to production. 249 GuestViewBase* guest = GuestViewBase::FromWebContents(web_contents); 250 embedder_web_contents_ = guest->embedder_web_contents(); 251 // Condtionally invoke parent class so that Wait will not exit 252 // until the target URL arrives. 253 content::WindowedNotificationObserver::Observe(type, source, details); 254 } 255 } 256 257 // Closes the window embedding the WebContents. The action is separated from 258 // the Observe method to make sure the list of observers is not deleted, 259 // while some event is already being processed. (That causes ASAN failures.) 260 void CloseEmbedderWebContents() { 261 if (embedder_web_contents_) 262 embedder_web_contents_->Close(); 263 } 264 265 private: 266 GURL url_; 267 content::WebContents* embedder_web_contents_; 268 }; 269 270 } // namespace 271 272 class FakeGetAuthTokenFunction : public IdentityGetAuthTokenFunction { 273 public: 274 FakeGetAuthTokenFunction() 275 : login_access_token_result_(true), 276 auto_login_access_token_(true), 277 login_ui_result_(true), 278 scope_ui_result_(true), 279 login_ui_shown_(false), 280 scope_ui_shown_(false) {} 281 282 void set_login_access_token_result(bool result) { 283 login_access_token_result_ = result; 284 } 285 286 void set_auto_login_access_token(bool automatic) { 287 auto_login_access_token_ = automatic; 288 } 289 290 void set_login_ui_result(bool result) { login_ui_result_ = result; } 291 292 void set_mint_token_flow(scoped_ptr<OAuth2MintTokenFlow> flow) { 293 flow_ = flow.Pass(); 294 } 295 296 void set_mint_token_result(TestOAuth2MintTokenFlow::ResultType result_type) { 297 set_mint_token_flow(scoped_ptr<TestOAuth2MintTokenFlow>( 298 new TestOAuth2MintTokenFlow(result_type, this)) 299 .PassAs<OAuth2MintTokenFlow>()); 300 } 301 302 void set_scope_ui_failure(GaiaWebAuthFlow::Failure failure) { 303 scope_ui_result_ = false; 304 scope_ui_failure_ = failure; 305 } 306 307 void set_scope_ui_oauth_error(const std::string& oauth_error) { 308 scope_ui_result_ = false; 309 scope_ui_failure_ = GaiaWebAuthFlow::OAUTH_ERROR; 310 scope_ui_oauth_error_ = oauth_error; 311 } 312 313 bool login_ui_shown() const { return login_ui_shown_; } 314 315 bool scope_ui_shown() const { return scope_ui_shown_; } 316 317 std::string login_access_token() const { return login_access_token_; } 318 319 virtual void StartLoginAccessTokenRequest() OVERRIDE { 320 if (auto_login_access_token_) { 321 if (login_access_token_result_) { 322 OnGetTokenSuccess(login_token_request_.get(), 323 "access_token", 324 base::Time::Now() + base::TimeDelta::FromHours(1LL)); 325 } else { 326 GoogleServiceAuthError error( 327 GoogleServiceAuthError::INVALID_GAIA_CREDENTIALS); 328 OnGetTokenFailure(login_token_request_.get(), error); 329 } 330 } else { 331 // Make a request to the token service. The test now must tell 332 // the token service to issue an access token (or an error). 333 IdentityGetAuthTokenFunction::StartLoginAccessTokenRequest(); 334 } 335 } 336 337 virtual void ShowLoginPopup() OVERRIDE { 338 EXPECT_FALSE(login_ui_shown_); 339 login_ui_shown_ = true; 340 if (login_ui_result_) 341 SigninSuccess(); 342 else 343 SigninFailed(); 344 } 345 346 virtual void ShowOAuthApprovalDialog( 347 const IssueAdviceInfo& issue_advice) OVERRIDE { 348 scope_ui_shown_ = true; 349 350 if (scope_ui_result_) { 351 OnGaiaFlowCompleted(kAccessToken, "3600"); 352 } else if (scope_ui_failure_ == GaiaWebAuthFlow::SERVICE_AUTH_ERROR) { 353 GoogleServiceAuthError error(GoogleServiceAuthError::CONNECTION_FAILED); 354 OnGaiaFlowFailure(scope_ui_failure_, error, ""); 355 } else { 356 GoogleServiceAuthError error(GoogleServiceAuthError::NONE); 357 OnGaiaFlowFailure(scope_ui_failure_, error, scope_ui_oauth_error_); 358 } 359 } 360 361 virtual OAuth2MintTokenFlow* CreateMintTokenFlow( 362 const std::string& login_access_token) OVERRIDE { 363 EXPECT_TRUE(login_access_token_.empty()); 364 // Save the login token used to create the flow so tests can see 365 // what account was used. 366 login_access_token_ = login_access_token; 367 return flow_.release(); 368 } 369 370 private: 371 virtual ~FakeGetAuthTokenFunction() {} 372 bool login_access_token_result_; 373 bool auto_login_access_token_; 374 bool login_ui_result_; 375 bool scope_ui_result_; 376 GaiaWebAuthFlow::Failure scope_ui_failure_; 377 std::string scope_ui_oauth_error_; 378 bool login_ui_shown_; 379 bool scope_ui_shown_; 380 381 scoped_ptr<OAuth2MintTokenFlow> flow_; 382 383 std::string login_access_token_; 384 }; 385 386 class MockQueuedMintRequest : public IdentityMintRequestQueue::Request { 387 public: 388 MOCK_METHOD1(StartMintToken, void(IdentityMintRequestQueue::MintType)); 389 }; 390 391 gaia::AccountIds CreateIds(std::string email, std::string obfid) { 392 gaia::AccountIds ids; 393 ids.account_key = email; 394 ids.email = email; 395 ids.gaia = obfid; 396 return ids; 397 } 398 399 class IdentityGetAccountsFunctionTest : public ExtensionBrowserTest { 400 virtual void SetUpCommandLine(CommandLine* command_line) OVERRIDE { 401 ExtensionBrowserTest::SetUpCommandLine(command_line); 402 command_line->AppendSwitch(switches::kExtensionsMultiAccount); 403 } 404 405 protected: 406 void SetAccountState(gaia::AccountIds ids, bool is_signed_in) { 407 IdentityAPI::GetFactoryInstance()->Get(profile())->SetAccountStateForTest( 408 ids, is_signed_in); 409 } 410 411 testing::AssertionResult ExpectGetAccounts( 412 const std::vector<std::string>& accounts) { 413 scoped_refptr<IdentityGetAccountsFunction> func( 414 new IdentityGetAccountsFunction); 415 func->set_extension(test_util::CreateEmptyExtension(kExtensionId).get()); 416 if (!utils::RunFunction( 417 func.get(), std::string("[]"), browser(), utils::NONE)) { 418 return GenerateFailureResult(accounts, NULL) 419 << "getAccounts did not return a result."; 420 } 421 const base::ListValue* callback_arguments = func->GetResultList(); 422 if (!callback_arguments) 423 return GenerateFailureResult(accounts, NULL) << "NULL result"; 424 425 if (callback_arguments->GetSize() != 1) { 426 return GenerateFailureResult(accounts, NULL) 427 << "Expected 1 argument but got " << callback_arguments->GetSize(); 428 } 429 430 const base::ListValue* results; 431 if (!callback_arguments->GetList(0, &results)) 432 GenerateFailureResult(accounts, NULL) << "Result was not an array"; 433 434 std::set<std::string> result_ids; 435 for (base::ListValue::const_iterator it = results->begin(); 436 it != results->end(); 437 ++it) { 438 scoped_ptr<api::identity::AccountInfo> info = 439 api::identity::AccountInfo::FromValue(**it); 440 if (info.get()) 441 result_ids.insert(info->id); 442 else 443 return GenerateFailureResult(accounts, results); 444 } 445 446 for (std::vector<std::string>::const_iterator it = accounts.begin(); 447 it != accounts.end(); 448 ++it) { 449 if (result_ids.find(*it) == result_ids.end()) 450 return GenerateFailureResult(accounts, results); 451 } 452 453 return testing::AssertionResult(true); 454 } 455 456 testing::AssertionResult GenerateFailureResult( 457 const ::std::vector<std::string>& accounts, 458 const base::ListValue* results) { 459 testing::Message msg("Expected: "); 460 for (std::vector<std::string>::const_iterator it = accounts.begin(); 461 it != accounts.end(); 462 ++it) { 463 msg << *it << " "; 464 } 465 msg << "Actual: "; 466 if (!results) { 467 msg << "NULL"; 468 } else { 469 for (base::ListValue::const_iterator it = results->begin(); 470 it != results->end(); 471 ++it) { 472 scoped_ptr<api::identity::AccountInfo> info = 473 api::identity::AccountInfo::FromValue(**it); 474 if (info.get()) 475 msg << info->id << " "; 476 else 477 msg << *it << "<-" << (*it)->GetType() << " "; 478 } 479 } 480 481 return testing::AssertionFailure(msg); 482 } 483 }; 484 485 IN_PROC_BROWSER_TEST_F(IdentityGetAccountsFunctionTest, MultiAccountOn) { 486 EXPECT_TRUE(switches::IsExtensionsMultiAccount()); 487 } 488 489 IN_PROC_BROWSER_TEST_F(IdentityGetAccountsFunctionTest, NoneSignedIn) { 490 EXPECT_TRUE(ExpectGetAccounts(std::vector<std::string>())); 491 } 492 493 IN_PROC_BROWSER_TEST_F(IdentityGetAccountsFunctionTest, 494 PrimaryAccountSignedIn) { 495 SetAccountState(CreateIds("primary (at) example.com", "1"), true); 496 std::vector<std::string> primary; 497 primary.push_back("1"); 498 EXPECT_TRUE(ExpectGetAccounts(primary)); 499 } 500 501 IN_PROC_BROWSER_TEST_F(IdentityGetAccountsFunctionTest, TwoAccountsSignedIn) { 502 SetAccountState(CreateIds("primary (at) example.com", "1"), true); 503 SetAccountState(CreateIds("secondary (at) example.com", "2"), true); 504 std::vector<std::string> two_accounts; 505 two_accounts.push_back("1"); 506 two_accounts.push_back("2"); 507 EXPECT_TRUE(ExpectGetAccounts(two_accounts)); 508 } 509 510 class IdentityOldProfilesGetAccountsFunctionTest 511 : public IdentityGetAccountsFunctionTest { 512 virtual void SetUpCommandLine(CommandLine* command_line) OVERRIDE { 513 // Don't add the multi-account switch that parent class would have. 514 } 515 }; 516 517 IN_PROC_BROWSER_TEST_F(IdentityOldProfilesGetAccountsFunctionTest, 518 MultiAccountOff) { 519 EXPECT_FALSE(switches::IsExtensionsMultiAccount()); 520 } 521 522 IN_PROC_BROWSER_TEST_F(IdentityOldProfilesGetAccountsFunctionTest, 523 TwoAccountsSignedIn) { 524 SetAccountState(CreateIds("primary (at) example.com", "1"), true); 525 SetAccountState(CreateIds("secondary (at) example.com", "2"), true); 526 std::vector<std::string> only_primary; 527 only_primary.push_back("1"); 528 EXPECT_TRUE(ExpectGetAccounts(only_primary)); 529 } 530 531 class IdentityGetProfileUserInfoFunctionTest : public ExtensionBrowserTest { 532 protected: 533 scoped_ptr<api::identity::ProfileUserInfo> RunGetProfileUserInfo() { 534 scoped_refptr<IdentityGetProfileUserInfoFunction> func( 535 new IdentityGetProfileUserInfoFunction); 536 func->set_extension(test_util::CreateEmptyExtension(kExtensionId).get()); 537 scoped_ptr<base::Value> value( 538 utils::RunFunctionAndReturnSingleResult(func.get(), "[]", browser())); 539 return api::identity::ProfileUserInfo::FromValue(*value.get()); 540 } 541 542 scoped_ptr<api::identity::ProfileUserInfo> RunGetProfileUserInfoWithEmail() { 543 scoped_refptr<IdentityGetProfileUserInfoFunction> func( 544 new IdentityGetProfileUserInfoFunction); 545 func->set_extension(CreateExtensionWithEmailPermission()); 546 scoped_ptr<base::Value> value( 547 utils::RunFunctionAndReturnSingleResult(func.get(), "[]", browser())); 548 return api::identity::ProfileUserInfo::FromValue(*value.get()); 549 } 550 551 private: 552 scoped_refptr<Extension> CreateExtensionWithEmailPermission() { 553 scoped_ptr<base::DictionaryValue> test_extension_value( 554 utils::ParseDictionary( 555 "{\"name\": \"Test\", \"version\": \"1.0\", " 556 "\"permissions\": [\"identity.email\"]}")); 557 return utils::CreateExtension(test_extension_value.get()); 558 } 559 }; 560 561 IN_PROC_BROWSER_TEST_F(IdentityGetProfileUserInfoFunctionTest, NotSignedIn) { 562 scoped_ptr<api::identity::ProfileUserInfo> info = 563 RunGetProfileUserInfoWithEmail(); 564 EXPECT_TRUE(info->email.empty()); 565 EXPECT_TRUE(info->id.empty()); 566 } 567 568 IN_PROC_BROWSER_TEST_F(IdentityGetProfileUserInfoFunctionTest, SignedIn) { 569 profile()->GetPrefs() 570 ->SetString(prefs::kGoogleServicesUsername, "president (at) example.com"); 571 profile()->GetPrefs() 572 ->SetString(prefs::kGoogleServicesUserAccountId, "12345"); 573 574 scoped_ptr<api::identity::ProfileUserInfo> info = 575 RunGetProfileUserInfoWithEmail(); 576 EXPECT_EQ("president (at) example.com", info->email); 577 EXPECT_EQ("12345", info->id); 578 } 579 580 IN_PROC_BROWSER_TEST_F(IdentityGetProfileUserInfoFunctionTest, 581 NotSignedInNoEmail) { 582 scoped_ptr<api::identity::ProfileUserInfo> info = RunGetProfileUserInfo(); 583 EXPECT_TRUE(info->email.empty()); 584 EXPECT_TRUE(info->id.empty()); 585 } 586 587 IN_PROC_BROWSER_TEST_F(IdentityGetProfileUserInfoFunctionTest, 588 SignedInNoEmail) { 589 profile()->GetPrefs()->SetString(prefs::kGoogleServicesUsername, 590 "president (at) example.com"); 591 profile()->GetPrefs()->SetString(prefs::kGoogleServicesUserAccountId, 592 "12345"); 593 594 scoped_ptr<api::identity::ProfileUserInfo> info = RunGetProfileUserInfo(); 595 EXPECT_TRUE(info->email.empty()); 596 EXPECT_EQ("12345", info->id); 597 } 598 599 class GetAuthTokenFunctionTest : public AsyncExtensionBrowserTest { 600 public: 601 virtual void SetUpCommandLine(CommandLine* command_line) OVERRIDE { 602 AsyncExtensionBrowserTest::SetUpCommandLine(command_line); 603 command_line->AppendSwitch(switches::kExtensionsMultiAccount); 604 } 605 606 virtual void SetUpInProcessBrowserTestFixture() OVERRIDE { 607 AsyncExtensionBrowserTest::SetUpInProcessBrowserTestFixture(); 608 609 will_create_browser_context_services_subscription_ = 610 BrowserContextDependencyManager::GetInstance() 611 ->RegisterWillCreateBrowserContextServicesCallbackForTesting( 612 base::Bind(&GetAuthTokenFunctionTest:: 613 OnWillCreateBrowserContextServices, 614 base::Unretained(this))) 615 .Pass(); 616 } 617 618 void OnWillCreateBrowserContextServices(content::BrowserContext* context) { 619 // Replace the signin manager and token service with fakes. Do this ahead of 620 // creating the browser so that a bunch of classes don't register as 621 // observers and end up needing to unregister when the fake is substituted. 622 SigninManagerFactory::GetInstance()->SetTestingFactory( 623 context, &FakeSigninManagerBase::Build); 624 ProfileOAuth2TokenServiceFactory::GetInstance()->SetTestingFactory( 625 context, &BuildFakeProfileOAuth2TokenService); 626 AccountReconcilorFactory::GetInstance()->SetTestingFactory( 627 context, &FakeAccountReconcilor::Build); 628 } 629 630 virtual void SetUpOnMainThread() OVERRIDE { 631 AsyncExtensionBrowserTest::SetUpOnMainThread(); 632 633 // Grab references to the fake signin manager and token service. 634 signin_manager_ = static_cast<FakeSigninManagerForTesting*>( 635 SigninManagerFactory::GetInstance()->GetForProfile(profile())); 636 ASSERT_TRUE(signin_manager_); 637 token_service_ = static_cast<FakeProfileOAuth2TokenService*>( 638 ProfileOAuth2TokenServiceFactory::GetInstance()->GetForProfile( 639 profile())); 640 ASSERT_TRUE(token_service_); 641 } 642 643 void SignIn(const std::string account_key) { 644 #if defined(OS_CHROMEOS) 645 signin_manager_->SetAuthenticatedUsername(account_key); 646 #else 647 signin_manager_->SignIn(account_key, "password"); 648 #endif 649 token_service_->IssueRefreshTokenForUser(account_key, "refresh_token"); 650 } 651 652 void IssueLoginRefreshTokenForAccount(const std::string account_key) { 653 token_service_->IssueRefreshTokenForUser(account_key, "refresh_token"); 654 } 655 656 void IssueLoginAccessTokenForAccount(const std::string account_key) { 657 token_service_->IssueAllTokensForAccount( 658 account_key, 659 "access_token-" + account_key, 660 base::Time::Now() + base::TimeDelta::FromSeconds(3600)); 661 } 662 663 void SetAccountState(gaia::AccountIds ids, bool is_signed_in) { 664 IdentityAPI::GetFactoryInstance()->Get(profile())->SetAccountStateForTest( 665 ids, is_signed_in); 666 } 667 668 protected: 669 enum OAuth2Fields { 670 NONE = 0, 671 CLIENT_ID = 1, 672 SCOPES = 2, 673 AS_COMPONENT = 4 674 }; 675 676 FakeSigninManagerForTesting* signin_manager_; 677 FakeProfileOAuth2TokenService* token_service_; 678 679 virtual ~GetAuthTokenFunctionTest() {} 680 681 // Helper to create an extension with specific OAuth2Info fields set. 682 // |fields_to_set| should be computed by using fields of Oauth2Fields enum. 683 const Extension* CreateExtension(int fields_to_set) { 684 const Extension* ext; 685 base::FilePath manifest_path = 686 test_data_dir_.AppendASCII("platform_apps/oauth2"); 687 base::FilePath component_manifest_path = 688 test_data_dir_.AppendASCII("packaged_app/component_oauth2"); 689 if ((fields_to_set & AS_COMPONENT) == 0) 690 ext = LoadExtension(manifest_path); 691 else 692 ext = LoadExtensionAsComponent(component_manifest_path); 693 OAuth2Info& oauth2_info = 694 const_cast<OAuth2Info&>(OAuth2Info::GetOAuth2Info(ext)); 695 if ((fields_to_set & CLIENT_ID) != 0) 696 oauth2_info.client_id = "client1"; 697 if ((fields_to_set & SCOPES) != 0) { 698 oauth2_info.scopes.push_back("scope1"); 699 oauth2_info.scopes.push_back("scope2"); 700 } 701 702 extension_id_ = ext->id(); 703 oauth_scopes_ = std::set<std::string>(oauth2_info.scopes.begin(), 704 oauth2_info.scopes.end()); 705 return ext; 706 } 707 708 IdentityAPI* id_api() { 709 return IdentityAPI::GetFactoryInstance()->Get(browser()->profile()); 710 } 711 712 const std::string GetPrimaryAccountId() { 713 SigninManagerBase* signin_manager = 714 SigninManagerFactory::GetForProfile(browser()->profile()); 715 return signin_manager->GetAuthenticatedAccountId(); 716 } 717 718 void SetCachedToken(const IdentityTokenCacheValue& token_data) { 719 ExtensionTokenKey key(extension_id_, GetPrimaryAccountId(), oauth_scopes_); 720 id_api()->SetCachedToken(key, token_data); 721 } 722 723 const IdentityTokenCacheValue& GetCachedToken(std::string account_id) { 724 if (account_id.empty()) 725 account_id = GetPrimaryAccountId(); 726 ExtensionTokenKey key(extension_id_, account_id, oauth_scopes_); 727 return id_api()->GetCachedToken(key); 728 } 729 730 void QueueRequestStart(IdentityMintRequestQueue::MintType type, 731 IdentityMintRequestQueue::Request* request) { 732 ExtensionTokenKey key(extension_id_, GetPrimaryAccountId(), oauth_scopes_); 733 id_api()->mint_queue()->RequestStart(type, key, request); 734 } 735 736 void QueueRequestComplete(IdentityMintRequestQueue::MintType type, 737 IdentityMintRequestQueue::Request* request) { 738 ExtensionTokenKey key(extension_id_, GetPrimaryAccountId(), oauth_scopes_); 739 id_api()->mint_queue()->RequestComplete(type, key, request); 740 } 741 742 private: 743 std::string extension_id_; 744 std::set<std::string> oauth_scopes_; 745 746 scoped_ptr<base::CallbackList<void(content::BrowserContext*)>::Subscription> 747 will_create_browser_context_services_subscription_; 748 }; 749 750 IN_PROC_BROWSER_TEST_F(GetAuthTokenFunctionTest, 751 NoClientId) { 752 scoped_refptr<FakeGetAuthTokenFunction> func(new FakeGetAuthTokenFunction()); 753 func->set_extension(CreateExtension(SCOPES)); 754 std::string error = utils::RunFunctionAndReturnError( 755 func.get(), "[{}]", browser()); 756 EXPECT_EQ(std::string(errors::kInvalidClientId), error); 757 EXPECT_FALSE(func->login_ui_shown()); 758 EXPECT_FALSE(func->scope_ui_shown()); 759 } 760 761 IN_PROC_BROWSER_TEST_F(GetAuthTokenFunctionTest, 762 NoScopes) { 763 scoped_refptr<FakeGetAuthTokenFunction> func(new FakeGetAuthTokenFunction()); 764 func->set_extension(CreateExtension(CLIENT_ID)); 765 std::string error = utils::RunFunctionAndReturnError( 766 func.get(), "[{}]", browser()); 767 EXPECT_EQ(std::string(errors::kInvalidScopes), error); 768 EXPECT_FALSE(func->login_ui_shown()); 769 EXPECT_FALSE(func->scope_ui_shown()); 770 } 771 772 IN_PROC_BROWSER_TEST_F(GetAuthTokenFunctionTest, 773 NonInteractiveNotSignedIn) { 774 scoped_refptr<FakeGetAuthTokenFunction> func(new FakeGetAuthTokenFunction()); 775 func->set_extension(CreateExtension(CLIENT_ID | SCOPES)); 776 std::string error = utils::RunFunctionAndReturnError( 777 func.get(), "[{}]", browser()); 778 EXPECT_EQ(std::string(errors::kUserNotSignedIn), error); 779 EXPECT_FALSE(func->login_ui_shown()); 780 EXPECT_FALSE(func->scope_ui_shown()); 781 } 782 783 IN_PROC_BROWSER_TEST_F(GetAuthTokenFunctionTest, 784 NonInteractiveMintFailure) { 785 SignIn("primary (at) example.com"); 786 scoped_refptr<FakeGetAuthTokenFunction> func(new FakeGetAuthTokenFunction()); 787 func->set_extension(CreateExtension(CLIENT_ID | SCOPES)); 788 func->set_mint_token_result(TestOAuth2MintTokenFlow::MINT_TOKEN_FAILURE); 789 std::string error = 790 utils::RunFunctionAndReturnError(func.get(), "[{}]", browser()); 791 EXPECT_TRUE(StartsWithASCII(error, errors::kAuthFailure, false)); 792 EXPECT_FALSE(func->login_ui_shown()); 793 EXPECT_FALSE(func->scope_ui_shown()); 794 } 795 796 IN_PROC_BROWSER_TEST_F(GetAuthTokenFunctionTest, 797 NonInteractiveLoginAccessTokenFailure) { 798 SignIn("primary (at) example.com"); 799 scoped_refptr<FakeGetAuthTokenFunction> func(new FakeGetAuthTokenFunction()); 800 func->set_extension(CreateExtension(CLIENT_ID | SCOPES)); 801 func->set_login_access_token_result(false); 802 std::string error = utils::RunFunctionAndReturnError( 803 func.get(), "[{}]", browser()); 804 EXPECT_TRUE(StartsWithASCII(error, errors::kAuthFailure, false)); 805 } 806 807 IN_PROC_BROWSER_TEST_F(GetAuthTokenFunctionTest, 808 NonInteractiveMintAdviceSuccess) { 809 SignIn("primary (at) example.com"); 810 scoped_refptr<const Extension> extension(CreateExtension(CLIENT_ID | SCOPES)); 811 scoped_refptr<FakeGetAuthTokenFunction> func(new FakeGetAuthTokenFunction()); 812 func->set_extension(extension.get()); 813 func->set_mint_token_result(TestOAuth2MintTokenFlow::ISSUE_ADVICE_SUCCESS); 814 std::string error = 815 utils::RunFunctionAndReturnError(func.get(), "[{}]", browser()); 816 EXPECT_EQ(std::string(errors::kNoGrant), error); 817 EXPECT_FALSE(func->login_ui_shown()); 818 EXPECT_FALSE(func->scope_ui_shown()); 819 820 EXPECT_EQ(IdentityTokenCacheValue::CACHE_STATUS_ADVICE, 821 GetCachedToken(std::string()).status()); 822 } 823 824 IN_PROC_BROWSER_TEST_F(GetAuthTokenFunctionTest, 825 NonInteractiveMintBadCredentials) { 826 SignIn("primary (at) example.com"); 827 scoped_refptr<FakeGetAuthTokenFunction> func(new FakeGetAuthTokenFunction()); 828 func->set_extension(CreateExtension(CLIENT_ID | SCOPES)); 829 func->set_mint_token_result( 830 TestOAuth2MintTokenFlow::MINT_TOKEN_BAD_CREDENTIALS); 831 std::string error = 832 utils::RunFunctionAndReturnError(func.get(), "[{}]", browser()); 833 EXPECT_TRUE(StartsWithASCII(error, errors::kAuthFailure, false)); 834 EXPECT_FALSE(func->login_ui_shown()); 835 EXPECT_FALSE(func->scope_ui_shown()); 836 } 837 838 IN_PROC_BROWSER_TEST_F(GetAuthTokenFunctionTest, 839 NonInteractiveMintServiceError) { 840 SignIn("primary (at) example.com"); 841 scoped_refptr<FakeGetAuthTokenFunction> func(new FakeGetAuthTokenFunction()); 842 func->set_extension(CreateExtension(CLIENT_ID | SCOPES)); 843 func->set_mint_token_result( 844 TestOAuth2MintTokenFlow::MINT_TOKEN_SERVICE_ERROR); 845 std::string error = 846 utils::RunFunctionAndReturnError(func.get(), "[{}]", browser()); 847 EXPECT_TRUE(StartsWithASCII(error, errors::kAuthFailure, false)); 848 EXPECT_FALSE(func->login_ui_shown()); 849 EXPECT_FALSE(func->scope_ui_shown()); 850 } 851 852 IN_PROC_BROWSER_TEST_F(GetAuthTokenFunctionTest, 853 NoOptionsSuccess) { 854 SignIn("primary (at) example.com"); 855 #if defined(OS_WIN) && defined(USE_ASH) 856 // Disable this test in Metro+Ash for now (http://crbug.com/262796). 857 if (CommandLine::ForCurrentProcess()->HasSwitch(switches::kAshBrowserTests)) 858 return; 859 #endif 860 861 scoped_refptr<FakeGetAuthTokenFunction> func(new FakeGetAuthTokenFunction()); 862 scoped_refptr<const Extension> extension(CreateExtension(CLIENT_ID | SCOPES)); 863 func->set_extension(extension.get()); 864 func->set_mint_token_result(TestOAuth2MintTokenFlow::MINT_TOKEN_SUCCESS); 865 scoped_ptr<base::Value> value( 866 utils::RunFunctionAndReturnSingleResult(func.get(), "[]", browser())); 867 std::string access_token; 868 EXPECT_TRUE(value->GetAsString(&access_token)); 869 EXPECT_EQ(std::string(kAccessToken), access_token); 870 EXPECT_FALSE(func->login_ui_shown()); 871 EXPECT_FALSE(func->scope_ui_shown()); 872 EXPECT_EQ(IdentityTokenCacheValue::CACHE_STATUS_TOKEN, 873 GetCachedToken(std::string()).status()); 874 } 875 876 IN_PROC_BROWSER_TEST_F(GetAuthTokenFunctionTest, 877 NonInteractiveSuccess) { 878 SignIn("primary (at) example.com"); 879 #if defined(OS_WIN) && defined(USE_ASH) 880 // Disable this test in Metro+Ash for now (http://crbug.com/262796). 881 if (CommandLine::ForCurrentProcess()->HasSwitch(switches::kAshBrowserTests)) 882 return; 883 #endif 884 885 scoped_refptr<FakeGetAuthTokenFunction> func(new FakeGetAuthTokenFunction()); 886 scoped_refptr<const Extension> extension(CreateExtension(CLIENT_ID | SCOPES)); 887 func->set_extension(extension.get()); 888 func->set_mint_token_result(TestOAuth2MintTokenFlow::MINT_TOKEN_SUCCESS); 889 scoped_ptr<base::Value> value(utils::RunFunctionAndReturnSingleResult( 890 func.get(), "[{}]", browser())); 891 std::string access_token; 892 EXPECT_TRUE(value->GetAsString(&access_token)); 893 EXPECT_EQ(std::string(kAccessToken), access_token); 894 EXPECT_FALSE(func->login_ui_shown()); 895 EXPECT_FALSE(func->scope_ui_shown()); 896 EXPECT_EQ(IdentityTokenCacheValue::CACHE_STATUS_TOKEN, 897 GetCachedToken(std::string()).status()); 898 } 899 900 IN_PROC_BROWSER_TEST_F(GetAuthTokenFunctionTest, 901 InteractiveLoginCanceled) { 902 scoped_refptr<FakeGetAuthTokenFunction> func(new FakeGetAuthTokenFunction()); 903 func->set_extension(CreateExtension(CLIENT_ID | SCOPES)); 904 func->set_login_ui_result(false); 905 std::string error = utils::RunFunctionAndReturnError( 906 func.get(), "[{\"interactive\": true}]", browser()); 907 EXPECT_EQ(std::string(errors::kUserNotSignedIn), error); 908 EXPECT_TRUE(func->login_ui_shown()); 909 EXPECT_FALSE(func->scope_ui_shown()); 910 } 911 912 IN_PROC_BROWSER_TEST_F(GetAuthTokenFunctionTest, 913 InteractiveMintBadCredentialsLoginCanceled) { 914 SignIn("primary (at) example.com"); 915 scoped_refptr<FakeGetAuthTokenFunction> func(new FakeGetAuthTokenFunction()); 916 func->set_extension(CreateExtension(CLIENT_ID | SCOPES)); 917 func->set_mint_token_result( 918 TestOAuth2MintTokenFlow::MINT_TOKEN_BAD_CREDENTIALS); 919 func->set_login_ui_result(false); 920 std::string error = utils::RunFunctionAndReturnError( 921 func.get(), "[{\"interactive\": true}]", browser()); 922 EXPECT_EQ(std::string(errors::kUserNotSignedIn), error); 923 EXPECT_TRUE(func->login_ui_shown()); 924 EXPECT_FALSE(func->scope_ui_shown()); 925 } 926 927 IN_PROC_BROWSER_TEST_F(GetAuthTokenFunctionTest, 928 InteractiveLoginSuccessNoToken) { 929 scoped_refptr<FakeGetAuthTokenFunction> func(new FakeGetAuthTokenFunction()); 930 func->set_extension(CreateExtension(CLIENT_ID | SCOPES)); 931 func->set_login_ui_result(false); 932 std::string error = utils::RunFunctionAndReturnError( 933 func.get(), "[{\"interactive\": true}]", browser()); 934 EXPECT_EQ(std::string(errors::kUserNotSignedIn), error); 935 EXPECT_TRUE(func->login_ui_shown()); 936 EXPECT_FALSE(func->scope_ui_shown()); 937 } 938 939 IN_PROC_BROWSER_TEST_F(GetAuthTokenFunctionTest, 940 InteractiveLoginSuccessMintFailure) { 941 scoped_refptr<FakeGetAuthTokenFunction> func(new FakeGetAuthTokenFunction()); 942 func->set_extension(CreateExtension(CLIENT_ID | SCOPES)); 943 func->set_login_ui_result(true); 944 func->set_mint_token_result(TestOAuth2MintTokenFlow::MINT_TOKEN_FAILURE); 945 std::string error = utils::RunFunctionAndReturnError( 946 func.get(), "[{\"interactive\": true}]", browser()); 947 EXPECT_TRUE(StartsWithASCII(error, errors::kAuthFailure, false)); 948 EXPECT_TRUE(func->login_ui_shown()); 949 EXPECT_FALSE(func->scope_ui_shown()); 950 } 951 952 IN_PROC_BROWSER_TEST_F(GetAuthTokenFunctionTest, 953 InteractiveLoginSuccessLoginAccessTokenFailure) { 954 scoped_refptr<FakeGetAuthTokenFunction> func(new FakeGetAuthTokenFunction()); 955 func->set_extension(CreateExtension(CLIENT_ID | SCOPES)); 956 func->set_login_ui_result(true); 957 func->set_login_access_token_result(false); 958 std::string error = utils::RunFunctionAndReturnError( 959 func.get(), "[{\"interactive\": true}]", browser()); 960 EXPECT_TRUE(StartsWithASCII(error, errors::kAuthFailure, false)); 961 EXPECT_TRUE(func->login_ui_shown()); 962 EXPECT_FALSE(func->scope_ui_shown()); 963 } 964 965 IN_PROC_BROWSER_TEST_F(GetAuthTokenFunctionTest, 966 InteractiveLoginSuccessMintSuccess) { 967 // TODO(courage): verify that account_id in token service requests 968 // is correct once manual token minting for tests is implemented. 969 scoped_refptr<FakeGetAuthTokenFunction> func(new FakeGetAuthTokenFunction()); 970 func->set_extension(CreateExtension(CLIENT_ID | SCOPES)); 971 func->set_login_ui_result(true); 972 func->set_mint_token_result(TestOAuth2MintTokenFlow::MINT_TOKEN_SUCCESS); 973 scoped_ptr<base::Value> value(utils::RunFunctionAndReturnSingleResult( 974 func.get(), "[{\"interactive\": true}]", browser())); 975 std::string access_token; 976 EXPECT_TRUE(value->GetAsString(&access_token)); 977 EXPECT_EQ(std::string(kAccessToken), access_token); 978 EXPECT_TRUE(func->login_ui_shown()); 979 EXPECT_FALSE(func->scope_ui_shown()); 980 } 981 982 IN_PROC_BROWSER_TEST_F(GetAuthTokenFunctionTest, 983 InteractiveLoginSuccessApprovalAborted) { 984 scoped_refptr<FakeGetAuthTokenFunction> func(new FakeGetAuthTokenFunction()); 985 func->set_extension(CreateExtension(CLIENT_ID | SCOPES)); 986 func->set_login_ui_result(true); 987 func->set_mint_token_result(TestOAuth2MintTokenFlow::ISSUE_ADVICE_SUCCESS); 988 func->set_scope_ui_failure(GaiaWebAuthFlow::WINDOW_CLOSED); 989 std::string error = utils::RunFunctionAndReturnError( 990 func.get(), "[{\"interactive\": true}]", browser()); 991 EXPECT_EQ(std::string(errors::kUserRejected), error); 992 EXPECT_TRUE(func->login_ui_shown()); 993 EXPECT_TRUE(func->scope_ui_shown()); 994 } 995 996 IN_PROC_BROWSER_TEST_F(GetAuthTokenFunctionTest, 997 InteractiveLoginSuccessApprovalSuccess) { 998 scoped_refptr<const Extension> extension(CreateExtension(CLIENT_ID | SCOPES)); 999 scoped_refptr<FakeGetAuthTokenFunction> func(new FakeGetAuthTokenFunction()); 1000 func->set_extension(extension.get()); 1001 func->set_login_ui_result(true); 1002 func->set_mint_token_result(TestOAuth2MintTokenFlow::ISSUE_ADVICE_SUCCESS); 1003 1004 scoped_ptr<base::Value> value(utils::RunFunctionAndReturnSingleResult( 1005 func.get(), "[{\"interactive\": true}]", browser())); 1006 std::string access_token; 1007 EXPECT_TRUE(value->GetAsString(&access_token)); 1008 EXPECT_EQ(std::string(kAccessToken), access_token); 1009 EXPECT_TRUE(func->login_ui_shown()); 1010 EXPECT_TRUE(func->scope_ui_shown()); 1011 } 1012 1013 IN_PROC_BROWSER_TEST_F(GetAuthTokenFunctionTest, 1014 InteractiveApprovalAborted) { 1015 SignIn("primary (at) example.com"); 1016 scoped_refptr<FakeGetAuthTokenFunction> func(new FakeGetAuthTokenFunction()); 1017 func->set_extension(CreateExtension(CLIENT_ID | SCOPES)); 1018 func->set_mint_token_result(TestOAuth2MintTokenFlow::ISSUE_ADVICE_SUCCESS); 1019 func->set_scope_ui_failure(GaiaWebAuthFlow::WINDOW_CLOSED); 1020 std::string error = utils::RunFunctionAndReturnError( 1021 func.get(), "[{\"interactive\": true}]", browser()); 1022 EXPECT_EQ(std::string(errors::kUserRejected), error); 1023 EXPECT_FALSE(func->login_ui_shown()); 1024 EXPECT_TRUE(func->scope_ui_shown()); 1025 } 1026 1027 IN_PROC_BROWSER_TEST_F(GetAuthTokenFunctionTest, 1028 InteractiveApprovalLoadFailed) { 1029 SignIn("primary (at) example.com"); 1030 scoped_refptr<FakeGetAuthTokenFunction> func(new FakeGetAuthTokenFunction()); 1031 func->set_extension(CreateExtension(CLIENT_ID | SCOPES)); 1032 func->set_mint_token_result(TestOAuth2MintTokenFlow::ISSUE_ADVICE_SUCCESS); 1033 func->set_scope_ui_failure(GaiaWebAuthFlow::LOAD_FAILED); 1034 std::string error = utils::RunFunctionAndReturnError( 1035 func.get(), "[{\"interactive\": true}]", browser()); 1036 EXPECT_EQ(std::string(errors::kPageLoadFailure), error); 1037 EXPECT_FALSE(func->login_ui_shown()); 1038 EXPECT_TRUE(func->scope_ui_shown()); 1039 } 1040 1041 IN_PROC_BROWSER_TEST_F(GetAuthTokenFunctionTest, 1042 InteractiveApprovalInvalidRedirect) { 1043 SignIn("primary (at) example.com"); 1044 scoped_refptr<FakeGetAuthTokenFunction> func(new FakeGetAuthTokenFunction()); 1045 func->set_extension(CreateExtension(CLIENT_ID | SCOPES)); 1046 func->set_mint_token_result(TestOAuth2MintTokenFlow::ISSUE_ADVICE_SUCCESS); 1047 func->set_scope_ui_failure(GaiaWebAuthFlow::INVALID_REDIRECT); 1048 std::string error = utils::RunFunctionAndReturnError( 1049 func.get(), "[{\"interactive\": true}]", browser()); 1050 EXPECT_EQ(std::string(errors::kInvalidRedirect), error); 1051 EXPECT_FALSE(func->login_ui_shown()); 1052 EXPECT_TRUE(func->scope_ui_shown()); 1053 } 1054 1055 IN_PROC_BROWSER_TEST_F(GetAuthTokenFunctionTest, 1056 InteractiveApprovalConnectionFailure) { 1057 SignIn("primary (at) example.com"); 1058 scoped_refptr<FakeGetAuthTokenFunction> func(new FakeGetAuthTokenFunction()); 1059 func->set_extension(CreateExtension(CLIENT_ID | SCOPES)); 1060 func->set_mint_token_result(TestOAuth2MintTokenFlow::ISSUE_ADVICE_SUCCESS); 1061 func->set_scope_ui_failure(GaiaWebAuthFlow::SERVICE_AUTH_ERROR); 1062 std::string error = utils::RunFunctionAndReturnError( 1063 func.get(), "[{\"interactive\": true}]", browser()); 1064 EXPECT_TRUE(StartsWithASCII(error, errors::kAuthFailure, false)); 1065 EXPECT_FALSE(func->login_ui_shown()); 1066 EXPECT_TRUE(func->scope_ui_shown()); 1067 } 1068 1069 IN_PROC_BROWSER_TEST_F(GetAuthTokenFunctionTest, 1070 InteractiveApprovalOAuthErrors) { 1071 SignIn("primary (at) example.com"); 1072 scoped_refptr<const Extension> extension(CreateExtension(CLIENT_ID | SCOPES)); 1073 1074 std::map<std::string, std::string> error_map; 1075 error_map.insert(std::make_pair("access_denied", errors::kUserRejected)); 1076 error_map.insert(std::make_pair("invalid_scope", errors::kInvalidScopes)); 1077 error_map.insert(std::make_pair( 1078 "unmapped_error", std::string(errors::kAuthFailure) + "unmapped_error")); 1079 1080 for (std::map<std::string, std::string>::const_iterator 1081 it = error_map.begin(); 1082 it != error_map.end(); 1083 ++it) { 1084 scoped_refptr<FakeGetAuthTokenFunction> func( 1085 new FakeGetAuthTokenFunction()); 1086 func->set_extension(extension.get()); 1087 // Make sure we don't get a cached issue_advice result, which would cause 1088 // flow to be leaked. 1089 id_api()->EraseAllCachedTokens(); 1090 func->set_mint_token_result(TestOAuth2MintTokenFlow::ISSUE_ADVICE_SUCCESS); 1091 func->set_scope_ui_oauth_error(it->first); 1092 std::string error = utils::RunFunctionAndReturnError( 1093 func.get(), "[{\"interactive\": true}]", browser()); 1094 EXPECT_EQ(it->second, error); 1095 EXPECT_FALSE(func->login_ui_shown()); 1096 EXPECT_TRUE(func->scope_ui_shown()); 1097 } 1098 } 1099 1100 IN_PROC_BROWSER_TEST_F(GetAuthTokenFunctionTest, 1101 InteractiveApprovalSuccess) { 1102 SignIn("primary (at) example.com"); 1103 scoped_refptr<const Extension> extension(CreateExtension(CLIENT_ID | SCOPES)); 1104 scoped_refptr<FakeGetAuthTokenFunction> func(new FakeGetAuthTokenFunction()); 1105 func->set_extension(extension.get()); 1106 func->set_mint_token_result(TestOAuth2MintTokenFlow::ISSUE_ADVICE_SUCCESS); 1107 1108 scoped_ptr<base::Value> value(utils::RunFunctionAndReturnSingleResult( 1109 func.get(), "[{\"interactive\": true}]", browser())); 1110 std::string access_token; 1111 EXPECT_TRUE(value->GetAsString(&access_token)); 1112 EXPECT_EQ(std::string(kAccessToken), access_token); 1113 EXPECT_FALSE(func->login_ui_shown()); 1114 EXPECT_TRUE(func->scope_ui_shown()); 1115 1116 EXPECT_EQ(IdentityTokenCacheValue::CACHE_STATUS_TOKEN, 1117 GetCachedToken(std::string()).status()); 1118 } 1119 1120 IN_PROC_BROWSER_TEST_F(GetAuthTokenFunctionTest, NoninteractiveQueue) { 1121 SignIn("primary (at) example.com"); 1122 scoped_refptr<const Extension> extension(CreateExtension(CLIENT_ID | SCOPES)); 1123 scoped_refptr<FakeGetAuthTokenFunction> func(new FakeGetAuthTokenFunction()); 1124 func->set_extension(extension.get()); 1125 1126 // Create a fake request to block the queue. 1127 MockQueuedMintRequest queued_request; 1128 IdentityMintRequestQueue::MintType type = 1129 IdentityMintRequestQueue::MINT_TYPE_NONINTERACTIVE; 1130 1131 EXPECT_CALL(queued_request, StartMintToken(type)).Times(1); 1132 QueueRequestStart(type, &queued_request); 1133 1134 // The real request will start processing, but wait in the queue behind 1135 // the blocker. 1136 RunFunctionAsync(func.get(), "[{}]"); 1137 // Verify that we have fetched the login token at this point. 1138 testing::Mock::VerifyAndClearExpectations(func.get()); 1139 1140 // The flow will be created after the first queued request clears. 1141 func->set_mint_token_result(TestOAuth2MintTokenFlow::MINT_TOKEN_SUCCESS); 1142 1143 QueueRequestComplete(type, &queued_request); 1144 1145 scoped_ptr<base::Value> value(WaitForSingleResult(func.get())); 1146 std::string access_token; 1147 EXPECT_TRUE(value->GetAsString(&access_token)); 1148 EXPECT_EQ(std::string(kAccessToken), access_token); 1149 EXPECT_FALSE(func->login_ui_shown()); 1150 EXPECT_FALSE(func->scope_ui_shown()); 1151 } 1152 1153 IN_PROC_BROWSER_TEST_F(GetAuthTokenFunctionTest, InteractiveQueue) { 1154 SignIn("primary (at) example.com"); 1155 scoped_refptr<const Extension> extension(CreateExtension(CLIENT_ID | SCOPES)); 1156 scoped_refptr<FakeGetAuthTokenFunction> func(new FakeGetAuthTokenFunction()); 1157 func->set_extension(extension.get()); 1158 1159 // Create a fake request to block the queue. 1160 MockQueuedMintRequest queued_request; 1161 IdentityMintRequestQueue::MintType type = 1162 IdentityMintRequestQueue::MINT_TYPE_INTERACTIVE; 1163 1164 EXPECT_CALL(queued_request, StartMintToken(type)).Times(1); 1165 QueueRequestStart(type, &queued_request); 1166 1167 // The real request will start processing, but wait in the queue behind 1168 // the blocker. 1169 func->set_mint_token_result(TestOAuth2MintTokenFlow::ISSUE_ADVICE_SUCCESS); 1170 RunFunctionAsync(func.get(), "[{\"interactive\": true}]"); 1171 // Verify that we have fetched the login token and run the first flow. 1172 testing::Mock::VerifyAndClearExpectations(func.get()); 1173 EXPECT_FALSE(func->scope_ui_shown()); 1174 1175 // The UI will be displayed and a token retrieved after the first 1176 // queued request clears. 1177 QueueRequestComplete(type, &queued_request); 1178 1179 scoped_ptr<base::Value> value(WaitForSingleResult(func.get())); 1180 std::string access_token; 1181 EXPECT_TRUE(value->GetAsString(&access_token)); 1182 EXPECT_EQ(std::string(kAccessToken), access_token); 1183 EXPECT_FALSE(func->login_ui_shown()); 1184 EXPECT_TRUE(func->scope_ui_shown()); 1185 } 1186 1187 IN_PROC_BROWSER_TEST_F(GetAuthTokenFunctionTest, InteractiveQueueShutdown) { 1188 SignIn("primary (at) example.com"); 1189 scoped_refptr<const Extension> extension(CreateExtension(CLIENT_ID | SCOPES)); 1190 scoped_refptr<FakeGetAuthTokenFunction> func(new FakeGetAuthTokenFunction()); 1191 func->set_extension(extension.get()); 1192 1193 // Create a fake request to block the queue. 1194 MockQueuedMintRequest queued_request; 1195 IdentityMintRequestQueue::MintType type = 1196 IdentityMintRequestQueue::MINT_TYPE_INTERACTIVE; 1197 1198 EXPECT_CALL(queued_request, StartMintToken(type)).Times(1); 1199 QueueRequestStart(type, &queued_request); 1200 1201 // The real request will start processing, but wait in the queue behind 1202 // the blocker. 1203 func->set_mint_token_result(TestOAuth2MintTokenFlow::ISSUE_ADVICE_SUCCESS); 1204 RunFunctionAsync(func.get(), "[{\"interactive\": true}]"); 1205 // Verify that we have fetched the login token and run the first flow. 1206 testing::Mock::VerifyAndClearExpectations(func.get()); 1207 EXPECT_FALSE(func->scope_ui_shown()); 1208 1209 // After the request is canceled, the function will complete. 1210 func->OnShutdown(); 1211 EXPECT_EQ(std::string(errors::kCanceled), WaitForError(func.get())); 1212 EXPECT_FALSE(func->login_ui_shown()); 1213 EXPECT_FALSE(func->scope_ui_shown()); 1214 1215 QueueRequestComplete(type, &queued_request); 1216 } 1217 1218 IN_PROC_BROWSER_TEST_F(GetAuthTokenFunctionTest, NoninteractiveShutdown) { 1219 SignIn("primary (at) example.com"); 1220 scoped_refptr<const Extension> extension(CreateExtension(CLIENT_ID | SCOPES)); 1221 scoped_refptr<FakeGetAuthTokenFunction> func(new FakeGetAuthTokenFunction()); 1222 func->set_extension(extension.get()); 1223 1224 scoped_ptr<TestHangOAuth2MintTokenFlow> flow( 1225 new TestHangOAuth2MintTokenFlow()); 1226 func->set_mint_token_flow(flow.PassAs<OAuth2MintTokenFlow>()); 1227 RunFunctionAsync(func.get(), "[{\"interactive\": false}]"); 1228 1229 // After the request is canceled, the function will complete. 1230 func->OnShutdown(); 1231 EXPECT_EQ(std::string(errors::kCanceled), WaitForError(func.get())); 1232 } 1233 1234 IN_PROC_BROWSER_TEST_F(GetAuthTokenFunctionTest, 1235 InteractiveQueuedNoninteractiveFails) { 1236 SignIn("primary (at) example.com"); 1237 scoped_refptr<const Extension> extension(CreateExtension(CLIENT_ID | SCOPES)); 1238 scoped_refptr<FakeGetAuthTokenFunction> func(new FakeGetAuthTokenFunction()); 1239 func->set_extension(extension.get()); 1240 1241 // Create a fake request to block the interactive queue. 1242 MockQueuedMintRequest queued_request; 1243 IdentityMintRequestQueue::MintType type = 1244 IdentityMintRequestQueue::MINT_TYPE_INTERACTIVE; 1245 1246 EXPECT_CALL(queued_request, StartMintToken(type)).Times(1); 1247 QueueRequestStart(type, &queued_request); 1248 1249 // Non-interactive requests fail without hitting GAIA, because a 1250 // consent UI is known to be up. 1251 std::string error = utils::RunFunctionAndReturnError( 1252 func.get(), "[{}]", browser()); 1253 EXPECT_EQ(std::string(errors::kNoGrant), error); 1254 EXPECT_FALSE(func->login_ui_shown()); 1255 EXPECT_FALSE(func->scope_ui_shown()); 1256 1257 QueueRequestComplete(type, &queued_request); 1258 } 1259 1260 IN_PROC_BROWSER_TEST_F(GetAuthTokenFunctionTest, 1261 NonInteractiveCacheHit) { 1262 SignIn("primary (at) example.com"); 1263 scoped_refptr<const Extension> extension(CreateExtension(CLIENT_ID | SCOPES)); 1264 scoped_refptr<FakeGetAuthTokenFunction> func(new FakeGetAuthTokenFunction()); 1265 func->set_extension(extension.get()); 1266 1267 // pre-populate the cache with a token 1268 IdentityTokenCacheValue token(kAccessToken, 1269 base::TimeDelta::FromSeconds(3600)); 1270 SetCachedToken(token); 1271 1272 // Get a token. Should not require a GAIA request. 1273 scoped_ptr<base::Value> value(utils::RunFunctionAndReturnSingleResult( 1274 func.get(), "[{}]", browser())); 1275 std::string access_token; 1276 EXPECT_TRUE(value->GetAsString(&access_token)); 1277 EXPECT_EQ(std::string(kAccessToken), access_token); 1278 EXPECT_FALSE(func->login_ui_shown()); 1279 EXPECT_FALSE(func->scope_ui_shown()); 1280 } 1281 1282 IN_PROC_BROWSER_TEST_F(GetAuthTokenFunctionTest, 1283 NonInteractiveIssueAdviceCacheHit) { 1284 SignIn("primary (at) example.com"); 1285 scoped_refptr<const Extension> extension(CreateExtension(CLIENT_ID | SCOPES)); 1286 scoped_refptr<FakeGetAuthTokenFunction> func(new FakeGetAuthTokenFunction()); 1287 func->set_extension(extension.get()); 1288 1289 // pre-populate the cache with advice 1290 IssueAdviceInfo info; 1291 IdentityTokenCacheValue token(info); 1292 SetCachedToken(token); 1293 1294 // Should return an error without a GAIA request. 1295 std::string error = utils::RunFunctionAndReturnError( 1296 func.get(), "[{}]", browser()); 1297 EXPECT_EQ(std::string(errors::kNoGrant), error); 1298 EXPECT_FALSE(func->login_ui_shown()); 1299 EXPECT_FALSE(func->scope_ui_shown()); 1300 } 1301 1302 IN_PROC_BROWSER_TEST_F(GetAuthTokenFunctionTest, 1303 InteractiveCacheHit) { 1304 SignIn("primary (at) example.com"); 1305 scoped_refptr<const Extension> extension(CreateExtension(CLIENT_ID | SCOPES)); 1306 scoped_refptr<FakeGetAuthTokenFunction> func(new FakeGetAuthTokenFunction()); 1307 func->set_extension(extension.get()); 1308 1309 // Create a fake request to block the queue. 1310 MockQueuedMintRequest queued_request; 1311 IdentityMintRequestQueue::MintType type = 1312 IdentityMintRequestQueue::MINT_TYPE_INTERACTIVE; 1313 1314 EXPECT_CALL(queued_request, StartMintToken(type)).Times(1); 1315 QueueRequestStart(type, &queued_request); 1316 1317 // The real request will start processing, but wait in the queue behind 1318 // the blocker. 1319 func->set_mint_token_result(TestOAuth2MintTokenFlow::ISSUE_ADVICE_SUCCESS); 1320 RunFunctionAsync(func.get(), "[{\"interactive\": true}]"); 1321 1322 // Populate the cache with a token while the request is blocked. 1323 IdentityTokenCacheValue token(kAccessToken, 1324 base::TimeDelta::FromSeconds(3600)); 1325 SetCachedToken(token); 1326 1327 // When we wake up the request, it returns the cached token without 1328 // displaying a UI, or hitting GAIA. 1329 1330 QueueRequestComplete(type, &queued_request); 1331 1332 scoped_ptr<base::Value> value(WaitForSingleResult(func.get())); 1333 std::string access_token; 1334 EXPECT_TRUE(value->GetAsString(&access_token)); 1335 EXPECT_EQ(std::string(kAccessToken), access_token); 1336 EXPECT_FALSE(func->login_ui_shown()); 1337 EXPECT_FALSE(func->scope_ui_shown()); 1338 } 1339 1340 IN_PROC_BROWSER_TEST_F(GetAuthTokenFunctionTest, 1341 LoginInvalidatesTokenCache) { 1342 scoped_refptr<FakeGetAuthTokenFunction> func(new FakeGetAuthTokenFunction()); 1343 scoped_refptr<const Extension> extension(CreateExtension(CLIENT_ID | SCOPES)); 1344 func->set_extension(extension.get()); 1345 1346 // pre-populate the cache with a token 1347 IdentityTokenCacheValue token(kAccessToken, 1348 base::TimeDelta::FromSeconds(3600)); 1349 SetCachedToken(token); 1350 1351 // Because the user is not signed in, the token will be removed, 1352 // and we'll hit GAIA for new tokens. 1353 func->set_login_ui_result(true); 1354 func->set_mint_token_result(TestOAuth2MintTokenFlow::ISSUE_ADVICE_SUCCESS); 1355 1356 scoped_ptr<base::Value> value(utils::RunFunctionAndReturnSingleResult( 1357 func.get(), "[{\"interactive\": true}]", browser())); 1358 std::string access_token; 1359 EXPECT_TRUE(value->GetAsString(&access_token)); 1360 EXPECT_EQ(std::string(kAccessToken), access_token); 1361 EXPECT_TRUE(func->login_ui_shown()); 1362 EXPECT_TRUE(func->scope_ui_shown()); 1363 EXPECT_EQ(IdentityTokenCacheValue::CACHE_STATUS_TOKEN, 1364 GetCachedToken(std::string()).status()); 1365 } 1366 1367 IN_PROC_BROWSER_TEST_F(GetAuthTokenFunctionTest, ComponentWithChromeClientId) { 1368 scoped_refptr<FakeGetAuthTokenFunction> func(new FakeGetAuthTokenFunction()); 1369 scoped_refptr<const Extension> extension( 1370 CreateExtension(SCOPES | AS_COMPONENT)); 1371 func->set_extension(extension.get()); 1372 const OAuth2Info& oauth2_info = OAuth2Info::GetOAuth2Info(extension.get()); 1373 EXPECT_TRUE(oauth2_info.client_id.empty()); 1374 EXPECT_FALSE(func->GetOAuth2ClientId().empty()); 1375 EXPECT_NE("client1", func->GetOAuth2ClientId()); 1376 } 1377 1378 IN_PROC_BROWSER_TEST_F(GetAuthTokenFunctionTest, ComponentWithNormalClientId) { 1379 scoped_refptr<FakeGetAuthTokenFunction> func(new FakeGetAuthTokenFunction()); 1380 scoped_refptr<const Extension> extension( 1381 CreateExtension(CLIENT_ID | SCOPES | AS_COMPONENT)); 1382 func->set_extension(extension.get()); 1383 EXPECT_EQ("client1", func->GetOAuth2ClientId()); 1384 } 1385 1386 IN_PROC_BROWSER_TEST_F(GetAuthTokenFunctionTest, MultiDefaultUser) { 1387 SignIn("primary (at) example.com"); 1388 SetAccountState(CreateIds("primary (at) example.com", "1"), true); 1389 SetAccountState(CreateIds("secondary (at) example.com", "2"), true); 1390 1391 scoped_refptr<FakeGetAuthTokenFunction> func(new FakeGetAuthTokenFunction()); 1392 scoped_refptr<const Extension> extension(CreateExtension(CLIENT_ID | SCOPES)); 1393 func->set_extension(extension.get()); 1394 func->set_auto_login_access_token(false); 1395 func->set_mint_token_result(TestOAuth2MintTokenFlow::MINT_TOKEN_SUCCESS); 1396 1397 RunFunctionAsync(func.get(), "[{}]"); 1398 1399 IssueLoginAccessTokenForAccount("primary (at) example.com"); 1400 1401 scoped_ptr<base::Value> value(WaitForSingleResult(func.get())); 1402 std::string access_token; 1403 EXPECT_TRUE(value->GetAsString(&access_token)); 1404 EXPECT_EQ(std::string(kAccessToken), access_token); 1405 EXPECT_EQ(IdentityTokenCacheValue::CACHE_STATUS_TOKEN, 1406 GetCachedToken(std::string()).status()); 1407 EXPECT_EQ("access_token-primary (at) example.com", func->login_access_token()); 1408 } 1409 1410 IN_PROC_BROWSER_TEST_F(GetAuthTokenFunctionTest, MultiPrimaryUser) { 1411 SignIn("primary (at) example.com"); 1412 IssueLoginRefreshTokenForAccount("secondary (at) example.com"); 1413 SetAccountState(CreateIds("primary (at) example.com", "1"), true); 1414 SetAccountState(CreateIds("secondary (at) example.com", "2"), true); 1415 1416 scoped_refptr<FakeGetAuthTokenFunction> func(new FakeGetAuthTokenFunction()); 1417 scoped_refptr<const Extension> extension(CreateExtension(CLIENT_ID | SCOPES)); 1418 func->set_extension(extension.get()); 1419 func->set_auto_login_access_token(false); 1420 func->set_mint_token_result(TestOAuth2MintTokenFlow::MINT_TOKEN_SUCCESS); 1421 1422 RunFunctionAsync(func.get(), "[{\"account\": { \"id\": \"1\" } }]"); 1423 1424 IssueLoginAccessTokenForAccount("primary (at) example.com"); 1425 1426 scoped_ptr<base::Value> value(WaitForSingleResult(func.get())); 1427 std::string access_token; 1428 EXPECT_TRUE(value->GetAsString(&access_token)); 1429 EXPECT_EQ(std::string(kAccessToken), access_token); 1430 EXPECT_EQ(IdentityTokenCacheValue::CACHE_STATUS_TOKEN, 1431 GetCachedToken(std::string()).status()); 1432 EXPECT_EQ("access_token-primary (at) example.com", func->login_access_token()); 1433 } 1434 1435 IN_PROC_BROWSER_TEST_F(GetAuthTokenFunctionTest, MultiSecondaryUser) { 1436 SignIn("primary (at) example.com"); 1437 IssueLoginRefreshTokenForAccount("secondary (at) example.com"); 1438 SetAccountState(CreateIds("primary (at) example.com", "1"), true); 1439 SetAccountState(CreateIds("secondary (at) example.com", "2"), true); 1440 1441 scoped_refptr<FakeGetAuthTokenFunction> func(new FakeGetAuthTokenFunction()); 1442 scoped_refptr<const Extension> extension(CreateExtension(CLIENT_ID | SCOPES)); 1443 func->set_extension(extension.get()); 1444 func->set_auto_login_access_token(false); 1445 func->set_mint_token_result(TestOAuth2MintTokenFlow::MINT_TOKEN_SUCCESS); 1446 1447 RunFunctionAsync(func.get(), "[{\"account\": { \"id\": \"2\" } }]"); 1448 1449 IssueLoginAccessTokenForAccount("secondary (at) example.com"); 1450 1451 scoped_ptr<base::Value> value(WaitForSingleResult(func.get())); 1452 std::string access_token; 1453 EXPECT_TRUE(value->GetAsString(&access_token)); 1454 EXPECT_EQ(std::string(kAccessToken), access_token); 1455 EXPECT_EQ(IdentityTokenCacheValue::CACHE_STATUS_TOKEN, 1456 GetCachedToken("secondary (at) example.com").status()); 1457 EXPECT_EQ("access_token-secondary (at) example.com", func->login_access_token()); 1458 } 1459 1460 IN_PROC_BROWSER_TEST_F(GetAuthTokenFunctionTest, MultiUnknownUser) { 1461 SignIn("primary (at) example.com"); 1462 IssueLoginRefreshTokenForAccount("secondary (at) example.com"); 1463 SetAccountState(CreateIds("primary (at) example.com", "1"), true); 1464 SetAccountState(CreateIds("secondary (at) example.com", "2"), true); 1465 1466 scoped_refptr<FakeGetAuthTokenFunction> func(new FakeGetAuthTokenFunction()); 1467 scoped_refptr<const Extension> extension(CreateExtension(CLIENT_ID | SCOPES)); 1468 func->set_extension(extension.get()); 1469 func->set_auto_login_access_token(false); 1470 1471 std::string error = utils::RunFunctionAndReturnError( 1472 func.get(), "[{\"account\": { \"id\": \"3\" } }]", browser()); 1473 EXPECT_EQ(std::string(errors::kUserNotSignedIn), error); 1474 } 1475 1476 IN_PROC_BROWSER_TEST_F(GetAuthTokenFunctionTest, 1477 MultiSecondaryNonInteractiveMintFailure) { 1478 SignIn("primary (at) example.com"); 1479 IssueLoginRefreshTokenForAccount("secondary (at) example.com"); 1480 SetAccountState(CreateIds("primary (at) example.com", "1"), true); 1481 SetAccountState(CreateIds("secondary (at) example.com", "2"), true); 1482 1483 scoped_refptr<FakeGetAuthTokenFunction> func(new FakeGetAuthTokenFunction()); 1484 func->set_extension(CreateExtension(CLIENT_ID | SCOPES)); 1485 func->set_mint_token_result(TestOAuth2MintTokenFlow::MINT_TOKEN_FAILURE); 1486 std::string error = utils::RunFunctionAndReturnError( 1487 func.get(), "[{\"account\": { \"id\": \"2\" } }]", browser()); 1488 EXPECT_TRUE(StartsWithASCII(error, errors::kAuthFailure, false)); 1489 EXPECT_FALSE(func->login_ui_shown()); 1490 EXPECT_FALSE(func->scope_ui_shown()); 1491 } 1492 1493 IN_PROC_BROWSER_TEST_F(GetAuthTokenFunctionTest, 1494 MultiSecondaryNonInteractiveLoginAccessTokenFailure) { 1495 SignIn("primary (at) example.com"); 1496 IssueLoginRefreshTokenForAccount("secondary (at) example.com"); 1497 SetAccountState(CreateIds("primary (at) example.com", "1"), true); 1498 SetAccountState(CreateIds("secondary (at) example.com", "2"), true); 1499 1500 scoped_refptr<FakeGetAuthTokenFunction> func(new FakeGetAuthTokenFunction()); 1501 func->set_extension(CreateExtension(CLIENT_ID | SCOPES)); 1502 func->set_login_access_token_result(false); 1503 std::string error = utils::RunFunctionAndReturnError( 1504 func.get(), "[{\"account\": { \"id\": \"2\" } }]", browser()); 1505 EXPECT_TRUE(StartsWithASCII(error, errors::kAuthFailure, false)); 1506 } 1507 1508 IN_PROC_BROWSER_TEST_F(GetAuthTokenFunctionTest, 1509 MultiSecondaryInteractiveApprovalAborted) { 1510 SignIn("primary (at) example.com"); 1511 IssueLoginRefreshTokenForAccount("secondary (at) example.com"); 1512 SetAccountState(CreateIds("primary (at) example.com", "1"), true); 1513 SetAccountState(CreateIds("secondary (at) example.com", "2"), true); 1514 1515 scoped_refptr<FakeGetAuthTokenFunction> func(new FakeGetAuthTokenFunction()); 1516 func->set_extension(CreateExtension(CLIENT_ID | SCOPES)); 1517 func->set_mint_token_result(TestOAuth2MintTokenFlow::ISSUE_ADVICE_SUCCESS); 1518 func->set_scope_ui_failure(GaiaWebAuthFlow::WINDOW_CLOSED); 1519 std::string error = utils::RunFunctionAndReturnError( 1520 func.get(), 1521 "[{\"account\": { \"id\": \"2\" }, \"interactive\": true}]", 1522 browser()); 1523 EXPECT_EQ(std::string(errors::kUserRejected), error); 1524 EXPECT_FALSE(func->login_ui_shown()); 1525 EXPECT_TRUE(func->scope_ui_shown()); 1526 } 1527 1528 IN_PROC_BROWSER_TEST_F(GetAuthTokenFunctionTest, ScopesDefault) { 1529 SignIn("primary (at) example.com"); 1530 scoped_refptr<FakeGetAuthTokenFunction> func(new FakeGetAuthTokenFunction()); 1531 scoped_refptr<const Extension> extension(CreateExtension(CLIENT_ID | SCOPES)); 1532 func->set_extension(extension.get()); 1533 func->set_mint_token_result(TestOAuth2MintTokenFlow::MINT_TOKEN_SUCCESS); 1534 scoped_ptr<base::Value> value( 1535 utils::RunFunctionAndReturnSingleResult(func.get(), "[{}]", browser())); 1536 std::string access_token; 1537 EXPECT_TRUE(value->GetAsString(&access_token)); 1538 EXPECT_EQ(std::string(kAccessToken), access_token); 1539 1540 const ExtensionTokenKey* token_key = func->GetExtensionTokenKeyForTest(); 1541 EXPECT_EQ(2ul, token_key->scopes.size()); 1542 EXPECT_TRUE(ContainsKey(token_key->scopes, "scope1")); 1543 EXPECT_TRUE(ContainsKey(token_key->scopes, "scope2")); 1544 } 1545 1546 IN_PROC_BROWSER_TEST_F(GetAuthTokenFunctionTest, ScopesEmpty) { 1547 scoped_refptr<FakeGetAuthTokenFunction> func(new FakeGetAuthTokenFunction()); 1548 scoped_refptr<const Extension> extension(CreateExtension(CLIENT_ID | SCOPES)); 1549 func->set_extension(extension.get()); 1550 1551 std::string error(utils::RunFunctionAndReturnError( 1552 func.get(), "[{\"scopes\": []}]", browser())); 1553 1554 EXPECT_EQ(errors::kInvalidScopes, error); 1555 } 1556 1557 IN_PROC_BROWSER_TEST_F(GetAuthTokenFunctionTest, ScopesEmail) { 1558 SignIn("primary (at) example.com"); 1559 scoped_refptr<FakeGetAuthTokenFunction> func(new FakeGetAuthTokenFunction()); 1560 scoped_refptr<const Extension> extension(CreateExtension(CLIENT_ID | SCOPES)); 1561 func->set_extension(extension.get()); 1562 func->set_mint_token_result(TestOAuth2MintTokenFlow::MINT_TOKEN_SUCCESS); 1563 scoped_ptr<base::Value> value(utils::RunFunctionAndReturnSingleResult( 1564 func.get(), "[{\"scopes\": [\"email\"]}]", browser())); 1565 std::string access_token; 1566 EXPECT_TRUE(value->GetAsString(&access_token)); 1567 EXPECT_EQ(std::string(kAccessToken), access_token); 1568 1569 const ExtensionTokenKey* token_key = func->GetExtensionTokenKeyForTest(); 1570 EXPECT_EQ(1ul, token_key->scopes.size()); 1571 EXPECT_TRUE(ContainsKey(token_key->scopes, "email")); 1572 } 1573 1574 IN_PROC_BROWSER_TEST_F(GetAuthTokenFunctionTest, ScopesEmailFooBar) { 1575 SignIn("primary (at) example.com"); 1576 scoped_refptr<FakeGetAuthTokenFunction> func(new FakeGetAuthTokenFunction()); 1577 scoped_refptr<const Extension> extension(CreateExtension(CLIENT_ID | SCOPES)); 1578 func->set_extension(extension.get()); 1579 func->set_mint_token_result(TestOAuth2MintTokenFlow::MINT_TOKEN_SUCCESS); 1580 scoped_ptr<base::Value> value(utils::RunFunctionAndReturnSingleResult( 1581 func.get(), "[{\"scopes\": [\"email\", \"foo\", \"bar\"]}]", browser())); 1582 std::string access_token; 1583 EXPECT_TRUE(value->GetAsString(&access_token)); 1584 EXPECT_EQ(std::string(kAccessToken), access_token); 1585 1586 const ExtensionTokenKey* token_key = func->GetExtensionTokenKeyForTest(); 1587 EXPECT_EQ(3ul, token_key->scopes.size()); 1588 EXPECT_TRUE(ContainsKey(token_key->scopes, "email")); 1589 EXPECT_TRUE(ContainsKey(token_key->scopes, "foo")); 1590 EXPECT_TRUE(ContainsKey(token_key->scopes, "bar")); 1591 } 1592 1593 class RemoveCachedAuthTokenFunctionTest : public ExtensionBrowserTest { 1594 protected: 1595 bool InvalidateDefaultToken() { 1596 scoped_refptr<IdentityRemoveCachedAuthTokenFunction> func( 1597 new IdentityRemoveCachedAuthTokenFunction); 1598 func->set_extension(test_util::CreateEmptyExtension(kExtensionId).get()); 1599 return utils::RunFunction( 1600 func.get(), 1601 std::string("[{\"token\": \"") + kAccessToken + "\"}]", 1602 browser(), 1603 extension_function_test_utils::NONE); 1604 } 1605 1606 IdentityAPI* id_api() { 1607 return IdentityAPI::GetFactoryInstance()->Get(browser()->profile()); 1608 } 1609 1610 void SetCachedToken(IdentityTokenCacheValue& token_data) { 1611 ExtensionTokenKey key( 1612 kExtensionId, "test (at) example.com", std::set<std::string>()); 1613 id_api()->SetCachedToken(key, token_data); 1614 } 1615 1616 const IdentityTokenCacheValue& GetCachedToken() { 1617 return id_api()->GetCachedToken(ExtensionTokenKey( 1618 kExtensionId, "test (at) example.com", std::set<std::string>())); 1619 } 1620 }; 1621 1622 IN_PROC_BROWSER_TEST_F(RemoveCachedAuthTokenFunctionTest, NotFound) { 1623 EXPECT_TRUE(InvalidateDefaultToken()); 1624 EXPECT_EQ(IdentityTokenCacheValue::CACHE_STATUS_NOTFOUND, 1625 GetCachedToken().status()); 1626 } 1627 1628 IN_PROC_BROWSER_TEST_F(RemoveCachedAuthTokenFunctionTest, Advice) { 1629 IssueAdviceInfo info; 1630 IdentityTokenCacheValue advice(info); 1631 SetCachedToken(advice); 1632 EXPECT_TRUE(InvalidateDefaultToken()); 1633 EXPECT_EQ(IdentityTokenCacheValue::CACHE_STATUS_ADVICE, 1634 GetCachedToken().status()); 1635 } 1636 1637 IN_PROC_BROWSER_TEST_F(RemoveCachedAuthTokenFunctionTest, NonMatchingToken) { 1638 IdentityTokenCacheValue token("non_matching_token", 1639 base::TimeDelta::FromSeconds(3600)); 1640 SetCachedToken(token); 1641 EXPECT_TRUE(InvalidateDefaultToken()); 1642 EXPECT_EQ(IdentityTokenCacheValue::CACHE_STATUS_TOKEN, 1643 GetCachedToken().status()); 1644 EXPECT_EQ("non_matching_token", GetCachedToken().token()); 1645 } 1646 1647 IN_PROC_BROWSER_TEST_F(RemoveCachedAuthTokenFunctionTest, MatchingToken) { 1648 IdentityTokenCacheValue token(kAccessToken, 1649 base::TimeDelta::FromSeconds(3600)); 1650 SetCachedToken(token); 1651 EXPECT_EQ(IdentityTokenCacheValue::CACHE_STATUS_TOKEN, 1652 GetCachedToken().status()); 1653 EXPECT_TRUE(InvalidateDefaultToken()); 1654 EXPECT_EQ(IdentityTokenCacheValue::CACHE_STATUS_NOTFOUND, 1655 GetCachedToken().status()); 1656 } 1657 1658 class LaunchWebAuthFlowFunctionTest : public AsyncExtensionBrowserTest { 1659 public: 1660 virtual void SetUpCommandLine(CommandLine* command_line) OVERRIDE { 1661 AsyncExtensionBrowserTest::SetUpCommandLine(command_line); 1662 // Reduce performance test variance by disabling background networking. 1663 command_line->AppendSwitch(switches::kDisableBackgroundNetworking); 1664 } 1665 }; 1666 1667 IN_PROC_BROWSER_TEST_F(LaunchWebAuthFlowFunctionTest, UserCloseWindow) { 1668 net::SpawnedTestServer https_server( 1669 net::SpawnedTestServer::TYPE_HTTPS, 1670 net::SpawnedTestServer::kLocalhost, 1671 base::FilePath(FILE_PATH_LITERAL( 1672 "chrome/test/data/extensions/api_test/identity"))); 1673 ASSERT_TRUE(https_server.Start()); 1674 GURL auth_url(https_server.GetURL("files/interaction_required.html")); 1675 1676 scoped_refptr<IdentityLaunchWebAuthFlowFunction> function( 1677 new IdentityLaunchWebAuthFlowFunction()); 1678 scoped_refptr<Extension> empty_extension(test_util::CreateEmptyExtension()); 1679 function->set_extension(empty_extension.get()); 1680 1681 WaitForGURLAndCloseWindow popup_observer(auth_url); 1682 1683 std::string args = "[{\"interactive\": true, \"url\": \"" + 1684 auth_url.spec() + "\"}]"; 1685 RunFunctionAsync(function.get(), args); 1686 1687 popup_observer.Wait(); 1688 popup_observer.CloseEmbedderWebContents(); 1689 1690 EXPECT_EQ(std::string(errors::kUserRejected), WaitForError(function.get())); 1691 } 1692 1693 IN_PROC_BROWSER_TEST_F(LaunchWebAuthFlowFunctionTest, InteractionRequired) { 1694 net::SpawnedTestServer https_server( 1695 net::SpawnedTestServer::TYPE_HTTPS, 1696 net::SpawnedTestServer::kLocalhost, 1697 base::FilePath(FILE_PATH_LITERAL( 1698 "chrome/test/data/extensions/api_test/identity"))); 1699 ASSERT_TRUE(https_server.Start()); 1700 GURL auth_url(https_server.GetURL("files/interaction_required.html")); 1701 1702 scoped_refptr<IdentityLaunchWebAuthFlowFunction> function( 1703 new IdentityLaunchWebAuthFlowFunction()); 1704 scoped_refptr<Extension> empty_extension(test_util::CreateEmptyExtension()); 1705 function->set_extension(empty_extension.get()); 1706 1707 std::string args = "[{\"interactive\": false, \"url\": \"" + 1708 auth_url.spec() + "\"}]"; 1709 std::string error = 1710 utils::RunFunctionAndReturnError(function.get(), args, browser()); 1711 1712 EXPECT_EQ(std::string(errors::kInteractionRequired), error); 1713 } 1714 1715 IN_PROC_BROWSER_TEST_F(LaunchWebAuthFlowFunctionTest, LoadFailed) { 1716 net::SpawnedTestServer https_server( 1717 net::SpawnedTestServer::TYPE_HTTPS, 1718 net::SpawnedTestServer::kLocalhost, 1719 base::FilePath(FILE_PATH_LITERAL( 1720 "chrome/test/data/extensions/api_test/identity"))); 1721 ASSERT_TRUE(https_server.Start()); 1722 GURL auth_url(https_server.GetURL("files/five_hundred.html")); 1723 1724 scoped_refptr<IdentityLaunchWebAuthFlowFunction> function( 1725 new IdentityLaunchWebAuthFlowFunction()); 1726 scoped_refptr<Extension> empty_extension(test_util::CreateEmptyExtension()); 1727 function->set_extension(empty_extension.get()); 1728 1729 std::string args = "[{\"interactive\": true, \"url\": \"" + 1730 auth_url.spec() + "\"}]"; 1731 std::string error = 1732 utils::RunFunctionAndReturnError(function.get(), args, browser()); 1733 1734 EXPECT_EQ(std::string(errors::kPageLoadFailure), error); 1735 } 1736 1737 IN_PROC_BROWSER_TEST_F(LaunchWebAuthFlowFunctionTest, NonInteractiveSuccess) { 1738 #if defined(OS_WIN) && defined(USE_ASH) 1739 // Disable this test in Metro+Ash for now (http://crbug.com/262796). 1740 if (CommandLine::ForCurrentProcess()->HasSwitch(switches::kAshBrowserTests)) 1741 return; 1742 #endif 1743 1744 scoped_refptr<IdentityLaunchWebAuthFlowFunction> function( 1745 new IdentityLaunchWebAuthFlowFunction()); 1746 scoped_refptr<Extension> empty_extension(test_util::CreateEmptyExtension()); 1747 function->set_extension(empty_extension.get()); 1748 1749 function->InitFinalRedirectURLPrefixForTest("abcdefghij"); 1750 scoped_ptr<base::Value> value(utils::RunFunctionAndReturnSingleResult( 1751 function.get(), 1752 "[{\"interactive\": false," 1753 "\"url\": \"https://abcdefghij.chromiumapp.org/callback#test\"}]", 1754 browser())); 1755 1756 std::string url; 1757 EXPECT_TRUE(value->GetAsString(&url)); 1758 EXPECT_EQ(std::string("https://abcdefghij.chromiumapp.org/callback#test"), 1759 url); 1760 } 1761 1762 IN_PROC_BROWSER_TEST_F( 1763 LaunchWebAuthFlowFunctionTest, InteractiveFirstNavigationSuccess) { 1764 #if defined(OS_WIN) && defined(USE_ASH) 1765 // Disable this test in Metro+Ash for now (http://crbug.com/262796). 1766 if (CommandLine::ForCurrentProcess()->HasSwitch(switches::kAshBrowserTests)) 1767 return; 1768 #endif 1769 1770 scoped_refptr<IdentityLaunchWebAuthFlowFunction> function( 1771 new IdentityLaunchWebAuthFlowFunction()); 1772 scoped_refptr<Extension> empty_extension(test_util::CreateEmptyExtension()); 1773 function->set_extension(empty_extension.get()); 1774 1775 function->InitFinalRedirectURLPrefixForTest("abcdefghij"); 1776 scoped_ptr<base::Value> value(utils::RunFunctionAndReturnSingleResult( 1777 function.get(), 1778 "[{\"interactive\": true," 1779 "\"url\": \"https://abcdefghij.chromiumapp.org/callback#test\"}]", 1780 browser())); 1781 1782 std::string url; 1783 EXPECT_TRUE(value->GetAsString(&url)); 1784 EXPECT_EQ(std::string("https://abcdefghij.chromiumapp.org/callback#test"), 1785 url); 1786 } 1787 1788 IN_PROC_BROWSER_TEST_F(LaunchWebAuthFlowFunctionTest, 1789 DISABLED_InteractiveSecondNavigationSuccess) { 1790 net::SpawnedTestServer https_server( 1791 net::SpawnedTestServer::TYPE_HTTPS, 1792 net::SpawnedTestServer::kLocalhost, 1793 base::FilePath(FILE_PATH_LITERAL( 1794 "chrome/test/data/extensions/api_test/identity"))); 1795 ASSERT_TRUE(https_server.Start()); 1796 GURL auth_url(https_server.GetURL("files/redirect_to_chromiumapp.html")); 1797 1798 scoped_refptr<IdentityLaunchWebAuthFlowFunction> function( 1799 new IdentityLaunchWebAuthFlowFunction()); 1800 scoped_refptr<Extension> empty_extension(test_util::CreateEmptyExtension()); 1801 function->set_extension(empty_extension.get()); 1802 1803 function->InitFinalRedirectURLPrefixForTest("abcdefghij"); 1804 std::string args = "[{\"interactive\": true, \"url\": \"" + 1805 auth_url.spec() + "\"}]"; 1806 scoped_ptr<base::Value> value( 1807 utils::RunFunctionAndReturnSingleResult(function.get(), args, browser())); 1808 1809 std::string url; 1810 EXPECT_TRUE(value->GetAsString(&url)); 1811 EXPECT_EQ(std::string("https://abcdefghij.chromiumapp.org/callback#test"), 1812 url); 1813 } 1814 1815 } // namespace extensions 1816 1817 // Tests the chrome.identity API implemented by custom JS bindings . 1818 IN_PROC_BROWSER_TEST_F(ExtensionApiTest, ChromeIdentityJsBindings) { 1819 ASSERT_TRUE(RunExtensionTest("identity/js_bindings")) << message_; 1820 } 1821