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/test/base/in_process_browser_test.h"
34 #include "chrome/test/base/test_switches.h"
35 #include "components/crx_file/id_util.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/manifest_handlers/oauth2_manifest_handler.h"
44 #include "extensions/common/test_util.h"
45 #include "google_apis/gaia/google_service_auth_error.h"
46 #include "google_apis/gaia/oauth2_mint_token_flow.h"
47 #include "net/test/spawned_test_server/spawned_test_server.h"
48 #include "testing/gmock/include/gmock/gmock.h"
49 #include "testing/gtest/include/gtest/gtest.h"
53 using testing::Return;
54 using testing::ReturnRef;
56 namespace extensions {
60 namespace errors = identity_constants;
61 namespace utils = extension_function_test_utils;
63 static const char kAccessToken[] = "auth_token";
64 static const char kExtensionId[] = "ext_id";
66 // This helps us be able to wait until an UIThreadExtensionFunction calls
68 class SendResponseDelegate
69 : public UIThreadExtensionFunction::DelegateForTests {
71 SendResponseDelegate() : should_post_quit_(false) {}
73 virtual ~SendResponseDelegate() {}
75 void set_should_post_quit(bool should_quit) {
76 should_post_quit_ = should_quit;
80 return response_.get() != NULL;
84 EXPECT_TRUE(HasResponse());
85 return *response_.get();
88 void OnSendResponse(UIThreadExtensionFunction* function,
90 bool bad_message) override {
91 ASSERT_FALSE(bad_message);
92 ASSERT_FALSE(HasResponse());
93 response_.reset(new bool);
95 if (should_post_quit_) {
96 base::MessageLoopForUI::current()->Quit();
101 scoped_ptr<bool> response_;
102 bool should_post_quit_;
105 class AsyncExtensionBrowserTest : public ExtensionBrowserTest {
107 // Asynchronous function runner allows tests to manipulate the browser window
108 // after the call happens.
109 void RunFunctionAsync(
110 UIThreadExtensionFunction* function,
111 const std::string& args) {
112 response_delegate_.reset(new SendResponseDelegate);
113 function->set_test_delegate(response_delegate_.get());
114 scoped_ptr<base::ListValue> parsed_args(utils::ParseList(args));
115 EXPECT_TRUE(parsed_args.get()) <<
116 "Could not parse extension function arguments: " << args;
117 function->SetArgs(parsed_args.get());
119 if (!function->extension()) {
120 scoped_refptr<Extension> empty_extension(
121 test_util::CreateEmptyExtension());
122 function->set_extension(empty_extension.get());
125 function->set_browser_context(browser()->profile());
126 function->set_has_callback(true);
127 function->Run()->Execute();
130 std::string WaitForError(UIThreadExtensionFunction* function) {
131 RunMessageLoopUntilResponse();
132 EXPECT_FALSE(function->GetResultList()) << "Did not expect a result";
133 return function->GetError();
136 base::Value* WaitForSingleResult(UIThreadExtensionFunction* function) {
137 RunMessageLoopUntilResponse();
138 EXPECT_TRUE(function->GetError().empty()) << "Unexpected error: "
139 << function->GetError();
140 const base::Value* single_result = NULL;
141 if (function->GetResultList() != NULL &&
142 function->GetResultList()->Get(0, &single_result)) {
143 return single_result->DeepCopy();
149 void RunMessageLoopUntilResponse() {
150 // If the RunAsync of |function| didn't already call SendResponse, run the
151 // message loop until they do.
152 if (!response_delegate_->HasResponse()) {
153 response_delegate_->set_should_post_quit(true);
154 content::RunMessageLoop();
156 EXPECT_TRUE(response_delegate_->HasResponse());
159 scoped_ptr<SendResponseDelegate> response_delegate_;
162 class TestHangOAuth2MintTokenFlow : public OAuth2MintTokenFlow {
164 TestHangOAuth2MintTokenFlow()
165 : OAuth2MintTokenFlow(NULL, OAuth2MintTokenFlow::Parameters()) {}
167 void Start(net::URLRequestContextGetter* context,
168 const std::string& access_token) override {
169 // Do nothing, simulating a hanging network call.
173 class TestOAuth2MintTokenFlow : public OAuth2MintTokenFlow {
176 ISSUE_ADVICE_SUCCESS,
179 MINT_TOKEN_BAD_CREDENTIALS,
180 MINT_TOKEN_SERVICE_ERROR
183 TestOAuth2MintTokenFlow(ResultType result,
184 OAuth2MintTokenFlow::Delegate* delegate)
185 : OAuth2MintTokenFlow(delegate, OAuth2MintTokenFlow::Parameters()),
187 delegate_(delegate) {}
189 void Start(net::URLRequestContextGetter* context,
190 const std::string& access_token) override {
192 case ISSUE_ADVICE_SUCCESS: {
193 IssueAdviceInfo info;
194 delegate_->OnIssueAdviceSuccess(info);
197 case MINT_TOKEN_SUCCESS: {
198 delegate_->OnMintTokenSuccess(kAccessToken, 3600);
201 case MINT_TOKEN_FAILURE: {
202 GoogleServiceAuthError error(GoogleServiceAuthError::CONNECTION_FAILED);
203 delegate_->OnMintTokenFailure(error);
206 case MINT_TOKEN_BAD_CREDENTIALS: {
207 GoogleServiceAuthError error(
208 GoogleServiceAuthError::INVALID_GAIA_CREDENTIALS);
209 delegate_->OnMintTokenFailure(error);
212 case MINT_TOKEN_SERVICE_ERROR: {
213 GoogleServiceAuthError error =
214 GoogleServiceAuthError::FromServiceError("invalid_scope");
215 delegate_->OnMintTokenFailure(error);
223 OAuth2MintTokenFlow::Delegate* delegate_;
226 // Waits for a specific GURL to generate a NOTIFICATION_LOAD_STOP event and
227 // saves a pointer to the window embedding the WebContents, which can be later
229 class WaitForGURLAndCloseWindow : public content::WindowedNotificationObserver {
231 explicit WaitForGURLAndCloseWindow(GURL url)
232 : WindowedNotificationObserver(
233 content::NOTIFICATION_LOAD_STOP,
234 content::NotificationService::AllSources()),
237 // NotificationObserver:
238 void Observe(int type,
239 const content::NotificationSource& source,
240 const content::NotificationDetails& details) override {
241 content::NavigationController* web_auth_flow_controller =
242 content::Source<content::NavigationController>(source).ptr();
243 content::WebContents* web_contents =
244 web_auth_flow_controller->GetWebContents();
246 if (web_contents->GetURL() == url_) {
247 // It is safe to keep the pointer here, because we know in a test, that
248 // the WebContents won't go away before CloseEmbedderWebContents is
249 // called. Don't copy this code to production.
250 GuestViewBase* guest = GuestViewBase::FromWebContents(web_contents);
251 embedder_web_contents_ = guest->embedder_web_contents();
252 // Condtionally invoke parent class so that Wait will not exit
253 // until the target URL arrives.
254 content::WindowedNotificationObserver::Observe(type, source, details);
258 // Closes the window embedding the WebContents. The action is separated from
259 // the Observe method to make sure the list of observers is not deleted,
260 // while some event is already being processed. (That causes ASAN failures.)
261 void CloseEmbedderWebContents() {
262 if (embedder_web_contents_)
263 embedder_web_contents_->Close();
268 content::WebContents* embedder_web_contents_;
273 class FakeGetAuthTokenFunction : public IdentityGetAuthTokenFunction {
275 FakeGetAuthTokenFunction()
276 : login_access_token_result_(true),
277 auto_login_access_token_(true),
278 login_ui_result_(true),
279 scope_ui_result_(true),
280 login_ui_shown_(false),
281 scope_ui_shown_(false) {}
283 void set_login_access_token_result(bool result) {
284 login_access_token_result_ = result;
287 void set_auto_login_access_token(bool automatic) {
288 auto_login_access_token_ = automatic;
291 void set_login_ui_result(bool result) { login_ui_result_ = result; }
293 void set_mint_token_flow(scoped_ptr<OAuth2MintTokenFlow> flow) {
297 void set_mint_token_result(TestOAuth2MintTokenFlow::ResultType result_type) {
299 make_scoped_ptr(new TestOAuth2MintTokenFlow(result_type, this)));
302 void set_scope_ui_failure(GaiaWebAuthFlow::Failure failure) {
303 scope_ui_result_ = false;
304 scope_ui_failure_ = failure;
307 void set_scope_ui_oauth_error(const std::string& oauth_error) {
308 scope_ui_result_ = false;
309 scope_ui_failure_ = GaiaWebAuthFlow::OAUTH_ERROR;
310 scope_ui_oauth_error_ = oauth_error;
313 bool login_ui_shown() const { return login_ui_shown_; }
315 bool scope_ui_shown() const { return scope_ui_shown_; }
317 std::string login_access_token() const { return login_access_token_; }
319 void StartLoginAccessTokenRequest() override {
320 if (auto_login_access_token_) {
321 if (login_access_token_result_) {
322 OnGetTokenSuccess(login_token_request_.get(),
324 base::Time::Now() + base::TimeDelta::FromHours(1LL));
326 GoogleServiceAuthError error(
327 GoogleServiceAuthError::INVALID_GAIA_CREDENTIALS);
328 OnGetTokenFailure(login_token_request_.get(), error);
331 // Make a request to the token service. The test now must tell
332 // the token service to issue an access token (or an error).
333 IdentityGetAuthTokenFunction::StartLoginAccessTokenRequest();
337 void ShowLoginPopup() override {
338 EXPECT_FALSE(login_ui_shown_);
339 login_ui_shown_ = true;
340 if (login_ui_result_)
346 void ShowOAuthApprovalDialog(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 void StartGaiaRequest(const std::string& login_access_token) override {
361 EXPECT_TRUE(login_access_token_.empty());
362 // Save the login token used in the mint token flow so tests can see
363 // what account was used.
364 login_access_token_ = login_access_token;
365 IdentityGetAuthTokenFunction::StartGaiaRequest(login_access_token);
368 OAuth2MintTokenFlow* CreateMintTokenFlow() override {
369 return flow_.release();
373 ~FakeGetAuthTokenFunction() override {}
374 bool login_access_token_result_;
375 bool auto_login_access_token_;
376 bool login_ui_result_;
377 bool scope_ui_result_;
378 GaiaWebAuthFlow::Failure scope_ui_failure_;
379 std::string scope_ui_oauth_error_;
380 bool login_ui_shown_;
381 bool scope_ui_shown_;
383 scoped_ptr<OAuth2MintTokenFlow> flow_;
385 std::string login_access_token_;
388 class MockQueuedMintRequest : public IdentityMintRequestQueue::Request {
390 MOCK_METHOD1(StartMintToken, void(IdentityMintRequestQueue::MintType));
393 gaia::AccountIds CreateIds(std::string email, std::string obfid) {
394 gaia::AccountIds ids;
395 ids.account_key = email;
401 class IdentityGetAccountsFunctionTest : public ExtensionBrowserTest {
402 void SetUpCommandLine(CommandLine* command_line) override {
403 ExtensionBrowserTest::SetUpCommandLine(command_line);
404 command_line->AppendSwitch(switches::kExtensionsMultiAccount);
408 void SetAccountState(gaia::AccountIds ids, bool is_signed_in) {
409 IdentityAPI::GetFactoryInstance()->Get(profile())->SetAccountStateForTest(
413 testing::AssertionResult ExpectGetAccounts(
414 const std::vector<std::string>& accounts) {
415 scoped_refptr<IdentityGetAccountsFunction> func(
416 new IdentityGetAccountsFunction);
417 func->set_extension(test_util::CreateEmptyExtension(kExtensionId).get());
418 if (!utils::RunFunction(
419 func.get(), std::string("[]"), browser(), utils::NONE)) {
420 return GenerateFailureResult(accounts, NULL)
421 << "getAccounts did not return a result.";
423 const base::ListValue* callback_arguments = func->GetResultList();
424 if (!callback_arguments)
425 return GenerateFailureResult(accounts, NULL) << "NULL result";
427 if (callback_arguments->GetSize() != 1) {
428 return GenerateFailureResult(accounts, NULL)
429 << "Expected 1 argument but got " << callback_arguments->GetSize();
432 const base::ListValue* results;
433 if (!callback_arguments->GetList(0, &results))
434 GenerateFailureResult(accounts, NULL) << "Result was not an array";
436 std::set<std::string> result_ids;
437 for (base::ListValue::const_iterator it = results->begin();
438 it != results->end();
440 scoped_ptr<api::identity::AccountInfo> info =
441 api::identity::AccountInfo::FromValue(**it);
443 result_ids.insert(info->id);
445 return GenerateFailureResult(accounts, results);
448 for (std::vector<std::string>::const_iterator it = accounts.begin();
449 it != accounts.end();
451 if (result_ids.find(*it) == result_ids.end())
452 return GenerateFailureResult(accounts, results);
455 return testing::AssertionResult(true);
458 testing::AssertionResult GenerateFailureResult(
459 const ::std::vector<std::string>& accounts,
460 const base::ListValue* results) {
461 testing::Message msg("Expected: ");
462 for (std::vector<std::string>::const_iterator it = accounts.begin();
463 it != accounts.end();
471 for (base::ListValue::const_iterator it = results->begin();
472 it != results->end();
474 scoped_ptr<api::identity::AccountInfo> info =
475 api::identity::AccountInfo::FromValue(**it);
477 msg << info->id << " ";
479 msg << *it << "<-" << (*it)->GetType() << " ";
483 return testing::AssertionFailure(msg);
487 IN_PROC_BROWSER_TEST_F(IdentityGetAccountsFunctionTest, MultiAccountOn) {
488 EXPECT_TRUE(switches::IsExtensionsMultiAccount());
491 IN_PROC_BROWSER_TEST_F(IdentityGetAccountsFunctionTest, NoneSignedIn) {
492 EXPECT_TRUE(ExpectGetAccounts(std::vector<std::string>()));
495 IN_PROC_BROWSER_TEST_F(IdentityGetAccountsFunctionTest,
496 PrimaryAccountSignedIn) {
497 SetAccountState(CreateIds("primary@example.com", "1"), true);
498 std::vector<std::string> primary;
499 primary.push_back("1");
500 EXPECT_TRUE(ExpectGetAccounts(primary));
503 IN_PROC_BROWSER_TEST_F(IdentityGetAccountsFunctionTest, TwoAccountsSignedIn) {
504 SetAccountState(CreateIds("primary@example.com", "1"), true);
505 SetAccountState(CreateIds("secondary@example.com", "2"), true);
506 std::vector<std::string> two_accounts;
507 two_accounts.push_back("1");
508 two_accounts.push_back("2");
509 EXPECT_TRUE(ExpectGetAccounts(two_accounts));
512 class IdentityOldProfilesGetAccountsFunctionTest
513 : public IdentityGetAccountsFunctionTest {
514 void SetUpCommandLine(CommandLine* command_line) override {
515 // Don't add the multi-account switch that parent class would have.
519 IN_PROC_BROWSER_TEST_F(IdentityOldProfilesGetAccountsFunctionTest,
521 EXPECT_FALSE(switches::IsExtensionsMultiAccount());
524 IN_PROC_BROWSER_TEST_F(IdentityOldProfilesGetAccountsFunctionTest,
525 TwoAccountsSignedIn) {
526 SetAccountState(CreateIds("primary@example.com", "1"), true);
527 SetAccountState(CreateIds("secondary@example.com", "2"), true);
528 std::vector<std::string> only_primary;
529 only_primary.push_back("1");
530 EXPECT_TRUE(ExpectGetAccounts(only_primary));
533 class IdentityGetProfileUserInfoFunctionTest : public ExtensionBrowserTest {
535 scoped_ptr<api::identity::ProfileUserInfo> RunGetProfileUserInfo() {
536 scoped_refptr<IdentityGetProfileUserInfoFunction> func(
537 new IdentityGetProfileUserInfoFunction);
538 func->set_extension(test_util::CreateEmptyExtension(kExtensionId).get());
539 scoped_ptr<base::Value> value(
540 utils::RunFunctionAndReturnSingleResult(func.get(), "[]", browser()));
541 return api::identity::ProfileUserInfo::FromValue(*value.get());
544 scoped_ptr<api::identity::ProfileUserInfo> RunGetProfileUserInfoWithEmail() {
545 scoped_refptr<IdentityGetProfileUserInfoFunction> func(
546 new IdentityGetProfileUserInfoFunction);
547 func->set_extension(CreateExtensionWithEmailPermission());
548 scoped_ptr<base::Value> value(
549 utils::RunFunctionAndReturnSingleResult(func.get(), "[]", browser()));
550 return api::identity::ProfileUserInfo::FromValue(*value.get());
554 scoped_refptr<Extension> CreateExtensionWithEmailPermission() {
555 scoped_ptr<base::DictionaryValue> test_extension_value(
556 utils::ParseDictionary(
557 "{\"name\": \"Test\", \"version\": \"1.0\", "
558 "\"permissions\": [\"identity.email\"]}"));
559 return utils::CreateExtension(test_extension_value.get());
563 IN_PROC_BROWSER_TEST_F(IdentityGetProfileUserInfoFunctionTest, NotSignedIn) {
564 scoped_ptr<api::identity::ProfileUserInfo> info =
565 RunGetProfileUserInfoWithEmail();
566 EXPECT_TRUE(info->email.empty());
567 EXPECT_TRUE(info->id.empty());
570 IN_PROC_BROWSER_TEST_F(IdentityGetProfileUserInfoFunctionTest, SignedIn) {
571 profile()->GetPrefs()
572 ->SetString(prefs::kGoogleServicesUsername, "president@example.com");
573 profile()->GetPrefs()
574 ->SetString(prefs::kGoogleServicesUserAccountId, "12345");
576 scoped_ptr<api::identity::ProfileUserInfo> info =
577 RunGetProfileUserInfoWithEmail();
578 EXPECT_EQ("president@example.com", info->email);
579 EXPECT_EQ("12345", info->id);
582 IN_PROC_BROWSER_TEST_F(IdentityGetProfileUserInfoFunctionTest,
583 NotSignedInNoEmail) {
584 scoped_ptr<api::identity::ProfileUserInfo> info = RunGetProfileUserInfo();
585 EXPECT_TRUE(info->email.empty());
586 EXPECT_TRUE(info->id.empty());
589 IN_PROC_BROWSER_TEST_F(IdentityGetProfileUserInfoFunctionTest,
591 profile()->GetPrefs()->SetString(prefs::kGoogleServicesUsername,
592 "president@example.com");
593 profile()->GetPrefs()->SetString(prefs::kGoogleServicesUserAccountId,
596 scoped_ptr<api::identity::ProfileUserInfo> info = RunGetProfileUserInfo();
597 EXPECT_TRUE(info->email.empty());
598 EXPECT_EQ("12345", info->id);
601 class GetAuthTokenFunctionTest : public AsyncExtensionBrowserTest {
603 void SetUpCommandLine(CommandLine* command_line) override {
604 AsyncExtensionBrowserTest::SetUpCommandLine(command_line);
605 command_line->AppendSwitch(switches::kExtensionsMultiAccount);
608 void SetUpInProcessBrowserTestFixture() override {
609 AsyncExtensionBrowserTest::SetUpInProcessBrowserTestFixture();
611 will_create_browser_context_services_subscription_ =
612 BrowserContextDependencyManager::GetInstance()
613 ->RegisterWillCreateBrowserContextServicesCallbackForTesting(
614 base::Bind(&GetAuthTokenFunctionTest::
615 OnWillCreateBrowserContextServices,
616 base::Unretained(this)))
620 void OnWillCreateBrowserContextServices(content::BrowserContext* context) {
621 // Replace the signin manager and token service with fakes. Do this ahead of
622 // creating the browser so that a bunch of classes don't register as
623 // observers and end up needing to unregister when the fake is substituted.
624 SigninManagerFactory::GetInstance()->SetTestingFactory(
625 context, &FakeSigninManagerBase::Build);
626 ProfileOAuth2TokenServiceFactory::GetInstance()->SetTestingFactory(
627 context, &BuildFakeProfileOAuth2TokenService);
628 AccountReconcilorFactory::GetInstance()->SetTestingFactory(
629 context, &FakeAccountReconcilor::Build);
632 void SetUpOnMainThread() override {
633 AsyncExtensionBrowserTest::SetUpOnMainThread();
635 // Grab references to the fake signin manager and token service.
636 signin_manager_ = static_cast<FakeSigninManagerForTesting*>(
637 SigninManagerFactory::GetInstance()->GetForProfile(profile()));
638 ASSERT_TRUE(signin_manager_);
639 token_service_ = static_cast<FakeProfileOAuth2TokenService*>(
640 ProfileOAuth2TokenServiceFactory::GetInstance()->GetForProfile(
642 ASSERT_TRUE(token_service_);
645 void SignIn(const std::string account_key) {
646 #if defined(OS_CHROMEOS)
647 signin_manager_->SetAuthenticatedUsername(account_key);
649 signin_manager_->SignIn(account_key, "password");
651 token_service_->IssueRefreshTokenForUser(account_key, "refresh_token");
654 void IssueLoginRefreshTokenForAccount(const std::string account_key) {
655 token_service_->IssueRefreshTokenForUser(account_key, "refresh_token");
658 void IssueLoginAccessTokenForAccount(const std::string account_key) {
659 token_service_->IssueAllTokensForAccount(
661 "access_token-" + account_key,
662 base::Time::Now() + base::TimeDelta::FromSeconds(3600));
665 void SetAccountState(gaia::AccountIds ids, bool is_signed_in) {
666 IdentityAPI::GetFactoryInstance()->Get(profile())->SetAccountStateForTest(
678 FakeSigninManagerForTesting* signin_manager_;
679 FakeProfileOAuth2TokenService* token_service_;
681 ~GetAuthTokenFunctionTest() override {}
683 // Helper to create an extension with specific OAuth2Info fields set.
684 // |fields_to_set| should be computed by using fields of Oauth2Fields enum.
685 const Extension* CreateExtension(int fields_to_set) {
686 const Extension* ext;
687 base::FilePath manifest_path =
688 test_data_dir_.AppendASCII("platform_apps/oauth2");
689 base::FilePath component_manifest_path =
690 test_data_dir_.AppendASCII("packaged_app/component_oauth2");
691 if ((fields_to_set & AS_COMPONENT) == 0)
692 ext = LoadExtension(manifest_path);
694 ext = LoadExtensionAsComponent(component_manifest_path);
695 OAuth2Info& oauth2_info =
696 const_cast<OAuth2Info&>(OAuth2Info::GetOAuth2Info(ext));
697 if ((fields_to_set & CLIENT_ID) != 0)
698 oauth2_info.client_id = "client1";
699 if ((fields_to_set & SCOPES) != 0) {
700 oauth2_info.scopes.push_back("scope1");
701 oauth2_info.scopes.push_back("scope2");
704 extension_id_ = ext->id();
705 oauth_scopes_ = std::set<std::string>(oauth2_info.scopes.begin(),
706 oauth2_info.scopes.end());
710 IdentityAPI* id_api() {
711 return IdentityAPI::GetFactoryInstance()->Get(browser()->profile());
714 const std::string GetPrimaryAccountId() {
715 SigninManagerBase* signin_manager =
716 SigninManagerFactory::GetForProfile(browser()->profile());
717 return signin_manager->GetAuthenticatedAccountId();
720 void SetCachedToken(const IdentityTokenCacheValue& token_data) {
721 ExtensionTokenKey key(extension_id_, GetPrimaryAccountId(), oauth_scopes_);
722 id_api()->SetCachedToken(key, token_data);
725 const IdentityTokenCacheValue& GetCachedToken(std::string account_id) {
726 if (account_id.empty())
727 account_id = GetPrimaryAccountId();
728 ExtensionTokenKey key(extension_id_, account_id, oauth_scopes_);
729 return id_api()->GetCachedToken(key);
732 void QueueRequestStart(IdentityMintRequestQueue::MintType type,
733 IdentityMintRequestQueue::Request* request) {
734 ExtensionTokenKey key(extension_id_, GetPrimaryAccountId(), oauth_scopes_);
735 id_api()->mint_queue()->RequestStart(type, key, request);
738 void QueueRequestComplete(IdentityMintRequestQueue::MintType type,
739 IdentityMintRequestQueue::Request* request) {
740 ExtensionTokenKey key(extension_id_, GetPrimaryAccountId(), oauth_scopes_);
741 id_api()->mint_queue()->RequestComplete(type, key, request);
745 std::string extension_id_;
746 std::set<std::string> oauth_scopes_;
748 scoped_ptr<base::CallbackList<void(content::BrowserContext*)>::Subscription>
749 will_create_browser_context_services_subscription_;
752 IN_PROC_BROWSER_TEST_F(GetAuthTokenFunctionTest,
754 scoped_refptr<FakeGetAuthTokenFunction> func(new FakeGetAuthTokenFunction());
755 func->set_extension(CreateExtension(SCOPES));
756 std::string error = utils::RunFunctionAndReturnError(
757 func.get(), "[{}]", browser());
758 EXPECT_EQ(std::string(errors::kInvalidClientId), error);
759 EXPECT_FALSE(func->login_ui_shown());
760 EXPECT_FALSE(func->scope_ui_shown());
763 IN_PROC_BROWSER_TEST_F(GetAuthTokenFunctionTest,
765 scoped_refptr<FakeGetAuthTokenFunction> func(new FakeGetAuthTokenFunction());
766 func->set_extension(CreateExtension(CLIENT_ID));
767 std::string error = utils::RunFunctionAndReturnError(
768 func.get(), "[{}]", browser());
769 EXPECT_EQ(std::string(errors::kInvalidScopes), error);
770 EXPECT_FALSE(func->login_ui_shown());
771 EXPECT_FALSE(func->scope_ui_shown());
774 IN_PROC_BROWSER_TEST_F(GetAuthTokenFunctionTest,
775 NonInteractiveNotSignedIn) {
776 scoped_refptr<FakeGetAuthTokenFunction> func(new FakeGetAuthTokenFunction());
777 func->set_extension(CreateExtension(CLIENT_ID | SCOPES));
778 std::string error = utils::RunFunctionAndReturnError(
779 func.get(), "[{}]", browser());
780 EXPECT_EQ(std::string(errors::kUserNotSignedIn), error);
781 EXPECT_FALSE(func->login_ui_shown());
782 EXPECT_FALSE(func->scope_ui_shown());
785 IN_PROC_BROWSER_TEST_F(GetAuthTokenFunctionTest,
786 NonInteractiveMintFailure) {
787 SignIn("primary@example.com");
788 scoped_refptr<FakeGetAuthTokenFunction> func(new FakeGetAuthTokenFunction());
789 func->set_extension(CreateExtension(CLIENT_ID | SCOPES));
790 func->set_mint_token_result(TestOAuth2MintTokenFlow::MINT_TOKEN_FAILURE);
792 utils::RunFunctionAndReturnError(func.get(), "[{}]", browser());
793 EXPECT_TRUE(StartsWithASCII(error, errors::kAuthFailure, false));
794 EXPECT_FALSE(func->login_ui_shown());
795 EXPECT_FALSE(func->scope_ui_shown());
798 IN_PROC_BROWSER_TEST_F(GetAuthTokenFunctionTest,
799 NonInteractiveLoginAccessTokenFailure) {
800 SignIn("primary@example.com");
801 scoped_refptr<FakeGetAuthTokenFunction> func(new FakeGetAuthTokenFunction());
802 func->set_extension(CreateExtension(CLIENT_ID | SCOPES));
803 func->set_login_access_token_result(false);
804 std::string error = utils::RunFunctionAndReturnError(
805 func.get(), "[{}]", browser());
806 EXPECT_TRUE(StartsWithASCII(error, errors::kAuthFailure, false));
809 IN_PROC_BROWSER_TEST_F(GetAuthTokenFunctionTest,
810 NonInteractiveMintAdviceSuccess) {
811 SignIn("primary@example.com");
812 scoped_refptr<const Extension> extension(CreateExtension(CLIENT_ID | SCOPES));
813 scoped_refptr<FakeGetAuthTokenFunction> func(new FakeGetAuthTokenFunction());
814 func->set_extension(extension.get());
815 func->set_mint_token_result(TestOAuth2MintTokenFlow::ISSUE_ADVICE_SUCCESS);
817 utils::RunFunctionAndReturnError(func.get(), "[{}]", browser());
818 EXPECT_EQ(std::string(errors::kNoGrant), error);
819 EXPECT_FALSE(func->login_ui_shown());
820 EXPECT_FALSE(func->scope_ui_shown());
822 EXPECT_EQ(IdentityTokenCacheValue::CACHE_STATUS_ADVICE,
823 GetCachedToken(std::string()).status());
826 IN_PROC_BROWSER_TEST_F(GetAuthTokenFunctionTest,
827 NonInteractiveMintBadCredentials) {
828 SignIn("primary@example.com");
829 scoped_refptr<FakeGetAuthTokenFunction> func(new FakeGetAuthTokenFunction());
830 func->set_extension(CreateExtension(CLIENT_ID | SCOPES));
831 func->set_mint_token_result(
832 TestOAuth2MintTokenFlow::MINT_TOKEN_BAD_CREDENTIALS);
834 utils::RunFunctionAndReturnError(func.get(), "[{}]", browser());
835 EXPECT_TRUE(StartsWithASCII(error, errors::kAuthFailure, false));
836 EXPECT_FALSE(func->login_ui_shown());
837 EXPECT_FALSE(func->scope_ui_shown());
840 IN_PROC_BROWSER_TEST_F(GetAuthTokenFunctionTest,
841 NonInteractiveMintServiceError) {
842 SignIn("primary@example.com");
843 scoped_refptr<FakeGetAuthTokenFunction> func(new FakeGetAuthTokenFunction());
844 func->set_extension(CreateExtension(CLIENT_ID | SCOPES));
845 func->set_mint_token_result(
846 TestOAuth2MintTokenFlow::MINT_TOKEN_SERVICE_ERROR);
848 utils::RunFunctionAndReturnError(func.get(), "[{}]", browser());
849 EXPECT_TRUE(StartsWithASCII(error, errors::kAuthFailure, false));
850 EXPECT_FALSE(func->login_ui_shown());
851 EXPECT_FALSE(func->scope_ui_shown());
854 IN_PROC_BROWSER_TEST_F(GetAuthTokenFunctionTest,
856 SignIn("primary@example.com");
857 #if defined(OS_WIN) && defined(USE_ASH)
858 // Disable this test in Metro+Ash for now (http://crbug.com/262796).
859 if (CommandLine::ForCurrentProcess()->HasSwitch(switches::kAshBrowserTests))
863 scoped_refptr<FakeGetAuthTokenFunction> func(new FakeGetAuthTokenFunction());
864 scoped_refptr<const Extension> extension(CreateExtension(CLIENT_ID | SCOPES));
865 func->set_extension(extension.get());
866 func->set_mint_token_result(TestOAuth2MintTokenFlow::MINT_TOKEN_SUCCESS);
867 scoped_ptr<base::Value> value(
868 utils::RunFunctionAndReturnSingleResult(func.get(), "[]", browser()));
869 std::string access_token;
870 EXPECT_TRUE(value->GetAsString(&access_token));
871 EXPECT_EQ(std::string(kAccessToken), access_token);
872 EXPECT_FALSE(func->login_ui_shown());
873 EXPECT_FALSE(func->scope_ui_shown());
874 EXPECT_EQ(IdentityTokenCacheValue::CACHE_STATUS_TOKEN,
875 GetCachedToken(std::string()).status());
878 IN_PROC_BROWSER_TEST_F(GetAuthTokenFunctionTest,
879 NonInteractiveSuccess) {
880 SignIn("primary@example.com");
881 #if defined(OS_WIN) && defined(USE_ASH)
882 // Disable this test in Metro+Ash for now (http://crbug.com/262796).
883 if (CommandLine::ForCurrentProcess()->HasSwitch(switches::kAshBrowserTests))
887 scoped_refptr<FakeGetAuthTokenFunction> func(new FakeGetAuthTokenFunction());
888 scoped_refptr<const Extension> extension(CreateExtension(CLIENT_ID | SCOPES));
889 func->set_extension(extension.get());
890 func->set_mint_token_result(TestOAuth2MintTokenFlow::MINT_TOKEN_SUCCESS);
891 scoped_ptr<base::Value> value(utils::RunFunctionAndReturnSingleResult(
892 func.get(), "[{}]", browser()));
893 std::string access_token;
894 EXPECT_TRUE(value->GetAsString(&access_token));
895 EXPECT_EQ(std::string(kAccessToken), access_token);
896 EXPECT_FALSE(func->login_ui_shown());
897 EXPECT_FALSE(func->scope_ui_shown());
898 EXPECT_EQ(IdentityTokenCacheValue::CACHE_STATUS_TOKEN,
899 GetCachedToken(std::string()).status());
902 IN_PROC_BROWSER_TEST_F(GetAuthTokenFunctionTest,
903 InteractiveLoginCanceled) {
904 scoped_refptr<FakeGetAuthTokenFunction> func(new FakeGetAuthTokenFunction());
905 func->set_extension(CreateExtension(CLIENT_ID | SCOPES));
906 func->set_login_ui_result(false);
907 std::string error = utils::RunFunctionAndReturnError(
908 func.get(), "[{\"interactive\": true}]", browser());
909 EXPECT_EQ(std::string(errors::kUserNotSignedIn), error);
910 EXPECT_TRUE(func->login_ui_shown());
911 EXPECT_FALSE(func->scope_ui_shown());
914 IN_PROC_BROWSER_TEST_F(GetAuthTokenFunctionTest,
915 InteractiveMintBadCredentialsLoginCanceled) {
916 SignIn("primary@example.com");
917 scoped_refptr<FakeGetAuthTokenFunction> func(new FakeGetAuthTokenFunction());
918 func->set_extension(CreateExtension(CLIENT_ID | SCOPES));
919 func->set_mint_token_result(
920 TestOAuth2MintTokenFlow::MINT_TOKEN_BAD_CREDENTIALS);
921 func->set_login_ui_result(false);
922 std::string error = utils::RunFunctionAndReturnError(
923 func.get(), "[{\"interactive\": true}]", browser());
924 EXPECT_EQ(std::string(errors::kUserNotSignedIn), error);
925 EXPECT_TRUE(func->login_ui_shown());
926 EXPECT_FALSE(func->scope_ui_shown());
929 IN_PROC_BROWSER_TEST_F(GetAuthTokenFunctionTest,
930 InteractiveLoginSuccessNoToken) {
931 scoped_refptr<FakeGetAuthTokenFunction> func(new FakeGetAuthTokenFunction());
932 func->set_extension(CreateExtension(CLIENT_ID | SCOPES));
933 func->set_login_ui_result(false);
934 std::string error = utils::RunFunctionAndReturnError(
935 func.get(), "[{\"interactive\": true}]", browser());
936 EXPECT_EQ(std::string(errors::kUserNotSignedIn), error);
937 EXPECT_TRUE(func->login_ui_shown());
938 EXPECT_FALSE(func->scope_ui_shown());
941 IN_PROC_BROWSER_TEST_F(GetAuthTokenFunctionTest,
942 InteractiveLoginSuccessMintFailure) {
943 scoped_refptr<FakeGetAuthTokenFunction> func(new FakeGetAuthTokenFunction());
944 func->set_extension(CreateExtension(CLIENT_ID | SCOPES));
945 func->set_login_ui_result(true);
946 func->set_mint_token_result(TestOAuth2MintTokenFlow::MINT_TOKEN_FAILURE);
947 std::string error = utils::RunFunctionAndReturnError(
948 func.get(), "[{\"interactive\": true}]", browser());
949 EXPECT_TRUE(StartsWithASCII(error, errors::kAuthFailure, false));
950 EXPECT_TRUE(func->login_ui_shown());
951 EXPECT_FALSE(func->scope_ui_shown());
954 IN_PROC_BROWSER_TEST_F(GetAuthTokenFunctionTest,
955 InteractiveLoginSuccessLoginAccessTokenFailure) {
956 scoped_refptr<FakeGetAuthTokenFunction> func(new FakeGetAuthTokenFunction());
957 func->set_extension(CreateExtension(CLIENT_ID | SCOPES));
958 func->set_login_ui_result(true);
959 func->set_login_access_token_result(false);
960 std::string error = utils::RunFunctionAndReturnError(
961 func.get(), "[{\"interactive\": true}]", browser());
962 EXPECT_TRUE(StartsWithASCII(error, errors::kAuthFailure, false));
963 EXPECT_TRUE(func->login_ui_shown());
964 EXPECT_FALSE(func->scope_ui_shown());
967 IN_PROC_BROWSER_TEST_F(GetAuthTokenFunctionTest,
968 InteractiveLoginSuccessMintSuccess) {
969 // TODO(courage): verify that account_id in token service requests
970 // is correct once manual token minting for tests is implemented.
971 scoped_refptr<FakeGetAuthTokenFunction> func(new FakeGetAuthTokenFunction());
972 func->set_extension(CreateExtension(CLIENT_ID | SCOPES));
973 func->set_login_ui_result(true);
974 func->set_mint_token_result(TestOAuth2MintTokenFlow::MINT_TOKEN_SUCCESS);
975 scoped_ptr<base::Value> value(utils::RunFunctionAndReturnSingleResult(
976 func.get(), "[{\"interactive\": true}]", browser()));
977 std::string access_token;
978 EXPECT_TRUE(value->GetAsString(&access_token));
979 EXPECT_EQ(std::string(kAccessToken), access_token);
980 EXPECT_TRUE(func->login_ui_shown());
981 EXPECT_FALSE(func->scope_ui_shown());
984 IN_PROC_BROWSER_TEST_F(GetAuthTokenFunctionTest,
985 InteractiveLoginSuccessApprovalAborted) {
986 scoped_refptr<FakeGetAuthTokenFunction> func(new FakeGetAuthTokenFunction());
987 func->set_extension(CreateExtension(CLIENT_ID | SCOPES));
988 func->set_login_ui_result(true);
989 func->set_mint_token_result(TestOAuth2MintTokenFlow::ISSUE_ADVICE_SUCCESS);
990 func->set_scope_ui_failure(GaiaWebAuthFlow::WINDOW_CLOSED);
991 std::string error = utils::RunFunctionAndReturnError(
992 func.get(), "[{\"interactive\": true}]", browser());
993 EXPECT_EQ(std::string(errors::kUserRejected), error);
994 EXPECT_TRUE(func->login_ui_shown());
995 EXPECT_TRUE(func->scope_ui_shown());
998 IN_PROC_BROWSER_TEST_F(GetAuthTokenFunctionTest,
999 InteractiveLoginSuccessApprovalSuccess) {
1000 scoped_refptr<const Extension> extension(CreateExtension(CLIENT_ID | SCOPES));
1001 scoped_refptr<FakeGetAuthTokenFunction> func(new FakeGetAuthTokenFunction());
1002 func->set_extension(extension.get());
1003 func->set_login_ui_result(true);
1004 func->set_mint_token_result(TestOAuth2MintTokenFlow::ISSUE_ADVICE_SUCCESS);
1006 scoped_ptr<base::Value> value(utils::RunFunctionAndReturnSingleResult(
1007 func.get(), "[{\"interactive\": true}]", browser()));
1008 std::string access_token;
1009 EXPECT_TRUE(value->GetAsString(&access_token));
1010 EXPECT_EQ(std::string(kAccessToken), access_token);
1011 EXPECT_TRUE(func->login_ui_shown());
1012 EXPECT_TRUE(func->scope_ui_shown());
1015 IN_PROC_BROWSER_TEST_F(GetAuthTokenFunctionTest,
1016 InteractiveApprovalAborted) {
1017 SignIn("primary@example.com");
1018 scoped_refptr<FakeGetAuthTokenFunction> func(new FakeGetAuthTokenFunction());
1019 func->set_extension(CreateExtension(CLIENT_ID | SCOPES));
1020 func->set_mint_token_result(TestOAuth2MintTokenFlow::ISSUE_ADVICE_SUCCESS);
1021 func->set_scope_ui_failure(GaiaWebAuthFlow::WINDOW_CLOSED);
1022 std::string error = utils::RunFunctionAndReturnError(
1023 func.get(), "[{\"interactive\": true}]", browser());
1024 EXPECT_EQ(std::string(errors::kUserRejected), error);
1025 EXPECT_FALSE(func->login_ui_shown());
1026 EXPECT_TRUE(func->scope_ui_shown());
1029 IN_PROC_BROWSER_TEST_F(GetAuthTokenFunctionTest,
1030 InteractiveApprovalLoadFailed) {
1031 SignIn("primary@example.com");
1032 scoped_refptr<FakeGetAuthTokenFunction> func(new FakeGetAuthTokenFunction());
1033 func->set_extension(CreateExtension(CLIENT_ID | SCOPES));
1034 func->set_mint_token_result(TestOAuth2MintTokenFlow::ISSUE_ADVICE_SUCCESS);
1035 func->set_scope_ui_failure(GaiaWebAuthFlow::LOAD_FAILED);
1036 std::string error = utils::RunFunctionAndReturnError(
1037 func.get(), "[{\"interactive\": true}]", browser());
1038 EXPECT_EQ(std::string(errors::kPageLoadFailure), error);
1039 EXPECT_FALSE(func->login_ui_shown());
1040 EXPECT_TRUE(func->scope_ui_shown());
1043 IN_PROC_BROWSER_TEST_F(GetAuthTokenFunctionTest,
1044 InteractiveApprovalInvalidRedirect) {
1045 SignIn("primary@example.com");
1046 scoped_refptr<FakeGetAuthTokenFunction> func(new FakeGetAuthTokenFunction());
1047 func->set_extension(CreateExtension(CLIENT_ID | SCOPES));
1048 func->set_mint_token_result(TestOAuth2MintTokenFlow::ISSUE_ADVICE_SUCCESS);
1049 func->set_scope_ui_failure(GaiaWebAuthFlow::INVALID_REDIRECT);
1050 std::string error = utils::RunFunctionAndReturnError(
1051 func.get(), "[{\"interactive\": true}]", browser());
1052 EXPECT_EQ(std::string(errors::kInvalidRedirect), error);
1053 EXPECT_FALSE(func->login_ui_shown());
1054 EXPECT_TRUE(func->scope_ui_shown());
1057 IN_PROC_BROWSER_TEST_F(GetAuthTokenFunctionTest,
1058 InteractiveApprovalConnectionFailure) {
1059 SignIn("primary@example.com");
1060 scoped_refptr<FakeGetAuthTokenFunction> func(new FakeGetAuthTokenFunction());
1061 func->set_extension(CreateExtension(CLIENT_ID | SCOPES));
1062 func->set_mint_token_result(TestOAuth2MintTokenFlow::ISSUE_ADVICE_SUCCESS);
1063 func->set_scope_ui_failure(GaiaWebAuthFlow::SERVICE_AUTH_ERROR);
1064 std::string error = utils::RunFunctionAndReturnError(
1065 func.get(), "[{\"interactive\": true}]", browser());
1066 EXPECT_TRUE(StartsWithASCII(error, errors::kAuthFailure, false));
1067 EXPECT_FALSE(func->login_ui_shown());
1068 EXPECT_TRUE(func->scope_ui_shown());
1071 IN_PROC_BROWSER_TEST_F(GetAuthTokenFunctionTest,
1072 InteractiveApprovalOAuthErrors) {
1073 SignIn("primary@example.com");
1074 scoped_refptr<const Extension> extension(CreateExtension(CLIENT_ID | SCOPES));
1076 std::map<std::string, std::string> error_map;
1077 error_map.insert(std::make_pair("access_denied", errors::kUserRejected));
1078 error_map.insert(std::make_pair("invalid_scope", errors::kInvalidScopes));
1079 error_map.insert(std::make_pair(
1080 "unmapped_error", std::string(errors::kAuthFailure) + "unmapped_error"));
1082 for (std::map<std::string, std::string>::const_iterator
1083 it = error_map.begin();
1084 it != error_map.end();
1086 scoped_refptr<FakeGetAuthTokenFunction> func(
1087 new FakeGetAuthTokenFunction());
1088 func->set_extension(extension.get());
1089 // Make sure we don't get a cached issue_advice result, which would cause
1090 // flow to be leaked.
1091 id_api()->EraseAllCachedTokens();
1092 func->set_mint_token_result(TestOAuth2MintTokenFlow::ISSUE_ADVICE_SUCCESS);
1093 func->set_scope_ui_oauth_error(it->first);
1094 std::string error = utils::RunFunctionAndReturnError(
1095 func.get(), "[{\"interactive\": true}]", browser());
1096 EXPECT_EQ(it->second, error);
1097 EXPECT_FALSE(func->login_ui_shown());
1098 EXPECT_TRUE(func->scope_ui_shown());
1102 IN_PROC_BROWSER_TEST_F(GetAuthTokenFunctionTest,
1103 InteractiveApprovalSuccess) {
1104 SignIn("primary@example.com");
1105 scoped_refptr<const Extension> extension(CreateExtension(CLIENT_ID | SCOPES));
1106 scoped_refptr<FakeGetAuthTokenFunction> func(new FakeGetAuthTokenFunction());
1107 func->set_extension(extension.get());
1108 func->set_mint_token_result(TestOAuth2MintTokenFlow::ISSUE_ADVICE_SUCCESS);
1110 scoped_ptr<base::Value> value(utils::RunFunctionAndReturnSingleResult(
1111 func.get(), "[{\"interactive\": true}]", browser()));
1112 std::string access_token;
1113 EXPECT_TRUE(value->GetAsString(&access_token));
1114 EXPECT_EQ(std::string(kAccessToken), access_token);
1115 EXPECT_FALSE(func->login_ui_shown());
1116 EXPECT_TRUE(func->scope_ui_shown());
1118 EXPECT_EQ(IdentityTokenCacheValue::CACHE_STATUS_TOKEN,
1119 GetCachedToken(std::string()).status());
1122 IN_PROC_BROWSER_TEST_F(GetAuthTokenFunctionTest, NoninteractiveQueue) {
1123 SignIn("primary@example.com");
1124 scoped_refptr<const Extension> extension(CreateExtension(CLIENT_ID | SCOPES));
1125 scoped_refptr<FakeGetAuthTokenFunction> func(new FakeGetAuthTokenFunction());
1126 func->set_extension(extension.get());
1128 // Create a fake request to block the queue.
1129 MockQueuedMintRequest queued_request;
1130 IdentityMintRequestQueue::MintType type =
1131 IdentityMintRequestQueue::MINT_TYPE_NONINTERACTIVE;
1133 EXPECT_CALL(queued_request, StartMintToken(type)).Times(1);
1134 QueueRequestStart(type, &queued_request);
1136 // The real request will start processing, but wait in the queue behind
1138 RunFunctionAsync(func.get(), "[{}]");
1139 // Verify that we have fetched the login token at this point.
1140 testing::Mock::VerifyAndClearExpectations(func.get());
1142 // The flow will be created after the first queued request clears.
1143 func->set_mint_token_result(TestOAuth2MintTokenFlow::MINT_TOKEN_SUCCESS);
1145 QueueRequestComplete(type, &queued_request);
1147 scoped_ptr<base::Value> value(WaitForSingleResult(func.get()));
1148 std::string access_token;
1149 EXPECT_TRUE(value->GetAsString(&access_token));
1150 EXPECT_EQ(std::string(kAccessToken), access_token);
1151 EXPECT_FALSE(func->login_ui_shown());
1152 EXPECT_FALSE(func->scope_ui_shown());
1155 IN_PROC_BROWSER_TEST_F(GetAuthTokenFunctionTest, InteractiveQueue) {
1156 SignIn("primary@example.com");
1157 scoped_refptr<const Extension> extension(CreateExtension(CLIENT_ID | SCOPES));
1158 scoped_refptr<FakeGetAuthTokenFunction> func(new FakeGetAuthTokenFunction());
1159 func->set_extension(extension.get());
1161 // Create a fake request to block the queue.
1162 MockQueuedMintRequest queued_request;
1163 IdentityMintRequestQueue::MintType type =
1164 IdentityMintRequestQueue::MINT_TYPE_INTERACTIVE;
1166 EXPECT_CALL(queued_request, StartMintToken(type)).Times(1);
1167 QueueRequestStart(type, &queued_request);
1169 // The real request will start processing, but wait in the queue behind
1171 func->set_mint_token_result(TestOAuth2MintTokenFlow::ISSUE_ADVICE_SUCCESS);
1172 RunFunctionAsync(func.get(), "[{\"interactive\": true}]");
1173 // Verify that we have fetched the login token and run the first flow.
1174 testing::Mock::VerifyAndClearExpectations(func.get());
1175 EXPECT_FALSE(func->scope_ui_shown());
1177 // The UI will be displayed and a token retrieved after the first
1178 // queued request clears.
1179 QueueRequestComplete(type, &queued_request);
1181 scoped_ptr<base::Value> value(WaitForSingleResult(func.get()));
1182 std::string access_token;
1183 EXPECT_TRUE(value->GetAsString(&access_token));
1184 EXPECT_EQ(std::string(kAccessToken), access_token);
1185 EXPECT_FALSE(func->login_ui_shown());
1186 EXPECT_TRUE(func->scope_ui_shown());
1189 IN_PROC_BROWSER_TEST_F(GetAuthTokenFunctionTest, InteractiveQueueShutdown) {
1190 SignIn("primary@example.com");
1191 scoped_refptr<const Extension> extension(CreateExtension(CLIENT_ID | SCOPES));
1192 scoped_refptr<FakeGetAuthTokenFunction> func(new FakeGetAuthTokenFunction());
1193 func->set_extension(extension.get());
1195 // Create a fake request to block the queue.
1196 MockQueuedMintRequest queued_request;
1197 IdentityMintRequestQueue::MintType type =
1198 IdentityMintRequestQueue::MINT_TYPE_INTERACTIVE;
1200 EXPECT_CALL(queued_request, StartMintToken(type)).Times(1);
1201 QueueRequestStart(type, &queued_request);
1203 // The real request will start processing, but wait in the queue behind
1205 func->set_mint_token_result(TestOAuth2MintTokenFlow::ISSUE_ADVICE_SUCCESS);
1206 RunFunctionAsync(func.get(), "[{\"interactive\": true}]");
1207 // Verify that we have fetched the login token and run the first flow.
1208 testing::Mock::VerifyAndClearExpectations(func.get());
1209 EXPECT_FALSE(func->scope_ui_shown());
1211 // After the request is canceled, the function will complete.
1213 EXPECT_EQ(std::string(errors::kCanceled), WaitForError(func.get()));
1214 EXPECT_FALSE(func->login_ui_shown());
1215 EXPECT_FALSE(func->scope_ui_shown());
1217 QueueRequestComplete(type, &queued_request);
1220 IN_PROC_BROWSER_TEST_F(GetAuthTokenFunctionTest, NoninteractiveShutdown) {
1221 SignIn("primary@example.com");
1222 scoped_refptr<const Extension> extension(CreateExtension(CLIENT_ID | SCOPES));
1223 scoped_refptr<FakeGetAuthTokenFunction> func(new FakeGetAuthTokenFunction());
1224 func->set_extension(extension.get());
1226 func->set_mint_token_flow(make_scoped_ptr(new TestHangOAuth2MintTokenFlow()));
1227 RunFunctionAsync(func.get(), "[{\"interactive\": false}]");
1229 // After the request is canceled, the function will complete.
1231 EXPECT_EQ(std::string(errors::kCanceled), WaitForError(func.get()));
1234 IN_PROC_BROWSER_TEST_F(GetAuthTokenFunctionTest,
1235 InteractiveQueuedNoninteractiveFails) {
1236 SignIn("primary@example.com");
1237 scoped_refptr<const Extension> extension(CreateExtension(CLIENT_ID | SCOPES));
1238 scoped_refptr<FakeGetAuthTokenFunction> func(new FakeGetAuthTokenFunction());
1239 func->set_extension(extension.get());
1241 // Create a fake request to block the interactive queue.
1242 MockQueuedMintRequest queued_request;
1243 IdentityMintRequestQueue::MintType type =
1244 IdentityMintRequestQueue::MINT_TYPE_INTERACTIVE;
1246 EXPECT_CALL(queued_request, StartMintToken(type)).Times(1);
1247 QueueRequestStart(type, &queued_request);
1249 // Non-interactive requests fail without hitting GAIA, because a
1250 // consent UI is known to be up.
1251 std::string error = utils::RunFunctionAndReturnError(
1252 func.get(), "[{}]", browser());
1253 EXPECT_EQ(std::string(errors::kNoGrant), error);
1254 EXPECT_FALSE(func->login_ui_shown());
1255 EXPECT_FALSE(func->scope_ui_shown());
1257 QueueRequestComplete(type, &queued_request);
1260 IN_PROC_BROWSER_TEST_F(GetAuthTokenFunctionTest,
1261 NonInteractiveCacheHit) {
1262 SignIn("primary@example.com");
1263 scoped_refptr<const Extension> extension(CreateExtension(CLIENT_ID | SCOPES));
1264 scoped_refptr<FakeGetAuthTokenFunction> func(new FakeGetAuthTokenFunction());
1265 func->set_extension(extension.get());
1267 // pre-populate the cache with a token
1268 IdentityTokenCacheValue token(kAccessToken,
1269 base::TimeDelta::FromSeconds(3600));
1270 SetCachedToken(token);
1272 // Get a token. Should not require a GAIA request.
1273 scoped_ptr<base::Value> value(utils::RunFunctionAndReturnSingleResult(
1274 func.get(), "[{}]", browser()));
1275 std::string access_token;
1276 EXPECT_TRUE(value->GetAsString(&access_token));
1277 EXPECT_EQ(std::string(kAccessToken), access_token);
1278 EXPECT_FALSE(func->login_ui_shown());
1279 EXPECT_FALSE(func->scope_ui_shown());
1282 IN_PROC_BROWSER_TEST_F(GetAuthTokenFunctionTest,
1283 NonInteractiveIssueAdviceCacheHit) {
1284 SignIn("primary@example.com");
1285 scoped_refptr<const Extension> extension(CreateExtension(CLIENT_ID | SCOPES));
1286 scoped_refptr<FakeGetAuthTokenFunction> func(new FakeGetAuthTokenFunction());
1287 func->set_extension(extension.get());
1289 // pre-populate the cache with advice
1290 IssueAdviceInfo info;
1291 IdentityTokenCacheValue token(info);
1292 SetCachedToken(token);
1294 // Should return an error without a GAIA request.
1295 std::string error = utils::RunFunctionAndReturnError(
1296 func.get(), "[{}]", browser());
1297 EXPECT_EQ(std::string(errors::kNoGrant), error);
1298 EXPECT_FALSE(func->login_ui_shown());
1299 EXPECT_FALSE(func->scope_ui_shown());
1302 IN_PROC_BROWSER_TEST_F(GetAuthTokenFunctionTest,
1303 InteractiveCacheHit) {
1304 SignIn("primary@example.com");
1305 scoped_refptr<const Extension> extension(CreateExtension(CLIENT_ID | SCOPES));
1306 scoped_refptr<FakeGetAuthTokenFunction> func(new FakeGetAuthTokenFunction());
1307 func->set_extension(extension.get());
1309 // Create a fake request to block the queue.
1310 MockQueuedMintRequest queued_request;
1311 IdentityMintRequestQueue::MintType type =
1312 IdentityMintRequestQueue::MINT_TYPE_INTERACTIVE;
1314 EXPECT_CALL(queued_request, StartMintToken(type)).Times(1);
1315 QueueRequestStart(type, &queued_request);
1317 // The real request will start processing, but wait in the queue behind
1319 func->set_mint_token_result(TestOAuth2MintTokenFlow::ISSUE_ADVICE_SUCCESS);
1320 RunFunctionAsync(func.get(), "[{\"interactive\": true}]");
1322 // Populate the cache with a token while the request is blocked.
1323 IdentityTokenCacheValue token(kAccessToken,
1324 base::TimeDelta::FromSeconds(3600));
1325 SetCachedToken(token);
1327 // When we wake up the request, it returns the cached token without
1328 // displaying a UI, or hitting GAIA.
1330 QueueRequestComplete(type, &queued_request);
1332 scoped_ptr<base::Value> value(WaitForSingleResult(func.get()));
1333 std::string access_token;
1334 EXPECT_TRUE(value->GetAsString(&access_token));
1335 EXPECT_EQ(std::string(kAccessToken), access_token);
1336 EXPECT_FALSE(func->login_ui_shown());
1337 EXPECT_FALSE(func->scope_ui_shown());
1340 IN_PROC_BROWSER_TEST_F(GetAuthTokenFunctionTest,
1341 LoginInvalidatesTokenCache) {
1342 scoped_refptr<FakeGetAuthTokenFunction> func(new FakeGetAuthTokenFunction());
1343 scoped_refptr<const Extension> extension(CreateExtension(CLIENT_ID | SCOPES));
1344 func->set_extension(extension.get());
1346 // pre-populate the cache with a token
1347 IdentityTokenCacheValue token(kAccessToken,
1348 base::TimeDelta::FromSeconds(3600));
1349 SetCachedToken(token);
1351 // Because the user is not signed in, the token will be removed,
1352 // and we'll hit GAIA for new tokens.
1353 func->set_login_ui_result(true);
1354 func->set_mint_token_result(TestOAuth2MintTokenFlow::ISSUE_ADVICE_SUCCESS);
1356 scoped_ptr<base::Value> value(utils::RunFunctionAndReturnSingleResult(
1357 func.get(), "[{\"interactive\": true}]", browser()));
1358 std::string access_token;
1359 EXPECT_TRUE(value->GetAsString(&access_token));
1360 EXPECT_EQ(std::string(kAccessToken), access_token);
1361 EXPECT_TRUE(func->login_ui_shown());
1362 EXPECT_TRUE(func->scope_ui_shown());
1363 EXPECT_EQ(IdentityTokenCacheValue::CACHE_STATUS_TOKEN,
1364 GetCachedToken(std::string()).status());
1367 IN_PROC_BROWSER_TEST_F(GetAuthTokenFunctionTest, ComponentWithChromeClientId) {
1368 scoped_refptr<FakeGetAuthTokenFunction> func(new FakeGetAuthTokenFunction());
1369 scoped_refptr<const Extension> extension(
1370 CreateExtension(SCOPES | AS_COMPONENT));
1371 func->set_extension(extension.get());
1372 const OAuth2Info& oauth2_info = OAuth2Info::GetOAuth2Info(extension.get());
1373 EXPECT_TRUE(oauth2_info.client_id.empty());
1374 EXPECT_FALSE(func->GetOAuth2ClientId().empty());
1375 EXPECT_NE("client1", func->GetOAuth2ClientId());
1378 IN_PROC_BROWSER_TEST_F(GetAuthTokenFunctionTest, ComponentWithNormalClientId) {
1379 scoped_refptr<FakeGetAuthTokenFunction> func(new FakeGetAuthTokenFunction());
1380 scoped_refptr<const Extension> extension(
1381 CreateExtension(CLIENT_ID | SCOPES | AS_COMPONENT));
1382 func->set_extension(extension.get());
1383 EXPECT_EQ("client1", func->GetOAuth2ClientId());
1386 IN_PROC_BROWSER_TEST_F(GetAuthTokenFunctionTest, MultiDefaultUser) {
1387 SignIn("primary@example.com");
1388 SetAccountState(CreateIds("primary@example.com", "1"), true);
1389 SetAccountState(CreateIds("secondary@example.com", "2"), true);
1391 scoped_refptr<FakeGetAuthTokenFunction> func(new FakeGetAuthTokenFunction());
1392 scoped_refptr<const Extension> extension(CreateExtension(CLIENT_ID | SCOPES));
1393 func->set_extension(extension.get());
1394 func->set_auto_login_access_token(false);
1395 func->set_mint_token_result(TestOAuth2MintTokenFlow::MINT_TOKEN_SUCCESS);
1397 RunFunctionAsync(func.get(), "[{}]");
1399 IssueLoginAccessTokenForAccount("primary@example.com");
1401 scoped_ptr<base::Value> value(WaitForSingleResult(func.get()));
1402 std::string access_token;
1403 EXPECT_TRUE(value->GetAsString(&access_token));
1404 EXPECT_EQ(std::string(kAccessToken), access_token);
1405 EXPECT_EQ(IdentityTokenCacheValue::CACHE_STATUS_TOKEN,
1406 GetCachedToken(std::string()).status());
1407 EXPECT_EQ("access_token-primary@example.com", func->login_access_token());
1410 IN_PROC_BROWSER_TEST_F(GetAuthTokenFunctionTest, MultiPrimaryUser) {
1411 SignIn("primary@example.com");
1412 IssueLoginRefreshTokenForAccount("secondary@example.com");
1413 SetAccountState(CreateIds("primary@example.com", "1"), true);
1414 SetAccountState(CreateIds("secondary@example.com", "2"), true);
1416 scoped_refptr<FakeGetAuthTokenFunction> func(new FakeGetAuthTokenFunction());
1417 scoped_refptr<const Extension> extension(CreateExtension(CLIENT_ID | SCOPES));
1418 func->set_extension(extension.get());
1419 func->set_auto_login_access_token(false);
1420 func->set_mint_token_result(TestOAuth2MintTokenFlow::MINT_TOKEN_SUCCESS);
1422 RunFunctionAsync(func.get(), "[{\"account\": { \"id\": \"1\" } }]");
1424 IssueLoginAccessTokenForAccount("primary@example.com");
1426 scoped_ptr<base::Value> value(WaitForSingleResult(func.get()));
1427 std::string access_token;
1428 EXPECT_TRUE(value->GetAsString(&access_token));
1429 EXPECT_EQ(std::string(kAccessToken), access_token);
1430 EXPECT_EQ(IdentityTokenCacheValue::CACHE_STATUS_TOKEN,
1431 GetCachedToken(std::string()).status());
1432 EXPECT_EQ("access_token-primary@example.com", func->login_access_token());
1435 IN_PROC_BROWSER_TEST_F(GetAuthTokenFunctionTest, MultiSecondaryUser) {
1436 SignIn("primary@example.com");
1437 IssueLoginRefreshTokenForAccount("secondary@example.com");
1438 SetAccountState(CreateIds("primary@example.com", "1"), true);
1439 SetAccountState(CreateIds("secondary@example.com", "2"), true);
1441 scoped_refptr<FakeGetAuthTokenFunction> func(new FakeGetAuthTokenFunction());
1442 scoped_refptr<const Extension> extension(CreateExtension(CLIENT_ID | SCOPES));
1443 func->set_extension(extension.get());
1444 func->set_auto_login_access_token(false);
1445 func->set_mint_token_result(TestOAuth2MintTokenFlow::MINT_TOKEN_SUCCESS);
1447 RunFunctionAsync(func.get(), "[{\"account\": { \"id\": \"2\" } }]");
1449 IssueLoginAccessTokenForAccount("secondary@example.com");
1451 scoped_ptr<base::Value> value(WaitForSingleResult(func.get()));
1452 std::string access_token;
1453 EXPECT_TRUE(value->GetAsString(&access_token));
1454 EXPECT_EQ(std::string(kAccessToken), access_token);
1455 EXPECT_EQ(IdentityTokenCacheValue::CACHE_STATUS_TOKEN,
1456 GetCachedToken("secondary@example.com").status());
1457 EXPECT_EQ("access_token-secondary@example.com", func->login_access_token());
1460 IN_PROC_BROWSER_TEST_F(GetAuthTokenFunctionTest, MultiUnknownUser) {
1461 SignIn("primary@example.com");
1462 IssueLoginRefreshTokenForAccount("secondary@example.com");
1463 SetAccountState(CreateIds("primary@example.com", "1"), true);
1464 SetAccountState(CreateIds("secondary@example.com", "2"), true);
1466 scoped_refptr<FakeGetAuthTokenFunction> func(new FakeGetAuthTokenFunction());
1467 scoped_refptr<const Extension> extension(CreateExtension(CLIENT_ID | SCOPES));
1468 func->set_extension(extension.get());
1469 func->set_auto_login_access_token(false);
1471 std::string error = utils::RunFunctionAndReturnError(
1472 func.get(), "[{\"account\": { \"id\": \"3\" } }]", browser());
1473 EXPECT_EQ(std::string(errors::kUserNotSignedIn), error);
1476 IN_PROC_BROWSER_TEST_F(GetAuthTokenFunctionTest,
1477 MultiSecondaryNonInteractiveMintFailure) {
1478 SignIn("primary@example.com");
1479 IssueLoginRefreshTokenForAccount("secondary@example.com");
1480 SetAccountState(CreateIds("primary@example.com", "1"), true);
1481 SetAccountState(CreateIds("secondary@example.com", "2"), true);
1483 scoped_refptr<FakeGetAuthTokenFunction> func(new FakeGetAuthTokenFunction());
1484 func->set_extension(CreateExtension(CLIENT_ID | SCOPES));
1485 func->set_mint_token_result(TestOAuth2MintTokenFlow::MINT_TOKEN_FAILURE);
1486 std::string error = utils::RunFunctionAndReturnError(
1487 func.get(), "[{\"account\": { \"id\": \"2\" } }]", browser());
1488 EXPECT_TRUE(StartsWithASCII(error, errors::kAuthFailure, false));
1489 EXPECT_FALSE(func->login_ui_shown());
1490 EXPECT_FALSE(func->scope_ui_shown());
1493 IN_PROC_BROWSER_TEST_F(GetAuthTokenFunctionTest,
1494 MultiSecondaryNonInteractiveLoginAccessTokenFailure) {
1495 SignIn("primary@example.com");
1496 IssueLoginRefreshTokenForAccount("secondary@example.com");
1497 SetAccountState(CreateIds("primary@example.com", "1"), true);
1498 SetAccountState(CreateIds("secondary@example.com", "2"), true);
1500 scoped_refptr<FakeGetAuthTokenFunction> func(new FakeGetAuthTokenFunction());
1501 func->set_extension(CreateExtension(CLIENT_ID | SCOPES));
1502 func->set_login_access_token_result(false);
1503 std::string error = utils::RunFunctionAndReturnError(
1504 func.get(), "[{\"account\": { \"id\": \"2\" } }]", browser());
1505 EXPECT_TRUE(StartsWithASCII(error, errors::kAuthFailure, false));
1508 IN_PROC_BROWSER_TEST_F(GetAuthTokenFunctionTest,
1509 MultiSecondaryInteractiveApprovalAborted) {
1510 SignIn("primary@example.com");
1511 IssueLoginRefreshTokenForAccount("secondary@example.com");
1512 SetAccountState(CreateIds("primary@example.com", "1"), true);
1513 SetAccountState(CreateIds("secondary@example.com", "2"), true);
1515 scoped_refptr<FakeGetAuthTokenFunction> func(new FakeGetAuthTokenFunction());
1516 func->set_extension(CreateExtension(CLIENT_ID | SCOPES));
1517 func->set_mint_token_result(TestOAuth2MintTokenFlow::ISSUE_ADVICE_SUCCESS);
1518 func->set_scope_ui_failure(GaiaWebAuthFlow::WINDOW_CLOSED);
1519 std::string error = utils::RunFunctionAndReturnError(
1521 "[{\"account\": { \"id\": \"2\" }, \"interactive\": true}]",
1523 EXPECT_EQ(std::string(errors::kUserRejected), error);
1524 EXPECT_FALSE(func->login_ui_shown());
1525 EXPECT_TRUE(func->scope_ui_shown());
1528 IN_PROC_BROWSER_TEST_F(GetAuthTokenFunctionTest, ScopesDefault) {
1529 SignIn("primary@example.com");
1530 scoped_refptr<FakeGetAuthTokenFunction> func(new FakeGetAuthTokenFunction());
1531 scoped_refptr<const Extension> extension(CreateExtension(CLIENT_ID | SCOPES));
1532 func->set_extension(extension.get());
1533 func->set_mint_token_result(TestOAuth2MintTokenFlow::MINT_TOKEN_SUCCESS);
1534 scoped_ptr<base::Value> value(
1535 utils::RunFunctionAndReturnSingleResult(func.get(), "[{}]", browser()));
1536 std::string access_token;
1537 EXPECT_TRUE(value->GetAsString(&access_token));
1538 EXPECT_EQ(std::string(kAccessToken), access_token);
1540 const ExtensionTokenKey* token_key = func->GetExtensionTokenKeyForTest();
1541 EXPECT_EQ(2ul, token_key->scopes.size());
1542 EXPECT_TRUE(ContainsKey(token_key->scopes, "scope1"));
1543 EXPECT_TRUE(ContainsKey(token_key->scopes, "scope2"));
1546 IN_PROC_BROWSER_TEST_F(GetAuthTokenFunctionTest, ScopesEmpty) {
1547 scoped_refptr<FakeGetAuthTokenFunction> func(new FakeGetAuthTokenFunction());
1548 scoped_refptr<const Extension> extension(CreateExtension(CLIENT_ID | SCOPES));
1549 func->set_extension(extension.get());
1551 std::string error(utils::RunFunctionAndReturnError(
1552 func.get(), "[{\"scopes\": []}]", browser()));
1554 EXPECT_EQ(errors::kInvalidScopes, error);
1557 IN_PROC_BROWSER_TEST_F(GetAuthTokenFunctionTest, ScopesEmail) {
1558 SignIn("primary@example.com");
1559 scoped_refptr<FakeGetAuthTokenFunction> func(new FakeGetAuthTokenFunction());
1560 scoped_refptr<const Extension> extension(CreateExtension(CLIENT_ID | SCOPES));
1561 func->set_extension(extension.get());
1562 func->set_mint_token_result(TestOAuth2MintTokenFlow::MINT_TOKEN_SUCCESS);
1563 scoped_ptr<base::Value> value(utils::RunFunctionAndReturnSingleResult(
1564 func.get(), "[{\"scopes\": [\"email\"]}]", browser()));
1565 std::string access_token;
1566 EXPECT_TRUE(value->GetAsString(&access_token));
1567 EXPECT_EQ(std::string(kAccessToken), access_token);
1569 const ExtensionTokenKey* token_key = func->GetExtensionTokenKeyForTest();
1570 EXPECT_EQ(1ul, token_key->scopes.size());
1571 EXPECT_TRUE(ContainsKey(token_key->scopes, "email"));
1574 IN_PROC_BROWSER_TEST_F(GetAuthTokenFunctionTest, ScopesEmailFooBar) {
1575 SignIn("primary@example.com");
1576 scoped_refptr<FakeGetAuthTokenFunction> func(new FakeGetAuthTokenFunction());
1577 scoped_refptr<const Extension> extension(CreateExtension(CLIENT_ID | SCOPES));
1578 func->set_extension(extension.get());
1579 func->set_mint_token_result(TestOAuth2MintTokenFlow::MINT_TOKEN_SUCCESS);
1580 scoped_ptr<base::Value> value(utils::RunFunctionAndReturnSingleResult(
1581 func.get(), "[{\"scopes\": [\"email\", \"foo\", \"bar\"]}]", browser()));
1582 std::string access_token;
1583 EXPECT_TRUE(value->GetAsString(&access_token));
1584 EXPECT_EQ(std::string(kAccessToken), access_token);
1586 const ExtensionTokenKey* token_key = func->GetExtensionTokenKeyForTest();
1587 EXPECT_EQ(3ul, token_key->scopes.size());
1588 EXPECT_TRUE(ContainsKey(token_key->scopes, "email"));
1589 EXPECT_TRUE(ContainsKey(token_key->scopes, "foo"));
1590 EXPECT_TRUE(ContainsKey(token_key->scopes, "bar"));
1593 class RemoveCachedAuthTokenFunctionTest : public ExtensionBrowserTest {
1595 bool InvalidateDefaultToken() {
1596 scoped_refptr<IdentityRemoveCachedAuthTokenFunction> func(
1597 new IdentityRemoveCachedAuthTokenFunction);
1598 func->set_extension(test_util::CreateEmptyExtension(kExtensionId).get());
1599 return utils::RunFunction(
1601 std::string("[{\"token\": \"") + kAccessToken + "\"}]",
1603 extension_function_test_utils::NONE);
1606 IdentityAPI* id_api() {
1607 return IdentityAPI::GetFactoryInstance()->Get(browser()->profile());
1610 void SetCachedToken(IdentityTokenCacheValue& token_data) {
1611 ExtensionTokenKey key(
1612 kExtensionId, "test@example.com", std::set<std::string>());
1613 id_api()->SetCachedToken(key, token_data);
1616 const IdentityTokenCacheValue& GetCachedToken() {
1617 return id_api()->GetCachedToken(ExtensionTokenKey(
1618 kExtensionId, "test@example.com", std::set<std::string>()));
1622 IN_PROC_BROWSER_TEST_F(RemoveCachedAuthTokenFunctionTest, NotFound) {
1623 EXPECT_TRUE(InvalidateDefaultToken());
1624 EXPECT_EQ(IdentityTokenCacheValue::CACHE_STATUS_NOTFOUND,
1625 GetCachedToken().status());
1628 IN_PROC_BROWSER_TEST_F(RemoveCachedAuthTokenFunctionTest, Advice) {
1629 IssueAdviceInfo info;
1630 IdentityTokenCacheValue advice(info);
1631 SetCachedToken(advice);
1632 EXPECT_TRUE(InvalidateDefaultToken());
1633 EXPECT_EQ(IdentityTokenCacheValue::CACHE_STATUS_ADVICE,
1634 GetCachedToken().status());
1637 IN_PROC_BROWSER_TEST_F(RemoveCachedAuthTokenFunctionTest, NonMatchingToken) {
1638 IdentityTokenCacheValue token("non_matching_token",
1639 base::TimeDelta::FromSeconds(3600));
1640 SetCachedToken(token);
1641 EXPECT_TRUE(InvalidateDefaultToken());
1642 EXPECT_EQ(IdentityTokenCacheValue::CACHE_STATUS_TOKEN,
1643 GetCachedToken().status());
1644 EXPECT_EQ("non_matching_token", GetCachedToken().token());
1647 IN_PROC_BROWSER_TEST_F(RemoveCachedAuthTokenFunctionTest, MatchingToken) {
1648 IdentityTokenCacheValue token(kAccessToken,
1649 base::TimeDelta::FromSeconds(3600));
1650 SetCachedToken(token);
1651 EXPECT_EQ(IdentityTokenCacheValue::CACHE_STATUS_TOKEN,
1652 GetCachedToken().status());
1653 EXPECT_TRUE(InvalidateDefaultToken());
1654 EXPECT_EQ(IdentityTokenCacheValue::CACHE_STATUS_NOTFOUND,
1655 GetCachedToken().status());
1658 class LaunchWebAuthFlowFunctionTest : public AsyncExtensionBrowserTest {
1660 void SetUpCommandLine(CommandLine* command_line) override {
1661 AsyncExtensionBrowserTest::SetUpCommandLine(command_line);
1662 // Reduce performance test variance by disabling background networking.
1663 command_line->AppendSwitch(switches::kDisableBackgroundNetworking);
1667 IN_PROC_BROWSER_TEST_F(LaunchWebAuthFlowFunctionTest, UserCloseWindow) {
1668 net::SpawnedTestServer https_server(
1669 net::SpawnedTestServer::TYPE_HTTPS,
1670 net::SpawnedTestServer::kLocalhost,
1671 base::FilePath(FILE_PATH_LITERAL(
1672 "chrome/test/data/extensions/api_test/identity")));
1673 ASSERT_TRUE(https_server.Start());
1674 GURL auth_url(https_server.GetURL("files/interaction_required.html"));
1676 scoped_refptr<IdentityLaunchWebAuthFlowFunction> function(
1677 new IdentityLaunchWebAuthFlowFunction());
1678 scoped_refptr<Extension> empty_extension(test_util::CreateEmptyExtension());
1679 function->set_extension(empty_extension.get());
1681 WaitForGURLAndCloseWindow popup_observer(auth_url);
1683 std::string args = "[{\"interactive\": true, \"url\": \"" +
1684 auth_url.spec() + "\"}]";
1685 RunFunctionAsync(function.get(), args);
1687 popup_observer.Wait();
1688 popup_observer.CloseEmbedderWebContents();
1690 EXPECT_EQ(std::string(errors::kUserRejected), WaitForError(function.get()));
1693 IN_PROC_BROWSER_TEST_F(LaunchWebAuthFlowFunctionTest, InteractionRequired) {
1694 net::SpawnedTestServer https_server(
1695 net::SpawnedTestServer::TYPE_HTTPS,
1696 net::SpawnedTestServer::kLocalhost,
1697 base::FilePath(FILE_PATH_LITERAL(
1698 "chrome/test/data/extensions/api_test/identity")));
1699 ASSERT_TRUE(https_server.Start());
1700 GURL auth_url(https_server.GetURL("files/interaction_required.html"));
1702 scoped_refptr<IdentityLaunchWebAuthFlowFunction> function(
1703 new IdentityLaunchWebAuthFlowFunction());
1704 scoped_refptr<Extension> empty_extension(test_util::CreateEmptyExtension());
1705 function->set_extension(empty_extension.get());
1707 std::string args = "[{\"interactive\": false, \"url\": \"" +
1708 auth_url.spec() + "\"}]";
1710 utils::RunFunctionAndReturnError(function.get(), args, browser());
1712 EXPECT_EQ(std::string(errors::kInteractionRequired), error);
1715 IN_PROC_BROWSER_TEST_F(LaunchWebAuthFlowFunctionTest, LoadFailed) {
1716 net::SpawnedTestServer https_server(
1717 net::SpawnedTestServer::TYPE_HTTPS,
1718 net::SpawnedTestServer::kLocalhost,
1719 base::FilePath(FILE_PATH_LITERAL(
1720 "chrome/test/data/extensions/api_test/identity")));
1721 ASSERT_TRUE(https_server.Start());
1722 GURL auth_url(https_server.GetURL("files/five_hundred.html"));
1724 scoped_refptr<IdentityLaunchWebAuthFlowFunction> function(
1725 new IdentityLaunchWebAuthFlowFunction());
1726 scoped_refptr<Extension> empty_extension(test_util::CreateEmptyExtension());
1727 function->set_extension(empty_extension.get());
1729 std::string args = "[{\"interactive\": true, \"url\": \"" +
1730 auth_url.spec() + "\"}]";
1732 utils::RunFunctionAndReturnError(function.get(), args, browser());
1734 EXPECT_EQ(std::string(errors::kPageLoadFailure), error);
1737 IN_PROC_BROWSER_TEST_F(LaunchWebAuthFlowFunctionTest, NonInteractiveSuccess) {
1738 #if defined(OS_WIN) && defined(USE_ASH)
1739 // Disable this test in Metro+Ash for now (http://crbug.com/262796).
1740 if (CommandLine::ForCurrentProcess()->HasSwitch(switches::kAshBrowserTests))
1744 scoped_refptr<IdentityLaunchWebAuthFlowFunction> function(
1745 new IdentityLaunchWebAuthFlowFunction());
1746 scoped_refptr<Extension> empty_extension(test_util::CreateEmptyExtension());
1747 function->set_extension(empty_extension.get());
1749 function->InitFinalRedirectURLPrefixForTest("abcdefghij");
1750 scoped_ptr<base::Value> value(utils::RunFunctionAndReturnSingleResult(
1752 "[{\"interactive\": false,"
1753 "\"url\": \"https://abcdefghij.chromiumapp.org/callback#test\"}]",
1757 EXPECT_TRUE(value->GetAsString(&url));
1758 EXPECT_EQ(std::string("https://abcdefghij.chromiumapp.org/callback#test"),
1762 IN_PROC_BROWSER_TEST_F(
1763 LaunchWebAuthFlowFunctionTest, InteractiveFirstNavigationSuccess) {
1764 #if defined(OS_WIN) && defined(USE_ASH)
1765 // Disable this test in Metro+Ash for now (http://crbug.com/262796).
1766 if (CommandLine::ForCurrentProcess()->HasSwitch(switches::kAshBrowserTests))
1770 scoped_refptr<IdentityLaunchWebAuthFlowFunction> function(
1771 new IdentityLaunchWebAuthFlowFunction());
1772 scoped_refptr<Extension> empty_extension(test_util::CreateEmptyExtension());
1773 function->set_extension(empty_extension.get());
1775 function->InitFinalRedirectURLPrefixForTest("abcdefghij");
1776 scoped_ptr<base::Value> value(utils::RunFunctionAndReturnSingleResult(
1778 "[{\"interactive\": true,"
1779 "\"url\": \"https://abcdefghij.chromiumapp.org/callback#test\"}]",
1783 EXPECT_TRUE(value->GetAsString(&url));
1784 EXPECT_EQ(std::string("https://abcdefghij.chromiumapp.org/callback#test"),
1788 IN_PROC_BROWSER_TEST_F(LaunchWebAuthFlowFunctionTest,
1789 DISABLED_InteractiveSecondNavigationSuccess) {
1790 net::SpawnedTestServer https_server(
1791 net::SpawnedTestServer::TYPE_HTTPS,
1792 net::SpawnedTestServer::kLocalhost,
1793 base::FilePath(FILE_PATH_LITERAL(
1794 "chrome/test/data/extensions/api_test/identity")));
1795 ASSERT_TRUE(https_server.Start());
1796 GURL auth_url(https_server.GetURL("files/redirect_to_chromiumapp.html"));
1798 scoped_refptr<IdentityLaunchWebAuthFlowFunction> function(
1799 new IdentityLaunchWebAuthFlowFunction());
1800 scoped_refptr<Extension> empty_extension(test_util::CreateEmptyExtension());
1801 function->set_extension(empty_extension.get());
1803 function->InitFinalRedirectURLPrefixForTest("abcdefghij");
1804 std::string args = "[{\"interactive\": true, \"url\": \"" +
1805 auth_url.spec() + "\"}]";
1806 scoped_ptr<base::Value> value(
1807 utils::RunFunctionAndReturnSingleResult(function.get(), args, browser()));
1810 EXPECT_TRUE(value->GetAsString(&url));
1811 EXPECT_EQ(std::string("https://abcdefghij.chromiumapp.org/callback#test"),
1815 } // namespace extensions
1817 // Tests the chrome.identity API implemented by custom JS bindings .
1818 IN_PROC_BROWSER_TEST_F(ExtensionApiTest, ChromeIdentityJsBindings) {
1819 ASSERT_TRUE(RunExtensionTest("identity/js_bindings")) << message_;