Pin Chrome's shortcut to the Win10 Start menu on install and OS upgrade.
[chromium-blink-merge.git] / chrome / browser / extensions / api / identity / identity_apitest.cc
blobfe3ec93ecfa4a4e2cebb31e4249f718e9052118d
1 // Copyright (c) 2012 The Chromium Authors. All rights reserved.
2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file.
5 #include <set>
6 #include <string>
7 #include <vector>
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_tracker_service_factory.h"
23 #include "chrome/browser/signin/fake_gaia_cookie_manager_service.h"
24 #include "chrome/browser/signin/fake_profile_oauth2_token_service_builder.h"
25 #include "chrome/browser/signin/fake_signin_manager_builder.h"
26 #include "chrome/browser/signin/gaia_cookie_manager_service_factory.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/guest_view/browser/guest_view_base.h"
37 #include "components/signin/core/browser/account_tracker_service.h"
38 #include "components/signin/core/browser/fake_profile_oauth2_token_service.h"
39 #include "components/signin/core/browser/signin_manager.h"
40 #include "components/signin/core/common/profile_management_switches.h"
41 #include "components/signin/core/common/signin_pref_names.h"
42 #include "content/public/browser/notification_service.h"
43 #include "content/public/browser/notification_source.h"
44 #include "content/public/test/test_utils.h"
45 #include "extensions/browser/api_test_utils.h"
46 #include "extensions/common/manifest_handlers/oauth2_manifest_handler.h"
47 #include "extensions/common/test_util.h"
48 #include "google_apis/gaia/google_service_auth_error.h"
49 #include "google_apis/gaia/oauth2_mint_token_flow.h"
50 #include "net/test/spawned_test_server/spawned_test_server.h"
51 #include "testing/gmock/include/gmock/gmock.h"
52 #include "testing/gtest/include/gtest/gtest.h"
53 #include "url/gurl.h"
55 using guest_view::GuestViewBase;
56 using testing::_;
57 using testing::Return;
58 using testing::ReturnRef;
60 namespace extensions {
62 namespace {
64 namespace errors = identity_constants;
65 namespace utils = extension_function_test_utils;
67 static const char kAccessToken[] = "auth_token";
68 static const char kExtensionId[] = "ext_id";
70 // This helps us be able to wait until an UIThreadExtensionFunction calls
71 // SendResponse.
72 class SendResponseDelegate
73 : public UIThreadExtensionFunction::DelegateForTests {
74 public:
75 SendResponseDelegate() : should_post_quit_(false) {}
77 virtual ~SendResponseDelegate() {}
79 void set_should_post_quit(bool should_quit) {
80 should_post_quit_ = should_quit;
83 bool HasResponse() {
84 return response_.get() != NULL;
87 bool GetResponse() {
88 EXPECT_TRUE(HasResponse());
89 return *response_.get();
92 void OnSendResponse(UIThreadExtensionFunction* function,
93 bool success,
94 bool bad_message) override {
95 ASSERT_FALSE(bad_message);
96 ASSERT_FALSE(HasResponse());
97 response_.reset(new bool);
98 *response_ = success;
99 if (should_post_quit_) {
100 base::MessageLoopForUI::current()->Quit();
104 private:
105 scoped_ptr<bool> response_;
106 bool should_post_quit_;
109 class AsyncExtensionBrowserTest : public ExtensionBrowserTest {
110 protected:
111 // Asynchronous function runner allows tests to manipulate the browser window
112 // after the call happens.
113 void RunFunctionAsync(
114 UIThreadExtensionFunction* function,
115 const std::string& args) {
116 response_delegate_.reset(new SendResponseDelegate);
117 function->set_test_delegate(response_delegate_.get());
118 scoped_ptr<base::ListValue> parsed_args(utils::ParseList(args));
119 EXPECT_TRUE(parsed_args.get()) <<
120 "Could not parse extension function arguments: " << args;
121 function->SetArgs(parsed_args.get());
123 if (!function->extension()) {
124 scoped_refptr<Extension> empty_extension(
125 test_util::CreateEmptyExtension());
126 function->set_extension(empty_extension.get());
129 function->set_browser_context(browser()->profile());
130 function->set_has_callback(true);
131 function->Run()->Execute();
134 std::string WaitForError(UIThreadExtensionFunction* function) {
135 RunMessageLoopUntilResponse();
136 EXPECT_FALSE(function->GetResultList()) << "Did not expect a result";
137 return function->GetError();
140 base::Value* WaitForSingleResult(UIThreadExtensionFunction* function) {
141 RunMessageLoopUntilResponse();
142 EXPECT_TRUE(function->GetError().empty()) << "Unexpected error: "
143 << function->GetError();
144 const base::Value* single_result = NULL;
145 if (function->GetResultList() != NULL &&
146 function->GetResultList()->Get(0, &single_result)) {
147 return single_result->DeepCopy();
149 return NULL;
152 private:
153 void RunMessageLoopUntilResponse() {
154 // If the RunAsync of |function| didn't already call SendResponse, run the
155 // message loop until they do.
156 if (!response_delegate_->HasResponse()) {
157 response_delegate_->set_should_post_quit(true);
158 content::RunMessageLoop();
160 EXPECT_TRUE(response_delegate_->HasResponse());
163 scoped_ptr<SendResponseDelegate> response_delegate_;
166 class TestHangOAuth2MintTokenFlow : public OAuth2MintTokenFlow {
167 public:
168 TestHangOAuth2MintTokenFlow()
169 : OAuth2MintTokenFlow(NULL, OAuth2MintTokenFlow::Parameters()) {}
171 void Start(net::URLRequestContextGetter* context,
172 const std::string& access_token) override {
173 // Do nothing, simulating a hanging network call.
177 class TestOAuth2MintTokenFlow : public OAuth2MintTokenFlow {
178 public:
179 enum ResultType {
180 ISSUE_ADVICE_SUCCESS,
181 MINT_TOKEN_SUCCESS,
182 MINT_TOKEN_FAILURE,
183 MINT_TOKEN_BAD_CREDENTIALS,
184 MINT_TOKEN_SERVICE_ERROR
187 TestOAuth2MintTokenFlow(ResultType result,
188 OAuth2MintTokenFlow::Delegate* delegate)
189 : OAuth2MintTokenFlow(delegate, OAuth2MintTokenFlow::Parameters()),
190 result_(result),
191 delegate_(delegate) {}
193 void Start(net::URLRequestContextGetter* context,
194 const std::string& access_token) override {
195 switch (result_) {
196 case ISSUE_ADVICE_SUCCESS: {
197 IssueAdviceInfo info;
198 delegate_->OnIssueAdviceSuccess(info);
199 break;
201 case MINT_TOKEN_SUCCESS: {
202 delegate_->OnMintTokenSuccess(kAccessToken, 3600);
203 break;
205 case MINT_TOKEN_FAILURE: {
206 GoogleServiceAuthError error(GoogleServiceAuthError::CONNECTION_FAILED);
207 delegate_->OnMintTokenFailure(error);
208 break;
210 case MINT_TOKEN_BAD_CREDENTIALS: {
211 GoogleServiceAuthError error(
212 GoogleServiceAuthError::INVALID_GAIA_CREDENTIALS);
213 delegate_->OnMintTokenFailure(error);
214 break;
216 case MINT_TOKEN_SERVICE_ERROR: {
217 GoogleServiceAuthError error =
218 GoogleServiceAuthError::FromServiceError("invalid_scope");
219 delegate_->OnMintTokenFailure(error);
220 break;
225 private:
226 ResultType result_;
227 OAuth2MintTokenFlow::Delegate* delegate_;
230 // Waits for a specific GURL to generate a NOTIFICATION_LOAD_STOP event and
231 // saves a pointer to the window embedding the WebContents, which can be later
232 // closed.
233 class WaitForGURLAndCloseWindow : public content::WindowedNotificationObserver {
234 public:
235 explicit WaitForGURLAndCloseWindow(GURL url)
236 : WindowedNotificationObserver(
237 content::NOTIFICATION_LOAD_STOP,
238 content::NotificationService::AllSources()),
239 url_(url) {}
241 // NotificationObserver:
242 void Observe(int type,
243 const content::NotificationSource& source,
244 const content::NotificationDetails& details) override {
245 content::NavigationController* web_auth_flow_controller =
246 content::Source<content::NavigationController>(source).ptr();
247 content::WebContents* web_contents =
248 web_auth_flow_controller->GetWebContents();
250 if (web_contents->GetURL() == url_) {
251 // It is safe to keep the pointer here, because we know in a test, that
252 // the WebContents won't go away before CloseEmbedderWebContents is
253 // called. Don't copy this code to production.
254 GuestViewBase* guest = GuestViewBase::FromWebContents(web_contents);
255 embedder_web_contents_ = guest->embedder_web_contents();
256 // Condtionally invoke parent class so that Wait will not exit
257 // until the target URL arrives.
258 content::WindowedNotificationObserver::Observe(type, source, details);
262 // Closes the window embedding the WebContents. The action is separated from
263 // the Observe method to make sure the list of observers is not deleted,
264 // while some event is already being processed. (That causes ASAN failures.)
265 void CloseEmbedderWebContents() {
266 if (embedder_web_contents_)
267 embedder_web_contents_->Close();
270 private:
271 GURL url_;
272 content::WebContents* embedder_web_contents_;
275 } // namespace
277 class FakeGetAuthTokenFunction : public IdentityGetAuthTokenFunction {
278 public:
279 FakeGetAuthTokenFunction()
280 : login_access_token_result_(true),
281 auto_login_access_token_(true),
282 login_ui_result_(true),
283 scope_ui_result_(true),
284 login_ui_shown_(false),
285 scope_ui_shown_(false) {}
287 void set_login_access_token_result(bool result) {
288 login_access_token_result_ = result;
291 void set_auto_login_access_token(bool automatic) {
292 auto_login_access_token_ = automatic;
295 void set_login_ui_result(bool result) { login_ui_result_ = result; }
297 void set_mint_token_flow(scoped_ptr<OAuth2MintTokenFlow> flow) {
298 flow_ = flow.Pass();
301 void set_mint_token_result(TestOAuth2MintTokenFlow::ResultType result_type) {
302 set_mint_token_flow(
303 make_scoped_ptr(new TestOAuth2MintTokenFlow(result_type, this)));
306 void set_scope_ui_failure(GaiaWebAuthFlow::Failure failure) {
307 scope_ui_result_ = false;
308 scope_ui_failure_ = failure;
311 void set_scope_ui_oauth_error(const std::string& oauth_error) {
312 scope_ui_result_ = false;
313 scope_ui_failure_ = GaiaWebAuthFlow::OAUTH_ERROR;
314 scope_ui_oauth_error_ = oauth_error;
317 bool login_ui_shown() const { return login_ui_shown_; }
319 bool scope_ui_shown() const { return scope_ui_shown_; }
321 std::string login_access_token() const { return login_access_token_; }
323 void StartLoginAccessTokenRequest() override {
324 if (auto_login_access_token_) {
325 if (login_access_token_result_) {
326 OnGetTokenSuccess(login_token_request_.get(),
327 "access_token",
328 base::Time::Now() + base::TimeDelta::FromHours(1LL));
329 } else {
330 GoogleServiceAuthError error(
331 GoogleServiceAuthError::INVALID_GAIA_CREDENTIALS);
332 OnGetTokenFailure(login_token_request_.get(), error);
334 } else {
335 // Make a request to the token service. The test now must tell
336 // the token service to issue an access token (or an error).
337 IdentityGetAuthTokenFunction::StartLoginAccessTokenRequest();
341 void ShowLoginPopup() override {
342 EXPECT_FALSE(login_ui_shown_);
343 login_ui_shown_ = true;
344 if (login_ui_result_)
345 SigninSuccess();
346 else
347 SigninFailed();
350 void ShowOAuthApprovalDialog(const IssueAdviceInfo& issue_advice) override {
351 scope_ui_shown_ = true;
353 if (scope_ui_result_) {
354 OnGaiaFlowCompleted(kAccessToken, "3600");
355 } else if (scope_ui_failure_ == GaiaWebAuthFlow::SERVICE_AUTH_ERROR) {
356 GoogleServiceAuthError error(GoogleServiceAuthError::CONNECTION_FAILED);
357 OnGaiaFlowFailure(scope_ui_failure_, error, "");
358 } else {
359 GoogleServiceAuthError error(GoogleServiceAuthError::NONE);
360 OnGaiaFlowFailure(scope_ui_failure_, error, scope_ui_oauth_error_);
364 void StartGaiaRequest(const std::string& login_access_token) override {
365 EXPECT_TRUE(login_access_token_.empty());
366 // Save the login token used in the mint token flow so tests can see
367 // what account was used.
368 login_access_token_ = login_access_token;
369 IdentityGetAuthTokenFunction::StartGaiaRequest(login_access_token);
372 OAuth2MintTokenFlow* CreateMintTokenFlow() override {
373 return flow_.release();
376 private:
377 ~FakeGetAuthTokenFunction() override {}
378 bool login_access_token_result_;
379 bool auto_login_access_token_;
380 bool login_ui_result_;
381 bool scope_ui_result_;
382 GaiaWebAuthFlow::Failure scope_ui_failure_;
383 std::string scope_ui_oauth_error_;
384 bool login_ui_shown_;
385 bool scope_ui_shown_;
387 scoped_ptr<OAuth2MintTokenFlow> flow_;
389 std::string login_access_token_;
392 class MockQueuedMintRequest : public IdentityMintRequestQueue::Request {
393 public:
394 MOCK_METHOD1(StartMintToken, void(IdentityMintRequestQueue::MintType));
397 gaia::AccountIds CreateIds(std::string email, std::string obfid) {
398 gaia::AccountIds ids;
399 ids.account_key = email;
400 ids.email = email;
401 ids.gaia = obfid;
402 return ids;
405 class IdentityGetAccountsFunctionTest : public ExtensionBrowserTest {
406 void SetUpCommandLine(base::CommandLine* command_line) override {
407 ExtensionBrowserTest::SetUpCommandLine(command_line);
408 command_line->AppendSwitch(switches::kExtensionsMultiAccount);
411 protected:
412 void SetAccountState(gaia::AccountIds ids, bool is_signed_in) {
413 IdentityAPI::GetFactoryInstance()->Get(profile())->SetAccountStateForTest(
414 ids, is_signed_in);
417 testing::AssertionResult ExpectGetAccounts(
418 const std::vector<std::string>& accounts) {
419 scoped_refptr<IdentityGetAccountsFunction> func(
420 new IdentityGetAccountsFunction);
421 func->set_extension(test_util::CreateEmptyExtension(kExtensionId).get());
422 if (!utils::RunFunction(
423 func.get(), std::string("[]"), browser(), utils::NONE)) {
424 return GenerateFailureResult(accounts, NULL)
425 << "getAccounts did not return a result.";
427 const base::ListValue* callback_arguments = func->GetResultList();
428 if (!callback_arguments)
429 return GenerateFailureResult(accounts, NULL) << "NULL result";
431 if (callback_arguments->GetSize() != 1) {
432 return GenerateFailureResult(accounts, NULL)
433 << "Expected 1 argument but got " << callback_arguments->GetSize();
436 const base::ListValue* results;
437 if (!callback_arguments->GetList(0, &results))
438 GenerateFailureResult(accounts, NULL) << "Result was not an array";
440 std::set<std::string> result_ids;
441 for (base::ListValue::const_iterator it = results->begin();
442 it != results->end();
443 ++it) {
444 scoped_ptr<api::identity::AccountInfo> info =
445 api::identity::AccountInfo::FromValue(**it);
446 if (info.get())
447 result_ids.insert(info->id);
448 else
449 return GenerateFailureResult(accounts, results);
452 for (std::vector<std::string>::const_iterator it = accounts.begin();
453 it != accounts.end();
454 ++it) {
455 if (result_ids.find(*it) == result_ids.end())
456 return GenerateFailureResult(accounts, results);
459 return testing::AssertionResult(true);
462 testing::AssertionResult GenerateFailureResult(
463 const ::std::vector<std::string>& accounts,
464 const base::ListValue* results) {
465 testing::Message msg("Expected: ");
466 for (std::vector<std::string>::const_iterator it = accounts.begin();
467 it != accounts.end();
468 ++it) {
469 msg << *it << " ";
471 msg << "Actual: ";
472 if (!results) {
473 msg << "NULL";
474 } else {
475 for (base::ListValue::const_iterator it = results->begin();
476 it != results->end();
477 ++it) {
478 scoped_ptr<api::identity::AccountInfo> info =
479 api::identity::AccountInfo::FromValue(**it);
480 if (info.get())
481 msg << info->id << " ";
482 else
483 msg << *it << "<-" << (*it)->GetType() << " ";
487 return testing::AssertionFailure(msg);
491 IN_PROC_BROWSER_TEST_F(IdentityGetAccountsFunctionTest, MultiAccountOn) {
492 EXPECT_TRUE(switches::IsExtensionsMultiAccount());
495 IN_PROC_BROWSER_TEST_F(IdentityGetAccountsFunctionTest, NoneSignedIn) {
496 EXPECT_TRUE(ExpectGetAccounts(std::vector<std::string>()));
499 IN_PROC_BROWSER_TEST_F(IdentityGetAccountsFunctionTest,
500 PrimaryAccountSignedIn) {
501 SetAccountState(CreateIds("primary@example.com", "1"), true);
502 std::vector<std::string> primary;
503 primary.push_back("1");
504 EXPECT_TRUE(ExpectGetAccounts(primary));
507 IN_PROC_BROWSER_TEST_F(IdentityGetAccountsFunctionTest, TwoAccountsSignedIn) {
508 SetAccountState(CreateIds("primary@example.com", "1"), true);
509 SetAccountState(CreateIds("secondary@example.com", "2"), true);
510 std::vector<std::string> two_accounts;
511 two_accounts.push_back("1");
512 two_accounts.push_back("2");
513 EXPECT_TRUE(ExpectGetAccounts(two_accounts));
516 class IdentityOldProfilesGetAccountsFunctionTest
517 : public IdentityGetAccountsFunctionTest {
518 void SetUpCommandLine(base::CommandLine* command_line) override {
519 // Don't add the multi-account switch that parent class would have.
523 IN_PROC_BROWSER_TEST_F(IdentityOldProfilesGetAccountsFunctionTest,
524 MultiAccountOff) {
525 EXPECT_FALSE(switches::IsExtensionsMultiAccount());
528 IN_PROC_BROWSER_TEST_F(IdentityOldProfilesGetAccountsFunctionTest,
529 TwoAccountsSignedIn) {
530 SetAccountState(CreateIds("primary@example.com", "1"), true);
531 SetAccountState(CreateIds("secondary@example.com", "2"), true);
532 std::vector<std::string> only_primary;
533 only_primary.push_back("1");
534 EXPECT_TRUE(ExpectGetAccounts(only_primary));
537 class IdentityTestWithSignin : public AsyncExtensionBrowserTest {
538 public:
539 void SetUpInProcessBrowserTestFixture() override {
540 AsyncExtensionBrowserTest::SetUpInProcessBrowserTestFixture();
542 will_create_browser_context_services_subscription_ =
543 BrowserContextDependencyManager::GetInstance()
544 ->RegisterWillCreateBrowserContextServicesCallbackForTesting(
545 base::Bind(&IdentityTestWithSignin::
546 OnWillCreateBrowserContextServices,
547 base::Unretained(this)))
548 .Pass();
551 void OnWillCreateBrowserContextServices(content::BrowserContext* context) {
552 // Replace the signin manager and token service with fakes. Do this ahead of
553 // creating the browser so that a bunch of classes don't register as
554 // observers and end up needing to unregister when the fake is substituted.
555 SigninManagerFactory::GetInstance()->SetTestingFactory(
556 context, &BuildFakeSigninManagerBase);
557 ProfileOAuth2TokenServiceFactory::GetInstance()->SetTestingFactory(
558 context, &BuildFakeProfileOAuth2TokenService);
559 GaiaCookieManagerServiceFactory::GetInstance()->SetTestingFactory(
560 context, &FakeGaiaCookieManagerService::Build);
563 void SetUpOnMainThread() override {
564 AsyncExtensionBrowserTest::SetUpOnMainThread();
566 // Grab references to the fake signin manager and token service.
567 signin_manager_ = static_cast<FakeSigninManagerForTesting*>(
568 SigninManagerFactory::GetInstance()->GetForProfile(profile()));
569 ASSERT_TRUE(signin_manager_);
570 token_service_ = static_cast<FakeProfileOAuth2TokenService*>(
571 ProfileOAuth2TokenServiceFactory::GetInstance()->GetForProfile(
572 profile()));
573 ASSERT_TRUE(token_service_);
574 GaiaCookieManagerServiceFactory::GetInstance()->GetForProfile(profile())
575 ->Init();
578 protected:
579 void SignIn(const std::string& account_key) {
580 SignIn(account_key, account_key);
583 void SignIn(const std::string& email, const std::string& gaia) {
584 AccountTrackerService* account_tracker =
585 AccountTrackerServiceFactory::GetForProfile(profile());
586 std::string account_id =
587 account_tracker->SeedAccountInfo(gaia, email);
589 #if defined(OS_CHROMEOS)
590 signin_manager_->SetAuthenticatedAccountInfo(gaia, email);
591 #else
592 signin_manager_->SignIn(gaia, email, "password");
593 #endif
594 token_service_->UpdateCredentials(account_id, "refresh_token");
597 FakeSigninManagerForTesting* signin_manager_;
598 FakeProfileOAuth2TokenService* token_service_;
600 scoped_ptr<base::CallbackList<void(content::BrowserContext*)>::Subscription>
601 will_create_browser_context_services_subscription_;
604 class IdentityGetProfileUserInfoFunctionTest : public IdentityTestWithSignin {
605 protected:
606 scoped_ptr<api::identity::ProfileUserInfo> RunGetProfileUserInfo() {
607 scoped_refptr<IdentityGetProfileUserInfoFunction> func(
608 new IdentityGetProfileUserInfoFunction);
609 func->set_extension(test_util::CreateEmptyExtension(kExtensionId).get());
610 scoped_ptr<base::Value> value(
611 utils::RunFunctionAndReturnSingleResult(func.get(), "[]", browser()));
612 return api::identity::ProfileUserInfo::FromValue(*value.get());
615 scoped_ptr<api::identity::ProfileUserInfo> RunGetProfileUserInfoWithEmail() {
616 scoped_refptr<IdentityGetProfileUserInfoFunction> func(
617 new IdentityGetProfileUserInfoFunction);
618 func->set_extension(CreateExtensionWithEmailPermission());
619 scoped_ptr<base::Value> value(
620 utils::RunFunctionAndReturnSingleResult(func.get(), "[]", browser()));
621 return api::identity::ProfileUserInfo::FromValue(*value.get());
624 private:
625 scoped_refptr<Extension> CreateExtensionWithEmailPermission() {
626 scoped_ptr<base::DictionaryValue> test_extension_value(
627 api_test_utils::ParseDictionary(
628 "{\"name\": \"Test\", \"version\": \"1.0\", "
629 "\"permissions\": [\"identity.email\"]}"));
630 return api_test_utils::CreateExtension(test_extension_value.get());
634 IN_PROC_BROWSER_TEST_F(IdentityGetProfileUserInfoFunctionTest, NotSignedIn) {
635 scoped_ptr<api::identity::ProfileUserInfo> info =
636 RunGetProfileUserInfoWithEmail();
637 EXPECT_TRUE(info->email.empty());
638 EXPECT_TRUE(info->id.empty());
641 IN_PROC_BROWSER_TEST_F(IdentityGetProfileUserInfoFunctionTest, SignedIn) {
642 SignIn("president@example.com", "12345");
643 scoped_ptr<api::identity::ProfileUserInfo> info =
644 RunGetProfileUserInfoWithEmail();
645 EXPECT_EQ("president@example.com", info->email);
646 EXPECT_EQ("12345", info->id);
649 IN_PROC_BROWSER_TEST_F(IdentityGetProfileUserInfoFunctionTest,
650 NotSignedInNoEmail) {
651 scoped_ptr<api::identity::ProfileUserInfo> info = RunGetProfileUserInfo();
652 EXPECT_TRUE(info->email.empty());
653 EXPECT_TRUE(info->id.empty());
656 IN_PROC_BROWSER_TEST_F(IdentityGetProfileUserInfoFunctionTest,
657 SignedInNoEmail) {
658 SignIn("president@example.com", "12345");
659 scoped_ptr<api::identity::ProfileUserInfo> info = RunGetProfileUserInfo();
660 EXPECT_TRUE(info->email.empty());
661 EXPECT_TRUE(info->id.empty());
664 class GetAuthTokenFunctionTest : public IdentityTestWithSignin {
665 public:
666 void SetUpCommandLine(base::CommandLine* command_line) override {
667 IdentityTestWithSignin::SetUpCommandLine(command_line);
668 command_line->AppendSwitch(switches::kExtensionsMultiAccount);
671 void IssueLoginRefreshTokenForAccount(const std::string account_key) {
672 token_service_->UpdateCredentials(account_key, "refresh_token");
675 void IssueLoginAccessTokenForAccount(const std::string account_key) {
676 token_service_->IssueAllTokensForAccount(
677 account_key,
678 "access_token-" + account_key,
679 base::Time::Now() + base::TimeDelta::FromSeconds(3600));
682 void SetAccountState(gaia::AccountIds ids, bool is_signed_in) {
683 IdentityAPI::GetFactoryInstance()->Get(profile())->SetAccountStateForTest(
684 ids, is_signed_in);
687 protected:
688 enum OAuth2Fields {
689 NONE = 0,
690 CLIENT_ID = 1,
691 SCOPES = 2,
692 AS_COMPONENT = 4
695 ~GetAuthTokenFunctionTest() override {}
697 // Helper to create an extension with specific OAuth2Info fields set.
698 // |fields_to_set| should be computed by using fields of Oauth2Fields enum.
699 const Extension* CreateExtension(int fields_to_set) {
700 const Extension* ext;
701 base::FilePath manifest_path =
702 test_data_dir_.AppendASCII("platform_apps/oauth2");
703 base::FilePath component_manifest_path =
704 test_data_dir_.AppendASCII("packaged_app/component_oauth2");
705 if ((fields_to_set & AS_COMPONENT) == 0)
706 ext = LoadExtension(manifest_path);
707 else
708 ext = LoadExtensionAsComponent(component_manifest_path);
709 OAuth2Info& oauth2_info =
710 const_cast<OAuth2Info&>(OAuth2Info::GetOAuth2Info(ext));
711 if ((fields_to_set & CLIENT_ID) != 0)
712 oauth2_info.client_id = "client1";
713 if ((fields_to_set & SCOPES) != 0) {
714 oauth2_info.scopes.push_back("scope1");
715 oauth2_info.scopes.push_back("scope2");
718 extension_id_ = ext->id();
719 oauth_scopes_ = std::set<std::string>(oauth2_info.scopes.begin(),
720 oauth2_info.scopes.end());
721 return ext;
724 IdentityAPI* id_api() {
725 return IdentityAPI::GetFactoryInstance()->Get(browser()->profile());
728 const std::string& GetPrimaryAccountId() {
729 SigninManagerBase* signin_manager =
730 SigninManagerFactory::GetForProfile(browser()->profile());
731 return signin_manager->GetAuthenticatedAccountId();
734 void SetCachedToken(const IdentityTokenCacheValue& token_data) {
735 ExtensionTokenKey key(extension_id_, GetPrimaryAccountId(), oauth_scopes_);
736 id_api()->SetCachedToken(key, token_data);
739 const IdentityTokenCacheValue& GetCachedToken(std::string account_id) {
740 if (account_id.empty())
741 account_id = GetPrimaryAccountId();
742 ExtensionTokenKey key(extension_id_, account_id, oauth_scopes_);
743 return id_api()->GetCachedToken(key);
746 void QueueRequestStart(IdentityMintRequestQueue::MintType type,
747 IdentityMintRequestQueue::Request* request) {
748 ExtensionTokenKey key(extension_id_, GetPrimaryAccountId(), oauth_scopes_);
749 id_api()->mint_queue()->RequestStart(type, key, request);
752 void QueueRequestComplete(IdentityMintRequestQueue::MintType type,
753 IdentityMintRequestQueue::Request* request) {
754 ExtensionTokenKey key(extension_id_, GetPrimaryAccountId(), oauth_scopes_);
755 id_api()->mint_queue()->RequestComplete(type, key, request);
758 private:
759 std::string extension_id_;
760 std::set<std::string> oauth_scopes_;
763 IN_PROC_BROWSER_TEST_F(GetAuthTokenFunctionTest,
764 NoClientId) {
765 scoped_refptr<FakeGetAuthTokenFunction> func(new FakeGetAuthTokenFunction());
766 func->set_extension(CreateExtension(SCOPES));
767 std::string error = utils::RunFunctionAndReturnError(
768 func.get(), "[{}]", browser());
769 EXPECT_EQ(std::string(errors::kInvalidClientId), error);
770 EXPECT_FALSE(func->login_ui_shown());
771 EXPECT_FALSE(func->scope_ui_shown());
774 IN_PROC_BROWSER_TEST_F(GetAuthTokenFunctionTest,
775 NoScopes) {
776 scoped_refptr<FakeGetAuthTokenFunction> func(new FakeGetAuthTokenFunction());
777 func->set_extension(CreateExtension(CLIENT_ID));
778 std::string error = utils::RunFunctionAndReturnError(
779 func.get(), "[{}]", browser());
780 EXPECT_EQ(std::string(errors::kInvalidScopes), error);
781 EXPECT_FALSE(func->login_ui_shown());
782 EXPECT_FALSE(func->scope_ui_shown());
785 IN_PROC_BROWSER_TEST_F(GetAuthTokenFunctionTest,
786 NonInteractiveNotSignedIn) {
787 scoped_refptr<FakeGetAuthTokenFunction> func(new FakeGetAuthTokenFunction());
788 func->set_extension(CreateExtension(CLIENT_ID | SCOPES));
789 std::string error = utils::RunFunctionAndReturnError(
790 func.get(), "[{}]", browser());
791 EXPECT_EQ(std::string(errors::kUserNotSignedIn), error);
792 EXPECT_FALSE(func->login_ui_shown());
793 EXPECT_FALSE(func->scope_ui_shown());
796 IN_PROC_BROWSER_TEST_F(GetAuthTokenFunctionTest,
797 NonInteractiveMintFailure) {
798 SignIn("primary@example.com");
799 scoped_refptr<FakeGetAuthTokenFunction> func(new FakeGetAuthTokenFunction());
800 func->set_extension(CreateExtension(CLIENT_ID | SCOPES));
801 func->set_mint_token_result(TestOAuth2MintTokenFlow::MINT_TOKEN_FAILURE);
802 std::string error =
803 utils::RunFunctionAndReturnError(func.get(), "[{}]", browser());
804 EXPECT_TRUE(base::StartsWith(error, errors::kAuthFailure,
805 base::CompareCase::INSENSITIVE_ASCII));
806 EXPECT_FALSE(func->login_ui_shown());
807 EXPECT_FALSE(func->scope_ui_shown());
810 IN_PROC_BROWSER_TEST_F(GetAuthTokenFunctionTest,
811 NonInteractiveLoginAccessTokenFailure) {
812 SignIn("primary@example.com");
813 scoped_refptr<FakeGetAuthTokenFunction> func(new FakeGetAuthTokenFunction());
814 func->set_extension(CreateExtension(CLIENT_ID | SCOPES));
815 func->set_login_access_token_result(false);
816 std::string error = utils::RunFunctionAndReturnError(
817 func.get(), "[{}]", browser());
818 EXPECT_TRUE(base::StartsWith(error, errors::kAuthFailure,
819 base::CompareCase::INSENSITIVE_ASCII));
822 IN_PROC_BROWSER_TEST_F(GetAuthTokenFunctionTest,
823 NonInteractiveMintAdviceSuccess) {
824 SignIn("primary@example.com");
825 scoped_refptr<const Extension> extension(CreateExtension(CLIENT_ID | SCOPES));
826 scoped_refptr<FakeGetAuthTokenFunction> func(new FakeGetAuthTokenFunction());
827 func->set_extension(extension.get());
828 func->set_mint_token_result(TestOAuth2MintTokenFlow::ISSUE_ADVICE_SUCCESS);
829 std::string error =
830 utils::RunFunctionAndReturnError(func.get(), "[{}]", browser());
831 EXPECT_EQ(std::string(errors::kNoGrant), error);
832 EXPECT_FALSE(func->login_ui_shown());
833 EXPECT_FALSE(func->scope_ui_shown());
835 EXPECT_EQ(IdentityTokenCacheValue::CACHE_STATUS_ADVICE,
836 GetCachedToken(std::string()).status());
839 IN_PROC_BROWSER_TEST_F(GetAuthTokenFunctionTest,
840 NonInteractiveMintBadCredentials) {
841 SignIn("primary@example.com");
842 scoped_refptr<FakeGetAuthTokenFunction> func(new FakeGetAuthTokenFunction());
843 func->set_extension(CreateExtension(CLIENT_ID | SCOPES));
844 func->set_mint_token_result(
845 TestOAuth2MintTokenFlow::MINT_TOKEN_BAD_CREDENTIALS);
846 std::string error =
847 utils::RunFunctionAndReturnError(func.get(), "[{}]", browser());
848 EXPECT_TRUE(base::StartsWith(error, errors::kAuthFailure,
849 base::CompareCase::INSENSITIVE_ASCII));
850 EXPECT_FALSE(func->login_ui_shown());
851 EXPECT_FALSE(func->scope_ui_shown());
854 IN_PROC_BROWSER_TEST_F(GetAuthTokenFunctionTest,
855 NonInteractiveMintServiceError) {
856 SignIn("primary@example.com");
857 scoped_refptr<FakeGetAuthTokenFunction> func(new FakeGetAuthTokenFunction());
858 func->set_extension(CreateExtension(CLIENT_ID | SCOPES));
859 func->set_mint_token_result(
860 TestOAuth2MintTokenFlow::MINT_TOKEN_SERVICE_ERROR);
861 std::string error =
862 utils::RunFunctionAndReturnError(func.get(), "[{}]", browser());
863 EXPECT_TRUE(base::StartsWith(error, errors::kAuthFailure,
864 base::CompareCase::INSENSITIVE_ASCII));
865 EXPECT_FALSE(func->login_ui_shown());
866 EXPECT_FALSE(func->scope_ui_shown());
869 IN_PROC_BROWSER_TEST_F(GetAuthTokenFunctionTest,
870 NoOptionsSuccess) {
871 SignIn("primary@example.com");
872 #if defined(OS_WIN) && defined(USE_ASH)
873 // Disable this test in Metro+Ash for now (http://crbug.com/262796).
874 if (base::CommandLine::ForCurrentProcess()->HasSwitch(
875 switches::kAshBrowserTests))
876 return;
877 #endif
879 scoped_refptr<FakeGetAuthTokenFunction> func(new FakeGetAuthTokenFunction());
880 scoped_refptr<const Extension> extension(CreateExtension(CLIENT_ID | SCOPES));
881 func->set_extension(extension.get());
882 func->set_mint_token_result(TestOAuth2MintTokenFlow::MINT_TOKEN_SUCCESS);
883 scoped_ptr<base::Value> value(
884 utils::RunFunctionAndReturnSingleResult(func.get(), "[]", browser()));
885 std::string access_token;
886 EXPECT_TRUE(value->GetAsString(&access_token));
887 EXPECT_EQ(std::string(kAccessToken), access_token);
888 EXPECT_FALSE(func->login_ui_shown());
889 EXPECT_FALSE(func->scope_ui_shown());
890 EXPECT_EQ(IdentityTokenCacheValue::CACHE_STATUS_TOKEN,
891 GetCachedToken(std::string()).status());
894 IN_PROC_BROWSER_TEST_F(GetAuthTokenFunctionTest,
895 NonInteractiveSuccess) {
896 SignIn("primary@example.com");
897 #if defined(OS_WIN) && defined(USE_ASH)
898 // Disable this test in Metro+Ash for now (http://crbug.com/262796).
899 if (base::CommandLine::ForCurrentProcess()->HasSwitch(
900 switches::kAshBrowserTests))
901 return;
902 #endif
904 scoped_refptr<FakeGetAuthTokenFunction> func(new FakeGetAuthTokenFunction());
905 scoped_refptr<const Extension> extension(CreateExtension(CLIENT_ID | SCOPES));
906 func->set_extension(extension.get());
907 func->set_mint_token_result(TestOAuth2MintTokenFlow::MINT_TOKEN_SUCCESS);
908 scoped_ptr<base::Value> value(utils::RunFunctionAndReturnSingleResult(
909 func.get(), "[{}]", browser()));
910 std::string access_token;
911 EXPECT_TRUE(value->GetAsString(&access_token));
912 EXPECT_EQ(std::string(kAccessToken), access_token);
913 EXPECT_FALSE(func->login_ui_shown());
914 EXPECT_FALSE(func->scope_ui_shown());
915 EXPECT_EQ(IdentityTokenCacheValue::CACHE_STATUS_TOKEN,
916 GetCachedToken(std::string()).status());
919 IN_PROC_BROWSER_TEST_F(GetAuthTokenFunctionTest,
920 InteractiveLoginCanceled) {
921 scoped_refptr<FakeGetAuthTokenFunction> func(new FakeGetAuthTokenFunction());
922 func->set_extension(CreateExtension(CLIENT_ID | SCOPES));
923 func->set_login_ui_result(false);
924 std::string error = utils::RunFunctionAndReturnError(
925 func.get(), "[{\"interactive\": true}]", browser());
926 EXPECT_EQ(std::string(errors::kUserNotSignedIn), error);
927 EXPECT_TRUE(func->login_ui_shown());
928 EXPECT_FALSE(func->scope_ui_shown());
931 IN_PROC_BROWSER_TEST_F(GetAuthTokenFunctionTest,
932 InteractiveMintBadCredentialsLoginCanceled) {
933 SignIn("primary@example.com");
934 scoped_refptr<FakeGetAuthTokenFunction> func(new FakeGetAuthTokenFunction());
935 func->set_extension(CreateExtension(CLIENT_ID | SCOPES));
936 func->set_mint_token_result(
937 TestOAuth2MintTokenFlow::MINT_TOKEN_BAD_CREDENTIALS);
938 func->set_login_ui_result(false);
939 std::string error = utils::RunFunctionAndReturnError(
940 func.get(), "[{\"interactive\": true}]", browser());
941 EXPECT_EQ(std::string(errors::kUserNotSignedIn), error);
942 EXPECT_TRUE(func->login_ui_shown());
943 EXPECT_FALSE(func->scope_ui_shown());
946 IN_PROC_BROWSER_TEST_F(GetAuthTokenFunctionTest,
947 InteractiveLoginSuccessNoToken) {
948 scoped_refptr<FakeGetAuthTokenFunction> func(new FakeGetAuthTokenFunction());
949 func->set_extension(CreateExtension(CLIENT_ID | SCOPES));
950 func->set_login_ui_result(false);
951 std::string error = utils::RunFunctionAndReturnError(
952 func.get(), "[{\"interactive\": true}]", browser());
953 EXPECT_EQ(std::string(errors::kUserNotSignedIn), error);
954 EXPECT_TRUE(func->login_ui_shown());
955 EXPECT_FALSE(func->scope_ui_shown());
958 IN_PROC_BROWSER_TEST_F(GetAuthTokenFunctionTest,
959 InteractiveLoginSuccessMintFailure) {
960 scoped_refptr<FakeGetAuthTokenFunction> func(new FakeGetAuthTokenFunction());
961 func->set_extension(CreateExtension(CLIENT_ID | SCOPES));
962 func->set_login_ui_result(true);
963 func->set_mint_token_result(TestOAuth2MintTokenFlow::MINT_TOKEN_FAILURE);
964 std::string error = utils::RunFunctionAndReturnError(
965 func.get(), "[{\"interactive\": true}]", browser());
966 EXPECT_TRUE(base::StartsWith(error, errors::kAuthFailure,
967 base::CompareCase::INSENSITIVE_ASCII));
968 EXPECT_TRUE(func->login_ui_shown());
969 EXPECT_FALSE(func->scope_ui_shown());
972 IN_PROC_BROWSER_TEST_F(GetAuthTokenFunctionTest,
973 InteractiveLoginSuccessLoginAccessTokenFailure) {
974 scoped_refptr<FakeGetAuthTokenFunction> func(new FakeGetAuthTokenFunction());
975 func->set_extension(CreateExtension(CLIENT_ID | SCOPES));
976 func->set_login_ui_result(true);
977 func->set_login_access_token_result(false);
978 std::string error = utils::RunFunctionAndReturnError(
979 func.get(), "[{\"interactive\": true}]", browser());
980 EXPECT_TRUE(base::StartsWith(error, errors::kAuthFailure,
981 base::CompareCase::INSENSITIVE_ASCII));
982 EXPECT_TRUE(func->login_ui_shown());
983 EXPECT_FALSE(func->scope_ui_shown());
986 IN_PROC_BROWSER_TEST_F(GetAuthTokenFunctionTest,
987 InteractiveLoginSuccessMintSuccess) {
988 // TODO(courage): verify that account_id in token service requests
989 // is correct once manual token minting for tests is implemented.
990 scoped_refptr<FakeGetAuthTokenFunction> func(new FakeGetAuthTokenFunction());
991 func->set_extension(CreateExtension(CLIENT_ID | SCOPES));
992 func->set_login_ui_result(true);
993 func->set_mint_token_result(TestOAuth2MintTokenFlow::MINT_TOKEN_SUCCESS);
994 scoped_ptr<base::Value> value(utils::RunFunctionAndReturnSingleResult(
995 func.get(), "[{\"interactive\": true}]", browser()));
996 std::string access_token;
997 EXPECT_TRUE(value->GetAsString(&access_token));
998 EXPECT_EQ(std::string(kAccessToken), access_token);
999 EXPECT_TRUE(func->login_ui_shown());
1000 EXPECT_FALSE(func->scope_ui_shown());
1003 IN_PROC_BROWSER_TEST_F(GetAuthTokenFunctionTest,
1004 InteractiveLoginSuccessApprovalAborted) {
1005 scoped_refptr<FakeGetAuthTokenFunction> func(new FakeGetAuthTokenFunction());
1006 func->set_extension(CreateExtension(CLIENT_ID | SCOPES));
1007 func->set_login_ui_result(true);
1008 func->set_mint_token_result(TestOAuth2MintTokenFlow::ISSUE_ADVICE_SUCCESS);
1009 func->set_scope_ui_failure(GaiaWebAuthFlow::WINDOW_CLOSED);
1010 std::string error = utils::RunFunctionAndReturnError(
1011 func.get(), "[{\"interactive\": true}]", browser());
1012 EXPECT_EQ(std::string(errors::kUserRejected), error);
1013 EXPECT_TRUE(func->login_ui_shown());
1014 EXPECT_TRUE(func->scope_ui_shown());
1017 IN_PROC_BROWSER_TEST_F(GetAuthTokenFunctionTest,
1018 InteractiveLoginSuccessApprovalSuccess) {
1019 scoped_refptr<const Extension> extension(CreateExtension(CLIENT_ID | SCOPES));
1020 scoped_refptr<FakeGetAuthTokenFunction> func(new FakeGetAuthTokenFunction());
1021 func->set_extension(extension.get());
1022 func->set_login_ui_result(true);
1023 func->set_mint_token_result(TestOAuth2MintTokenFlow::ISSUE_ADVICE_SUCCESS);
1025 scoped_ptr<base::Value> value(utils::RunFunctionAndReturnSingleResult(
1026 func.get(), "[{\"interactive\": true}]", browser()));
1027 std::string access_token;
1028 EXPECT_TRUE(value->GetAsString(&access_token));
1029 EXPECT_EQ(std::string(kAccessToken), access_token);
1030 EXPECT_TRUE(func->login_ui_shown());
1031 EXPECT_TRUE(func->scope_ui_shown());
1034 IN_PROC_BROWSER_TEST_F(GetAuthTokenFunctionTest,
1035 InteractiveApprovalAborted) {
1036 SignIn("primary@example.com");
1037 scoped_refptr<FakeGetAuthTokenFunction> func(new FakeGetAuthTokenFunction());
1038 func->set_extension(CreateExtension(CLIENT_ID | SCOPES));
1039 func->set_mint_token_result(TestOAuth2MintTokenFlow::ISSUE_ADVICE_SUCCESS);
1040 func->set_scope_ui_failure(GaiaWebAuthFlow::WINDOW_CLOSED);
1041 std::string error = utils::RunFunctionAndReturnError(
1042 func.get(), "[{\"interactive\": true}]", browser());
1043 EXPECT_EQ(std::string(errors::kUserRejected), error);
1044 EXPECT_FALSE(func->login_ui_shown());
1045 EXPECT_TRUE(func->scope_ui_shown());
1048 IN_PROC_BROWSER_TEST_F(GetAuthTokenFunctionTest,
1049 InteractiveApprovalLoadFailed) {
1050 SignIn("primary@example.com");
1051 scoped_refptr<FakeGetAuthTokenFunction> func(new FakeGetAuthTokenFunction());
1052 func->set_extension(CreateExtension(CLIENT_ID | SCOPES));
1053 func->set_mint_token_result(TestOAuth2MintTokenFlow::ISSUE_ADVICE_SUCCESS);
1054 func->set_scope_ui_failure(GaiaWebAuthFlow::LOAD_FAILED);
1055 std::string error = utils::RunFunctionAndReturnError(
1056 func.get(), "[{\"interactive\": true}]", browser());
1057 EXPECT_EQ(std::string(errors::kPageLoadFailure), error);
1058 EXPECT_FALSE(func->login_ui_shown());
1059 EXPECT_TRUE(func->scope_ui_shown());
1062 IN_PROC_BROWSER_TEST_F(GetAuthTokenFunctionTest,
1063 InteractiveApprovalInvalidRedirect) {
1064 SignIn("primary@example.com");
1065 scoped_refptr<FakeGetAuthTokenFunction> func(new FakeGetAuthTokenFunction());
1066 func->set_extension(CreateExtension(CLIENT_ID | SCOPES));
1067 func->set_mint_token_result(TestOAuth2MintTokenFlow::ISSUE_ADVICE_SUCCESS);
1068 func->set_scope_ui_failure(GaiaWebAuthFlow::INVALID_REDIRECT);
1069 std::string error = utils::RunFunctionAndReturnError(
1070 func.get(), "[{\"interactive\": true}]", browser());
1071 EXPECT_EQ(std::string(errors::kInvalidRedirect), error);
1072 EXPECT_FALSE(func->login_ui_shown());
1073 EXPECT_TRUE(func->scope_ui_shown());
1076 IN_PROC_BROWSER_TEST_F(GetAuthTokenFunctionTest,
1077 InteractiveApprovalConnectionFailure) {
1078 SignIn("primary@example.com");
1079 scoped_refptr<FakeGetAuthTokenFunction> func(new FakeGetAuthTokenFunction());
1080 func->set_extension(CreateExtension(CLIENT_ID | SCOPES));
1081 func->set_mint_token_result(TestOAuth2MintTokenFlow::ISSUE_ADVICE_SUCCESS);
1082 func->set_scope_ui_failure(GaiaWebAuthFlow::SERVICE_AUTH_ERROR);
1083 std::string error = utils::RunFunctionAndReturnError(
1084 func.get(), "[{\"interactive\": true}]", browser());
1085 EXPECT_TRUE(base::StartsWith(error, errors::kAuthFailure,
1086 base::CompareCase::INSENSITIVE_ASCII));
1087 EXPECT_FALSE(func->login_ui_shown());
1088 EXPECT_TRUE(func->scope_ui_shown());
1091 IN_PROC_BROWSER_TEST_F(GetAuthTokenFunctionTest,
1092 InteractiveApprovalOAuthErrors) {
1093 SignIn("primary@example.com");
1094 scoped_refptr<const Extension> extension(CreateExtension(CLIENT_ID | SCOPES));
1096 std::map<std::string, std::string> error_map;
1097 error_map.insert(std::make_pair("access_denied", errors::kUserRejected));
1098 error_map.insert(std::make_pair("invalid_scope", errors::kInvalidScopes));
1099 error_map.insert(std::make_pair(
1100 "unmapped_error", std::string(errors::kAuthFailure) + "unmapped_error"));
1102 for (std::map<std::string, std::string>::const_iterator
1103 it = error_map.begin();
1104 it != error_map.end();
1105 ++it) {
1106 scoped_refptr<FakeGetAuthTokenFunction> func(
1107 new FakeGetAuthTokenFunction());
1108 func->set_extension(extension.get());
1109 // Make sure we don't get a cached issue_advice result, which would cause
1110 // flow to be leaked.
1111 id_api()->EraseAllCachedTokens();
1112 func->set_mint_token_result(TestOAuth2MintTokenFlow::ISSUE_ADVICE_SUCCESS);
1113 func->set_scope_ui_oauth_error(it->first);
1114 std::string error = utils::RunFunctionAndReturnError(
1115 func.get(), "[{\"interactive\": true}]", browser());
1116 EXPECT_EQ(it->second, error);
1117 EXPECT_FALSE(func->login_ui_shown());
1118 EXPECT_TRUE(func->scope_ui_shown());
1122 IN_PROC_BROWSER_TEST_F(GetAuthTokenFunctionTest,
1123 InteractiveApprovalSuccess) {
1124 SignIn("primary@example.com");
1125 scoped_refptr<const Extension> extension(CreateExtension(CLIENT_ID | SCOPES));
1126 scoped_refptr<FakeGetAuthTokenFunction> func(new FakeGetAuthTokenFunction());
1127 func->set_extension(extension.get());
1128 func->set_mint_token_result(TestOAuth2MintTokenFlow::ISSUE_ADVICE_SUCCESS);
1130 scoped_ptr<base::Value> value(utils::RunFunctionAndReturnSingleResult(
1131 func.get(), "[{\"interactive\": true}]", browser()));
1132 std::string access_token;
1133 EXPECT_TRUE(value->GetAsString(&access_token));
1134 EXPECT_EQ(std::string(kAccessToken), access_token);
1135 EXPECT_FALSE(func->login_ui_shown());
1136 EXPECT_TRUE(func->scope_ui_shown());
1138 EXPECT_EQ(IdentityTokenCacheValue::CACHE_STATUS_TOKEN,
1139 GetCachedToken(std::string()).status());
1142 IN_PROC_BROWSER_TEST_F(GetAuthTokenFunctionTest, NoninteractiveQueue) {
1143 SignIn("primary@example.com");
1144 scoped_refptr<const Extension> extension(CreateExtension(CLIENT_ID | SCOPES));
1145 scoped_refptr<FakeGetAuthTokenFunction> func(new FakeGetAuthTokenFunction());
1146 func->set_extension(extension.get());
1148 // Create a fake request to block the queue.
1149 MockQueuedMintRequest queued_request;
1150 IdentityMintRequestQueue::MintType type =
1151 IdentityMintRequestQueue::MINT_TYPE_NONINTERACTIVE;
1153 EXPECT_CALL(queued_request, StartMintToken(type)).Times(1);
1154 QueueRequestStart(type, &queued_request);
1156 // The real request will start processing, but wait in the queue behind
1157 // the blocker.
1158 RunFunctionAsync(func.get(), "[{}]");
1159 // Verify that we have fetched the login token at this point.
1160 testing::Mock::VerifyAndClearExpectations(func.get());
1162 // The flow will be created after the first queued request clears.
1163 func->set_mint_token_result(TestOAuth2MintTokenFlow::MINT_TOKEN_SUCCESS);
1165 QueueRequestComplete(type, &queued_request);
1167 scoped_ptr<base::Value> value(WaitForSingleResult(func.get()));
1168 std::string access_token;
1169 EXPECT_TRUE(value->GetAsString(&access_token));
1170 EXPECT_EQ(std::string(kAccessToken), access_token);
1171 EXPECT_FALSE(func->login_ui_shown());
1172 EXPECT_FALSE(func->scope_ui_shown());
1175 IN_PROC_BROWSER_TEST_F(GetAuthTokenFunctionTest, InteractiveQueue) {
1176 SignIn("primary@example.com");
1177 scoped_refptr<const Extension> extension(CreateExtension(CLIENT_ID | SCOPES));
1178 scoped_refptr<FakeGetAuthTokenFunction> func(new FakeGetAuthTokenFunction());
1179 func->set_extension(extension.get());
1181 // Create a fake request to block the queue.
1182 MockQueuedMintRequest queued_request;
1183 IdentityMintRequestQueue::MintType type =
1184 IdentityMintRequestQueue::MINT_TYPE_INTERACTIVE;
1186 EXPECT_CALL(queued_request, StartMintToken(type)).Times(1);
1187 QueueRequestStart(type, &queued_request);
1189 // The real request will start processing, but wait in the queue behind
1190 // the blocker.
1191 func->set_mint_token_result(TestOAuth2MintTokenFlow::ISSUE_ADVICE_SUCCESS);
1192 RunFunctionAsync(func.get(), "[{\"interactive\": true}]");
1193 // Verify that we have fetched the login token and run the first flow.
1194 testing::Mock::VerifyAndClearExpectations(func.get());
1195 EXPECT_FALSE(func->scope_ui_shown());
1197 // The UI will be displayed and a token retrieved after the first
1198 // queued request clears.
1199 QueueRequestComplete(type, &queued_request);
1201 scoped_ptr<base::Value> value(WaitForSingleResult(func.get()));
1202 std::string access_token;
1203 EXPECT_TRUE(value->GetAsString(&access_token));
1204 EXPECT_EQ(std::string(kAccessToken), access_token);
1205 EXPECT_FALSE(func->login_ui_shown());
1206 EXPECT_TRUE(func->scope_ui_shown());
1209 IN_PROC_BROWSER_TEST_F(GetAuthTokenFunctionTest, InteractiveQueueShutdown) {
1210 SignIn("primary@example.com");
1211 scoped_refptr<const Extension> extension(CreateExtension(CLIENT_ID | SCOPES));
1212 scoped_refptr<FakeGetAuthTokenFunction> func(new FakeGetAuthTokenFunction());
1213 func->set_extension(extension.get());
1215 // Create a fake request to block the queue.
1216 MockQueuedMintRequest queued_request;
1217 IdentityMintRequestQueue::MintType type =
1218 IdentityMintRequestQueue::MINT_TYPE_INTERACTIVE;
1220 EXPECT_CALL(queued_request, StartMintToken(type)).Times(1);
1221 QueueRequestStart(type, &queued_request);
1223 // The real request will start processing, but wait in the queue behind
1224 // the blocker.
1225 func->set_mint_token_result(TestOAuth2MintTokenFlow::ISSUE_ADVICE_SUCCESS);
1226 RunFunctionAsync(func.get(), "[{\"interactive\": true}]");
1227 // Verify that we have fetched the login token and run the first flow.
1228 testing::Mock::VerifyAndClearExpectations(func.get());
1229 EXPECT_FALSE(func->scope_ui_shown());
1231 // After the request is canceled, the function will complete.
1232 func->OnShutdown();
1233 EXPECT_EQ(std::string(errors::kCanceled), WaitForError(func.get()));
1234 EXPECT_FALSE(func->login_ui_shown());
1235 EXPECT_FALSE(func->scope_ui_shown());
1237 QueueRequestComplete(type, &queued_request);
1240 IN_PROC_BROWSER_TEST_F(GetAuthTokenFunctionTest, NoninteractiveShutdown) {
1241 SignIn("primary@example.com");
1242 scoped_refptr<const Extension> extension(CreateExtension(CLIENT_ID | SCOPES));
1243 scoped_refptr<FakeGetAuthTokenFunction> func(new FakeGetAuthTokenFunction());
1244 func->set_extension(extension.get());
1246 func->set_mint_token_flow(make_scoped_ptr(new TestHangOAuth2MintTokenFlow()));
1247 RunFunctionAsync(func.get(), "[{\"interactive\": false}]");
1249 // After the request is canceled, the function will complete.
1250 func->OnShutdown();
1251 EXPECT_EQ(std::string(errors::kCanceled), WaitForError(func.get()));
1254 IN_PROC_BROWSER_TEST_F(GetAuthTokenFunctionTest,
1255 InteractiveQueuedNoninteractiveFails) {
1256 SignIn("primary@example.com");
1257 scoped_refptr<const Extension> extension(CreateExtension(CLIENT_ID | SCOPES));
1258 scoped_refptr<FakeGetAuthTokenFunction> func(new FakeGetAuthTokenFunction());
1259 func->set_extension(extension.get());
1261 // Create a fake request to block the interactive queue.
1262 MockQueuedMintRequest queued_request;
1263 IdentityMintRequestQueue::MintType type =
1264 IdentityMintRequestQueue::MINT_TYPE_INTERACTIVE;
1266 EXPECT_CALL(queued_request, StartMintToken(type)).Times(1);
1267 QueueRequestStart(type, &queued_request);
1269 // Non-interactive requests fail without hitting GAIA, because a
1270 // consent UI is known to be up.
1271 std::string error = utils::RunFunctionAndReturnError(
1272 func.get(), "[{}]", browser());
1273 EXPECT_EQ(std::string(errors::kNoGrant), error);
1274 EXPECT_FALSE(func->login_ui_shown());
1275 EXPECT_FALSE(func->scope_ui_shown());
1277 QueueRequestComplete(type, &queued_request);
1280 IN_PROC_BROWSER_TEST_F(GetAuthTokenFunctionTest,
1281 NonInteractiveCacheHit) {
1282 SignIn("primary@example.com");
1283 scoped_refptr<const Extension> extension(CreateExtension(CLIENT_ID | SCOPES));
1284 scoped_refptr<FakeGetAuthTokenFunction> func(new FakeGetAuthTokenFunction());
1285 func->set_extension(extension.get());
1287 // pre-populate the cache with a token
1288 IdentityTokenCacheValue token(kAccessToken,
1289 base::TimeDelta::FromSeconds(3600));
1290 SetCachedToken(token);
1292 // Get a token. Should not require a GAIA request.
1293 scoped_ptr<base::Value> value(utils::RunFunctionAndReturnSingleResult(
1294 func.get(), "[{}]", browser()));
1295 std::string access_token;
1296 EXPECT_TRUE(value->GetAsString(&access_token));
1297 EXPECT_EQ(std::string(kAccessToken), access_token);
1298 EXPECT_FALSE(func->login_ui_shown());
1299 EXPECT_FALSE(func->scope_ui_shown());
1302 IN_PROC_BROWSER_TEST_F(GetAuthTokenFunctionTest,
1303 NonInteractiveIssueAdviceCacheHit) {
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 // pre-populate the cache with advice
1310 IssueAdviceInfo info;
1311 IdentityTokenCacheValue token(info);
1312 SetCachedToken(token);
1314 // Should return an error without a GAIA request.
1315 std::string error = utils::RunFunctionAndReturnError(
1316 func.get(), "[{}]", browser());
1317 EXPECT_EQ(std::string(errors::kNoGrant), error);
1318 EXPECT_FALSE(func->login_ui_shown());
1319 EXPECT_FALSE(func->scope_ui_shown());
1322 IN_PROC_BROWSER_TEST_F(GetAuthTokenFunctionTest,
1323 InteractiveCacheHit) {
1324 SignIn("primary@example.com");
1325 scoped_refptr<const Extension> extension(CreateExtension(CLIENT_ID | SCOPES));
1326 scoped_refptr<FakeGetAuthTokenFunction> func(new FakeGetAuthTokenFunction());
1327 func->set_extension(extension.get());
1329 // Create a fake request to block the queue.
1330 MockQueuedMintRequest queued_request;
1331 IdentityMintRequestQueue::MintType type =
1332 IdentityMintRequestQueue::MINT_TYPE_INTERACTIVE;
1334 EXPECT_CALL(queued_request, StartMintToken(type)).Times(1);
1335 QueueRequestStart(type, &queued_request);
1337 // The real request will start processing, but wait in the queue behind
1338 // the blocker.
1339 func->set_mint_token_result(TestOAuth2MintTokenFlow::ISSUE_ADVICE_SUCCESS);
1340 RunFunctionAsync(func.get(), "[{\"interactive\": true}]");
1342 // Populate the cache with a token while the request is blocked.
1343 IdentityTokenCacheValue token(kAccessToken,
1344 base::TimeDelta::FromSeconds(3600));
1345 SetCachedToken(token);
1347 // When we wake up the request, it returns the cached token without
1348 // displaying a UI, or hitting GAIA.
1350 QueueRequestComplete(type, &queued_request);
1352 scoped_ptr<base::Value> value(WaitForSingleResult(func.get()));
1353 std::string access_token;
1354 EXPECT_TRUE(value->GetAsString(&access_token));
1355 EXPECT_EQ(std::string(kAccessToken), access_token);
1356 EXPECT_FALSE(func->login_ui_shown());
1357 EXPECT_FALSE(func->scope_ui_shown());
1360 IN_PROC_BROWSER_TEST_F(GetAuthTokenFunctionTest,
1361 LoginInvalidatesTokenCache) {
1362 scoped_refptr<FakeGetAuthTokenFunction> func(new FakeGetAuthTokenFunction());
1363 scoped_refptr<const Extension> extension(CreateExtension(CLIENT_ID | SCOPES));
1364 func->set_extension(extension.get());
1366 // pre-populate the cache with a token
1367 IdentityTokenCacheValue token(kAccessToken,
1368 base::TimeDelta::FromSeconds(3600));
1369 SetCachedToken(token);
1371 // Because the user is not signed in, the token will be removed,
1372 // and we'll hit GAIA for new tokens.
1373 func->set_login_ui_result(true);
1374 func->set_mint_token_result(TestOAuth2MintTokenFlow::ISSUE_ADVICE_SUCCESS);
1376 scoped_ptr<base::Value> value(utils::RunFunctionAndReturnSingleResult(
1377 func.get(), "[{\"interactive\": true}]", browser()));
1378 std::string access_token;
1379 EXPECT_TRUE(value->GetAsString(&access_token));
1380 EXPECT_EQ(std::string(kAccessToken), access_token);
1381 EXPECT_TRUE(func->login_ui_shown());
1382 EXPECT_TRUE(func->scope_ui_shown());
1383 EXPECT_EQ(IdentityTokenCacheValue::CACHE_STATUS_TOKEN,
1384 GetCachedToken(std::string()).status());
1387 IN_PROC_BROWSER_TEST_F(GetAuthTokenFunctionTest, ComponentWithChromeClientId) {
1388 scoped_refptr<FakeGetAuthTokenFunction> func(new FakeGetAuthTokenFunction());
1389 scoped_refptr<const Extension> extension(
1390 CreateExtension(SCOPES | AS_COMPONENT));
1391 func->set_extension(extension.get());
1392 const OAuth2Info& oauth2_info = OAuth2Info::GetOAuth2Info(extension.get());
1393 EXPECT_TRUE(oauth2_info.client_id.empty());
1394 EXPECT_FALSE(func->GetOAuth2ClientId().empty());
1395 EXPECT_NE("client1", func->GetOAuth2ClientId());
1398 IN_PROC_BROWSER_TEST_F(GetAuthTokenFunctionTest, ComponentWithNormalClientId) {
1399 scoped_refptr<FakeGetAuthTokenFunction> func(new FakeGetAuthTokenFunction());
1400 scoped_refptr<const Extension> extension(
1401 CreateExtension(CLIENT_ID | SCOPES | AS_COMPONENT));
1402 func->set_extension(extension.get());
1403 EXPECT_EQ("client1", func->GetOAuth2ClientId());
1406 IN_PROC_BROWSER_TEST_F(GetAuthTokenFunctionTest, MultiDefaultUser) {
1407 SignIn("primary@example.com");
1408 SetAccountState(CreateIds("primary@example.com", "1"), true);
1409 SetAccountState(CreateIds("secondary@example.com", "2"), true);
1411 scoped_refptr<FakeGetAuthTokenFunction> func(new FakeGetAuthTokenFunction());
1412 scoped_refptr<const Extension> extension(CreateExtension(CLIENT_ID | SCOPES));
1413 func->set_extension(extension.get());
1414 func->set_auto_login_access_token(false);
1415 func->set_mint_token_result(TestOAuth2MintTokenFlow::MINT_TOKEN_SUCCESS);
1417 RunFunctionAsync(func.get(), "[{}]");
1419 IssueLoginAccessTokenForAccount("primary@example.com");
1421 scoped_ptr<base::Value> value(WaitForSingleResult(func.get()));
1422 std::string access_token;
1423 EXPECT_TRUE(value->GetAsString(&access_token));
1424 EXPECT_EQ(std::string(kAccessToken), access_token);
1425 EXPECT_EQ(IdentityTokenCacheValue::CACHE_STATUS_TOKEN,
1426 GetCachedToken(std::string()).status());
1427 EXPECT_EQ("access_token-primary@example.com", func->login_access_token());
1430 IN_PROC_BROWSER_TEST_F(GetAuthTokenFunctionTest, MultiPrimaryUser) {
1431 SignIn("primary@example.com");
1432 IssueLoginRefreshTokenForAccount("secondary@example.com");
1433 SetAccountState(CreateIds("primary@example.com", "1"), true);
1434 SetAccountState(CreateIds("secondary@example.com", "2"), true);
1436 scoped_refptr<FakeGetAuthTokenFunction> func(new FakeGetAuthTokenFunction());
1437 scoped_refptr<const Extension> extension(CreateExtension(CLIENT_ID | SCOPES));
1438 func->set_extension(extension.get());
1439 func->set_auto_login_access_token(false);
1440 func->set_mint_token_result(TestOAuth2MintTokenFlow::MINT_TOKEN_SUCCESS);
1442 RunFunctionAsync(func.get(), "[{\"account\": { \"id\": \"1\" } }]");
1444 IssueLoginAccessTokenForAccount("primary@example.com");
1446 scoped_ptr<base::Value> value(WaitForSingleResult(func.get()));
1447 std::string access_token;
1448 EXPECT_TRUE(value->GetAsString(&access_token));
1449 EXPECT_EQ(std::string(kAccessToken), access_token);
1450 EXPECT_EQ(IdentityTokenCacheValue::CACHE_STATUS_TOKEN,
1451 GetCachedToken(std::string()).status());
1452 EXPECT_EQ("access_token-primary@example.com", func->login_access_token());
1455 IN_PROC_BROWSER_TEST_F(GetAuthTokenFunctionTest, MultiSecondaryUser) {
1456 SignIn("primary@example.com");
1457 IssueLoginRefreshTokenForAccount("secondary@example.com");
1458 SetAccountState(CreateIds("primary@example.com", "1"), true);
1459 SetAccountState(CreateIds("secondary@example.com", "2"), true);
1461 scoped_refptr<FakeGetAuthTokenFunction> func(new FakeGetAuthTokenFunction());
1462 scoped_refptr<const Extension> extension(CreateExtension(CLIENT_ID | SCOPES));
1463 func->set_extension(extension.get());
1464 func->set_auto_login_access_token(false);
1465 func->set_mint_token_result(TestOAuth2MintTokenFlow::MINT_TOKEN_SUCCESS);
1467 RunFunctionAsync(func.get(), "[{\"account\": { \"id\": \"2\" } }]");
1469 IssueLoginAccessTokenForAccount("secondary@example.com");
1471 scoped_ptr<base::Value> value(WaitForSingleResult(func.get()));
1472 std::string access_token;
1473 EXPECT_TRUE(value->GetAsString(&access_token));
1474 EXPECT_EQ(std::string(kAccessToken), access_token);
1475 EXPECT_EQ(IdentityTokenCacheValue::CACHE_STATUS_TOKEN,
1476 GetCachedToken("secondary@example.com").status());
1477 EXPECT_EQ("access_token-secondary@example.com", func->login_access_token());
1480 IN_PROC_BROWSER_TEST_F(GetAuthTokenFunctionTest, MultiUnknownUser) {
1481 SignIn("primary@example.com");
1482 IssueLoginRefreshTokenForAccount("secondary@example.com");
1483 SetAccountState(CreateIds("primary@example.com", "1"), true);
1484 SetAccountState(CreateIds("secondary@example.com", "2"), true);
1486 scoped_refptr<FakeGetAuthTokenFunction> func(new FakeGetAuthTokenFunction());
1487 scoped_refptr<const Extension> extension(CreateExtension(CLIENT_ID | SCOPES));
1488 func->set_extension(extension.get());
1489 func->set_auto_login_access_token(false);
1491 std::string error = utils::RunFunctionAndReturnError(
1492 func.get(), "[{\"account\": { \"id\": \"3\" } }]", browser());
1493 EXPECT_EQ(std::string(errors::kUserNotSignedIn), error);
1496 IN_PROC_BROWSER_TEST_F(GetAuthTokenFunctionTest,
1497 MultiSecondaryNonInteractiveMintFailure) {
1498 SignIn("primary@example.com");
1499 IssueLoginRefreshTokenForAccount("secondary@example.com");
1500 SetAccountState(CreateIds("primary@example.com", "1"), true);
1501 SetAccountState(CreateIds("secondary@example.com", "2"), true);
1503 scoped_refptr<FakeGetAuthTokenFunction> func(new FakeGetAuthTokenFunction());
1504 func->set_extension(CreateExtension(CLIENT_ID | SCOPES));
1505 func->set_mint_token_result(TestOAuth2MintTokenFlow::MINT_TOKEN_FAILURE);
1506 std::string error = utils::RunFunctionAndReturnError(
1507 func.get(), "[{\"account\": { \"id\": \"2\" } }]", browser());
1508 EXPECT_TRUE(base::StartsWith(error, errors::kAuthFailure,
1509 base::CompareCase::INSENSITIVE_ASCII));
1510 EXPECT_FALSE(func->login_ui_shown());
1511 EXPECT_FALSE(func->scope_ui_shown());
1514 IN_PROC_BROWSER_TEST_F(GetAuthTokenFunctionTest,
1515 MultiSecondaryNonInteractiveLoginAccessTokenFailure) {
1516 SignIn("primary@example.com");
1517 IssueLoginRefreshTokenForAccount("secondary@example.com");
1518 SetAccountState(CreateIds("primary@example.com", "1"), true);
1519 SetAccountState(CreateIds("secondary@example.com", "2"), true);
1521 scoped_refptr<FakeGetAuthTokenFunction> func(new FakeGetAuthTokenFunction());
1522 func->set_extension(CreateExtension(CLIENT_ID | SCOPES));
1523 func->set_login_access_token_result(false);
1524 std::string error = utils::RunFunctionAndReturnError(
1525 func.get(), "[{\"account\": { \"id\": \"2\" } }]", browser());
1526 EXPECT_TRUE(base::StartsWith(error, errors::kAuthFailure,
1527 base::CompareCase::INSENSITIVE_ASCII));
1530 IN_PROC_BROWSER_TEST_F(GetAuthTokenFunctionTest,
1531 MultiSecondaryInteractiveApprovalAborted) {
1532 SignIn("primary@example.com");
1533 IssueLoginRefreshTokenForAccount("secondary@example.com");
1534 SetAccountState(CreateIds("primary@example.com", "1"), true);
1535 SetAccountState(CreateIds("secondary@example.com", "2"), true);
1537 scoped_refptr<FakeGetAuthTokenFunction> func(new FakeGetAuthTokenFunction());
1538 func->set_extension(CreateExtension(CLIENT_ID | SCOPES));
1539 func->set_mint_token_result(TestOAuth2MintTokenFlow::ISSUE_ADVICE_SUCCESS);
1540 func->set_scope_ui_failure(GaiaWebAuthFlow::WINDOW_CLOSED);
1541 std::string error = utils::RunFunctionAndReturnError(
1542 func.get(),
1543 "[{\"account\": { \"id\": \"2\" }, \"interactive\": true}]",
1544 browser());
1545 EXPECT_EQ(std::string(errors::kUserRejected), error);
1546 EXPECT_FALSE(func->login_ui_shown());
1547 EXPECT_TRUE(func->scope_ui_shown());
1550 IN_PROC_BROWSER_TEST_F(GetAuthTokenFunctionTest, ScopesDefault) {
1551 SignIn("primary@example.com");
1552 scoped_refptr<FakeGetAuthTokenFunction> func(new FakeGetAuthTokenFunction());
1553 scoped_refptr<const Extension> extension(CreateExtension(CLIENT_ID | SCOPES));
1554 func->set_extension(extension.get());
1555 func->set_mint_token_result(TestOAuth2MintTokenFlow::MINT_TOKEN_SUCCESS);
1556 scoped_ptr<base::Value> value(
1557 utils::RunFunctionAndReturnSingleResult(func.get(), "[{}]", browser()));
1558 std::string access_token;
1559 EXPECT_TRUE(value->GetAsString(&access_token));
1560 EXPECT_EQ(std::string(kAccessToken), access_token);
1562 const ExtensionTokenKey* token_key = func->GetExtensionTokenKeyForTest();
1563 EXPECT_EQ(2ul, token_key->scopes.size());
1564 EXPECT_TRUE(ContainsKey(token_key->scopes, "scope1"));
1565 EXPECT_TRUE(ContainsKey(token_key->scopes, "scope2"));
1568 IN_PROC_BROWSER_TEST_F(GetAuthTokenFunctionTest, ScopesEmpty) {
1569 scoped_refptr<FakeGetAuthTokenFunction> func(new FakeGetAuthTokenFunction());
1570 scoped_refptr<const Extension> extension(CreateExtension(CLIENT_ID | SCOPES));
1571 func->set_extension(extension.get());
1573 std::string error(utils::RunFunctionAndReturnError(
1574 func.get(), "[{\"scopes\": []}]", browser()));
1576 EXPECT_EQ(errors::kInvalidScopes, error);
1579 IN_PROC_BROWSER_TEST_F(GetAuthTokenFunctionTest, ScopesEmail) {
1580 SignIn("primary@example.com");
1581 scoped_refptr<FakeGetAuthTokenFunction> func(new FakeGetAuthTokenFunction());
1582 scoped_refptr<const Extension> extension(CreateExtension(CLIENT_ID | SCOPES));
1583 func->set_extension(extension.get());
1584 func->set_mint_token_result(TestOAuth2MintTokenFlow::MINT_TOKEN_SUCCESS);
1585 scoped_ptr<base::Value> value(utils::RunFunctionAndReturnSingleResult(
1586 func.get(), "[{\"scopes\": [\"email\"]}]", browser()));
1587 std::string access_token;
1588 EXPECT_TRUE(value->GetAsString(&access_token));
1589 EXPECT_EQ(std::string(kAccessToken), access_token);
1591 const ExtensionTokenKey* token_key = func->GetExtensionTokenKeyForTest();
1592 EXPECT_EQ(1ul, token_key->scopes.size());
1593 EXPECT_TRUE(ContainsKey(token_key->scopes, "email"));
1596 IN_PROC_BROWSER_TEST_F(GetAuthTokenFunctionTest, ScopesEmailFooBar) {
1597 SignIn("primary@example.com");
1598 scoped_refptr<FakeGetAuthTokenFunction> func(new FakeGetAuthTokenFunction());
1599 scoped_refptr<const Extension> extension(CreateExtension(CLIENT_ID | SCOPES));
1600 func->set_extension(extension.get());
1601 func->set_mint_token_result(TestOAuth2MintTokenFlow::MINT_TOKEN_SUCCESS);
1602 scoped_ptr<base::Value> value(utils::RunFunctionAndReturnSingleResult(
1603 func.get(), "[{\"scopes\": [\"email\", \"foo\", \"bar\"]}]", browser()));
1604 std::string access_token;
1605 EXPECT_TRUE(value->GetAsString(&access_token));
1606 EXPECT_EQ(std::string(kAccessToken), access_token);
1608 const ExtensionTokenKey* token_key = func->GetExtensionTokenKeyForTest();
1609 EXPECT_EQ(3ul, token_key->scopes.size());
1610 EXPECT_TRUE(ContainsKey(token_key->scopes, "email"));
1611 EXPECT_TRUE(ContainsKey(token_key->scopes, "foo"));
1612 EXPECT_TRUE(ContainsKey(token_key->scopes, "bar"));
1615 class RemoveCachedAuthTokenFunctionTest : public ExtensionBrowserTest {
1616 protected:
1617 bool InvalidateDefaultToken() {
1618 scoped_refptr<IdentityRemoveCachedAuthTokenFunction> func(
1619 new IdentityRemoveCachedAuthTokenFunction);
1620 func->set_extension(test_util::CreateEmptyExtension(kExtensionId).get());
1621 return utils::RunFunction(
1622 func.get(),
1623 std::string("[{\"token\": \"") + kAccessToken + "\"}]",
1624 browser(),
1625 extension_function_test_utils::NONE);
1628 IdentityAPI* id_api() {
1629 return IdentityAPI::GetFactoryInstance()->Get(browser()->profile());
1632 void SetCachedToken(IdentityTokenCacheValue& token_data) {
1633 ExtensionTokenKey key(
1634 kExtensionId, "test@example.com", std::set<std::string>());
1635 id_api()->SetCachedToken(key, token_data);
1638 const IdentityTokenCacheValue& GetCachedToken() {
1639 return id_api()->GetCachedToken(ExtensionTokenKey(
1640 kExtensionId, "test@example.com", std::set<std::string>()));
1644 IN_PROC_BROWSER_TEST_F(RemoveCachedAuthTokenFunctionTest, NotFound) {
1645 EXPECT_TRUE(InvalidateDefaultToken());
1646 EXPECT_EQ(IdentityTokenCacheValue::CACHE_STATUS_NOTFOUND,
1647 GetCachedToken().status());
1650 IN_PROC_BROWSER_TEST_F(RemoveCachedAuthTokenFunctionTest, Advice) {
1651 IssueAdviceInfo info;
1652 IdentityTokenCacheValue advice(info);
1653 SetCachedToken(advice);
1654 EXPECT_TRUE(InvalidateDefaultToken());
1655 EXPECT_EQ(IdentityTokenCacheValue::CACHE_STATUS_ADVICE,
1656 GetCachedToken().status());
1659 IN_PROC_BROWSER_TEST_F(RemoveCachedAuthTokenFunctionTest, NonMatchingToken) {
1660 IdentityTokenCacheValue token("non_matching_token",
1661 base::TimeDelta::FromSeconds(3600));
1662 SetCachedToken(token);
1663 EXPECT_TRUE(InvalidateDefaultToken());
1664 EXPECT_EQ(IdentityTokenCacheValue::CACHE_STATUS_TOKEN,
1665 GetCachedToken().status());
1666 EXPECT_EQ("non_matching_token", GetCachedToken().token());
1669 IN_PROC_BROWSER_TEST_F(RemoveCachedAuthTokenFunctionTest, MatchingToken) {
1670 IdentityTokenCacheValue token(kAccessToken,
1671 base::TimeDelta::FromSeconds(3600));
1672 SetCachedToken(token);
1673 EXPECT_EQ(IdentityTokenCacheValue::CACHE_STATUS_TOKEN,
1674 GetCachedToken().status());
1675 EXPECT_TRUE(InvalidateDefaultToken());
1676 EXPECT_EQ(IdentityTokenCacheValue::CACHE_STATUS_NOTFOUND,
1677 GetCachedToken().status());
1680 class LaunchWebAuthFlowFunctionTest : public AsyncExtensionBrowserTest {
1681 public:
1682 void SetUpCommandLine(base::CommandLine* command_line) override {
1683 AsyncExtensionBrowserTest::SetUpCommandLine(command_line);
1684 // Reduce performance test variance by disabling background networking.
1685 command_line->AppendSwitch(switches::kDisableBackgroundNetworking);
1689 IN_PROC_BROWSER_TEST_F(LaunchWebAuthFlowFunctionTest, UserCloseWindow) {
1690 net::SpawnedTestServer https_server(
1691 net::SpawnedTestServer::TYPE_HTTPS,
1692 net::SpawnedTestServer::kLocalhost,
1693 base::FilePath(FILE_PATH_LITERAL(
1694 "chrome/test/data/extensions/api_test/identity")));
1695 ASSERT_TRUE(https_server.Start());
1696 GURL auth_url(https_server.GetURL("files/interaction_required.html"));
1698 scoped_refptr<IdentityLaunchWebAuthFlowFunction> function(
1699 new IdentityLaunchWebAuthFlowFunction());
1700 scoped_refptr<Extension> empty_extension(test_util::CreateEmptyExtension());
1701 function->set_extension(empty_extension.get());
1703 WaitForGURLAndCloseWindow popup_observer(auth_url);
1705 std::string args = "[{\"interactive\": true, \"url\": \"" +
1706 auth_url.spec() + "\"}]";
1707 RunFunctionAsync(function.get(), args);
1709 popup_observer.Wait();
1710 popup_observer.CloseEmbedderWebContents();
1712 EXPECT_EQ(std::string(errors::kUserRejected), WaitForError(function.get()));
1715 IN_PROC_BROWSER_TEST_F(LaunchWebAuthFlowFunctionTest, InteractionRequired) {
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/interaction_required.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\": false, \"url\": \"" +
1730 auth_url.spec() + "\"}]";
1731 std::string error =
1732 utils::RunFunctionAndReturnError(function.get(), args, browser());
1734 EXPECT_EQ(std::string(errors::kInteractionRequired), error);
1737 IN_PROC_BROWSER_TEST_F(LaunchWebAuthFlowFunctionTest, LoadFailed) {
1738 net::SpawnedTestServer https_server(
1739 net::SpawnedTestServer::TYPE_HTTPS,
1740 net::SpawnedTestServer::kLocalhost,
1741 base::FilePath(FILE_PATH_LITERAL(
1742 "chrome/test/data/extensions/api_test/identity")));
1743 ASSERT_TRUE(https_server.Start());
1744 GURL auth_url(https_server.GetURL("files/five_hundred.html"));
1746 scoped_refptr<IdentityLaunchWebAuthFlowFunction> function(
1747 new IdentityLaunchWebAuthFlowFunction());
1748 scoped_refptr<Extension> empty_extension(test_util::CreateEmptyExtension());
1749 function->set_extension(empty_extension.get());
1751 std::string args = "[{\"interactive\": true, \"url\": \"" +
1752 auth_url.spec() + "\"}]";
1753 std::string error =
1754 utils::RunFunctionAndReturnError(function.get(), args, browser());
1756 EXPECT_EQ(std::string(errors::kPageLoadFailure), error);
1759 IN_PROC_BROWSER_TEST_F(LaunchWebAuthFlowFunctionTest, NonInteractiveSuccess) {
1760 #if defined(OS_WIN) && defined(USE_ASH)
1761 // Disable this test in Metro+Ash for now (http://crbug.com/262796).
1762 if (base::CommandLine::ForCurrentProcess()->HasSwitch(
1763 switches::kAshBrowserTests))
1764 return;
1765 #endif
1767 scoped_refptr<IdentityLaunchWebAuthFlowFunction> function(
1768 new IdentityLaunchWebAuthFlowFunction());
1769 scoped_refptr<Extension> empty_extension(test_util::CreateEmptyExtension());
1770 function->set_extension(empty_extension.get());
1772 function->InitFinalRedirectURLPrefixForTest("abcdefghij");
1773 scoped_ptr<base::Value> value(utils::RunFunctionAndReturnSingleResult(
1774 function.get(),
1775 "[{\"interactive\": false,"
1776 "\"url\": \"https://abcdefghij.chromiumapp.org/callback#test\"}]",
1777 browser()));
1779 std::string url;
1780 EXPECT_TRUE(value->GetAsString(&url));
1781 EXPECT_EQ(std::string("https://abcdefghij.chromiumapp.org/callback#test"),
1782 url);
1785 IN_PROC_BROWSER_TEST_F(
1786 LaunchWebAuthFlowFunctionTest, InteractiveFirstNavigationSuccess) {
1787 #if defined(OS_WIN) && defined(USE_ASH)
1788 // Disable this test in Metro+Ash for now (http://crbug.com/262796).
1789 if (base::CommandLine::ForCurrentProcess()->HasSwitch(
1790 switches::kAshBrowserTests))
1791 return;
1792 #endif
1794 scoped_refptr<IdentityLaunchWebAuthFlowFunction> function(
1795 new IdentityLaunchWebAuthFlowFunction());
1796 scoped_refptr<Extension> empty_extension(test_util::CreateEmptyExtension());
1797 function->set_extension(empty_extension.get());
1799 function->InitFinalRedirectURLPrefixForTest("abcdefghij");
1800 scoped_ptr<base::Value> value(utils::RunFunctionAndReturnSingleResult(
1801 function.get(),
1802 "[{\"interactive\": true,"
1803 "\"url\": \"https://abcdefghij.chromiumapp.org/callback#test\"}]",
1804 browser()));
1806 std::string url;
1807 EXPECT_TRUE(value->GetAsString(&url));
1808 EXPECT_EQ(std::string("https://abcdefghij.chromiumapp.org/callback#test"),
1809 url);
1812 IN_PROC_BROWSER_TEST_F(LaunchWebAuthFlowFunctionTest,
1813 DISABLED_InteractiveSecondNavigationSuccess) {
1814 net::SpawnedTestServer https_server(
1815 net::SpawnedTestServer::TYPE_HTTPS,
1816 net::SpawnedTestServer::kLocalhost,
1817 base::FilePath(FILE_PATH_LITERAL(
1818 "chrome/test/data/extensions/api_test/identity")));
1819 ASSERT_TRUE(https_server.Start());
1820 GURL auth_url(https_server.GetURL("files/redirect_to_chromiumapp.html"));
1822 scoped_refptr<IdentityLaunchWebAuthFlowFunction> function(
1823 new IdentityLaunchWebAuthFlowFunction());
1824 scoped_refptr<Extension> empty_extension(test_util::CreateEmptyExtension());
1825 function->set_extension(empty_extension.get());
1827 function->InitFinalRedirectURLPrefixForTest("abcdefghij");
1828 std::string args = "[{\"interactive\": true, \"url\": \"" +
1829 auth_url.spec() + "\"}]";
1830 scoped_ptr<base::Value> value(
1831 utils::RunFunctionAndReturnSingleResult(function.get(), args, browser()));
1833 std::string url;
1834 EXPECT_TRUE(value->GetAsString(&url));
1835 EXPECT_EQ(std::string("https://abcdefghij.chromiumapp.org/callback#test"),
1836 url);
1839 } // namespace extensions
1841 // Tests the chrome.identity API implemented by custom JS bindings .
1842 IN_PROC_BROWSER_TEST_F(ExtensionApiTest, ChromeIdentityJsBindings) {
1843 ASSERT_TRUE(RunExtensionTest("identity/js_bindings")) << message_;