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.
9 #include "base/command_line.h"
10 #include "base/prefs/pref_service.h"
11 #include "base/strings/string_util.h"
12 #include "base/strings/stringprintf.h"
13 #include "base/values.h"
14 #include "chrome/browser/chrome_notification_types.h"
15 #include "chrome/browser/extensions/api/identity/identity_api.h"
16 #include "chrome/browser/extensions/component_loader.h"
17 #include "chrome/browser/extensions/extension_apitest.h"
18 #include "chrome/browser/extensions/extension_browsertest.h"
19 #include "chrome/browser/extensions/extension_function_test_utils.h"
20 #include "chrome/browser/extensions/extension_service.h"
21 #include "chrome/browser/profiles/profile.h"
22 #include "chrome/browser/signin/account_reconcilor_factory.h"
23 #include "chrome/browser/signin/fake_account_reconcilor.h"
24 #include "chrome/browser/signin/fake_profile_oauth2_token_service.h"
25 #include "chrome/browser/signin/fake_profile_oauth2_token_service_builder.h"
26 #include "chrome/browser/signin/fake_signin_manager.h"
27 #include "chrome/browser/signin/profile_oauth2_token_service_factory.h"
28 #include "chrome/browser/signin/signin_manager_factory.h"
29 #include "chrome/browser/ui/browser.h"
30 #include "chrome/browser/ui/browser_window.h"
31 #include "chrome/common/chrome_switches.h"
32 #include "chrome/common/extensions/api/identity.h"
33 #include "chrome/common/extensions/api/identity/oauth2_manifest_handler.h"
34 #include "chrome/test/base/in_process_browser_test.h"
35 #include "chrome/test/base/test_switches.h"
36 #include "components/signin/core/browser/signin_manager.h"
37 #include "components/signin/core/common/profile_management_switches.h"
38 #include "components/signin/core/common/signin_pref_names.h"
39 #include "content/public/browser/notification_service.h"
40 #include "content/public/browser/notification_source.h"
41 #include "content/public/test/test_utils.h"
42 #include "extensions/browser/guest_view/guest_view_base.h"
43 #include "extensions/common/id_util.h"
44 #include "google_apis/gaia/google_service_auth_error.h"
45 #include "google_apis/gaia/oauth2_mint_token_flow.h"
46 #include "net/test/spawned_test_server/spawned_test_server.h"
47 #include "testing/gmock/include/gmock/gmock.h"
48 #include "testing/gtest/include/gtest/gtest.h"
52 using testing::Return;
53 using testing::ReturnRef;
55 namespace extensions {
59 namespace errors = identity_constants;
60 namespace utils = extension_function_test_utils;
62 static const char kAccessToken[] = "auth_token";
63 static const char kExtensionId[] = "ext_id";
65 // This helps us be able to wait until an UIThreadExtensionFunction calls
67 class SendResponseDelegate
68 : public UIThreadExtensionFunction::DelegateForTests {
70 SendResponseDelegate() : should_post_quit_(false) {}
72 virtual ~SendResponseDelegate() {}
74 void set_should_post_quit(bool should_quit) {
75 should_post_quit_ = should_quit;
79 return response_.get() != NULL;
83 EXPECT_TRUE(HasResponse());
84 return *response_.get();
87 virtual void OnSendResponse(UIThreadExtensionFunction* function,
89 bool bad_message) OVERRIDE {
90 ASSERT_FALSE(bad_message);
91 ASSERT_FALSE(HasResponse());
92 response_.reset(new bool);
94 if (should_post_quit_) {
95 base::MessageLoopForUI::current()->Quit();
100 scoped_ptr<bool> response_;
101 bool should_post_quit_;
104 class AsyncExtensionBrowserTest : public ExtensionBrowserTest {
106 // Asynchronous function runner allows tests to manipulate the browser window
107 // after the call happens.
108 void RunFunctionAsync(
109 UIThreadExtensionFunction* function,
110 const std::string& args) {
111 response_delegate_.reset(new SendResponseDelegate);
112 function->set_test_delegate(response_delegate_.get());
113 scoped_ptr<base::ListValue> parsed_args(utils::ParseList(args));
114 EXPECT_TRUE(parsed_args.get()) <<
115 "Could not parse extension function arguments: " << args;
116 function->SetArgs(parsed_args.get());
118 if (!function->extension()) {
119 scoped_refptr<Extension> empty_extension(
120 utils::CreateEmptyExtension());
121 function->set_extension(empty_extension.get());
124 function->set_browser_context(browser()->profile());
125 function->set_has_callback(true);
126 function->Run()->Execute();
129 std::string WaitForError(UIThreadExtensionFunction* function) {
130 RunMessageLoopUntilResponse();
131 EXPECT_FALSE(function->GetResultList()) << "Did not expect a result";
132 return function->GetError();
135 base::Value* WaitForSingleResult(UIThreadExtensionFunction* function) {
136 RunMessageLoopUntilResponse();
137 EXPECT_TRUE(function->GetError().empty()) << "Unexpected error: "
138 << function->GetError();
139 const base::Value* single_result = NULL;
140 if (function->GetResultList() != NULL &&
141 function->GetResultList()->Get(0, &single_result)) {
142 return single_result->DeepCopy();
148 void RunMessageLoopUntilResponse() {
149 // If the RunAsync of |function| didn't already call SendResponse, run the
150 // message loop until they do.
151 if (!response_delegate_->HasResponse()) {
152 response_delegate_->set_should_post_quit(true);
153 content::RunMessageLoop();
155 EXPECT_TRUE(response_delegate_->HasResponse());
158 scoped_ptr<SendResponseDelegate> response_delegate_;
161 class TestHangOAuth2MintTokenFlow : public OAuth2MintTokenFlow {
163 TestHangOAuth2MintTokenFlow()
164 : OAuth2MintTokenFlow(NULL, NULL, OAuth2MintTokenFlow::Parameters()) {}
166 virtual void Start() OVERRIDE {
167 // Do nothing, simulating a hanging network call.
171 class TestOAuth2MintTokenFlow : public OAuth2MintTokenFlow {
174 ISSUE_ADVICE_SUCCESS,
177 MINT_TOKEN_BAD_CREDENTIALS,
178 MINT_TOKEN_SERVICE_ERROR
181 TestOAuth2MintTokenFlow(ResultType result,
182 OAuth2MintTokenFlow::Delegate* delegate)
183 : OAuth2MintTokenFlow(NULL, delegate, OAuth2MintTokenFlow::Parameters()),
185 delegate_(delegate) {
188 virtual void Start() OVERRIDE {
190 case ISSUE_ADVICE_SUCCESS: {
191 IssueAdviceInfo info;
192 delegate_->OnIssueAdviceSuccess(info);
195 case MINT_TOKEN_SUCCESS: {
196 delegate_->OnMintTokenSuccess(kAccessToken, 3600);
199 case MINT_TOKEN_FAILURE: {
200 GoogleServiceAuthError error(GoogleServiceAuthError::CONNECTION_FAILED);
201 delegate_->OnMintTokenFailure(error);
204 case MINT_TOKEN_BAD_CREDENTIALS: {
205 GoogleServiceAuthError error(
206 GoogleServiceAuthError::INVALID_GAIA_CREDENTIALS);
207 delegate_->OnMintTokenFailure(error);
210 case MINT_TOKEN_SERVICE_ERROR: {
211 GoogleServiceAuthError error =
212 GoogleServiceAuthError::FromServiceError("invalid_scope");
213 delegate_->OnMintTokenFailure(error);
221 OAuth2MintTokenFlow::Delegate* delegate_;
224 // Waits for a specific GURL to generate a NOTIFICATION_LOAD_STOP event and
225 // saves a pointer to the window embedding the WebContents, which can be later
227 class WaitForGURLAndCloseWindow : public content::WindowedNotificationObserver {
229 explicit WaitForGURLAndCloseWindow(GURL url)
230 : WindowedNotificationObserver(
231 content::NOTIFICATION_LOAD_STOP,
232 content::NotificationService::AllSources()),
235 // NotificationObserver:
236 virtual void Observe(int type,
237 const content::NotificationSource& source,
238 const content::NotificationDetails& details) OVERRIDE {
239 content::NavigationController* web_auth_flow_controller =
240 content::Source<content::NavigationController>(source).ptr();
241 content::WebContents* web_contents =
242 web_auth_flow_controller->GetWebContents();
244 if (web_contents->GetURL() == url_) {
245 // It is safe to keep the pointer here, because we know in a test, that
246 // the WebContents won't go away before CloseEmbedderWebContents is
247 // called. Don't copy this code to production.
248 GuestViewBase* guest = GuestViewBase::FromWebContents(web_contents);
249 embedder_web_contents_ = guest->embedder_web_contents();
250 // Condtionally invoke parent class so that Wait will not exit
251 // until the target URL arrives.
252 content::WindowedNotificationObserver::Observe(type, source, details);
256 // Closes the window embedding the WebContents. The action is separated from
257 // the Observe method to make sure the list of observers is not deleted,
258 // while some event is already being processed. (That causes ASAN failures.)
259 void CloseEmbedderWebContents() {
260 if (embedder_web_contents_)
261 embedder_web_contents_->Close();
266 content::WebContents* embedder_web_contents_;
271 class FakeGetAuthTokenFunction : public IdentityGetAuthTokenFunction {
273 FakeGetAuthTokenFunction()
274 : login_access_token_result_(true),
275 auto_login_access_token_(true),
276 login_ui_result_(true),
277 scope_ui_result_(true),
278 login_ui_shown_(false),
279 scope_ui_shown_(false) {}
281 void set_login_access_token_result(bool result) {
282 login_access_token_result_ = result;
285 void set_auto_login_access_token(bool automatic) {
286 auto_login_access_token_ = automatic;
289 void set_login_ui_result(bool result) { login_ui_result_ = result; }
291 void set_mint_token_flow(scoped_ptr<OAuth2MintTokenFlow> flow) {
295 void set_mint_token_result(TestOAuth2MintTokenFlow::ResultType result_type) {
296 set_mint_token_flow(scoped_ptr<TestOAuth2MintTokenFlow>(
297 new TestOAuth2MintTokenFlow(result_type, this))
298 .PassAs<OAuth2MintTokenFlow>());
301 void set_scope_ui_failure(GaiaWebAuthFlow::Failure failure) {
302 scope_ui_result_ = false;
303 scope_ui_failure_ = failure;
306 void set_scope_ui_oauth_error(const std::string& oauth_error) {
307 scope_ui_result_ = false;
308 scope_ui_failure_ = GaiaWebAuthFlow::OAUTH_ERROR;
309 scope_ui_oauth_error_ = oauth_error;
312 bool login_ui_shown() const { return login_ui_shown_; }
314 bool scope_ui_shown() const { return scope_ui_shown_; }
316 std::string login_access_token() const { return login_access_token_; }
318 virtual void StartLoginAccessTokenRequest() OVERRIDE {
319 if (auto_login_access_token_) {
320 if (login_access_token_result_) {
321 OnGetTokenSuccess(login_token_request_.get(),
323 base::Time::Now() + base::TimeDelta::FromHours(1LL));
325 GoogleServiceAuthError error(
326 GoogleServiceAuthError::INVALID_GAIA_CREDENTIALS);
327 OnGetTokenFailure(login_token_request_.get(), error);
330 // Make a request to the token service. The test now must tell
331 // the token service to issue an access token (or an error).
332 IdentityGetAuthTokenFunction::StartLoginAccessTokenRequest();
336 virtual void ShowLoginPopup() OVERRIDE {
337 EXPECT_FALSE(login_ui_shown_);
338 login_ui_shown_ = true;
339 if (login_ui_result_)
345 virtual void ShowOAuthApprovalDialog(
346 const IssueAdviceInfo& issue_advice) OVERRIDE {
347 scope_ui_shown_ = true;
349 if (scope_ui_result_) {
350 OnGaiaFlowCompleted(kAccessToken, "3600");
351 } else if (scope_ui_failure_ == GaiaWebAuthFlow::SERVICE_AUTH_ERROR) {
352 GoogleServiceAuthError error(GoogleServiceAuthError::CONNECTION_FAILED);
353 OnGaiaFlowFailure(scope_ui_failure_, error, "");
355 GoogleServiceAuthError error(GoogleServiceAuthError::NONE);
356 OnGaiaFlowFailure(scope_ui_failure_, error, scope_ui_oauth_error_);
360 virtual OAuth2MintTokenFlow* CreateMintTokenFlow(
361 const std::string& login_access_token) OVERRIDE {
362 EXPECT_TRUE(login_access_token_.empty());
363 // Save the login token used to create the flow so tests can see
364 // what account was used.
365 login_access_token_ = login_access_token;
366 return flow_.release();
370 virtual ~FakeGetAuthTokenFunction() {}
371 bool login_access_token_result_;
372 bool auto_login_access_token_;
373 bool login_ui_result_;
374 bool scope_ui_result_;
375 GaiaWebAuthFlow::Failure scope_ui_failure_;
376 std::string scope_ui_oauth_error_;
377 bool login_ui_shown_;
378 bool scope_ui_shown_;
380 scoped_ptr<OAuth2MintTokenFlow> flow_;
382 std::string login_access_token_;
385 class MockQueuedMintRequest : public IdentityMintRequestQueue::Request {
387 MOCK_METHOD1(StartMintToken, void(IdentityMintRequestQueue::MintType));
390 gaia::AccountIds CreateIds(std::string email, std::string obfid) {
391 gaia::AccountIds ids;
392 ids.account_key = email;
398 class IdentityGetAccountsFunctionTest : public ExtensionBrowserTest {
399 virtual void SetUpCommandLine(CommandLine* command_line) OVERRIDE {
400 ExtensionBrowserTest::SetUpCommandLine(command_line);
401 command_line->AppendSwitch(switches::kExtensionsMultiAccount);
405 void SetAccountState(gaia::AccountIds ids, bool is_signed_in) {
406 IdentityAPI::GetFactoryInstance()->Get(profile())->SetAccountStateForTest(
410 testing::AssertionResult ExpectGetAccounts(
411 const std::vector<std::string>& accounts) {
412 scoped_refptr<IdentityGetAccountsFunction> func(
413 new IdentityGetAccountsFunction);
414 func->set_extension(utils::CreateEmptyExtension(kExtensionId).get());
415 if (!utils::RunFunction(
416 func.get(), std::string("[]"), browser(), utils::NONE)) {
417 return GenerateFailureResult(accounts, NULL)
418 << "getAccounts did not return a result.";
420 const base::ListValue* callback_arguments = func->GetResultList();
421 if (!callback_arguments)
422 return GenerateFailureResult(accounts, NULL) << "NULL result";
424 if (callback_arguments->GetSize() != 1) {
425 return GenerateFailureResult(accounts, NULL)
426 << "Expected 1 argument but got " << callback_arguments->GetSize();
429 const base::ListValue* results;
430 if (!callback_arguments->GetList(0, &results))
431 GenerateFailureResult(accounts, NULL) << "Result was not an array";
433 std::set<std::string> result_ids;
434 for (base::ListValue::const_iterator it = results->begin();
435 it != results->end();
437 scoped_ptr<api::identity::AccountInfo> info =
438 api::identity::AccountInfo::FromValue(**it);
440 result_ids.insert(info->id);
442 return GenerateFailureResult(accounts, results);
445 for (std::vector<std::string>::const_iterator it = accounts.begin();
446 it != accounts.end();
448 if (result_ids.find(*it) == result_ids.end())
449 return GenerateFailureResult(accounts, results);
452 return testing::AssertionResult(true);
455 testing::AssertionResult GenerateFailureResult(
456 const ::std::vector<std::string>& accounts,
457 const base::ListValue* results) {
458 testing::Message msg("Expected: ");
459 for (std::vector<std::string>::const_iterator it = accounts.begin();
460 it != accounts.end();
468 for (base::ListValue::const_iterator it = results->begin();
469 it != results->end();
471 scoped_ptr<api::identity::AccountInfo> info =
472 api::identity::AccountInfo::FromValue(**it);
474 msg << info->id << " ";
476 msg << *it << "<-" << (*it)->GetType() << " ";
480 return testing::AssertionFailure(msg);
484 IN_PROC_BROWSER_TEST_F(IdentityGetAccountsFunctionTest, MultiAccountOn) {
485 EXPECT_TRUE(switches::IsExtensionsMultiAccount());
488 IN_PROC_BROWSER_TEST_F(IdentityGetAccountsFunctionTest, NoneSignedIn) {
489 EXPECT_TRUE(ExpectGetAccounts(std::vector<std::string>()));
492 IN_PROC_BROWSER_TEST_F(IdentityGetAccountsFunctionTest,
493 PrimaryAccountSignedIn) {
494 SetAccountState(CreateIds("primary@example.com", "1"), true);
495 std::vector<std::string> primary;
496 primary.push_back("1");
497 EXPECT_TRUE(ExpectGetAccounts(primary));
500 IN_PROC_BROWSER_TEST_F(IdentityGetAccountsFunctionTest, TwoAccountsSignedIn) {
501 SetAccountState(CreateIds("primary@example.com", "1"), true);
502 SetAccountState(CreateIds("secondary@example.com", "2"), true);
503 std::vector<std::string> two_accounts;
504 two_accounts.push_back("1");
505 two_accounts.push_back("2");
506 EXPECT_TRUE(ExpectGetAccounts(two_accounts));
509 class IdentityOldProfilesGetAccountsFunctionTest
510 : public IdentityGetAccountsFunctionTest {
511 virtual void SetUpCommandLine(CommandLine* command_line) OVERRIDE {
512 // Don't add the multi-account switch that parent class would have.
516 IN_PROC_BROWSER_TEST_F(IdentityOldProfilesGetAccountsFunctionTest,
518 EXPECT_FALSE(switches::IsExtensionsMultiAccount());
521 IN_PROC_BROWSER_TEST_F(IdentityOldProfilesGetAccountsFunctionTest,
522 TwoAccountsSignedIn) {
523 SetAccountState(CreateIds("primary@example.com", "1"), true);
524 SetAccountState(CreateIds("secondary@example.com", "2"), true);
525 std::vector<std::string> only_primary;
526 only_primary.push_back("1");
527 EXPECT_TRUE(ExpectGetAccounts(only_primary));
530 class IdentityGetProfileUserInfoFunctionTest : public ExtensionBrowserTest {
532 scoped_ptr<api::identity::ProfileUserInfo> RunGetProfileUserInfo() {
533 scoped_refptr<IdentityGetProfileUserInfoFunction> func(
534 new IdentityGetProfileUserInfoFunction);
535 func->set_extension(utils::CreateEmptyExtension(kExtensionId).get());
536 scoped_ptr<base::Value> value(
537 utils::RunFunctionAndReturnSingleResult(func.get(), "[]", browser()));
538 return api::identity::ProfileUserInfo::FromValue(*value.get());
541 scoped_ptr<api::identity::ProfileUserInfo> RunGetProfileUserInfoWithEmail() {
542 scoped_refptr<IdentityGetProfileUserInfoFunction> func(
543 new IdentityGetProfileUserInfoFunction);
544 func->set_extension(CreateExtensionWithEmailPermission());
545 scoped_ptr<base::Value> value(
546 utils::RunFunctionAndReturnSingleResult(func.get(), "[]", browser()));
547 return api::identity::ProfileUserInfo::FromValue(*value.get());
551 scoped_refptr<Extension> CreateExtensionWithEmailPermission() {
552 scoped_ptr<base::DictionaryValue> test_extension_value(
553 utils::ParseDictionary(
554 "{\"name\": \"Test\", \"version\": \"1.0\", "
555 "\"permissions\": [\"identity.email\"]}"));
556 return utils::CreateExtension(test_extension_value.get());
560 IN_PROC_BROWSER_TEST_F(IdentityGetProfileUserInfoFunctionTest, NotSignedIn) {
561 scoped_ptr<api::identity::ProfileUserInfo> info =
562 RunGetProfileUserInfoWithEmail();
563 EXPECT_TRUE(info->email.empty());
564 EXPECT_TRUE(info->id.empty());
567 IN_PROC_BROWSER_TEST_F(IdentityGetProfileUserInfoFunctionTest, SignedIn) {
568 profile()->GetPrefs()
569 ->SetString(prefs::kGoogleServicesUsername, "president@example.com");
570 profile()->GetPrefs()
571 ->SetString(prefs::kGoogleServicesUserAccountId, "12345");
573 scoped_ptr<api::identity::ProfileUserInfo> info =
574 RunGetProfileUserInfoWithEmail();
575 EXPECT_EQ("president@example.com", info->email);
576 EXPECT_EQ("12345", info->id);
579 IN_PROC_BROWSER_TEST_F(IdentityGetProfileUserInfoFunctionTest,
580 NotSignedInNoEmail) {
581 scoped_ptr<api::identity::ProfileUserInfo> info = RunGetProfileUserInfo();
582 EXPECT_TRUE(info->email.empty());
583 EXPECT_TRUE(info->id.empty());
586 IN_PROC_BROWSER_TEST_F(IdentityGetProfileUserInfoFunctionTest,
588 profile()->GetPrefs()->SetString(prefs::kGoogleServicesUsername,
589 "president@example.com");
590 profile()->GetPrefs()->SetString(prefs::kGoogleServicesUserAccountId,
593 scoped_ptr<api::identity::ProfileUserInfo> info = RunGetProfileUserInfo();
594 EXPECT_TRUE(info->email.empty());
595 EXPECT_EQ("12345", info->id);
598 class GetAuthTokenFunctionTest : public AsyncExtensionBrowserTest {
600 virtual void SetUpCommandLine(CommandLine* command_line) OVERRIDE {
601 AsyncExtensionBrowserTest::SetUpCommandLine(command_line);
602 command_line->AppendSwitch(switches::kExtensionsMultiAccount);
605 virtual void SetUpInProcessBrowserTestFixture() OVERRIDE {
606 AsyncExtensionBrowserTest::SetUpInProcessBrowserTestFixture();
608 will_create_browser_context_services_subscription_ =
609 BrowserContextDependencyManager::GetInstance()
610 ->RegisterWillCreateBrowserContextServicesCallbackForTesting(
611 base::Bind(&GetAuthTokenFunctionTest::
612 OnWillCreateBrowserContextServices,
613 base::Unretained(this)))
617 void OnWillCreateBrowserContextServices(content::BrowserContext* context) {
618 // Replace the signin manager and token service with fakes. Do this ahead of
619 // creating the browser so that a bunch of classes don't register as
620 // observers and end up needing to unregister when the fake is substituted.
621 SigninManagerFactory::GetInstance()->SetTestingFactory(
622 context, &FakeSigninManagerBase::Build);
623 ProfileOAuth2TokenServiceFactory::GetInstance()->SetTestingFactory(
624 context, &BuildFakeProfileOAuth2TokenService);
625 AccountReconcilorFactory::GetInstance()->SetTestingFactory(
626 context, &FakeAccountReconcilor::Build);
629 virtual void SetUpOnMainThread() OVERRIDE {
630 AsyncExtensionBrowserTest::SetUpOnMainThread();
632 // Grab references to the fake signin manager and token service.
633 signin_manager_ = static_cast<FakeSigninManagerForTesting*>(
634 SigninManagerFactory::GetInstance()->GetForProfile(profile()));
635 ASSERT_TRUE(signin_manager_);
636 token_service_ = static_cast<FakeProfileOAuth2TokenService*>(
637 ProfileOAuth2TokenServiceFactory::GetInstance()->GetForProfile(
639 ASSERT_TRUE(token_service_);
642 void SignIn(const std::string account_key) {
643 #if defined(OS_CHROMEOS)
644 signin_manager_->SetAuthenticatedUsername(account_key);
646 signin_manager_->SignIn(account_key, "password");
648 token_service_->IssueRefreshTokenForUser(account_key, "refresh_token");
651 void IssueLoginRefreshTokenForAccount(const std::string account_key) {
652 token_service_->IssueRefreshTokenForUser(account_key, "refresh_token");
655 void IssueLoginAccessTokenForAccount(const std::string account_key) {
656 token_service_->IssueAllTokensForAccount(
658 "access_token-" + account_key,
659 base::Time::Now() + base::TimeDelta::FromSeconds(3600));
662 void SetAccountState(gaia::AccountIds ids, bool is_signed_in) {
663 IdentityAPI::GetFactoryInstance()->Get(profile())->SetAccountStateForTest(
675 FakeSigninManagerForTesting* signin_manager_;
676 FakeProfileOAuth2TokenService* token_service_;
678 virtual ~GetAuthTokenFunctionTest() {}
680 // Helper to create an extension with specific OAuth2Info fields set.
681 // |fields_to_set| should be computed by using fields of Oauth2Fields enum.
682 const Extension* CreateExtension(int fields_to_set) {
683 const Extension* ext;
684 base::FilePath manifest_path =
685 test_data_dir_.AppendASCII("platform_apps/oauth2");
686 base::FilePath component_manifest_path =
687 test_data_dir_.AppendASCII("packaged_app/component_oauth2");
688 if ((fields_to_set & AS_COMPONENT) == 0)
689 ext = LoadExtension(manifest_path);
691 ext = LoadExtensionAsComponent(component_manifest_path);
692 OAuth2Info& oauth2_info =
693 const_cast<OAuth2Info&>(OAuth2Info::GetOAuth2Info(ext));
694 if ((fields_to_set & CLIENT_ID) != 0)
695 oauth2_info.client_id = "client1";
696 if ((fields_to_set & SCOPES) != 0) {
697 oauth2_info.scopes.push_back("scope1");
698 oauth2_info.scopes.push_back("scope2");
701 extension_id_ = ext->id();
702 oauth_scopes_ = std::set<std::string>(oauth2_info.scopes.begin(),
703 oauth2_info.scopes.end());
707 IdentityAPI* id_api() {
708 return IdentityAPI::GetFactoryInstance()->Get(browser()->profile());
711 const std::string GetPrimaryAccountId() {
712 SigninManagerBase* signin_manager =
713 SigninManagerFactory::GetForProfile(browser()->profile());
714 return signin_manager->GetAuthenticatedAccountId();
717 void SetCachedToken(const IdentityTokenCacheValue& token_data) {
718 ExtensionTokenKey key(extension_id_, GetPrimaryAccountId(), oauth_scopes_);
719 id_api()->SetCachedToken(key, token_data);
722 const IdentityTokenCacheValue& GetCachedToken(std::string account_id) {
723 if (account_id.empty())
724 account_id = GetPrimaryAccountId();
725 ExtensionTokenKey key(extension_id_, account_id, oauth_scopes_);
726 return id_api()->GetCachedToken(key);
729 void QueueRequestStart(IdentityMintRequestQueue::MintType type,
730 IdentityMintRequestQueue::Request* request) {
731 ExtensionTokenKey key(extension_id_, GetPrimaryAccountId(), oauth_scopes_);
732 id_api()->mint_queue()->RequestStart(type, key, request);
735 void QueueRequestComplete(IdentityMintRequestQueue::MintType type,
736 IdentityMintRequestQueue::Request* request) {
737 ExtensionTokenKey key(extension_id_, GetPrimaryAccountId(), oauth_scopes_);
738 id_api()->mint_queue()->RequestComplete(type, key, request);
742 std::string extension_id_;
743 std::set<std::string> oauth_scopes_;
745 scoped_ptr<base::CallbackList<void(content::BrowserContext*)>::Subscription>
746 will_create_browser_context_services_subscription_;
749 IN_PROC_BROWSER_TEST_F(GetAuthTokenFunctionTest,
751 scoped_refptr<FakeGetAuthTokenFunction> func(new FakeGetAuthTokenFunction());
752 func->set_extension(CreateExtension(SCOPES));
753 std::string error = utils::RunFunctionAndReturnError(
754 func.get(), "[{}]", browser());
755 EXPECT_EQ(std::string(errors::kInvalidClientId), error);
756 EXPECT_FALSE(func->login_ui_shown());
757 EXPECT_FALSE(func->scope_ui_shown());
760 IN_PROC_BROWSER_TEST_F(GetAuthTokenFunctionTest,
762 scoped_refptr<FakeGetAuthTokenFunction> func(new FakeGetAuthTokenFunction());
763 func->set_extension(CreateExtension(CLIENT_ID));
764 std::string error = utils::RunFunctionAndReturnError(
765 func.get(), "[{}]", browser());
766 EXPECT_EQ(std::string(errors::kInvalidScopes), error);
767 EXPECT_FALSE(func->login_ui_shown());
768 EXPECT_FALSE(func->scope_ui_shown());
771 IN_PROC_BROWSER_TEST_F(GetAuthTokenFunctionTest,
772 NonInteractiveNotSignedIn) {
773 scoped_refptr<FakeGetAuthTokenFunction> func(new FakeGetAuthTokenFunction());
774 func->set_extension(CreateExtension(CLIENT_ID | SCOPES));
775 std::string error = utils::RunFunctionAndReturnError(
776 func.get(), "[{}]", browser());
777 EXPECT_EQ(std::string(errors::kUserNotSignedIn), error);
778 EXPECT_FALSE(func->login_ui_shown());
779 EXPECT_FALSE(func->scope_ui_shown());
782 IN_PROC_BROWSER_TEST_F(GetAuthTokenFunctionTest,
783 NonInteractiveMintFailure) {
784 SignIn("primary@example.com");
785 scoped_refptr<FakeGetAuthTokenFunction> func(new FakeGetAuthTokenFunction());
786 func->set_extension(CreateExtension(CLIENT_ID | SCOPES));
787 func->set_mint_token_result(TestOAuth2MintTokenFlow::MINT_TOKEN_FAILURE);
789 utils::RunFunctionAndReturnError(func.get(), "[{}]", browser());
790 EXPECT_TRUE(StartsWithASCII(error, errors::kAuthFailure, false));
791 EXPECT_FALSE(func->login_ui_shown());
792 EXPECT_FALSE(func->scope_ui_shown());
795 IN_PROC_BROWSER_TEST_F(GetAuthTokenFunctionTest,
796 NonInteractiveLoginAccessTokenFailure) {
797 SignIn("primary@example.com");
798 scoped_refptr<FakeGetAuthTokenFunction> func(new FakeGetAuthTokenFunction());
799 func->set_extension(CreateExtension(CLIENT_ID | SCOPES));
800 func->set_login_access_token_result(false);
801 std::string error = utils::RunFunctionAndReturnError(
802 func.get(), "[{}]", browser());
803 EXPECT_TRUE(StartsWithASCII(error, errors::kAuthFailure, false));
806 IN_PROC_BROWSER_TEST_F(GetAuthTokenFunctionTest,
807 NonInteractiveMintAdviceSuccess) {
808 SignIn("primary@example.com");
809 scoped_refptr<const Extension> extension(CreateExtension(CLIENT_ID | SCOPES));
810 scoped_refptr<FakeGetAuthTokenFunction> func(new FakeGetAuthTokenFunction());
811 func->set_extension(extension.get());
812 func->set_mint_token_result(TestOAuth2MintTokenFlow::ISSUE_ADVICE_SUCCESS);
814 utils::RunFunctionAndReturnError(func.get(), "[{}]", browser());
815 EXPECT_EQ(std::string(errors::kNoGrant), error);
816 EXPECT_FALSE(func->login_ui_shown());
817 EXPECT_FALSE(func->scope_ui_shown());
819 EXPECT_EQ(IdentityTokenCacheValue::CACHE_STATUS_ADVICE,
820 GetCachedToken(std::string()).status());
823 IN_PROC_BROWSER_TEST_F(GetAuthTokenFunctionTest,
824 NonInteractiveMintBadCredentials) {
825 SignIn("primary@example.com");
826 scoped_refptr<FakeGetAuthTokenFunction> func(new FakeGetAuthTokenFunction());
827 func->set_extension(CreateExtension(CLIENT_ID | SCOPES));
828 func->set_mint_token_result(
829 TestOAuth2MintTokenFlow::MINT_TOKEN_BAD_CREDENTIALS);
831 utils::RunFunctionAndReturnError(func.get(), "[{}]", browser());
832 EXPECT_TRUE(StartsWithASCII(error, errors::kAuthFailure, false));
833 EXPECT_FALSE(func->login_ui_shown());
834 EXPECT_FALSE(func->scope_ui_shown());
837 IN_PROC_BROWSER_TEST_F(GetAuthTokenFunctionTest,
838 NonInteractiveMintServiceError) {
839 SignIn("primary@example.com");
840 scoped_refptr<FakeGetAuthTokenFunction> func(new FakeGetAuthTokenFunction());
841 func->set_extension(CreateExtension(CLIENT_ID | SCOPES));
842 func->set_mint_token_result(
843 TestOAuth2MintTokenFlow::MINT_TOKEN_SERVICE_ERROR);
845 utils::RunFunctionAndReturnError(func.get(), "[{}]", browser());
846 EXPECT_TRUE(StartsWithASCII(error, errors::kAuthFailure, false));
847 EXPECT_FALSE(func->login_ui_shown());
848 EXPECT_FALSE(func->scope_ui_shown());
851 IN_PROC_BROWSER_TEST_F(GetAuthTokenFunctionTest,
853 SignIn("primary@example.com");
854 #if defined(OS_WIN) && defined(USE_ASH)
855 // Disable this test in Metro+Ash for now (http://crbug.com/262796).
856 if (CommandLine::ForCurrentProcess()->HasSwitch(switches::kAshBrowserTests))
860 scoped_refptr<FakeGetAuthTokenFunction> func(new FakeGetAuthTokenFunction());
861 scoped_refptr<const Extension> extension(CreateExtension(CLIENT_ID | SCOPES));
862 func->set_extension(extension.get());
863 func->set_mint_token_result(TestOAuth2MintTokenFlow::MINT_TOKEN_SUCCESS);
864 scoped_ptr<base::Value> value(
865 utils::RunFunctionAndReturnSingleResult(func.get(), "[]", browser()));
866 std::string access_token;
867 EXPECT_TRUE(value->GetAsString(&access_token));
868 EXPECT_EQ(std::string(kAccessToken), access_token);
869 EXPECT_FALSE(func->login_ui_shown());
870 EXPECT_FALSE(func->scope_ui_shown());
871 EXPECT_EQ(IdentityTokenCacheValue::CACHE_STATUS_TOKEN,
872 GetCachedToken(std::string()).status());
875 IN_PROC_BROWSER_TEST_F(GetAuthTokenFunctionTest,
876 NonInteractiveSuccess) {
877 SignIn("primary@example.com");
878 #if defined(OS_WIN) && defined(USE_ASH)
879 // Disable this test in Metro+Ash for now (http://crbug.com/262796).
880 if (CommandLine::ForCurrentProcess()->HasSwitch(switches::kAshBrowserTests))
884 scoped_refptr<FakeGetAuthTokenFunction> func(new FakeGetAuthTokenFunction());
885 scoped_refptr<const Extension> extension(CreateExtension(CLIENT_ID | SCOPES));
886 func->set_extension(extension.get());
887 func->set_mint_token_result(TestOAuth2MintTokenFlow::MINT_TOKEN_SUCCESS);
888 scoped_ptr<base::Value> value(utils::RunFunctionAndReturnSingleResult(
889 func.get(), "[{}]", browser()));
890 std::string access_token;
891 EXPECT_TRUE(value->GetAsString(&access_token));
892 EXPECT_EQ(std::string(kAccessToken), access_token);
893 EXPECT_FALSE(func->login_ui_shown());
894 EXPECT_FALSE(func->scope_ui_shown());
895 EXPECT_EQ(IdentityTokenCacheValue::CACHE_STATUS_TOKEN,
896 GetCachedToken(std::string()).status());
899 IN_PROC_BROWSER_TEST_F(GetAuthTokenFunctionTest,
900 InteractiveLoginCanceled) {
901 scoped_refptr<FakeGetAuthTokenFunction> func(new FakeGetAuthTokenFunction());
902 func->set_extension(CreateExtension(CLIENT_ID | SCOPES));
903 func->set_login_ui_result(false);
904 std::string error = utils::RunFunctionAndReturnError(
905 func.get(), "[{\"interactive\": true}]", browser());
906 EXPECT_EQ(std::string(errors::kUserNotSignedIn), error);
907 EXPECT_TRUE(func->login_ui_shown());
908 EXPECT_FALSE(func->scope_ui_shown());
911 IN_PROC_BROWSER_TEST_F(GetAuthTokenFunctionTest,
912 InteractiveMintBadCredentialsLoginCanceled) {
913 SignIn("primary@example.com");
914 scoped_refptr<FakeGetAuthTokenFunction> func(new FakeGetAuthTokenFunction());
915 func->set_extension(CreateExtension(CLIENT_ID | SCOPES));
916 func->set_mint_token_result(
917 TestOAuth2MintTokenFlow::MINT_TOKEN_BAD_CREDENTIALS);
918 func->set_login_ui_result(false);
919 std::string error = utils::RunFunctionAndReturnError(
920 func.get(), "[{\"interactive\": true}]", browser());
921 EXPECT_EQ(std::string(errors::kUserNotSignedIn), error);
922 EXPECT_TRUE(func->login_ui_shown());
923 EXPECT_FALSE(func->scope_ui_shown());
926 IN_PROC_BROWSER_TEST_F(GetAuthTokenFunctionTest,
927 InteractiveLoginSuccessNoToken) {
928 scoped_refptr<FakeGetAuthTokenFunction> func(new FakeGetAuthTokenFunction());
929 func->set_extension(CreateExtension(CLIENT_ID | SCOPES));
930 func->set_login_ui_result(false);
931 std::string error = utils::RunFunctionAndReturnError(
932 func.get(), "[{\"interactive\": true}]", browser());
933 EXPECT_EQ(std::string(errors::kUserNotSignedIn), error);
934 EXPECT_TRUE(func->login_ui_shown());
935 EXPECT_FALSE(func->scope_ui_shown());
938 IN_PROC_BROWSER_TEST_F(GetAuthTokenFunctionTest,
939 InteractiveLoginSuccessMintFailure) {
940 scoped_refptr<FakeGetAuthTokenFunction> func(new FakeGetAuthTokenFunction());
941 func->set_extension(CreateExtension(CLIENT_ID | SCOPES));
942 func->set_login_ui_result(true);
943 func->set_mint_token_result(TestOAuth2MintTokenFlow::MINT_TOKEN_FAILURE);
944 std::string error = utils::RunFunctionAndReturnError(
945 func.get(), "[{\"interactive\": true}]", browser());
946 EXPECT_TRUE(StartsWithASCII(error, errors::kAuthFailure, false));
947 EXPECT_TRUE(func->login_ui_shown());
948 EXPECT_FALSE(func->scope_ui_shown());
951 IN_PROC_BROWSER_TEST_F(GetAuthTokenFunctionTest,
952 InteractiveLoginSuccessLoginAccessTokenFailure) {
953 scoped_refptr<FakeGetAuthTokenFunction> func(new FakeGetAuthTokenFunction());
954 func->set_extension(CreateExtension(CLIENT_ID | SCOPES));
955 func->set_login_ui_result(true);
956 func->set_login_access_token_result(false);
957 std::string error = utils::RunFunctionAndReturnError(
958 func.get(), "[{\"interactive\": true}]", browser());
959 EXPECT_TRUE(StartsWithASCII(error, errors::kAuthFailure, false));
960 EXPECT_TRUE(func->login_ui_shown());
961 EXPECT_FALSE(func->scope_ui_shown());
964 IN_PROC_BROWSER_TEST_F(GetAuthTokenFunctionTest,
965 InteractiveLoginSuccessMintSuccess) {
966 // TODO(courage): verify that account_id in token service requests
967 // is correct once manual token minting for tests is implemented.
968 scoped_refptr<FakeGetAuthTokenFunction> func(new FakeGetAuthTokenFunction());
969 func->set_extension(CreateExtension(CLIENT_ID | SCOPES));
970 func->set_login_ui_result(true);
971 func->set_mint_token_result(TestOAuth2MintTokenFlow::MINT_TOKEN_SUCCESS);
972 scoped_ptr<base::Value> value(utils::RunFunctionAndReturnSingleResult(
973 func.get(), "[{\"interactive\": true}]", browser()));
974 std::string access_token;
975 EXPECT_TRUE(value->GetAsString(&access_token));
976 EXPECT_EQ(std::string(kAccessToken), access_token);
977 EXPECT_TRUE(func->login_ui_shown());
978 EXPECT_FALSE(func->scope_ui_shown());
981 IN_PROC_BROWSER_TEST_F(GetAuthTokenFunctionTest,
982 InteractiveLoginSuccessApprovalAborted) {
983 scoped_refptr<FakeGetAuthTokenFunction> func(new FakeGetAuthTokenFunction());
984 func->set_extension(CreateExtension(CLIENT_ID | SCOPES));
985 func->set_login_ui_result(true);
986 func->set_mint_token_result(TestOAuth2MintTokenFlow::ISSUE_ADVICE_SUCCESS);
987 func->set_scope_ui_failure(GaiaWebAuthFlow::WINDOW_CLOSED);
988 std::string error = utils::RunFunctionAndReturnError(
989 func.get(), "[{\"interactive\": true}]", browser());
990 EXPECT_EQ(std::string(errors::kUserRejected), error);
991 EXPECT_TRUE(func->login_ui_shown());
992 EXPECT_TRUE(func->scope_ui_shown());
995 IN_PROC_BROWSER_TEST_F(GetAuthTokenFunctionTest,
996 InteractiveLoginSuccessApprovalSuccess) {
997 scoped_refptr<const Extension> extension(CreateExtension(CLIENT_ID | SCOPES));
998 scoped_refptr<FakeGetAuthTokenFunction> func(new FakeGetAuthTokenFunction());
999 func->set_extension(extension.get());
1000 func->set_login_ui_result(true);
1001 func->set_mint_token_result(TestOAuth2MintTokenFlow::ISSUE_ADVICE_SUCCESS);
1003 scoped_ptr<base::Value> value(utils::RunFunctionAndReturnSingleResult(
1004 func.get(), "[{\"interactive\": true}]", browser()));
1005 std::string access_token;
1006 EXPECT_TRUE(value->GetAsString(&access_token));
1007 EXPECT_EQ(std::string(kAccessToken), access_token);
1008 EXPECT_TRUE(func->login_ui_shown());
1009 EXPECT_TRUE(func->scope_ui_shown());
1012 IN_PROC_BROWSER_TEST_F(GetAuthTokenFunctionTest,
1013 InteractiveApprovalAborted) {
1014 SignIn("primary@example.com");
1015 scoped_refptr<FakeGetAuthTokenFunction> func(new FakeGetAuthTokenFunction());
1016 func->set_extension(CreateExtension(CLIENT_ID | SCOPES));
1017 func->set_mint_token_result(TestOAuth2MintTokenFlow::ISSUE_ADVICE_SUCCESS);
1018 func->set_scope_ui_failure(GaiaWebAuthFlow::WINDOW_CLOSED);
1019 std::string error = utils::RunFunctionAndReturnError(
1020 func.get(), "[{\"interactive\": true}]", browser());
1021 EXPECT_EQ(std::string(errors::kUserRejected), error);
1022 EXPECT_FALSE(func->login_ui_shown());
1023 EXPECT_TRUE(func->scope_ui_shown());
1026 IN_PROC_BROWSER_TEST_F(GetAuthTokenFunctionTest,
1027 InteractiveApprovalLoadFailed) {
1028 SignIn("primary@example.com");
1029 scoped_refptr<FakeGetAuthTokenFunction> func(new FakeGetAuthTokenFunction());
1030 func->set_extension(CreateExtension(CLIENT_ID | SCOPES));
1031 func->set_mint_token_result(TestOAuth2MintTokenFlow::ISSUE_ADVICE_SUCCESS);
1032 func->set_scope_ui_failure(GaiaWebAuthFlow::LOAD_FAILED);
1033 std::string error = utils::RunFunctionAndReturnError(
1034 func.get(), "[{\"interactive\": true}]", browser());
1035 EXPECT_EQ(std::string(errors::kPageLoadFailure), error);
1036 EXPECT_FALSE(func->login_ui_shown());
1037 EXPECT_TRUE(func->scope_ui_shown());
1040 IN_PROC_BROWSER_TEST_F(GetAuthTokenFunctionTest,
1041 InteractiveApprovalInvalidRedirect) {
1042 SignIn("primary@example.com");
1043 scoped_refptr<FakeGetAuthTokenFunction> func(new FakeGetAuthTokenFunction());
1044 func->set_extension(CreateExtension(CLIENT_ID | SCOPES));
1045 func->set_mint_token_result(TestOAuth2MintTokenFlow::ISSUE_ADVICE_SUCCESS);
1046 func->set_scope_ui_failure(GaiaWebAuthFlow::INVALID_REDIRECT);
1047 std::string error = utils::RunFunctionAndReturnError(
1048 func.get(), "[{\"interactive\": true}]", browser());
1049 EXPECT_EQ(std::string(errors::kInvalidRedirect), error);
1050 EXPECT_FALSE(func->login_ui_shown());
1051 EXPECT_TRUE(func->scope_ui_shown());
1054 IN_PROC_BROWSER_TEST_F(GetAuthTokenFunctionTest,
1055 InteractiveApprovalConnectionFailure) {
1056 SignIn("primary@example.com");
1057 scoped_refptr<FakeGetAuthTokenFunction> func(new FakeGetAuthTokenFunction());
1058 func->set_extension(CreateExtension(CLIENT_ID | SCOPES));
1059 func->set_mint_token_result(TestOAuth2MintTokenFlow::ISSUE_ADVICE_SUCCESS);
1060 func->set_scope_ui_failure(GaiaWebAuthFlow::SERVICE_AUTH_ERROR);
1061 std::string error = utils::RunFunctionAndReturnError(
1062 func.get(), "[{\"interactive\": true}]", browser());
1063 EXPECT_TRUE(StartsWithASCII(error, errors::kAuthFailure, false));
1064 EXPECT_FALSE(func->login_ui_shown());
1065 EXPECT_TRUE(func->scope_ui_shown());
1068 IN_PROC_BROWSER_TEST_F(GetAuthTokenFunctionTest,
1069 InteractiveApprovalOAuthErrors) {
1070 SignIn("primary@example.com");
1071 scoped_refptr<const Extension> extension(CreateExtension(CLIENT_ID | SCOPES));
1073 std::map<std::string, std::string> error_map;
1074 error_map.insert(std::make_pair("access_denied", errors::kUserRejected));
1075 error_map.insert(std::make_pair("invalid_scope", errors::kInvalidScopes));
1076 error_map.insert(std::make_pair(
1077 "unmapped_error", std::string(errors::kAuthFailure) + "unmapped_error"));
1079 for (std::map<std::string, std::string>::const_iterator
1080 it = error_map.begin();
1081 it != error_map.end();
1083 scoped_refptr<FakeGetAuthTokenFunction> func(
1084 new FakeGetAuthTokenFunction());
1085 func->set_extension(extension.get());
1086 // Make sure we don't get a cached issue_advice result, which would cause
1087 // flow to be leaked.
1088 id_api()->EraseAllCachedTokens();
1089 func->set_mint_token_result(TestOAuth2MintTokenFlow::ISSUE_ADVICE_SUCCESS);
1090 func->set_scope_ui_oauth_error(it->first);
1091 std::string error = utils::RunFunctionAndReturnError(
1092 func.get(), "[{\"interactive\": true}]", browser());
1093 EXPECT_EQ(it->second, error);
1094 EXPECT_FALSE(func->login_ui_shown());
1095 EXPECT_TRUE(func->scope_ui_shown());
1099 IN_PROC_BROWSER_TEST_F(GetAuthTokenFunctionTest,
1100 InteractiveApprovalSuccess) {
1101 SignIn("primary@example.com");
1102 scoped_refptr<const Extension> extension(CreateExtension(CLIENT_ID | SCOPES));
1103 scoped_refptr<FakeGetAuthTokenFunction> func(new FakeGetAuthTokenFunction());
1104 func->set_extension(extension.get());
1105 func->set_mint_token_result(TestOAuth2MintTokenFlow::ISSUE_ADVICE_SUCCESS);
1107 scoped_ptr<base::Value> value(utils::RunFunctionAndReturnSingleResult(
1108 func.get(), "[{\"interactive\": true}]", browser()));
1109 std::string access_token;
1110 EXPECT_TRUE(value->GetAsString(&access_token));
1111 EXPECT_EQ(std::string(kAccessToken), access_token);
1112 EXPECT_FALSE(func->login_ui_shown());
1113 EXPECT_TRUE(func->scope_ui_shown());
1115 EXPECT_EQ(IdentityTokenCacheValue::CACHE_STATUS_TOKEN,
1116 GetCachedToken(std::string()).status());
1119 IN_PROC_BROWSER_TEST_F(GetAuthTokenFunctionTest, NoninteractiveQueue) {
1120 SignIn("primary@example.com");
1121 scoped_refptr<const Extension> extension(CreateExtension(CLIENT_ID | SCOPES));
1122 scoped_refptr<FakeGetAuthTokenFunction> func(new FakeGetAuthTokenFunction());
1123 func->set_extension(extension.get());
1125 // Create a fake request to block the queue.
1126 MockQueuedMintRequest queued_request;
1127 IdentityMintRequestQueue::MintType type =
1128 IdentityMintRequestQueue::MINT_TYPE_NONINTERACTIVE;
1130 EXPECT_CALL(queued_request, StartMintToken(type)).Times(1);
1131 QueueRequestStart(type, &queued_request);
1133 // The real request will start processing, but wait in the queue behind
1135 RunFunctionAsync(func.get(), "[{}]");
1136 // Verify that we have fetched the login token at this point.
1137 testing::Mock::VerifyAndClearExpectations(func.get());
1139 // The flow will be created after the first queued request clears.
1140 func->set_mint_token_result(TestOAuth2MintTokenFlow::MINT_TOKEN_SUCCESS);
1142 QueueRequestComplete(type, &queued_request);
1144 scoped_ptr<base::Value> value(WaitForSingleResult(func.get()));
1145 std::string access_token;
1146 EXPECT_TRUE(value->GetAsString(&access_token));
1147 EXPECT_EQ(std::string(kAccessToken), access_token);
1148 EXPECT_FALSE(func->login_ui_shown());
1149 EXPECT_FALSE(func->scope_ui_shown());
1152 IN_PROC_BROWSER_TEST_F(GetAuthTokenFunctionTest, InteractiveQueue) {
1153 SignIn("primary@example.com");
1154 scoped_refptr<const Extension> extension(CreateExtension(CLIENT_ID | SCOPES));
1155 scoped_refptr<FakeGetAuthTokenFunction> func(new FakeGetAuthTokenFunction());
1156 func->set_extension(extension.get());
1158 // Create a fake request to block the queue.
1159 MockQueuedMintRequest queued_request;
1160 IdentityMintRequestQueue::MintType type =
1161 IdentityMintRequestQueue::MINT_TYPE_INTERACTIVE;
1163 EXPECT_CALL(queued_request, StartMintToken(type)).Times(1);
1164 QueueRequestStart(type, &queued_request);
1166 // The real request will start processing, but wait in the queue behind
1168 func->set_mint_token_result(TestOAuth2MintTokenFlow::ISSUE_ADVICE_SUCCESS);
1169 RunFunctionAsync(func.get(), "[{\"interactive\": true}]");
1170 // Verify that we have fetched the login token and run the first flow.
1171 testing::Mock::VerifyAndClearExpectations(func.get());
1172 EXPECT_FALSE(func->scope_ui_shown());
1174 // The UI will be displayed and a token retrieved after the first
1175 // queued request clears.
1176 QueueRequestComplete(type, &queued_request);
1178 scoped_ptr<base::Value> value(WaitForSingleResult(func.get()));
1179 std::string access_token;
1180 EXPECT_TRUE(value->GetAsString(&access_token));
1181 EXPECT_EQ(std::string(kAccessToken), access_token);
1182 EXPECT_FALSE(func->login_ui_shown());
1183 EXPECT_TRUE(func->scope_ui_shown());
1186 IN_PROC_BROWSER_TEST_F(GetAuthTokenFunctionTest, InteractiveQueueShutdown) {
1187 SignIn("primary@example.com");
1188 scoped_refptr<const Extension> extension(CreateExtension(CLIENT_ID | SCOPES));
1189 scoped_refptr<FakeGetAuthTokenFunction> func(new FakeGetAuthTokenFunction());
1190 func->set_extension(extension.get());
1192 // Create a fake request to block the queue.
1193 MockQueuedMintRequest queued_request;
1194 IdentityMintRequestQueue::MintType type =
1195 IdentityMintRequestQueue::MINT_TYPE_INTERACTIVE;
1197 EXPECT_CALL(queued_request, StartMintToken(type)).Times(1);
1198 QueueRequestStart(type, &queued_request);
1200 // The real request will start processing, but wait in the queue behind
1202 func->set_mint_token_result(TestOAuth2MintTokenFlow::ISSUE_ADVICE_SUCCESS);
1203 RunFunctionAsync(func.get(), "[{\"interactive\": true}]");
1204 // Verify that we have fetched the login token and run the first flow.
1205 testing::Mock::VerifyAndClearExpectations(func.get());
1206 EXPECT_FALSE(func->scope_ui_shown());
1208 // After the request is canceled, the function will complete.
1210 EXPECT_EQ(std::string(errors::kCanceled), WaitForError(func.get()));
1211 EXPECT_FALSE(func->login_ui_shown());
1212 EXPECT_FALSE(func->scope_ui_shown());
1214 QueueRequestComplete(type, &queued_request);
1217 IN_PROC_BROWSER_TEST_F(GetAuthTokenFunctionTest, NoninteractiveShutdown) {
1218 SignIn("primary@example.com");
1219 scoped_refptr<const Extension> extension(CreateExtension(CLIENT_ID | SCOPES));
1220 scoped_refptr<FakeGetAuthTokenFunction> func(new FakeGetAuthTokenFunction());
1221 func->set_extension(extension.get());
1223 scoped_ptr<TestHangOAuth2MintTokenFlow> flow(
1224 new TestHangOAuth2MintTokenFlow());
1225 func->set_mint_token_flow(flow.PassAs<OAuth2MintTokenFlow>());
1226 RunFunctionAsync(func.get(), "[{\"interactive\": false}]");
1228 // After the request is canceled, the function will complete.
1230 EXPECT_EQ(std::string(errors::kCanceled), WaitForError(func.get()));
1233 IN_PROC_BROWSER_TEST_F(GetAuthTokenFunctionTest,
1234 InteractiveQueuedNoninteractiveFails) {
1235 SignIn("primary@example.com");
1236 scoped_refptr<const Extension> extension(CreateExtension(CLIENT_ID | SCOPES));
1237 scoped_refptr<FakeGetAuthTokenFunction> func(new FakeGetAuthTokenFunction());
1238 func->set_extension(extension.get());
1240 // Create a fake request to block the interactive queue.
1241 MockQueuedMintRequest queued_request;
1242 IdentityMintRequestQueue::MintType type =
1243 IdentityMintRequestQueue::MINT_TYPE_INTERACTIVE;
1245 EXPECT_CALL(queued_request, StartMintToken(type)).Times(1);
1246 QueueRequestStart(type, &queued_request);
1248 // Non-interactive requests fail without hitting GAIA, because a
1249 // consent UI is known to be up.
1250 std::string error = utils::RunFunctionAndReturnError(
1251 func.get(), "[{}]", browser());
1252 EXPECT_EQ(std::string(errors::kNoGrant), error);
1253 EXPECT_FALSE(func->login_ui_shown());
1254 EXPECT_FALSE(func->scope_ui_shown());
1256 QueueRequestComplete(type, &queued_request);
1259 IN_PROC_BROWSER_TEST_F(GetAuthTokenFunctionTest,
1260 NonInteractiveCacheHit) {
1261 SignIn("primary@example.com");
1262 scoped_refptr<const Extension> extension(CreateExtension(CLIENT_ID | SCOPES));
1263 scoped_refptr<FakeGetAuthTokenFunction> func(new FakeGetAuthTokenFunction());
1264 func->set_extension(extension.get());
1266 // pre-populate the cache with a token
1267 IdentityTokenCacheValue token(kAccessToken,
1268 base::TimeDelta::FromSeconds(3600));
1269 SetCachedToken(token);
1271 // Get a token. Should not require a GAIA request.
1272 scoped_ptr<base::Value> value(utils::RunFunctionAndReturnSingleResult(
1273 func.get(), "[{}]", browser()));
1274 std::string access_token;
1275 EXPECT_TRUE(value->GetAsString(&access_token));
1276 EXPECT_EQ(std::string(kAccessToken), access_token);
1277 EXPECT_FALSE(func->login_ui_shown());
1278 EXPECT_FALSE(func->scope_ui_shown());
1281 IN_PROC_BROWSER_TEST_F(GetAuthTokenFunctionTest,
1282 NonInteractiveIssueAdviceCacheHit) {
1283 SignIn("primary@example.com");
1284 scoped_refptr<const Extension> extension(CreateExtension(CLIENT_ID | SCOPES));
1285 scoped_refptr<FakeGetAuthTokenFunction> func(new FakeGetAuthTokenFunction());
1286 func->set_extension(extension.get());
1288 // pre-populate the cache with advice
1289 IssueAdviceInfo info;
1290 IdentityTokenCacheValue token(info);
1291 SetCachedToken(token);
1293 // Should return an error without a GAIA request.
1294 std::string error = utils::RunFunctionAndReturnError(
1295 func.get(), "[{}]", browser());
1296 EXPECT_EQ(std::string(errors::kNoGrant), error);
1297 EXPECT_FALSE(func->login_ui_shown());
1298 EXPECT_FALSE(func->scope_ui_shown());
1301 IN_PROC_BROWSER_TEST_F(GetAuthTokenFunctionTest,
1302 InteractiveCacheHit) {
1303 SignIn("primary@example.com");
1304 scoped_refptr<const Extension> extension(CreateExtension(CLIENT_ID | SCOPES));
1305 scoped_refptr<FakeGetAuthTokenFunction> func(new FakeGetAuthTokenFunction());
1306 func->set_extension(extension.get());
1308 // Create a fake request to block the queue.
1309 MockQueuedMintRequest queued_request;
1310 IdentityMintRequestQueue::MintType type =
1311 IdentityMintRequestQueue::MINT_TYPE_INTERACTIVE;
1313 EXPECT_CALL(queued_request, StartMintToken(type)).Times(1);
1314 QueueRequestStart(type, &queued_request);
1316 // The real request will start processing, but wait in the queue behind
1318 func->set_mint_token_result(TestOAuth2MintTokenFlow::ISSUE_ADVICE_SUCCESS);
1319 RunFunctionAsync(func.get(), "[{\"interactive\": true}]");
1321 // Populate the cache with a token while the request is blocked.
1322 IdentityTokenCacheValue token(kAccessToken,
1323 base::TimeDelta::FromSeconds(3600));
1324 SetCachedToken(token);
1326 // When we wake up the request, it returns the cached token without
1327 // displaying a UI, or hitting GAIA.
1329 QueueRequestComplete(type, &queued_request);
1331 scoped_ptr<base::Value> value(WaitForSingleResult(func.get()));
1332 std::string access_token;
1333 EXPECT_TRUE(value->GetAsString(&access_token));
1334 EXPECT_EQ(std::string(kAccessToken), access_token);
1335 EXPECT_FALSE(func->login_ui_shown());
1336 EXPECT_FALSE(func->scope_ui_shown());
1339 IN_PROC_BROWSER_TEST_F(GetAuthTokenFunctionTest,
1340 LoginInvalidatesTokenCache) {
1341 scoped_refptr<FakeGetAuthTokenFunction> func(new FakeGetAuthTokenFunction());
1342 scoped_refptr<const Extension> extension(CreateExtension(CLIENT_ID | SCOPES));
1343 func->set_extension(extension.get());
1345 // pre-populate the cache with a token
1346 IdentityTokenCacheValue token(kAccessToken,
1347 base::TimeDelta::FromSeconds(3600));
1348 SetCachedToken(token);
1350 // Because the user is not signed in, the token will be removed,
1351 // and we'll hit GAIA for new tokens.
1352 func->set_login_ui_result(true);
1353 func->set_mint_token_result(TestOAuth2MintTokenFlow::ISSUE_ADVICE_SUCCESS);
1355 scoped_ptr<base::Value> value(utils::RunFunctionAndReturnSingleResult(
1356 func.get(), "[{\"interactive\": true}]", browser()));
1357 std::string access_token;
1358 EXPECT_TRUE(value->GetAsString(&access_token));
1359 EXPECT_EQ(std::string(kAccessToken), access_token);
1360 EXPECT_TRUE(func->login_ui_shown());
1361 EXPECT_TRUE(func->scope_ui_shown());
1362 EXPECT_EQ(IdentityTokenCacheValue::CACHE_STATUS_TOKEN,
1363 GetCachedToken(std::string()).status());
1366 IN_PROC_BROWSER_TEST_F(GetAuthTokenFunctionTest, ComponentWithChromeClientId) {
1367 scoped_refptr<FakeGetAuthTokenFunction> func(new FakeGetAuthTokenFunction());
1368 scoped_refptr<const Extension> extension(
1369 CreateExtension(SCOPES | AS_COMPONENT));
1370 func->set_extension(extension.get());
1371 const OAuth2Info& oauth2_info = OAuth2Info::GetOAuth2Info(extension.get());
1372 EXPECT_TRUE(oauth2_info.client_id.empty());
1373 EXPECT_FALSE(func->GetOAuth2ClientId().empty());
1374 EXPECT_NE("client1", func->GetOAuth2ClientId());
1377 IN_PROC_BROWSER_TEST_F(GetAuthTokenFunctionTest, ComponentWithNormalClientId) {
1378 scoped_refptr<FakeGetAuthTokenFunction> func(new FakeGetAuthTokenFunction());
1379 scoped_refptr<const Extension> extension(
1380 CreateExtension(CLIENT_ID | SCOPES | AS_COMPONENT));
1381 func->set_extension(extension.get());
1382 EXPECT_EQ("client1", func->GetOAuth2ClientId());
1385 IN_PROC_BROWSER_TEST_F(GetAuthTokenFunctionTest, MultiDefaultUser) {
1386 SignIn("primary@example.com");
1387 SetAccountState(CreateIds("primary@example.com", "1"), true);
1388 SetAccountState(CreateIds("secondary@example.com", "2"), true);
1390 scoped_refptr<FakeGetAuthTokenFunction> func(new FakeGetAuthTokenFunction());
1391 scoped_refptr<const Extension> extension(CreateExtension(CLIENT_ID | SCOPES));
1392 func->set_extension(extension.get());
1393 func->set_auto_login_access_token(false);
1394 func->set_mint_token_result(TestOAuth2MintTokenFlow::MINT_TOKEN_SUCCESS);
1396 RunFunctionAsync(func.get(), "[{}]");
1398 IssueLoginAccessTokenForAccount("primary@example.com");
1400 scoped_ptr<base::Value> value(WaitForSingleResult(func.get()));
1401 std::string access_token;
1402 EXPECT_TRUE(value->GetAsString(&access_token));
1403 EXPECT_EQ(std::string(kAccessToken), access_token);
1404 EXPECT_EQ(IdentityTokenCacheValue::CACHE_STATUS_TOKEN,
1405 GetCachedToken(std::string()).status());
1406 EXPECT_EQ("access_token-primary@example.com", func->login_access_token());
1409 IN_PROC_BROWSER_TEST_F(GetAuthTokenFunctionTest, MultiPrimaryUser) {
1410 SignIn("primary@example.com");
1411 IssueLoginRefreshTokenForAccount("secondary@example.com");
1412 SetAccountState(CreateIds("primary@example.com", "1"), true);
1413 SetAccountState(CreateIds("secondary@example.com", "2"), true);
1415 scoped_refptr<FakeGetAuthTokenFunction> func(new FakeGetAuthTokenFunction());
1416 scoped_refptr<const Extension> extension(CreateExtension(CLIENT_ID | SCOPES));
1417 func->set_extension(extension.get());
1418 func->set_auto_login_access_token(false);
1419 func->set_mint_token_result(TestOAuth2MintTokenFlow::MINT_TOKEN_SUCCESS);
1421 RunFunctionAsync(func.get(), "[{\"account\": { \"id\": \"1\" } }]");
1423 IssueLoginAccessTokenForAccount("primary@example.com");
1425 scoped_ptr<base::Value> value(WaitForSingleResult(func.get()));
1426 std::string access_token;
1427 EXPECT_TRUE(value->GetAsString(&access_token));
1428 EXPECT_EQ(std::string(kAccessToken), access_token);
1429 EXPECT_EQ(IdentityTokenCacheValue::CACHE_STATUS_TOKEN,
1430 GetCachedToken(std::string()).status());
1431 EXPECT_EQ("access_token-primary@example.com", func->login_access_token());
1434 IN_PROC_BROWSER_TEST_F(GetAuthTokenFunctionTest, MultiSecondaryUser) {
1435 SignIn("primary@example.com");
1436 IssueLoginRefreshTokenForAccount("secondary@example.com");
1437 SetAccountState(CreateIds("primary@example.com", "1"), true);
1438 SetAccountState(CreateIds("secondary@example.com", "2"), true);
1440 scoped_refptr<FakeGetAuthTokenFunction> func(new FakeGetAuthTokenFunction());
1441 scoped_refptr<const Extension> extension(CreateExtension(CLIENT_ID | SCOPES));
1442 func->set_extension(extension.get());
1443 func->set_auto_login_access_token(false);
1444 func->set_mint_token_result(TestOAuth2MintTokenFlow::MINT_TOKEN_SUCCESS);
1446 RunFunctionAsync(func.get(), "[{\"account\": { \"id\": \"2\" } }]");
1448 IssueLoginAccessTokenForAccount("secondary@example.com");
1450 scoped_ptr<base::Value> value(WaitForSingleResult(func.get()));
1451 std::string access_token;
1452 EXPECT_TRUE(value->GetAsString(&access_token));
1453 EXPECT_EQ(std::string(kAccessToken), access_token);
1454 EXPECT_EQ(IdentityTokenCacheValue::CACHE_STATUS_TOKEN,
1455 GetCachedToken("secondary@example.com").status());
1456 EXPECT_EQ("access_token-secondary@example.com", func->login_access_token());
1459 IN_PROC_BROWSER_TEST_F(GetAuthTokenFunctionTest, MultiUnknownUser) {
1460 SignIn("primary@example.com");
1461 IssueLoginRefreshTokenForAccount("secondary@example.com");
1462 SetAccountState(CreateIds("primary@example.com", "1"), true);
1463 SetAccountState(CreateIds("secondary@example.com", "2"), true);
1465 scoped_refptr<FakeGetAuthTokenFunction> func(new FakeGetAuthTokenFunction());
1466 scoped_refptr<const Extension> extension(CreateExtension(CLIENT_ID | SCOPES));
1467 func->set_extension(extension.get());
1468 func->set_auto_login_access_token(false);
1470 std::string error = utils::RunFunctionAndReturnError(
1471 func.get(), "[{\"account\": { \"id\": \"3\" } }]", browser());
1472 EXPECT_EQ(std::string(errors::kUserNotSignedIn), error);
1475 IN_PROC_BROWSER_TEST_F(GetAuthTokenFunctionTest,
1476 MultiSecondaryNonInteractiveMintFailure) {
1477 SignIn("primary@example.com");
1478 IssueLoginRefreshTokenForAccount("secondary@example.com");
1479 SetAccountState(CreateIds("primary@example.com", "1"), true);
1480 SetAccountState(CreateIds("secondary@example.com", "2"), true);
1482 scoped_refptr<FakeGetAuthTokenFunction> func(new FakeGetAuthTokenFunction());
1483 func->set_extension(CreateExtension(CLIENT_ID | SCOPES));
1484 func->set_mint_token_result(TestOAuth2MintTokenFlow::MINT_TOKEN_FAILURE);
1485 std::string error = utils::RunFunctionAndReturnError(
1486 func.get(), "[{\"account\": { \"id\": \"2\" } }]", browser());
1487 EXPECT_TRUE(StartsWithASCII(error, errors::kAuthFailure, false));
1488 EXPECT_FALSE(func->login_ui_shown());
1489 EXPECT_FALSE(func->scope_ui_shown());
1492 IN_PROC_BROWSER_TEST_F(GetAuthTokenFunctionTest,
1493 MultiSecondaryNonInteractiveLoginAccessTokenFailure) {
1494 SignIn("primary@example.com");
1495 IssueLoginRefreshTokenForAccount("secondary@example.com");
1496 SetAccountState(CreateIds("primary@example.com", "1"), true);
1497 SetAccountState(CreateIds("secondary@example.com", "2"), true);
1499 scoped_refptr<FakeGetAuthTokenFunction> func(new FakeGetAuthTokenFunction());
1500 func->set_extension(CreateExtension(CLIENT_ID | SCOPES));
1501 func->set_login_access_token_result(false);
1502 std::string error = utils::RunFunctionAndReturnError(
1503 func.get(), "[{\"account\": { \"id\": \"2\" } }]", browser());
1504 EXPECT_TRUE(StartsWithASCII(error, errors::kAuthFailure, false));
1507 IN_PROC_BROWSER_TEST_F(GetAuthTokenFunctionTest,
1508 MultiSecondaryInteractiveApprovalAborted) {
1509 SignIn("primary@example.com");
1510 IssueLoginRefreshTokenForAccount("secondary@example.com");
1511 SetAccountState(CreateIds("primary@example.com", "1"), true);
1512 SetAccountState(CreateIds("secondary@example.com", "2"), true);
1514 scoped_refptr<FakeGetAuthTokenFunction> func(new FakeGetAuthTokenFunction());
1515 func->set_extension(CreateExtension(CLIENT_ID | SCOPES));
1516 func->set_mint_token_result(TestOAuth2MintTokenFlow::ISSUE_ADVICE_SUCCESS);
1517 func->set_scope_ui_failure(GaiaWebAuthFlow::WINDOW_CLOSED);
1518 std::string error = utils::RunFunctionAndReturnError(
1520 "[{\"account\": { \"id\": \"2\" }, \"interactive\": true}]",
1522 EXPECT_EQ(std::string(errors::kUserRejected), error);
1523 EXPECT_FALSE(func->login_ui_shown());
1524 EXPECT_TRUE(func->scope_ui_shown());
1527 IN_PROC_BROWSER_TEST_F(GetAuthTokenFunctionTest, ScopesDefault) {
1528 SignIn("primary@example.com");
1529 scoped_refptr<FakeGetAuthTokenFunction> func(new FakeGetAuthTokenFunction());
1530 scoped_refptr<const Extension> extension(CreateExtension(CLIENT_ID | SCOPES));
1531 func->set_extension(extension.get());
1532 func->set_mint_token_result(TestOAuth2MintTokenFlow::MINT_TOKEN_SUCCESS);
1533 scoped_ptr<base::Value> value(
1534 utils::RunFunctionAndReturnSingleResult(func.get(), "[{}]", browser()));
1535 std::string access_token;
1536 EXPECT_TRUE(value->GetAsString(&access_token));
1537 EXPECT_EQ(std::string(kAccessToken), access_token);
1539 const ExtensionTokenKey* token_key = func->GetExtensionTokenKeyForTest();
1540 EXPECT_EQ(2ul, token_key->scopes.size());
1541 EXPECT_TRUE(ContainsKey(token_key->scopes, "scope1"));
1542 EXPECT_TRUE(ContainsKey(token_key->scopes, "scope2"));
1545 IN_PROC_BROWSER_TEST_F(GetAuthTokenFunctionTest, ScopesEmpty) {
1546 scoped_refptr<FakeGetAuthTokenFunction> func(new FakeGetAuthTokenFunction());
1547 scoped_refptr<const Extension> extension(CreateExtension(CLIENT_ID | SCOPES));
1548 func->set_extension(extension.get());
1550 std::string error(utils::RunFunctionAndReturnError(
1551 func.get(), "[{\"scopes\": []}]", browser()));
1553 EXPECT_EQ(errors::kInvalidScopes, error);
1556 IN_PROC_BROWSER_TEST_F(GetAuthTokenFunctionTest, ScopesEmail) {
1557 SignIn("primary@example.com");
1558 scoped_refptr<FakeGetAuthTokenFunction> func(new FakeGetAuthTokenFunction());
1559 scoped_refptr<const Extension> extension(CreateExtension(CLIENT_ID | SCOPES));
1560 func->set_extension(extension.get());
1561 func->set_mint_token_result(TestOAuth2MintTokenFlow::MINT_TOKEN_SUCCESS);
1562 scoped_ptr<base::Value> value(utils::RunFunctionAndReturnSingleResult(
1563 func.get(), "[{\"scopes\": [\"email\"]}]", browser()));
1564 std::string access_token;
1565 EXPECT_TRUE(value->GetAsString(&access_token));
1566 EXPECT_EQ(std::string(kAccessToken), access_token);
1568 const ExtensionTokenKey* token_key = func->GetExtensionTokenKeyForTest();
1569 EXPECT_EQ(1ul, token_key->scopes.size());
1570 EXPECT_TRUE(ContainsKey(token_key->scopes, "email"));
1573 IN_PROC_BROWSER_TEST_F(GetAuthTokenFunctionTest, ScopesEmailFooBar) {
1574 SignIn("primary@example.com");
1575 scoped_refptr<FakeGetAuthTokenFunction> func(new FakeGetAuthTokenFunction());
1576 scoped_refptr<const Extension> extension(CreateExtension(CLIENT_ID | SCOPES));
1577 func->set_extension(extension.get());
1578 func->set_mint_token_result(TestOAuth2MintTokenFlow::MINT_TOKEN_SUCCESS);
1579 scoped_ptr<base::Value> value(utils::RunFunctionAndReturnSingleResult(
1580 func.get(), "[{\"scopes\": [\"email\", \"foo\", \"bar\"]}]", browser()));
1581 std::string access_token;
1582 EXPECT_TRUE(value->GetAsString(&access_token));
1583 EXPECT_EQ(std::string(kAccessToken), access_token);
1585 const ExtensionTokenKey* token_key = func->GetExtensionTokenKeyForTest();
1586 EXPECT_EQ(3ul, token_key->scopes.size());
1587 EXPECT_TRUE(ContainsKey(token_key->scopes, "email"));
1588 EXPECT_TRUE(ContainsKey(token_key->scopes, "foo"));
1589 EXPECT_TRUE(ContainsKey(token_key->scopes, "bar"));
1592 class RemoveCachedAuthTokenFunctionTest : public ExtensionBrowserTest {
1594 bool InvalidateDefaultToken() {
1595 scoped_refptr<IdentityRemoveCachedAuthTokenFunction> func(
1596 new IdentityRemoveCachedAuthTokenFunction);
1597 func->set_extension(utils::CreateEmptyExtension(kExtensionId).get());
1598 return utils::RunFunction(
1600 std::string("[{\"token\": \"") + kAccessToken + "\"}]",
1602 extension_function_test_utils::NONE);
1605 IdentityAPI* id_api() {
1606 return IdentityAPI::GetFactoryInstance()->Get(browser()->profile());
1609 void SetCachedToken(IdentityTokenCacheValue& token_data) {
1610 ExtensionTokenKey key(extensions::id_util::GenerateId(kExtensionId),
1612 std::set<std::string>());
1613 id_api()->SetCachedToken(key, token_data);
1616 const IdentityTokenCacheValue& GetCachedToken() {
1617 return id_api()->GetCachedToken(
1618 ExtensionTokenKey(extensions::id_util::GenerateId(kExtensionId),
1620 std::set<std::string>()));
1624 IN_PROC_BROWSER_TEST_F(RemoveCachedAuthTokenFunctionTest, NotFound) {
1625 EXPECT_TRUE(InvalidateDefaultToken());
1626 EXPECT_EQ(IdentityTokenCacheValue::CACHE_STATUS_NOTFOUND,
1627 GetCachedToken().status());
1630 IN_PROC_BROWSER_TEST_F(RemoveCachedAuthTokenFunctionTest, Advice) {
1631 IssueAdviceInfo info;
1632 IdentityTokenCacheValue advice(info);
1633 SetCachedToken(advice);
1634 EXPECT_TRUE(InvalidateDefaultToken());
1635 EXPECT_EQ(IdentityTokenCacheValue::CACHE_STATUS_ADVICE,
1636 GetCachedToken().status());
1639 IN_PROC_BROWSER_TEST_F(RemoveCachedAuthTokenFunctionTest, NonMatchingToken) {
1640 IdentityTokenCacheValue token("non_matching_token",
1641 base::TimeDelta::FromSeconds(3600));
1642 SetCachedToken(token);
1643 EXPECT_TRUE(InvalidateDefaultToken());
1644 EXPECT_EQ(IdentityTokenCacheValue::CACHE_STATUS_TOKEN,
1645 GetCachedToken().status());
1646 EXPECT_EQ("non_matching_token", GetCachedToken().token());
1649 IN_PROC_BROWSER_TEST_F(RemoveCachedAuthTokenFunctionTest, MatchingToken) {
1650 IdentityTokenCacheValue token(kAccessToken,
1651 base::TimeDelta::FromSeconds(3600));
1652 SetCachedToken(token);
1653 EXPECT_EQ(IdentityTokenCacheValue::CACHE_STATUS_TOKEN,
1654 GetCachedToken().status());
1655 EXPECT_TRUE(InvalidateDefaultToken());
1656 EXPECT_EQ(IdentityTokenCacheValue::CACHE_STATUS_NOTFOUND,
1657 GetCachedToken().status());
1660 class LaunchWebAuthFlowFunctionTest : public AsyncExtensionBrowserTest {
1662 virtual void SetUpCommandLine(CommandLine* command_line) OVERRIDE {
1663 AsyncExtensionBrowserTest::SetUpCommandLine(command_line);
1664 // Reduce performance test variance by disabling background networking.
1665 command_line->AppendSwitch(switches::kDisableBackgroundNetworking);
1669 IN_PROC_BROWSER_TEST_F(LaunchWebAuthFlowFunctionTest, UserCloseWindow) {
1670 net::SpawnedTestServer https_server(
1671 net::SpawnedTestServer::TYPE_HTTPS,
1672 net::SpawnedTestServer::kLocalhost,
1673 base::FilePath(FILE_PATH_LITERAL(
1674 "chrome/test/data/extensions/api_test/identity")));
1675 ASSERT_TRUE(https_server.Start());
1676 GURL auth_url(https_server.GetURL("files/interaction_required.html"));
1678 scoped_refptr<IdentityLaunchWebAuthFlowFunction> function(
1679 new IdentityLaunchWebAuthFlowFunction());
1680 scoped_refptr<Extension> empty_extension(
1681 utils::CreateEmptyExtension());
1682 function->set_extension(empty_extension.get());
1684 WaitForGURLAndCloseWindow popup_observer(auth_url);
1686 std::string args = "[{\"interactive\": true, \"url\": \"" +
1687 auth_url.spec() + "\"}]";
1688 RunFunctionAsync(function.get(), args);
1690 popup_observer.Wait();
1691 popup_observer.CloseEmbedderWebContents();
1693 EXPECT_EQ(std::string(errors::kUserRejected), WaitForError(function.get()));
1696 IN_PROC_BROWSER_TEST_F(LaunchWebAuthFlowFunctionTest, InteractionRequired) {
1697 net::SpawnedTestServer https_server(
1698 net::SpawnedTestServer::TYPE_HTTPS,
1699 net::SpawnedTestServer::kLocalhost,
1700 base::FilePath(FILE_PATH_LITERAL(
1701 "chrome/test/data/extensions/api_test/identity")));
1702 ASSERT_TRUE(https_server.Start());
1703 GURL auth_url(https_server.GetURL("files/interaction_required.html"));
1705 scoped_refptr<IdentityLaunchWebAuthFlowFunction> function(
1706 new IdentityLaunchWebAuthFlowFunction());
1707 scoped_refptr<Extension> empty_extension(
1708 utils::CreateEmptyExtension());
1709 function->set_extension(empty_extension.get());
1711 std::string args = "[{\"interactive\": false, \"url\": \"" +
1712 auth_url.spec() + "\"}]";
1714 utils::RunFunctionAndReturnError(function.get(), args, browser());
1716 EXPECT_EQ(std::string(errors::kInteractionRequired), error);
1719 IN_PROC_BROWSER_TEST_F(LaunchWebAuthFlowFunctionTest, LoadFailed) {
1720 net::SpawnedTestServer https_server(
1721 net::SpawnedTestServer::TYPE_HTTPS,
1722 net::SpawnedTestServer::kLocalhost,
1723 base::FilePath(FILE_PATH_LITERAL(
1724 "chrome/test/data/extensions/api_test/identity")));
1725 ASSERT_TRUE(https_server.Start());
1726 GURL auth_url(https_server.GetURL("files/five_hundred.html"));
1728 scoped_refptr<IdentityLaunchWebAuthFlowFunction> function(
1729 new IdentityLaunchWebAuthFlowFunction());
1730 scoped_refptr<Extension> empty_extension(
1731 utils::CreateEmptyExtension());
1732 function->set_extension(empty_extension.get());
1734 std::string args = "[{\"interactive\": true, \"url\": \"" +
1735 auth_url.spec() + "\"}]";
1737 utils::RunFunctionAndReturnError(function.get(), args, browser());
1739 EXPECT_EQ(std::string(errors::kPageLoadFailure), error);
1742 IN_PROC_BROWSER_TEST_F(LaunchWebAuthFlowFunctionTest, NonInteractiveSuccess) {
1743 #if defined(OS_WIN) && defined(USE_ASH)
1744 // Disable this test in Metro+Ash for now (http://crbug.com/262796).
1745 if (CommandLine::ForCurrentProcess()->HasSwitch(switches::kAshBrowserTests))
1749 scoped_refptr<IdentityLaunchWebAuthFlowFunction> function(
1750 new IdentityLaunchWebAuthFlowFunction());
1751 scoped_refptr<Extension> empty_extension(
1752 utils::CreateEmptyExtension());
1753 function->set_extension(empty_extension.get());
1755 function->InitFinalRedirectURLPrefixForTest("abcdefghij");
1756 scoped_ptr<base::Value> value(utils::RunFunctionAndReturnSingleResult(
1758 "[{\"interactive\": false,"
1759 "\"url\": \"https://abcdefghij.chromiumapp.org/callback#test\"}]",
1763 EXPECT_TRUE(value->GetAsString(&url));
1764 EXPECT_EQ(std::string("https://abcdefghij.chromiumapp.org/callback#test"),
1768 IN_PROC_BROWSER_TEST_F(
1769 LaunchWebAuthFlowFunctionTest, InteractiveFirstNavigationSuccess) {
1770 #if defined(OS_WIN) && defined(USE_ASH)
1771 // Disable this test in Metro+Ash for now (http://crbug.com/262796).
1772 if (CommandLine::ForCurrentProcess()->HasSwitch(switches::kAshBrowserTests))
1776 scoped_refptr<IdentityLaunchWebAuthFlowFunction> function(
1777 new IdentityLaunchWebAuthFlowFunction());
1778 scoped_refptr<Extension> empty_extension(
1779 utils::CreateEmptyExtension());
1780 function->set_extension(empty_extension.get());
1782 function->InitFinalRedirectURLPrefixForTest("abcdefghij");
1783 scoped_ptr<base::Value> value(utils::RunFunctionAndReturnSingleResult(
1785 "[{\"interactive\": true,"
1786 "\"url\": \"https://abcdefghij.chromiumapp.org/callback#test\"}]",
1790 EXPECT_TRUE(value->GetAsString(&url));
1791 EXPECT_EQ(std::string("https://abcdefghij.chromiumapp.org/callback#test"),
1795 IN_PROC_BROWSER_TEST_F(LaunchWebAuthFlowFunctionTest,
1796 DISABLED_InteractiveSecondNavigationSuccess) {
1797 net::SpawnedTestServer https_server(
1798 net::SpawnedTestServer::TYPE_HTTPS,
1799 net::SpawnedTestServer::kLocalhost,
1800 base::FilePath(FILE_PATH_LITERAL(
1801 "chrome/test/data/extensions/api_test/identity")));
1802 ASSERT_TRUE(https_server.Start());
1803 GURL auth_url(https_server.GetURL("files/redirect_to_chromiumapp.html"));
1805 scoped_refptr<IdentityLaunchWebAuthFlowFunction> function(
1806 new IdentityLaunchWebAuthFlowFunction());
1807 scoped_refptr<Extension> empty_extension(
1808 utils::CreateEmptyExtension());
1809 function->set_extension(empty_extension.get());
1811 function->InitFinalRedirectURLPrefixForTest("abcdefghij");
1812 std::string args = "[{\"interactive\": true, \"url\": \"" +
1813 auth_url.spec() + "\"}]";
1814 scoped_ptr<base::Value> value(
1815 utils::RunFunctionAndReturnSingleResult(function.get(), args, browser()));
1818 EXPECT_TRUE(value->GetAsString(&url));
1819 EXPECT_EQ(std::string("https://abcdefghij.chromiumapp.org/callback#test"),
1823 } // namespace extensions
1825 // Tests the chrome.identity API implemented by custom JS bindings .
1826 IN_PROC_BROWSER_TEST_F(ExtensionApiTest, ChromeIdentityJsBindings) {
1827 ASSERT_TRUE(RunExtensionTest("identity/js_bindings")) << message_;