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