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.
4
5 #include <set>
6 #include <string>
7 #include <vector>
8
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/guest_view/guest_view_base.h"
22 #include "chrome/browser/profiles/profile.h"
23 #include "chrome/browser/signin/fake_profile_oauth2_token_service.h"
24 #include "chrome/browser/signin/fake_profile_oauth2_token_service_builder.h"
25 #include "chrome/browser/signin/fake_signin_manager.h"
26 #include "chrome/browser/signin/profile_oauth2_token_service_factory.h"
27 #include "chrome/browser/signin/signin_manager_factory.h"
28 #include "chrome/browser/ui/browser.h"
29 #include "chrome/browser/ui/browser_window.h"
30 #include "chrome/common/chrome_switches.h"
31 #include "chrome/common/extensions/api/identity.h"
32 #include "chrome/common/extensions/api/identity/oauth2_manifest_handler.h"
33 #include "chrome/test/base/in_process_browser_test.h"
34 #include "chrome/test/base/test_switches.h"
35 #include "components/signin/core/browser/signin_manager.h"
36 #include "components/signin/core/common/profile_management_switches.h"
37 #include "components/signin/core/common/signin_pref_names.h"
38 #include "content/public/browser/notification_service.h"
39 #include "content/public/browser/notification_source.h"
40 #include "content/public/test/test_utils.h"
41 #include "extensions/common/id_util.h"
42 #include "google_apis/gaia/google_service_auth_error.h"
43 #include "google_apis/gaia/oauth2_mint_token_flow.h"
44 #include "grit/browser_resources.h"
45 #include "net/test/spawned_test_server/spawned_test_server.h"
46 #include "testing/gmock/include/gmock/gmock.h"
47 #include "testing/gtest/include/gtest/gtest.h"
48 #include "url/gurl.h"
49
50 using testing::_;
51 using testing::Return;
52 using testing::ReturnRef;
53
54 namespace extensions {
55
56 namespace {
57
58 namespace errors = identity_constants;
59 namespace utils = extension_function_test_utils;
60
61 static const char kAccessToken[] = "auth_token";
62 static const char kExtensionId[] = "ext_id";
63
64 // This helps us be able to wait until an UIThreadExtensionFunction calls
65 // SendResponse.
66 class SendResponseDelegate
67 : public UIThreadExtensionFunction::DelegateForTests {
68 public:
SendResponseDelegate()69 SendResponseDelegate() : should_post_quit_(false) {}
70
~SendResponseDelegate()71 virtual ~SendResponseDelegate() {}
72
set_should_post_quit(bool should_quit)73 void set_should_post_quit(bool should_quit) {
74 should_post_quit_ = should_quit;
75 }
76
HasResponse()77 bool HasResponse() {
78 return response_.get() != NULL;
79 }
80
GetResponse()81 bool GetResponse() {
82 EXPECT_TRUE(HasResponse());
83 return *response_.get();
84 }
85
OnSendResponse(UIThreadExtensionFunction * function,bool success,bool bad_message)86 virtual void OnSendResponse(UIThreadExtensionFunction* function,
87 bool success,
88 bool bad_message) OVERRIDE {
89 ASSERT_FALSE(bad_message);
90 ASSERT_FALSE(HasResponse());
91 response_.reset(new bool);
92 *response_ = success;
93 if (should_post_quit_) {
94 base::MessageLoopForUI::current()->Quit();
95 }
96 }
97
98 private:
99 scoped_ptr<bool> response_;
100 bool should_post_quit_;
101 };
102
103 class AsyncExtensionBrowserTest : public ExtensionBrowserTest {
104 protected:
105 // Asynchronous function runner allows tests to manipulate the browser window
106 // after the call happens.
RunFunctionAsync(UIThreadExtensionFunction * function,const std::string & args)107 void RunFunctionAsync(
108 UIThreadExtensionFunction* function,
109 const std::string& args) {
110 response_delegate_.reset(new SendResponseDelegate);
111 function->set_test_delegate(response_delegate_.get());
112 scoped_ptr<base::ListValue> parsed_args(utils::ParseList(args));
113 EXPECT_TRUE(parsed_args.get()) <<
114 "Could not parse extension function arguments: " << args;
115 function->SetArgs(parsed_args.get());
116
117 if (!function->GetExtension()) {
118 scoped_refptr<Extension> empty_extension(
119 utils::CreateEmptyExtension());
120 function->set_extension(empty_extension.get());
121 }
122
123 function->set_browser_context(browser()->profile());
124 function->set_has_callback(true);
125 function->Run()->Execute();
126 }
127
WaitForError(UIThreadExtensionFunction * function)128 std::string WaitForError(UIThreadExtensionFunction* function) {
129 RunMessageLoopUntilResponse();
130 EXPECT_FALSE(function->GetResultList()) << "Did not expect a result";
131 return function->GetError();
132 }
133
WaitForSingleResult(UIThreadExtensionFunction * function)134 base::Value* WaitForSingleResult(UIThreadExtensionFunction* function) {
135 RunMessageLoopUntilResponse();
136 EXPECT_TRUE(function->GetError().empty()) << "Unexpected error: "
137 << function->GetError();
138 const base::Value* single_result = NULL;
139 if (function->GetResultList() != NULL &&
140 function->GetResultList()->Get(0, &single_result)) {
141 return single_result->DeepCopy();
142 }
143 return NULL;
144 }
145
146 private:
RunMessageLoopUntilResponse()147 void RunMessageLoopUntilResponse() {
148 // If the RunAsync of |function| didn't already call SendResponse, run the
149 // message loop until they do.
150 if (!response_delegate_->HasResponse()) {
151 response_delegate_->set_should_post_quit(true);
152 content::RunMessageLoop();
153 }
154 EXPECT_TRUE(response_delegate_->HasResponse());
155 }
156
157 scoped_ptr<SendResponseDelegate> response_delegate_;
158 };
159
160 class TestHangOAuth2MintTokenFlow : public OAuth2MintTokenFlow {
161 public:
TestHangOAuth2MintTokenFlow()162 TestHangOAuth2MintTokenFlow()
163 : OAuth2MintTokenFlow(NULL, NULL, OAuth2MintTokenFlow::Parameters()) {}
164
Start()165 virtual void Start() OVERRIDE {
166 // Do nothing, simulating a hanging network call.
167 }
168 };
169
170 class TestOAuth2MintTokenFlow : public OAuth2MintTokenFlow {
171 public:
172 enum ResultType {
173 ISSUE_ADVICE_SUCCESS,
174 MINT_TOKEN_SUCCESS,
175 MINT_TOKEN_FAILURE,
176 MINT_TOKEN_BAD_CREDENTIALS,
177 MINT_TOKEN_SERVICE_ERROR
178 };
179
TestOAuth2MintTokenFlow(ResultType result,OAuth2MintTokenFlow::Delegate * delegate)180 TestOAuth2MintTokenFlow(ResultType result,
181 OAuth2MintTokenFlow::Delegate* delegate)
182 : OAuth2MintTokenFlow(NULL, delegate, OAuth2MintTokenFlow::Parameters()),
183 result_(result),
184 delegate_(delegate) {
185 }
186
Start()187 virtual void Start() OVERRIDE {
188 switch (result_) {
189 case ISSUE_ADVICE_SUCCESS: {
190 IssueAdviceInfo info;
191 delegate_->OnIssueAdviceSuccess(info);
192 break;
193 }
194 case MINT_TOKEN_SUCCESS: {
195 delegate_->OnMintTokenSuccess(kAccessToken, 3600);
196 break;
197 }
198 case MINT_TOKEN_FAILURE: {
199 GoogleServiceAuthError error(GoogleServiceAuthError::CONNECTION_FAILED);
200 delegate_->OnMintTokenFailure(error);
201 break;
202 }
203 case MINT_TOKEN_BAD_CREDENTIALS: {
204 GoogleServiceAuthError error(
205 GoogleServiceAuthError::INVALID_GAIA_CREDENTIALS);
206 delegate_->OnMintTokenFailure(error);
207 break;
208 }
209 case MINT_TOKEN_SERVICE_ERROR: {
210 GoogleServiceAuthError error =
211 GoogleServiceAuthError::FromServiceError("invalid_scope");
212 delegate_->OnMintTokenFailure(error);
213 break;
214 }
215 }
216 }
217
218 private:
219 ResultType result_;
220 OAuth2MintTokenFlow::Delegate* delegate_;
221 };
222
223 // Waits for a specific GURL to generate a NOTIFICATION_LOAD_STOP event and
224 // saves a pointer to the window embedding the WebContents, which can be later
225 // closed.
226 class WaitForGURLAndCloseWindow : public content::WindowedNotificationObserver {
227 public:
WaitForGURLAndCloseWindow(GURL url)228 explicit WaitForGURLAndCloseWindow(GURL url)
229 : WindowedNotificationObserver(
230 content::NOTIFICATION_LOAD_STOP,
231 content::NotificationService::AllSources()),
232 url_(url) {}
233
234 // NotificationObserver:
Observe(int type,const content::NotificationSource & source,const content::NotificationDetails & details)235 virtual void Observe(int type,
236 const content::NotificationSource& source,
237 const content::NotificationDetails& details) OVERRIDE {
238 content::NavigationController* web_auth_flow_controller =
239 content::Source<content::NavigationController>(source).ptr();
240 content::WebContents* web_contents =
241 web_auth_flow_controller->GetWebContents();
242
243 if (web_contents->GetURL() == url_) {
244 // It is safe to keep the pointer here, because we know in a test, that
245 // the WebContents won't go away before CloseEmbedderWebContents is
246 // called. Don't copy this code to production.
247 GuestViewBase* guest = GuestViewBase::FromWebContents(web_contents);
248 embedder_web_contents_ = guest->embedder_web_contents();
249 // Condtionally invoke parent class so that Wait will not exit
250 // until the target URL arrives.
251 content::WindowedNotificationObserver::Observe(type, source, details);
252 }
253 }
254
255 // Closes the window embedding the WebContents. The action is separated from
256 // the Observe method to make sure the list of observers is not deleted,
257 // while some event is already being processed. (That causes ASAN failures.)
CloseEmbedderWebContents()258 void CloseEmbedderWebContents() {
259 if (embedder_web_contents_)
260 embedder_web_contents_->Close();
261 }
262
263 private:
264 GURL url_;
265 content::WebContents* embedder_web_contents_;
266 };
267
268 } // namespace
269
270 class MockGetAuthTokenFunction : public IdentityGetAuthTokenFunction {
271 public:
MockGetAuthTokenFunction()272 MockGetAuthTokenFunction() : login_access_token_result_(true),
273 login_ui_result_(true),
274 scope_ui_result_(true),
275 login_ui_shown_(false),
276 scope_ui_shown_(false) {
277 }
278
set_login_access_token_result(bool result)279 void set_login_access_token_result(bool result) {
280 login_access_token_result_ = result;
281 }
282
set_login_ui_result(bool result)283 void set_login_ui_result(bool result) {
284 login_ui_result_ = result;
285 }
286
set_scope_ui_failure(GaiaWebAuthFlow::Failure failure)287 void set_scope_ui_failure(GaiaWebAuthFlow::Failure failure) {
288 scope_ui_result_ = false;
289 scope_ui_failure_ = failure;
290 }
291
set_scope_ui_oauth_error(const std::string & oauth_error)292 void set_scope_ui_oauth_error(const std::string& oauth_error) {
293 scope_ui_result_ = false;
294 scope_ui_failure_ = GaiaWebAuthFlow::OAUTH_ERROR;
295 scope_ui_oauth_error_ = oauth_error;
296 }
297
login_ui_shown() const298 bool login_ui_shown() const {
299 return login_ui_shown_;
300 }
301
scope_ui_shown() const302 bool scope_ui_shown() const {
303 return scope_ui_shown_;
304 }
305
extension_token_key()306 const ExtensionTokenKey* extension_token_key() { return token_key_.get(); }
307
StartLoginAccessTokenRequest()308 virtual void StartLoginAccessTokenRequest() OVERRIDE {
309 if (login_access_token_result_) {
310 OnGetTokenSuccess(login_token_request_.get(), "access_token",
311 base::Time::Now() + base::TimeDelta::FromHours(1LL));
312 } else {
313 GoogleServiceAuthError error(
314 GoogleServiceAuthError::INVALID_GAIA_CREDENTIALS);
315 OnGetTokenFailure(login_token_request_.get(), error);
316 }
317 }
318
ShowLoginPopup()319 virtual void ShowLoginPopup() OVERRIDE {
320 EXPECT_FALSE(login_ui_shown_);
321 login_ui_shown_ = true;
322 if (login_ui_result_)
323 SigninSuccess();
324 else
325 SigninFailed();
326 }
327
ShowOAuthApprovalDialog(const IssueAdviceInfo & issue_advice)328 virtual void ShowOAuthApprovalDialog(
329 const IssueAdviceInfo& issue_advice) OVERRIDE {
330 scope_ui_shown_ = true;
331
332 if (scope_ui_result_) {
333 OnGaiaFlowCompleted(kAccessToken, "3600");
334 } else if (scope_ui_failure_ == GaiaWebAuthFlow::SERVICE_AUTH_ERROR) {
335 GoogleServiceAuthError error(GoogleServiceAuthError::CONNECTION_FAILED);
336 OnGaiaFlowFailure(scope_ui_failure_, error, "");
337 } else {
338 GoogleServiceAuthError error(GoogleServiceAuthError::NONE);
339 OnGaiaFlowFailure(scope_ui_failure_, error, scope_ui_oauth_error_);
340 }
341 }
342
343 MOCK_CONST_METHOD0(HasLoginToken, bool());
344 MOCK_METHOD1(CreateMintTokenFlow,
345 OAuth2MintTokenFlow* (const std::string& login_access_token));
346
347 private:
~MockGetAuthTokenFunction()348 ~MockGetAuthTokenFunction() {}
349 bool login_access_token_result_;
350 bool login_ui_result_;
351 bool scope_ui_result_;
352 GaiaWebAuthFlow::Failure scope_ui_failure_;
353 std::string scope_ui_oauth_error_;
354 bool login_ui_shown_;
355 bool scope_ui_shown_;
356 };
357
358 // TODO(courage): Replace MockGetAuthTokenFunction with
359 // FakeGetAuthTokenFunction in all tests.
360
361 class FakeGetAuthTokenFunction : public IdentityGetAuthTokenFunction {
362 public:
FakeGetAuthTokenFunction()363 FakeGetAuthTokenFunction()
364 : login_access_token_result_(true),
365 login_ui_result_(true),
366 scope_ui_result_(true),
367 login_ui_shown_(false),
368 scope_ui_shown_(false) {}
369
set_login_access_token_result(bool result)370 void set_login_access_token_result(bool result) {
371 login_access_token_result_ = result;
372 }
373
set_login_ui_result(bool result)374 void set_login_ui_result(bool result) { login_ui_result_ = result; }
375
set_mint_token_flow(scoped_ptr<OAuth2MintTokenFlow> flow)376 void set_mint_token_flow(scoped_ptr<OAuth2MintTokenFlow> flow) {
377 flow_ = flow.Pass();
378 }
379
set_scope_ui_failure(GaiaWebAuthFlow::Failure failure)380 void set_scope_ui_failure(GaiaWebAuthFlow::Failure failure) {
381 scope_ui_result_ = false;
382 scope_ui_failure_ = failure;
383 }
384
set_scope_ui_oauth_error(const std::string & oauth_error)385 void set_scope_ui_oauth_error(const std::string& oauth_error) {
386 scope_ui_result_ = false;
387 scope_ui_failure_ = GaiaWebAuthFlow::OAUTH_ERROR;
388 scope_ui_oauth_error_ = oauth_error;
389 }
390
login_ui_shown() const391 bool login_ui_shown() const { return login_ui_shown_; }
392
scope_ui_shown() const393 bool scope_ui_shown() const { return scope_ui_shown_; }
394
login_access_token() const395 std::string login_access_token() const { return login_access_token_; }
396
ShowLoginPopup()397 virtual void ShowLoginPopup() OVERRIDE {
398 EXPECT_FALSE(login_ui_shown_);
399 login_ui_shown_ = true;
400 if (login_ui_result_)
401 SigninSuccess();
402 else
403 SigninFailed();
404 }
405
ShowOAuthApprovalDialog(const IssueAdviceInfo & issue_advice)406 virtual void ShowOAuthApprovalDialog(
407 const IssueAdviceInfo& issue_advice) OVERRIDE {
408 scope_ui_shown_ = true;
409
410 if (scope_ui_result_) {
411 OnGaiaFlowCompleted(kAccessToken, "3600");
412 } else if (scope_ui_failure_ == GaiaWebAuthFlow::SERVICE_AUTH_ERROR) {
413 GoogleServiceAuthError error(GoogleServiceAuthError::CONNECTION_FAILED);
414 OnGaiaFlowFailure(scope_ui_failure_, error, "");
415 } else {
416 GoogleServiceAuthError error(GoogleServiceAuthError::NONE);
417 OnGaiaFlowFailure(scope_ui_failure_, error, scope_ui_oauth_error_);
418 }
419 }
420
CreateMintTokenFlow(const std::string & login_access_token)421 virtual OAuth2MintTokenFlow* CreateMintTokenFlow(
422 const std::string& login_access_token) OVERRIDE {
423 EXPECT_TRUE(login_access_token_.empty());
424 login_access_token_ = login_access_token;
425 return flow_.release();
426 }
427
428 private:
~FakeGetAuthTokenFunction()429 virtual ~FakeGetAuthTokenFunction() {}
430 bool login_access_token_result_;
431 bool login_ui_result_;
432 bool scope_ui_result_;
433 GaiaWebAuthFlow::Failure scope_ui_failure_;
434 std::string scope_ui_oauth_error_;
435 bool login_ui_shown_;
436 bool scope_ui_shown_;
437
438 scoped_ptr<OAuth2MintTokenFlow> flow_;
439
440 std::string login_access_token_;
441 };
442
443 class MockQueuedMintRequest : public IdentityMintRequestQueue::Request {
444 public:
445 MOCK_METHOD1(StartMintToken, void(IdentityMintRequestQueue::MintType));
446 };
447
CreateIds(std::string email,std::string obfid)448 AccountIds CreateIds(std::string email, std::string obfid) {
449 AccountIds ids;
450 ids.account_key = email;
451 ids.email = email;
452 ids.gaia = obfid;
453 return ids;
454 }
455
456 class IdentityGetAccountsFunctionTest : public ExtensionBrowserTest {
SetUpCommandLine(CommandLine * command_line)457 virtual void SetUpCommandLine(CommandLine* command_line) OVERRIDE {
458 ExtensionBrowserTest::SetUpCommandLine(command_line);
459 command_line->AppendSwitch(switches::kExtensionsMultiAccount);
460 }
461
462 protected:
SetAccountState(AccountIds ids,bool is_signed_in)463 void SetAccountState(AccountIds ids, bool is_signed_in) {
464 IdentityAPI::GetFactoryInstance()->Get(profile())->SetAccountStateForTest(
465 ids, is_signed_in);
466 }
467
ExpectGetAccounts(const std::vector<std::string> & accounts)468 testing::AssertionResult ExpectGetAccounts(
469 const std::vector<std::string>& accounts) {
470 scoped_refptr<IdentityGetAccountsFunction> func(
471 new IdentityGetAccountsFunction);
472 func->set_extension(utils::CreateEmptyExtension(kExtensionId).get());
473 if (!utils::RunFunction(
474 func.get(), std::string("[]"), browser(), utils::NONE)) {
475 return GenerateFailureResult(accounts, NULL)
476 << "getAccounts did not return a result.";
477 }
478 const base::ListValue* callback_arguments = func->GetResultList();
479 if (!callback_arguments)
480 return GenerateFailureResult(accounts, NULL) << "NULL result";
481
482 if (callback_arguments->GetSize() != 1) {
483 return GenerateFailureResult(accounts, NULL)
484 << "Expected 1 argument but got " << callback_arguments->GetSize();
485 }
486
487 const base::ListValue* results;
488 if (!callback_arguments->GetList(0, &results))
489 GenerateFailureResult(accounts, NULL) << "Result was not an array";
490
491 std::set<std::string> result_ids;
492 for (base::ListValue::const_iterator it = results->begin();
493 it != results->end();
494 ++it) {
495 scoped_ptr<api::identity::AccountInfo> info =
496 api::identity::AccountInfo::FromValue(**it);
497 if (info.get())
498 result_ids.insert(info->id);
499 else
500 return GenerateFailureResult(accounts, results);
501 }
502
503 for (std::vector<std::string>::const_iterator it = accounts.begin();
504 it != accounts.end();
505 ++it) {
506 if (result_ids.find(*it) == result_ids.end())
507 return GenerateFailureResult(accounts, results);
508 }
509
510 return testing::AssertionResult(true);
511 }
512
GenerateFailureResult(const::std::vector<std::string> & accounts,const base::ListValue * results)513 testing::AssertionResult GenerateFailureResult(
514 const ::std::vector<std::string>& accounts,
515 const base::ListValue* results) {
516 testing::Message msg("Expected: ");
517 for (std::vector<std::string>::const_iterator it = accounts.begin();
518 it != accounts.end();
519 ++it) {
520 msg << *it << " ";
521 }
522 msg << "Actual: ";
523 if (!results) {
524 msg << "NULL";
525 } else {
526 for (base::ListValue::const_iterator it = results->begin();
527 it != results->end();
528 ++it) {
529 scoped_ptr<api::identity::AccountInfo> info =
530 api::identity::AccountInfo::FromValue(**it);
531 if (info.get())
532 msg << info->id << " ";
533 else
534 msg << *it << "<-" << (*it)->GetType() << " ";
535 }
536 }
537
538 return testing::AssertionFailure(msg);
539 }
540 };
541
IN_PROC_BROWSER_TEST_F(IdentityGetAccountsFunctionTest,MultiAccountOn)542 IN_PROC_BROWSER_TEST_F(IdentityGetAccountsFunctionTest, MultiAccountOn) {
543 EXPECT_TRUE(switches::IsExtensionsMultiAccount());
544 }
545
IN_PROC_BROWSER_TEST_F(IdentityGetAccountsFunctionTest,NoneSignedIn)546 IN_PROC_BROWSER_TEST_F(IdentityGetAccountsFunctionTest, NoneSignedIn) {
547 EXPECT_TRUE(ExpectGetAccounts(std::vector<std::string>()));
548 }
549
IN_PROC_BROWSER_TEST_F(IdentityGetAccountsFunctionTest,PrimaryAccountSignedIn)550 IN_PROC_BROWSER_TEST_F(IdentityGetAccountsFunctionTest,
551 PrimaryAccountSignedIn) {
552 SetAccountState(CreateIds("primary@example.com", "1"), true);
553 std::vector<std::string> primary;
554 primary.push_back("1");
555 EXPECT_TRUE(ExpectGetAccounts(primary));
556 }
557
IN_PROC_BROWSER_TEST_F(IdentityGetAccountsFunctionTest,TwoAccountsSignedIn)558 IN_PROC_BROWSER_TEST_F(IdentityGetAccountsFunctionTest, TwoAccountsSignedIn) {
559 SetAccountState(CreateIds("primary@example.com", "1"), true);
560 SetAccountState(CreateIds("secondary@example.com", "2"), true);
561 std::vector<std::string> two_accounts;
562 two_accounts.push_back("1");
563 two_accounts.push_back("2");
564 EXPECT_TRUE(ExpectGetAccounts(two_accounts));
565 }
566
567 class IdentityOldProfilesGetAccountsFunctionTest
568 : public IdentityGetAccountsFunctionTest {
SetUpCommandLine(CommandLine * command_line)569 virtual void SetUpCommandLine(CommandLine* command_line) OVERRIDE {
570 // Don't add the multi-account switch that parent class would have.
571 }
572 };
573
IN_PROC_BROWSER_TEST_F(IdentityOldProfilesGetAccountsFunctionTest,MultiAccountOff)574 IN_PROC_BROWSER_TEST_F(IdentityOldProfilesGetAccountsFunctionTest,
575 MultiAccountOff) {
576 EXPECT_FALSE(switches::IsExtensionsMultiAccount());
577 }
578
IN_PROC_BROWSER_TEST_F(IdentityOldProfilesGetAccountsFunctionTest,TwoAccountsSignedIn)579 IN_PROC_BROWSER_TEST_F(IdentityOldProfilesGetAccountsFunctionTest,
580 TwoAccountsSignedIn) {
581 SetAccountState(CreateIds("primary@example.com", "1"), true);
582 SetAccountState(CreateIds("secondary@example.com", "2"), true);
583 std::vector<std::string> only_primary;
584 only_primary.push_back("1");
585 EXPECT_TRUE(ExpectGetAccounts(only_primary));
586 }
587
588 class IdentityGetProfileUserInfoFunctionTest : public ExtensionBrowserTest {
589 protected:
RunGetProfileUserInfo()590 scoped_ptr<api::identity::ProfileUserInfo> RunGetProfileUserInfo() {
591 scoped_refptr<IdentityGetProfileUserInfoFunction> func(
592 new IdentityGetProfileUserInfoFunction);
593 func->set_extension(utils::CreateEmptyExtension(kExtensionId).get());
594 scoped_ptr<base::Value> value(
595 utils::RunFunctionAndReturnSingleResult(func.get(), "[]", browser()));
596 return api::identity::ProfileUserInfo::FromValue(*value.get());
597 }
598
RunGetProfileUserInfoWithEmail()599 scoped_ptr<api::identity::ProfileUserInfo> RunGetProfileUserInfoWithEmail() {
600 scoped_refptr<IdentityGetProfileUserInfoFunction> func(
601 new IdentityGetProfileUserInfoFunction);
602 func->set_extension(CreateExtensionWithEmailPermission());
603 scoped_ptr<base::Value> value(
604 utils::RunFunctionAndReturnSingleResult(func.get(), "[]", browser()));
605 return api::identity::ProfileUserInfo::FromValue(*value.get());
606 }
607
608 private:
CreateExtensionWithEmailPermission()609 scoped_refptr<Extension> CreateExtensionWithEmailPermission() {
610 scoped_ptr<base::DictionaryValue> test_extension_value(
611 utils::ParseDictionary(
612 "{\"name\": \"Test\", \"version\": \"1.0\", "
613 "\"permissions\": [\"identity.email\"]}"));
614 return utils::CreateExtension(test_extension_value.get());
615 }
616 };
617
IN_PROC_BROWSER_TEST_F(IdentityGetProfileUserInfoFunctionTest,NotSignedIn)618 IN_PROC_BROWSER_TEST_F(IdentityGetProfileUserInfoFunctionTest, NotSignedIn) {
619 scoped_ptr<api::identity::ProfileUserInfo> info =
620 RunGetProfileUserInfoWithEmail();
621 EXPECT_TRUE(info->email.empty());
622 EXPECT_TRUE(info->id.empty());
623 }
624
IN_PROC_BROWSER_TEST_F(IdentityGetProfileUserInfoFunctionTest,SignedIn)625 IN_PROC_BROWSER_TEST_F(IdentityGetProfileUserInfoFunctionTest, SignedIn) {
626 profile()->GetPrefs()
627 ->SetString(prefs::kGoogleServicesUsername, "president@example.com");
628 profile()->GetPrefs()
629 ->SetString(prefs::kGoogleServicesUserAccountId, "12345");
630
631 scoped_ptr<api::identity::ProfileUserInfo> info =
632 RunGetProfileUserInfoWithEmail();
633 EXPECT_EQ("president@example.com", info->email);
634 EXPECT_EQ("12345", info->id);
635 }
636
IN_PROC_BROWSER_TEST_F(IdentityGetProfileUserInfoFunctionTest,NotSignedInNoEmail)637 IN_PROC_BROWSER_TEST_F(IdentityGetProfileUserInfoFunctionTest,
638 NotSignedInNoEmail) {
639 scoped_ptr<api::identity::ProfileUserInfo> info = RunGetProfileUserInfo();
640 EXPECT_TRUE(info->email.empty());
641 EXPECT_TRUE(info->id.empty());
642 }
643
IN_PROC_BROWSER_TEST_F(IdentityGetProfileUserInfoFunctionTest,SignedInNoEmail)644 IN_PROC_BROWSER_TEST_F(IdentityGetProfileUserInfoFunctionTest,
645 SignedInNoEmail) {
646 profile()->GetPrefs()->SetString(prefs::kGoogleServicesUsername,
647 "president@example.com");
648 profile()->GetPrefs()->SetString(prefs::kGoogleServicesUserAccountId,
649 "12345");
650
651 scoped_ptr<api::identity::ProfileUserInfo> info = RunGetProfileUserInfo();
652 EXPECT_TRUE(info->email.empty());
653 EXPECT_EQ("12345", info->id);
654 }
655
656 class GetAuthTokenFunctionTest : public AsyncExtensionBrowserTest {
657 public:
SetUpCommandLine(CommandLine * command_line)658 virtual void SetUpCommandLine(CommandLine* command_line) OVERRIDE {
659 AsyncExtensionBrowserTest::SetUpCommandLine(command_line);
660 command_line->AppendSwitch(switches::kExtensionsMultiAccount);
661 }
662
SetUpInProcessBrowserTestFixture()663 virtual void SetUpInProcessBrowserTestFixture() OVERRIDE {
664 AsyncExtensionBrowserTest::SetUpInProcessBrowserTestFixture();
665
666 will_create_browser_context_services_subscription_ =
667 BrowserContextDependencyManager::GetInstance()
668 ->RegisterWillCreateBrowserContextServicesCallbackForTesting(
669 base::Bind(&GetAuthTokenFunctionTest::
670 OnWillCreateBrowserContextServices,
671 base::Unretained(this)))
672 .Pass();
673 }
674
OnWillCreateBrowserContextServices(content::BrowserContext * context)675 void OnWillCreateBrowserContextServices(content::BrowserContext* context) {
676 // Replace the signin manager and token service with fakes. Do this ahead of
677 // creating the browser so that a bunch of classes don't register as
678 // observers and end up needing to unregister when the fake is substituted.
679 SigninManagerFactory::GetInstance()->SetTestingFactory(
680 context, &FakeSigninManagerBase::Build);
681 ProfileOAuth2TokenServiceFactory::GetInstance()->SetTestingFactory(
682 context, &BuildFakeProfileOAuth2TokenService);
683 }
684
SetUpOnMainThread()685 virtual void SetUpOnMainThread() OVERRIDE {
686 AsyncExtensionBrowserTest::SetUpOnMainThread();
687
688 // Grab references to the fake signin manager and token service.
689 signin_manager_ = static_cast<FakeSigninManagerForTesting*>(
690 SigninManagerFactory::GetInstance()->GetForProfile(profile()));
691 ASSERT_TRUE(signin_manager_);
692 token_service_ = static_cast<FakeProfileOAuth2TokenService*>(
693 ProfileOAuth2TokenServiceFactory::GetInstance()->GetForProfile(
694 profile()));
695 ASSERT_TRUE(token_service_);
696 }
697
SignIn(const std::string account_key)698 void SignIn(const std::string account_key) {
699 #if defined(OS_CHROMEOS)
700 signin_manager_->SetAuthenticatedUsername(account_key);
701 #else
702 signin_manager_->SignIn(account_key, "password");
703 #endif
704 }
705
SetAccountState(AccountIds ids,bool is_signed_in)706 void SetAccountState(AccountIds ids, bool is_signed_in) {
707 IdentityAPI::GetFactoryInstance()->Get(profile())->SetAccountStateForTest(
708 ids, is_signed_in);
709 }
710
711 protected:
712 enum OAuth2Fields {
713 NONE = 0,
714 CLIENT_ID = 1,
715 SCOPES = 2,
716 AS_COMPONENT = 4
717 };
718
719 FakeSigninManagerForTesting* signin_manager_;
720 FakeProfileOAuth2TokenService* token_service_;
721
~GetAuthTokenFunctionTest()722 virtual ~GetAuthTokenFunctionTest() {}
723
724 // Helper to create an extension with specific OAuth2Info fields set.
725 // |fields_to_set| should be computed by using fields of Oauth2Fields enum.
CreateExtension(int fields_to_set)726 const Extension* CreateExtension(int fields_to_set) {
727 const Extension* ext;
728 base::FilePath manifest_path =
729 test_data_dir_.AppendASCII("platform_apps/oauth2");
730 base::FilePath component_manifest_path =
731 test_data_dir_.AppendASCII("packaged_app/component_oauth2");
732 if ((fields_to_set & AS_COMPONENT) == 0)
733 ext = LoadExtension(manifest_path);
734 else
735 ext = LoadExtensionAsComponent(component_manifest_path);
736 OAuth2Info& oauth2_info =
737 const_cast<OAuth2Info&>(OAuth2Info::GetOAuth2Info(ext));
738 if ((fields_to_set & CLIENT_ID) != 0)
739 oauth2_info.client_id = "client1";
740 if ((fields_to_set & SCOPES) != 0) {
741 oauth2_info.scopes.push_back("scope1");
742 oauth2_info.scopes.push_back("scope2");
743 }
744
745 extension_id_ = ext->id();
746 oauth_scopes_ = std::set<std::string>(oauth2_info.scopes.begin(),
747 oauth2_info.scopes.end());
748 return ext;
749 }
750
id_api()751 IdentityAPI* id_api() {
752 return IdentityAPI::GetFactoryInstance()->Get(browser()->profile());
753 }
754
GetPrimaryAccountId()755 const std::string GetPrimaryAccountId() {
756 SigninManagerBase* signin_manager =
757 SigninManagerFactory::GetForProfile(browser()->profile());
758 return signin_manager->GetAuthenticatedAccountId();
759 }
760
SetCachedToken(const IdentityTokenCacheValue & token_data)761 void SetCachedToken(const IdentityTokenCacheValue& token_data) {
762 ExtensionTokenKey key(extension_id_, GetPrimaryAccountId(), oauth_scopes_);
763 id_api()->SetCachedToken(key, token_data);
764 }
765
GetCachedToken(std::string account_id)766 const IdentityTokenCacheValue& GetCachedToken(std::string account_id) {
767 if (account_id.empty())
768 account_id = GetPrimaryAccountId();
769 ExtensionTokenKey key(extension_id_, account_id, oauth_scopes_);
770 return id_api()->GetCachedToken(key);
771 }
772
QueueRequestStart(IdentityMintRequestQueue::MintType type,IdentityMintRequestQueue::Request * request)773 void QueueRequestStart(IdentityMintRequestQueue::MintType type,
774 IdentityMintRequestQueue::Request* request) {
775 ExtensionTokenKey key(extension_id_, GetPrimaryAccountId(), oauth_scopes_);
776 id_api()->mint_queue()->RequestStart(type, key, request);
777 }
778
QueueRequestComplete(IdentityMintRequestQueue::MintType type,IdentityMintRequestQueue::Request * request)779 void QueueRequestComplete(IdentityMintRequestQueue::MintType type,
780 IdentityMintRequestQueue::Request* request) {
781 ExtensionTokenKey key(extension_id_, GetPrimaryAccountId(), oauth_scopes_);
782 id_api()->mint_queue()->RequestComplete(type, key, request);
783 }
784
785 private:
786 std::string extension_id_;
787 std::set<std::string> oauth_scopes_;
788
789 scoped_ptr<base::CallbackList<void(content::BrowserContext*)>::Subscription>
790 will_create_browser_context_services_subscription_;
791 };
792
IN_PROC_BROWSER_TEST_F(GetAuthTokenFunctionTest,NoClientId)793 IN_PROC_BROWSER_TEST_F(GetAuthTokenFunctionTest,
794 NoClientId) {
795 scoped_refptr<MockGetAuthTokenFunction> func(new MockGetAuthTokenFunction());
796 func->set_extension(CreateExtension(SCOPES));
797 std::string error = utils::RunFunctionAndReturnError(
798 func.get(), "[{}]", browser());
799 EXPECT_EQ(std::string(errors::kInvalidClientId), error);
800 EXPECT_FALSE(func->login_ui_shown());
801 EXPECT_FALSE(func->scope_ui_shown());
802 }
803
IN_PROC_BROWSER_TEST_F(GetAuthTokenFunctionTest,NoScopes)804 IN_PROC_BROWSER_TEST_F(GetAuthTokenFunctionTest,
805 NoScopes) {
806 scoped_refptr<MockGetAuthTokenFunction> func(new MockGetAuthTokenFunction());
807 func->set_extension(CreateExtension(CLIENT_ID));
808 std::string error = utils::RunFunctionAndReturnError(
809 func.get(), "[{}]", browser());
810 EXPECT_EQ(std::string(errors::kInvalidScopes), error);
811 EXPECT_FALSE(func->login_ui_shown());
812 EXPECT_FALSE(func->scope_ui_shown());
813 }
814
IN_PROC_BROWSER_TEST_F(GetAuthTokenFunctionTest,NonInteractiveNotSignedIn)815 IN_PROC_BROWSER_TEST_F(GetAuthTokenFunctionTest,
816 NonInteractiveNotSignedIn) {
817 scoped_refptr<MockGetAuthTokenFunction> func(new MockGetAuthTokenFunction());
818 func->set_extension(CreateExtension(CLIENT_ID | SCOPES));
819 EXPECT_CALL(*func.get(), HasLoginToken()).WillOnce(Return(false));
820 std::string error = utils::RunFunctionAndReturnError(
821 func.get(), "[{}]", browser());
822 EXPECT_EQ(std::string(errors::kUserNotSignedIn), error);
823 EXPECT_FALSE(func->login_ui_shown());
824 EXPECT_FALSE(func->scope_ui_shown());
825 }
826
IN_PROC_BROWSER_TEST_F(GetAuthTokenFunctionTest,NonInteractiveMintFailure)827 IN_PROC_BROWSER_TEST_F(GetAuthTokenFunctionTest,
828 NonInteractiveMintFailure) {
829 scoped_refptr<MockGetAuthTokenFunction> func(new MockGetAuthTokenFunction());
830 func->set_extension(CreateExtension(CLIENT_ID | SCOPES));
831 EXPECT_CALL(*func.get(), HasLoginToken())
832 .WillOnce(Return(true));
833 TestOAuth2MintTokenFlow* flow = new TestOAuth2MintTokenFlow(
834 TestOAuth2MintTokenFlow::MINT_TOKEN_FAILURE, func.get());
835 EXPECT_CALL(*func.get(), CreateMintTokenFlow(_)).WillOnce(Return(flow));
836 std::string error = utils::RunFunctionAndReturnError(
837 func.get(), "[{}]", browser());
838 EXPECT_TRUE(StartsWithASCII(error, errors::kAuthFailure, false));
839 EXPECT_FALSE(func->login_ui_shown());
840 EXPECT_FALSE(func->scope_ui_shown());
841 }
842
IN_PROC_BROWSER_TEST_F(GetAuthTokenFunctionTest,NonInteractiveLoginAccessTokenFailure)843 IN_PROC_BROWSER_TEST_F(GetAuthTokenFunctionTest,
844 NonInteractiveLoginAccessTokenFailure) {
845 scoped_refptr<MockGetAuthTokenFunction> func(new MockGetAuthTokenFunction());
846 func->set_extension(CreateExtension(CLIENT_ID | SCOPES));
847 EXPECT_CALL(*func.get(), HasLoginToken())
848 .WillOnce(Return(true));
849 func->set_login_access_token_result(false);
850 std::string error = utils::RunFunctionAndReturnError(
851 func.get(), "[{}]", browser());
852 EXPECT_TRUE(StartsWithASCII(error, errors::kAuthFailure, false));
853 }
854
IN_PROC_BROWSER_TEST_F(GetAuthTokenFunctionTest,NonInteractiveMintAdviceSuccess)855 IN_PROC_BROWSER_TEST_F(GetAuthTokenFunctionTest,
856 NonInteractiveMintAdviceSuccess) {
857 scoped_refptr<const Extension> extension(CreateExtension(CLIENT_ID | SCOPES));
858 scoped_refptr<MockGetAuthTokenFunction> func(new MockGetAuthTokenFunction());
859 func->set_extension(extension.get());
860 EXPECT_CALL(*func.get(), HasLoginToken()).WillOnce(Return(true));
861 TestOAuth2MintTokenFlow* flow = new TestOAuth2MintTokenFlow(
862 TestOAuth2MintTokenFlow::ISSUE_ADVICE_SUCCESS, func.get());
863 EXPECT_CALL(*func.get(), CreateMintTokenFlow(_)).WillOnce(Return(flow));
864 std::string error = utils::RunFunctionAndReturnError(
865 func.get(), "[{}]", browser());
866 EXPECT_EQ(std::string(errors::kNoGrant), error);
867 EXPECT_FALSE(func->login_ui_shown());
868 EXPECT_FALSE(func->scope_ui_shown());
869
870 EXPECT_EQ(IdentityTokenCacheValue::CACHE_STATUS_ADVICE,
871 GetCachedToken(std::string()).status());
872 }
873
IN_PROC_BROWSER_TEST_F(GetAuthTokenFunctionTest,NonInteractiveMintBadCredentials)874 IN_PROC_BROWSER_TEST_F(GetAuthTokenFunctionTest,
875 NonInteractiveMintBadCredentials) {
876 scoped_refptr<MockGetAuthTokenFunction> func(new MockGetAuthTokenFunction());
877 func->set_extension(CreateExtension(CLIENT_ID | SCOPES));
878 EXPECT_CALL(*func.get(), HasLoginToken())
879 .WillOnce(Return(true));
880 TestOAuth2MintTokenFlow* flow = new TestOAuth2MintTokenFlow(
881 TestOAuth2MintTokenFlow::MINT_TOKEN_BAD_CREDENTIALS, func.get());
882 EXPECT_CALL(*func.get(), CreateMintTokenFlow(_)).WillOnce(Return(flow));
883 std::string error = utils::RunFunctionAndReturnError(
884 func.get(), "[{}]", browser());
885 EXPECT_TRUE(StartsWithASCII(error, errors::kAuthFailure, false));
886 EXPECT_FALSE(func->login_ui_shown());
887 EXPECT_FALSE(func->scope_ui_shown());
888
889 EXPECT_EQ(GoogleServiceAuthError::INVALID_GAIA_CREDENTIALS,
890 id_api()->GetAuthStatusForTest().state());
891 }
892
IN_PROC_BROWSER_TEST_F(GetAuthTokenFunctionTest,NonInteractiveMintServiceError)893 IN_PROC_BROWSER_TEST_F(GetAuthTokenFunctionTest,
894 NonInteractiveMintServiceError) {
895 scoped_refptr<MockGetAuthTokenFunction> func(new MockGetAuthTokenFunction());
896 func->set_extension(CreateExtension(CLIENT_ID | SCOPES));
897 EXPECT_CALL(*func.get(), HasLoginToken()).WillOnce(Return(true));
898 TestOAuth2MintTokenFlow* flow = new TestOAuth2MintTokenFlow(
899 TestOAuth2MintTokenFlow::MINT_TOKEN_SERVICE_ERROR, func.get());
900 EXPECT_CALL(*func.get(), CreateMintTokenFlow(_)).WillOnce(Return(flow));
901 std::string error =
902 utils::RunFunctionAndReturnError(func.get(), "[{}]", browser());
903 EXPECT_TRUE(StartsWithASCII(error, errors::kAuthFailure, false));
904 EXPECT_FALSE(func->login_ui_shown());
905 EXPECT_FALSE(func->scope_ui_shown());
906
907 EXPECT_EQ(GoogleServiceAuthError::AuthErrorNone(),
908 id_api()->GetAuthStatusForTest());
909 }
910
IN_PROC_BROWSER_TEST_F(GetAuthTokenFunctionTest,NoOptionsSuccess)911 IN_PROC_BROWSER_TEST_F(GetAuthTokenFunctionTest,
912 NoOptionsSuccess) {
913 #if defined(OS_WIN) && defined(USE_ASH)
914 // Disable this test in Metro+Ash for now (http://crbug.com/262796).
915 if (CommandLine::ForCurrentProcess()->HasSwitch(switches::kAshBrowserTests))
916 return;
917 #endif
918
919 scoped_refptr<MockGetAuthTokenFunction> func(new MockGetAuthTokenFunction());
920 scoped_refptr<const Extension> extension(CreateExtension(CLIENT_ID | SCOPES));
921 func->set_extension(extension.get());
922 EXPECT_CALL(*func.get(), HasLoginToken()).WillOnce(Return(true));
923 TestOAuth2MintTokenFlow* flow = new TestOAuth2MintTokenFlow(
924 TestOAuth2MintTokenFlow::MINT_TOKEN_SUCCESS, func.get());
925 EXPECT_CALL(*func.get(), CreateMintTokenFlow(_)).WillOnce(Return(flow));
926 scoped_ptr<base::Value> value(utils::RunFunctionAndReturnSingleResult(
927 func.get(), "[]", browser()));
928 std::string access_token;
929 EXPECT_TRUE(value->GetAsString(&access_token));
930 EXPECT_EQ(std::string(kAccessToken), access_token);
931 EXPECT_FALSE(func->login_ui_shown());
932 EXPECT_FALSE(func->scope_ui_shown());
933 EXPECT_EQ(IdentityTokenCacheValue::CACHE_STATUS_TOKEN,
934 GetCachedToken(std::string()).status());
935 }
936
IN_PROC_BROWSER_TEST_F(GetAuthTokenFunctionTest,NonInteractiveSuccess)937 IN_PROC_BROWSER_TEST_F(GetAuthTokenFunctionTest,
938 NonInteractiveSuccess) {
939 #if defined(OS_WIN) && defined(USE_ASH)
940 // Disable this test in Metro+Ash for now (http://crbug.com/262796).
941 if (CommandLine::ForCurrentProcess()->HasSwitch(switches::kAshBrowserTests))
942 return;
943 #endif
944
945 scoped_refptr<MockGetAuthTokenFunction> func(new MockGetAuthTokenFunction());
946 scoped_refptr<const Extension> extension(CreateExtension(CLIENT_ID | SCOPES));
947 func->set_extension(extension.get());
948 EXPECT_CALL(*func.get(), HasLoginToken()).WillOnce(Return(true));
949 TestOAuth2MintTokenFlow* flow = new TestOAuth2MintTokenFlow(
950 TestOAuth2MintTokenFlow::MINT_TOKEN_SUCCESS, func.get());
951 EXPECT_CALL(*func.get(), CreateMintTokenFlow(_)).WillOnce(Return(flow));
952 scoped_ptr<base::Value> value(utils::RunFunctionAndReturnSingleResult(
953 func.get(), "[{}]", browser()));
954 std::string access_token;
955 EXPECT_TRUE(value->GetAsString(&access_token));
956 EXPECT_EQ(std::string(kAccessToken), access_token);
957 EXPECT_FALSE(func->login_ui_shown());
958 EXPECT_FALSE(func->scope_ui_shown());
959 EXPECT_EQ(IdentityTokenCacheValue::CACHE_STATUS_TOKEN,
960 GetCachedToken(std::string()).status());
961 }
962
IN_PROC_BROWSER_TEST_F(GetAuthTokenFunctionTest,InteractiveLoginCanceled)963 IN_PROC_BROWSER_TEST_F(GetAuthTokenFunctionTest,
964 InteractiveLoginCanceled) {
965 scoped_refptr<MockGetAuthTokenFunction> func(new MockGetAuthTokenFunction());
966 func->set_extension(CreateExtension(CLIENT_ID | SCOPES));
967 EXPECT_CALL(*func.get(), HasLoginToken()).WillOnce(Return(false));
968 func->set_login_ui_result(false);
969 std::string error = utils::RunFunctionAndReturnError(
970 func.get(), "[{\"interactive\": true}]", browser());
971 EXPECT_EQ(std::string(errors::kUserNotSignedIn), error);
972 EXPECT_TRUE(func->login_ui_shown());
973 EXPECT_FALSE(func->scope_ui_shown());
974 }
975
IN_PROC_BROWSER_TEST_F(GetAuthTokenFunctionTest,InteractiveMintBadCredentialsLoginCanceled)976 IN_PROC_BROWSER_TEST_F(GetAuthTokenFunctionTest,
977 InteractiveMintBadCredentialsLoginCanceled) {
978 scoped_refptr<MockGetAuthTokenFunction> func(new MockGetAuthTokenFunction());
979 func->set_extension(CreateExtension(CLIENT_ID | SCOPES));
980 EXPECT_CALL(*func.get(), HasLoginToken())
981 .WillOnce(Return(true));
982 TestOAuth2MintTokenFlow* flow = new TestOAuth2MintTokenFlow(
983 TestOAuth2MintTokenFlow::MINT_TOKEN_BAD_CREDENTIALS, func.get());
984 EXPECT_CALL(*func.get(), CreateMintTokenFlow(_)).WillOnce(Return(flow));
985 func->set_login_ui_result(false);
986 std::string error = utils::RunFunctionAndReturnError(
987 func.get(), "[{\"interactive\": true}]", browser());
988 EXPECT_EQ(std::string(errors::kUserNotSignedIn), error);
989 EXPECT_TRUE(func->login_ui_shown());
990 EXPECT_FALSE(func->scope_ui_shown());
991 }
992
IN_PROC_BROWSER_TEST_F(GetAuthTokenFunctionTest,InteractiveLoginSuccessNoToken)993 IN_PROC_BROWSER_TEST_F(GetAuthTokenFunctionTest,
994 InteractiveLoginSuccessNoToken) {
995 scoped_refptr<MockGetAuthTokenFunction> func(new MockGetAuthTokenFunction());
996 func->set_extension(CreateExtension(CLIENT_ID | SCOPES));
997 EXPECT_CALL(*func.get(), HasLoginToken()).WillOnce(Return(false));
998 func->set_login_ui_result(false);
999 std::string error = utils::RunFunctionAndReturnError(
1000 func.get(), "[{\"interactive\": true}]", browser());
1001 EXPECT_EQ(std::string(errors::kUserNotSignedIn), error);
1002 EXPECT_TRUE(func->login_ui_shown());
1003 EXPECT_FALSE(func->scope_ui_shown());
1004 }
1005
IN_PROC_BROWSER_TEST_F(GetAuthTokenFunctionTest,InteractiveLoginSuccessMintFailure)1006 IN_PROC_BROWSER_TEST_F(GetAuthTokenFunctionTest,
1007 InteractiveLoginSuccessMintFailure) {
1008 scoped_refptr<MockGetAuthTokenFunction> func(new MockGetAuthTokenFunction());
1009 func->set_extension(CreateExtension(CLIENT_ID | SCOPES));
1010 EXPECT_CALL(*func.get(), HasLoginToken())
1011 .WillOnce(Return(false));
1012 func->set_login_ui_result(true);
1013 TestOAuth2MintTokenFlow* flow = new TestOAuth2MintTokenFlow(
1014 TestOAuth2MintTokenFlow::MINT_TOKEN_FAILURE, func.get());
1015 EXPECT_CALL(*func.get(), CreateMintTokenFlow(_)).WillOnce(Return(flow));
1016 std::string error = utils::RunFunctionAndReturnError(
1017 func.get(), "[{\"interactive\": true}]", browser());
1018 EXPECT_TRUE(StartsWithASCII(error, errors::kAuthFailure, false));
1019 EXPECT_TRUE(func->login_ui_shown());
1020 EXPECT_FALSE(func->scope_ui_shown());
1021 }
1022
IN_PROC_BROWSER_TEST_F(GetAuthTokenFunctionTest,InteractiveLoginSuccessLoginAccessTokenFailure)1023 IN_PROC_BROWSER_TEST_F(GetAuthTokenFunctionTest,
1024 InteractiveLoginSuccessLoginAccessTokenFailure) {
1025 scoped_refptr<MockGetAuthTokenFunction> func(new MockGetAuthTokenFunction());
1026 func->set_extension(CreateExtension(CLIENT_ID | SCOPES));
1027 EXPECT_CALL(*func.get(), HasLoginToken()).WillOnce(Return(false));
1028 func->set_login_ui_result(true);
1029 func->set_login_access_token_result(false);
1030 std::string error = utils::RunFunctionAndReturnError(
1031 func.get(), "[{\"interactive\": true}]", browser());
1032 EXPECT_TRUE(StartsWithASCII(error, errors::kAuthFailure, false));
1033 EXPECT_TRUE(func->login_ui_shown());
1034 EXPECT_FALSE(func->scope_ui_shown());
1035 }
1036
IN_PROC_BROWSER_TEST_F(GetAuthTokenFunctionTest,InteractiveLoginSuccessMintSuccess)1037 IN_PROC_BROWSER_TEST_F(GetAuthTokenFunctionTest,
1038 InteractiveLoginSuccessMintSuccess) {
1039 scoped_refptr<MockGetAuthTokenFunction> func(new MockGetAuthTokenFunction());
1040 func->set_extension(CreateExtension(CLIENT_ID | SCOPES));
1041 EXPECT_CALL(*func.get(), HasLoginToken())
1042 .WillOnce(Return(false));
1043 func->set_login_ui_result(true);
1044 TestOAuth2MintTokenFlow* flow = new TestOAuth2MintTokenFlow(
1045 TestOAuth2MintTokenFlow::MINT_TOKEN_SUCCESS, func.get());
1046 EXPECT_CALL(*func.get(), CreateMintTokenFlow(_)).WillOnce(Return(flow));
1047 scoped_ptr<base::Value> value(utils::RunFunctionAndReturnSingleResult(
1048 func.get(), "[{\"interactive\": true}]", browser()));
1049 std::string access_token;
1050 EXPECT_TRUE(value->GetAsString(&access_token));
1051 EXPECT_EQ(std::string(kAccessToken), access_token);
1052 EXPECT_TRUE(func->login_ui_shown());
1053 EXPECT_FALSE(func->scope_ui_shown());
1054 }
1055
IN_PROC_BROWSER_TEST_F(GetAuthTokenFunctionTest,InteractiveLoginSuccessApprovalAborted)1056 IN_PROC_BROWSER_TEST_F(GetAuthTokenFunctionTest,
1057 InteractiveLoginSuccessApprovalAborted) {
1058 scoped_refptr<MockGetAuthTokenFunction> func(new MockGetAuthTokenFunction());
1059 func->set_extension(CreateExtension(CLIENT_ID | SCOPES));
1060 EXPECT_CALL(*func.get(), HasLoginToken())
1061 .WillOnce(Return(false));
1062 func->set_login_ui_result(true);
1063 TestOAuth2MintTokenFlow* flow = new TestOAuth2MintTokenFlow(
1064 TestOAuth2MintTokenFlow::ISSUE_ADVICE_SUCCESS, func.get());
1065 EXPECT_CALL(*func.get(), CreateMintTokenFlow(_)).WillOnce(Return(flow));
1066 func->set_scope_ui_failure(GaiaWebAuthFlow::WINDOW_CLOSED);
1067 std::string error = utils::RunFunctionAndReturnError(
1068 func.get(), "[{\"interactive\": true}]", browser());
1069 EXPECT_EQ(std::string(errors::kUserRejected), error);
1070 EXPECT_TRUE(func->login_ui_shown());
1071 EXPECT_TRUE(func->scope_ui_shown());
1072 }
1073
IN_PROC_BROWSER_TEST_F(GetAuthTokenFunctionTest,InteractiveLoginSuccessApprovalSuccess)1074 IN_PROC_BROWSER_TEST_F(GetAuthTokenFunctionTest,
1075 InteractiveLoginSuccessApprovalSuccess) {
1076 scoped_refptr<const Extension> extension(CreateExtension(CLIENT_ID | SCOPES));
1077 scoped_refptr<MockGetAuthTokenFunction> func(new MockGetAuthTokenFunction());
1078 func->set_extension(extension.get());
1079 EXPECT_CALL(*func.get(), HasLoginToken()).WillOnce(Return(false));
1080 func->set_login_ui_result(true);
1081 TestOAuth2MintTokenFlow* flow = new TestOAuth2MintTokenFlow(
1082 TestOAuth2MintTokenFlow::ISSUE_ADVICE_SUCCESS, func.get());
1083 EXPECT_CALL(*func.get(), CreateMintTokenFlow(_))
1084 .WillOnce(Return(flow));
1085
1086 scoped_ptr<base::Value> value(utils::RunFunctionAndReturnSingleResult(
1087 func.get(), "[{\"interactive\": true}]", browser()));
1088 std::string access_token;
1089 EXPECT_TRUE(value->GetAsString(&access_token));
1090 EXPECT_EQ(std::string(kAccessToken), access_token);
1091 EXPECT_TRUE(func->login_ui_shown());
1092 EXPECT_TRUE(func->scope_ui_shown());
1093 }
1094
IN_PROC_BROWSER_TEST_F(GetAuthTokenFunctionTest,InteractiveApprovalAborted)1095 IN_PROC_BROWSER_TEST_F(GetAuthTokenFunctionTest,
1096 InteractiveApprovalAborted) {
1097 scoped_refptr<MockGetAuthTokenFunction> func(new MockGetAuthTokenFunction());
1098 func->set_extension(CreateExtension(CLIENT_ID | SCOPES));
1099 EXPECT_CALL(*func.get(), HasLoginToken())
1100 .WillOnce(Return(true));
1101 TestOAuth2MintTokenFlow* flow = new TestOAuth2MintTokenFlow(
1102 TestOAuth2MintTokenFlow::ISSUE_ADVICE_SUCCESS, func.get());
1103 EXPECT_CALL(*func.get(), CreateMintTokenFlow(_)).WillOnce(Return(flow));
1104 func->set_scope_ui_failure(GaiaWebAuthFlow::WINDOW_CLOSED);
1105 std::string error = utils::RunFunctionAndReturnError(
1106 func.get(), "[{\"interactive\": true}]", browser());
1107 EXPECT_EQ(std::string(errors::kUserRejected), error);
1108 EXPECT_FALSE(func->login_ui_shown());
1109 EXPECT_TRUE(func->scope_ui_shown());
1110 }
1111
IN_PROC_BROWSER_TEST_F(GetAuthTokenFunctionTest,InteractiveApprovalLoadFailed)1112 IN_PROC_BROWSER_TEST_F(GetAuthTokenFunctionTest,
1113 InteractiveApprovalLoadFailed) {
1114 scoped_refptr<MockGetAuthTokenFunction> func(new MockGetAuthTokenFunction());
1115 func->set_extension(CreateExtension(CLIENT_ID | SCOPES));
1116 EXPECT_CALL(*func.get(), HasLoginToken())
1117 .WillOnce(Return(true));
1118 TestOAuth2MintTokenFlow* flow = new TestOAuth2MintTokenFlow(
1119 TestOAuth2MintTokenFlow::ISSUE_ADVICE_SUCCESS, func.get());
1120 EXPECT_CALL(*func.get(), CreateMintTokenFlow(_)).WillOnce(Return(flow));
1121 func->set_scope_ui_failure(GaiaWebAuthFlow::LOAD_FAILED);
1122 std::string error = utils::RunFunctionAndReturnError(
1123 func.get(), "[{\"interactive\": true}]", browser());
1124 EXPECT_EQ(std::string(errors::kPageLoadFailure), error);
1125 EXPECT_FALSE(func->login_ui_shown());
1126 EXPECT_TRUE(func->scope_ui_shown());
1127 }
1128
IN_PROC_BROWSER_TEST_F(GetAuthTokenFunctionTest,InteractiveApprovalInvalidRedirect)1129 IN_PROC_BROWSER_TEST_F(GetAuthTokenFunctionTest,
1130 InteractiveApprovalInvalidRedirect) {
1131 scoped_refptr<MockGetAuthTokenFunction> func(new MockGetAuthTokenFunction());
1132 func->set_extension(CreateExtension(CLIENT_ID | SCOPES));
1133 EXPECT_CALL(*func.get(), HasLoginToken())
1134 .WillOnce(Return(true));
1135 TestOAuth2MintTokenFlow* flow = new TestOAuth2MintTokenFlow(
1136 TestOAuth2MintTokenFlow::ISSUE_ADVICE_SUCCESS, func.get());
1137 EXPECT_CALL(*func.get(), CreateMintTokenFlow(_)).WillOnce(Return(flow));
1138 func->set_scope_ui_failure(GaiaWebAuthFlow::INVALID_REDIRECT);
1139 std::string error = utils::RunFunctionAndReturnError(
1140 func.get(), "[{\"interactive\": true}]", browser());
1141 EXPECT_EQ(std::string(errors::kInvalidRedirect), error);
1142 EXPECT_FALSE(func->login_ui_shown());
1143 EXPECT_TRUE(func->scope_ui_shown());
1144 }
1145
IN_PROC_BROWSER_TEST_F(GetAuthTokenFunctionTest,InteractiveApprovalConnectionFailure)1146 IN_PROC_BROWSER_TEST_F(GetAuthTokenFunctionTest,
1147 InteractiveApprovalConnectionFailure) {
1148 scoped_refptr<MockGetAuthTokenFunction> func(new MockGetAuthTokenFunction());
1149 func->set_extension(CreateExtension(CLIENT_ID | SCOPES));
1150 EXPECT_CALL(*func.get(), HasLoginToken())
1151 .WillOnce(Return(true));
1152 TestOAuth2MintTokenFlow* flow = new TestOAuth2MintTokenFlow(
1153 TestOAuth2MintTokenFlow::ISSUE_ADVICE_SUCCESS, func.get());
1154 EXPECT_CALL(*func.get(), CreateMintTokenFlow(_)).WillOnce(Return(flow));
1155 func->set_scope_ui_failure(GaiaWebAuthFlow::SERVICE_AUTH_ERROR);
1156 std::string error = utils::RunFunctionAndReturnError(
1157 func.get(), "[{\"interactive\": true}]", browser());
1158 EXPECT_TRUE(StartsWithASCII(error, errors::kAuthFailure, false));
1159 EXPECT_FALSE(func->login_ui_shown());
1160 EXPECT_TRUE(func->scope_ui_shown());
1161 }
1162
IN_PROC_BROWSER_TEST_F(GetAuthTokenFunctionTest,InteractiveApprovalOAuthErrors)1163 IN_PROC_BROWSER_TEST_F(GetAuthTokenFunctionTest,
1164 InteractiveApprovalOAuthErrors) {
1165 scoped_refptr<const Extension> extension(CreateExtension(CLIENT_ID | SCOPES));
1166
1167 std::map<std::string, std::string> error_map;
1168 error_map.insert(std::make_pair("access_denied", errors::kUserRejected));
1169 error_map.insert(std::make_pair("invalid_scope", errors::kInvalidScopes));
1170 error_map.insert(std::make_pair(
1171 "unmapped_error", std::string(errors::kAuthFailure) + "unmapped_error"));
1172
1173 for (std::map<std::string, std::string>::const_iterator
1174 it = error_map.begin();
1175 it != error_map.end();
1176 ++it) {
1177 scoped_refptr<MockGetAuthTokenFunction> func(
1178 new MockGetAuthTokenFunction());
1179 func->set_extension(extension.get());
1180 EXPECT_CALL(*func.get(), HasLoginToken()).WillOnce(Return(true));
1181 // Make sure we don't get a cached issue_advice result, which would cause
1182 // flow to be leaked.
1183 id_api()->EraseAllCachedTokens();
1184 TestOAuth2MintTokenFlow* flow = new TestOAuth2MintTokenFlow(
1185 TestOAuth2MintTokenFlow::ISSUE_ADVICE_SUCCESS, func.get());
1186 EXPECT_CALL(*func.get(), CreateMintTokenFlow(_)).WillOnce(Return(flow));
1187 func->set_scope_ui_oauth_error(it->first);
1188 std::string error = utils::RunFunctionAndReturnError(
1189 func.get(), "[{\"interactive\": true}]", browser());
1190 EXPECT_EQ(it->second, error);
1191 EXPECT_FALSE(func->login_ui_shown());
1192 EXPECT_TRUE(func->scope_ui_shown());
1193 }
1194 }
1195
IN_PROC_BROWSER_TEST_F(GetAuthTokenFunctionTest,InteractiveApprovalSuccess)1196 IN_PROC_BROWSER_TEST_F(GetAuthTokenFunctionTest,
1197 InteractiveApprovalSuccess) {
1198 scoped_refptr<const Extension> extension(CreateExtension(CLIENT_ID | SCOPES));
1199 scoped_refptr<MockGetAuthTokenFunction> func(new MockGetAuthTokenFunction());
1200 func->set_extension(extension.get());
1201 EXPECT_CALL(*func.get(), HasLoginToken()).WillOnce(Return(true));
1202 TestOAuth2MintTokenFlow* flow = new TestOAuth2MintTokenFlow(
1203 TestOAuth2MintTokenFlow::ISSUE_ADVICE_SUCCESS, func.get());
1204 EXPECT_CALL(*func.get(), CreateMintTokenFlow(_))
1205 .WillOnce(Return(flow));
1206
1207 scoped_ptr<base::Value> value(utils::RunFunctionAndReturnSingleResult(
1208 func.get(), "[{\"interactive\": true}]", browser()));
1209 std::string access_token;
1210 EXPECT_TRUE(value->GetAsString(&access_token));
1211 EXPECT_EQ(std::string(kAccessToken), access_token);
1212 EXPECT_FALSE(func->login_ui_shown());
1213 EXPECT_TRUE(func->scope_ui_shown());
1214
1215 EXPECT_EQ(IdentityTokenCacheValue::CACHE_STATUS_TOKEN,
1216 GetCachedToken(std::string()).status());
1217 }
1218
IN_PROC_BROWSER_TEST_F(GetAuthTokenFunctionTest,NoninteractiveQueue)1219 IN_PROC_BROWSER_TEST_F(GetAuthTokenFunctionTest, NoninteractiveQueue) {
1220 scoped_refptr<const Extension> extension(CreateExtension(CLIENT_ID | SCOPES));
1221 scoped_refptr<MockGetAuthTokenFunction> func(new MockGetAuthTokenFunction());
1222 func->set_extension(extension.get());
1223
1224 // Create a fake request to block the queue.
1225 MockQueuedMintRequest queued_request;
1226 IdentityMintRequestQueue::MintType type =
1227 IdentityMintRequestQueue::MINT_TYPE_NONINTERACTIVE;
1228
1229 EXPECT_CALL(queued_request, StartMintToken(type)).Times(1);
1230 QueueRequestStart(type, &queued_request);
1231
1232 // The real request will start processing, but wait in the queue behind
1233 // the blocker.
1234 EXPECT_CALL(*func.get(), HasLoginToken()).WillOnce(Return(true));
1235 RunFunctionAsync(func.get(), "[{}]");
1236 // Verify that we have fetched the login token at this point.
1237 testing::Mock::VerifyAndClearExpectations(func.get());
1238
1239 // The flow will be created after the first queued request clears.
1240 TestOAuth2MintTokenFlow* flow = new TestOAuth2MintTokenFlow(
1241 TestOAuth2MintTokenFlow::MINT_TOKEN_SUCCESS, func.get());
1242 EXPECT_CALL(*func.get(), CreateMintTokenFlow(_)).WillOnce(Return(flow));
1243
1244 QueueRequestComplete(type, &queued_request);
1245
1246 scoped_ptr<base::Value> value(WaitForSingleResult(func.get()));
1247 std::string access_token;
1248 EXPECT_TRUE(value->GetAsString(&access_token));
1249 EXPECT_EQ(std::string(kAccessToken), access_token);
1250 EXPECT_FALSE(func->login_ui_shown());
1251 EXPECT_FALSE(func->scope_ui_shown());
1252 }
1253
IN_PROC_BROWSER_TEST_F(GetAuthTokenFunctionTest,InteractiveQueue)1254 IN_PROC_BROWSER_TEST_F(GetAuthTokenFunctionTest, InteractiveQueue) {
1255 scoped_refptr<const Extension> extension(CreateExtension(CLIENT_ID | SCOPES));
1256 scoped_refptr<MockGetAuthTokenFunction> func(new MockGetAuthTokenFunction());
1257 func->set_extension(extension.get());
1258
1259 // Create a fake request to block the queue.
1260 MockQueuedMintRequest queued_request;
1261 IdentityMintRequestQueue::MintType type =
1262 IdentityMintRequestQueue::MINT_TYPE_INTERACTIVE;
1263
1264 EXPECT_CALL(queued_request, StartMintToken(type)).Times(1);
1265 QueueRequestStart(type, &queued_request);
1266
1267 // The real request will start processing, but wait in the queue behind
1268 // the blocker.
1269 EXPECT_CALL(*func.get(), HasLoginToken()).WillOnce(Return(true));
1270 TestOAuth2MintTokenFlow* flow1 = new TestOAuth2MintTokenFlow(
1271 TestOAuth2MintTokenFlow::ISSUE_ADVICE_SUCCESS, func.get());
1272 EXPECT_CALL(*func.get(), CreateMintTokenFlow(_)).WillOnce(Return(flow1));
1273 RunFunctionAsync(func.get(), "[{\"interactive\": true}]");
1274 // Verify that we have fetched the login token and run the first flow.
1275 testing::Mock::VerifyAndClearExpectations(func.get());
1276 EXPECT_FALSE(func->scope_ui_shown());
1277
1278 // The UI will be displayed and a token retrieved after the first
1279 // queued request clears.
1280 QueueRequestComplete(type, &queued_request);
1281
1282 scoped_ptr<base::Value> value(WaitForSingleResult(func.get()));
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_TRUE(func->scope_ui_shown());
1288 }
1289
IN_PROC_BROWSER_TEST_F(GetAuthTokenFunctionTest,InteractiveQueueShutdown)1290 IN_PROC_BROWSER_TEST_F(GetAuthTokenFunctionTest, InteractiveQueueShutdown) {
1291 scoped_refptr<const Extension> extension(CreateExtension(CLIENT_ID | SCOPES));
1292 scoped_refptr<MockGetAuthTokenFunction> func(new MockGetAuthTokenFunction());
1293 func->set_extension(extension.get());
1294
1295 // Create a fake request to block the queue.
1296 MockQueuedMintRequest queued_request;
1297 IdentityMintRequestQueue::MintType type =
1298 IdentityMintRequestQueue::MINT_TYPE_INTERACTIVE;
1299
1300 EXPECT_CALL(queued_request, StartMintToken(type)).Times(1);
1301 QueueRequestStart(type, &queued_request);
1302
1303 // The real request will start processing, but wait in the queue behind
1304 // the blocker.
1305 EXPECT_CALL(*func.get(), HasLoginToken()).WillOnce(Return(true));
1306 TestOAuth2MintTokenFlow* flow1 = new TestOAuth2MintTokenFlow(
1307 TestOAuth2MintTokenFlow::ISSUE_ADVICE_SUCCESS, func.get());
1308 EXPECT_CALL(*func.get(), CreateMintTokenFlow(_)).WillOnce(Return(flow1));
1309 RunFunctionAsync(func.get(), "[{\"interactive\": true}]");
1310 // Verify that we have fetched the login token and run the first flow.
1311 testing::Mock::VerifyAndClearExpectations(func.get());
1312 EXPECT_FALSE(func->scope_ui_shown());
1313
1314 // After the request is canceled, the function will complete.
1315 func->OnShutdown();
1316 EXPECT_EQ(std::string(errors::kCanceled), WaitForError(func.get()));
1317 EXPECT_FALSE(func->login_ui_shown());
1318 EXPECT_FALSE(func->scope_ui_shown());
1319
1320 QueueRequestComplete(type, &queued_request);
1321 }
1322
IN_PROC_BROWSER_TEST_F(GetAuthTokenFunctionTest,NoninteractiveShutdown)1323 IN_PROC_BROWSER_TEST_F(GetAuthTokenFunctionTest, NoninteractiveShutdown) {
1324 scoped_refptr<const Extension> extension(CreateExtension(CLIENT_ID | SCOPES));
1325 scoped_refptr<MockGetAuthTokenFunction> func(new MockGetAuthTokenFunction());
1326 func->set_extension(extension.get());
1327
1328 EXPECT_CALL(*func.get(), HasLoginToken()).WillOnce(Return(true));
1329 TestHangOAuth2MintTokenFlow* flow = new TestHangOAuth2MintTokenFlow();
1330 EXPECT_CALL(*func.get(), CreateMintTokenFlow(_)).WillOnce(Return(flow));
1331 RunFunctionAsync(func.get(), "[{\"interactive\": false}]");
1332
1333 // After the request is canceled, the function will complete.
1334 func->OnShutdown();
1335 EXPECT_EQ(std::string(errors::kCanceled), WaitForError(func.get()));
1336 }
1337
IN_PROC_BROWSER_TEST_F(GetAuthTokenFunctionTest,InteractiveQueuedNoninteractiveFails)1338 IN_PROC_BROWSER_TEST_F(GetAuthTokenFunctionTest,
1339 InteractiveQueuedNoninteractiveFails) {
1340 scoped_refptr<const Extension> extension(CreateExtension(CLIENT_ID | SCOPES));
1341 scoped_refptr<MockGetAuthTokenFunction> func(new MockGetAuthTokenFunction());
1342 func->set_extension(extension.get());
1343
1344 // Create a fake request to block the interactive queue.
1345 MockQueuedMintRequest queued_request;
1346 IdentityMintRequestQueue::MintType type =
1347 IdentityMintRequestQueue::MINT_TYPE_INTERACTIVE;
1348
1349 EXPECT_CALL(queued_request, StartMintToken(type)).Times(1);
1350 QueueRequestStart(type, &queued_request);
1351
1352 // Non-interactive requests fail without hitting GAIA, because a
1353 // consent UI is known to be up.
1354 EXPECT_CALL(*func.get(), HasLoginToken()).WillOnce(Return(true));
1355 std::string error = utils::RunFunctionAndReturnError(
1356 func.get(), "[{}]", browser());
1357 EXPECT_EQ(std::string(errors::kNoGrant), error);
1358 EXPECT_FALSE(func->login_ui_shown());
1359 EXPECT_FALSE(func->scope_ui_shown());
1360
1361 QueueRequestComplete(type, &queued_request);
1362 }
1363
IN_PROC_BROWSER_TEST_F(GetAuthTokenFunctionTest,NonInteractiveCacheHit)1364 IN_PROC_BROWSER_TEST_F(GetAuthTokenFunctionTest,
1365 NonInteractiveCacheHit) {
1366 scoped_refptr<const Extension> extension(CreateExtension(CLIENT_ID | SCOPES));
1367 scoped_refptr<MockGetAuthTokenFunction> func(new MockGetAuthTokenFunction());
1368 func->set_extension(extension.get());
1369
1370 // pre-populate the cache with a token
1371 IdentityTokenCacheValue token(kAccessToken,
1372 base::TimeDelta::FromSeconds(3600));
1373 SetCachedToken(token);
1374
1375 // Get a token. Should not require a GAIA request.
1376 EXPECT_CALL(*func.get(), HasLoginToken())
1377 .WillOnce(Return(true));
1378 scoped_ptr<base::Value> value(utils::RunFunctionAndReturnSingleResult(
1379 func.get(), "[{}]", browser()));
1380 std::string access_token;
1381 EXPECT_TRUE(value->GetAsString(&access_token));
1382 EXPECT_EQ(std::string(kAccessToken), access_token);
1383 EXPECT_FALSE(func->login_ui_shown());
1384 EXPECT_FALSE(func->scope_ui_shown());
1385 }
1386
IN_PROC_BROWSER_TEST_F(GetAuthTokenFunctionTest,NonInteractiveIssueAdviceCacheHit)1387 IN_PROC_BROWSER_TEST_F(GetAuthTokenFunctionTest,
1388 NonInteractiveIssueAdviceCacheHit) {
1389 scoped_refptr<const Extension> extension(CreateExtension(CLIENT_ID | SCOPES));
1390 scoped_refptr<MockGetAuthTokenFunction> func(new MockGetAuthTokenFunction());
1391 func->set_extension(extension.get());
1392
1393 // pre-populate the cache with advice
1394 IssueAdviceInfo info;
1395 IdentityTokenCacheValue token(info);
1396 SetCachedToken(token);
1397
1398 // Should return an error without a GAIA request.
1399 EXPECT_CALL(*func.get(), HasLoginToken())
1400 .WillOnce(Return(true));
1401 std::string error = utils::RunFunctionAndReturnError(
1402 func.get(), "[{}]", browser());
1403 EXPECT_EQ(std::string(errors::kNoGrant), error);
1404 EXPECT_FALSE(func->login_ui_shown());
1405 EXPECT_FALSE(func->scope_ui_shown());
1406 }
1407
IN_PROC_BROWSER_TEST_F(GetAuthTokenFunctionTest,InteractiveCacheHit)1408 IN_PROC_BROWSER_TEST_F(GetAuthTokenFunctionTest,
1409 InteractiveCacheHit) {
1410 scoped_refptr<const Extension> extension(CreateExtension(CLIENT_ID | SCOPES));
1411 scoped_refptr<MockGetAuthTokenFunction> func(new MockGetAuthTokenFunction());
1412 func->set_extension(extension.get());
1413
1414 // Create a fake request to block the queue.
1415 MockQueuedMintRequest queued_request;
1416 IdentityMintRequestQueue::MintType type =
1417 IdentityMintRequestQueue::MINT_TYPE_INTERACTIVE;
1418
1419 EXPECT_CALL(queued_request, StartMintToken(type)).Times(1);
1420 QueueRequestStart(type, &queued_request);
1421
1422 // The real request will start processing, but wait in the queue behind
1423 // the blocker.
1424 EXPECT_CALL(*func.get(), HasLoginToken()).WillOnce(Return(true));
1425 TestOAuth2MintTokenFlow* flow = new TestOAuth2MintTokenFlow(
1426 TestOAuth2MintTokenFlow::ISSUE_ADVICE_SUCCESS, func.get());
1427 EXPECT_CALL(*func.get(), CreateMintTokenFlow(_)).WillOnce(Return(flow));
1428 RunFunctionAsync(func.get(), "[{\"interactive\": true}]");
1429
1430 // Populate the cache with a token while the request is blocked.
1431 IdentityTokenCacheValue token(kAccessToken,
1432 base::TimeDelta::FromSeconds(3600));
1433 SetCachedToken(token);
1434
1435 // When we wake up the request, it returns the cached token without
1436 // displaying a UI, or hitting GAIA.
1437
1438 QueueRequestComplete(type, &queued_request);
1439
1440 scoped_ptr<base::Value> value(WaitForSingleResult(func.get()));
1441 std::string access_token;
1442 EXPECT_TRUE(value->GetAsString(&access_token));
1443 EXPECT_EQ(std::string(kAccessToken), access_token);
1444 EXPECT_FALSE(func->login_ui_shown());
1445 EXPECT_FALSE(func->scope_ui_shown());
1446 }
1447
IN_PROC_BROWSER_TEST_F(GetAuthTokenFunctionTest,LoginInvalidatesTokenCache)1448 IN_PROC_BROWSER_TEST_F(GetAuthTokenFunctionTest,
1449 LoginInvalidatesTokenCache) {
1450 scoped_refptr<MockGetAuthTokenFunction> func(new MockGetAuthTokenFunction());
1451 scoped_refptr<const Extension> extension(CreateExtension(CLIENT_ID | SCOPES));
1452 func->set_extension(extension.get());
1453
1454 // pre-populate the cache with a token
1455 IdentityTokenCacheValue token(kAccessToken,
1456 base::TimeDelta::FromSeconds(3600));
1457 SetCachedToken(token);
1458
1459 // Because the user is not signed in, the token will be removed,
1460 // and we'll hit GAIA for new tokens.
1461 EXPECT_CALL(*func.get(), HasLoginToken())
1462 .WillOnce(Return(false));
1463 func->set_login_ui_result(true);
1464 TestOAuth2MintTokenFlow* flow = new TestOAuth2MintTokenFlow(
1465 TestOAuth2MintTokenFlow::ISSUE_ADVICE_SUCCESS, func.get());
1466 EXPECT_CALL(*func.get(), CreateMintTokenFlow(_))
1467 .WillOnce(Return(flow));
1468
1469 scoped_ptr<base::Value> value(utils::RunFunctionAndReturnSingleResult(
1470 func.get(), "[{\"interactive\": true}]", browser()));
1471 std::string access_token;
1472 EXPECT_TRUE(value->GetAsString(&access_token));
1473 EXPECT_EQ(std::string(kAccessToken), access_token);
1474 EXPECT_TRUE(func->login_ui_shown());
1475 EXPECT_TRUE(func->scope_ui_shown());
1476 EXPECT_EQ(IdentityTokenCacheValue::CACHE_STATUS_TOKEN,
1477 GetCachedToken(std::string()).status());
1478 }
1479
IN_PROC_BROWSER_TEST_F(GetAuthTokenFunctionTest,ComponentWithChromeClientId)1480 IN_PROC_BROWSER_TEST_F(GetAuthTokenFunctionTest, ComponentWithChromeClientId) {
1481 scoped_refptr<MockGetAuthTokenFunction> func(new MockGetAuthTokenFunction());
1482 scoped_refptr<const Extension> extension(
1483 CreateExtension(SCOPES | AS_COMPONENT));
1484 func->set_extension(extension.get());
1485 const OAuth2Info& oauth2_info = OAuth2Info::GetOAuth2Info(extension.get());
1486 EXPECT_TRUE(oauth2_info.client_id.empty());
1487 EXPECT_FALSE(func->GetOAuth2ClientId().empty());
1488 EXPECT_NE("client1", func->GetOAuth2ClientId());
1489 }
1490
IN_PROC_BROWSER_TEST_F(GetAuthTokenFunctionTest,ComponentWithNormalClientId)1491 IN_PROC_BROWSER_TEST_F(GetAuthTokenFunctionTest, ComponentWithNormalClientId) {
1492 scoped_refptr<MockGetAuthTokenFunction> func(new MockGetAuthTokenFunction());
1493 scoped_refptr<const Extension> extension(
1494 CreateExtension(CLIENT_ID | SCOPES | AS_COMPONENT));
1495 func->set_extension(extension.get());
1496 EXPECT_EQ("client1", func->GetOAuth2ClientId());
1497 }
1498
IN_PROC_BROWSER_TEST_F(GetAuthTokenFunctionTest,MultiDefaultUser)1499 IN_PROC_BROWSER_TEST_F(GetAuthTokenFunctionTest, MultiDefaultUser) {
1500 SignIn("primary@example.com");
1501 token_service_->IssueRefreshTokenForUser("primary@example.com",
1502 "refresh_token");
1503 SetAccountState(CreateIds("primary@example.com", "1"), true);
1504 SetAccountState(CreateIds("secondary@example.com", "2"), true);
1505
1506 scoped_refptr<FakeGetAuthTokenFunction> func(new FakeGetAuthTokenFunction());
1507 scoped_refptr<const Extension> extension(CreateExtension(CLIENT_ID | SCOPES));
1508 func->set_extension(extension.get());
1509 func->set_mint_token_flow(
1510 scoped_ptr<OAuth2MintTokenFlow>(new TestOAuth2MintTokenFlow(
1511 TestOAuth2MintTokenFlow::MINT_TOKEN_SUCCESS, func.get())));
1512
1513 RunFunctionAsync(func.get(), "[{}]");
1514
1515 token_service_->IssueAllTokensForAccount(
1516 "primary@example.com",
1517 "access_token-primary@example.com",
1518 base::Time::Now() + base::TimeDelta::FromSeconds(3600));
1519
1520 scoped_ptr<base::Value> value(WaitForSingleResult(func.get()));
1521 std::string access_token;
1522 EXPECT_TRUE(value->GetAsString(&access_token));
1523 EXPECT_EQ(std::string(kAccessToken), access_token);
1524 EXPECT_EQ(IdentityTokenCacheValue::CACHE_STATUS_TOKEN,
1525 GetCachedToken(std::string()).status());
1526 EXPECT_EQ("access_token-primary@example.com", func->login_access_token());
1527 }
1528
IN_PROC_BROWSER_TEST_F(GetAuthTokenFunctionTest,MultiPrimaryUser)1529 IN_PROC_BROWSER_TEST_F(GetAuthTokenFunctionTest, MultiPrimaryUser) {
1530 SignIn("primary@example.com");
1531 token_service_->IssueRefreshTokenForUser("primary@example.com",
1532 "refresh_token");
1533 SetAccountState(CreateIds("primary@example.com", "1"), true);
1534 SetAccountState(CreateIds("secondary@example.com", "2"), true);
1535
1536 scoped_refptr<FakeGetAuthTokenFunction> func(new FakeGetAuthTokenFunction());
1537 scoped_refptr<const Extension> extension(CreateExtension(CLIENT_ID | SCOPES));
1538 func->set_extension(extension.get());
1539 func->set_mint_token_flow(
1540 scoped_ptr<OAuth2MintTokenFlow>(new TestOAuth2MintTokenFlow(
1541 TestOAuth2MintTokenFlow::MINT_TOKEN_SUCCESS, func.get())));
1542
1543 RunFunctionAsync(func.get(), "[{\"account\": { \"id\": \"1\" } }]");
1544
1545 token_service_->IssueAllTokensForAccount(
1546 "primary@example.com",
1547 "access_token-primary@example.com",
1548 base::Time::Now() + base::TimeDelta::FromSeconds(3600));
1549
1550 scoped_ptr<base::Value> value(WaitForSingleResult(func.get()));
1551 std::string access_token;
1552 EXPECT_TRUE(value->GetAsString(&access_token));
1553 EXPECT_EQ(std::string(kAccessToken), access_token);
1554 EXPECT_EQ(IdentityTokenCacheValue::CACHE_STATUS_TOKEN,
1555 GetCachedToken(std::string()).status());
1556 EXPECT_EQ("access_token-primary@example.com", func->login_access_token());
1557 }
1558
IN_PROC_BROWSER_TEST_F(GetAuthTokenFunctionTest,MultiSecondaryUser)1559 IN_PROC_BROWSER_TEST_F(GetAuthTokenFunctionTest, MultiSecondaryUser) {
1560 SignIn("primary@example.com");
1561 token_service_->IssueRefreshTokenForUser("secondary@example.com",
1562 "refresh_token");
1563 SetAccountState(CreateIds("primary@example.com", "1"), true);
1564 SetAccountState(CreateIds("secondary@example.com", "2"), true);
1565
1566 scoped_refptr<FakeGetAuthTokenFunction> func(new FakeGetAuthTokenFunction());
1567 scoped_refptr<const Extension> extension(CreateExtension(CLIENT_ID | SCOPES));
1568 func->set_extension(extension.get());
1569 func->set_mint_token_flow(
1570 scoped_ptr<OAuth2MintTokenFlow>(new TestOAuth2MintTokenFlow(
1571 TestOAuth2MintTokenFlow::MINT_TOKEN_SUCCESS, func.get())));
1572
1573 RunFunctionAsync(func.get(), "[{\"account\": { \"id\": \"2\" } }]");
1574
1575 token_service_->IssueAllTokensForAccount(
1576 "secondary@example.com",
1577 "access_token-secondary@example.com",
1578 base::Time::Now() + base::TimeDelta::FromSeconds(3600));
1579
1580 scoped_ptr<base::Value> value(WaitForSingleResult(func.get()));
1581 std::string access_token;
1582 EXPECT_TRUE(value->GetAsString(&access_token));
1583 EXPECT_EQ(std::string(kAccessToken), access_token);
1584 EXPECT_EQ(IdentityTokenCacheValue::CACHE_STATUS_TOKEN,
1585 GetCachedToken("secondary@example.com").status());
1586 EXPECT_EQ("access_token-secondary@example.com", func->login_access_token());
1587 }
1588
1589 // TODO(courage): negative cases for secondary accounts
1590
IN_PROC_BROWSER_TEST_F(GetAuthTokenFunctionTest,ScopesDefault)1591 IN_PROC_BROWSER_TEST_F(GetAuthTokenFunctionTest, ScopesDefault) {
1592 scoped_refptr<MockGetAuthTokenFunction> func(new MockGetAuthTokenFunction());
1593 scoped_refptr<const Extension> extension(CreateExtension(CLIENT_ID | SCOPES));
1594 func->set_extension(extension.get());
1595 EXPECT_CALL(*func.get(), HasLoginToken()).WillOnce(Return(true));
1596 TestOAuth2MintTokenFlow* flow = new TestOAuth2MintTokenFlow(
1597 TestOAuth2MintTokenFlow::MINT_TOKEN_SUCCESS, func.get());
1598 EXPECT_CALL(*func.get(), CreateMintTokenFlow(_)).WillOnce(Return(flow));
1599 scoped_ptr<base::Value> value(
1600 utils::RunFunctionAndReturnSingleResult(func.get(), "[{}]", browser()));
1601 std::string access_token;
1602 EXPECT_TRUE(value->GetAsString(&access_token));
1603 EXPECT_EQ(std::string(kAccessToken), access_token);
1604
1605 const ExtensionTokenKey* token_key = func->extension_token_key();
1606 EXPECT_EQ(2ul, token_key->scopes.size());
1607 EXPECT_TRUE(ContainsKey(token_key->scopes, "scope1"));
1608 EXPECT_TRUE(ContainsKey(token_key->scopes, "scope2"));
1609 }
1610
IN_PROC_BROWSER_TEST_F(GetAuthTokenFunctionTest,ScopesEmpty)1611 IN_PROC_BROWSER_TEST_F(GetAuthTokenFunctionTest, ScopesEmpty) {
1612 scoped_refptr<MockGetAuthTokenFunction> func(new MockGetAuthTokenFunction());
1613 scoped_refptr<const Extension> extension(CreateExtension(CLIENT_ID | SCOPES));
1614 func->set_extension(extension.get());
1615
1616 std::string error(utils::RunFunctionAndReturnError(
1617 func.get(), "[{\"scopes\": []}]", browser()));
1618
1619 EXPECT_EQ(errors::kInvalidScopes, error);
1620 }
1621
IN_PROC_BROWSER_TEST_F(GetAuthTokenFunctionTest,ScopesEmail)1622 IN_PROC_BROWSER_TEST_F(GetAuthTokenFunctionTest, ScopesEmail) {
1623 scoped_refptr<MockGetAuthTokenFunction> func(new MockGetAuthTokenFunction());
1624 scoped_refptr<const Extension> extension(CreateExtension(CLIENT_ID | SCOPES));
1625 func->set_extension(extension.get());
1626 EXPECT_CALL(*func.get(), HasLoginToken()).WillOnce(Return(true));
1627 TestOAuth2MintTokenFlow* flow = new TestOAuth2MintTokenFlow(
1628 TestOAuth2MintTokenFlow::MINT_TOKEN_SUCCESS, func.get());
1629 EXPECT_CALL(*func.get(), CreateMintTokenFlow(_)).WillOnce(Return(flow));
1630 scoped_ptr<base::Value> value(utils::RunFunctionAndReturnSingleResult(
1631 func.get(), "[{\"scopes\": [\"email\"]}]", browser()));
1632 std::string access_token;
1633 EXPECT_TRUE(value->GetAsString(&access_token));
1634 EXPECT_EQ(std::string(kAccessToken), access_token);
1635
1636 const ExtensionTokenKey* token_key = func->extension_token_key();
1637 EXPECT_EQ(1ul, token_key->scopes.size());
1638 EXPECT_TRUE(ContainsKey(token_key->scopes, "email"));
1639 }
1640
IN_PROC_BROWSER_TEST_F(GetAuthTokenFunctionTest,ScopesEmailFooBar)1641 IN_PROC_BROWSER_TEST_F(GetAuthTokenFunctionTest, ScopesEmailFooBar) {
1642 scoped_refptr<MockGetAuthTokenFunction> func(new MockGetAuthTokenFunction());
1643 scoped_refptr<const Extension> extension(CreateExtension(CLIENT_ID | SCOPES));
1644 func->set_extension(extension.get());
1645 EXPECT_CALL(*func.get(), HasLoginToken()).WillOnce(Return(true));
1646 TestOAuth2MintTokenFlow* flow = new TestOAuth2MintTokenFlow(
1647 TestOAuth2MintTokenFlow::MINT_TOKEN_SUCCESS, func.get());
1648 EXPECT_CALL(*func.get(), CreateMintTokenFlow(_)).WillOnce(Return(flow));
1649 scoped_ptr<base::Value> value(utils::RunFunctionAndReturnSingleResult(
1650 func.get(), "[{\"scopes\": [\"email\", \"foo\", \"bar\"]}]", browser()));
1651 std::string access_token;
1652 EXPECT_TRUE(value->GetAsString(&access_token));
1653 EXPECT_EQ(std::string(kAccessToken), access_token);
1654
1655 const ExtensionTokenKey* token_key = func->extension_token_key();
1656 EXPECT_EQ(3ul, token_key->scopes.size());
1657 EXPECT_TRUE(ContainsKey(token_key->scopes, "email"));
1658 EXPECT_TRUE(ContainsKey(token_key->scopes, "foo"));
1659 EXPECT_TRUE(ContainsKey(token_key->scopes, "bar"));
1660 }
1661
1662 class RemoveCachedAuthTokenFunctionTest : public ExtensionBrowserTest {
1663 protected:
InvalidateDefaultToken()1664 bool InvalidateDefaultToken() {
1665 scoped_refptr<IdentityRemoveCachedAuthTokenFunction> func(
1666 new IdentityRemoveCachedAuthTokenFunction);
1667 func->set_extension(utils::CreateEmptyExtension(kExtensionId).get());
1668 return utils::RunFunction(
1669 func.get(),
1670 std::string("[{\"token\": \"") + kAccessToken + "\"}]",
1671 browser(),
1672 extension_function_test_utils::NONE);
1673 }
1674
id_api()1675 IdentityAPI* id_api() {
1676 return IdentityAPI::GetFactoryInstance()->Get(browser()->profile());
1677 }
1678
SetCachedToken(IdentityTokenCacheValue & token_data)1679 void SetCachedToken(IdentityTokenCacheValue& token_data) {
1680 ExtensionTokenKey key(extensions::id_util::GenerateId(kExtensionId),
1681 "test@example.com",
1682 std::set<std::string>());
1683 id_api()->SetCachedToken(key, token_data);
1684 }
1685
GetCachedToken()1686 const IdentityTokenCacheValue& GetCachedToken() {
1687 return id_api()->GetCachedToken(
1688 ExtensionTokenKey(extensions::id_util::GenerateId(kExtensionId),
1689 "test@example.com",
1690 std::set<std::string>()));
1691 }
1692 };
1693
IN_PROC_BROWSER_TEST_F(RemoveCachedAuthTokenFunctionTest,NotFound)1694 IN_PROC_BROWSER_TEST_F(RemoveCachedAuthTokenFunctionTest, NotFound) {
1695 EXPECT_TRUE(InvalidateDefaultToken());
1696 EXPECT_EQ(IdentityTokenCacheValue::CACHE_STATUS_NOTFOUND,
1697 GetCachedToken().status());
1698 }
1699
IN_PROC_BROWSER_TEST_F(RemoveCachedAuthTokenFunctionTest,Advice)1700 IN_PROC_BROWSER_TEST_F(RemoveCachedAuthTokenFunctionTest, Advice) {
1701 IssueAdviceInfo info;
1702 IdentityTokenCacheValue advice(info);
1703 SetCachedToken(advice);
1704 EXPECT_TRUE(InvalidateDefaultToken());
1705 EXPECT_EQ(IdentityTokenCacheValue::CACHE_STATUS_ADVICE,
1706 GetCachedToken().status());
1707 }
1708
IN_PROC_BROWSER_TEST_F(RemoveCachedAuthTokenFunctionTest,NonMatchingToken)1709 IN_PROC_BROWSER_TEST_F(RemoveCachedAuthTokenFunctionTest, NonMatchingToken) {
1710 IdentityTokenCacheValue token("non_matching_token",
1711 base::TimeDelta::FromSeconds(3600));
1712 SetCachedToken(token);
1713 EXPECT_TRUE(InvalidateDefaultToken());
1714 EXPECT_EQ(IdentityTokenCacheValue::CACHE_STATUS_TOKEN,
1715 GetCachedToken().status());
1716 EXPECT_EQ("non_matching_token", GetCachedToken().token());
1717 }
1718
IN_PROC_BROWSER_TEST_F(RemoveCachedAuthTokenFunctionTest,MatchingToken)1719 IN_PROC_BROWSER_TEST_F(RemoveCachedAuthTokenFunctionTest, MatchingToken) {
1720 IdentityTokenCacheValue token(kAccessToken,
1721 base::TimeDelta::FromSeconds(3600));
1722 SetCachedToken(token);
1723 EXPECT_EQ(IdentityTokenCacheValue::CACHE_STATUS_TOKEN,
1724 GetCachedToken().status());
1725 EXPECT_TRUE(InvalidateDefaultToken());
1726 EXPECT_EQ(IdentityTokenCacheValue::CACHE_STATUS_NOTFOUND,
1727 GetCachedToken().status());
1728 }
1729
1730 class LaunchWebAuthFlowFunctionTest : public AsyncExtensionBrowserTest {
1731 public:
SetUpCommandLine(CommandLine * command_line)1732 virtual void SetUpCommandLine(CommandLine* command_line) OVERRIDE {
1733 AsyncExtensionBrowserTest::SetUpCommandLine(command_line);
1734 // Reduce performance test variance by disabling background networking.
1735 command_line->AppendSwitch(switches::kDisableBackgroundNetworking);
1736 }
1737 };
1738
IN_PROC_BROWSER_TEST_F(LaunchWebAuthFlowFunctionTest,UserCloseWindow)1739 IN_PROC_BROWSER_TEST_F(LaunchWebAuthFlowFunctionTest, UserCloseWindow) {
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/interaction_required.html"));
1747
1748 scoped_refptr<IdentityLaunchWebAuthFlowFunction> function(
1749 new IdentityLaunchWebAuthFlowFunction());
1750 scoped_refptr<Extension> empty_extension(
1751 utils::CreateEmptyExtension());
1752 function->set_extension(empty_extension.get());
1753
1754 WaitForGURLAndCloseWindow popup_observer(auth_url);
1755
1756 std::string args = "[{\"interactive\": true, \"url\": \"" +
1757 auth_url.spec() + "\"}]";
1758 RunFunctionAsync(function.get(), args);
1759
1760 popup_observer.Wait();
1761 popup_observer.CloseEmbedderWebContents();
1762
1763 EXPECT_EQ(std::string(errors::kUserRejected), WaitForError(function.get()));
1764 }
1765
IN_PROC_BROWSER_TEST_F(LaunchWebAuthFlowFunctionTest,InteractionRequired)1766 IN_PROC_BROWSER_TEST_F(LaunchWebAuthFlowFunctionTest, InteractionRequired) {
1767 net::SpawnedTestServer https_server(
1768 net::SpawnedTestServer::TYPE_HTTPS,
1769 net::SpawnedTestServer::kLocalhost,
1770 base::FilePath(FILE_PATH_LITERAL(
1771 "chrome/test/data/extensions/api_test/identity")));
1772 ASSERT_TRUE(https_server.Start());
1773 GURL auth_url(https_server.GetURL("files/interaction_required.html"));
1774
1775 scoped_refptr<IdentityLaunchWebAuthFlowFunction> function(
1776 new IdentityLaunchWebAuthFlowFunction());
1777 scoped_refptr<Extension> empty_extension(
1778 utils::CreateEmptyExtension());
1779 function->set_extension(empty_extension.get());
1780
1781 std::string args = "[{\"interactive\": false, \"url\": \"" +
1782 auth_url.spec() + "\"}]";
1783 std::string error =
1784 utils::RunFunctionAndReturnError(function.get(), args, browser());
1785
1786 EXPECT_EQ(std::string(errors::kInteractionRequired), error);
1787 }
1788
IN_PROC_BROWSER_TEST_F(LaunchWebAuthFlowFunctionTest,LoadFailed)1789 IN_PROC_BROWSER_TEST_F(LaunchWebAuthFlowFunctionTest, LoadFailed) {
1790 net::SpawnedTestServer https_server(
1791 net::SpawnedTestServer::TYPE_HTTPS,
1792 net::SpawnedTestServer::kLocalhost,
1793 base::FilePath(FILE_PATH_LITERAL(
1794 "chrome/test/data/extensions/api_test/identity")));
1795 ASSERT_TRUE(https_server.Start());
1796 GURL auth_url(https_server.GetURL("files/five_hundred.html"));
1797
1798 scoped_refptr<IdentityLaunchWebAuthFlowFunction> function(
1799 new IdentityLaunchWebAuthFlowFunction());
1800 scoped_refptr<Extension> empty_extension(
1801 utils::CreateEmptyExtension());
1802 function->set_extension(empty_extension.get());
1803
1804 std::string args = "[{\"interactive\": true, \"url\": \"" +
1805 auth_url.spec() + "\"}]";
1806 std::string error =
1807 utils::RunFunctionAndReturnError(function.get(), args, browser());
1808
1809 EXPECT_EQ(std::string(errors::kPageLoadFailure), error);
1810 }
1811
IN_PROC_BROWSER_TEST_F(LaunchWebAuthFlowFunctionTest,NonInteractiveSuccess)1812 IN_PROC_BROWSER_TEST_F(LaunchWebAuthFlowFunctionTest, NonInteractiveSuccess) {
1813 #if defined(OS_WIN) && defined(USE_ASH)
1814 // Disable this test in Metro+Ash for now (http://crbug.com/262796).
1815 if (CommandLine::ForCurrentProcess()->HasSwitch(switches::kAshBrowserTests))
1816 return;
1817 #endif
1818
1819 scoped_refptr<IdentityLaunchWebAuthFlowFunction> function(
1820 new IdentityLaunchWebAuthFlowFunction());
1821 scoped_refptr<Extension> empty_extension(
1822 utils::CreateEmptyExtension());
1823 function->set_extension(empty_extension.get());
1824
1825 function->InitFinalRedirectURLPrefixForTest("abcdefghij");
1826 scoped_ptr<base::Value> value(utils::RunFunctionAndReturnSingleResult(
1827 function.get(),
1828 "[{\"interactive\": false,"
1829 "\"url\": \"https://abcdefghij.chromiumapp.org/callback#test\"}]",
1830 browser()));
1831
1832 std::string url;
1833 EXPECT_TRUE(value->GetAsString(&url));
1834 EXPECT_EQ(std::string("https://abcdefghij.chromiumapp.org/callback#test"),
1835 url);
1836 }
1837
IN_PROC_BROWSER_TEST_F(LaunchWebAuthFlowFunctionTest,InteractiveFirstNavigationSuccess)1838 IN_PROC_BROWSER_TEST_F(
1839 LaunchWebAuthFlowFunctionTest, InteractiveFirstNavigationSuccess) {
1840 #if defined(OS_WIN) && defined(USE_ASH)
1841 // Disable this test in Metro+Ash for now (http://crbug.com/262796).
1842 if (CommandLine::ForCurrentProcess()->HasSwitch(switches::kAshBrowserTests))
1843 return;
1844 #endif
1845
1846 scoped_refptr<IdentityLaunchWebAuthFlowFunction> function(
1847 new IdentityLaunchWebAuthFlowFunction());
1848 scoped_refptr<Extension> empty_extension(
1849 utils::CreateEmptyExtension());
1850 function->set_extension(empty_extension.get());
1851
1852 function->InitFinalRedirectURLPrefixForTest("abcdefghij");
1853 scoped_ptr<base::Value> value(utils::RunFunctionAndReturnSingleResult(
1854 function.get(),
1855 "[{\"interactive\": true,"
1856 "\"url\": \"https://abcdefghij.chromiumapp.org/callback#test\"}]",
1857 browser()));
1858
1859 std::string url;
1860 EXPECT_TRUE(value->GetAsString(&url));
1861 EXPECT_EQ(std::string("https://abcdefghij.chromiumapp.org/callback#test"),
1862 url);
1863 }
1864
IN_PROC_BROWSER_TEST_F(LaunchWebAuthFlowFunctionTest,DISABLED_InteractiveSecondNavigationSuccess)1865 IN_PROC_BROWSER_TEST_F(LaunchWebAuthFlowFunctionTest,
1866 DISABLED_InteractiveSecondNavigationSuccess) {
1867 net::SpawnedTestServer https_server(
1868 net::SpawnedTestServer::TYPE_HTTPS,
1869 net::SpawnedTestServer::kLocalhost,
1870 base::FilePath(FILE_PATH_LITERAL(
1871 "chrome/test/data/extensions/api_test/identity")));
1872 ASSERT_TRUE(https_server.Start());
1873 GURL auth_url(https_server.GetURL("files/redirect_to_chromiumapp.html"));
1874
1875 scoped_refptr<IdentityLaunchWebAuthFlowFunction> function(
1876 new IdentityLaunchWebAuthFlowFunction());
1877 scoped_refptr<Extension> empty_extension(
1878 utils::CreateEmptyExtension());
1879 function->set_extension(empty_extension.get());
1880
1881 function->InitFinalRedirectURLPrefixForTest("abcdefghij");
1882 std::string args = "[{\"interactive\": true, \"url\": \"" +
1883 auth_url.spec() + "\"}]";
1884 scoped_ptr<base::Value> value(
1885 utils::RunFunctionAndReturnSingleResult(function.get(), args, browser()));
1886
1887 std::string url;
1888 EXPECT_TRUE(value->GetAsString(&url));
1889 EXPECT_EQ(std::string("https://abcdefghij.chromiumapp.org/callback#test"),
1890 url);
1891 }
1892
1893 } // namespace extensions
1894
1895 // Tests the chrome.identity API implemented by custom JS bindings .
IN_PROC_BROWSER_TEST_F(ExtensionApiTest,ChromeIdentityJsBindings)1896 IN_PROC_BROWSER_TEST_F(ExtensionApiTest, ChromeIdentityJsBindings) {
1897 ASSERT_TRUE(RunExtensionTest("identity/js_bindings")) << message_;
1898 }
1899