Elim cr-checkbox
[chromium-blink-merge.git] / chrome / browser / extensions / api / identity / identity_apitest.cc
blobf72177ad8de80ace1a3148ed6fbed544b1e096d2
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),
240 embedder_web_contents_(nullptr) {}
242 // NotificationObserver:
243 void Observe(int type,
244 const content::NotificationSource& source,
245 const content::NotificationDetails& details) override {
246 content::NavigationController* web_auth_flow_controller =
247 content::Source<content::NavigationController>(source).ptr();
248 content::WebContents* web_contents =
249 web_auth_flow_controller->GetWebContents();
251 if (web_contents->GetURL() == url_) {
252 // It is safe to keep the pointer here, because we know in a test, that
253 // the WebContents won't go away before CloseEmbedderWebContents is
254 // called. Don't copy this code to production.
255 GuestViewBase* guest = GuestViewBase::FromWebContents(web_contents);
256 embedder_web_contents_ = guest->embedder_web_contents();
257 // Condtionally invoke parent class so that Wait will not exit
258 // until the target URL arrives.
259 content::WindowedNotificationObserver::Observe(type, source, details);
263 // Closes the window embedding the WebContents. The action is separated from
264 // the Observe method to make sure the list of observers is not deleted,
265 // while some event is already being processed. (That causes ASAN failures.)
266 void CloseEmbedderWebContents() {
267 if (embedder_web_contents_)
268 embedder_web_contents_->Close();
271 private:
272 GURL url_;
273 content::WebContents* embedder_web_contents_;
276 } // namespace
278 class FakeGetAuthTokenFunction : public IdentityGetAuthTokenFunction {
279 public:
280 FakeGetAuthTokenFunction()
281 : login_access_token_result_(true),
282 auto_login_access_token_(true),
283 login_ui_result_(true),
284 scope_ui_result_(true),
285 scope_ui_failure_(GaiaWebAuthFlow::WINDOW_CLOSED),
286 login_ui_shown_(false),
287 scope_ui_shown_(false) {}
289 void set_login_access_token_result(bool result) {
290 login_access_token_result_ = result;
293 void set_auto_login_access_token(bool automatic) {
294 auto_login_access_token_ = automatic;
297 void set_login_ui_result(bool result) { login_ui_result_ = result; }
299 void set_mint_token_flow(scoped_ptr<OAuth2MintTokenFlow> flow) {
300 flow_ = flow.Pass();
303 void set_mint_token_result(TestOAuth2MintTokenFlow::ResultType result_type) {
304 set_mint_token_flow(
305 make_scoped_ptr(new TestOAuth2MintTokenFlow(result_type, this)));
308 void set_scope_ui_failure(GaiaWebAuthFlow::Failure failure) {
309 scope_ui_result_ = false;
310 scope_ui_failure_ = failure;
313 void set_scope_ui_oauth_error(const std::string& oauth_error) {
314 scope_ui_result_ = false;
315 scope_ui_failure_ = GaiaWebAuthFlow::OAUTH_ERROR;
316 scope_ui_oauth_error_ = oauth_error;
319 bool login_ui_shown() const { return login_ui_shown_; }
321 bool scope_ui_shown() const { return scope_ui_shown_; }
323 std::string login_access_token() const { return login_access_token_; }
325 void StartLoginAccessTokenRequest() override {
326 if (auto_login_access_token_) {
327 if (login_access_token_result_) {
328 OnGetTokenSuccess(login_token_request_.get(),
329 "access_token",
330 base::Time::Now() + base::TimeDelta::FromHours(1LL));
331 } else {
332 GoogleServiceAuthError error(
333 GoogleServiceAuthError::INVALID_GAIA_CREDENTIALS);
334 OnGetTokenFailure(login_token_request_.get(), error);
336 } else {
337 // Make a request to the token service. The test now must tell
338 // the token service to issue an access token (or an error).
339 IdentityGetAuthTokenFunction::StartLoginAccessTokenRequest();
343 void ShowLoginPopup() override {
344 EXPECT_FALSE(login_ui_shown_);
345 login_ui_shown_ = true;
346 if (login_ui_result_)
347 SigninSuccess();
348 else
349 SigninFailed();
352 void ShowOAuthApprovalDialog(const IssueAdviceInfo& issue_advice) override {
353 scope_ui_shown_ = true;
355 if (scope_ui_result_) {
356 OnGaiaFlowCompleted(kAccessToken, "3600");
357 } else if (scope_ui_failure_ == GaiaWebAuthFlow::SERVICE_AUTH_ERROR) {
358 GoogleServiceAuthError error(GoogleServiceAuthError::CONNECTION_FAILED);
359 OnGaiaFlowFailure(scope_ui_failure_, error, "");
360 } else {
361 GoogleServiceAuthError error(GoogleServiceAuthError::NONE);
362 OnGaiaFlowFailure(scope_ui_failure_, error, scope_ui_oauth_error_);
366 void StartGaiaRequest(const std::string& login_access_token) override {
367 EXPECT_TRUE(login_access_token_.empty());
368 // Save the login token used in the mint token flow so tests can see
369 // what account was used.
370 login_access_token_ = login_access_token;
371 IdentityGetAuthTokenFunction::StartGaiaRequest(login_access_token);
374 OAuth2MintTokenFlow* CreateMintTokenFlow() override {
375 return flow_.release();
378 private:
379 ~FakeGetAuthTokenFunction() override {}
380 bool login_access_token_result_;
381 bool auto_login_access_token_;
382 bool login_ui_result_;
383 bool scope_ui_result_;
384 GaiaWebAuthFlow::Failure scope_ui_failure_;
385 std::string scope_ui_oauth_error_;
386 bool login_ui_shown_;
387 bool scope_ui_shown_;
389 scoped_ptr<OAuth2MintTokenFlow> flow_;
391 std::string login_access_token_;
394 class MockQueuedMintRequest : public IdentityMintRequestQueue::Request {
395 public:
396 MOCK_METHOD1(StartMintToken, void(IdentityMintRequestQueue::MintType));
399 gaia::AccountIds CreateIds(std::string email, std::string obfid) {
400 gaia::AccountIds ids;
401 ids.account_key = email;
402 ids.email = email;
403 ids.gaia = obfid;
404 return ids;
407 class IdentityGetAccountsFunctionTest : public ExtensionBrowserTest {
408 void SetUpCommandLine(base::CommandLine* command_line) override {
409 ExtensionBrowserTest::SetUpCommandLine(command_line);
410 command_line->AppendSwitch(switches::kExtensionsMultiAccount);
413 protected:
414 void SetAccountState(gaia::AccountIds ids, bool is_signed_in) {
415 IdentityAPI::GetFactoryInstance()->Get(profile())->SetAccountStateForTest(
416 ids, is_signed_in);
419 testing::AssertionResult ExpectGetAccounts(
420 const std::vector<std::string>& accounts) {
421 scoped_refptr<IdentityGetAccountsFunction> func(
422 new IdentityGetAccountsFunction);
423 func->set_extension(test_util::CreateEmptyExtension(kExtensionId).get());
424 if (!utils::RunFunction(
425 func.get(), std::string("[]"), browser(), utils::NONE)) {
426 return GenerateFailureResult(accounts, NULL)
427 << "getAccounts did not return a result.";
429 const base::ListValue* callback_arguments = func->GetResultList();
430 if (!callback_arguments)
431 return GenerateFailureResult(accounts, NULL) << "NULL result";
433 if (callback_arguments->GetSize() != 1) {
434 return GenerateFailureResult(accounts, NULL)
435 << "Expected 1 argument but got " << callback_arguments->GetSize();
438 const base::ListValue* results;
439 if (!callback_arguments->GetList(0, &results))
440 GenerateFailureResult(accounts, NULL) << "Result was not an array";
442 std::set<std::string> result_ids;
443 for (base::ListValue::const_iterator it = results->begin();
444 it != results->end();
445 ++it) {
446 scoped_ptr<api::identity::AccountInfo> info =
447 api::identity::AccountInfo::FromValue(**it);
448 if (info.get())
449 result_ids.insert(info->id);
450 else
451 return GenerateFailureResult(accounts, results);
454 for (std::vector<std::string>::const_iterator it = accounts.begin();
455 it != accounts.end();
456 ++it) {
457 if (result_ids.find(*it) == result_ids.end())
458 return GenerateFailureResult(accounts, results);
461 return testing::AssertionResult(true);
464 testing::AssertionResult GenerateFailureResult(
465 const ::std::vector<std::string>& accounts,
466 const base::ListValue* results) {
467 testing::Message msg("Expected: ");
468 for (std::vector<std::string>::const_iterator it = accounts.begin();
469 it != accounts.end();
470 ++it) {
471 msg << *it << " ";
473 msg << "Actual: ";
474 if (!results) {
475 msg << "NULL";
476 } else {
477 for (base::ListValue::const_iterator it = results->begin();
478 it != results->end();
479 ++it) {
480 scoped_ptr<api::identity::AccountInfo> info =
481 api::identity::AccountInfo::FromValue(**it);
482 if (info.get())
483 msg << info->id << " ";
484 else
485 msg << *it << "<-" << (*it)->GetType() << " ";
489 return testing::AssertionFailure(msg);
493 IN_PROC_BROWSER_TEST_F(IdentityGetAccountsFunctionTest, MultiAccountOn) {
494 EXPECT_TRUE(switches::IsExtensionsMultiAccount());
497 IN_PROC_BROWSER_TEST_F(IdentityGetAccountsFunctionTest, NoneSignedIn) {
498 EXPECT_TRUE(ExpectGetAccounts(std::vector<std::string>()));
501 IN_PROC_BROWSER_TEST_F(IdentityGetAccountsFunctionTest,
502 PrimaryAccountSignedIn) {
503 SetAccountState(CreateIds("primary@example.com", "1"), true);
504 std::vector<std::string> primary;
505 primary.push_back("1");
506 EXPECT_TRUE(ExpectGetAccounts(primary));
509 IN_PROC_BROWSER_TEST_F(IdentityGetAccountsFunctionTest, TwoAccountsSignedIn) {
510 SetAccountState(CreateIds("primary@example.com", "1"), true);
511 SetAccountState(CreateIds("secondary@example.com", "2"), true);
512 std::vector<std::string> two_accounts;
513 two_accounts.push_back("1");
514 two_accounts.push_back("2");
515 EXPECT_TRUE(ExpectGetAccounts(two_accounts));
518 class IdentityOldProfilesGetAccountsFunctionTest
519 : public IdentityGetAccountsFunctionTest {
520 void SetUpCommandLine(base::CommandLine* command_line) override {
521 // Don't add the multi-account switch that parent class would have.
525 IN_PROC_BROWSER_TEST_F(IdentityOldProfilesGetAccountsFunctionTest,
526 MultiAccountOff) {
527 EXPECT_FALSE(switches::IsExtensionsMultiAccount());
530 IN_PROC_BROWSER_TEST_F(IdentityOldProfilesGetAccountsFunctionTest,
531 TwoAccountsSignedIn) {
532 SetAccountState(CreateIds("primary@example.com", "1"), true);
533 SetAccountState(CreateIds("secondary@example.com", "2"), true);
534 std::vector<std::string> only_primary;
535 only_primary.push_back("1");
536 EXPECT_TRUE(ExpectGetAccounts(only_primary));
539 class IdentityTestWithSignin : public AsyncExtensionBrowserTest {
540 public:
541 void SetUpInProcessBrowserTestFixture() override {
542 AsyncExtensionBrowserTest::SetUpInProcessBrowserTestFixture();
544 will_create_browser_context_services_subscription_ =
545 BrowserContextDependencyManager::GetInstance()
546 ->RegisterWillCreateBrowserContextServicesCallbackForTesting(
547 base::Bind(&IdentityTestWithSignin::
548 OnWillCreateBrowserContextServices,
549 base::Unretained(this)))
550 .Pass();
553 void OnWillCreateBrowserContextServices(content::BrowserContext* context) {
554 // Replace the signin manager and token service with fakes. Do this ahead of
555 // creating the browser so that a bunch of classes don't register as
556 // observers and end up needing to unregister when the fake is substituted.
557 SigninManagerFactory::GetInstance()->SetTestingFactory(
558 context, &BuildFakeSigninManagerBase);
559 ProfileOAuth2TokenServiceFactory::GetInstance()->SetTestingFactory(
560 context, &BuildFakeProfileOAuth2TokenService);
561 GaiaCookieManagerServiceFactory::GetInstance()->SetTestingFactory(
562 context, &FakeGaiaCookieManagerService::Build);
565 void SetUpOnMainThread() override {
566 AsyncExtensionBrowserTest::SetUpOnMainThread();
568 // Grab references to the fake signin manager and token service.
569 signin_manager_ = static_cast<FakeSigninManagerForTesting*>(
570 SigninManagerFactory::GetInstance()->GetForProfile(profile()));
571 ASSERT_TRUE(signin_manager_);
572 token_service_ = static_cast<FakeProfileOAuth2TokenService*>(
573 ProfileOAuth2TokenServiceFactory::GetInstance()->GetForProfile(
574 profile()));
575 ASSERT_TRUE(token_service_);
576 GaiaCookieManagerServiceFactory::GetInstance()->GetForProfile(profile())
577 ->Init();
580 protected:
581 void SignIn(const std::string& account_key) {
582 SignIn(account_key, account_key);
585 void SignIn(const std::string& email, const std::string& gaia) {
586 AccountTrackerService* account_tracker =
587 AccountTrackerServiceFactory::GetForProfile(profile());
588 std::string account_id =
589 account_tracker->SeedAccountInfo(gaia, email);
591 #if defined(OS_CHROMEOS)
592 signin_manager_->SetAuthenticatedAccountInfo(gaia, email);
593 #else
594 signin_manager_->SignIn(gaia, email, "password");
595 #endif
596 token_service_->UpdateCredentials(account_id, "refresh_token");
599 FakeSigninManagerForTesting* signin_manager_;
600 FakeProfileOAuth2TokenService* token_service_;
602 scoped_ptr<base::CallbackList<void(content::BrowserContext*)>::Subscription>
603 will_create_browser_context_services_subscription_;
606 class IdentityGetProfileUserInfoFunctionTest : public IdentityTestWithSignin {
607 protected:
608 scoped_ptr<api::identity::ProfileUserInfo> RunGetProfileUserInfo() {
609 scoped_refptr<IdentityGetProfileUserInfoFunction> func(
610 new IdentityGetProfileUserInfoFunction);
611 func->set_extension(test_util::CreateEmptyExtension(kExtensionId).get());
612 scoped_ptr<base::Value> value(
613 utils::RunFunctionAndReturnSingleResult(func.get(), "[]", browser()));
614 return api::identity::ProfileUserInfo::FromValue(*value.get());
617 scoped_ptr<api::identity::ProfileUserInfo> RunGetProfileUserInfoWithEmail() {
618 scoped_refptr<IdentityGetProfileUserInfoFunction> func(
619 new IdentityGetProfileUserInfoFunction);
620 func->set_extension(CreateExtensionWithEmailPermission());
621 scoped_ptr<base::Value> value(
622 utils::RunFunctionAndReturnSingleResult(func.get(), "[]", browser()));
623 return api::identity::ProfileUserInfo::FromValue(*value.get());
626 private:
627 scoped_refptr<Extension> CreateExtensionWithEmailPermission() {
628 scoped_ptr<base::DictionaryValue> test_extension_value(
629 api_test_utils::ParseDictionary(
630 "{\"name\": \"Test\", \"version\": \"1.0\", "
631 "\"permissions\": [\"identity.email\"]}"));
632 return api_test_utils::CreateExtension(test_extension_value.get());
636 IN_PROC_BROWSER_TEST_F(IdentityGetProfileUserInfoFunctionTest, NotSignedIn) {
637 scoped_ptr<api::identity::ProfileUserInfo> info =
638 RunGetProfileUserInfoWithEmail();
639 EXPECT_TRUE(info->email.empty());
640 EXPECT_TRUE(info->id.empty());
643 IN_PROC_BROWSER_TEST_F(IdentityGetProfileUserInfoFunctionTest, SignedIn) {
644 SignIn("president@example.com", "12345");
645 scoped_ptr<api::identity::ProfileUserInfo> info =
646 RunGetProfileUserInfoWithEmail();
647 EXPECT_EQ("president@example.com", info->email);
648 EXPECT_EQ("12345", info->id);
651 IN_PROC_BROWSER_TEST_F(IdentityGetProfileUserInfoFunctionTest,
652 NotSignedInNoEmail) {
653 scoped_ptr<api::identity::ProfileUserInfo> info = RunGetProfileUserInfo();
654 EXPECT_TRUE(info->email.empty());
655 EXPECT_TRUE(info->id.empty());
658 IN_PROC_BROWSER_TEST_F(IdentityGetProfileUserInfoFunctionTest,
659 SignedInNoEmail) {
660 SignIn("president@example.com", "12345");
661 scoped_ptr<api::identity::ProfileUserInfo> info = RunGetProfileUserInfo();
662 EXPECT_TRUE(info->email.empty());
663 EXPECT_TRUE(info->id.empty());
666 class GetAuthTokenFunctionTest : public IdentityTestWithSignin {
667 public:
668 void SetUpCommandLine(base::CommandLine* command_line) override {
669 IdentityTestWithSignin::SetUpCommandLine(command_line);
670 command_line->AppendSwitch(switches::kExtensionsMultiAccount);
673 void IssueLoginRefreshTokenForAccount(const std::string account_key) {
674 token_service_->UpdateCredentials(account_key, "refresh_token");
677 void IssueLoginAccessTokenForAccount(const std::string account_key) {
678 token_service_->IssueAllTokensForAccount(
679 account_key,
680 "access_token-" + account_key,
681 base::Time::Now() + base::TimeDelta::FromSeconds(3600));
684 void SetAccountState(gaia::AccountIds ids, bool is_signed_in) {
685 IdentityAPI::GetFactoryInstance()->Get(profile())->SetAccountStateForTest(
686 ids, is_signed_in);
689 protected:
690 enum OAuth2Fields {
691 NONE = 0,
692 CLIENT_ID = 1,
693 SCOPES = 2,
694 AS_COMPONENT = 4
697 ~GetAuthTokenFunctionTest() override {}
699 // Helper to create an extension with specific OAuth2Info fields set.
700 // |fields_to_set| should be computed by using fields of Oauth2Fields enum.
701 const Extension* CreateExtension(int fields_to_set) {
702 const Extension* ext;
703 base::FilePath manifest_path =
704 test_data_dir_.AppendASCII("platform_apps/oauth2");
705 base::FilePath component_manifest_path =
706 test_data_dir_.AppendASCII("packaged_app/component_oauth2");
707 if ((fields_to_set & AS_COMPONENT) == 0)
708 ext = LoadExtension(manifest_path);
709 else
710 ext = LoadExtensionAsComponent(component_manifest_path);
711 OAuth2Info& oauth2_info =
712 const_cast<OAuth2Info&>(OAuth2Info::GetOAuth2Info(ext));
713 if ((fields_to_set & CLIENT_ID) != 0)
714 oauth2_info.client_id = "client1";
715 if ((fields_to_set & SCOPES) != 0) {
716 oauth2_info.scopes.push_back("scope1");
717 oauth2_info.scopes.push_back("scope2");
720 extension_id_ = ext->id();
721 oauth_scopes_ = std::set<std::string>(oauth2_info.scopes.begin(),
722 oauth2_info.scopes.end());
723 return ext;
726 IdentityAPI* id_api() {
727 return IdentityAPI::GetFactoryInstance()->Get(browser()->profile());
730 const std::string& GetPrimaryAccountId() {
731 SigninManagerBase* signin_manager =
732 SigninManagerFactory::GetForProfile(browser()->profile());
733 return signin_manager->GetAuthenticatedAccountId();
736 void SetCachedToken(const IdentityTokenCacheValue& token_data) {
737 ExtensionTokenKey key(extension_id_, GetPrimaryAccountId(), oauth_scopes_);
738 id_api()->SetCachedToken(key, token_data);
741 const IdentityTokenCacheValue& GetCachedToken(std::string account_id) {
742 if (account_id.empty())
743 account_id = GetPrimaryAccountId();
744 ExtensionTokenKey key(extension_id_, account_id, oauth_scopes_);
745 return id_api()->GetCachedToken(key);
748 void QueueRequestStart(IdentityMintRequestQueue::MintType type,
749 IdentityMintRequestQueue::Request* request) {
750 ExtensionTokenKey key(extension_id_, GetPrimaryAccountId(), oauth_scopes_);
751 id_api()->mint_queue()->RequestStart(type, key, request);
754 void QueueRequestComplete(IdentityMintRequestQueue::MintType type,
755 IdentityMintRequestQueue::Request* request) {
756 ExtensionTokenKey key(extension_id_, GetPrimaryAccountId(), oauth_scopes_);
757 id_api()->mint_queue()->RequestComplete(type, key, request);
760 private:
761 std::string extension_id_;
762 std::set<std::string> oauth_scopes_;
765 IN_PROC_BROWSER_TEST_F(GetAuthTokenFunctionTest,
766 NoClientId) {
767 scoped_refptr<FakeGetAuthTokenFunction> func(new FakeGetAuthTokenFunction());
768 func->set_extension(CreateExtension(SCOPES));
769 std::string error = utils::RunFunctionAndReturnError(
770 func.get(), "[{}]", browser());
771 EXPECT_EQ(std::string(errors::kInvalidClientId), error);
772 EXPECT_FALSE(func->login_ui_shown());
773 EXPECT_FALSE(func->scope_ui_shown());
776 IN_PROC_BROWSER_TEST_F(GetAuthTokenFunctionTest,
777 NoScopes) {
778 scoped_refptr<FakeGetAuthTokenFunction> func(new FakeGetAuthTokenFunction());
779 func->set_extension(CreateExtension(CLIENT_ID));
780 std::string error = utils::RunFunctionAndReturnError(
781 func.get(), "[{}]", browser());
782 EXPECT_EQ(std::string(errors::kInvalidScopes), error);
783 EXPECT_FALSE(func->login_ui_shown());
784 EXPECT_FALSE(func->scope_ui_shown());
787 IN_PROC_BROWSER_TEST_F(GetAuthTokenFunctionTest,
788 NonInteractiveNotSignedIn) {
789 scoped_refptr<FakeGetAuthTokenFunction> func(new FakeGetAuthTokenFunction());
790 func->set_extension(CreateExtension(CLIENT_ID | SCOPES));
791 std::string error = utils::RunFunctionAndReturnError(
792 func.get(), "[{}]", browser());
793 EXPECT_EQ(std::string(errors::kUserNotSignedIn), error);
794 EXPECT_FALSE(func->login_ui_shown());
795 EXPECT_FALSE(func->scope_ui_shown());
798 IN_PROC_BROWSER_TEST_F(GetAuthTokenFunctionTest,
799 NonInteractiveMintFailure) {
800 SignIn("primary@example.com");
801 scoped_refptr<FakeGetAuthTokenFunction> func(new FakeGetAuthTokenFunction());
802 func->set_extension(CreateExtension(CLIENT_ID | SCOPES));
803 func->set_mint_token_result(TestOAuth2MintTokenFlow::MINT_TOKEN_FAILURE);
804 std::string error =
805 utils::RunFunctionAndReturnError(func.get(), "[{}]", browser());
806 EXPECT_TRUE(base::StartsWith(error, errors::kAuthFailure,
807 base::CompareCase::INSENSITIVE_ASCII));
808 EXPECT_FALSE(func->login_ui_shown());
809 EXPECT_FALSE(func->scope_ui_shown());
812 IN_PROC_BROWSER_TEST_F(GetAuthTokenFunctionTest,
813 NonInteractiveLoginAccessTokenFailure) {
814 SignIn("primary@example.com");
815 scoped_refptr<FakeGetAuthTokenFunction> func(new FakeGetAuthTokenFunction());
816 func->set_extension(CreateExtension(CLIENT_ID | SCOPES));
817 func->set_login_access_token_result(false);
818 std::string error = utils::RunFunctionAndReturnError(
819 func.get(), "[{}]", browser());
820 EXPECT_TRUE(base::StartsWith(error, errors::kAuthFailure,
821 base::CompareCase::INSENSITIVE_ASCII));
824 IN_PROC_BROWSER_TEST_F(GetAuthTokenFunctionTest,
825 NonInteractiveMintAdviceSuccess) {
826 SignIn("primary@example.com");
827 scoped_refptr<const Extension> extension(CreateExtension(CLIENT_ID | SCOPES));
828 scoped_refptr<FakeGetAuthTokenFunction> func(new FakeGetAuthTokenFunction());
829 func->set_extension(extension.get());
830 func->set_mint_token_result(TestOAuth2MintTokenFlow::ISSUE_ADVICE_SUCCESS);
831 std::string error =
832 utils::RunFunctionAndReturnError(func.get(), "[{}]", browser());
833 EXPECT_EQ(std::string(errors::kNoGrant), error);
834 EXPECT_FALSE(func->login_ui_shown());
835 EXPECT_FALSE(func->scope_ui_shown());
837 EXPECT_EQ(IdentityTokenCacheValue::CACHE_STATUS_ADVICE,
838 GetCachedToken(std::string()).status());
841 IN_PROC_BROWSER_TEST_F(GetAuthTokenFunctionTest,
842 NonInteractiveMintBadCredentials) {
843 SignIn("primary@example.com");
844 scoped_refptr<FakeGetAuthTokenFunction> func(new FakeGetAuthTokenFunction());
845 func->set_extension(CreateExtension(CLIENT_ID | SCOPES));
846 func->set_mint_token_result(
847 TestOAuth2MintTokenFlow::MINT_TOKEN_BAD_CREDENTIALS);
848 std::string error =
849 utils::RunFunctionAndReturnError(func.get(), "[{}]", browser());
850 EXPECT_TRUE(base::StartsWith(error, errors::kAuthFailure,
851 base::CompareCase::INSENSITIVE_ASCII));
852 EXPECT_FALSE(func->login_ui_shown());
853 EXPECT_FALSE(func->scope_ui_shown());
856 IN_PROC_BROWSER_TEST_F(GetAuthTokenFunctionTest,
857 NonInteractiveMintServiceError) {
858 SignIn("primary@example.com");
859 scoped_refptr<FakeGetAuthTokenFunction> func(new FakeGetAuthTokenFunction());
860 func->set_extension(CreateExtension(CLIENT_ID | SCOPES));
861 func->set_mint_token_result(
862 TestOAuth2MintTokenFlow::MINT_TOKEN_SERVICE_ERROR);
863 std::string error =
864 utils::RunFunctionAndReturnError(func.get(), "[{}]", browser());
865 EXPECT_TRUE(base::StartsWith(error, errors::kAuthFailure,
866 base::CompareCase::INSENSITIVE_ASCII));
867 EXPECT_FALSE(func->login_ui_shown());
868 EXPECT_FALSE(func->scope_ui_shown());
871 IN_PROC_BROWSER_TEST_F(GetAuthTokenFunctionTest,
872 NoOptionsSuccess) {
873 SignIn("primary@example.com");
874 #if defined(OS_WIN) && defined(USE_ASH)
875 // Disable this test in Metro+Ash for now (http://crbug.com/262796).
876 if (base::CommandLine::ForCurrentProcess()->HasSwitch(
877 switches::kAshBrowserTests))
878 return;
879 #endif
881 scoped_refptr<FakeGetAuthTokenFunction> func(new FakeGetAuthTokenFunction());
882 scoped_refptr<const Extension> extension(CreateExtension(CLIENT_ID | SCOPES));
883 func->set_extension(extension.get());
884 func->set_mint_token_result(TestOAuth2MintTokenFlow::MINT_TOKEN_SUCCESS);
885 scoped_ptr<base::Value> value(
886 utils::RunFunctionAndReturnSingleResult(func.get(), "[]", browser()));
887 std::string access_token;
888 EXPECT_TRUE(value->GetAsString(&access_token));
889 EXPECT_EQ(std::string(kAccessToken), access_token);
890 EXPECT_FALSE(func->login_ui_shown());
891 EXPECT_FALSE(func->scope_ui_shown());
892 EXPECT_EQ(IdentityTokenCacheValue::CACHE_STATUS_TOKEN,
893 GetCachedToken(std::string()).status());
896 IN_PROC_BROWSER_TEST_F(GetAuthTokenFunctionTest,
897 NonInteractiveSuccess) {
898 SignIn("primary@example.com");
899 #if defined(OS_WIN) && defined(USE_ASH)
900 // Disable this test in Metro+Ash for now (http://crbug.com/262796).
901 if (base::CommandLine::ForCurrentProcess()->HasSwitch(
902 switches::kAshBrowserTests))
903 return;
904 #endif
906 scoped_refptr<FakeGetAuthTokenFunction> func(new FakeGetAuthTokenFunction());
907 scoped_refptr<const Extension> extension(CreateExtension(CLIENT_ID | SCOPES));
908 func->set_extension(extension.get());
909 func->set_mint_token_result(TestOAuth2MintTokenFlow::MINT_TOKEN_SUCCESS);
910 scoped_ptr<base::Value> value(utils::RunFunctionAndReturnSingleResult(
911 func.get(), "[{}]", browser()));
912 std::string access_token;
913 EXPECT_TRUE(value->GetAsString(&access_token));
914 EXPECT_EQ(std::string(kAccessToken), access_token);
915 EXPECT_FALSE(func->login_ui_shown());
916 EXPECT_FALSE(func->scope_ui_shown());
917 EXPECT_EQ(IdentityTokenCacheValue::CACHE_STATUS_TOKEN,
918 GetCachedToken(std::string()).status());
921 IN_PROC_BROWSER_TEST_F(GetAuthTokenFunctionTest,
922 InteractiveLoginCanceled) {
923 scoped_refptr<FakeGetAuthTokenFunction> func(new FakeGetAuthTokenFunction());
924 func->set_extension(CreateExtension(CLIENT_ID | SCOPES));
925 func->set_login_ui_result(false);
926 std::string error = utils::RunFunctionAndReturnError(
927 func.get(), "[{\"interactive\": true}]", browser());
928 EXPECT_EQ(std::string(errors::kUserNotSignedIn), error);
929 EXPECT_TRUE(func->login_ui_shown());
930 EXPECT_FALSE(func->scope_ui_shown());
933 IN_PROC_BROWSER_TEST_F(GetAuthTokenFunctionTest,
934 InteractiveMintBadCredentialsLoginCanceled) {
935 SignIn("primary@example.com");
936 scoped_refptr<FakeGetAuthTokenFunction> func(new FakeGetAuthTokenFunction());
937 func->set_extension(CreateExtension(CLIENT_ID | SCOPES));
938 func->set_mint_token_result(
939 TestOAuth2MintTokenFlow::MINT_TOKEN_BAD_CREDENTIALS);
940 func->set_login_ui_result(false);
941 std::string error = utils::RunFunctionAndReturnError(
942 func.get(), "[{\"interactive\": true}]", browser());
943 EXPECT_EQ(std::string(errors::kUserNotSignedIn), error);
944 EXPECT_TRUE(func->login_ui_shown());
945 EXPECT_FALSE(func->scope_ui_shown());
948 IN_PROC_BROWSER_TEST_F(GetAuthTokenFunctionTest,
949 InteractiveLoginSuccessNoToken) {
950 scoped_refptr<FakeGetAuthTokenFunction> func(new FakeGetAuthTokenFunction());
951 func->set_extension(CreateExtension(CLIENT_ID | SCOPES));
952 func->set_login_ui_result(false);
953 std::string error = utils::RunFunctionAndReturnError(
954 func.get(), "[{\"interactive\": true}]", browser());
955 EXPECT_EQ(std::string(errors::kUserNotSignedIn), error);
956 EXPECT_TRUE(func->login_ui_shown());
957 EXPECT_FALSE(func->scope_ui_shown());
960 IN_PROC_BROWSER_TEST_F(GetAuthTokenFunctionTest,
961 InteractiveLoginSuccessMintFailure) {
962 scoped_refptr<FakeGetAuthTokenFunction> func(new FakeGetAuthTokenFunction());
963 func->set_extension(CreateExtension(CLIENT_ID | SCOPES));
964 func->set_login_ui_result(true);
965 func->set_mint_token_result(TestOAuth2MintTokenFlow::MINT_TOKEN_FAILURE);
966 std::string error = utils::RunFunctionAndReturnError(
967 func.get(), "[{\"interactive\": true}]", browser());
968 EXPECT_TRUE(base::StartsWith(error, errors::kAuthFailure,
969 base::CompareCase::INSENSITIVE_ASCII));
970 EXPECT_TRUE(func->login_ui_shown());
971 EXPECT_FALSE(func->scope_ui_shown());
974 IN_PROC_BROWSER_TEST_F(GetAuthTokenFunctionTest,
975 InteractiveLoginSuccessLoginAccessTokenFailure) {
976 scoped_refptr<FakeGetAuthTokenFunction> func(new FakeGetAuthTokenFunction());
977 func->set_extension(CreateExtension(CLIENT_ID | SCOPES));
978 func->set_login_ui_result(true);
979 func->set_login_access_token_result(false);
980 std::string error = utils::RunFunctionAndReturnError(
981 func.get(), "[{\"interactive\": true}]", browser());
982 EXPECT_TRUE(base::StartsWith(error, errors::kAuthFailure,
983 base::CompareCase::INSENSITIVE_ASCII));
984 EXPECT_TRUE(func->login_ui_shown());
985 EXPECT_FALSE(func->scope_ui_shown());
988 IN_PROC_BROWSER_TEST_F(GetAuthTokenFunctionTest,
989 InteractiveLoginSuccessMintSuccess) {
990 // TODO(courage): verify that account_id in token service requests
991 // is correct once manual token minting for tests is implemented.
992 scoped_refptr<FakeGetAuthTokenFunction> func(new FakeGetAuthTokenFunction());
993 func->set_extension(CreateExtension(CLIENT_ID | SCOPES));
994 func->set_login_ui_result(true);
995 func->set_mint_token_result(TestOAuth2MintTokenFlow::MINT_TOKEN_SUCCESS);
996 scoped_ptr<base::Value> value(utils::RunFunctionAndReturnSingleResult(
997 func.get(), "[{\"interactive\": true}]", browser()));
998 std::string access_token;
999 EXPECT_TRUE(value->GetAsString(&access_token));
1000 EXPECT_EQ(std::string(kAccessToken), access_token);
1001 EXPECT_TRUE(func->login_ui_shown());
1002 EXPECT_FALSE(func->scope_ui_shown());
1005 IN_PROC_BROWSER_TEST_F(GetAuthTokenFunctionTest,
1006 InteractiveLoginSuccessApprovalAborted) {
1007 scoped_refptr<FakeGetAuthTokenFunction> func(new FakeGetAuthTokenFunction());
1008 func->set_extension(CreateExtension(CLIENT_ID | SCOPES));
1009 func->set_login_ui_result(true);
1010 func->set_mint_token_result(TestOAuth2MintTokenFlow::ISSUE_ADVICE_SUCCESS);
1011 func->set_scope_ui_failure(GaiaWebAuthFlow::WINDOW_CLOSED);
1012 std::string error = utils::RunFunctionAndReturnError(
1013 func.get(), "[{\"interactive\": true}]", browser());
1014 EXPECT_EQ(std::string(errors::kUserRejected), error);
1015 EXPECT_TRUE(func->login_ui_shown());
1016 EXPECT_TRUE(func->scope_ui_shown());
1019 IN_PROC_BROWSER_TEST_F(GetAuthTokenFunctionTest,
1020 InteractiveLoginSuccessApprovalSuccess) {
1021 scoped_refptr<const Extension> extension(CreateExtension(CLIENT_ID | SCOPES));
1022 scoped_refptr<FakeGetAuthTokenFunction> func(new FakeGetAuthTokenFunction());
1023 func->set_extension(extension.get());
1024 func->set_login_ui_result(true);
1025 func->set_mint_token_result(TestOAuth2MintTokenFlow::ISSUE_ADVICE_SUCCESS);
1027 scoped_ptr<base::Value> value(utils::RunFunctionAndReturnSingleResult(
1028 func.get(), "[{\"interactive\": true}]", browser()));
1029 std::string access_token;
1030 EXPECT_TRUE(value->GetAsString(&access_token));
1031 EXPECT_EQ(std::string(kAccessToken), access_token);
1032 EXPECT_TRUE(func->login_ui_shown());
1033 EXPECT_TRUE(func->scope_ui_shown());
1036 IN_PROC_BROWSER_TEST_F(GetAuthTokenFunctionTest,
1037 InteractiveApprovalAborted) {
1038 SignIn("primary@example.com");
1039 scoped_refptr<FakeGetAuthTokenFunction> func(new FakeGetAuthTokenFunction());
1040 func->set_extension(CreateExtension(CLIENT_ID | SCOPES));
1041 func->set_mint_token_result(TestOAuth2MintTokenFlow::ISSUE_ADVICE_SUCCESS);
1042 func->set_scope_ui_failure(GaiaWebAuthFlow::WINDOW_CLOSED);
1043 std::string error = utils::RunFunctionAndReturnError(
1044 func.get(), "[{\"interactive\": true}]", browser());
1045 EXPECT_EQ(std::string(errors::kUserRejected), error);
1046 EXPECT_FALSE(func->login_ui_shown());
1047 EXPECT_TRUE(func->scope_ui_shown());
1050 IN_PROC_BROWSER_TEST_F(GetAuthTokenFunctionTest,
1051 InteractiveApprovalLoadFailed) {
1052 SignIn("primary@example.com");
1053 scoped_refptr<FakeGetAuthTokenFunction> func(new FakeGetAuthTokenFunction());
1054 func->set_extension(CreateExtension(CLIENT_ID | SCOPES));
1055 func->set_mint_token_result(TestOAuth2MintTokenFlow::ISSUE_ADVICE_SUCCESS);
1056 func->set_scope_ui_failure(GaiaWebAuthFlow::LOAD_FAILED);
1057 std::string error = utils::RunFunctionAndReturnError(
1058 func.get(), "[{\"interactive\": true}]", browser());
1059 EXPECT_EQ(std::string(errors::kPageLoadFailure), error);
1060 EXPECT_FALSE(func->login_ui_shown());
1061 EXPECT_TRUE(func->scope_ui_shown());
1064 IN_PROC_BROWSER_TEST_F(GetAuthTokenFunctionTest,
1065 InteractiveApprovalInvalidRedirect) {
1066 SignIn("primary@example.com");
1067 scoped_refptr<FakeGetAuthTokenFunction> func(new FakeGetAuthTokenFunction());
1068 func->set_extension(CreateExtension(CLIENT_ID | SCOPES));
1069 func->set_mint_token_result(TestOAuth2MintTokenFlow::ISSUE_ADVICE_SUCCESS);
1070 func->set_scope_ui_failure(GaiaWebAuthFlow::INVALID_REDIRECT);
1071 std::string error = utils::RunFunctionAndReturnError(
1072 func.get(), "[{\"interactive\": true}]", browser());
1073 EXPECT_EQ(std::string(errors::kInvalidRedirect), error);
1074 EXPECT_FALSE(func->login_ui_shown());
1075 EXPECT_TRUE(func->scope_ui_shown());
1078 IN_PROC_BROWSER_TEST_F(GetAuthTokenFunctionTest,
1079 InteractiveApprovalConnectionFailure) {
1080 SignIn("primary@example.com");
1081 scoped_refptr<FakeGetAuthTokenFunction> func(new FakeGetAuthTokenFunction());
1082 func->set_extension(CreateExtension(CLIENT_ID | SCOPES));
1083 func->set_mint_token_result(TestOAuth2MintTokenFlow::ISSUE_ADVICE_SUCCESS);
1084 func->set_scope_ui_failure(GaiaWebAuthFlow::SERVICE_AUTH_ERROR);
1085 std::string error = utils::RunFunctionAndReturnError(
1086 func.get(), "[{\"interactive\": true}]", browser());
1087 EXPECT_TRUE(base::StartsWith(error, errors::kAuthFailure,
1088 base::CompareCase::INSENSITIVE_ASCII));
1089 EXPECT_FALSE(func->login_ui_shown());
1090 EXPECT_TRUE(func->scope_ui_shown());
1093 IN_PROC_BROWSER_TEST_F(GetAuthTokenFunctionTest,
1094 InteractiveApprovalOAuthErrors) {
1095 SignIn("primary@example.com");
1096 scoped_refptr<const Extension> extension(CreateExtension(CLIENT_ID | SCOPES));
1098 std::map<std::string, std::string> error_map;
1099 error_map.insert(std::make_pair("access_denied", errors::kUserRejected));
1100 error_map.insert(std::make_pair("invalid_scope", errors::kInvalidScopes));
1101 error_map.insert(std::make_pair(
1102 "unmapped_error", std::string(errors::kAuthFailure) + "unmapped_error"));
1104 for (std::map<std::string, std::string>::const_iterator
1105 it = error_map.begin();
1106 it != error_map.end();
1107 ++it) {
1108 scoped_refptr<FakeGetAuthTokenFunction> func(
1109 new FakeGetAuthTokenFunction());
1110 func->set_extension(extension.get());
1111 // Make sure we don't get a cached issue_advice result, which would cause
1112 // flow to be leaked.
1113 id_api()->EraseAllCachedTokens();
1114 func->set_mint_token_result(TestOAuth2MintTokenFlow::ISSUE_ADVICE_SUCCESS);
1115 func->set_scope_ui_oauth_error(it->first);
1116 std::string error = utils::RunFunctionAndReturnError(
1117 func.get(), "[{\"interactive\": true}]", browser());
1118 EXPECT_EQ(it->second, error);
1119 EXPECT_FALSE(func->login_ui_shown());
1120 EXPECT_TRUE(func->scope_ui_shown());
1124 IN_PROC_BROWSER_TEST_F(GetAuthTokenFunctionTest,
1125 InteractiveApprovalSuccess) {
1126 SignIn("primary@example.com");
1127 scoped_refptr<const Extension> extension(CreateExtension(CLIENT_ID | SCOPES));
1128 scoped_refptr<FakeGetAuthTokenFunction> func(new FakeGetAuthTokenFunction());
1129 func->set_extension(extension.get());
1130 func->set_mint_token_result(TestOAuth2MintTokenFlow::ISSUE_ADVICE_SUCCESS);
1132 scoped_ptr<base::Value> value(utils::RunFunctionAndReturnSingleResult(
1133 func.get(), "[{\"interactive\": true}]", browser()));
1134 std::string access_token;
1135 EXPECT_TRUE(value->GetAsString(&access_token));
1136 EXPECT_EQ(std::string(kAccessToken), access_token);
1137 EXPECT_FALSE(func->login_ui_shown());
1138 EXPECT_TRUE(func->scope_ui_shown());
1140 EXPECT_EQ(IdentityTokenCacheValue::CACHE_STATUS_TOKEN,
1141 GetCachedToken(std::string()).status());
1144 IN_PROC_BROWSER_TEST_F(GetAuthTokenFunctionTest, NoninteractiveQueue) {
1145 SignIn("primary@example.com");
1146 scoped_refptr<const Extension> extension(CreateExtension(CLIENT_ID | SCOPES));
1147 scoped_refptr<FakeGetAuthTokenFunction> func(new FakeGetAuthTokenFunction());
1148 func->set_extension(extension.get());
1150 // Create a fake request to block the queue.
1151 MockQueuedMintRequest queued_request;
1152 IdentityMintRequestQueue::MintType type =
1153 IdentityMintRequestQueue::MINT_TYPE_NONINTERACTIVE;
1155 EXPECT_CALL(queued_request, StartMintToken(type)).Times(1);
1156 QueueRequestStart(type, &queued_request);
1158 // The real request will start processing, but wait in the queue behind
1159 // the blocker.
1160 RunFunctionAsync(func.get(), "[{}]");
1161 // Verify that we have fetched the login token at this point.
1162 testing::Mock::VerifyAndClearExpectations(func.get());
1164 // The flow will be created after the first queued request clears.
1165 func->set_mint_token_result(TestOAuth2MintTokenFlow::MINT_TOKEN_SUCCESS);
1167 QueueRequestComplete(type, &queued_request);
1169 scoped_ptr<base::Value> value(WaitForSingleResult(func.get()));
1170 std::string access_token;
1171 EXPECT_TRUE(value->GetAsString(&access_token));
1172 EXPECT_EQ(std::string(kAccessToken), access_token);
1173 EXPECT_FALSE(func->login_ui_shown());
1174 EXPECT_FALSE(func->scope_ui_shown());
1177 IN_PROC_BROWSER_TEST_F(GetAuthTokenFunctionTest, InteractiveQueue) {
1178 SignIn("primary@example.com");
1179 scoped_refptr<const Extension> extension(CreateExtension(CLIENT_ID | SCOPES));
1180 scoped_refptr<FakeGetAuthTokenFunction> func(new FakeGetAuthTokenFunction());
1181 func->set_extension(extension.get());
1183 // Create a fake request to block the queue.
1184 MockQueuedMintRequest queued_request;
1185 IdentityMintRequestQueue::MintType type =
1186 IdentityMintRequestQueue::MINT_TYPE_INTERACTIVE;
1188 EXPECT_CALL(queued_request, StartMintToken(type)).Times(1);
1189 QueueRequestStart(type, &queued_request);
1191 // The real request will start processing, but wait in the queue behind
1192 // the blocker.
1193 func->set_mint_token_result(TestOAuth2MintTokenFlow::ISSUE_ADVICE_SUCCESS);
1194 RunFunctionAsync(func.get(), "[{\"interactive\": true}]");
1195 // Verify that we have fetched the login token and run the first flow.
1196 testing::Mock::VerifyAndClearExpectations(func.get());
1197 EXPECT_FALSE(func->scope_ui_shown());
1199 // The UI will be displayed and a token retrieved after the first
1200 // queued request clears.
1201 QueueRequestComplete(type, &queued_request);
1203 scoped_ptr<base::Value> value(WaitForSingleResult(func.get()));
1204 std::string access_token;
1205 EXPECT_TRUE(value->GetAsString(&access_token));
1206 EXPECT_EQ(std::string(kAccessToken), access_token);
1207 EXPECT_FALSE(func->login_ui_shown());
1208 EXPECT_TRUE(func->scope_ui_shown());
1211 IN_PROC_BROWSER_TEST_F(GetAuthTokenFunctionTest, InteractiveQueueShutdown) {
1212 SignIn("primary@example.com");
1213 scoped_refptr<const Extension> extension(CreateExtension(CLIENT_ID | SCOPES));
1214 scoped_refptr<FakeGetAuthTokenFunction> func(new FakeGetAuthTokenFunction());
1215 func->set_extension(extension.get());
1217 // Create a fake request to block the queue.
1218 MockQueuedMintRequest queued_request;
1219 IdentityMintRequestQueue::MintType type =
1220 IdentityMintRequestQueue::MINT_TYPE_INTERACTIVE;
1222 EXPECT_CALL(queued_request, StartMintToken(type)).Times(1);
1223 QueueRequestStart(type, &queued_request);
1225 // The real request will start processing, but wait in the queue behind
1226 // the blocker.
1227 func->set_mint_token_result(TestOAuth2MintTokenFlow::ISSUE_ADVICE_SUCCESS);
1228 RunFunctionAsync(func.get(), "[{\"interactive\": true}]");
1229 // Verify that we have fetched the login token and run the first flow.
1230 testing::Mock::VerifyAndClearExpectations(func.get());
1231 EXPECT_FALSE(func->scope_ui_shown());
1233 // After the request is canceled, the function will complete.
1234 func->OnShutdown();
1235 EXPECT_EQ(std::string(errors::kCanceled), WaitForError(func.get()));
1236 EXPECT_FALSE(func->login_ui_shown());
1237 EXPECT_FALSE(func->scope_ui_shown());
1239 QueueRequestComplete(type, &queued_request);
1242 IN_PROC_BROWSER_TEST_F(GetAuthTokenFunctionTest, NoninteractiveShutdown) {
1243 SignIn("primary@example.com");
1244 scoped_refptr<const Extension> extension(CreateExtension(CLIENT_ID | SCOPES));
1245 scoped_refptr<FakeGetAuthTokenFunction> func(new FakeGetAuthTokenFunction());
1246 func->set_extension(extension.get());
1248 func->set_mint_token_flow(make_scoped_ptr(new TestHangOAuth2MintTokenFlow()));
1249 RunFunctionAsync(func.get(), "[{\"interactive\": false}]");
1251 // After the request is canceled, the function will complete.
1252 func->OnShutdown();
1253 EXPECT_EQ(std::string(errors::kCanceled), WaitForError(func.get()));
1256 IN_PROC_BROWSER_TEST_F(GetAuthTokenFunctionTest,
1257 InteractiveQueuedNoninteractiveFails) {
1258 SignIn("primary@example.com");
1259 scoped_refptr<const Extension> extension(CreateExtension(CLIENT_ID | SCOPES));
1260 scoped_refptr<FakeGetAuthTokenFunction> func(new FakeGetAuthTokenFunction());
1261 func->set_extension(extension.get());
1263 // Create a fake request to block the interactive queue.
1264 MockQueuedMintRequest queued_request;
1265 IdentityMintRequestQueue::MintType type =
1266 IdentityMintRequestQueue::MINT_TYPE_INTERACTIVE;
1268 EXPECT_CALL(queued_request, StartMintToken(type)).Times(1);
1269 QueueRequestStart(type, &queued_request);
1271 // Non-interactive requests fail without hitting GAIA, because a
1272 // consent UI is known to be up.
1273 std::string error = utils::RunFunctionAndReturnError(
1274 func.get(), "[{}]", browser());
1275 EXPECT_EQ(std::string(errors::kNoGrant), error);
1276 EXPECT_FALSE(func->login_ui_shown());
1277 EXPECT_FALSE(func->scope_ui_shown());
1279 QueueRequestComplete(type, &queued_request);
1282 IN_PROC_BROWSER_TEST_F(GetAuthTokenFunctionTest,
1283 NonInteractiveCacheHit) {
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 a token
1290 IdentityTokenCacheValue token(kAccessToken,
1291 base::TimeDelta::FromSeconds(3600));
1292 SetCachedToken(token);
1294 // Get a token. Should not require a GAIA request.
1295 scoped_ptr<base::Value> value(utils::RunFunctionAndReturnSingleResult(
1296 func.get(), "[{}]", browser()));
1297 std::string access_token;
1298 EXPECT_TRUE(value->GetAsString(&access_token));
1299 EXPECT_EQ(std::string(kAccessToken), access_token);
1300 EXPECT_FALSE(func->login_ui_shown());
1301 EXPECT_FALSE(func->scope_ui_shown());
1304 IN_PROC_BROWSER_TEST_F(GetAuthTokenFunctionTest,
1305 NonInteractiveIssueAdviceCacheHit) {
1306 SignIn("primary@example.com");
1307 scoped_refptr<const Extension> extension(CreateExtension(CLIENT_ID | SCOPES));
1308 scoped_refptr<FakeGetAuthTokenFunction> func(new FakeGetAuthTokenFunction());
1309 func->set_extension(extension.get());
1311 // pre-populate the cache with advice
1312 IssueAdviceInfo info;
1313 IdentityTokenCacheValue token(info);
1314 SetCachedToken(token);
1316 // Should return an error without a GAIA request.
1317 std::string error = utils::RunFunctionAndReturnError(
1318 func.get(), "[{}]", browser());
1319 EXPECT_EQ(std::string(errors::kNoGrant), error);
1320 EXPECT_FALSE(func->login_ui_shown());
1321 EXPECT_FALSE(func->scope_ui_shown());
1324 IN_PROC_BROWSER_TEST_F(GetAuthTokenFunctionTest,
1325 InteractiveCacheHit) {
1326 SignIn("primary@example.com");
1327 scoped_refptr<const Extension> extension(CreateExtension(CLIENT_ID | SCOPES));
1328 scoped_refptr<FakeGetAuthTokenFunction> func(new FakeGetAuthTokenFunction());
1329 func->set_extension(extension.get());
1331 // Create a fake request to block the queue.
1332 MockQueuedMintRequest queued_request;
1333 IdentityMintRequestQueue::MintType type =
1334 IdentityMintRequestQueue::MINT_TYPE_INTERACTIVE;
1336 EXPECT_CALL(queued_request, StartMintToken(type)).Times(1);
1337 QueueRequestStart(type, &queued_request);
1339 // The real request will start processing, but wait in the queue behind
1340 // the blocker.
1341 func->set_mint_token_result(TestOAuth2MintTokenFlow::ISSUE_ADVICE_SUCCESS);
1342 RunFunctionAsync(func.get(), "[{\"interactive\": true}]");
1344 // Populate the cache with a token while the request is blocked.
1345 IdentityTokenCacheValue token(kAccessToken,
1346 base::TimeDelta::FromSeconds(3600));
1347 SetCachedToken(token);
1349 // When we wake up the request, it returns the cached token without
1350 // displaying a UI, or hitting GAIA.
1352 QueueRequestComplete(type, &queued_request);
1354 scoped_ptr<base::Value> value(WaitForSingleResult(func.get()));
1355 std::string access_token;
1356 EXPECT_TRUE(value->GetAsString(&access_token));
1357 EXPECT_EQ(std::string(kAccessToken), access_token);
1358 EXPECT_FALSE(func->login_ui_shown());
1359 EXPECT_FALSE(func->scope_ui_shown());
1362 IN_PROC_BROWSER_TEST_F(GetAuthTokenFunctionTest,
1363 LoginInvalidatesTokenCache) {
1364 scoped_refptr<FakeGetAuthTokenFunction> func(new FakeGetAuthTokenFunction());
1365 scoped_refptr<const Extension> extension(CreateExtension(CLIENT_ID | SCOPES));
1366 func->set_extension(extension.get());
1368 // pre-populate the cache with a token
1369 IdentityTokenCacheValue token(kAccessToken,
1370 base::TimeDelta::FromSeconds(3600));
1371 SetCachedToken(token);
1373 // Because the user is not signed in, the token will be removed,
1374 // and we'll hit GAIA for new tokens.
1375 func->set_login_ui_result(true);
1376 func->set_mint_token_result(TestOAuth2MintTokenFlow::ISSUE_ADVICE_SUCCESS);
1378 scoped_ptr<base::Value> value(utils::RunFunctionAndReturnSingleResult(
1379 func.get(), "[{\"interactive\": true}]", browser()));
1380 std::string access_token;
1381 EXPECT_TRUE(value->GetAsString(&access_token));
1382 EXPECT_EQ(std::string(kAccessToken), access_token);
1383 EXPECT_TRUE(func->login_ui_shown());
1384 EXPECT_TRUE(func->scope_ui_shown());
1385 EXPECT_EQ(IdentityTokenCacheValue::CACHE_STATUS_TOKEN,
1386 GetCachedToken(std::string()).status());
1389 IN_PROC_BROWSER_TEST_F(GetAuthTokenFunctionTest, ComponentWithChromeClientId) {
1390 scoped_refptr<FakeGetAuthTokenFunction> func(new FakeGetAuthTokenFunction());
1391 scoped_refptr<const Extension> extension(
1392 CreateExtension(SCOPES | AS_COMPONENT));
1393 func->set_extension(extension.get());
1394 const OAuth2Info& oauth2_info = OAuth2Info::GetOAuth2Info(extension.get());
1395 EXPECT_TRUE(oauth2_info.client_id.empty());
1396 EXPECT_FALSE(func->GetOAuth2ClientId().empty());
1397 EXPECT_NE("client1", func->GetOAuth2ClientId());
1400 IN_PROC_BROWSER_TEST_F(GetAuthTokenFunctionTest, ComponentWithNormalClientId) {
1401 scoped_refptr<FakeGetAuthTokenFunction> func(new FakeGetAuthTokenFunction());
1402 scoped_refptr<const Extension> extension(
1403 CreateExtension(CLIENT_ID | SCOPES | AS_COMPONENT));
1404 func->set_extension(extension.get());
1405 EXPECT_EQ("client1", func->GetOAuth2ClientId());
1408 IN_PROC_BROWSER_TEST_F(GetAuthTokenFunctionTest, MultiDefaultUser) {
1409 SignIn("primary@example.com");
1410 SetAccountState(CreateIds("primary@example.com", "1"), true);
1411 SetAccountState(CreateIds("secondary@example.com", "2"), true);
1413 scoped_refptr<FakeGetAuthTokenFunction> func(new FakeGetAuthTokenFunction());
1414 scoped_refptr<const Extension> extension(CreateExtension(CLIENT_ID | SCOPES));
1415 func->set_extension(extension.get());
1416 func->set_auto_login_access_token(false);
1417 func->set_mint_token_result(TestOAuth2MintTokenFlow::MINT_TOKEN_SUCCESS);
1419 RunFunctionAsync(func.get(), "[{}]");
1421 IssueLoginAccessTokenForAccount("primary@example.com");
1423 scoped_ptr<base::Value> value(WaitForSingleResult(func.get()));
1424 std::string access_token;
1425 EXPECT_TRUE(value->GetAsString(&access_token));
1426 EXPECT_EQ(std::string(kAccessToken), access_token);
1427 EXPECT_EQ(IdentityTokenCacheValue::CACHE_STATUS_TOKEN,
1428 GetCachedToken(std::string()).status());
1429 EXPECT_EQ("access_token-primary@example.com", func->login_access_token());
1432 IN_PROC_BROWSER_TEST_F(GetAuthTokenFunctionTest, MultiPrimaryUser) {
1433 SignIn("primary@example.com");
1434 IssueLoginRefreshTokenForAccount("secondary@example.com");
1435 SetAccountState(CreateIds("primary@example.com", "1"), true);
1436 SetAccountState(CreateIds("secondary@example.com", "2"), true);
1438 scoped_refptr<FakeGetAuthTokenFunction> func(new FakeGetAuthTokenFunction());
1439 scoped_refptr<const Extension> extension(CreateExtension(CLIENT_ID | SCOPES));
1440 func->set_extension(extension.get());
1441 func->set_auto_login_access_token(false);
1442 func->set_mint_token_result(TestOAuth2MintTokenFlow::MINT_TOKEN_SUCCESS);
1444 RunFunctionAsync(func.get(), "[{\"account\": { \"id\": \"1\" } }]");
1446 IssueLoginAccessTokenForAccount("primary@example.com");
1448 scoped_ptr<base::Value> value(WaitForSingleResult(func.get()));
1449 std::string access_token;
1450 EXPECT_TRUE(value->GetAsString(&access_token));
1451 EXPECT_EQ(std::string(kAccessToken), access_token);
1452 EXPECT_EQ(IdentityTokenCacheValue::CACHE_STATUS_TOKEN,
1453 GetCachedToken(std::string()).status());
1454 EXPECT_EQ("access_token-primary@example.com", func->login_access_token());
1457 IN_PROC_BROWSER_TEST_F(GetAuthTokenFunctionTest, MultiSecondaryUser) {
1458 SignIn("primary@example.com");
1459 IssueLoginRefreshTokenForAccount("secondary@example.com");
1460 SetAccountState(CreateIds("primary@example.com", "1"), true);
1461 SetAccountState(CreateIds("secondary@example.com", "2"), true);
1463 scoped_refptr<FakeGetAuthTokenFunction> func(new FakeGetAuthTokenFunction());
1464 scoped_refptr<const Extension> extension(CreateExtension(CLIENT_ID | SCOPES));
1465 func->set_extension(extension.get());
1466 func->set_auto_login_access_token(false);
1467 func->set_mint_token_result(TestOAuth2MintTokenFlow::MINT_TOKEN_SUCCESS);
1469 RunFunctionAsync(func.get(), "[{\"account\": { \"id\": \"2\" } }]");
1471 IssueLoginAccessTokenForAccount("secondary@example.com");
1473 scoped_ptr<base::Value> value(WaitForSingleResult(func.get()));
1474 std::string access_token;
1475 EXPECT_TRUE(value->GetAsString(&access_token));
1476 EXPECT_EQ(std::string(kAccessToken), access_token);
1477 EXPECT_EQ(IdentityTokenCacheValue::CACHE_STATUS_TOKEN,
1478 GetCachedToken("secondary@example.com").status());
1479 EXPECT_EQ("access_token-secondary@example.com", func->login_access_token());
1482 IN_PROC_BROWSER_TEST_F(GetAuthTokenFunctionTest, MultiUnknownUser) {
1483 SignIn("primary@example.com");
1484 IssueLoginRefreshTokenForAccount("secondary@example.com");
1485 SetAccountState(CreateIds("primary@example.com", "1"), true);
1486 SetAccountState(CreateIds("secondary@example.com", "2"), true);
1488 scoped_refptr<FakeGetAuthTokenFunction> func(new FakeGetAuthTokenFunction());
1489 scoped_refptr<const Extension> extension(CreateExtension(CLIENT_ID | SCOPES));
1490 func->set_extension(extension.get());
1491 func->set_auto_login_access_token(false);
1493 std::string error = utils::RunFunctionAndReturnError(
1494 func.get(), "[{\"account\": { \"id\": \"3\" } }]", browser());
1495 EXPECT_EQ(std::string(errors::kUserNotSignedIn), error);
1498 IN_PROC_BROWSER_TEST_F(GetAuthTokenFunctionTest,
1499 MultiSecondaryNonInteractiveMintFailure) {
1500 SignIn("primary@example.com");
1501 IssueLoginRefreshTokenForAccount("secondary@example.com");
1502 SetAccountState(CreateIds("primary@example.com", "1"), true);
1503 SetAccountState(CreateIds("secondary@example.com", "2"), true);
1505 scoped_refptr<FakeGetAuthTokenFunction> func(new FakeGetAuthTokenFunction());
1506 func->set_extension(CreateExtension(CLIENT_ID | SCOPES));
1507 func->set_mint_token_result(TestOAuth2MintTokenFlow::MINT_TOKEN_FAILURE);
1508 std::string error = utils::RunFunctionAndReturnError(
1509 func.get(), "[{\"account\": { \"id\": \"2\" } }]", browser());
1510 EXPECT_TRUE(base::StartsWith(error, errors::kAuthFailure,
1511 base::CompareCase::INSENSITIVE_ASCII));
1512 EXPECT_FALSE(func->login_ui_shown());
1513 EXPECT_FALSE(func->scope_ui_shown());
1516 IN_PROC_BROWSER_TEST_F(GetAuthTokenFunctionTest,
1517 MultiSecondaryNonInteractiveLoginAccessTokenFailure) {
1518 SignIn("primary@example.com");
1519 IssueLoginRefreshTokenForAccount("secondary@example.com");
1520 SetAccountState(CreateIds("primary@example.com", "1"), true);
1521 SetAccountState(CreateIds("secondary@example.com", "2"), true);
1523 scoped_refptr<FakeGetAuthTokenFunction> func(new FakeGetAuthTokenFunction());
1524 func->set_extension(CreateExtension(CLIENT_ID | SCOPES));
1525 func->set_login_access_token_result(false);
1526 std::string error = utils::RunFunctionAndReturnError(
1527 func.get(), "[{\"account\": { \"id\": \"2\" } }]", browser());
1528 EXPECT_TRUE(base::StartsWith(error, errors::kAuthFailure,
1529 base::CompareCase::INSENSITIVE_ASCII));
1532 IN_PROC_BROWSER_TEST_F(GetAuthTokenFunctionTest,
1533 MultiSecondaryInteractiveApprovalAborted) {
1534 SignIn("primary@example.com");
1535 IssueLoginRefreshTokenForAccount("secondary@example.com");
1536 SetAccountState(CreateIds("primary@example.com", "1"), true);
1537 SetAccountState(CreateIds("secondary@example.com", "2"), true);
1539 scoped_refptr<FakeGetAuthTokenFunction> func(new FakeGetAuthTokenFunction());
1540 func->set_extension(CreateExtension(CLIENT_ID | SCOPES));
1541 func->set_mint_token_result(TestOAuth2MintTokenFlow::ISSUE_ADVICE_SUCCESS);
1542 func->set_scope_ui_failure(GaiaWebAuthFlow::WINDOW_CLOSED);
1543 std::string error = utils::RunFunctionAndReturnError(
1544 func.get(),
1545 "[{\"account\": { \"id\": \"2\" }, \"interactive\": true}]",
1546 browser());
1547 EXPECT_EQ(std::string(errors::kUserRejected), error);
1548 EXPECT_FALSE(func->login_ui_shown());
1549 EXPECT_TRUE(func->scope_ui_shown());
1552 IN_PROC_BROWSER_TEST_F(GetAuthTokenFunctionTest, ScopesDefault) {
1553 SignIn("primary@example.com");
1554 scoped_refptr<FakeGetAuthTokenFunction> func(new FakeGetAuthTokenFunction());
1555 scoped_refptr<const Extension> extension(CreateExtension(CLIENT_ID | SCOPES));
1556 func->set_extension(extension.get());
1557 func->set_mint_token_result(TestOAuth2MintTokenFlow::MINT_TOKEN_SUCCESS);
1558 scoped_ptr<base::Value> value(
1559 utils::RunFunctionAndReturnSingleResult(func.get(), "[{}]", browser()));
1560 std::string access_token;
1561 EXPECT_TRUE(value->GetAsString(&access_token));
1562 EXPECT_EQ(std::string(kAccessToken), access_token);
1564 const ExtensionTokenKey* token_key = func->GetExtensionTokenKeyForTest();
1565 EXPECT_EQ(2ul, token_key->scopes.size());
1566 EXPECT_TRUE(ContainsKey(token_key->scopes, "scope1"));
1567 EXPECT_TRUE(ContainsKey(token_key->scopes, "scope2"));
1570 IN_PROC_BROWSER_TEST_F(GetAuthTokenFunctionTest, ScopesEmpty) {
1571 scoped_refptr<FakeGetAuthTokenFunction> func(new FakeGetAuthTokenFunction());
1572 scoped_refptr<const Extension> extension(CreateExtension(CLIENT_ID | SCOPES));
1573 func->set_extension(extension.get());
1575 std::string error(utils::RunFunctionAndReturnError(
1576 func.get(), "[{\"scopes\": []}]", browser()));
1578 EXPECT_EQ(errors::kInvalidScopes, error);
1581 IN_PROC_BROWSER_TEST_F(GetAuthTokenFunctionTest, ScopesEmail) {
1582 SignIn("primary@example.com");
1583 scoped_refptr<FakeGetAuthTokenFunction> func(new FakeGetAuthTokenFunction());
1584 scoped_refptr<const Extension> extension(CreateExtension(CLIENT_ID | SCOPES));
1585 func->set_extension(extension.get());
1586 func->set_mint_token_result(TestOAuth2MintTokenFlow::MINT_TOKEN_SUCCESS);
1587 scoped_ptr<base::Value> value(utils::RunFunctionAndReturnSingleResult(
1588 func.get(), "[{\"scopes\": [\"email\"]}]", browser()));
1589 std::string access_token;
1590 EXPECT_TRUE(value->GetAsString(&access_token));
1591 EXPECT_EQ(std::string(kAccessToken), access_token);
1593 const ExtensionTokenKey* token_key = func->GetExtensionTokenKeyForTest();
1594 EXPECT_EQ(1ul, token_key->scopes.size());
1595 EXPECT_TRUE(ContainsKey(token_key->scopes, "email"));
1598 IN_PROC_BROWSER_TEST_F(GetAuthTokenFunctionTest, ScopesEmailFooBar) {
1599 SignIn("primary@example.com");
1600 scoped_refptr<FakeGetAuthTokenFunction> func(new FakeGetAuthTokenFunction());
1601 scoped_refptr<const Extension> extension(CreateExtension(CLIENT_ID | SCOPES));
1602 func->set_extension(extension.get());
1603 func->set_mint_token_result(TestOAuth2MintTokenFlow::MINT_TOKEN_SUCCESS);
1604 scoped_ptr<base::Value> value(utils::RunFunctionAndReturnSingleResult(
1605 func.get(), "[{\"scopes\": [\"email\", \"foo\", \"bar\"]}]", browser()));
1606 std::string access_token;
1607 EXPECT_TRUE(value->GetAsString(&access_token));
1608 EXPECT_EQ(std::string(kAccessToken), access_token);
1610 const ExtensionTokenKey* token_key = func->GetExtensionTokenKeyForTest();
1611 EXPECT_EQ(3ul, token_key->scopes.size());
1612 EXPECT_TRUE(ContainsKey(token_key->scopes, "email"));
1613 EXPECT_TRUE(ContainsKey(token_key->scopes, "foo"));
1614 EXPECT_TRUE(ContainsKey(token_key->scopes, "bar"));
1617 class RemoveCachedAuthTokenFunctionTest : public ExtensionBrowserTest {
1618 protected:
1619 bool InvalidateDefaultToken() {
1620 scoped_refptr<IdentityRemoveCachedAuthTokenFunction> func(
1621 new IdentityRemoveCachedAuthTokenFunction);
1622 func->set_extension(test_util::CreateEmptyExtension(kExtensionId).get());
1623 return utils::RunFunction(
1624 func.get(),
1625 std::string("[{\"token\": \"") + kAccessToken + "\"}]",
1626 browser(),
1627 extension_function_test_utils::NONE);
1630 IdentityAPI* id_api() {
1631 return IdentityAPI::GetFactoryInstance()->Get(browser()->profile());
1634 void SetCachedToken(IdentityTokenCacheValue& token_data) {
1635 ExtensionTokenKey key(
1636 kExtensionId, "test@example.com", std::set<std::string>());
1637 id_api()->SetCachedToken(key, token_data);
1640 const IdentityTokenCacheValue& GetCachedToken() {
1641 return id_api()->GetCachedToken(ExtensionTokenKey(
1642 kExtensionId, "test@example.com", std::set<std::string>()));
1646 IN_PROC_BROWSER_TEST_F(RemoveCachedAuthTokenFunctionTest, NotFound) {
1647 EXPECT_TRUE(InvalidateDefaultToken());
1648 EXPECT_EQ(IdentityTokenCacheValue::CACHE_STATUS_NOTFOUND,
1649 GetCachedToken().status());
1652 IN_PROC_BROWSER_TEST_F(RemoveCachedAuthTokenFunctionTest, Advice) {
1653 IssueAdviceInfo info;
1654 IdentityTokenCacheValue advice(info);
1655 SetCachedToken(advice);
1656 EXPECT_TRUE(InvalidateDefaultToken());
1657 EXPECT_EQ(IdentityTokenCacheValue::CACHE_STATUS_ADVICE,
1658 GetCachedToken().status());
1661 IN_PROC_BROWSER_TEST_F(RemoveCachedAuthTokenFunctionTest, NonMatchingToken) {
1662 IdentityTokenCacheValue token("non_matching_token",
1663 base::TimeDelta::FromSeconds(3600));
1664 SetCachedToken(token);
1665 EXPECT_TRUE(InvalidateDefaultToken());
1666 EXPECT_EQ(IdentityTokenCacheValue::CACHE_STATUS_TOKEN,
1667 GetCachedToken().status());
1668 EXPECT_EQ("non_matching_token", GetCachedToken().token());
1671 IN_PROC_BROWSER_TEST_F(RemoveCachedAuthTokenFunctionTest, MatchingToken) {
1672 IdentityTokenCacheValue token(kAccessToken,
1673 base::TimeDelta::FromSeconds(3600));
1674 SetCachedToken(token);
1675 EXPECT_EQ(IdentityTokenCacheValue::CACHE_STATUS_TOKEN,
1676 GetCachedToken().status());
1677 EXPECT_TRUE(InvalidateDefaultToken());
1678 EXPECT_EQ(IdentityTokenCacheValue::CACHE_STATUS_NOTFOUND,
1679 GetCachedToken().status());
1682 class LaunchWebAuthFlowFunctionTest : public AsyncExtensionBrowserTest {
1683 public:
1684 void SetUpCommandLine(base::CommandLine* command_line) override {
1685 AsyncExtensionBrowserTest::SetUpCommandLine(command_line);
1686 // Reduce performance test variance by disabling background networking.
1687 command_line->AppendSwitch(switches::kDisableBackgroundNetworking);
1691 IN_PROC_BROWSER_TEST_F(LaunchWebAuthFlowFunctionTest, UserCloseWindow) {
1692 net::SpawnedTestServer https_server(
1693 net::SpawnedTestServer::TYPE_HTTPS,
1694 net::SpawnedTestServer::kLocalhost,
1695 base::FilePath(FILE_PATH_LITERAL(
1696 "chrome/test/data/extensions/api_test/identity")));
1697 ASSERT_TRUE(https_server.Start());
1698 GURL auth_url(https_server.GetURL("files/interaction_required.html"));
1700 scoped_refptr<IdentityLaunchWebAuthFlowFunction> function(
1701 new IdentityLaunchWebAuthFlowFunction());
1702 scoped_refptr<Extension> empty_extension(test_util::CreateEmptyExtension());
1703 function->set_extension(empty_extension.get());
1705 WaitForGURLAndCloseWindow popup_observer(auth_url);
1707 std::string args = "[{\"interactive\": true, \"url\": \"" +
1708 auth_url.spec() + "\"}]";
1709 RunFunctionAsync(function.get(), args);
1711 popup_observer.Wait();
1712 popup_observer.CloseEmbedderWebContents();
1714 EXPECT_EQ(std::string(errors::kUserRejected), WaitForError(function.get()));
1717 IN_PROC_BROWSER_TEST_F(LaunchWebAuthFlowFunctionTest, InteractionRequired) {
1718 net::SpawnedTestServer https_server(
1719 net::SpawnedTestServer::TYPE_HTTPS,
1720 net::SpawnedTestServer::kLocalhost,
1721 base::FilePath(FILE_PATH_LITERAL(
1722 "chrome/test/data/extensions/api_test/identity")));
1723 ASSERT_TRUE(https_server.Start());
1724 GURL auth_url(https_server.GetURL("files/interaction_required.html"));
1726 scoped_refptr<IdentityLaunchWebAuthFlowFunction> function(
1727 new IdentityLaunchWebAuthFlowFunction());
1728 scoped_refptr<Extension> empty_extension(test_util::CreateEmptyExtension());
1729 function->set_extension(empty_extension.get());
1731 std::string args = "[{\"interactive\": false, \"url\": \"" +
1732 auth_url.spec() + "\"}]";
1733 std::string error =
1734 utils::RunFunctionAndReturnError(function.get(), args, browser());
1736 EXPECT_EQ(std::string(errors::kInteractionRequired), error);
1739 IN_PROC_BROWSER_TEST_F(LaunchWebAuthFlowFunctionTest, LoadFailed) {
1740 net::SpawnedTestServer https_server(
1741 net::SpawnedTestServer::TYPE_HTTPS,
1742 net::SpawnedTestServer::kLocalhost,
1743 base::FilePath(FILE_PATH_LITERAL(
1744 "chrome/test/data/extensions/api_test/identity")));
1745 ASSERT_TRUE(https_server.Start());
1746 GURL auth_url(https_server.GetURL("files/five_hundred.html"));
1748 scoped_refptr<IdentityLaunchWebAuthFlowFunction> function(
1749 new IdentityLaunchWebAuthFlowFunction());
1750 scoped_refptr<Extension> empty_extension(test_util::CreateEmptyExtension());
1751 function->set_extension(empty_extension.get());
1753 std::string args = "[{\"interactive\": true, \"url\": \"" +
1754 auth_url.spec() + "\"}]";
1755 std::string error =
1756 utils::RunFunctionAndReturnError(function.get(), args, browser());
1758 EXPECT_EQ(std::string(errors::kPageLoadFailure), error);
1761 IN_PROC_BROWSER_TEST_F(LaunchWebAuthFlowFunctionTest, NonInteractiveSuccess) {
1762 #if defined(OS_WIN) && defined(USE_ASH)
1763 // Disable this test in Metro+Ash for now (http://crbug.com/262796).
1764 if (base::CommandLine::ForCurrentProcess()->HasSwitch(
1765 switches::kAshBrowserTests))
1766 return;
1767 #endif
1769 scoped_refptr<IdentityLaunchWebAuthFlowFunction> function(
1770 new IdentityLaunchWebAuthFlowFunction());
1771 scoped_refptr<Extension> empty_extension(test_util::CreateEmptyExtension());
1772 function->set_extension(empty_extension.get());
1774 function->InitFinalRedirectURLPrefixForTest("abcdefghij");
1775 scoped_ptr<base::Value> value(utils::RunFunctionAndReturnSingleResult(
1776 function.get(),
1777 "[{\"interactive\": false,"
1778 "\"url\": \"https://abcdefghij.chromiumapp.org/callback#test\"}]",
1779 browser()));
1781 std::string url;
1782 EXPECT_TRUE(value->GetAsString(&url));
1783 EXPECT_EQ(std::string("https://abcdefghij.chromiumapp.org/callback#test"),
1784 url);
1787 IN_PROC_BROWSER_TEST_F(
1788 LaunchWebAuthFlowFunctionTest, InteractiveFirstNavigationSuccess) {
1789 #if defined(OS_WIN) && defined(USE_ASH)
1790 // Disable this test in Metro+Ash for now (http://crbug.com/262796).
1791 if (base::CommandLine::ForCurrentProcess()->HasSwitch(
1792 switches::kAshBrowserTests))
1793 return;
1794 #endif
1796 scoped_refptr<IdentityLaunchWebAuthFlowFunction> function(
1797 new IdentityLaunchWebAuthFlowFunction());
1798 scoped_refptr<Extension> empty_extension(test_util::CreateEmptyExtension());
1799 function->set_extension(empty_extension.get());
1801 function->InitFinalRedirectURLPrefixForTest("abcdefghij");
1802 scoped_ptr<base::Value> value(utils::RunFunctionAndReturnSingleResult(
1803 function.get(),
1804 "[{\"interactive\": true,"
1805 "\"url\": \"https://abcdefghij.chromiumapp.org/callback#test\"}]",
1806 browser()));
1808 std::string url;
1809 EXPECT_TRUE(value->GetAsString(&url));
1810 EXPECT_EQ(std::string("https://abcdefghij.chromiumapp.org/callback#test"),
1811 url);
1814 IN_PROC_BROWSER_TEST_F(LaunchWebAuthFlowFunctionTest,
1815 DISABLED_InteractiveSecondNavigationSuccess) {
1816 net::SpawnedTestServer https_server(
1817 net::SpawnedTestServer::TYPE_HTTPS,
1818 net::SpawnedTestServer::kLocalhost,
1819 base::FilePath(FILE_PATH_LITERAL(
1820 "chrome/test/data/extensions/api_test/identity")));
1821 ASSERT_TRUE(https_server.Start());
1822 GURL auth_url(https_server.GetURL("files/redirect_to_chromiumapp.html"));
1824 scoped_refptr<IdentityLaunchWebAuthFlowFunction> function(
1825 new IdentityLaunchWebAuthFlowFunction());
1826 scoped_refptr<Extension> empty_extension(test_util::CreateEmptyExtension());
1827 function->set_extension(empty_extension.get());
1829 function->InitFinalRedirectURLPrefixForTest("abcdefghij");
1830 std::string args = "[{\"interactive\": true, \"url\": \"" +
1831 auth_url.spec() + "\"}]";
1832 scoped_ptr<base::Value> value(
1833 utils::RunFunctionAndReturnSingleResult(function.get(), args, browser()));
1835 std::string url;
1836 EXPECT_TRUE(value->GetAsString(&url));
1837 EXPECT_EQ(std::string("https://abcdefghij.chromiumapp.org/callback#test"),
1838 url);
1841 } // namespace extensions
1843 // Tests the chrome.identity API implemented by custom JS bindings .
1844 IN_PROC_BROWSER_TEST_F(ExtensionApiTest, ChromeIdentityJsBindings) {
1845 ASSERT_TRUE(RunExtensionTest("identity/js_bindings")) << message_;