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