1 // Copyright (c) 2012 The Chromium Authors. All rights reserved.
2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file.
9 #include "base/command_line.h"
10 #include "base/prefs/pref_service.h"
11 #include "base/strings/string_util.h"
12 #include "base/strings/stringprintf.h"
13 #include "base/values.h"
14 #include "chrome/browser/chrome_notification_types.h"
15 #include "chrome/browser/extensions/api/identity/identity_api.h"
16 #include "chrome/browser/extensions/component_loader.h"
17 #include "chrome/browser/extensions/extension_apitest.h"
18 #include "chrome/browser/extensions/extension_browsertest.h"
19 #include "chrome/browser/extensions/extension_function_test_utils.h"
20 #include "chrome/browser/extensions/extension_service.h"
21 #include "chrome/browser/profiles/profile.h"
22 #include "chrome/browser/signin/account_reconcilor_factory.h"
23 #include "chrome/browser/signin/account_tracker_service_factory.h"
24 #include "chrome/browser/signin/fake_account_reconcilor.h"
25 #include "chrome/browser/signin/fake_profile_oauth2_token_service.h"
26 #include "chrome/browser/signin/fake_profile_oauth2_token_service_builder.h"
27 #include "chrome/browser/signin/fake_signin_manager.h"
28 #include "chrome/browser/signin/profile_oauth2_token_service_factory.h"
29 #include "chrome/browser/signin/signin_manager_factory.h"
30 #include "chrome/browser/ui/browser.h"
31 #include "chrome/browser/ui/browser_window.h"
32 #include "chrome/common/chrome_switches.h"
33 #include "chrome/common/extensions/api/identity.h"
34 #include "chrome/test/base/in_process_browser_test.h"
35 #include "chrome/test/base/test_switches.h"
36 #include "components/crx_file/id_util.h"
37 #include "components/signin/core/browser/account_tracker_service.h"
38 #include "components/signin/core/browser/signin_manager.h"
39 #include "components/signin/core/common/profile_management_switches.h"
40 #include "components/signin/core/common/signin_pref_names.h"
41 #include "content/public/browser/notification_service.h"
42 #include "content/public/browser/notification_source.h"
43 #include "content/public/test/test_utils.h"
44 #include "extensions/browser/api_test_utils.h"
45 #include "extensions/browser/guest_view/guest_view_base.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"
56 using testing::Return
;
57 using testing::ReturnRef
;
59 namespace extensions
{
63 namespace errors
= identity_constants
;
64 namespace utils
= extension_function_test_utils
;
66 static const char kAccessToken
[] = "auth_token";
67 static const char kExtensionId
[] = "ext_id";
69 // This helps us be able to wait until an UIThreadExtensionFunction calls
71 class SendResponseDelegate
72 : public UIThreadExtensionFunction::DelegateForTests
{
74 SendResponseDelegate() : should_post_quit_(false) {}
76 virtual ~SendResponseDelegate() {}
78 void set_should_post_quit(bool should_quit
) {
79 should_post_quit_
= should_quit
;
83 return response_
.get() != NULL
;
87 EXPECT_TRUE(HasResponse());
88 return *response_
.get();
91 void OnSendResponse(UIThreadExtensionFunction
* function
,
93 bool bad_message
) override
{
94 ASSERT_FALSE(bad_message
);
95 ASSERT_FALSE(HasResponse());
96 response_
.reset(new bool);
98 if (should_post_quit_
) {
99 base::MessageLoopForUI::current()->Quit();
104 scoped_ptr
<bool> response_
;
105 bool should_post_quit_
;
108 class AsyncExtensionBrowserTest
: public ExtensionBrowserTest
{
110 // Asynchronous function runner allows tests to manipulate the browser window
111 // after the call happens.
112 void RunFunctionAsync(
113 UIThreadExtensionFunction
* function
,
114 const std::string
& args
) {
115 response_delegate_
.reset(new SendResponseDelegate
);
116 function
->set_test_delegate(response_delegate_
.get());
117 scoped_ptr
<base::ListValue
> parsed_args(utils::ParseList(args
));
118 EXPECT_TRUE(parsed_args
.get()) <<
119 "Could not parse extension function arguments: " << args
;
120 function
->SetArgs(parsed_args
.get());
122 if (!function
->extension()) {
123 scoped_refptr
<Extension
> empty_extension(
124 test_util::CreateEmptyExtension());
125 function
->set_extension(empty_extension
.get());
128 function
->set_browser_context(browser()->profile());
129 function
->set_has_callback(true);
130 function
->Run()->Execute();
133 std::string
WaitForError(UIThreadExtensionFunction
* function
) {
134 RunMessageLoopUntilResponse();
135 EXPECT_FALSE(function
->GetResultList()) << "Did not expect a result";
136 return function
->GetError();
139 base::Value
* WaitForSingleResult(UIThreadExtensionFunction
* function
) {
140 RunMessageLoopUntilResponse();
141 EXPECT_TRUE(function
->GetError().empty()) << "Unexpected error: "
142 << function
->GetError();
143 const base::Value
* single_result
= NULL
;
144 if (function
->GetResultList() != NULL
&&
145 function
->GetResultList()->Get(0, &single_result
)) {
146 return single_result
->DeepCopy();
152 void RunMessageLoopUntilResponse() {
153 // If the RunAsync of |function| didn't already call SendResponse, run the
154 // message loop until they do.
155 if (!response_delegate_
->HasResponse()) {
156 response_delegate_
->set_should_post_quit(true);
157 content::RunMessageLoop();
159 EXPECT_TRUE(response_delegate_
->HasResponse());
162 scoped_ptr
<SendResponseDelegate
> response_delegate_
;
165 class TestHangOAuth2MintTokenFlow
: public OAuth2MintTokenFlow
{
167 TestHangOAuth2MintTokenFlow()
168 : OAuth2MintTokenFlow(NULL
, OAuth2MintTokenFlow::Parameters()) {}
170 void Start(net::URLRequestContextGetter
* context
,
171 const std::string
& access_token
) override
{
172 // Do nothing, simulating a hanging network call.
176 class TestOAuth2MintTokenFlow
: public OAuth2MintTokenFlow
{
179 ISSUE_ADVICE_SUCCESS
,
182 MINT_TOKEN_BAD_CREDENTIALS
,
183 MINT_TOKEN_SERVICE_ERROR
186 TestOAuth2MintTokenFlow(ResultType result
,
187 OAuth2MintTokenFlow::Delegate
* delegate
)
188 : OAuth2MintTokenFlow(delegate
, OAuth2MintTokenFlow::Parameters()),
190 delegate_(delegate
) {}
192 void Start(net::URLRequestContextGetter
* context
,
193 const std::string
& access_token
) override
{
195 case ISSUE_ADVICE_SUCCESS
: {
196 IssueAdviceInfo info
;
197 delegate_
->OnIssueAdviceSuccess(info
);
200 case MINT_TOKEN_SUCCESS
: {
201 delegate_
->OnMintTokenSuccess(kAccessToken
, 3600);
204 case MINT_TOKEN_FAILURE
: {
205 GoogleServiceAuthError
error(GoogleServiceAuthError::CONNECTION_FAILED
);
206 delegate_
->OnMintTokenFailure(error
);
209 case MINT_TOKEN_BAD_CREDENTIALS
: {
210 GoogleServiceAuthError
error(
211 GoogleServiceAuthError::INVALID_GAIA_CREDENTIALS
);
212 delegate_
->OnMintTokenFailure(error
);
215 case MINT_TOKEN_SERVICE_ERROR
: {
216 GoogleServiceAuthError error
=
217 GoogleServiceAuthError::FromServiceError("invalid_scope");
218 delegate_
->OnMintTokenFailure(error
);
226 OAuth2MintTokenFlow::Delegate
* delegate_
;
229 // Waits for a specific GURL to generate a NOTIFICATION_LOAD_STOP event and
230 // saves a pointer to the window embedding the WebContents, which can be later
232 class WaitForGURLAndCloseWindow
: public content::WindowedNotificationObserver
{
234 explicit WaitForGURLAndCloseWindow(GURL url
)
235 : WindowedNotificationObserver(
236 content::NOTIFICATION_LOAD_STOP
,
237 content::NotificationService::AllSources()),
240 // NotificationObserver:
241 void Observe(int type
,
242 const content::NotificationSource
& source
,
243 const content::NotificationDetails
& details
) override
{
244 content::NavigationController
* web_auth_flow_controller
=
245 content::Source
<content::NavigationController
>(source
).ptr();
246 content::WebContents
* web_contents
=
247 web_auth_flow_controller
->GetWebContents();
249 if (web_contents
->GetURL() == url_
) {
250 // It is safe to keep the pointer here, because we know in a test, that
251 // the WebContents won't go away before CloseEmbedderWebContents is
252 // called. Don't copy this code to production.
253 GuestViewBase
* guest
= GuestViewBase::FromWebContents(web_contents
);
254 embedder_web_contents_
= guest
->embedder_web_contents();
255 // Condtionally invoke parent class so that Wait will not exit
256 // until the target URL arrives.
257 content::WindowedNotificationObserver::Observe(type
, source
, details
);
261 // Closes the window embedding the WebContents. The action is separated from
262 // the Observe method to make sure the list of observers is not deleted,
263 // while some event is already being processed. (That causes ASAN failures.)
264 void CloseEmbedderWebContents() {
265 if (embedder_web_contents_
)
266 embedder_web_contents_
->Close();
271 content::WebContents
* embedder_web_contents_
;
276 class FakeGetAuthTokenFunction
: public IdentityGetAuthTokenFunction
{
278 FakeGetAuthTokenFunction()
279 : login_access_token_result_(true),
280 auto_login_access_token_(true),
281 login_ui_result_(true),
282 scope_ui_result_(true),
283 login_ui_shown_(false),
284 scope_ui_shown_(false) {}
286 void set_login_access_token_result(bool result
) {
287 login_access_token_result_
= result
;
290 void set_auto_login_access_token(bool automatic
) {
291 auto_login_access_token_
= automatic
;
294 void set_login_ui_result(bool result
) { login_ui_result_
= result
; }
296 void set_mint_token_flow(scoped_ptr
<OAuth2MintTokenFlow
> flow
) {
300 void set_mint_token_result(TestOAuth2MintTokenFlow::ResultType result_type
) {
302 make_scoped_ptr(new TestOAuth2MintTokenFlow(result_type
, this)));
305 void set_scope_ui_failure(GaiaWebAuthFlow::Failure failure
) {
306 scope_ui_result_
= false;
307 scope_ui_failure_
= failure
;
310 void set_scope_ui_oauth_error(const std::string
& oauth_error
) {
311 scope_ui_result_
= false;
312 scope_ui_failure_
= GaiaWebAuthFlow::OAUTH_ERROR
;
313 scope_ui_oauth_error_
= oauth_error
;
316 bool login_ui_shown() const { return login_ui_shown_
; }
318 bool scope_ui_shown() const { return scope_ui_shown_
; }
320 std::string
login_access_token() const { return login_access_token_
; }
322 void StartLoginAccessTokenRequest() override
{
323 if (auto_login_access_token_
) {
324 if (login_access_token_result_
) {
325 OnGetTokenSuccess(login_token_request_
.get(),
327 base::Time::Now() + base::TimeDelta::FromHours(1LL));
329 GoogleServiceAuthError
error(
330 GoogleServiceAuthError::INVALID_GAIA_CREDENTIALS
);
331 OnGetTokenFailure(login_token_request_
.get(), error
);
334 // Make a request to the token service. The test now must tell
335 // the token service to issue an access token (or an error).
336 IdentityGetAuthTokenFunction::StartLoginAccessTokenRequest();
340 void ShowLoginPopup() override
{
341 EXPECT_FALSE(login_ui_shown_
);
342 login_ui_shown_
= true;
343 if (login_ui_result_
)
349 void ShowOAuthApprovalDialog(const IssueAdviceInfo
& issue_advice
) override
{
350 scope_ui_shown_
= true;
352 if (scope_ui_result_
) {
353 OnGaiaFlowCompleted(kAccessToken
, "3600");
354 } else if (scope_ui_failure_
== GaiaWebAuthFlow::SERVICE_AUTH_ERROR
) {
355 GoogleServiceAuthError
error(GoogleServiceAuthError::CONNECTION_FAILED
);
356 OnGaiaFlowFailure(scope_ui_failure_
, error
, "");
358 GoogleServiceAuthError
error(GoogleServiceAuthError::NONE
);
359 OnGaiaFlowFailure(scope_ui_failure_
, error
, scope_ui_oauth_error_
);
363 void StartGaiaRequest(const std::string
& login_access_token
) override
{
364 EXPECT_TRUE(login_access_token_
.empty());
365 // Save the login token used in the mint token flow so tests can see
366 // what account was used.
367 login_access_token_
= login_access_token
;
368 IdentityGetAuthTokenFunction::StartGaiaRequest(login_access_token
);
371 OAuth2MintTokenFlow
* CreateMintTokenFlow() override
{
372 return flow_
.release();
376 ~FakeGetAuthTokenFunction() override
{}
377 bool login_access_token_result_
;
378 bool auto_login_access_token_
;
379 bool login_ui_result_
;
380 bool scope_ui_result_
;
381 GaiaWebAuthFlow::Failure scope_ui_failure_
;
382 std::string scope_ui_oauth_error_
;
383 bool login_ui_shown_
;
384 bool scope_ui_shown_
;
386 scoped_ptr
<OAuth2MintTokenFlow
> flow_
;
388 std::string login_access_token_
;
391 class MockQueuedMintRequest
: public IdentityMintRequestQueue::Request
{
393 MOCK_METHOD1(StartMintToken
, void(IdentityMintRequestQueue::MintType
));
396 gaia::AccountIds
CreateIds(std::string email
, std::string obfid
) {
397 gaia::AccountIds ids
;
398 ids
.account_key
= email
;
404 class IdentityGetAccountsFunctionTest
: public ExtensionBrowserTest
{
405 void SetUpCommandLine(base::CommandLine
* command_line
) override
{
406 ExtensionBrowserTest::SetUpCommandLine(command_line
);
407 command_line
->AppendSwitch(switches::kExtensionsMultiAccount
);
411 void SetAccountState(gaia::AccountIds ids
, bool is_signed_in
) {
412 IdentityAPI::GetFactoryInstance()->Get(profile())->SetAccountStateForTest(
416 testing::AssertionResult
ExpectGetAccounts(
417 const std::vector
<std::string
>& accounts
) {
418 scoped_refptr
<IdentityGetAccountsFunction
> func(
419 new IdentityGetAccountsFunction
);
420 func
->set_extension(test_util::CreateEmptyExtension(kExtensionId
).get());
421 if (!utils::RunFunction(
422 func
.get(), std::string("[]"), browser(), utils::NONE
)) {
423 return GenerateFailureResult(accounts
, NULL
)
424 << "getAccounts did not return a result.";
426 const base::ListValue
* callback_arguments
= func
->GetResultList();
427 if (!callback_arguments
)
428 return GenerateFailureResult(accounts
, NULL
) << "NULL result";
430 if (callback_arguments
->GetSize() != 1) {
431 return GenerateFailureResult(accounts
, NULL
)
432 << "Expected 1 argument but got " << callback_arguments
->GetSize();
435 const base::ListValue
* results
;
436 if (!callback_arguments
->GetList(0, &results
))
437 GenerateFailureResult(accounts
, NULL
) << "Result was not an array";
439 std::set
<std::string
> result_ids
;
440 for (base::ListValue::const_iterator it
= results
->begin();
441 it
!= results
->end();
443 scoped_ptr
<api::identity::AccountInfo
> info
=
444 api::identity::AccountInfo::FromValue(**it
);
446 result_ids
.insert(info
->id
);
448 return GenerateFailureResult(accounts
, results
);
451 for (std::vector
<std::string
>::const_iterator it
= accounts
.begin();
452 it
!= accounts
.end();
454 if (result_ids
.find(*it
) == result_ids
.end())
455 return GenerateFailureResult(accounts
, results
);
458 return testing::AssertionResult(true);
461 testing::AssertionResult
GenerateFailureResult(
462 const ::std::vector
<std::string
>& accounts
,
463 const base::ListValue
* results
) {
464 testing::Message
msg("Expected: ");
465 for (std::vector
<std::string
>::const_iterator it
= accounts
.begin();
466 it
!= accounts
.end();
474 for (base::ListValue::const_iterator it
= results
->begin();
475 it
!= results
->end();
477 scoped_ptr
<api::identity::AccountInfo
> info
=
478 api::identity::AccountInfo::FromValue(**it
);
480 msg
<< info
->id
<< " ";
482 msg
<< *it
<< "<-" << (*it
)->GetType() << " ";
486 return testing::AssertionFailure(msg
);
490 IN_PROC_BROWSER_TEST_F(IdentityGetAccountsFunctionTest
, MultiAccountOn
) {
491 EXPECT_TRUE(switches::IsExtensionsMultiAccount());
494 IN_PROC_BROWSER_TEST_F(IdentityGetAccountsFunctionTest
, NoneSignedIn
) {
495 EXPECT_TRUE(ExpectGetAccounts(std::vector
<std::string
>()));
498 IN_PROC_BROWSER_TEST_F(IdentityGetAccountsFunctionTest
,
499 PrimaryAccountSignedIn
) {
500 SetAccountState(CreateIds("primary@example.com", "1"), true);
501 std::vector
<std::string
> primary
;
502 primary
.push_back("1");
503 EXPECT_TRUE(ExpectGetAccounts(primary
));
506 IN_PROC_BROWSER_TEST_F(IdentityGetAccountsFunctionTest
, TwoAccountsSignedIn
) {
507 SetAccountState(CreateIds("primary@example.com", "1"), true);
508 SetAccountState(CreateIds("secondary@example.com", "2"), true);
509 std::vector
<std::string
> two_accounts
;
510 two_accounts
.push_back("1");
511 two_accounts
.push_back("2");
512 EXPECT_TRUE(ExpectGetAccounts(two_accounts
));
515 class IdentityOldProfilesGetAccountsFunctionTest
516 : public IdentityGetAccountsFunctionTest
{
517 void SetUpCommandLine(base::CommandLine
* command_line
) override
{
518 // Don't add the multi-account switch that parent class would have.
522 IN_PROC_BROWSER_TEST_F(IdentityOldProfilesGetAccountsFunctionTest
,
524 EXPECT_FALSE(switches::IsExtensionsMultiAccount());
527 IN_PROC_BROWSER_TEST_F(IdentityOldProfilesGetAccountsFunctionTest
,
528 TwoAccountsSignedIn
) {
529 SetAccountState(CreateIds("primary@example.com", "1"), true);
530 SetAccountState(CreateIds("secondary@example.com", "2"), true);
531 std::vector
<std::string
> only_primary
;
532 only_primary
.push_back("1");
533 EXPECT_TRUE(ExpectGetAccounts(only_primary
));
536 class IdentityTestWithSignin
: public AsyncExtensionBrowserTest
{
538 void SetUpInProcessBrowserTestFixture() override
{
539 AsyncExtensionBrowserTest::SetUpInProcessBrowserTestFixture();
541 will_create_browser_context_services_subscription_
=
542 BrowserContextDependencyManager::GetInstance()
543 ->RegisterWillCreateBrowserContextServicesCallbackForTesting(
544 base::Bind(&IdentityTestWithSignin::
545 OnWillCreateBrowserContextServices
,
546 base::Unretained(this)))
550 void OnWillCreateBrowserContextServices(content::BrowserContext
* context
) {
551 // Replace the signin manager and token service with fakes. Do this ahead of
552 // creating the browser so that a bunch of classes don't register as
553 // observers and end up needing to unregister when the fake is substituted.
554 SigninManagerFactory::GetInstance()->SetTestingFactory(
555 context
, &FakeSigninManagerBase::Build
);
556 ProfileOAuth2TokenServiceFactory::GetInstance()->SetTestingFactory(
557 context
, &BuildFakeProfileOAuth2TokenService
);
558 AccountReconcilorFactory::GetInstance()->SetTestingFactory(
559 context
, &FakeAccountReconcilor::Build
);
562 void SetUpOnMainThread() override
{
563 AsyncExtensionBrowserTest::SetUpOnMainThread();
565 // Grab references to the fake signin manager and token service.
566 signin_manager_
= static_cast<FakeSigninManagerForTesting
*>(
567 SigninManagerFactory::GetInstance()->GetForProfile(profile()));
568 ASSERT_TRUE(signin_manager_
);
569 token_service_
= static_cast<FakeProfileOAuth2TokenService
*>(
570 ProfileOAuth2TokenServiceFactory::GetInstance()->GetForProfile(
572 ASSERT_TRUE(token_service_
);
576 void SignIn(const std::string account_key
) {
577 #if defined(OS_CHROMEOS)
578 signin_manager_
->SetAuthenticatedUsername(account_key
);
580 signin_manager_
->SignIn(account_key
, "password");
582 token_service_
->IssueRefreshTokenForUser(account_key
, "refresh_token");
585 void SignIn(const std::string
& account_key
, const std::string
& gaia
) {
586 AccountTrackerService
* account_tracker
=
587 AccountTrackerServiceFactory::GetForProfile(profile());
588 account_tracker
->SeedAccountInfo(gaia
, account_key
);
592 FakeSigninManagerForTesting
* signin_manager_
;
593 FakeProfileOAuth2TokenService
* token_service_
;
595 scoped_ptr
<base::CallbackList
<void(content::BrowserContext
*)>::Subscription
>
596 will_create_browser_context_services_subscription_
;
599 class IdentityGetProfileUserInfoFunctionTest
: public IdentityTestWithSignin
{
601 scoped_ptr
<api::identity::ProfileUserInfo
> RunGetProfileUserInfo() {
602 scoped_refptr
<IdentityGetProfileUserInfoFunction
> func(
603 new IdentityGetProfileUserInfoFunction
);
604 func
->set_extension(test_util::CreateEmptyExtension(kExtensionId
).get());
605 scoped_ptr
<base::Value
> value(
606 utils::RunFunctionAndReturnSingleResult(func
.get(), "[]", browser()));
607 return api::identity::ProfileUserInfo::FromValue(*value
.get());
610 scoped_ptr
<api::identity::ProfileUserInfo
> RunGetProfileUserInfoWithEmail() {
611 scoped_refptr
<IdentityGetProfileUserInfoFunction
> func(
612 new IdentityGetProfileUserInfoFunction
);
613 func
->set_extension(CreateExtensionWithEmailPermission());
614 scoped_ptr
<base::Value
> value(
615 utils::RunFunctionAndReturnSingleResult(func
.get(), "[]", browser()));
616 return api::identity::ProfileUserInfo::FromValue(*value
.get());
620 scoped_refptr
<Extension
> CreateExtensionWithEmailPermission() {
621 scoped_ptr
<base::DictionaryValue
> test_extension_value(
622 api_test_utils::ParseDictionary(
623 "{\"name\": \"Test\", \"version\": \"1.0\", "
624 "\"permissions\": [\"identity.email\"]}"));
625 return api_test_utils::CreateExtension(test_extension_value
.get());
629 IN_PROC_BROWSER_TEST_F(IdentityGetProfileUserInfoFunctionTest
, NotSignedIn
) {
630 scoped_ptr
<api::identity::ProfileUserInfo
> info
=
631 RunGetProfileUserInfoWithEmail();
632 EXPECT_TRUE(info
->email
.empty());
633 EXPECT_TRUE(info
->id
.empty());
636 IN_PROC_BROWSER_TEST_F(IdentityGetProfileUserInfoFunctionTest
, SignedIn
) {
637 SignIn("president@example.com", "12345");
638 scoped_ptr
<api::identity::ProfileUserInfo
> info
=
639 RunGetProfileUserInfoWithEmail();
640 EXPECT_EQ("president@example.com", info
->email
);
641 EXPECT_EQ("12345", info
->id
);
644 IN_PROC_BROWSER_TEST_F(IdentityGetProfileUserInfoFunctionTest
,
645 NotSignedInNoEmail
) {
646 scoped_ptr
<api::identity::ProfileUserInfo
> info
= RunGetProfileUserInfo();
647 EXPECT_TRUE(info
->email
.empty());
648 EXPECT_TRUE(info
->id
.empty());
651 IN_PROC_BROWSER_TEST_F(IdentityGetProfileUserInfoFunctionTest
,
653 SignIn("president@example.com", "12345");
654 scoped_ptr
<api::identity::ProfileUserInfo
> info
= RunGetProfileUserInfo();
655 EXPECT_TRUE(info
->email
.empty());
656 EXPECT_TRUE(info
->id
.empty());
659 class GetAuthTokenFunctionTest
: public IdentityTestWithSignin
{
661 void SetUpCommandLine(base::CommandLine
* command_line
) override
{
662 IdentityTestWithSignin::SetUpCommandLine(command_line
);
663 command_line
->AppendSwitch(switches::kExtensionsMultiAccount
);
666 void IssueLoginRefreshTokenForAccount(const std::string account_key
) {
667 token_service_
->IssueRefreshTokenForUser(account_key
, "refresh_token");
670 void IssueLoginAccessTokenForAccount(const std::string account_key
) {
671 token_service_
->IssueAllTokensForAccount(
673 "access_token-" + account_key
,
674 base::Time::Now() + base::TimeDelta::FromSeconds(3600));
677 void SetAccountState(gaia::AccountIds ids
, bool is_signed_in
) {
678 IdentityAPI::GetFactoryInstance()->Get(profile())->SetAccountStateForTest(
690 ~GetAuthTokenFunctionTest() override
{}
692 // Helper to create an extension with specific OAuth2Info fields set.
693 // |fields_to_set| should be computed by using fields of Oauth2Fields enum.
694 const Extension
* CreateExtension(int fields_to_set
) {
695 const Extension
* ext
;
696 base::FilePath manifest_path
=
697 test_data_dir_
.AppendASCII("platform_apps/oauth2");
698 base::FilePath component_manifest_path
=
699 test_data_dir_
.AppendASCII("packaged_app/component_oauth2");
700 if ((fields_to_set
& AS_COMPONENT
) == 0)
701 ext
= LoadExtension(manifest_path
);
703 ext
= LoadExtensionAsComponent(component_manifest_path
);
704 OAuth2Info
& oauth2_info
=
705 const_cast<OAuth2Info
&>(OAuth2Info::GetOAuth2Info(ext
));
706 if ((fields_to_set
& CLIENT_ID
) != 0)
707 oauth2_info
.client_id
= "client1";
708 if ((fields_to_set
& SCOPES
) != 0) {
709 oauth2_info
.scopes
.push_back("scope1");
710 oauth2_info
.scopes
.push_back("scope2");
713 extension_id_
= ext
->id();
714 oauth_scopes_
= std::set
<std::string
>(oauth2_info
.scopes
.begin(),
715 oauth2_info
.scopes
.end());
719 IdentityAPI
* id_api() {
720 return IdentityAPI::GetFactoryInstance()->Get(browser()->profile());
723 const std::string
GetPrimaryAccountId() {
724 SigninManagerBase
* signin_manager
=
725 SigninManagerFactory::GetForProfile(browser()->profile());
726 return signin_manager
->GetAuthenticatedAccountId();
729 void SetCachedToken(const IdentityTokenCacheValue
& token_data
) {
730 ExtensionTokenKey
key(extension_id_
, GetPrimaryAccountId(), oauth_scopes_
);
731 id_api()->SetCachedToken(key
, token_data
);
734 const IdentityTokenCacheValue
& GetCachedToken(std::string account_id
) {
735 if (account_id
.empty())
736 account_id
= GetPrimaryAccountId();
737 ExtensionTokenKey
key(extension_id_
, account_id
, oauth_scopes_
);
738 return id_api()->GetCachedToken(key
);
741 void QueueRequestStart(IdentityMintRequestQueue::MintType type
,
742 IdentityMintRequestQueue::Request
* request
) {
743 ExtensionTokenKey
key(extension_id_
, GetPrimaryAccountId(), oauth_scopes_
);
744 id_api()->mint_queue()->RequestStart(type
, key
, request
);
747 void QueueRequestComplete(IdentityMintRequestQueue::MintType type
,
748 IdentityMintRequestQueue::Request
* request
) {
749 ExtensionTokenKey
key(extension_id_
, GetPrimaryAccountId(), oauth_scopes_
);
750 id_api()->mint_queue()->RequestComplete(type
, key
, request
);
754 std::string extension_id_
;
755 std::set
<std::string
> oauth_scopes_
;
758 IN_PROC_BROWSER_TEST_F(GetAuthTokenFunctionTest
,
760 scoped_refptr
<FakeGetAuthTokenFunction
> func(new FakeGetAuthTokenFunction());
761 func
->set_extension(CreateExtension(SCOPES
));
762 std::string error
= utils::RunFunctionAndReturnError(
763 func
.get(), "[{}]", browser());
764 EXPECT_EQ(std::string(errors::kInvalidClientId
), error
);
765 EXPECT_FALSE(func
->login_ui_shown());
766 EXPECT_FALSE(func
->scope_ui_shown());
769 IN_PROC_BROWSER_TEST_F(GetAuthTokenFunctionTest
,
771 scoped_refptr
<FakeGetAuthTokenFunction
> func(new FakeGetAuthTokenFunction());
772 func
->set_extension(CreateExtension(CLIENT_ID
));
773 std::string error
= utils::RunFunctionAndReturnError(
774 func
.get(), "[{}]", browser());
775 EXPECT_EQ(std::string(errors::kInvalidScopes
), error
);
776 EXPECT_FALSE(func
->login_ui_shown());
777 EXPECT_FALSE(func
->scope_ui_shown());
780 IN_PROC_BROWSER_TEST_F(GetAuthTokenFunctionTest
,
781 NonInteractiveNotSignedIn
) {
782 scoped_refptr
<FakeGetAuthTokenFunction
> func(new FakeGetAuthTokenFunction());
783 func
->set_extension(CreateExtension(CLIENT_ID
| SCOPES
));
784 std::string error
= utils::RunFunctionAndReturnError(
785 func
.get(), "[{}]", browser());
786 EXPECT_EQ(std::string(errors::kUserNotSignedIn
), error
);
787 EXPECT_FALSE(func
->login_ui_shown());
788 EXPECT_FALSE(func
->scope_ui_shown());
791 IN_PROC_BROWSER_TEST_F(GetAuthTokenFunctionTest
,
792 NonInteractiveMintFailure
) {
793 SignIn("primary@example.com");
794 scoped_refptr
<FakeGetAuthTokenFunction
> func(new FakeGetAuthTokenFunction());
795 func
->set_extension(CreateExtension(CLIENT_ID
| SCOPES
));
796 func
->set_mint_token_result(TestOAuth2MintTokenFlow::MINT_TOKEN_FAILURE
);
798 utils::RunFunctionAndReturnError(func
.get(), "[{}]", browser());
799 EXPECT_TRUE(StartsWithASCII(error
, errors::kAuthFailure
, false));
800 EXPECT_FALSE(func
->login_ui_shown());
801 EXPECT_FALSE(func
->scope_ui_shown());
804 IN_PROC_BROWSER_TEST_F(GetAuthTokenFunctionTest
,
805 NonInteractiveLoginAccessTokenFailure
) {
806 SignIn("primary@example.com");
807 scoped_refptr
<FakeGetAuthTokenFunction
> func(new FakeGetAuthTokenFunction());
808 func
->set_extension(CreateExtension(CLIENT_ID
| SCOPES
));
809 func
->set_login_access_token_result(false);
810 std::string error
= utils::RunFunctionAndReturnError(
811 func
.get(), "[{}]", browser());
812 EXPECT_TRUE(StartsWithASCII(error
, errors::kAuthFailure
, false));
815 IN_PROC_BROWSER_TEST_F(GetAuthTokenFunctionTest
,
816 NonInteractiveMintAdviceSuccess
) {
817 SignIn("primary@example.com");
818 scoped_refptr
<const Extension
> extension(CreateExtension(CLIENT_ID
| SCOPES
));
819 scoped_refptr
<FakeGetAuthTokenFunction
> func(new FakeGetAuthTokenFunction());
820 func
->set_extension(extension
.get());
821 func
->set_mint_token_result(TestOAuth2MintTokenFlow::ISSUE_ADVICE_SUCCESS
);
823 utils::RunFunctionAndReturnError(func
.get(), "[{}]", browser());
824 EXPECT_EQ(std::string(errors::kNoGrant
), error
);
825 EXPECT_FALSE(func
->login_ui_shown());
826 EXPECT_FALSE(func
->scope_ui_shown());
828 EXPECT_EQ(IdentityTokenCacheValue::CACHE_STATUS_ADVICE
,
829 GetCachedToken(std::string()).status());
832 IN_PROC_BROWSER_TEST_F(GetAuthTokenFunctionTest
,
833 NonInteractiveMintBadCredentials
) {
834 SignIn("primary@example.com");
835 scoped_refptr
<FakeGetAuthTokenFunction
> func(new FakeGetAuthTokenFunction());
836 func
->set_extension(CreateExtension(CLIENT_ID
| SCOPES
));
837 func
->set_mint_token_result(
838 TestOAuth2MintTokenFlow::MINT_TOKEN_BAD_CREDENTIALS
);
840 utils::RunFunctionAndReturnError(func
.get(), "[{}]", browser());
841 EXPECT_TRUE(StartsWithASCII(error
, errors::kAuthFailure
, false));
842 EXPECT_FALSE(func
->login_ui_shown());
843 EXPECT_FALSE(func
->scope_ui_shown());
846 IN_PROC_BROWSER_TEST_F(GetAuthTokenFunctionTest
,
847 NonInteractiveMintServiceError
) {
848 SignIn("primary@example.com");
849 scoped_refptr
<FakeGetAuthTokenFunction
> func(new FakeGetAuthTokenFunction());
850 func
->set_extension(CreateExtension(CLIENT_ID
| SCOPES
));
851 func
->set_mint_token_result(
852 TestOAuth2MintTokenFlow::MINT_TOKEN_SERVICE_ERROR
);
854 utils::RunFunctionAndReturnError(func
.get(), "[{}]", browser());
855 EXPECT_TRUE(StartsWithASCII(error
, errors::kAuthFailure
, false));
856 EXPECT_FALSE(func
->login_ui_shown());
857 EXPECT_FALSE(func
->scope_ui_shown());
860 IN_PROC_BROWSER_TEST_F(GetAuthTokenFunctionTest
,
862 SignIn("primary@example.com");
863 #if defined(OS_WIN) && defined(USE_ASH)
864 // Disable this test in Metro+Ash for now (http://crbug.com/262796).
865 if (base::CommandLine::ForCurrentProcess()->HasSwitch(
866 switches::kAshBrowserTests
))
870 scoped_refptr
<FakeGetAuthTokenFunction
> func(new FakeGetAuthTokenFunction());
871 scoped_refptr
<const Extension
> extension(CreateExtension(CLIENT_ID
| SCOPES
));
872 func
->set_extension(extension
.get());
873 func
->set_mint_token_result(TestOAuth2MintTokenFlow::MINT_TOKEN_SUCCESS
);
874 scoped_ptr
<base::Value
> value(
875 utils::RunFunctionAndReturnSingleResult(func
.get(), "[]", browser()));
876 std::string access_token
;
877 EXPECT_TRUE(value
->GetAsString(&access_token
));
878 EXPECT_EQ(std::string(kAccessToken
), access_token
);
879 EXPECT_FALSE(func
->login_ui_shown());
880 EXPECT_FALSE(func
->scope_ui_shown());
881 EXPECT_EQ(IdentityTokenCacheValue::CACHE_STATUS_TOKEN
,
882 GetCachedToken(std::string()).status());
885 IN_PROC_BROWSER_TEST_F(GetAuthTokenFunctionTest
,
886 NonInteractiveSuccess
) {
887 SignIn("primary@example.com");
888 #if defined(OS_WIN) && defined(USE_ASH)
889 // Disable this test in Metro+Ash for now (http://crbug.com/262796).
890 if (base::CommandLine::ForCurrentProcess()->HasSwitch(
891 switches::kAshBrowserTests
))
895 scoped_refptr
<FakeGetAuthTokenFunction
> func(new FakeGetAuthTokenFunction());
896 scoped_refptr
<const Extension
> extension(CreateExtension(CLIENT_ID
| SCOPES
));
897 func
->set_extension(extension
.get());
898 func
->set_mint_token_result(TestOAuth2MintTokenFlow::MINT_TOKEN_SUCCESS
);
899 scoped_ptr
<base::Value
> value(utils::RunFunctionAndReturnSingleResult(
900 func
.get(), "[{}]", browser()));
901 std::string access_token
;
902 EXPECT_TRUE(value
->GetAsString(&access_token
));
903 EXPECT_EQ(std::string(kAccessToken
), access_token
);
904 EXPECT_FALSE(func
->login_ui_shown());
905 EXPECT_FALSE(func
->scope_ui_shown());
906 EXPECT_EQ(IdentityTokenCacheValue::CACHE_STATUS_TOKEN
,
907 GetCachedToken(std::string()).status());
910 IN_PROC_BROWSER_TEST_F(GetAuthTokenFunctionTest
,
911 InteractiveLoginCanceled
) {
912 scoped_refptr
<FakeGetAuthTokenFunction
> func(new FakeGetAuthTokenFunction());
913 func
->set_extension(CreateExtension(CLIENT_ID
| SCOPES
));
914 func
->set_login_ui_result(false);
915 std::string error
= utils::RunFunctionAndReturnError(
916 func
.get(), "[{\"interactive\": true}]", browser());
917 EXPECT_EQ(std::string(errors::kUserNotSignedIn
), error
);
918 EXPECT_TRUE(func
->login_ui_shown());
919 EXPECT_FALSE(func
->scope_ui_shown());
922 IN_PROC_BROWSER_TEST_F(GetAuthTokenFunctionTest
,
923 InteractiveMintBadCredentialsLoginCanceled
) {
924 SignIn("primary@example.com");
925 scoped_refptr
<FakeGetAuthTokenFunction
> func(new FakeGetAuthTokenFunction());
926 func
->set_extension(CreateExtension(CLIENT_ID
| SCOPES
));
927 func
->set_mint_token_result(
928 TestOAuth2MintTokenFlow::MINT_TOKEN_BAD_CREDENTIALS
);
929 func
->set_login_ui_result(false);
930 std::string error
= utils::RunFunctionAndReturnError(
931 func
.get(), "[{\"interactive\": true}]", browser());
932 EXPECT_EQ(std::string(errors::kUserNotSignedIn
), error
);
933 EXPECT_TRUE(func
->login_ui_shown());
934 EXPECT_FALSE(func
->scope_ui_shown());
937 IN_PROC_BROWSER_TEST_F(GetAuthTokenFunctionTest
,
938 InteractiveLoginSuccessNoToken
) {
939 scoped_refptr
<FakeGetAuthTokenFunction
> func(new FakeGetAuthTokenFunction());
940 func
->set_extension(CreateExtension(CLIENT_ID
| SCOPES
));
941 func
->set_login_ui_result(false);
942 std::string error
= utils::RunFunctionAndReturnError(
943 func
.get(), "[{\"interactive\": true}]", browser());
944 EXPECT_EQ(std::string(errors::kUserNotSignedIn
), error
);
945 EXPECT_TRUE(func
->login_ui_shown());
946 EXPECT_FALSE(func
->scope_ui_shown());
949 IN_PROC_BROWSER_TEST_F(GetAuthTokenFunctionTest
,
950 InteractiveLoginSuccessMintFailure
) {
951 scoped_refptr
<FakeGetAuthTokenFunction
> func(new FakeGetAuthTokenFunction());
952 func
->set_extension(CreateExtension(CLIENT_ID
| SCOPES
));
953 func
->set_login_ui_result(true);
954 func
->set_mint_token_result(TestOAuth2MintTokenFlow::MINT_TOKEN_FAILURE
);
955 std::string error
= utils::RunFunctionAndReturnError(
956 func
.get(), "[{\"interactive\": true}]", browser());
957 EXPECT_TRUE(StartsWithASCII(error
, errors::kAuthFailure
, false));
958 EXPECT_TRUE(func
->login_ui_shown());
959 EXPECT_FALSE(func
->scope_ui_shown());
962 IN_PROC_BROWSER_TEST_F(GetAuthTokenFunctionTest
,
963 InteractiveLoginSuccessLoginAccessTokenFailure
) {
964 scoped_refptr
<FakeGetAuthTokenFunction
> func(new FakeGetAuthTokenFunction());
965 func
->set_extension(CreateExtension(CLIENT_ID
| SCOPES
));
966 func
->set_login_ui_result(true);
967 func
->set_login_access_token_result(false);
968 std::string error
= utils::RunFunctionAndReturnError(
969 func
.get(), "[{\"interactive\": true}]", browser());
970 EXPECT_TRUE(StartsWithASCII(error
, errors::kAuthFailure
, false));
971 EXPECT_TRUE(func
->login_ui_shown());
972 EXPECT_FALSE(func
->scope_ui_shown());
975 IN_PROC_BROWSER_TEST_F(GetAuthTokenFunctionTest
,
976 InteractiveLoginSuccessMintSuccess
) {
977 // TODO(courage): verify that account_id in token service requests
978 // is correct once manual token minting for tests is implemented.
979 scoped_refptr
<FakeGetAuthTokenFunction
> func(new FakeGetAuthTokenFunction());
980 func
->set_extension(CreateExtension(CLIENT_ID
| SCOPES
));
981 func
->set_login_ui_result(true);
982 func
->set_mint_token_result(TestOAuth2MintTokenFlow::MINT_TOKEN_SUCCESS
);
983 scoped_ptr
<base::Value
> value(utils::RunFunctionAndReturnSingleResult(
984 func
.get(), "[{\"interactive\": true}]", browser()));
985 std::string access_token
;
986 EXPECT_TRUE(value
->GetAsString(&access_token
));
987 EXPECT_EQ(std::string(kAccessToken
), access_token
);
988 EXPECT_TRUE(func
->login_ui_shown());
989 EXPECT_FALSE(func
->scope_ui_shown());
992 IN_PROC_BROWSER_TEST_F(GetAuthTokenFunctionTest
,
993 InteractiveLoginSuccessApprovalAborted
) {
994 scoped_refptr
<FakeGetAuthTokenFunction
> func(new FakeGetAuthTokenFunction());
995 func
->set_extension(CreateExtension(CLIENT_ID
| SCOPES
));
996 func
->set_login_ui_result(true);
997 func
->set_mint_token_result(TestOAuth2MintTokenFlow::ISSUE_ADVICE_SUCCESS
);
998 func
->set_scope_ui_failure(GaiaWebAuthFlow::WINDOW_CLOSED
);
999 std::string error
= utils::RunFunctionAndReturnError(
1000 func
.get(), "[{\"interactive\": true}]", browser());
1001 EXPECT_EQ(std::string(errors::kUserRejected
), error
);
1002 EXPECT_TRUE(func
->login_ui_shown());
1003 EXPECT_TRUE(func
->scope_ui_shown());
1006 IN_PROC_BROWSER_TEST_F(GetAuthTokenFunctionTest
,
1007 InteractiveLoginSuccessApprovalSuccess
) {
1008 scoped_refptr
<const Extension
> extension(CreateExtension(CLIENT_ID
| SCOPES
));
1009 scoped_refptr
<FakeGetAuthTokenFunction
> func(new FakeGetAuthTokenFunction());
1010 func
->set_extension(extension
.get());
1011 func
->set_login_ui_result(true);
1012 func
->set_mint_token_result(TestOAuth2MintTokenFlow::ISSUE_ADVICE_SUCCESS
);
1014 scoped_ptr
<base::Value
> value(utils::RunFunctionAndReturnSingleResult(
1015 func
.get(), "[{\"interactive\": true}]", browser()));
1016 std::string access_token
;
1017 EXPECT_TRUE(value
->GetAsString(&access_token
));
1018 EXPECT_EQ(std::string(kAccessToken
), access_token
);
1019 EXPECT_TRUE(func
->login_ui_shown());
1020 EXPECT_TRUE(func
->scope_ui_shown());
1023 IN_PROC_BROWSER_TEST_F(GetAuthTokenFunctionTest
,
1024 InteractiveApprovalAborted
) {
1025 SignIn("primary@example.com");
1026 scoped_refptr
<FakeGetAuthTokenFunction
> func(new FakeGetAuthTokenFunction());
1027 func
->set_extension(CreateExtension(CLIENT_ID
| SCOPES
));
1028 func
->set_mint_token_result(TestOAuth2MintTokenFlow::ISSUE_ADVICE_SUCCESS
);
1029 func
->set_scope_ui_failure(GaiaWebAuthFlow::WINDOW_CLOSED
);
1030 std::string error
= utils::RunFunctionAndReturnError(
1031 func
.get(), "[{\"interactive\": true}]", browser());
1032 EXPECT_EQ(std::string(errors::kUserRejected
), error
);
1033 EXPECT_FALSE(func
->login_ui_shown());
1034 EXPECT_TRUE(func
->scope_ui_shown());
1037 IN_PROC_BROWSER_TEST_F(GetAuthTokenFunctionTest
,
1038 InteractiveApprovalLoadFailed
) {
1039 SignIn("primary@example.com");
1040 scoped_refptr
<FakeGetAuthTokenFunction
> func(new FakeGetAuthTokenFunction());
1041 func
->set_extension(CreateExtension(CLIENT_ID
| SCOPES
));
1042 func
->set_mint_token_result(TestOAuth2MintTokenFlow::ISSUE_ADVICE_SUCCESS
);
1043 func
->set_scope_ui_failure(GaiaWebAuthFlow::LOAD_FAILED
);
1044 std::string error
= utils::RunFunctionAndReturnError(
1045 func
.get(), "[{\"interactive\": true}]", browser());
1046 EXPECT_EQ(std::string(errors::kPageLoadFailure
), error
);
1047 EXPECT_FALSE(func
->login_ui_shown());
1048 EXPECT_TRUE(func
->scope_ui_shown());
1051 IN_PROC_BROWSER_TEST_F(GetAuthTokenFunctionTest
,
1052 InteractiveApprovalInvalidRedirect
) {
1053 SignIn("primary@example.com");
1054 scoped_refptr
<FakeGetAuthTokenFunction
> func(new FakeGetAuthTokenFunction());
1055 func
->set_extension(CreateExtension(CLIENT_ID
| SCOPES
));
1056 func
->set_mint_token_result(TestOAuth2MintTokenFlow::ISSUE_ADVICE_SUCCESS
);
1057 func
->set_scope_ui_failure(GaiaWebAuthFlow::INVALID_REDIRECT
);
1058 std::string error
= utils::RunFunctionAndReturnError(
1059 func
.get(), "[{\"interactive\": true}]", browser());
1060 EXPECT_EQ(std::string(errors::kInvalidRedirect
), error
);
1061 EXPECT_FALSE(func
->login_ui_shown());
1062 EXPECT_TRUE(func
->scope_ui_shown());
1065 IN_PROC_BROWSER_TEST_F(GetAuthTokenFunctionTest
,
1066 InteractiveApprovalConnectionFailure
) {
1067 SignIn("primary@example.com");
1068 scoped_refptr
<FakeGetAuthTokenFunction
> func(new FakeGetAuthTokenFunction());
1069 func
->set_extension(CreateExtension(CLIENT_ID
| SCOPES
));
1070 func
->set_mint_token_result(TestOAuth2MintTokenFlow::ISSUE_ADVICE_SUCCESS
);
1071 func
->set_scope_ui_failure(GaiaWebAuthFlow::SERVICE_AUTH_ERROR
);
1072 std::string error
= utils::RunFunctionAndReturnError(
1073 func
.get(), "[{\"interactive\": true}]", browser());
1074 EXPECT_TRUE(StartsWithASCII(error
, errors::kAuthFailure
, false));
1075 EXPECT_FALSE(func
->login_ui_shown());
1076 EXPECT_TRUE(func
->scope_ui_shown());
1079 IN_PROC_BROWSER_TEST_F(GetAuthTokenFunctionTest
,
1080 InteractiveApprovalOAuthErrors
) {
1081 SignIn("primary@example.com");
1082 scoped_refptr
<const Extension
> extension(CreateExtension(CLIENT_ID
| SCOPES
));
1084 std::map
<std::string
, std::string
> error_map
;
1085 error_map
.insert(std::make_pair("access_denied", errors::kUserRejected
));
1086 error_map
.insert(std::make_pair("invalid_scope", errors::kInvalidScopes
));
1087 error_map
.insert(std::make_pair(
1088 "unmapped_error", std::string(errors::kAuthFailure
) + "unmapped_error"));
1090 for (std::map
<std::string
, std::string
>::const_iterator
1091 it
= error_map
.begin();
1092 it
!= error_map
.end();
1094 scoped_refptr
<FakeGetAuthTokenFunction
> func(
1095 new FakeGetAuthTokenFunction());
1096 func
->set_extension(extension
.get());
1097 // Make sure we don't get a cached issue_advice result, which would cause
1098 // flow to be leaked.
1099 id_api()->EraseAllCachedTokens();
1100 func
->set_mint_token_result(TestOAuth2MintTokenFlow::ISSUE_ADVICE_SUCCESS
);
1101 func
->set_scope_ui_oauth_error(it
->first
);
1102 std::string error
= utils::RunFunctionAndReturnError(
1103 func
.get(), "[{\"interactive\": true}]", browser());
1104 EXPECT_EQ(it
->second
, error
);
1105 EXPECT_FALSE(func
->login_ui_shown());
1106 EXPECT_TRUE(func
->scope_ui_shown());
1110 IN_PROC_BROWSER_TEST_F(GetAuthTokenFunctionTest
,
1111 InteractiveApprovalSuccess
) {
1112 SignIn("primary@example.com");
1113 scoped_refptr
<const Extension
> extension(CreateExtension(CLIENT_ID
| SCOPES
));
1114 scoped_refptr
<FakeGetAuthTokenFunction
> func(new FakeGetAuthTokenFunction());
1115 func
->set_extension(extension
.get());
1116 func
->set_mint_token_result(TestOAuth2MintTokenFlow::ISSUE_ADVICE_SUCCESS
);
1118 scoped_ptr
<base::Value
> value(utils::RunFunctionAndReturnSingleResult(
1119 func
.get(), "[{\"interactive\": true}]", browser()));
1120 std::string access_token
;
1121 EXPECT_TRUE(value
->GetAsString(&access_token
));
1122 EXPECT_EQ(std::string(kAccessToken
), access_token
);
1123 EXPECT_FALSE(func
->login_ui_shown());
1124 EXPECT_TRUE(func
->scope_ui_shown());
1126 EXPECT_EQ(IdentityTokenCacheValue::CACHE_STATUS_TOKEN
,
1127 GetCachedToken(std::string()).status());
1130 IN_PROC_BROWSER_TEST_F(GetAuthTokenFunctionTest
, NoninteractiveQueue
) {
1131 SignIn("primary@example.com");
1132 scoped_refptr
<const Extension
> extension(CreateExtension(CLIENT_ID
| SCOPES
));
1133 scoped_refptr
<FakeGetAuthTokenFunction
> func(new FakeGetAuthTokenFunction());
1134 func
->set_extension(extension
.get());
1136 // Create a fake request to block the queue.
1137 MockQueuedMintRequest queued_request
;
1138 IdentityMintRequestQueue::MintType type
=
1139 IdentityMintRequestQueue::MINT_TYPE_NONINTERACTIVE
;
1141 EXPECT_CALL(queued_request
, StartMintToken(type
)).Times(1);
1142 QueueRequestStart(type
, &queued_request
);
1144 // The real request will start processing, but wait in the queue behind
1146 RunFunctionAsync(func
.get(), "[{}]");
1147 // Verify that we have fetched the login token at this point.
1148 testing::Mock::VerifyAndClearExpectations(func
.get());
1150 // The flow will be created after the first queued request clears.
1151 func
->set_mint_token_result(TestOAuth2MintTokenFlow::MINT_TOKEN_SUCCESS
);
1153 QueueRequestComplete(type
, &queued_request
);
1155 scoped_ptr
<base::Value
> value(WaitForSingleResult(func
.get()));
1156 std::string access_token
;
1157 EXPECT_TRUE(value
->GetAsString(&access_token
));
1158 EXPECT_EQ(std::string(kAccessToken
), access_token
);
1159 EXPECT_FALSE(func
->login_ui_shown());
1160 EXPECT_FALSE(func
->scope_ui_shown());
1163 IN_PROC_BROWSER_TEST_F(GetAuthTokenFunctionTest
, InteractiveQueue
) {
1164 SignIn("primary@example.com");
1165 scoped_refptr
<const Extension
> extension(CreateExtension(CLIENT_ID
| SCOPES
));
1166 scoped_refptr
<FakeGetAuthTokenFunction
> func(new FakeGetAuthTokenFunction());
1167 func
->set_extension(extension
.get());
1169 // Create a fake request to block the queue.
1170 MockQueuedMintRequest queued_request
;
1171 IdentityMintRequestQueue::MintType type
=
1172 IdentityMintRequestQueue::MINT_TYPE_INTERACTIVE
;
1174 EXPECT_CALL(queued_request
, StartMintToken(type
)).Times(1);
1175 QueueRequestStart(type
, &queued_request
);
1177 // The real request will start processing, but wait in the queue behind
1179 func
->set_mint_token_result(TestOAuth2MintTokenFlow::ISSUE_ADVICE_SUCCESS
);
1180 RunFunctionAsync(func
.get(), "[{\"interactive\": true}]");
1181 // Verify that we have fetched the login token and run the first flow.
1182 testing::Mock::VerifyAndClearExpectations(func
.get());
1183 EXPECT_FALSE(func
->scope_ui_shown());
1185 // The UI will be displayed and a token retrieved after the first
1186 // queued request clears.
1187 QueueRequestComplete(type
, &queued_request
);
1189 scoped_ptr
<base::Value
> value(WaitForSingleResult(func
.get()));
1190 std::string access_token
;
1191 EXPECT_TRUE(value
->GetAsString(&access_token
));
1192 EXPECT_EQ(std::string(kAccessToken
), access_token
);
1193 EXPECT_FALSE(func
->login_ui_shown());
1194 EXPECT_TRUE(func
->scope_ui_shown());
1197 IN_PROC_BROWSER_TEST_F(GetAuthTokenFunctionTest
, InteractiveQueueShutdown
) {
1198 SignIn("primary@example.com");
1199 scoped_refptr
<const Extension
> extension(CreateExtension(CLIENT_ID
| SCOPES
));
1200 scoped_refptr
<FakeGetAuthTokenFunction
> func(new FakeGetAuthTokenFunction());
1201 func
->set_extension(extension
.get());
1203 // Create a fake request to block the queue.
1204 MockQueuedMintRequest queued_request
;
1205 IdentityMintRequestQueue::MintType type
=
1206 IdentityMintRequestQueue::MINT_TYPE_INTERACTIVE
;
1208 EXPECT_CALL(queued_request
, StartMintToken(type
)).Times(1);
1209 QueueRequestStart(type
, &queued_request
);
1211 // The real request will start processing, but wait in the queue behind
1213 func
->set_mint_token_result(TestOAuth2MintTokenFlow::ISSUE_ADVICE_SUCCESS
);
1214 RunFunctionAsync(func
.get(), "[{\"interactive\": true}]");
1215 // Verify that we have fetched the login token and run the first flow.
1216 testing::Mock::VerifyAndClearExpectations(func
.get());
1217 EXPECT_FALSE(func
->scope_ui_shown());
1219 // After the request is canceled, the function will complete.
1221 EXPECT_EQ(std::string(errors::kCanceled
), WaitForError(func
.get()));
1222 EXPECT_FALSE(func
->login_ui_shown());
1223 EXPECT_FALSE(func
->scope_ui_shown());
1225 QueueRequestComplete(type
, &queued_request
);
1228 IN_PROC_BROWSER_TEST_F(GetAuthTokenFunctionTest
, NoninteractiveShutdown
) {
1229 SignIn("primary@example.com");
1230 scoped_refptr
<const Extension
> extension(CreateExtension(CLIENT_ID
| SCOPES
));
1231 scoped_refptr
<FakeGetAuthTokenFunction
> func(new FakeGetAuthTokenFunction());
1232 func
->set_extension(extension
.get());
1234 func
->set_mint_token_flow(make_scoped_ptr(new TestHangOAuth2MintTokenFlow()));
1235 RunFunctionAsync(func
.get(), "[{\"interactive\": false}]");
1237 // After the request is canceled, the function will complete.
1239 EXPECT_EQ(std::string(errors::kCanceled
), WaitForError(func
.get()));
1242 IN_PROC_BROWSER_TEST_F(GetAuthTokenFunctionTest
,
1243 InteractiveQueuedNoninteractiveFails
) {
1244 SignIn("primary@example.com");
1245 scoped_refptr
<const Extension
> extension(CreateExtension(CLIENT_ID
| SCOPES
));
1246 scoped_refptr
<FakeGetAuthTokenFunction
> func(new FakeGetAuthTokenFunction());
1247 func
->set_extension(extension
.get());
1249 // Create a fake request to block the interactive queue.
1250 MockQueuedMintRequest queued_request
;
1251 IdentityMintRequestQueue::MintType type
=
1252 IdentityMintRequestQueue::MINT_TYPE_INTERACTIVE
;
1254 EXPECT_CALL(queued_request
, StartMintToken(type
)).Times(1);
1255 QueueRequestStart(type
, &queued_request
);
1257 // Non-interactive requests fail without hitting GAIA, because a
1258 // consent UI is known to be up.
1259 std::string error
= utils::RunFunctionAndReturnError(
1260 func
.get(), "[{}]", browser());
1261 EXPECT_EQ(std::string(errors::kNoGrant
), error
);
1262 EXPECT_FALSE(func
->login_ui_shown());
1263 EXPECT_FALSE(func
->scope_ui_shown());
1265 QueueRequestComplete(type
, &queued_request
);
1268 IN_PROC_BROWSER_TEST_F(GetAuthTokenFunctionTest
,
1269 NonInteractiveCacheHit
) {
1270 SignIn("primary@example.com");
1271 scoped_refptr
<const Extension
> extension(CreateExtension(CLIENT_ID
| SCOPES
));
1272 scoped_refptr
<FakeGetAuthTokenFunction
> func(new FakeGetAuthTokenFunction());
1273 func
->set_extension(extension
.get());
1275 // pre-populate the cache with a token
1276 IdentityTokenCacheValue
token(kAccessToken
,
1277 base::TimeDelta::FromSeconds(3600));
1278 SetCachedToken(token
);
1280 // Get a token. Should not require a GAIA request.
1281 scoped_ptr
<base::Value
> value(utils::RunFunctionAndReturnSingleResult(
1282 func
.get(), "[{}]", browser()));
1283 std::string access_token
;
1284 EXPECT_TRUE(value
->GetAsString(&access_token
));
1285 EXPECT_EQ(std::string(kAccessToken
), access_token
);
1286 EXPECT_FALSE(func
->login_ui_shown());
1287 EXPECT_FALSE(func
->scope_ui_shown());
1290 IN_PROC_BROWSER_TEST_F(GetAuthTokenFunctionTest
,
1291 NonInteractiveIssueAdviceCacheHit
) {
1292 SignIn("primary@example.com");
1293 scoped_refptr
<const Extension
> extension(CreateExtension(CLIENT_ID
| SCOPES
));
1294 scoped_refptr
<FakeGetAuthTokenFunction
> func(new FakeGetAuthTokenFunction());
1295 func
->set_extension(extension
.get());
1297 // pre-populate the cache with advice
1298 IssueAdviceInfo info
;
1299 IdentityTokenCacheValue
token(info
);
1300 SetCachedToken(token
);
1302 // Should return an error without a GAIA request.
1303 std::string error
= utils::RunFunctionAndReturnError(
1304 func
.get(), "[{}]", browser());
1305 EXPECT_EQ(std::string(errors::kNoGrant
), error
);
1306 EXPECT_FALSE(func
->login_ui_shown());
1307 EXPECT_FALSE(func
->scope_ui_shown());
1310 IN_PROC_BROWSER_TEST_F(GetAuthTokenFunctionTest
,
1311 InteractiveCacheHit
) {
1312 SignIn("primary@example.com");
1313 scoped_refptr
<const Extension
> extension(CreateExtension(CLIENT_ID
| SCOPES
));
1314 scoped_refptr
<FakeGetAuthTokenFunction
> func(new FakeGetAuthTokenFunction());
1315 func
->set_extension(extension
.get());
1317 // Create a fake request to block the queue.
1318 MockQueuedMintRequest queued_request
;
1319 IdentityMintRequestQueue::MintType type
=
1320 IdentityMintRequestQueue::MINT_TYPE_INTERACTIVE
;
1322 EXPECT_CALL(queued_request
, StartMintToken(type
)).Times(1);
1323 QueueRequestStart(type
, &queued_request
);
1325 // The real request will start processing, but wait in the queue behind
1327 func
->set_mint_token_result(TestOAuth2MintTokenFlow::ISSUE_ADVICE_SUCCESS
);
1328 RunFunctionAsync(func
.get(), "[{\"interactive\": true}]");
1330 // Populate the cache with a token while the request is blocked.
1331 IdentityTokenCacheValue
token(kAccessToken
,
1332 base::TimeDelta::FromSeconds(3600));
1333 SetCachedToken(token
);
1335 // When we wake up the request, it returns the cached token without
1336 // displaying a UI, or hitting GAIA.
1338 QueueRequestComplete(type
, &queued_request
);
1340 scoped_ptr
<base::Value
> value(WaitForSingleResult(func
.get()));
1341 std::string access_token
;
1342 EXPECT_TRUE(value
->GetAsString(&access_token
));
1343 EXPECT_EQ(std::string(kAccessToken
), access_token
);
1344 EXPECT_FALSE(func
->login_ui_shown());
1345 EXPECT_FALSE(func
->scope_ui_shown());
1348 IN_PROC_BROWSER_TEST_F(GetAuthTokenFunctionTest
,
1349 LoginInvalidatesTokenCache
) {
1350 scoped_refptr
<FakeGetAuthTokenFunction
> func(new FakeGetAuthTokenFunction());
1351 scoped_refptr
<const Extension
> extension(CreateExtension(CLIENT_ID
| SCOPES
));
1352 func
->set_extension(extension
.get());
1354 // pre-populate the cache with a token
1355 IdentityTokenCacheValue
token(kAccessToken
,
1356 base::TimeDelta::FromSeconds(3600));
1357 SetCachedToken(token
);
1359 // Because the user is not signed in, the token will be removed,
1360 // and we'll hit GAIA for new tokens.
1361 func
->set_login_ui_result(true);
1362 func
->set_mint_token_result(TestOAuth2MintTokenFlow::ISSUE_ADVICE_SUCCESS
);
1364 scoped_ptr
<base::Value
> value(utils::RunFunctionAndReturnSingleResult(
1365 func
.get(), "[{\"interactive\": true}]", browser()));
1366 std::string access_token
;
1367 EXPECT_TRUE(value
->GetAsString(&access_token
));
1368 EXPECT_EQ(std::string(kAccessToken
), access_token
);
1369 EXPECT_TRUE(func
->login_ui_shown());
1370 EXPECT_TRUE(func
->scope_ui_shown());
1371 EXPECT_EQ(IdentityTokenCacheValue::CACHE_STATUS_TOKEN
,
1372 GetCachedToken(std::string()).status());
1375 IN_PROC_BROWSER_TEST_F(GetAuthTokenFunctionTest
, ComponentWithChromeClientId
) {
1376 scoped_refptr
<FakeGetAuthTokenFunction
> func(new FakeGetAuthTokenFunction());
1377 scoped_refptr
<const Extension
> extension(
1378 CreateExtension(SCOPES
| AS_COMPONENT
));
1379 func
->set_extension(extension
.get());
1380 const OAuth2Info
& oauth2_info
= OAuth2Info::GetOAuth2Info(extension
.get());
1381 EXPECT_TRUE(oauth2_info
.client_id
.empty());
1382 EXPECT_FALSE(func
->GetOAuth2ClientId().empty());
1383 EXPECT_NE("client1", func
->GetOAuth2ClientId());
1386 IN_PROC_BROWSER_TEST_F(GetAuthTokenFunctionTest
, ComponentWithNormalClientId
) {
1387 scoped_refptr
<FakeGetAuthTokenFunction
> func(new FakeGetAuthTokenFunction());
1388 scoped_refptr
<const Extension
> extension(
1389 CreateExtension(CLIENT_ID
| SCOPES
| AS_COMPONENT
));
1390 func
->set_extension(extension
.get());
1391 EXPECT_EQ("client1", func
->GetOAuth2ClientId());
1394 IN_PROC_BROWSER_TEST_F(GetAuthTokenFunctionTest
, MultiDefaultUser
) {
1395 SignIn("primary@example.com");
1396 SetAccountState(CreateIds("primary@example.com", "1"), true);
1397 SetAccountState(CreateIds("secondary@example.com", "2"), true);
1399 scoped_refptr
<FakeGetAuthTokenFunction
> func(new FakeGetAuthTokenFunction());
1400 scoped_refptr
<const Extension
> extension(CreateExtension(CLIENT_ID
| SCOPES
));
1401 func
->set_extension(extension
.get());
1402 func
->set_auto_login_access_token(false);
1403 func
->set_mint_token_result(TestOAuth2MintTokenFlow::MINT_TOKEN_SUCCESS
);
1405 RunFunctionAsync(func
.get(), "[{}]");
1407 IssueLoginAccessTokenForAccount("primary@example.com");
1409 scoped_ptr
<base::Value
> value(WaitForSingleResult(func
.get()));
1410 std::string access_token
;
1411 EXPECT_TRUE(value
->GetAsString(&access_token
));
1412 EXPECT_EQ(std::string(kAccessToken
), access_token
);
1413 EXPECT_EQ(IdentityTokenCacheValue::CACHE_STATUS_TOKEN
,
1414 GetCachedToken(std::string()).status());
1415 EXPECT_EQ("access_token-primary@example.com", func
->login_access_token());
1418 IN_PROC_BROWSER_TEST_F(GetAuthTokenFunctionTest
, MultiPrimaryUser
) {
1419 SignIn("primary@example.com");
1420 IssueLoginRefreshTokenForAccount("secondary@example.com");
1421 SetAccountState(CreateIds("primary@example.com", "1"), true);
1422 SetAccountState(CreateIds("secondary@example.com", "2"), true);
1424 scoped_refptr
<FakeGetAuthTokenFunction
> func(new FakeGetAuthTokenFunction());
1425 scoped_refptr
<const Extension
> extension(CreateExtension(CLIENT_ID
| SCOPES
));
1426 func
->set_extension(extension
.get());
1427 func
->set_auto_login_access_token(false);
1428 func
->set_mint_token_result(TestOAuth2MintTokenFlow::MINT_TOKEN_SUCCESS
);
1430 RunFunctionAsync(func
.get(), "[{\"account\": { \"id\": \"1\" } }]");
1432 IssueLoginAccessTokenForAccount("primary@example.com");
1434 scoped_ptr
<base::Value
> value(WaitForSingleResult(func
.get()));
1435 std::string access_token
;
1436 EXPECT_TRUE(value
->GetAsString(&access_token
));
1437 EXPECT_EQ(std::string(kAccessToken
), access_token
);
1438 EXPECT_EQ(IdentityTokenCacheValue::CACHE_STATUS_TOKEN
,
1439 GetCachedToken(std::string()).status());
1440 EXPECT_EQ("access_token-primary@example.com", func
->login_access_token());
1443 IN_PROC_BROWSER_TEST_F(GetAuthTokenFunctionTest
, MultiSecondaryUser
) {
1444 SignIn("primary@example.com");
1445 IssueLoginRefreshTokenForAccount("secondary@example.com");
1446 SetAccountState(CreateIds("primary@example.com", "1"), true);
1447 SetAccountState(CreateIds("secondary@example.com", "2"), true);
1449 scoped_refptr
<FakeGetAuthTokenFunction
> func(new FakeGetAuthTokenFunction());
1450 scoped_refptr
<const Extension
> extension(CreateExtension(CLIENT_ID
| SCOPES
));
1451 func
->set_extension(extension
.get());
1452 func
->set_auto_login_access_token(false);
1453 func
->set_mint_token_result(TestOAuth2MintTokenFlow::MINT_TOKEN_SUCCESS
);
1455 RunFunctionAsync(func
.get(), "[{\"account\": { \"id\": \"2\" } }]");
1457 IssueLoginAccessTokenForAccount("secondary@example.com");
1459 scoped_ptr
<base::Value
> value(WaitForSingleResult(func
.get()));
1460 std::string access_token
;
1461 EXPECT_TRUE(value
->GetAsString(&access_token
));
1462 EXPECT_EQ(std::string(kAccessToken
), access_token
);
1463 EXPECT_EQ(IdentityTokenCacheValue::CACHE_STATUS_TOKEN
,
1464 GetCachedToken("secondary@example.com").status());
1465 EXPECT_EQ("access_token-secondary@example.com", func
->login_access_token());
1468 IN_PROC_BROWSER_TEST_F(GetAuthTokenFunctionTest
, MultiUnknownUser
) {
1469 SignIn("primary@example.com");
1470 IssueLoginRefreshTokenForAccount("secondary@example.com");
1471 SetAccountState(CreateIds("primary@example.com", "1"), true);
1472 SetAccountState(CreateIds("secondary@example.com", "2"), true);
1474 scoped_refptr
<FakeGetAuthTokenFunction
> func(new FakeGetAuthTokenFunction());
1475 scoped_refptr
<const Extension
> extension(CreateExtension(CLIENT_ID
| SCOPES
));
1476 func
->set_extension(extension
.get());
1477 func
->set_auto_login_access_token(false);
1479 std::string error
= utils::RunFunctionAndReturnError(
1480 func
.get(), "[{\"account\": { \"id\": \"3\" } }]", browser());
1481 EXPECT_EQ(std::string(errors::kUserNotSignedIn
), error
);
1484 IN_PROC_BROWSER_TEST_F(GetAuthTokenFunctionTest
,
1485 MultiSecondaryNonInteractiveMintFailure
) {
1486 SignIn("primary@example.com");
1487 IssueLoginRefreshTokenForAccount("secondary@example.com");
1488 SetAccountState(CreateIds("primary@example.com", "1"), true);
1489 SetAccountState(CreateIds("secondary@example.com", "2"), true);
1491 scoped_refptr
<FakeGetAuthTokenFunction
> func(new FakeGetAuthTokenFunction());
1492 func
->set_extension(CreateExtension(CLIENT_ID
| SCOPES
));
1493 func
->set_mint_token_result(TestOAuth2MintTokenFlow::MINT_TOKEN_FAILURE
);
1494 std::string error
= utils::RunFunctionAndReturnError(
1495 func
.get(), "[{\"account\": { \"id\": \"2\" } }]", browser());
1496 EXPECT_TRUE(StartsWithASCII(error
, errors::kAuthFailure
, false));
1497 EXPECT_FALSE(func
->login_ui_shown());
1498 EXPECT_FALSE(func
->scope_ui_shown());
1501 IN_PROC_BROWSER_TEST_F(GetAuthTokenFunctionTest
,
1502 MultiSecondaryNonInteractiveLoginAccessTokenFailure
) {
1503 SignIn("primary@example.com");
1504 IssueLoginRefreshTokenForAccount("secondary@example.com");
1505 SetAccountState(CreateIds("primary@example.com", "1"), true);
1506 SetAccountState(CreateIds("secondary@example.com", "2"), true);
1508 scoped_refptr
<FakeGetAuthTokenFunction
> func(new FakeGetAuthTokenFunction());
1509 func
->set_extension(CreateExtension(CLIENT_ID
| SCOPES
));
1510 func
->set_login_access_token_result(false);
1511 std::string error
= utils::RunFunctionAndReturnError(
1512 func
.get(), "[{\"account\": { \"id\": \"2\" } }]", browser());
1513 EXPECT_TRUE(StartsWithASCII(error
, errors::kAuthFailure
, false));
1516 IN_PROC_BROWSER_TEST_F(GetAuthTokenFunctionTest
,
1517 MultiSecondaryInteractiveApprovalAborted
) {
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_mint_token_result(TestOAuth2MintTokenFlow::ISSUE_ADVICE_SUCCESS
);
1526 func
->set_scope_ui_failure(GaiaWebAuthFlow::WINDOW_CLOSED
);
1527 std::string error
= utils::RunFunctionAndReturnError(
1529 "[{\"account\": { \"id\": \"2\" }, \"interactive\": true}]",
1531 EXPECT_EQ(std::string(errors::kUserRejected
), error
);
1532 EXPECT_FALSE(func
->login_ui_shown());
1533 EXPECT_TRUE(func
->scope_ui_shown());
1536 IN_PROC_BROWSER_TEST_F(GetAuthTokenFunctionTest
, ScopesDefault
) {
1537 SignIn("primary@example.com");
1538 scoped_refptr
<FakeGetAuthTokenFunction
> func(new FakeGetAuthTokenFunction());
1539 scoped_refptr
<const Extension
> extension(CreateExtension(CLIENT_ID
| SCOPES
));
1540 func
->set_extension(extension
.get());
1541 func
->set_mint_token_result(TestOAuth2MintTokenFlow::MINT_TOKEN_SUCCESS
);
1542 scoped_ptr
<base::Value
> value(
1543 utils::RunFunctionAndReturnSingleResult(func
.get(), "[{}]", browser()));
1544 std::string access_token
;
1545 EXPECT_TRUE(value
->GetAsString(&access_token
));
1546 EXPECT_EQ(std::string(kAccessToken
), access_token
);
1548 const ExtensionTokenKey
* token_key
= func
->GetExtensionTokenKeyForTest();
1549 EXPECT_EQ(2ul, token_key
->scopes
.size());
1550 EXPECT_TRUE(ContainsKey(token_key
->scopes
, "scope1"));
1551 EXPECT_TRUE(ContainsKey(token_key
->scopes
, "scope2"));
1554 IN_PROC_BROWSER_TEST_F(GetAuthTokenFunctionTest
, ScopesEmpty
) {
1555 scoped_refptr
<FakeGetAuthTokenFunction
> func(new FakeGetAuthTokenFunction());
1556 scoped_refptr
<const Extension
> extension(CreateExtension(CLIENT_ID
| SCOPES
));
1557 func
->set_extension(extension
.get());
1559 std::string
error(utils::RunFunctionAndReturnError(
1560 func
.get(), "[{\"scopes\": []}]", browser()));
1562 EXPECT_EQ(errors::kInvalidScopes
, error
);
1565 IN_PROC_BROWSER_TEST_F(GetAuthTokenFunctionTest
, ScopesEmail
) {
1566 SignIn("primary@example.com");
1567 scoped_refptr
<FakeGetAuthTokenFunction
> func(new FakeGetAuthTokenFunction());
1568 scoped_refptr
<const Extension
> extension(CreateExtension(CLIENT_ID
| SCOPES
));
1569 func
->set_extension(extension
.get());
1570 func
->set_mint_token_result(TestOAuth2MintTokenFlow::MINT_TOKEN_SUCCESS
);
1571 scoped_ptr
<base::Value
> value(utils::RunFunctionAndReturnSingleResult(
1572 func
.get(), "[{\"scopes\": [\"email\"]}]", browser()));
1573 std::string access_token
;
1574 EXPECT_TRUE(value
->GetAsString(&access_token
));
1575 EXPECT_EQ(std::string(kAccessToken
), access_token
);
1577 const ExtensionTokenKey
* token_key
= func
->GetExtensionTokenKeyForTest();
1578 EXPECT_EQ(1ul, token_key
->scopes
.size());
1579 EXPECT_TRUE(ContainsKey(token_key
->scopes
, "email"));
1582 IN_PROC_BROWSER_TEST_F(GetAuthTokenFunctionTest
, ScopesEmailFooBar
) {
1583 SignIn("primary@example.com");
1584 scoped_refptr
<FakeGetAuthTokenFunction
> func(new FakeGetAuthTokenFunction());
1585 scoped_refptr
<const Extension
> extension(CreateExtension(CLIENT_ID
| SCOPES
));
1586 func
->set_extension(extension
.get());
1587 func
->set_mint_token_result(TestOAuth2MintTokenFlow::MINT_TOKEN_SUCCESS
);
1588 scoped_ptr
<base::Value
> value(utils::RunFunctionAndReturnSingleResult(
1589 func
.get(), "[{\"scopes\": [\"email\", \"foo\", \"bar\"]}]", browser()));
1590 std::string access_token
;
1591 EXPECT_TRUE(value
->GetAsString(&access_token
));
1592 EXPECT_EQ(std::string(kAccessToken
), access_token
);
1594 const ExtensionTokenKey
* token_key
= func
->GetExtensionTokenKeyForTest();
1595 EXPECT_EQ(3ul, token_key
->scopes
.size());
1596 EXPECT_TRUE(ContainsKey(token_key
->scopes
, "email"));
1597 EXPECT_TRUE(ContainsKey(token_key
->scopes
, "foo"));
1598 EXPECT_TRUE(ContainsKey(token_key
->scopes
, "bar"));
1601 class RemoveCachedAuthTokenFunctionTest
: public ExtensionBrowserTest
{
1603 bool InvalidateDefaultToken() {
1604 scoped_refptr
<IdentityRemoveCachedAuthTokenFunction
> func(
1605 new IdentityRemoveCachedAuthTokenFunction
);
1606 func
->set_extension(test_util::CreateEmptyExtension(kExtensionId
).get());
1607 return utils::RunFunction(
1609 std::string("[{\"token\": \"") + kAccessToken
+ "\"}]",
1611 extension_function_test_utils::NONE
);
1614 IdentityAPI
* id_api() {
1615 return IdentityAPI::GetFactoryInstance()->Get(browser()->profile());
1618 void SetCachedToken(IdentityTokenCacheValue
& token_data
) {
1619 ExtensionTokenKey
key(
1620 kExtensionId
, "test@example.com", std::set
<std::string
>());
1621 id_api()->SetCachedToken(key
, token_data
);
1624 const IdentityTokenCacheValue
& GetCachedToken() {
1625 return id_api()->GetCachedToken(ExtensionTokenKey(
1626 kExtensionId
, "test@example.com", std::set
<std::string
>()));
1630 IN_PROC_BROWSER_TEST_F(RemoveCachedAuthTokenFunctionTest
, NotFound
) {
1631 EXPECT_TRUE(InvalidateDefaultToken());
1632 EXPECT_EQ(IdentityTokenCacheValue::CACHE_STATUS_NOTFOUND
,
1633 GetCachedToken().status());
1636 IN_PROC_BROWSER_TEST_F(RemoveCachedAuthTokenFunctionTest
, Advice
) {
1637 IssueAdviceInfo info
;
1638 IdentityTokenCacheValue
advice(info
);
1639 SetCachedToken(advice
);
1640 EXPECT_TRUE(InvalidateDefaultToken());
1641 EXPECT_EQ(IdentityTokenCacheValue::CACHE_STATUS_ADVICE
,
1642 GetCachedToken().status());
1645 IN_PROC_BROWSER_TEST_F(RemoveCachedAuthTokenFunctionTest
, NonMatchingToken
) {
1646 IdentityTokenCacheValue
token("non_matching_token",
1647 base::TimeDelta::FromSeconds(3600));
1648 SetCachedToken(token
);
1649 EXPECT_TRUE(InvalidateDefaultToken());
1650 EXPECT_EQ(IdentityTokenCacheValue::CACHE_STATUS_TOKEN
,
1651 GetCachedToken().status());
1652 EXPECT_EQ("non_matching_token", GetCachedToken().token());
1655 IN_PROC_BROWSER_TEST_F(RemoveCachedAuthTokenFunctionTest
, MatchingToken
) {
1656 IdentityTokenCacheValue
token(kAccessToken
,
1657 base::TimeDelta::FromSeconds(3600));
1658 SetCachedToken(token
);
1659 EXPECT_EQ(IdentityTokenCacheValue::CACHE_STATUS_TOKEN
,
1660 GetCachedToken().status());
1661 EXPECT_TRUE(InvalidateDefaultToken());
1662 EXPECT_EQ(IdentityTokenCacheValue::CACHE_STATUS_NOTFOUND
,
1663 GetCachedToken().status());
1666 class LaunchWebAuthFlowFunctionTest
: public AsyncExtensionBrowserTest
{
1668 void SetUpCommandLine(base::CommandLine
* command_line
) override
{
1669 AsyncExtensionBrowserTest::SetUpCommandLine(command_line
);
1670 // Reduce performance test variance by disabling background networking.
1671 command_line
->AppendSwitch(switches::kDisableBackgroundNetworking
);
1675 IN_PROC_BROWSER_TEST_F(LaunchWebAuthFlowFunctionTest
, UserCloseWindow
) {
1676 net::SpawnedTestServer
https_server(
1677 net::SpawnedTestServer::TYPE_HTTPS
,
1678 net::SpawnedTestServer::kLocalhost
,
1679 base::FilePath(FILE_PATH_LITERAL(
1680 "chrome/test/data/extensions/api_test/identity")));
1681 ASSERT_TRUE(https_server
.Start());
1682 GURL
auth_url(https_server
.GetURL("files/interaction_required.html"));
1684 scoped_refptr
<IdentityLaunchWebAuthFlowFunction
> function(
1685 new IdentityLaunchWebAuthFlowFunction());
1686 scoped_refptr
<Extension
> empty_extension(test_util::CreateEmptyExtension());
1687 function
->set_extension(empty_extension
.get());
1689 WaitForGURLAndCloseWindow
popup_observer(auth_url
);
1691 std::string args
= "[{\"interactive\": true, \"url\": \"" +
1692 auth_url
.spec() + "\"}]";
1693 RunFunctionAsync(function
.get(), args
);
1695 popup_observer
.Wait();
1696 popup_observer
.CloseEmbedderWebContents();
1698 EXPECT_EQ(std::string(errors::kUserRejected
), WaitForError(function
.get()));
1701 IN_PROC_BROWSER_TEST_F(LaunchWebAuthFlowFunctionTest
, InteractionRequired
) {
1702 net::SpawnedTestServer
https_server(
1703 net::SpawnedTestServer::TYPE_HTTPS
,
1704 net::SpawnedTestServer::kLocalhost
,
1705 base::FilePath(FILE_PATH_LITERAL(
1706 "chrome/test/data/extensions/api_test/identity")));
1707 ASSERT_TRUE(https_server
.Start());
1708 GURL
auth_url(https_server
.GetURL("files/interaction_required.html"));
1710 scoped_refptr
<IdentityLaunchWebAuthFlowFunction
> function(
1711 new IdentityLaunchWebAuthFlowFunction());
1712 scoped_refptr
<Extension
> empty_extension(test_util::CreateEmptyExtension());
1713 function
->set_extension(empty_extension
.get());
1715 std::string args
= "[{\"interactive\": false, \"url\": \"" +
1716 auth_url
.spec() + "\"}]";
1718 utils::RunFunctionAndReturnError(function
.get(), args
, browser());
1720 EXPECT_EQ(std::string(errors::kInteractionRequired
), error
);
1723 IN_PROC_BROWSER_TEST_F(LaunchWebAuthFlowFunctionTest
, LoadFailed
) {
1724 net::SpawnedTestServer
https_server(
1725 net::SpawnedTestServer::TYPE_HTTPS
,
1726 net::SpawnedTestServer::kLocalhost
,
1727 base::FilePath(FILE_PATH_LITERAL(
1728 "chrome/test/data/extensions/api_test/identity")));
1729 ASSERT_TRUE(https_server
.Start());
1730 GURL
auth_url(https_server
.GetURL("files/five_hundred.html"));
1732 scoped_refptr
<IdentityLaunchWebAuthFlowFunction
> function(
1733 new IdentityLaunchWebAuthFlowFunction());
1734 scoped_refptr
<Extension
> empty_extension(test_util::CreateEmptyExtension());
1735 function
->set_extension(empty_extension
.get());
1737 std::string args
= "[{\"interactive\": true, \"url\": \"" +
1738 auth_url
.spec() + "\"}]";
1740 utils::RunFunctionAndReturnError(function
.get(), args
, browser());
1742 EXPECT_EQ(std::string(errors::kPageLoadFailure
), error
);
1745 IN_PROC_BROWSER_TEST_F(LaunchWebAuthFlowFunctionTest
, NonInteractiveSuccess
) {
1746 #if defined(OS_WIN) && defined(USE_ASH)
1747 // Disable this test in Metro+Ash for now (http://crbug.com/262796).
1748 if (base::CommandLine::ForCurrentProcess()->HasSwitch(
1749 switches::kAshBrowserTests
))
1753 scoped_refptr
<IdentityLaunchWebAuthFlowFunction
> function(
1754 new IdentityLaunchWebAuthFlowFunction());
1755 scoped_refptr
<Extension
> empty_extension(test_util::CreateEmptyExtension());
1756 function
->set_extension(empty_extension
.get());
1758 function
->InitFinalRedirectURLPrefixForTest("abcdefghij");
1759 scoped_ptr
<base::Value
> value(utils::RunFunctionAndReturnSingleResult(
1761 "[{\"interactive\": false,"
1762 "\"url\": \"https://abcdefghij.chromiumapp.org/callback#test\"}]",
1766 EXPECT_TRUE(value
->GetAsString(&url
));
1767 EXPECT_EQ(std::string("https://abcdefghij.chromiumapp.org/callback#test"),
1771 IN_PROC_BROWSER_TEST_F(
1772 LaunchWebAuthFlowFunctionTest
, InteractiveFirstNavigationSuccess
) {
1773 #if defined(OS_WIN) && defined(USE_ASH)
1774 // Disable this test in Metro+Ash for now (http://crbug.com/262796).
1775 if (base::CommandLine::ForCurrentProcess()->HasSwitch(
1776 switches::kAshBrowserTests
))
1780 scoped_refptr
<IdentityLaunchWebAuthFlowFunction
> function(
1781 new IdentityLaunchWebAuthFlowFunction());
1782 scoped_refptr
<Extension
> empty_extension(test_util::CreateEmptyExtension());
1783 function
->set_extension(empty_extension
.get());
1785 function
->InitFinalRedirectURLPrefixForTest("abcdefghij");
1786 scoped_ptr
<base::Value
> value(utils::RunFunctionAndReturnSingleResult(
1788 "[{\"interactive\": true,"
1789 "\"url\": \"https://abcdefghij.chromiumapp.org/callback#test\"}]",
1793 EXPECT_TRUE(value
->GetAsString(&url
));
1794 EXPECT_EQ(std::string("https://abcdefghij.chromiumapp.org/callback#test"),
1798 IN_PROC_BROWSER_TEST_F(LaunchWebAuthFlowFunctionTest
,
1799 DISABLED_InteractiveSecondNavigationSuccess
) {
1800 net::SpawnedTestServer
https_server(
1801 net::SpawnedTestServer::TYPE_HTTPS
,
1802 net::SpawnedTestServer::kLocalhost
,
1803 base::FilePath(FILE_PATH_LITERAL(
1804 "chrome/test/data/extensions/api_test/identity")));
1805 ASSERT_TRUE(https_server
.Start());
1806 GURL
auth_url(https_server
.GetURL("files/redirect_to_chromiumapp.html"));
1808 scoped_refptr
<IdentityLaunchWebAuthFlowFunction
> function(
1809 new IdentityLaunchWebAuthFlowFunction());
1810 scoped_refptr
<Extension
> empty_extension(test_util::CreateEmptyExtension());
1811 function
->set_extension(empty_extension
.get());
1813 function
->InitFinalRedirectURLPrefixForTest("abcdefghij");
1814 std::string args
= "[{\"interactive\": true, \"url\": \"" +
1815 auth_url
.spec() + "\"}]";
1816 scoped_ptr
<base::Value
> value(
1817 utils::RunFunctionAndReturnSingleResult(function
.get(), args
, browser()));
1820 EXPECT_TRUE(value
->GetAsString(&url
));
1821 EXPECT_EQ(std::string("https://abcdefghij.chromiumapp.org/callback#test"),
1825 } // namespace extensions
1827 // Tests the chrome.identity API implemented by custom JS bindings .
1828 IN_PROC_BROWSER_TEST_F(ExtensionApiTest
, ChromeIdentityJsBindings
) {
1829 ASSERT_TRUE(RunExtensionTest("identity/js_bindings")) << message_
;