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.
5 #include "base/command_line.h"
6 #include "base/strings/string_util.h"
7 #include "base/strings/stringprintf.h"
8 #include "base/values.h"
9 #include "chrome/browser/chrome_notification_types.h"
10 #include "chrome/browser/extensions/api/identity/identity_api.h"
11 #include "chrome/browser/extensions/component_loader.h"
12 #include "chrome/browser/extensions/extension_apitest.h"
13 #include "chrome/browser/extensions/extension_browsertest.h"
14 #include "chrome/browser/extensions/extension_function_test_utils.h"
15 #include "chrome/browser/extensions/extension_service.h"
16 #include "chrome/browser/profiles/profile.h"
17 #include "chrome/browser/signin/signin_manager.h"
18 #include "chrome/browser/signin/signin_manager_factory.h"
19 #include "chrome/browser/ui/browser.h"
20 #include "chrome/browser/ui/browser_window.h"
21 #include "chrome/common/chrome_switches.h"
22 #include "chrome/common/extensions/api/identity/oauth2_manifest_handler.h"
23 #include "chrome/test/base/in_process_browser_test.h"
24 #include "chrome/test/base/test_switches.h"
25 #include "content/public/browser/notification_service.h"
26 #include "content/public/browser/notification_source.h"
27 #include "content/public/test/test_utils.h"
28 #include "extensions/common/id_util.h"
29 #include "google_apis/gaia/google_service_auth_error.h"
30 #include "google_apis/gaia/oauth2_mint_token_flow.h"
31 #include "grit/browser_resources.h"
32 #include "net/test/spawned_test_server/spawned_test_server.h"
33 #include "testing/gmock/include/gmock/gmock.h"
34 #include "testing/gtest/include/gtest/gtest.h"
38 using testing::Return;
39 using testing::ReturnRef;
41 namespace extensions {
45 namespace errors = identity_constants;
46 namespace utils = extension_function_test_utils;
48 static const char kAccessToken[] = "auth_token";
49 static const char kExtensionId[] = "ext_id";
51 // This helps us be able to wait until an AsyncExtensionFunction calls
53 class SendResponseDelegate
54 : public UIThreadExtensionFunction::DelegateForTests {
56 SendResponseDelegate() : should_post_quit_(false) {}
58 virtual ~SendResponseDelegate() {}
60 void set_should_post_quit(bool should_quit) {
61 should_post_quit_ = should_quit;
65 return response_.get() != NULL;
69 EXPECT_TRUE(HasResponse());
70 return *response_.get();
73 virtual void OnSendResponse(UIThreadExtensionFunction* function,
75 bool bad_message) OVERRIDE {
76 ASSERT_FALSE(bad_message);
77 ASSERT_FALSE(HasResponse());
78 response_.reset(new bool);
80 if (should_post_quit_) {
81 base::MessageLoopForUI::current()->Quit();
86 scoped_ptr<bool> response_;
87 bool should_post_quit_;
90 class AsyncExtensionBrowserTest : public ExtensionBrowserTest {
92 // Asynchronous function runner allows tests to manipulate the browser window
93 // after the call happens.
94 void RunFunctionAsync(
95 UIThreadExtensionFunction* function,
96 const std::string& args) {
97 response_delegate_.reset(new SendResponseDelegate);
98 function->set_test_delegate(response_delegate_.get());
99 scoped_ptr<base::ListValue> parsed_args(utils::ParseList(args));
100 EXPECT_TRUE(parsed_args.get()) <<
101 "Could not parse extension function arguments: " << args;
102 function->SetArgs(parsed_args.get());
104 if (!function->GetExtension()) {
105 scoped_refptr<Extension> empty_extension(
106 utils::CreateEmptyExtension());
107 function->set_extension(empty_extension.get());
110 function->set_context(browser()->profile());
111 function->set_has_callback(true);
115 std::string WaitForError(UIThreadExtensionFunction* function) {
116 RunMessageLoopUntilResponse();
117 EXPECT_FALSE(function->GetResultList()) << "Did not expect a result";
118 return function->GetError();
121 base::Value* WaitForSingleResult(UIThreadExtensionFunction* function) {
122 RunMessageLoopUntilResponse();
123 EXPECT_TRUE(function->GetError().empty()) << "Unexpected error: "
124 << function->GetError();
125 const base::Value* single_result = NULL;
126 if (function->GetResultList() != NULL &&
127 function->GetResultList()->Get(0, &single_result)) {
128 return single_result->DeepCopy();
134 void RunMessageLoopUntilResponse() {
135 // If the RunImpl of |function| didn't already call SendResponse, run the
136 // message loop until they do.
137 if (!response_delegate_->HasResponse()) {
138 response_delegate_->set_should_post_quit(true);
139 content::RunMessageLoop();
141 EXPECT_TRUE(response_delegate_->HasResponse());
144 scoped_ptr<SendResponseDelegate> response_delegate_;
147 class TestOAuth2MintTokenFlow : public OAuth2MintTokenFlow {
150 ISSUE_ADVICE_SUCCESS,
153 MINT_TOKEN_BAD_CREDENTIALS
156 TestOAuth2MintTokenFlow(ResultType result,
157 OAuth2MintTokenFlow::Delegate* delegate)
158 : OAuth2MintTokenFlow(NULL, delegate, OAuth2MintTokenFlow::Parameters()),
160 delegate_(delegate) {
163 virtual void Start() OVERRIDE {
165 case ISSUE_ADVICE_SUCCESS: {
166 IssueAdviceInfo info;
167 delegate_->OnIssueAdviceSuccess(info);
170 case MINT_TOKEN_SUCCESS: {
171 delegate_->OnMintTokenSuccess(kAccessToken, 3600);
174 case MINT_TOKEN_FAILURE: {
175 GoogleServiceAuthError error(GoogleServiceAuthError::CONNECTION_FAILED);
176 delegate_->OnMintTokenFailure(error);
179 case MINT_TOKEN_BAD_CREDENTIALS: {
180 GoogleServiceAuthError error(
181 GoogleServiceAuthError::INVALID_GAIA_CREDENTIALS);
182 delegate_->OnMintTokenFailure(error);
190 OAuth2MintTokenFlow::Delegate* delegate_;
193 // Waits for a specific GURL to generate a NOTIFICATION_LOAD_STOP event and
194 // saves a pointer to the window embedding the WebContents, which can be later
196 class WaitForGURLAndCloseWindow : public content::WindowedNotificationObserver {
198 explicit WaitForGURLAndCloseWindow(GURL url)
199 : WindowedNotificationObserver(
200 content::NOTIFICATION_LOAD_STOP,
201 content::NotificationService::AllSources()),
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();
213 if (web_contents->GetURL() == url_) {
214 // It is safe to keep the pointer here, because we know in a test, that
215 // the WebContents won't go away before CloseEmbedderWebContents is
216 // called. Don't copy this code to production.
217 embedder_web_contents_ = web_contents->GetEmbedderWebContents();
218 // Condtionally invoke parent class so that Wait will not exit
219 // until the target URL arrives.
220 content::WindowedNotificationObserver::Observe(type, source, details);
224 // Closes the window embedding the WebContents. The action is separated from
225 // the Observe method to make sure the list of observers is not deleted,
226 // while some event is already being processed. (That causes ASAN failures.)
227 void CloseEmbedderWebContents() {
228 if (embedder_web_contents_)
229 embedder_web_contents_->Close();
234 content::WebContents* embedder_web_contents_;
239 class MockGetAuthTokenFunction : public IdentityGetAuthTokenFunction {
241 MockGetAuthTokenFunction() : login_access_token_result_(true),
242 login_ui_result_(true),
243 scope_ui_result_(true),
244 login_ui_shown_(false),
245 scope_ui_shown_(false) {
248 void set_login_access_token_result(bool result) {
249 login_access_token_result_ = result;
252 void set_login_ui_result(bool result) {
253 login_ui_result_ = result;
256 void set_scope_ui_failure(GaiaWebAuthFlow::Failure failure) {
257 scope_ui_result_ = false;
258 scope_ui_failure_ = failure;
261 void set_scope_ui_oauth_error(const std::string& oauth_error) {
262 scope_ui_result_ = false;
263 scope_ui_failure_ = GaiaWebAuthFlow::OAUTH_ERROR;
264 scope_ui_oauth_error_ = oauth_error;
267 bool login_ui_shown() const {
268 return login_ui_shown_;
271 bool scope_ui_shown() const {
272 return scope_ui_shown_;
275 virtual void StartLoginAccessTokenRequest() OVERRIDE {
276 if (login_access_token_result_) {
277 OnGetTokenSuccess(login_token_request_.get(), "access_token",
278 base::Time::Now() + base::TimeDelta::FromHours(1LL));
280 GoogleServiceAuthError error(
281 GoogleServiceAuthError::INVALID_GAIA_CREDENTIALS);
282 OnGetTokenFailure(login_token_request_.get(), error);
286 virtual void ShowLoginPopup() OVERRIDE {
287 EXPECT_FALSE(login_ui_shown_);
288 login_ui_shown_ = true;
289 if (login_ui_result_)
295 virtual void ShowOAuthApprovalDialog(
296 const IssueAdviceInfo& issue_advice) OVERRIDE {
297 scope_ui_shown_ = true;
299 if (scope_ui_result_) {
300 OnGaiaFlowCompleted(kAccessToken, "3600");
301 } else if (scope_ui_failure_ == GaiaWebAuthFlow::SERVICE_AUTH_ERROR) {
302 GoogleServiceAuthError error(GoogleServiceAuthError::CONNECTION_FAILED);
303 OnGaiaFlowFailure(scope_ui_failure_, error, "");
305 GoogleServiceAuthError error(GoogleServiceAuthError::NONE);
306 OnGaiaFlowFailure(scope_ui_failure_, error, scope_ui_oauth_error_);
310 MOCK_CONST_METHOD0(HasLoginToken, bool());
311 MOCK_METHOD1(CreateMintTokenFlow,
312 OAuth2MintTokenFlow* (const std::string& login_access_token));
315 ~MockGetAuthTokenFunction() {}
316 bool login_access_token_result_;
317 bool login_ui_result_;
318 bool scope_ui_result_;
319 GaiaWebAuthFlow::Failure scope_ui_failure_;
320 std::string scope_ui_oauth_error_;
321 bool login_ui_shown_;
322 bool scope_ui_shown_;
325 class MockQueuedMintRequest : public IdentityMintRequestQueue::Request {
327 MOCK_METHOD1(StartMintToken, void(IdentityMintRequestQueue::MintType));
330 class GetAuthTokenFunctionTest : public AsyncExtensionBrowserTest {
339 virtual ~GetAuthTokenFunctionTest() {}
341 // Helper to create an extension with specific OAuth2Info fields set.
342 // |fields_to_set| should be computed by using fields of Oauth2Fields enum.
343 const Extension* CreateExtension(int fields_to_set) {
344 const Extension* ext;
345 base::FilePath manifest_path =
346 test_data_dir_.AppendASCII("platform_apps/oauth2");
347 base::FilePath component_manifest_path =
348 test_data_dir_.AppendASCII("packaged_app/component_oauth2");
349 if ((fields_to_set & AS_COMPONENT) == 0)
350 ext = LoadExtension(manifest_path);
352 ext = LoadExtensionAsComponent(component_manifest_path);
353 OAuth2Info& oauth2_info =
354 const_cast<OAuth2Info&>(OAuth2Info::GetOAuth2Info(ext));
355 if ((fields_to_set & CLIENT_ID) != 0)
356 oauth2_info.client_id = "client1";
357 if ((fields_to_set & SCOPES) != 0) {
358 oauth2_info.scopes.push_back("scope1");
359 oauth2_info.scopes.push_back("scope2");
362 extension_id_ = ext->id();
363 oauth_scopes_ = std::set<std::string>(oauth2_info.scopes.begin(),
364 oauth2_info.scopes.end());
368 IdentityAPI* id_api() {
369 return IdentityAPI::GetFactoryInstance()->GetForProfile(
370 browser()->profile());
373 const std::string GetPrimaryAccountId() {
374 SigninManagerBase* signin_manager =
375 SigninManagerFactory::GetForProfile(browser()->profile());
376 return signin_manager->GetAuthenticatedAccountId();
379 void SetCachedToken(const IdentityTokenCacheValue& token_data) {
380 ExtensionTokenKey key(extension_id_, GetPrimaryAccountId(), oauth_scopes_);
381 id_api()->SetCachedToken(key, token_data);
384 const IdentityTokenCacheValue& GetCachedToken() {
385 ExtensionTokenKey key(extension_id_, GetPrimaryAccountId(), oauth_scopes_);
386 return id_api()->GetCachedToken(key);
389 void QueueRequestStart(IdentityMintRequestQueue::MintType type,
390 IdentityMintRequestQueue::Request* request) {
391 ExtensionTokenKey key(extension_id_, GetPrimaryAccountId(), oauth_scopes_);
392 id_api()->mint_queue()->RequestStart(type, key, request);
395 void QueueRequestComplete(IdentityMintRequestQueue::MintType type,
396 IdentityMintRequestQueue::Request* request) {
397 ExtensionTokenKey key(extension_id_, GetPrimaryAccountId(), oauth_scopes_);
398 id_api()->mint_queue()->RequestComplete(type, key, request);
402 std::string extension_id_;
403 std::set<std::string> oauth_scopes_;
406 IN_PROC_BROWSER_TEST_F(GetAuthTokenFunctionTest,
408 scoped_refptr<MockGetAuthTokenFunction> func(new MockGetAuthTokenFunction());
409 func->set_extension(CreateExtension(SCOPES));
410 std::string error = utils::RunFunctionAndReturnError(
411 func.get(), "[{}]", browser());
412 EXPECT_EQ(std::string(errors::kInvalidClientId), error);
413 EXPECT_FALSE(func->login_ui_shown());
414 EXPECT_FALSE(func->scope_ui_shown());
417 IN_PROC_BROWSER_TEST_F(GetAuthTokenFunctionTest,
419 scoped_refptr<MockGetAuthTokenFunction> func(new MockGetAuthTokenFunction());
420 func->set_extension(CreateExtension(CLIENT_ID));
421 std::string error = utils::RunFunctionAndReturnError(
422 func.get(), "[{}]", browser());
423 EXPECT_EQ(std::string(errors::kInvalidScopes), error);
424 EXPECT_FALSE(func->login_ui_shown());
425 EXPECT_FALSE(func->scope_ui_shown());
428 IN_PROC_BROWSER_TEST_F(GetAuthTokenFunctionTest,
429 NonInteractiveNotSignedIn) {
430 scoped_refptr<MockGetAuthTokenFunction> func(new MockGetAuthTokenFunction());
431 func->set_extension(CreateExtension(CLIENT_ID | SCOPES));
432 EXPECT_CALL(*func.get(), HasLoginToken()).WillOnce(Return(false));
433 std::string error = utils::RunFunctionAndReturnError(
434 func.get(), "[{}]", browser());
435 EXPECT_EQ(std::string(errors::kUserNotSignedIn), error);
436 EXPECT_FALSE(func->login_ui_shown());
437 EXPECT_FALSE(func->scope_ui_shown());
440 IN_PROC_BROWSER_TEST_F(GetAuthTokenFunctionTest,
441 NonInteractiveMintFailure) {
442 scoped_refptr<MockGetAuthTokenFunction> func(new MockGetAuthTokenFunction());
443 func->set_extension(CreateExtension(CLIENT_ID | SCOPES));
444 EXPECT_CALL(*func.get(), HasLoginToken())
445 .WillOnce(Return(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(), "[{}]", browser());
451 EXPECT_TRUE(StartsWithASCII(error, errors::kAuthFailure, false));
452 EXPECT_FALSE(func->login_ui_shown());
453 EXPECT_FALSE(func->scope_ui_shown());
456 IN_PROC_BROWSER_TEST_F(GetAuthTokenFunctionTest,
457 NonInteractiveLoginAccessTokenFailure) {
458 scoped_refptr<MockGetAuthTokenFunction> func(new MockGetAuthTokenFunction());
459 func->set_extension(CreateExtension(CLIENT_ID | SCOPES));
460 EXPECT_CALL(*func.get(), HasLoginToken())
461 .WillOnce(Return(true));
462 func->set_login_access_token_result(false);
463 std::string error = utils::RunFunctionAndReturnError(
464 func.get(), "[{}]", browser());
465 EXPECT_TRUE(StartsWithASCII(error, errors::kAuthFailure, false));
468 IN_PROC_BROWSER_TEST_F(GetAuthTokenFunctionTest,
469 NonInteractiveMintAdviceSuccess) {
470 scoped_refptr<const Extension> extension(CreateExtension(CLIENT_ID | SCOPES));
471 scoped_refptr<MockGetAuthTokenFunction> func(new MockGetAuthTokenFunction());
472 func->set_extension(extension.get());
473 EXPECT_CALL(*func.get(), HasLoginToken()).WillOnce(Return(true));
474 TestOAuth2MintTokenFlow* flow = new TestOAuth2MintTokenFlow(
475 TestOAuth2MintTokenFlow::ISSUE_ADVICE_SUCCESS, func.get());
476 EXPECT_CALL(*func.get(), CreateMintTokenFlow(_)).WillOnce(Return(flow));
477 std::string error = utils::RunFunctionAndReturnError(
478 func.get(), "[{}]", browser());
479 EXPECT_EQ(std::string(errors::kNoGrant), error);
480 EXPECT_FALSE(func->login_ui_shown());
481 EXPECT_FALSE(func->scope_ui_shown());
483 EXPECT_EQ(IdentityTokenCacheValue::CACHE_STATUS_ADVICE,
484 GetCachedToken().status());
487 IN_PROC_BROWSER_TEST_F(GetAuthTokenFunctionTest,
488 NonInteractiveMintBadCredentials) {
489 scoped_refptr<MockGetAuthTokenFunction> func(new MockGetAuthTokenFunction());
490 func->set_extension(CreateExtension(CLIENT_ID | SCOPES));
491 EXPECT_CALL(*func.get(), HasLoginToken())
492 .WillOnce(Return(true));
493 TestOAuth2MintTokenFlow* flow = new TestOAuth2MintTokenFlow(
494 TestOAuth2MintTokenFlow::MINT_TOKEN_BAD_CREDENTIALS, func.get());
495 EXPECT_CALL(*func.get(), CreateMintTokenFlow(_)).WillOnce(Return(flow));
496 std::string error = utils::RunFunctionAndReturnError(
497 func.get(), "[{}]", browser());
498 EXPECT_TRUE(StartsWithASCII(error, errors::kAuthFailure, false));
499 EXPECT_FALSE(func->login_ui_shown());
500 EXPECT_FALSE(func->scope_ui_shown());
503 IN_PROC_BROWSER_TEST_F(GetAuthTokenFunctionTest,
504 NonInteractiveSuccess) {
505 #if defined(OS_WIN) && defined(USE_ASH)
506 // Disable this test in Metro+Ash for now (http://crbug.com/262796).
507 if (CommandLine::ForCurrentProcess()->HasSwitch(switches::kAshBrowserTests))
511 scoped_refptr<MockGetAuthTokenFunction> func(new MockGetAuthTokenFunction());
512 scoped_refptr<const Extension> extension(CreateExtension(CLIENT_ID | SCOPES));
513 func->set_extension(extension.get());
514 EXPECT_CALL(*func.get(), HasLoginToken()).WillOnce(Return(true));
515 TestOAuth2MintTokenFlow* flow = new TestOAuth2MintTokenFlow(
516 TestOAuth2MintTokenFlow::MINT_TOKEN_SUCCESS, func.get());
517 EXPECT_CALL(*func.get(), CreateMintTokenFlow(_)).WillOnce(Return(flow));
518 scoped_ptr<base::Value> value(utils::RunFunctionAndReturnSingleResult(
519 func.get(), "[{}]", browser()));
520 std::string access_token;
521 EXPECT_TRUE(value->GetAsString(&access_token));
522 EXPECT_EQ(std::string(kAccessToken), access_token);
523 EXPECT_FALSE(func->login_ui_shown());
524 EXPECT_FALSE(func->scope_ui_shown());
525 EXPECT_EQ(IdentityTokenCacheValue::CACHE_STATUS_TOKEN,
526 GetCachedToken().status());
529 IN_PROC_BROWSER_TEST_F(GetAuthTokenFunctionTest,
530 InteractiveLoginCanceled) {
531 scoped_refptr<MockGetAuthTokenFunction> func(new MockGetAuthTokenFunction());
532 func->set_extension(CreateExtension(CLIENT_ID | SCOPES));
533 EXPECT_CALL(*func.get(), HasLoginToken()).WillOnce(Return(false));
534 func->set_login_ui_result(false);
535 std::string error = utils::RunFunctionAndReturnError(
536 func.get(), "[{\"interactive\": true}]", browser());
537 EXPECT_EQ(std::string(errors::kUserNotSignedIn), error);
538 EXPECT_TRUE(func->login_ui_shown());
539 EXPECT_FALSE(func->scope_ui_shown());
542 IN_PROC_BROWSER_TEST_F(GetAuthTokenFunctionTest,
543 InteractiveMintBadCredentialsLoginCanceled) {
544 scoped_refptr<MockGetAuthTokenFunction> func(new MockGetAuthTokenFunction());
545 func->set_extension(CreateExtension(CLIENT_ID | SCOPES));
546 EXPECT_CALL(*func.get(), HasLoginToken())
547 .WillOnce(Return(true));
548 TestOAuth2MintTokenFlow* flow = new TestOAuth2MintTokenFlow(
549 TestOAuth2MintTokenFlow::MINT_TOKEN_BAD_CREDENTIALS, func.get());
550 EXPECT_CALL(*func.get(), CreateMintTokenFlow(_)).WillOnce(Return(flow));
551 func->set_login_ui_result(false);
552 std::string error = utils::RunFunctionAndReturnError(
553 func.get(), "[{\"interactive\": true}]", browser());
554 EXPECT_EQ(std::string(errors::kUserNotSignedIn), error);
555 EXPECT_TRUE(func->login_ui_shown());
556 EXPECT_FALSE(func->scope_ui_shown());
559 IN_PROC_BROWSER_TEST_F(GetAuthTokenFunctionTest,
560 InteractiveLoginSuccessNoToken) {
561 scoped_refptr<MockGetAuthTokenFunction> func(new MockGetAuthTokenFunction());
562 func->set_extension(CreateExtension(CLIENT_ID | SCOPES));
563 EXPECT_CALL(*func.get(), HasLoginToken()).WillOnce(Return(false));
564 func->set_login_ui_result(false);
565 std::string error = utils::RunFunctionAndReturnError(
566 func.get(), "[{\"interactive\": true}]", browser());
567 EXPECT_EQ(std::string(errors::kUserNotSignedIn), error);
568 EXPECT_TRUE(func->login_ui_shown());
569 EXPECT_FALSE(func->scope_ui_shown());
572 IN_PROC_BROWSER_TEST_F(GetAuthTokenFunctionTest,
573 InteractiveLoginSuccessMintFailure) {
574 scoped_refptr<MockGetAuthTokenFunction> func(new MockGetAuthTokenFunction());
575 func->set_extension(CreateExtension(CLIENT_ID | SCOPES));
576 EXPECT_CALL(*func.get(), HasLoginToken())
577 .WillOnce(Return(false));
578 func->set_login_ui_result(true);
579 TestOAuth2MintTokenFlow* flow = new TestOAuth2MintTokenFlow(
580 TestOAuth2MintTokenFlow::MINT_TOKEN_FAILURE, func.get());
581 EXPECT_CALL(*func.get(), CreateMintTokenFlow(_)).WillOnce(Return(flow));
582 std::string error = utils::RunFunctionAndReturnError(
583 func.get(), "[{\"interactive\": true}]", browser());
584 EXPECT_TRUE(StartsWithASCII(error, errors::kAuthFailure, false));
585 EXPECT_TRUE(func->login_ui_shown());
586 EXPECT_FALSE(func->scope_ui_shown());
589 IN_PROC_BROWSER_TEST_F(GetAuthTokenFunctionTest,
590 InteractiveLoginSuccessLoginAccessTokenFailure) {
591 scoped_refptr<MockGetAuthTokenFunction> func(new MockGetAuthTokenFunction());
592 func->set_extension(CreateExtension(CLIENT_ID | SCOPES));
593 EXPECT_CALL(*func.get(), HasLoginToken()).WillOnce(Return(false));
594 func->set_login_ui_result(true);
595 func->set_login_access_token_result(false);
596 std::string error = utils::RunFunctionAndReturnError(
597 func.get(), "[{\"interactive\": true}]", browser());
598 EXPECT_TRUE(StartsWithASCII(error, errors::kAuthFailure, false));
599 EXPECT_TRUE(func->login_ui_shown());
600 EXPECT_FALSE(func->scope_ui_shown());
603 IN_PROC_BROWSER_TEST_F(GetAuthTokenFunctionTest,
604 InteractiveLoginSuccessMintSuccess) {
605 scoped_refptr<MockGetAuthTokenFunction> func(new MockGetAuthTokenFunction());
606 func->set_extension(CreateExtension(CLIENT_ID | SCOPES));
607 EXPECT_CALL(*func.get(), HasLoginToken())
608 .WillOnce(Return(false));
609 func->set_login_ui_result(true);
610 TestOAuth2MintTokenFlow* flow = new TestOAuth2MintTokenFlow(
611 TestOAuth2MintTokenFlow::MINT_TOKEN_SUCCESS, func.get());
612 EXPECT_CALL(*func.get(), CreateMintTokenFlow(_)).WillOnce(Return(flow));
613 scoped_ptr<base::Value> value(utils::RunFunctionAndReturnSingleResult(
614 func.get(), "[{\"interactive\": true}]", browser()));
615 std::string access_token;
616 EXPECT_TRUE(value->GetAsString(&access_token));
617 EXPECT_EQ(std::string(kAccessToken), access_token);
618 EXPECT_TRUE(func->login_ui_shown());
619 EXPECT_FALSE(func->scope_ui_shown());
622 IN_PROC_BROWSER_TEST_F(GetAuthTokenFunctionTest,
623 InteractiveLoginSuccessApprovalAborted) {
624 scoped_refptr<MockGetAuthTokenFunction> func(new MockGetAuthTokenFunction());
625 func->set_extension(CreateExtension(CLIENT_ID | SCOPES));
626 EXPECT_CALL(*func.get(), HasLoginToken())
627 .WillOnce(Return(false));
628 func->set_login_ui_result(true);
629 TestOAuth2MintTokenFlow* flow = new TestOAuth2MintTokenFlow(
630 TestOAuth2MintTokenFlow::ISSUE_ADVICE_SUCCESS, func.get());
631 EXPECT_CALL(*func.get(), CreateMintTokenFlow(_)).WillOnce(Return(flow));
632 func->set_scope_ui_failure(GaiaWebAuthFlow::WINDOW_CLOSED);
633 std::string error = utils::RunFunctionAndReturnError(
634 func.get(), "[{\"interactive\": true}]", browser());
635 EXPECT_EQ(std::string(errors::kUserRejected), error);
636 EXPECT_TRUE(func->login_ui_shown());
637 EXPECT_TRUE(func->scope_ui_shown());
640 IN_PROC_BROWSER_TEST_F(GetAuthTokenFunctionTest,
641 InteractiveLoginSuccessApprovalSuccess) {
642 scoped_refptr<const Extension> extension(CreateExtension(CLIENT_ID | SCOPES));
643 scoped_refptr<MockGetAuthTokenFunction> func(new MockGetAuthTokenFunction());
644 func->set_extension(extension.get());
645 EXPECT_CALL(*func.get(), HasLoginToken()).WillOnce(Return(false));
646 func->set_login_ui_result(true);
647 TestOAuth2MintTokenFlow* flow = new TestOAuth2MintTokenFlow(
648 TestOAuth2MintTokenFlow::ISSUE_ADVICE_SUCCESS, func.get());
649 EXPECT_CALL(*func.get(), CreateMintTokenFlow(_))
650 .WillOnce(Return(flow));
652 scoped_ptr<base::Value> value(utils::RunFunctionAndReturnSingleResult(
653 func.get(), "[{\"interactive\": true}]", browser()));
654 std::string access_token;
655 EXPECT_TRUE(value->GetAsString(&access_token));
656 EXPECT_EQ(std::string(kAccessToken), access_token);
657 EXPECT_TRUE(func->login_ui_shown());
658 EXPECT_TRUE(func->scope_ui_shown());
661 IN_PROC_BROWSER_TEST_F(GetAuthTokenFunctionTest,
662 InteractiveApprovalAborted) {
663 scoped_refptr<MockGetAuthTokenFunction> func(new MockGetAuthTokenFunction());
664 func->set_extension(CreateExtension(CLIENT_ID | SCOPES));
665 EXPECT_CALL(*func.get(), HasLoginToken())
666 .WillOnce(Return(true));
667 TestOAuth2MintTokenFlow* flow = new TestOAuth2MintTokenFlow(
668 TestOAuth2MintTokenFlow::ISSUE_ADVICE_SUCCESS, func.get());
669 EXPECT_CALL(*func.get(), CreateMintTokenFlow(_)).WillOnce(Return(flow));
670 func->set_scope_ui_failure(GaiaWebAuthFlow::WINDOW_CLOSED);
671 std::string error = utils::RunFunctionAndReturnError(
672 func.get(), "[{\"interactive\": true}]", browser());
673 EXPECT_EQ(std::string(errors::kUserRejected), error);
674 EXPECT_FALSE(func->login_ui_shown());
675 EXPECT_TRUE(func->scope_ui_shown());
678 IN_PROC_BROWSER_TEST_F(GetAuthTokenFunctionTest,
679 InteractiveApprovalLoadFailed) {
680 scoped_refptr<MockGetAuthTokenFunction> func(new MockGetAuthTokenFunction());
681 func->set_extension(CreateExtension(CLIENT_ID | SCOPES));
682 EXPECT_CALL(*func.get(), HasLoginToken())
683 .WillOnce(Return(true));
684 TestOAuth2MintTokenFlow* flow = new TestOAuth2MintTokenFlow(
685 TestOAuth2MintTokenFlow::ISSUE_ADVICE_SUCCESS, func.get());
686 EXPECT_CALL(*func.get(), CreateMintTokenFlow(_)).WillOnce(Return(flow));
687 func->set_scope_ui_failure(GaiaWebAuthFlow::LOAD_FAILED);
688 std::string error = utils::RunFunctionAndReturnError(
689 func.get(), "[{\"interactive\": true}]", browser());
690 EXPECT_EQ(std::string(errors::kPageLoadFailure), error);
691 EXPECT_FALSE(func->login_ui_shown());
692 EXPECT_TRUE(func->scope_ui_shown());
695 IN_PROC_BROWSER_TEST_F(GetAuthTokenFunctionTest,
696 InteractiveApprovalInvalidRedirect) {
697 scoped_refptr<MockGetAuthTokenFunction> func(new MockGetAuthTokenFunction());
698 func->set_extension(CreateExtension(CLIENT_ID | SCOPES));
699 EXPECT_CALL(*func.get(), HasLoginToken())
700 .WillOnce(Return(true));
701 TestOAuth2MintTokenFlow* flow = new TestOAuth2MintTokenFlow(
702 TestOAuth2MintTokenFlow::ISSUE_ADVICE_SUCCESS, func.get());
703 EXPECT_CALL(*func.get(), CreateMintTokenFlow(_)).WillOnce(Return(flow));
704 func->set_scope_ui_failure(GaiaWebAuthFlow::INVALID_REDIRECT);
705 std::string error = utils::RunFunctionAndReturnError(
706 func.get(), "[{\"interactive\": true}]", browser());
707 EXPECT_EQ(std::string(errors::kInvalidRedirect), error);
708 EXPECT_FALSE(func->login_ui_shown());
709 EXPECT_TRUE(func->scope_ui_shown());
712 IN_PROC_BROWSER_TEST_F(GetAuthTokenFunctionTest,
713 InteractiveApprovalConnectionFailure) {
714 scoped_refptr<MockGetAuthTokenFunction> func(new MockGetAuthTokenFunction());
715 func->set_extension(CreateExtension(CLIENT_ID | SCOPES));
716 EXPECT_CALL(*func.get(), HasLoginToken())
717 .WillOnce(Return(true));
718 TestOAuth2MintTokenFlow* flow = new TestOAuth2MintTokenFlow(
719 TestOAuth2MintTokenFlow::ISSUE_ADVICE_SUCCESS, func.get());
720 EXPECT_CALL(*func.get(), CreateMintTokenFlow(_)).WillOnce(Return(flow));
721 func->set_scope_ui_failure(GaiaWebAuthFlow::SERVICE_AUTH_ERROR);
722 std::string error = utils::RunFunctionAndReturnError(
723 func.get(), "[{\"interactive\": true}]", browser());
724 EXPECT_TRUE(StartsWithASCII(error, errors::kAuthFailure, false));
725 EXPECT_FALSE(func->login_ui_shown());
726 EXPECT_TRUE(func->scope_ui_shown());
729 IN_PROC_BROWSER_TEST_F(GetAuthTokenFunctionTest,
730 InteractiveApprovalOAuthErrors) {
731 scoped_refptr<const Extension> extension(CreateExtension(CLIENT_ID | SCOPES));
733 std::map<std::string, std::string> error_map;
734 error_map.insert(std::make_pair("access_denied", errors::kUserRejected));
735 error_map.insert(std::make_pair("invalid_scope", errors::kInvalidScopes));
736 error_map.insert(std::make_pair(
737 "unmapped_error", std::string(errors::kAuthFailure) + "unmapped_error"));
739 for (std::map<std::string, std::string>::const_iterator
740 it = error_map.begin();
741 it != error_map.end();
743 scoped_refptr<MockGetAuthTokenFunction> func(
744 new MockGetAuthTokenFunction());
745 func->set_extension(extension.get());
746 EXPECT_CALL(*func.get(), HasLoginToken()).WillOnce(Return(true));
747 // Make sure we don't get a cached issue_advice result, which would cause
748 // flow to be leaked.
749 id_api()->EraseAllCachedTokens();
750 TestOAuth2MintTokenFlow* flow = new TestOAuth2MintTokenFlow(
751 TestOAuth2MintTokenFlow::ISSUE_ADVICE_SUCCESS, func.get());
752 EXPECT_CALL(*func.get(), CreateMintTokenFlow(_)).WillOnce(Return(flow));
753 func->set_scope_ui_oauth_error(it->first);
754 std::string error = utils::RunFunctionAndReturnError(
755 func.get(), "[{\"interactive\": true}]", browser());
756 EXPECT_EQ(it->second, error);
757 EXPECT_FALSE(func->login_ui_shown());
758 EXPECT_TRUE(func->scope_ui_shown());
762 IN_PROC_BROWSER_TEST_F(GetAuthTokenFunctionTest,
763 InteractiveApprovalSuccess) {
764 scoped_refptr<const Extension> extension(CreateExtension(CLIENT_ID | SCOPES));
765 scoped_refptr<MockGetAuthTokenFunction> func(new MockGetAuthTokenFunction());
766 func->set_extension(extension.get());
767 EXPECT_CALL(*func.get(), HasLoginToken()).WillOnce(Return(true));
768 TestOAuth2MintTokenFlow* flow = new TestOAuth2MintTokenFlow(
769 TestOAuth2MintTokenFlow::ISSUE_ADVICE_SUCCESS, func.get());
770 EXPECT_CALL(*func.get(), CreateMintTokenFlow(_))
771 .WillOnce(Return(flow));
773 scoped_ptr<base::Value> value(utils::RunFunctionAndReturnSingleResult(
774 func.get(), "[{\"interactive\": true}]", browser()));
775 std::string access_token;
776 EXPECT_TRUE(value->GetAsString(&access_token));
777 EXPECT_EQ(std::string(kAccessToken), access_token);
778 EXPECT_FALSE(func->login_ui_shown());
779 EXPECT_TRUE(func->scope_ui_shown());
781 EXPECT_EQ(IdentityTokenCacheValue::CACHE_STATUS_TOKEN,
782 GetCachedToken().status());
785 IN_PROC_BROWSER_TEST_F(GetAuthTokenFunctionTest, NoninteractiveQueue) {
786 scoped_refptr<const Extension> extension(CreateExtension(CLIENT_ID | SCOPES));
787 scoped_refptr<MockGetAuthTokenFunction> func(new MockGetAuthTokenFunction());
788 func->set_extension(extension.get());
790 // Create a fake request to block the queue.
791 MockQueuedMintRequest queued_request;
792 IdentityMintRequestQueue::MintType type =
793 IdentityMintRequestQueue::MINT_TYPE_NONINTERACTIVE;
795 EXPECT_CALL(queued_request, StartMintToken(type)).Times(1);
796 QueueRequestStart(type, &queued_request);
798 // The real request will start processing, but wait in the queue behind
800 EXPECT_CALL(*func.get(), HasLoginToken()).WillOnce(Return(true));
801 RunFunctionAsync(func.get(), "[{}]");
802 // Verify that we have fetched the login token at this point.
803 testing::Mock::VerifyAndClearExpectations(func.get());
805 // The flow will be created after the first queued request clears.
806 TestOAuth2MintTokenFlow* flow = new TestOAuth2MintTokenFlow(
807 TestOAuth2MintTokenFlow::MINT_TOKEN_SUCCESS, func.get());
808 EXPECT_CALL(*func.get(), CreateMintTokenFlow(_)).WillOnce(Return(flow));
810 QueueRequestComplete(type, &queued_request);
812 scoped_ptr<base::Value> value(WaitForSingleResult(func.get()));
813 std::string access_token;
814 EXPECT_TRUE(value->GetAsString(&access_token));
815 EXPECT_EQ(std::string(kAccessToken), access_token);
816 EXPECT_FALSE(func->login_ui_shown());
817 EXPECT_FALSE(func->scope_ui_shown());
820 IN_PROC_BROWSER_TEST_F(GetAuthTokenFunctionTest, InteractiveQueue) {
821 scoped_refptr<const Extension> extension(CreateExtension(CLIENT_ID | SCOPES));
822 scoped_refptr<MockGetAuthTokenFunction> func(new MockGetAuthTokenFunction());
823 func->set_extension(extension.get());
825 // Create a fake request to block the queue.
826 MockQueuedMintRequest queued_request;
827 IdentityMintRequestQueue::MintType type =
828 IdentityMintRequestQueue::MINT_TYPE_INTERACTIVE;
830 EXPECT_CALL(queued_request, StartMintToken(type)).Times(1);
831 QueueRequestStart(type, &queued_request);
833 // The real request will start processing, but wait in the queue behind
835 EXPECT_CALL(*func.get(), HasLoginToken()).WillOnce(Return(true));
836 TestOAuth2MintTokenFlow* flow1 = new TestOAuth2MintTokenFlow(
837 TestOAuth2MintTokenFlow::ISSUE_ADVICE_SUCCESS, func.get());
838 EXPECT_CALL(*func.get(), CreateMintTokenFlow(_)).WillOnce(Return(flow1));
839 RunFunctionAsync(func.get(), "[{\"interactive\": true}]");
840 // Verify that we have fetched the login token and run the first flow.
841 testing::Mock::VerifyAndClearExpectations(func.get());
842 EXPECT_FALSE(func->scope_ui_shown());
844 // The UI will be displayed and a token retrieved after the first
845 // queued request clears.
846 QueueRequestComplete(type, &queued_request);
848 scoped_ptr<base::Value> value(WaitForSingleResult(func.get()));
849 std::string access_token;
850 EXPECT_TRUE(value->GetAsString(&access_token));
851 EXPECT_EQ(std::string(kAccessToken), access_token);
852 EXPECT_FALSE(func->login_ui_shown());
853 EXPECT_TRUE(func->scope_ui_shown());
856 IN_PROC_BROWSER_TEST_F(GetAuthTokenFunctionTest,
857 InteractiveQueuedNoninteractiveFails) {
858 scoped_refptr<const Extension> extension(CreateExtension(CLIENT_ID | SCOPES));
859 scoped_refptr<MockGetAuthTokenFunction> func(new MockGetAuthTokenFunction());
860 func->set_extension(extension.get());
862 // Create a fake request to block the interactive queue.
863 MockQueuedMintRequest queued_request;
864 IdentityMintRequestQueue::MintType type =
865 IdentityMintRequestQueue::MINT_TYPE_INTERACTIVE;
867 EXPECT_CALL(queued_request, StartMintToken(type)).Times(1);
868 QueueRequestStart(type, &queued_request);
870 // Non-interactive requests fail without hitting GAIA, because a
871 // consent UI is known to be up.
872 EXPECT_CALL(*func.get(), HasLoginToken()).WillOnce(Return(true));
873 std::string error = utils::RunFunctionAndReturnError(
874 func.get(), "[{}]", browser());
875 EXPECT_EQ(std::string(errors::kNoGrant), error);
876 EXPECT_FALSE(func->login_ui_shown());
877 EXPECT_FALSE(func->scope_ui_shown());
879 QueueRequestComplete(type, &queued_request);
882 IN_PROC_BROWSER_TEST_F(GetAuthTokenFunctionTest,
883 NonInteractiveCacheHit) {
884 scoped_refptr<const Extension> extension(CreateExtension(CLIENT_ID | SCOPES));
885 scoped_refptr<MockGetAuthTokenFunction> func(new MockGetAuthTokenFunction());
886 func->set_extension(extension.get());
888 // pre-populate the cache with a token
889 IdentityTokenCacheValue token(kAccessToken,
890 base::TimeDelta::FromSeconds(3600));
891 SetCachedToken(token);
893 // Get a token. Should not require a GAIA request.
894 EXPECT_CALL(*func.get(), HasLoginToken())
895 .WillOnce(Return(true));
896 scoped_ptr<base::Value> value(utils::RunFunctionAndReturnSingleResult(
897 func.get(), "[{}]", browser()));
898 std::string access_token;
899 EXPECT_TRUE(value->GetAsString(&access_token));
900 EXPECT_EQ(std::string(kAccessToken), access_token);
901 EXPECT_FALSE(func->login_ui_shown());
902 EXPECT_FALSE(func->scope_ui_shown());
905 IN_PROC_BROWSER_TEST_F(GetAuthTokenFunctionTest,
906 NonInteractiveIssueAdviceCacheHit) {
907 scoped_refptr<const Extension> extension(CreateExtension(CLIENT_ID | SCOPES));
908 scoped_refptr<MockGetAuthTokenFunction> func(new MockGetAuthTokenFunction());
909 func->set_extension(extension.get());
911 // pre-populate the cache with advice
912 IssueAdviceInfo info;
913 IdentityTokenCacheValue token(info);
914 SetCachedToken(token);
916 // Should return an error without a GAIA request.
917 EXPECT_CALL(*func.get(), HasLoginToken())
918 .WillOnce(Return(true));
919 std::string error = utils::RunFunctionAndReturnError(
920 func.get(), "[{}]", browser());
921 EXPECT_EQ(std::string(errors::kNoGrant), error);
922 EXPECT_FALSE(func->login_ui_shown());
923 EXPECT_FALSE(func->scope_ui_shown());
926 IN_PROC_BROWSER_TEST_F(GetAuthTokenFunctionTest,
927 InteractiveCacheHit) {
928 scoped_refptr<const Extension> extension(CreateExtension(CLIENT_ID | SCOPES));
929 scoped_refptr<MockGetAuthTokenFunction> func(new MockGetAuthTokenFunction());
930 func->set_extension(extension.get());
932 // Create a fake request to block the queue.
933 MockQueuedMintRequest queued_request;
934 IdentityMintRequestQueue::MintType type =
935 IdentityMintRequestQueue::MINT_TYPE_INTERACTIVE;
937 EXPECT_CALL(queued_request, StartMintToken(type)).Times(1);
938 QueueRequestStart(type, &queued_request);
940 // The real request will start processing, but wait in the queue behind
942 EXPECT_CALL(*func.get(), HasLoginToken()).WillOnce(Return(true));
943 TestOAuth2MintTokenFlow* flow = new TestOAuth2MintTokenFlow(
944 TestOAuth2MintTokenFlow::ISSUE_ADVICE_SUCCESS, func.get());
945 EXPECT_CALL(*func.get(), CreateMintTokenFlow(_)).WillOnce(Return(flow));
946 RunFunctionAsync(func.get(), "[{\"interactive\": true}]");
948 // Populate the cache with a token while the request is blocked.
949 IdentityTokenCacheValue token(kAccessToken,
950 base::TimeDelta::FromSeconds(3600));
951 SetCachedToken(token);
953 // When we wake up the request, it returns the cached token without
954 // displaying a UI, or hitting GAIA.
956 QueueRequestComplete(type, &queued_request);
958 scoped_ptr<base::Value> value(WaitForSingleResult(func.get()));
959 std::string access_token;
960 EXPECT_TRUE(value->GetAsString(&access_token));
961 EXPECT_EQ(std::string(kAccessToken), access_token);
962 EXPECT_FALSE(func->login_ui_shown());
963 EXPECT_FALSE(func->scope_ui_shown());
966 IN_PROC_BROWSER_TEST_F(GetAuthTokenFunctionTest,
967 LoginInvalidatesTokenCache) {
968 scoped_refptr<MockGetAuthTokenFunction> func(new MockGetAuthTokenFunction());
969 scoped_refptr<const Extension> extension(CreateExtension(CLIENT_ID | SCOPES));
970 func->set_extension(extension.get());
972 // pre-populate the cache with a token
973 IdentityTokenCacheValue token(kAccessToken,
974 base::TimeDelta::FromSeconds(3600));
975 SetCachedToken(token);
977 // Because the user is not signed in, the token will be removed,
978 // and we'll hit GAIA for new tokens.
979 EXPECT_CALL(*func.get(), HasLoginToken())
980 .WillOnce(Return(false));
981 func->set_login_ui_result(true);
982 TestOAuth2MintTokenFlow* flow = new TestOAuth2MintTokenFlow(
983 TestOAuth2MintTokenFlow::ISSUE_ADVICE_SUCCESS, func.get());
984 EXPECT_CALL(*func.get(), CreateMintTokenFlow(_))
985 .WillOnce(Return(flow));
987 scoped_ptr<base::Value> value(utils::RunFunctionAndReturnSingleResult(
988 func.get(), "[{\"interactive\": true}]", browser()));
989 std::string access_token;
990 EXPECT_TRUE(value->GetAsString(&access_token));
991 EXPECT_EQ(std::string(kAccessToken), access_token);
992 EXPECT_TRUE(func->login_ui_shown());
993 EXPECT_TRUE(func->scope_ui_shown());
994 EXPECT_EQ(IdentityTokenCacheValue::CACHE_STATUS_TOKEN,
995 GetCachedToken().status());
998 IN_PROC_BROWSER_TEST_F(GetAuthTokenFunctionTest, ComponentWithChromeClientId) {
999 scoped_refptr<MockGetAuthTokenFunction> func(new MockGetAuthTokenFunction());
1000 scoped_refptr<const Extension> extension(
1001 CreateExtension(SCOPES | AS_COMPONENT));
1002 func->set_extension(extension.get());
1003 const OAuth2Info& oauth2_info = OAuth2Info::GetOAuth2Info(extension.get());
1004 EXPECT_TRUE(oauth2_info.client_id.empty());
1005 EXPECT_FALSE(func->GetOAuth2ClientId().empty());
1006 EXPECT_NE("client1", func->GetOAuth2ClientId());
1009 IN_PROC_BROWSER_TEST_F(GetAuthTokenFunctionTest, ComponentWithNormalClientId) {
1010 scoped_refptr<MockGetAuthTokenFunction> func(new MockGetAuthTokenFunction());
1011 scoped_refptr<const Extension> extension(
1012 CreateExtension(CLIENT_ID | SCOPES | AS_COMPONENT));
1013 func->set_extension(extension.get());
1014 EXPECT_EQ("client1", func->GetOAuth2ClientId());
1017 class RemoveCachedAuthTokenFunctionTest : public ExtensionBrowserTest {
1019 bool InvalidateDefaultToken() {
1020 scoped_refptr<IdentityRemoveCachedAuthTokenFunction> func(
1021 new IdentityRemoveCachedAuthTokenFunction);
1022 func->set_extension(utils::CreateEmptyExtension(kExtensionId).get());
1023 return utils::RunFunction(
1025 std::string("[{\"token\": \"") + kAccessToken + "\"}]",
1027 extension_function_test_utils::NONE);
1030 IdentityAPI* id_api() {
1031 return IdentityAPI::GetFactoryInstance()->GetForProfile(
1032 browser()->profile());
1035 void SetCachedToken(IdentityTokenCacheValue& token_data) {
1036 ExtensionTokenKey key(extensions::id_util::GenerateId(kExtensionId),
1038 std::set<std::string>());
1039 id_api()->SetCachedToken(key, token_data);
1042 const IdentityTokenCacheValue& GetCachedToken() {
1043 return id_api()->GetCachedToken(
1044 ExtensionTokenKey(extensions::id_util::GenerateId(kExtensionId),
1046 std::set<std::string>()));
1050 IN_PROC_BROWSER_TEST_F(RemoveCachedAuthTokenFunctionTest, NotFound) {
1051 EXPECT_TRUE(InvalidateDefaultToken());
1052 EXPECT_EQ(IdentityTokenCacheValue::CACHE_STATUS_NOTFOUND,
1053 GetCachedToken().status());
1056 IN_PROC_BROWSER_TEST_F(RemoveCachedAuthTokenFunctionTest, Advice) {
1057 IssueAdviceInfo info;
1058 IdentityTokenCacheValue advice(info);
1059 SetCachedToken(advice);
1060 EXPECT_TRUE(InvalidateDefaultToken());
1061 EXPECT_EQ(IdentityTokenCacheValue::CACHE_STATUS_ADVICE,
1062 GetCachedToken().status());
1065 IN_PROC_BROWSER_TEST_F(RemoveCachedAuthTokenFunctionTest, NonMatchingToken) {
1066 IdentityTokenCacheValue token("non_matching_token",
1067 base::TimeDelta::FromSeconds(3600));
1068 SetCachedToken(token);
1069 EXPECT_TRUE(InvalidateDefaultToken());
1070 EXPECT_EQ(IdentityTokenCacheValue::CACHE_STATUS_TOKEN,
1071 GetCachedToken().status());
1072 EXPECT_EQ("non_matching_token", GetCachedToken().token());
1075 IN_PROC_BROWSER_TEST_F(RemoveCachedAuthTokenFunctionTest, MatchingToken) {
1076 IdentityTokenCacheValue token(kAccessToken,
1077 base::TimeDelta::FromSeconds(3600));
1078 SetCachedToken(token);
1079 EXPECT_EQ(IdentityTokenCacheValue::CACHE_STATUS_TOKEN,
1080 GetCachedToken().status());
1081 EXPECT_TRUE(InvalidateDefaultToken());
1082 EXPECT_EQ(IdentityTokenCacheValue::CACHE_STATUS_NOTFOUND,
1083 GetCachedToken().status());
1086 class LaunchWebAuthFlowFunctionTest : public AsyncExtensionBrowserTest {
1088 virtual void SetUpCommandLine(CommandLine* command_line) OVERRIDE {
1089 // Reduce performance test variance by disabling background networking.
1090 command_line->AppendSwitch(switches::kDisableBackgroundNetworking);
1094 IN_PROC_BROWSER_TEST_F(LaunchWebAuthFlowFunctionTest, UserCloseWindow) {
1095 net::SpawnedTestServer https_server(
1096 net::SpawnedTestServer::TYPE_HTTPS,
1097 net::SpawnedTestServer::kLocalhost,
1098 base::FilePath(FILE_PATH_LITERAL(
1099 "chrome/test/data/extensions/api_test/identity")));
1100 ASSERT_TRUE(https_server.Start());
1101 GURL auth_url(https_server.GetURL("files/interaction_required.html"));
1103 scoped_refptr<IdentityLaunchWebAuthFlowFunction> function(
1104 new IdentityLaunchWebAuthFlowFunction());
1105 scoped_refptr<Extension> empty_extension(
1106 utils::CreateEmptyExtension());
1107 function->set_extension(empty_extension.get());
1109 WaitForGURLAndCloseWindow popup_observer(auth_url);
1111 std::string args = "[{\"interactive\": true, \"url\": \"" +
1112 auth_url.spec() + "\"}]";
1113 RunFunctionAsync(function.get(), args);
1115 popup_observer.Wait();
1116 popup_observer.CloseEmbedderWebContents();
1118 EXPECT_EQ(std::string(errors::kUserRejected), WaitForError(function.get()));
1121 IN_PROC_BROWSER_TEST_F(LaunchWebAuthFlowFunctionTest, InteractionRequired) {
1122 net::SpawnedTestServer https_server(
1123 net::SpawnedTestServer::TYPE_HTTPS,
1124 net::SpawnedTestServer::kLocalhost,
1125 base::FilePath(FILE_PATH_LITERAL(
1126 "chrome/test/data/extensions/api_test/identity")));
1127 ASSERT_TRUE(https_server.Start());
1128 GURL auth_url(https_server.GetURL("files/interaction_required.html"));
1130 scoped_refptr<IdentityLaunchWebAuthFlowFunction> function(
1131 new IdentityLaunchWebAuthFlowFunction());
1132 scoped_refptr<Extension> empty_extension(
1133 utils::CreateEmptyExtension());
1134 function->set_extension(empty_extension.get());
1136 std::string args = "[{\"interactive\": false, \"url\": \"" +
1137 auth_url.spec() + "\"}]";
1139 utils::RunFunctionAndReturnError(function.get(), args, browser());
1141 EXPECT_EQ(std::string(errors::kInteractionRequired), error);
1144 IN_PROC_BROWSER_TEST_F(LaunchWebAuthFlowFunctionTest, LoadFailed) {
1145 net::SpawnedTestServer https_server(
1146 net::SpawnedTestServer::TYPE_HTTPS,
1147 net::SpawnedTestServer::kLocalhost,
1148 base::FilePath(FILE_PATH_LITERAL(
1149 "chrome/test/data/extensions/api_test/identity")));
1150 ASSERT_TRUE(https_server.Start());
1151 GURL auth_url(https_server.GetURL("files/five_hundred.html"));
1153 scoped_refptr<IdentityLaunchWebAuthFlowFunction> function(
1154 new IdentityLaunchWebAuthFlowFunction());
1155 scoped_refptr<Extension> empty_extension(
1156 utils::CreateEmptyExtension());
1157 function->set_extension(empty_extension.get());
1159 std::string args = "[{\"interactive\": true, \"url\": \"" +
1160 auth_url.spec() + "\"}]";
1162 utils::RunFunctionAndReturnError(function.get(), args, browser());
1164 EXPECT_EQ(std::string(errors::kPageLoadFailure), error);
1167 IN_PROC_BROWSER_TEST_F(LaunchWebAuthFlowFunctionTest, NonInteractiveSuccess) {
1168 #if defined(OS_WIN) && defined(USE_ASH)
1169 // Disable this test in Metro+Ash for now (http://crbug.com/262796).
1170 if (CommandLine::ForCurrentProcess()->HasSwitch(switches::kAshBrowserTests))
1174 scoped_refptr<IdentityLaunchWebAuthFlowFunction> function(
1175 new IdentityLaunchWebAuthFlowFunction());
1176 scoped_refptr<Extension> empty_extension(
1177 utils::CreateEmptyExtension());
1178 function->set_extension(empty_extension.get());
1180 function->InitFinalRedirectURLPrefixForTest("abcdefghij");
1181 scoped_ptr<base::Value> value(utils::RunFunctionAndReturnSingleResult(
1183 "[{\"interactive\": false,"
1184 "\"url\": \"https://abcdefghij.chromiumapp.org/callback#test\"}]",
1188 EXPECT_TRUE(value->GetAsString(&url));
1189 EXPECT_EQ(std::string("https://abcdefghij.chromiumapp.org/callback#test"),
1193 IN_PROC_BROWSER_TEST_F(
1194 LaunchWebAuthFlowFunctionTest, InteractiveFirstNavigationSuccess) {
1195 #if defined(OS_WIN) && defined(USE_ASH)
1196 // Disable this test in Metro+Ash for now (http://crbug.com/262796).
1197 if (CommandLine::ForCurrentProcess()->HasSwitch(switches::kAshBrowserTests))
1201 scoped_refptr<IdentityLaunchWebAuthFlowFunction> function(
1202 new IdentityLaunchWebAuthFlowFunction());
1203 scoped_refptr<Extension> empty_extension(
1204 utils::CreateEmptyExtension());
1205 function->set_extension(empty_extension.get());
1207 function->InitFinalRedirectURLPrefixForTest("abcdefghij");
1208 scoped_ptr<base::Value> value(utils::RunFunctionAndReturnSingleResult(
1210 "[{\"interactive\": true,"
1211 "\"url\": \"https://abcdefghij.chromiumapp.org/callback#test\"}]",
1215 EXPECT_TRUE(value->GetAsString(&url));
1216 EXPECT_EQ(std::string("https://abcdefghij.chromiumapp.org/callback#test"),
1220 IN_PROC_BROWSER_TEST_F(
1221 LaunchWebAuthFlowFunctionTest, InteractiveSecondNavigationSuccess) {
1222 net::SpawnedTestServer https_server(
1223 net::SpawnedTestServer::TYPE_HTTPS,
1224 net::SpawnedTestServer::kLocalhost,
1225 base::FilePath(FILE_PATH_LITERAL(
1226 "chrome/test/data/extensions/api_test/identity")));
1227 ASSERT_TRUE(https_server.Start());
1228 GURL auth_url(https_server.GetURL("files/redirect_to_chromiumapp.html"));
1230 scoped_refptr<IdentityLaunchWebAuthFlowFunction> function(
1231 new IdentityLaunchWebAuthFlowFunction());
1232 scoped_refptr<Extension> empty_extension(
1233 utils::CreateEmptyExtension());
1234 function->set_extension(empty_extension.get());
1236 function->InitFinalRedirectURLPrefixForTest("abcdefghij");
1237 std::string args = "[{\"interactive\": true, \"url\": \"" +
1238 auth_url.spec() + "\"}]";
1239 scoped_ptr<base::Value> value(
1240 utils::RunFunctionAndReturnSingleResult(function.get(), args, browser()));
1243 EXPECT_TRUE(value->GetAsString(&url));
1244 EXPECT_EQ(std::string("https://abcdefghij.chromiumapp.org/callback#test"),
1248 } // namespace extensions
1250 // Tests the chrome.identity API implemented by custom JS bindings .
1251 IN_PROC_BROWSER_TEST_F(ExtensionApiTest, ChromeIdentityJsBindings) {
1252 ASSERT_TRUE(RunExtensionTest("identity/js_bindings")) << message_;