identity_apitest.cc revision b2df76ea8fec9e32f6f3718986dba0d95315b29c
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 "base/string_util.h" 6#include "base/stringprintf.h" 7#include "base/values.h" 8#include "chrome/browser/extensions/api/identity/identity_api.h" 9#include "chrome/browser/extensions/extension_apitest.h" 10#include "chrome/browser/extensions/extension_browsertest.h" 11#include "chrome/browser/extensions/extension_function_test_utils.h" 12#include "chrome/browser/extensions/extension_service.h" 13#include "chrome/browser/ui/browser.h" 14#include "chrome/browser/ui/browser_window.h" 15#include "chrome/common/chrome_notification_types.h" 16#include "chrome/common/chrome_switches.h" 17#include "chrome/common/extensions/api/identity/oauth2_manifest_handler.h" 18#include "chrome/test/base/in_process_browser_test.h" 19#include "content/public/browser/notification_service.h" 20#include "content/public/browser/notification_source.h" 21#include "content/public/test/test_utils.h" 22#include "extensions/common/id_util.h" 23#include "google_apis/gaia/google_service_auth_error.h" 24#include "google_apis/gaia/oauth2_mint_token_flow.h" 25#include "googleurl/src/gurl.h" 26#include "grit/browser_resources.h" 27#include "net/test/spawned_test_server/spawned_test_server.h" 28#include "testing/gmock/include/gmock/gmock.h" 29#include "testing/gtest/include/gtest/gtest.h" 30 31using testing::_; 32using testing::Return; 33using testing::ReturnRef; 34 35namespace extensions { 36 37namespace { 38 39namespace errors = identity_constants; 40namespace utils = extension_function_test_utils; 41 42static const char kAccessToken[] = "auth_token"; 43static const char kExtensionId[] = "ext_id"; 44 45// This helps us be able to wait until an AsyncExtensionFunction calls 46// SendResponse. 47class SendResponseDelegate 48 : public UIThreadExtensionFunction::DelegateForTests { 49 public: 50 SendResponseDelegate() : should_post_quit_(false) {} 51 52 virtual ~SendResponseDelegate() {} 53 54 void set_should_post_quit(bool should_quit) { 55 should_post_quit_ = should_quit; 56 } 57 58 bool HasResponse() { 59 return response_.get() != NULL; 60 } 61 62 bool GetResponse() { 63 EXPECT_TRUE(HasResponse()); 64 return *response_.get(); 65 } 66 67 virtual void OnSendResponse(UIThreadExtensionFunction* function, 68 bool success, 69 bool bad_message) OVERRIDE { 70 ASSERT_FALSE(bad_message); 71 ASSERT_FALSE(HasResponse()); 72 response_.reset(new bool); 73 *response_ = success; 74 if (should_post_quit_) { 75 MessageLoopForUI::current()->Quit(); 76 } 77 } 78 79 private: 80 scoped_ptr<bool> response_; 81 bool should_post_quit_; 82}; 83 84class AsyncExtensionBrowserTest : public ExtensionBrowserTest { 85 protected: 86 // Asynchronous function runner allows tests to manipulate the browser window 87 // after the call happens. 88 void RunFunctionAsync( 89 UIThreadExtensionFunction* function, 90 const std::string& args) { 91 response_delegate_.reset(new SendResponseDelegate); 92 function->set_test_delegate(response_delegate_.get()); 93 scoped_ptr<base::ListValue> parsed_args(utils::ParseList(args)); 94 EXPECT_TRUE(parsed_args.get()) << 95 "Could not parse extension function arguments: " << args; 96 function->SetArgs(parsed_args.get()); 97 98 if (!function->GetExtension()) { 99 scoped_refptr<Extension> empty_extension( 100 utils::CreateEmptyExtension()); 101 function->set_extension(empty_extension.get()); 102 } 103 104 function->set_profile(browser()->profile()); 105 function->set_has_callback(true); 106 function->Run(); 107 } 108 109 std::string WaitForError(UIThreadExtensionFunction* function) { 110 RunMessageLoopUntilResponse(); 111 EXPECT_FALSE(function->GetResultList()) << "Did not expect a result"; 112 return function->GetError(); 113 } 114 115 base::Value* WaitForSingleResult(UIThreadExtensionFunction* function) { 116 RunMessageLoopUntilResponse(); 117 EXPECT_TRUE(function->GetError().empty()) << "Unexpected error: " 118 << function->GetError(); 119 const base::Value* single_result = NULL; 120 if (function->GetResultList() != NULL && 121 function->GetResultList()->Get(0, &single_result)) { 122 return single_result->DeepCopy(); 123 } 124 return NULL; 125 } 126 127 private: 128 void RunMessageLoopUntilResponse() { 129 // If the RunImpl of |function| didn't already call SendResponse, run the 130 // message loop until they do. 131 if (!response_delegate_->HasResponse()) { 132 response_delegate_->set_should_post_quit(true); 133 content::RunMessageLoop(); 134 } 135 EXPECT_TRUE(response_delegate_->HasResponse()); 136 } 137 138 scoped_ptr<SendResponseDelegate> response_delegate_; 139}; 140 141class TestOAuth2MintTokenFlow : public OAuth2MintTokenFlow { 142 public: 143 enum ResultType { 144 ISSUE_ADVICE_SUCCESS, 145 MINT_TOKEN_SUCCESS, 146 MINT_TOKEN_FAILURE, 147 MINT_TOKEN_BAD_CREDENTIALS 148 }; 149 150 TestOAuth2MintTokenFlow(ResultType result, 151 OAuth2MintTokenFlow::Delegate* delegate) 152 : OAuth2MintTokenFlow(NULL, delegate, OAuth2MintTokenFlow::Parameters()), 153 result_(result), 154 delegate_(delegate) { 155 } 156 157 virtual void Start() OVERRIDE { 158 switch (result_) { 159 case ISSUE_ADVICE_SUCCESS: { 160 IssueAdviceInfo info; 161 delegate_->OnIssueAdviceSuccess(info); 162 break; 163 } 164 case MINT_TOKEN_SUCCESS: { 165 delegate_->OnMintTokenSuccess(kAccessToken, 3600); 166 break; 167 } 168 case MINT_TOKEN_FAILURE: { 169 GoogleServiceAuthError error(GoogleServiceAuthError::CONNECTION_FAILED); 170 delegate_->OnMintTokenFailure(error); 171 break; 172 } 173 case MINT_TOKEN_BAD_CREDENTIALS: { 174 GoogleServiceAuthError error( 175 GoogleServiceAuthError::INVALID_GAIA_CREDENTIALS); 176 delegate_->OnMintTokenFailure(error); 177 break; 178 } 179 } 180 } 181 182 private: 183 ResultType result_; 184 OAuth2MintTokenFlow::Delegate* delegate_; 185}; 186 187ProfileKeyedService* IdentityAPITestFactory(content::BrowserContext* profile) { 188 return new IdentityAPI(static_cast<Profile*>(profile)); 189} 190 191} // namespace 192 193class MockGetAuthTokenFunction : public IdentityGetAuthTokenFunction { 194 public: 195 MockGetAuthTokenFunction() : login_ui_result_(true), 196 install_ui_result_(false), 197 login_ui_shown_(false), 198 install_ui_shown_(false) { 199 } 200 201 void set_login_ui_result(bool result) { 202 login_ui_result_ = result; 203 } 204 205 void set_install_ui_result(bool result) { 206 install_ui_result_ = result; 207 } 208 209 bool login_ui_shown() const { 210 return login_ui_shown_; 211 } 212 213 bool install_ui_shown() const { 214 return install_ui_shown_; 215 } 216 217 virtual void ShowLoginPopup() OVERRIDE { 218 EXPECT_FALSE(login_ui_shown_); 219 login_ui_shown_ = true; 220 if (login_ui_result_) 221 SigninSuccess("fake_refresh_token"); 222 else 223 SigninFailed(); 224 } 225 226 virtual void ShowOAuthApprovalDialog( 227 const IssueAdviceInfo& issue_advice) OVERRIDE { 228 install_ui_shown_ = true; 229 // Call InstallUIProceed or InstallUIAbort based on the flag. 230 if (install_ui_result_) 231 InstallUIProceed(); 232 else 233 InstallUIAbort(true); 234 } 235 236 MOCK_CONST_METHOD0(HasLoginToken, bool()); 237 MOCK_METHOD1(CreateMintTokenFlow, 238 OAuth2MintTokenFlow* (OAuth2MintTokenFlow::Mode mode)); 239 240 private: 241 ~MockGetAuthTokenFunction() {} 242 bool login_ui_result_; 243 bool install_ui_result_; 244 bool login_ui_shown_; 245 bool install_ui_shown_; 246}; 247 248class MockQueuedMintRequest : public IdentityMintRequestQueue::Request { 249 public: 250 MOCK_METHOD1(StartMintToken, void(IdentityMintRequestQueue::MintType)); 251}; 252 253class GetAuthTokenFunctionTest : public AsyncExtensionBrowserTest { 254 protected: 255 enum OAuth2Fields { 256 NONE = 0, 257 CLIENT_ID = 1, 258 SCOPES = 2 259 }; 260 261 virtual ~GetAuthTokenFunctionTest() {} 262 263 // Helper to create an extension with specific OAuth2Info fields set. 264 // |fields_to_set| should be computed by using fields of Oauth2Fields enum. 265 const Extension* CreateExtension(int fields_to_set) { 266 const Extension* ext = LoadExtension( 267 test_data_dir_.AppendASCII("platform_apps/oauth2")); 268 OAuth2Info& oauth2_info = const_cast<OAuth2Info&>( 269 OAuth2Info::GetOAuth2Info(ext)); 270 if ((fields_to_set & CLIENT_ID) != 0) 271 oauth2_info.client_id = "client1"; 272 if ((fields_to_set & SCOPES) != 0) { 273 oauth2_info.scopes.push_back("scope1"); 274 oauth2_info.scopes.push_back("scope2"); 275 } 276 return ext; 277 } 278 279 IdentityAPI* id_api() { 280 return IdentityAPI::GetFactoryInstance()->GetForProfile( 281 browser()->profile()); 282 } 283}; 284 285IN_PROC_BROWSER_TEST_F(GetAuthTokenFunctionTest, 286 NoClientId) { 287 scoped_refptr<MockGetAuthTokenFunction> func(new MockGetAuthTokenFunction()); 288 func->set_extension(CreateExtension(SCOPES)); 289 std::string error = utils::RunFunctionAndReturnError( 290 func.get(), "[{}]", browser()); 291 EXPECT_EQ(std::string(errors::kInvalidClientId), error); 292 EXPECT_FALSE(func->login_ui_shown()); 293 EXPECT_FALSE(func->install_ui_shown()); 294} 295 296IN_PROC_BROWSER_TEST_F(GetAuthTokenFunctionTest, 297 NoScopes) { 298 scoped_refptr<MockGetAuthTokenFunction> func(new MockGetAuthTokenFunction()); 299 func->set_extension(CreateExtension(CLIENT_ID)); 300 std::string error = utils::RunFunctionAndReturnError( 301 func.get(), "[{}]", browser()); 302 EXPECT_EQ(std::string(errors::kInvalidScopes), error); 303 EXPECT_FALSE(func->login_ui_shown()); 304 EXPECT_FALSE(func->install_ui_shown()); 305} 306 307IN_PROC_BROWSER_TEST_F(GetAuthTokenFunctionTest, 308 NonInteractiveNotSignedIn) { 309 scoped_refptr<MockGetAuthTokenFunction> func(new MockGetAuthTokenFunction()); 310 func->set_extension(CreateExtension(CLIENT_ID | SCOPES)); 311 EXPECT_CALL(*func.get(), HasLoginToken()).WillOnce(Return(false)); 312 std::string error = utils::RunFunctionAndReturnError( 313 func.get(), "[{}]", browser()); 314 EXPECT_EQ(std::string(errors::kUserNotSignedIn), error); 315 EXPECT_FALSE(func->login_ui_shown()); 316 EXPECT_FALSE(func->install_ui_shown()); 317} 318 319IN_PROC_BROWSER_TEST_F(GetAuthTokenFunctionTest, 320 NonInteractiveMintFailure) { 321 scoped_refptr<MockGetAuthTokenFunction> func(new MockGetAuthTokenFunction()); 322 func->set_extension(CreateExtension(CLIENT_ID | SCOPES)); 323 EXPECT_CALL(*func.get(), HasLoginToken()) 324 .WillOnce(Return(true)); 325 TestOAuth2MintTokenFlow* flow = new TestOAuth2MintTokenFlow( 326 TestOAuth2MintTokenFlow::MINT_TOKEN_FAILURE, func.get()); 327 EXPECT_CALL(*func.get(), CreateMintTokenFlow(_)).WillOnce(Return(flow)); 328 std::string error = utils::RunFunctionAndReturnError( 329 func.get(), "[{}]", browser()); 330 EXPECT_TRUE(StartsWithASCII(error, errors::kAuthFailure, false)); 331 EXPECT_FALSE(func->login_ui_shown()); 332 EXPECT_FALSE(func->install_ui_shown()); 333} 334 335IN_PROC_BROWSER_TEST_F(GetAuthTokenFunctionTest, 336 NonInteractiveMintAdviceSuccess) { 337 scoped_refptr<const Extension> extension(CreateExtension(CLIENT_ID | SCOPES)); 338 scoped_refptr<MockGetAuthTokenFunction> func(new MockGetAuthTokenFunction()); 339 func->set_extension(extension); 340 EXPECT_CALL(*func.get(), HasLoginToken()) 341 .WillOnce(Return(true)); 342 TestOAuth2MintTokenFlow* flow = new TestOAuth2MintTokenFlow( 343 TestOAuth2MintTokenFlow::ISSUE_ADVICE_SUCCESS, func.get()); 344 EXPECT_CALL(*func.get(), CreateMintTokenFlow(_)).WillOnce(Return(flow)); 345 std::string error = utils::RunFunctionAndReturnError( 346 func.get(), "[{}]", browser()); 347 EXPECT_EQ(std::string(errors::kNoGrant), error); 348 EXPECT_FALSE(func->login_ui_shown()); 349 EXPECT_FALSE(func->install_ui_shown()); 350 351 const OAuth2Info& oauth2_info = OAuth2Info::GetOAuth2Info(extension); 352 EXPECT_EQ(IdentityTokenCacheValue::CACHE_STATUS_ADVICE, 353 id_api()->GetCachedToken(extension->id(), 354 oauth2_info.scopes).status()); 355} 356 357IN_PROC_BROWSER_TEST_F(GetAuthTokenFunctionTest, 358 NonInteractiveMintBadCredentials) { 359 scoped_refptr<MockGetAuthTokenFunction> func(new MockGetAuthTokenFunction()); 360 func->set_extension(CreateExtension(CLIENT_ID | SCOPES)); 361 EXPECT_CALL(*func.get(), HasLoginToken()) 362 .WillOnce(Return(true)); 363 TestOAuth2MintTokenFlow* flow = new TestOAuth2MintTokenFlow( 364 TestOAuth2MintTokenFlow::MINT_TOKEN_BAD_CREDENTIALS, func.get()); 365 EXPECT_CALL(*func.get(), CreateMintTokenFlow(_)).WillOnce(Return(flow)); 366 std::string error = utils::RunFunctionAndReturnError( 367 func.get(), "[{}]", browser()); 368 EXPECT_TRUE(StartsWithASCII(error, errors::kAuthFailure, false)); 369 EXPECT_FALSE(func->login_ui_shown()); 370 EXPECT_FALSE(func->install_ui_shown()); 371} 372 373IN_PROC_BROWSER_TEST_F(GetAuthTokenFunctionTest, 374 NonInteractiveSuccess) { 375 scoped_refptr<MockGetAuthTokenFunction> func(new MockGetAuthTokenFunction()); 376 scoped_refptr<const Extension> extension(CreateExtension(CLIENT_ID | SCOPES)); 377 func->set_extension(extension); 378 const OAuth2Info& oauth2_info = OAuth2Info::GetOAuth2Info(extension); 379 EXPECT_CALL(*func.get(), HasLoginToken()) 380 .WillOnce(Return(true)); 381 TestOAuth2MintTokenFlow* flow = new TestOAuth2MintTokenFlow( 382 TestOAuth2MintTokenFlow::MINT_TOKEN_SUCCESS, func.get()); 383 EXPECT_CALL(*func.get(), CreateMintTokenFlow(_)).WillOnce(Return(flow)); 384 scoped_ptr<base::Value> value(utils::RunFunctionAndReturnSingleResult( 385 func.get(), "[{}]", browser())); 386 std::string access_token; 387 EXPECT_TRUE(value->GetAsString(&access_token)); 388 EXPECT_EQ(std::string(kAccessToken), access_token); 389 EXPECT_FALSE(func->login_ui_shown()); 390 EXPECT_FALSE(func->install_ui_shown()); 391 EXPECT_EQ(IdentityTokenCacheValue::CACHE_STATUS_TOKEN, 392 id_api()->GetCachedToken(extension->id(), 393 oauth2_info.scopes).status()); 394} 395 396IN_PROC_BROWSER_TEST_F(GetAuthTokenFunctionTest, 397 InteractiveLoginCanceled) { 398 scoped_refptr<MockGetAuthTokenFunction> func(new MockGetAuthTokenFunction()); 399 func->set_extension(CreateExtension(CLIENT_ID | SCOPES)); 400 EXPECT_CALL(*func.get(), HasLoginToken()).WillOnce(Return(false)); 401 func->set_login_ui_result(false); 402 std::string error = utils::RunFunctionAndReturnError( 403 func.get(), "[{\"interactive\": true}]", browser()); 404 EXPECT_EQ(std::string(errors::kUserNotSignedIn), error); 405 EXPECT_TRUE(func->login_ui_shown()); 406 EXPECT_FALSE(func->install_ui_shown()); 407} 408 409IN_PROC_BROWSER_TEST_F(GetAuthTokenFunctionTest, 410 InteractiveMintBadCredentialsLoginCanceled) { 411 scoped_refptr<MockGetAuthTokenFunction> func(new MockGetAuthTokenFunction()); 412 func->set_extension(CreateExtension(CLIENT_ID | SCOPES)); 413 EXPECT_CALL(*func.get(), HasLoginToken()) 414 .WillOnce(Return(true)); 415 TestOAuth2MintTokenFlow* flow = new TestOAuth2MintTokenFlow( 416 TestOAuth2MintTokenFlow::MINT_TOKEN_BAD_CREDENTIALS, func.get()); 417 EXPECT_CALL(*func.get(), CreateMintTokenFlow(_)).WillOnce(Return(flow)); 418 func->set_login_ui_result(false); 419 std::string error = utils::RunFunctionAndReturnError( 420 func.get(), "[{\"interactive\": true}]", browser()); 421 EXPECT_EQ(std::string(errors::kUserNotSignedIn), error); 422 EXPECT_TRUE(func->login_ui_shown()); 423 EXPECT_FALSE(func->install_ui_shown()); 424} 425 426IN_PROC_BROWSER_TEST_F(GetAuthTokenFunctionTest, 427 InteractiveLoginSuccessNoToken) { 428 scoped_refptr<MockGetAuthTokenFunction> func(new MockGetAuthTokenFunction()); 429 func->set_extension(CreateExtension(CLIENT_ID | SCOPES)); 430 EXPECT_CALL(*func.get(), HasLoginToken()).WillOnce(Return(false)); 431 func->set_login_ui_result(false); 432 std::string error = utils::RunFunctionAndReturnError( 433 func.get(), "[{\"interactive\": true}]", browser()); 434 EXPECT_EQ(std::string(errors::kUserNotSignedIn), error); 435 EXPECT_TRUE(func->login_ui_shown()); 436 EXPECT_FALSE(func->install_ui_shown()); 437} 438 439IN_PROC_BROWSER_TEST_F(GetAuthTokenFunctionTest, 440 InteractiveLoginSuccessMintFailure) { 441 scoped_refptr<MockGetAuthTokenFunction> func(new MockGetAuthTokenFunction()); 442 func->set_extension(CreateExtension(CLIENT_ID | SCOPES)); 443 EXPECT_CALL(*func.get(), HasLoginToken()) 444 .WillOnce(Return(false)); 445 func->set_login_ui_result(true); 446 TestOAuth2MintTokenFlow* flow = new TestOAuth2MintTokenFlow( 447 TestOAuth2MintTokenFlow::MINT_TOKEN_FAILURE, func.get()); 448 EXPECT_CALL(*func.get(), CreateMintTokenFlow(_)).WillOnce(Return(flow)); 449 std::string error = utils::RunFunctionAndReturnError( 450 func.get(), "[{\"interactive\": true}]", browser()); 451 EXPECT_TRUE(StartsWithASCII(error, errors::kAuthFailure, false)); 452 EXPECT_TRUE(func->login_ui_shown()); 453 EXPECT_FALSE(func->install_ui_shown()); 454} 455 456IN_PROC_BROWSER_TEST_F(GetAuthTokenFunctionTest, 457 InteractiveLoginSuccessMintSuccess) { 458 scoped_refptr<MockGetAuthTokenFunction> func(new MockGetAuthTokenFunction()); 459 func->set_extension(CreateExtension(CLIENT_ID | SCOPES)); 460 EXPECT_CALL(*func.get(), HasLoginToken()) 461 .WillOnce(Return(false)); 462 func->set_login_ui_result(true); 463 TestOAuth2MintTokenFlow* flow = new TestOAuth2MintTokenFlow( 464 TestOAuth2MintTokenFlow::MINT_TOKEN_SUCCESS, func.get()); 465 EXPECT_CALL(*func.get(), CreateMintTokenFlow(_)).WillOnce(Return(flow)); 466 scoped_ptr<base::Value> value(utils::RunFunctionAndReturnSingleResult( 467 func.get(), "[{\"interactive\": true}]", browser())); 468 std::string access_token; 469 EXPECT_TRUE(value->GetAsString(&access_token)); 470 EXPECT_EQ(std::string(kAccessToken), access_token); 471 EXPECT_TRUE(func->login_ui_shown()); 472 EXPECT_FALSE(func->install_ui_shown()); 473} 474 475IN_PROC_BROWSER_TEST_F(GetAuthTokenFunctionTest, 476 InteractiveLoginSuccessApprovalAborted) { 477 scoped_refptr<MockGetAuthTokenFunction> func(new MockGetAuthTokenFunction()); 478 func->set_extension(CreateExtension(CLIENT_ID | SCOPES)); 479 EXPECT_CALL(*func.get(), HasLoginToken()) 480 .WillOnce(Return(false)); 481 func->set_login_ui_result(true); 482 TestOAuth2MintTokenFlow* flow = new TestOAuth2MintTokenFlow( 483 TestOAuth2MintTokenFlow::ISSUE_ADVICE_SUCCESS, func.get()); 484 EXPECT_CALL(*func.get(), CreateMintTokenFlow(_)).WillOnce(Return(flow)); 485 func->set_install_ui_result(false); 486 std::string error = utils::RunFunctionAndReturnError( 487 func.get(), "[{\"interactive\": true}]", browser()); 488 EXPECT_EQ(std::string(errors::kUserRejected), error); 489 EXPECT_TRUE(func->login_ui_shown()); 490 EXPECT_TRUE(func->install_ui_shown()); 491} 492 493IN_PROC_BROWSER_TEST_F(GetAuthTokenFunctionTest, 494 InteractiveLoginSuccessApprovalDoneMintFailure) { 495 scoped_refptr<MockGetAuthTokenFunction> func(new MockGetAuthTokenFunction()); 496 func->set_extension(CreateExtension(CLIENT_ID | SCOPES)); 497 EXPECT_CALL(*func.get(), HasLoginToken()) 498 .WillOnce(Return(false)); 499 func->set_login_ui_result(true); 500 TestOAuth2MintTokenFlow* flow1 = new TestOAuth2MintTokenFlow( 501 TestOAuth2MintTokenFlow::ISSUE_ADVICE_SUCCESS, func.get()); 502 TestOAuth2MintTokenFlow* flow2 = new TestOAuth2MintTokenFlow( 503 TestOAuth2MintTokenFlow::MINT_TOKEN_FAILURE, func.get()); 504 EXPECT_CALL(*func.get(), CreateMintTokenFlow(_)) 505 .WillOnce(Return(flow1)) 506 .WillOnce(Return(flow2)); 507 508 func->set_install_ui_result(true); 509 std::string error = utils::RunFunctionAndReturnError( 510 func.get(), "[{\"interactive\": true}]", browser()); 511 EXPECT_TRUE(StartsWithASCII(error, errors::kAuthFailure, false)); 512 EXPECT_TRUE(func->login_ui_shown()); 513 EXPECT_TRUE(func->install_ui_shown()); 514} 515 516IN_PROC_BROWSER_TEST_F(GetAuthTokenFunctionTest, 517 InteractiveLoginSuccessApprovalDoneMintSuccess) { 518 scoped_refptr<MockGetAuthTokenFunction> func(new MockGetAuthTokenFunction()); 519 scoped_refptr<const Extension> extension(CreateExtension(CLIENT_ID | SCOPES)); 520 func->set_extension(extension); 521 const OAuth2Info& oauth2_info = OAuth2Info::GetOAuth2Info(extension); 522 EXPECT_CALL(*func.get(), HasLoginToken()) 523 .WillOnce(Return(false)); 524 func->set_login_ui_result(true); 525 TestOAuth2MintTokenFlow* flow1 = new TestOAuth2MintTokenFlow( 526 TestOAuth2MintTokenFlow::ISSUE_ADVICE_SUCCESS, func.get()); 527 TestOAuth2MintTokenFlow* flow2 = new TestOAuth2MintTokenFlow( 528 TestOAuth2MintTokenFlow::MINT_TOKEN_SUCCESS, func.get()); 529 EXPECT_CALL(*func.get(), CreateMintTokenFlow(_)) 530 .WillOnce(Return(flow1)) 531 .WillOnce(Return(flow2)); 532 533 func->set_install_ui_result(true); 534 scoped_ptr<base::Value> value(utils::RunFunctionAndReturnSingleResult( 535 func.get(), "[{\"interactive\": true}]", browser())); 536 std::string access_token; 537 EXPECT_TRUE(value->GetAsString(&access_token)); 538 EXPECT_EQ(std::string(kAccessToken), access_token); 539 EXPECT_TRUE(func->login_ui_shown()); 540 EXPECT_TRUE(func->install_ui_shown()); 541 EXPECT_EQ(IdentityTokenCacheValue::CACHE_STATUS_TOKEN, 542 id_api()->GetCachedToken(extension->id(), 543 oauth2_info.scopes).status()); 544} 545 546IN_PROC_BROWSER_TEST_F(GetAuthTokenFunctionTest, 547 InteractiveApprovalAborted) { 548 scoped_refptr<MockGetAuthTokenFunction> func(new MockGetAuthTokenFunction()); 549 func->set_extension(CreateExtension(CLIENT_ID | SCOPES)); 550 EXPECT_CALL(*func.get(), HasLoginToken()) 551 .WillOnce(Return(true)); 552 TestOAuth2MintTokenFlow* flow = new TestOAuth2MintTokenFlow( 553 TestOAuth2MintTokenFlow::ISSUE_ADVICE_SUCCESS, func.get()); 554 EXPECT_CALL(*func.get(), CreateMintTokenFlow(_)).WillOnce(Return(flow)); 555 func->set_install_ui_result(false); 556 std::string error = utils::RunFunctionAndReturnError( 557 func.get(), "[{\"interactive\": true}]", browser()); 558 EXPECT_EQ(std::string(errors::kUserRejected), error); 559 EXPECT_FALSE(func->login_ui_shown()); 560 EXPECT_TRUE(func->install_ui_shown()); 561} 562 563IN_PROC_BROWSER_TEST_F(GetAuthTokenFunctionTest, 564 InteractiveApprovalDoneMintSuccess) { 565 scoped_refptr<MockGetAuthTokenFunction> func(new MockGetAuthTokenFunction()); 566 func->set_extension(CreateExtension(CLIENT_ID | SCOPES)); 567 EXPECT_CALL(*func.get(), HasLoginToken()) 568 .WillOnce(Return(true)); 569 TestOAuth2MintTokenFlow* flow1 = new TestOAuth2MintTokenFlow( 570 TestOAuth2MintTokenFlow::ISSUE_ADVICE_SUCCESS, func.get()); 571 TestOAuth2MintTokenFlow* flow2 = new TestOAuth2MintTokenFlow( 572 TestOAuth2MintTokenFlow::MINT_TOKEN_SUCCESS, func.get()); 573 EXPECT_CALL(*func.get(), CreateMintTokenFlow(_)) 574 .WillOnce(Return(flow1)) 575 .WillOnce(Return(flow2)); 576 577 func->set_install_ui_result(true); 578 scoped_ptr<base::Value> value(utils::RunFunctionAndReturnSingleResult( 579 func.get(), "[{\"interactive\": true}]", browser())); 580 std::string access_token; 581 EXPECT_TRUE(value->GetAsString(&access_token)); 582 EXPECT_EQ(std::string(kAccessToken), access_token); 583 EXPECT_FALSE(func->login_ui_shown()); 584 EXPECT_TRUE(func->install_ui_shown()); 585} 586 587IN_PROC_BROWSER_TEST_F(GetAuthTokenFunctionTest, 588 InteractiveApprovalDoneMintBadCredentials) { 589 scoped_refptr<MockGetAuthTokenFunction> func(new MockGetAuthTokenFunction()); 590 func->set_extension(CreateExtension(CLIENT_ID | SCOPES)); 591 EXPECT_CALL(*func.get(), HasLoginToken()) 592 .WillOnce(Return(true)); 593 TestOAuth2MintTokenFlow* flow1 = new TestOAuth2MintTokenFlow( 594 TestOAuth2MintTokenFlow::ISSUE_ADVICE_SUCCESS, func.get()); 595 TestOAuth2MintTokenFlow* flow2 = new TestOAuth2MintTokenFlow( 596 TestOAuth2MintTokenFlow::MINT_TOKEN_BAD_CREDENTIALS, func.get()); 597 EXPECT_CALL(*func.get(), CreateMintTokenFlow(_)) 598 .WillOnce(Return(flow1)) 599 .WillOnce(Return(flow2)); 600 601 func->set_install_ui_result(true); 602 std::string error = utils::RunFunctionAndReturnError( 603 func.get(), "[{\"interactive\": true}]", browser()); 604 EXPECT_TRUE(StartsWithASCII(error, errors::kAuthFailure, false)); 605 EXPECT_FALSE(func->login_ui_shown()); 606 EXPECT_TRUE(func->install_ui_shown()); 607} 608 609IN_PROC_BROWSER_TEST_F(GetAuthTokenFunctionTest, NoninteractiveQueue) { 610 scoped_refptr<const Extension> extension(CreateExtension(CLIENT_ID | SCOPES)); 611 scoped_refptr<MockGetAuthTokenFunction> func(new MockGetAuthTokenFunction()); 612 func->set_extension(extension); 613 614 // Create a fake request to block the queue. 615 const OAuth2Info& oauth2_info = OAuth2Info::GetOAuth2Info(extension); 616 std::set<std::string> scopes(oauth2_info.scopes.begin(), 617 oauth2_info.scopes.end()); 618 IdentityAPI* id_api = 619 extensions::IdentityAPI::GetFactoryInstance()->GetForProfile( 620 browser()->profile()); 621 IdentityMintRequestQueue* queue = id_api->mint_queue(); 622 MockQueuedMintRequest queued_request; 623 IdentityMintRequestQueue::MintType type = 624 IdentityMintRequestQueue::MINT_TYPE_NONINTERACTIVE; 625 626 EXPECT_CALL(queued_request, StartMintToken(type)).Times(1); 627 queue->RequestStart(type, extension->id(), scopes, &queued_request); 628 629 // The real request will start processing, but wait in the queue behind 630 // the blocker. 631 EXPECT_CALL(*func.get(), HasLoginToken()).WillOnce(Return(true)); 632 RunFunctionAsync(func, "[{}]"); 633 // Verify that we have fetched the login token at this point. 634 testing::Mock::VerifyAndClearExpectations(func); 635 636 // The flow will be created after the first queued request clears. 637 TestOAuth2MintTokenFlow* flow = new TestOAuth2MintTokenFlow( 638 TestOAuth2MintTokenFlow::MINT_TOKEN_SUCCESS, func.get()); 639 EXPECT_CALL(*func.get(), CreateMintTokenFlow(_)).WillOnce(Return(flow)); 640 641 queue->RequestComplete(type, extension->id(), scopes, &queued_request); 642 643 scoped_ptr<base::Value> value(WaitForSingleResult(func)); 644 std::string access_token; 645 EXPECT_TRUE(value->GetAsString(&access_token)); 646 EXPECT_EQ(std::string(kAccessToken), access_token); 647 EXPECT_FALSE(func->login_ui_shown()); 648 EXPECT_FALSE(func->install_ui_shown()); 649} 650 651IN_PROC_BROWSER_TEST_F(GetAuthTokenFunctionTest, InteractiveQueue) { 652 scoped_refptr<const Extension> extension(CreateExtension(CLIENT_ID | SCOPES)); 653 scoped_refptr<MockGetAuthTokenFunction> func(new MockGetAuthTokenFunction()); 654 func->set_extension(extension); 655 656 // Create a fake request to block the queue. 657 const OAuth2Info& oauth2_info = OAuth2Info::GetOAuth2Info(extension); 658 std::set<std::string> scopes(oauth2_info.scopes.begin(), 659 oauth2_info.scopes.end()); 660 IdentityAPI* id_api = 661 extensions::IdentityAPI::GetFactoryInstance()->GetForProfile( 662 browser()->profile()); 663 IdentityMintRequestQueue* queue = id_api->mint_queue(); 664 MockQueuedMintRequest queued_request; 665 IdentityMintRequestQueue::MintType type = 666 IdentityMintRequestQueue::MINT_TYPE_INTERACTIVE; 667 668 EXPECT_CALL(queued_request, StartMintToken(type)).Times(1); 669 queue->RequestStart(type, extension->id(), scopes, &queued_request); 670 671 // The real request will start processing, but wait in the queue behind 672 // the blocker. 673 EXPECT_CALL(*func.get(), HasLoginToken()).WillOnce(Return(true)); 674 TestOAuth2MintTokenFlow* flow1 = new TestOAuth2MintTokenFlow( 675 TestOAuth2MintTokenFlow::ISSUE_ADVICE_SUCCESS, func.get()); 676 EXPECT_CALL(*func.get(), CreateMintTokenFlow(_)).WillOnce(Return(flow1)); 677 RunFunctionAsync(func, "[{\"interactive\": true}]"); 678 // Verify that we have fetched the login token and run the first flow. 679 testing::Mock::VerifyAndClearExpectations(func); 680 EXPECT_FALSE(func->install_ui_shown()); 681 682 // The UI will be displayed and the second flow will be created 683 // after the first queued request clears. 684 func->set_install_ui_result(true); 685 TestOAuth2MintTokenFlow* flow2 = new TestOAuth2MintTokenFlow( 686 TestOAuth2MintTokenFlow::MINT_TOKEN_SUCCESS, func.get()); 687 EXPECT_CALL(*func.get(), CreateMintTokenFlow(_)).WillOnce(Return(flow2)); 688 689 queue->RequestComplete(type, extension->id(), scopes, &queued_request); 690 691 scoped_ptr<base::Value> value(WaitForSingleResult(func)); 692 std::string access_token; 693 EXPECT_TRUE(value->GetAsString(&access_token)); 694 EXPECT_EQ(std::string(kAccessToken), access_token); 695 EXPECT_FALSE(func->login_ui_shown()); 696 EXPECT_TRUE(func->install_ui_shown()); 697} 698 699IN_PROC_BROWSER_TEST_F(GetAuthTokenFunctionTest, 700 InteractiveQueuedNoninteractiveFails) { 701 scoped_refptr<const Extension> extension(CreateExtension(CLIENT_ID | SCOPES)); 702 scoped_refptr<MockGetAuthTokenFunction> func(new MockGetAuthTokenFunction()); 703 func->set_extension(extension); 704 705 // Create a fake request to block the interactive queue. 706 const OAuth2Info& oauth2_info = OAuth2Info::GetOAuth2Info(extension); 707 std::set<std::string> scopes(oauth2_info.scopes.begin(), 708 oauth2_info.scopes.end()); 709 IdentityAPI* id_api = 710 extensions::IdentityAPI::GetFactoryInstance()->GetForProfile( 711 browser()->profile()); 712 IdentityMintRequestQueue* queue = id_api->mint_queue(); 713 MockQueuedMintRequest queued_request; 714 IdentityMintRequestQueue::MintType type = 715 IdentityMintRequestQueue::MINT_TYPE_INTERACTIVE; 716 717 EXPECT_CALL(queued_request, StartMintToken(type)).Times(1); 718 queue->RequestStart(type, extension->id(), scopes, &queued_request); 719 720 // Non-interactive requests fail without hitting GAIA, because a 721 // consent UI is known to be up. 722 EXPECT_CALL(*func.get(), HasLoginToken()).WillOnce(Return(true)); 723 std::string error = utils::RunFunctionAndReturnError( 724 func.get(), "[{}]", browser()); 725 EXPECT_EQ(std::string(errors::kNoGrant), error); 726 EXPECT_FALSE(func->login_ui_shown()); 727 EXPECT_FALSE(func->install_ui_shown()); 728 729 queue->RequestComplete(type, extension->id(), scopes, &queued_request); 730} 731 732IN_PROC_BROWSER_TEST_F(GetAuthTokenFunctionTest, 733 NonInteractiveCacheHit) { 734 scoped_refptr<const Extension> extension(CreateExtension(CLIENT_ID | SCOPES)); 735 scoped_refptr<MockGetAuthTokenFunction> func(new MockGetAuthTokenFunction()); 736 func->set_extension(extension); 737 738 // pre-populate the cache with a token 739 const OAuth2Info& oauth2_info = OAuth2Info::GetOAuth2Info(extension); 740 IdentityTokenCacheValue token(kAccessToken, 741 base::TimeDelta::FromSeconds(3600)); 742 id_api()->SetCachedToken(extension->id(), oauth2_info.scopes, token); 743 744 // Get a token. Should not require a GAIA request. 745 EXPECT_CALL(*func.get(), HasLoginToken()) 746 .WillOnce(Return(true)); 747 scoped_ptr<base::Value> value(utils::RunFunctionAndReturnSingleResult( 748 func.get(), "[{}]", browser())); 749 std::string access_token; 750 EXPECT_TRUE(value->GetAsString(&access_token)); 751 EXPECT_EQ(std::string(kAccessToken), access_token); 752 EXPECT_FALSE(func->login_ui_shown()); 753 EXPECT_FALSE(func->install_ui_shown()); 754} 755 756IN_PROC_BROWSER_TEST_F(GetAuthTokenFunctionTest, 757 NonInteractiveIssueAdviceCacheHit) { 758 scoped_refptr<const Extension> extension(CreateExtension(CLIENT_ID | SCOPES)); 759 scoped_refptr<MockGetAuthTokenFunction> func(new MockGetAuthTokenFunction()); 760 func->set_extension(extension); 761 762 // pre-populate the cache with advice 763 const OAuth2Info& oauth2_info = OAuth2Info::GetOAuth2Info(extension); 764 IssueAdviceInfo info; 765 IdentityTokenCacheValue token(info); 766 id_api()->SetCachedToken(extension->id(), oauth2_info.scopes, token); 767 768 // Should return an error without a GAIA request. 769 EXPECT_CALL(*func.get(), HasLoginToken()) 770 .WillOnce(Return(true)); 771 std::string error = utils::RunFunctionAndReturnError( 772 func.get(), "[{}]", browser()); 773 EXPECT_EQ(std::string(errors::kNoGrant), error); 774 EXPECT_FALSE(func->login_ui_shown()); 775 EXPECT_FALSE(func->install_ui_shown()); 776} 777 778IN_PROC_BROWSER_TEST_F(GetAuthTokenFunctionTest, 779 InteractiveCacheHit) { 780 scoped_refptr<const Extension> extension(CreateExtension(CLIENT_ID | SCOPES)); 781 scoped_refptr<MockGetAuthTokenFunction> func(new MockGetAuthTokenFunction()); 782 func->set_extension(extension); 783 784 // Create a fake request to block the queue. 785 const OAuth2Info& oauth2_info = OAuth2Info::GetOAuth2Info(extension); 786 std::set<std::string> scopes(oauth2_info.scopes.begin(), 787 oauth2_info.scopes.end()); 788 IdentityMintRequestQueue* queue = id_api()->mint_queue(); 789 MockQueuedMintRequest queued_request; 790 IdentityMintRequestQueue::MintType type = 791 IdentityMintRequestQueue::MINT_TYPE_INTERACTIVE; 792 793 EXPECT_CALL(queued_request, StartMintToken(type)).Times(1); 794 queue->RequestStart(type, extension->id(), scopes, &queued_request); 795 796 // The real request will start processing, but wait in the queue behind 797 // the blocker. 798 EXPECT_CALL(*func.get(), HasLoginToken()).WillOnce(Return(true)); 799 TestOAuth2MintTokenFlow* flow = new TestOAuth2MintTokenFlow( 800 TestOAuth2MintTokenFlow::ISSUE_ADVICE_SUCCESS, func.get()); 801 EXPECT_CALL(*func.get(), CreateMintTokenFlow(_)).WillOnce(Return(flow)); 802 RunFunctionAsync(func, "[{\"interactive\": true}]"); 803 804 // Populate the cache with a token while the request is blocked. 805 IdentityTokenCacheValue token(kAccessToken, 806 base::TimeDelta::FromSeconds(3600)); 807 id_api()->SetCachedToken(extension->id(), oauth2_info.scopes, token); 808 809 // When we wake up the request, it returns the cached token without 810 // displaying a UI, or hitting GAIA. 811 812 queue->RequestComplete(type, extension->id(), scopes, &queued_request); 813 814 scoped_ptr<base::Value> value(WaitForSingleResult(func)); 815 std::string access_token; 816 EXPECT_TRUE(value->GetAsString(&access_token)); 817 EXPECT_EQ(std::string(kAccessToken), access_token); 818 EXPECT_FALSE(func->login_ui_shown()); 819 EXPECT_FALSE(func->install_ui_shown()); 820} 821 822IN_PROC_BROWSER_TEST_F(GetAuthTokenFunctionTest, 823 LoginInvalidatesTokenCache) { 824 scoped_refptr<MockGetAuthTokenFunction> func(new MockGetAuthTokenFunction()); 825 scoped_refptr<const Extension> extension(CreateExtension(CLIENT_ID | SCOPES)); 826 func->set_extension(extension); 827 828 // pre-populate the cache with a token 829 const OAuth2Info& oauth2_info = OAuth2Info::GetOAuth2Info(extension); 830 IdentityTokenCacheValue token(kAccessToken, 831 base::TimeDelta::FromSeconds(3600)); 832 id_api()->SetCachedToken(extension->id(), oauth2_info.scopes, token); 833 834 // Because the user is not signed in, the token will be removed, 835 // and we'll hit GAIA for new tokens. 836 EXPECT_CALL(*func.get(), HasLoginToken()) 837 .WillOnce(Return(false)); 838 func->set_login_ui_result(true); 839 TestOAuth2MintTokenFlow* flow1 = new TestOAuth2MintTokenFlow( 840 TestOAuth2MintTokenFlow::ISSUE_ADVICE_SUCCESS, func.get()); 841 TestOAuth2MintTokenFlow* flow2 = new TestOAuth2MintTokenFlow( 842 TestOAuth2MintTokenFlow::MINT_TOKEN_SUCCESS, func.get()); 843 EXPECT_CALL(*func.get(), CreateMintTokenFlow(_)) 844 .WillOnce(Return(flow1)) 845 .WillOnce(Return(flow2)); 846 847 func->set_install_ui_result(true); 848 scoped_ptr<base::Value> value(utils::RunFunctionAndReturnSingleResult( 849 func.get(), "[{\"interactive\": true}]", browser())); 850 std::string access_token; 851 EXPECT_TRUE(value->GetAsString(&access_token)); 852 EXPECT_EQ(std::string(kAccessToken), access_token); 853 EXPECT_TRUE(func->login_ui_shown()); 854 EXPECT_TRUE(func->install_ui_shown()); 855 EXPECT_EQ(IdentityTokenCacheValue::CACHE_STATUS_TOKEN, 856 id_api()->GetCachedToken(extension->id(), 857 oauth2_info.scopes).status()); 858} 859 860class RemoveCachedAuthTokenFunctionTest : public ExtensionBrowserTest { 861 protected: 862 bool InvalidateDefaultToken() { 863 scoped_refptr<IdentityRemoveCachedAuthTokenFunction> func( 864 new IdentityRemoveCachedAuthTokenFunction); 865 func->set_extension(utils::CreateEmptyExtension(kExtensionId)); 866 return utils::RunFunction( 867 func, std::string("[{\"token\": \"") + kAccessToken + "\"}]", browser(), 868 extension_function_test_utils::NONE); 869 } 870 871 IdentityAPI* id_api() { 872 return IdentityAPI::GetFactoryInstance()->GetForProfile( 873 browser()->profile()); 874 } 875 876 void SetCachedToken(IdentityTokenCacheValue& token_data) { 877 id_api()->SetCachedToken(extensions::id_util::GenerateId(kExtensionId), 878 std::vector<std::string>(), token_data); 879 } 880 881 const IdentityTokenCacheValue& GetCachedToken() { 882 return id_api()->GetCachedToken( 883 extensions::id_util::GenerateId(kExtensionId), 884 std::vector<std::string>()); 885 } 886}; 887 888IN_PROC_BROWSER_TEST_F(RemoveCachedAuthTokenFunctionTest, NotFound) { 889 EXPECT_TRUE(InvalidateDefaultToken()); 890 EXPECT_EQ(IdentityTokenCacheValue::CACHE_STATUS_NOTFOUND, 891 GetCachedToken().status()); 892} 893 894IN_PROC_BROWSER_TEST_F(RemoveCachedAuthTokenFunctionTest, Advice) { 895 IssueAdviceInfo info; 896 IdentityTokenCacheValue advice(info); 897 SetCachedToken(advice); 898 EXPECT_TRUE(InvalidateDefaultToken()); 899 EXPECT_EQ(IdentityTokenCacheValue::CACHE_STATUS_ADVICE, 900 GetCachedToken().status()); 901} 902 903IN_PROC_BROWSER_TEST_F(RemoveCachedAuthTokenFunctionTest, NonMatchingToken) { 904 IdentityTokenCacheValue token("non_matching_token", 905 base::TimeDelta::FromSeconds(3600)); 906 SetCachedToken(token); 907 EXPECT_TRUE(InvalidateDefaultToken()); 908 EXPECT_EQ(IdentityTokenCacheValue::CACHE_STATUS_TOKEN, 909 GetCachedToken().status()); 910 EXPECT_EQ("non_matching_token", GetCachedToken().token()); 911} 912 913IN_PROC_BROWSER_TEST_F(RemoveCachedAuthTokenFunctionTest, MatchingToken) { 914 IdentityTokenCacheValue token(kAccessToken, 915 base::TimeDelta::FromSeconds(3600)); 916 SetCachedToken(token); 917 EXPECT_TRUE(InvalidateDefaultToken()); 918 EXPECT_EQ(IdentityTokenCacheValue::CACHE_STATUS_NOTFOUND, 919 GetCachedToken().status()); 920} 921 922class LaunchWebAuthFlowFunctionTest : public AsyncExtensionBrowserTest { 923 public: 924 virtual void SetUpCommandLine(CommandLine* command_line) OVERRIDE { 925 // Reduce performance test variance by disabling background networking. 926 command_line->AppendSwitch(switches::kDisableBackgroundNetworking); 927 } 928}; 929 930IN_PROC_BROWSER_TEST_F(LaunchWebAuthFlowFunctionTest, UserCloseWindow) { 931 net::SpawnedTestServer https_server( 932 net::SpawnedTestServer::TYPE_HTTPS, 933 net::SpawnedTestServer::kLocalhost, 934 base::FilePath(FILE_PATH_LITERAL( 935 "chrome/test/data/extensions/api_test/identity"))); 936 ASSERT_TRUE(https_server.Start()); 937 GURL auth_url(https_server.GetURL("files/interaction_required.html")); 938 939 scoped_refptr<IdentityLaunchWebAuthFlowFunction> function( 940 new IdentityLaunchWebAuthFlowFunction()); 941 scoped_refptr<Extension> empty_extension( 942 utils::CreateEmptyExtension()); 943 function->set_extension(empty_extension.get()); 944 945 content::WindowedNotificationObserver popup_observer( 946 chrome::NOTIFICATION_BROWSER_WINDOW_READY, 947 content::NotificationService::AllSources()); 948 949 std::string args = "[{\"interactive\": true, \"url\": \"" + 950 auth_url.spec() + "\"}]"; 951 RunFunctionAsync(function, args); 952 953 popup_observer.Wait(); 954 content::Source<Browser>(popup_observer.source())->window()->Close(); 955 956 EXPECT_EQ(std::string(errors::kUserRejected), WaitForError(function)); 957} 958 959IN_PROC_BROWSER_TEST_F(LaunchWebAuthFlowFunctionTest, InteractionRequired) { 960 net::SpawnedTestServer https_server( 961 net::SpawnedTestServer::TYPE_HTTPS, 962 net::SpawnedTestServer::kLocalhost, 963 base::FilePath(FILE_PATH_LITERAL( 964 "chrome/test/data/extensions/api_test/identity"))); 965 ASSERT_TRUE(https_server.Start()); 966 GURL auth_url(https_server.GetURL("files/interaction_required.html")); 967 968 scoped_refptr<IdentityLaunchWebAuthFlowFunction> function( 969 new IdentityLaunchWebAuthFlowFunction()); 970 scoped_refptr<Extension> empty_extension( 971 utils::CreateEmptyExtension()); 972 function->set_extension(empty_extension.get()); 973 974 std::string args = "[{\"interactive\": false, \"url\": \"" + 975 auth_url.spec() + "\"}]"; 976 std::string error = utils::RunFunctionAndReturnError(function, args, 977 browser()); 978 979 EXPECT_EQ(std::string(errors::kInteractionRequired), error); 980} 981 982IN_PROC_BROWSER_TEST_F(LaunchWebAuthFlowFunctionTest, NonInteractiveSuccess) { 983 scoped_refptr<IdentityLaunchWebAuthFlowFunction> function( 984 new IdentityLaunchWebAuthFlowFunction()); 985 scoped_refptr<Extension> empty_extension( 986 utils::CreateEmptyExtension()); 987 function->set_extension(empty_extension.get()); 988 989 function->InitFinalRedirectURLPrefixForTest("abcdefghij"); 990 scoped_ptr<base::Value> value(utils::RunFunctionAndReturnSingleResult( 991 function, 992 "[{\"interactive\": false," 993 "\"url\": \"https://abcdefghij.chromiumapp.org/callback#test\"}]", 994 browser())); 995 996 std::string url; 997 EXPECT_TRUE(value->GetAsString(&url)); 998 EXPECT_EQ(std::string("https://abcdefghij.chromiumapp.org/callback#test"), 999 url); 1000} 1001 1002IN_PROC_BROWSER_TEST_F( 1003 LaunchWebAuthFlowFunctionTest, InteractiveFirstNavigationSuccess) { 1004 scoped_refptr<IdentityLaunchWebAuthFlowFunction> function( 1005 new IdentityLaunchWebAuthFlowFunction()); 1006 scoped_refptr<Extension> empty_extension( 1007 utils::CreateEmptyExtension()); 1008 function->set_extension(empty_extension.get()); 1009 1010 function->InitFinalRedirectURLPrefixForTest("abcdefghij"); 1011 scoped_ptr<base::Value> value(utils::RunFunctionAndReturnSingleResult( 1012 function, 1013 "[{\"interactive\": true," 1014 "\"url\": \"https://abcdefghij.chromiumapp.org/callback#test\"}]", 1015 browser())); 1016 1017 std::string url; 1018 EXPECT_TRUE(value->GetAsString(&url)); 1019 EXPECT_EQ(std::string("https://abcdefghij.chromiumapp.org/callback#test"), 1020 url); 1021} 1022 1023IN_PROC_BROWSER_TEST_F( 1024 LaunchWebAuthFlowFunctionTest, InteractiveSecondNavigationSuccess) { 1025 net::SpawnedTestServer https_server( 1026 net::SpawnedTestServer::TYPE_HTTPS, 1027 net::SpawnedTestServer::kLocalhost, 1028 base::FilePath(FILE_PATH_LITERAL( 1029 "chrome/test/data/extensions/api_test/identity"))); 1030 ASSERT_TRUE(https_server.Start()); 1031 GURL auth_url(https_server.GetURL("files/redirect_to_chromiumapp.html")); 1032 1033 scoped_refptr<IdentityLaunchWebAuthFlowFunction> function( 1034 new IdentityLaunchWebAuthFlowFunction()); 1035 scoped_refptr<Extension> empty_extension( 1036 utils::CreateEmptyExtension()); 1037 function->set_extension(empty_extension.get()); 1038 1039 function->InitFinalRedirectURLPrefixForTest("abcdefghij"); 1040 std::string args = "[{\"interactive\": true, \"url\": \"" + 1041 auth_url.spec() + "\"}]"; 1042 scoped_ptr<base::Value> value(utils::RunFunctionAndReturnSingleResult( 1043 function, args, browser())); 1044 1045 std::string url; 1046 EXPECT_TRUE(value->GetAsString(&url)); 1047 EXPECT_EQ(std::string("https://abcdefghij.chromiumapp.org/callback#test"), 1048 url); 1049} 1050 1051} // namespace extensions 1052