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