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/metrics/field_trial.h"
10 #include "base/strings/utf_string_conversions.h"
11 #include "chrome/browser/chrome_notification_types.h"
12 #include "chrome/browser/prerender/prerender_manager.h"
13 #include "chrome/browser/ui/browser.h"
14 #include "chrome/browser/ui/browser_commands.h"
15 #include "chrome/browser/ui/login/login_prompt.h"
16 #include "chrome/browser/ui/tabs/tab_strip_model.h"
17 #include "chrome/test/base/in_process_browser_test.h"
18 #include "chrome/test/base/ui_test_utils.h"
19 #include "content/public/browser/notification_details.h"
20 #include "content/public/browser/notification_source.h"
21 #include "content/public/browser/web_contents.h"
22 #include "content/public/test/browser_test_utils.h"
23 #include "net/base/auth.h"
24 #include "net/dns/mock_host_resolver.h"
26 using content::NavigationController
;
27 using content::OpenURLParams
;
28 using content::Referrer
;
32 class LoginPromptBrowserTest
: public InProcessBrowserTest
{
34 LoginPromptBrowserTest()
35 : bad_password_("incorrect"),
36 bad_username_("nouser"),
38 username_basic_("basicuser"),
39 username_digest_("digestuser") {
40 auth_map_
["foo"] = AuthInfo("testuser", "foopassword");
41 auth_map_
["bar"] = AuthInfo("testuser", "barpassword");
42 auth_map_
["testrealm"] = AuthInfo(username_basic_
, password_
);
47 std::string username_
;
48 std::string password_
;
52 AuthInfo(const std::string
& username
,
53 const std::string
& password
)
54 : username_(username
), password_(password
) {}
57 typedef std::map
<std::string
, AuthInfo
> AuthMap
;
59 void SetAuthFor(LoginHandler
* handler
);
62 std::string bad_password_
;
63 std::string bad_username_
;
64 std::string password_
;
65 std::string username_basic_
;
66 std::string username_digest_
;
69 void LoginPromptBrowserTest::SetAuthFor(LoginHandler
* handler
) {
70 const net::AuthChallengeInfo
* challenge
= handler
->auth_info();
72 ASSERT_TRUE(challenge
);
73 AuthMap::iterator i
= auth_map_
.find(challenge
->realm
);
74 EXPECT_TRUE(auth_map_
.end() != i
);
75 if (i
!= auth_map_
.end()) {
76 const AuthInfo
& info
= i
->second
;
77 handler
->SetAuth(base::UTF8ToUTF16(info
.username_
),
78 base::UTF8ToUTF16(info
.password_
));
82 // Maintains a set of LoginHandlers that are currently active and
83 // keeps a count of the notifications that were observed.
84 class LoginPromptBrowserTestObserver
: public content::NotificationObserver
{
86 LoginPromptBrowserTestObserver()
87 : auth_needed_count_(0),
88 auth_supplied_count_(0),
89 auth_cancelled_count_(0) {}
91 virtual void Observe(int type
,
92 const content::NotificationSource
& source
,
93 const content::NotificationDetails
& details
) OVERRIDE
;
95 void AddHandler(LoginHandler
* handler
);
97 void RemoveHandler(LoginHandler
* handler
);
99 void Register(const content::NotificationSource
& source
);
101 std::list
<LoginHandler
*> handlers_
;
103 // The exact number of notifications we receive is depedent on the
104 // number of requests that were dispatched and is subject to a
105 // number of factors that we don't directly control here. The
106 // values below should only be used qualitatively.
107 int auth_needed_count_
;
108 int auth_supplied_count_
;
109 int auth_cancelled_count_
;
112 content::NotificationRegistrar registrar_
;
114 DISALLOW_COPY_AND_ASSIGN(LoginPromptBrowserTestObserver
);
117 void LoginPromptBrowserTestObserver::Observe(
119 const content::NotificationSource
& source
,
120 const content::NotificationDetails
& details
) {
121 if (type
== chrome::NOTIFICATION_AUTH_NEEDED
) {
122 LoginNotificationDetails
* login_details
=
123 content::Details
<LoginNotificationDetails
>(details
).ptr();
124 AddHandler(login_details
->handler());
125 auth_needed_count_
++;
126 } else if (type
== chrome::NOTIFICATION_AUTH_SUPPLIED
) {
127 AuthSuppliedLoginNotificationDetails
* login_details
=
128 content::Details
<AuthSuppliedLoginNotificationDetails
>(details
).ptr();
129 RemoveHandler(login_details
->handler());
130 auth_supplied_count_
++;
131 } else if (type
== chrome::NOTIFICATION_AUTH_CANCELLED
) {
132 LoginNotificationDetails
* login_details
=
133 content::Details
<LoginNotificationDetails
>(details
).ptr();
134 RemoveHandler(login_details
->handler());
135 auth_cancelled_count_
++;
139 void LoginPromptBrowserTestObserver::AddHandler(LoginHandler
* handler
) {
140 std::list
<LoginHandler
*>::iterator i
= std::find(handlers_
.begin(),
143 EXPECT_TRUE(i
== handlers_
.end());
144 if (i
== handlers_
.end())
145 handlers_
.push_back(handler
);
148 void LoginPromptBrowserTestObserver::RemoveHandler(LoginHandler
* handler
) {
149 std::list
<LoginHandler
*>::iterator i
= std::find(handlers_
.begin(),
152 EXPECT_TRUE(i
!= handlers_
.end());
153 if (i
!= handlers_
.end())
157 void LoginPromptBrowserTestObserver::Register(
158 const content::NotificationSource
& source
) {
159 registrar_
.Add(this, chrome::NOTIFICATION_AUTH_NEEDED
, source
);
160 registrar_
.Add(this, chrome::NOTIFICATION_AUTH_SUPPLIED
, source
);
161 registrar_
.Add(this, chrome::NOTIFICATION_AUTH_CANCELLED
, source
);
165 class WindowedNavigationObserver
166 : public content::WindowedNotificationObserver
{
168 explicit WindowedNavigationObserver(NavigationController
* controller
)
169 : content::WindowedNotificationObserver(
170 T
, content::Source
<NavigationController
>(controller
)) {}
173 // LOAD_STOP observer is special since we want to be able to wait for
174 // multiple LOAD_STOP events.
175 class WindowedLoadStopObserver
176 : public WindowedNavigationObserver
<content::NOTIFICATION_LOAD_STOP
> {
178 WindowedLoadStopObserver(NavigationController
* controller
,
179 int notification_count
)
180 : WindowedNavigationObserver
<content::NOTIFICATION_LOAD_STOP
>(controller
),
181 remaining_notification_count_(notification_count
) {}
183 virtual void Observe(int type
,
184 const content::NotificationSource
& source
,
185 const content::NotificationDetails
& details
) OVERRIDE
;
187 int remaining_notification_count_
; // Number of notifications remaining.
190 void WindowedLoadStopObserver::Observe(
192 const content::NotificationSource
& source
,
193 const content::NotificationDetails
& details
) {
194 if (--remaining_notification_count_
== 0)
195 WindowedNotificationObserver::Observe(type
, source
, details
);
198 typedef WindowedNavigationObserver
<chrome::NOTIFICATION_AUTH_NEEDED
>
199 WindowedAuthNeededObserver
;
201 typedef WindowedNavigationObserver
<chrome::NOTIFICATION_AUTH_CANCELLED
>
202 WindowedAuthCancelledObserver
;
204 typedef WindowedNavigationObserver
<chrome::NOTIFICATION_AUTH_SUPPLIED
>
205 WindowedAuthSuppliedObserver
;
207 const char kPrefetchAuthPage
[] = "files/login/prefetch.html";
209 const char kMultiRealmTestPage
[] = "files/login/multi_realm.html";
210 const int kMultiRealmTestRealmCount
= 2;
212 const char kSingleRealmTestPage
[] = "files/login/single_realm.html";
214 const char* kAuthBasicPage
= "auth-basic";
215 const char* kAuthDigestPage
= "auth-digest";
217 base::string16
ExpectedTitleFromAuth(const base::string16
& username
,
218 const base::string16
& password
) {
219 // The TestServer sets the title to username/password on successful login.
220 return username
+ base::UTF8ToUTF16("/") + password
;
223 // Confirm that <link rel="prefetch"> targetting an auth required
224 // resource does not provide a login dialog. These types of requests
225 // should instead just cancel the auth.
227 // Unfortunately, this test doesn't assert on anything for its
228 // correctness. Instead, it relies on the auth dialog blocking the
229 // browser, and triggering a timeout to cause failure when the
230 // prefetch resource requires authorization.
231 IN_PROC_BROWSER_TEST_F(LoginPromptBrowserTest
, PrefetchAuthCancels
) {
232 ASSERT_TRUE(test_server()->Start());
234 GURL test_page
= test_server()->GetURL(kPrefetchAuthPage
);
236 class SetPrefetchForTest
{
238 explicit SetPrefetchForTest(bool prefetch
)
239 : old_prerender_mode_(prerender::PrerenderManager::GetMode()) {
240 std::string exp_group
= prefetch
? "ExperimentYes" : "ExperimentNo";
241 base::FieldTrialList::CreateFieldTrial("Prefetch", exp_group
);
242 // Disable prerender so this is just a prefetch of the top-level page.
243 prerender::PrerenderManager::SetMode(
244 prerender::PrerenderManager::PRERENDER_MODE_DISABLED
);
247 ~SetPrefetchForTest() {
248 prerender::PrerenderManager::SetMode(old_prerender_mode_
);
252 prerender::PrerenderManager::PrerenderManagerMode old_prerender_mode_
;
253 } set_prefetch_for_test(true);
255 content::WebContents
* contents
=
256 browser()->tab_strip_model()->GetActiveWebContents();
257 NavigationController
* controller
= &contents
->GetController();
258 LoginPromptBrowserTestObserver observer
;
260 observer
.Register(content::Source
<NavigationController
>(controller
));
262 WindowedLoadStopObserver
load_stop_waiter(controller
, 1);
263 browser()->OpenURL(OpenURLParams(
264 test_page
, Referrer(), CURRENT_TAB
, content::PAGE_TRANSITION_TYPED
,
267 load_stop_waiter
.Wait();
268 EXPECT_TRUE(observer
.handlers_
.empty());
269 EXPECT_TRUE(test_server()->Stop());
272 // Test that "Basic" HTTP authentication works.
273 IN_PROC_BROWSER_TEST_F(LoginPromptBrowserTest
, TestBasicAuth
) {
274 ASSERT_TRUE(test_server()->Start());
275 GURL test_page
= test_server()->GetURL(kAuthBasicPage
);
277 content::WebContents
* contents
=
278 browser()->tab_strip_model()->GetActiveWebContents();
279 NavigationController
* controller
= &contents
->GetController();
280 LoginPromptBrowserTestObserver observer
;
282 observer
.Register(content::Source
<NavigationController
>(controller
));
285 WindowedAuthNeededObserver
auth_needed_waiter(controller
);
286 browser()->OpenURL(OpenURLParams(
287 test_page
, Referrer(), CURRENT_TAB
, content::PAGE_TRANSITION_TYPED
,
289 auth_needed_waiter
.Wait();
292 ASSERT_FALSE(observer
.handlers_
.empty());
294 WindowedAuthNeededObserver
auth_needed_waiter(controller
);
295 WindowedAuthSuppliedObserver
auth_supplied_waiter(controller
);
296 LoginHandler
* handler
= *observer
.handlers_
.begin();
298 ASSERT_TRUE(handler
);
299 handler
->SetAuth(base::UTF8ToUTF16(bad_username_
),
300 base::UTF8ToUTF16(bad_password_
));
301 auth_supplied_waiter
.Wait();
303 // The request should be retried after the incorrect password is
304 // supplied. This should result in a new AUTH_NEEDED notification
305 // for the same realm.
306 auth_needed_waiter
.Wait();
309 ASSERT_EQ(1u, observer
.handlers_
.size());
310 WindowedAuthSuppliedObserver
auth_supplied_waiter(controller
);
311 LoginHandler
* handler
= *observer
.handlers_
.begin();
313 auth_supplied_waiter
.Wait();
315 base::string16 expected_title
=
316 ExpectedTitleFromAuth(base::ASCIIToUTF16("basicuser"),
317 base::ASCIIToUTF16("secret"));
318 content::TitleWatcher
title_watcher(contents
, expected_title
);
319 EXPECT_EQ(expected_title
, title_watcher
.WaitAndGetTitle());
322 // Test that "Digest" HTTP authentication works.
323 IN_PROC_BROWSER_TEST_F(LoginPromptBrowserTest
, TestDigestAuth
) {
324 ASSERT_TRUE(test_server()->Start());
325 GURL test_page
= test_server()->GetURL(kAuthDigestPage
);
327 content::WebContents
* contents
=
328 browser()->tab_strip_model()->GetActiveWebContents();
329 NavigationController
* controller
= &contents
->GetController();
330 LoginPromptBrowserTestObserver observer
;
332 observer
.Register(content::Source
<NavigationController
>(controller
));
335 WindowedAuthNeededObserver
auth_needed_waiter(controller
);
336 browser()->OpenURL(OpenURLParams(
337 test_page
, Referrer(), CURRENT_TAB
, content::PAGE_TRANSITION_TYPED
,
339 auth_needed_waiter
.Wait();
342 ASSERT_FALSE(observer
.handlers_
.empty());
344 WindowedAuthNeededObserver
auth_needed_waiter(controller
);
345 WindowedAuthSuppliedObserver
auth_supplied_waiter(controller
);
346 LoginHandler
* handler
= *observer
.handlers_
.begin();
348 ASSERT_TRUE(handler
);
349 handler
->SetAuth(base::UTF8ToUTF16(bad_username_
),
350 base::UTF8ToUTF16(bad_password_
));
351 auth_supplied_waiter
.Wait();
353 // The request should be retried after the incorrect password is
354 // supplied. This should result in a new AUTH_NEEDED notification
355 // for the same realm.
356 auth_needed_waiter
.Wait();
359 ASSERT_EQ(1u, observer
.handlers_
.size());
360 WindowedAuthSuppliedObserver
auth_supplied_waiter(controller
);
361 LoginHandler
* handler
= *observer
.handlers_
.begin();
363 base::string16
username(base::UTF8ToUTF16(username_digest_
));
364 base::string16
password(base::UTF8ToUTF16(password_
));
365 handler
->SetAuth(username
, password
);
366 auth_supplied_waiter
.Wait();
368 base::string16 expected_title
= ExpectedTitleFromAuth(username
, password
);
369 content::TitleWatcher
title_watcher(contents
, expected_title
);
370 EXPECT_EQ(expected_title
, title_watcher
.WaitAndGetTitle());
373 IN_PROC_BROWSER_TEST_F(LoginPromptBrowserTest
, TestTwoAuths
) {
374 ASSERT_TRUE(test_server()->Start());
376 content::WebContents
* contents1
=
377 browser()->tab_strip_model()->GetActiveWebContents();
378 NavigationController
* controller1
= &contents1
->GetController();
379 LoginPromptBrowserTestObserver observer
;
381 observer
.Register(content::Source
<NavigationController
>(controller1
));
384 ui_test_utils::NavigateToURLWithDisposition(
388 ui_test_utils::BROWSER_TEST_WAIT_FOR_TAB
);
390 content::WebContents
* contents2
=
391 browser()->tab_strip_model()->GetActiveWebContents();
392 ASSERT_NE(contents1
, contents2
);
393 NavigationController
* controller2
= &contents2
->GetController();
394 observer
.Register(content::Source
<NavigationController
>(controller2
));
397 WindowedAuthNeededObserver
auth_needed_waiter(controller1
);
398 contents1
->OpenURL(OpenURLParams(
399 test_server()->GetURL(kAuthBasicPage
), Referrer(),
400 CURRENT_TAB
, content::PAGE_TRANSITION_TYPED
, false));
401 auth_needed_waiter
.Wait();
405 WindowedAuthNeededObserver
auth_needed_waiter(controller2
);
406 contents2
->OpenURL(OpenURLParams(
407 test_server()->GetURL(kAuthDigestPage
), Referrer(),
408 CURRENT_TAB
, content::PAGE_TRANSITION_TYPED
, false));
409 auth_needed_waiter
.Wait();
412 ASSERT_EQ(2u, observer
.handlers_
.size());
414 LoginHandler
* handler1
= *observer
.handlers_
.begin();
415 LoginHandler
* handler2
= *(++(observer
.handlers_
.begin()));
417 base::string16 expected_title1
= ExpectedTitleFromAuth(
418 base::UTF8ToUTF16(username_basic_
), base::UTF8ToUTF16(password_
));
419 base::string16 expected_title2
= ExpectedTitleFromAuth(
420 base::UTF8ToUTF16(username_digest_
), base::UTF8ToUTF16(password_
));
421 content::TitleWatcher
title_watcher1(contents1
, expected_title1
);
422 content::TitleWatcher
title_watcher2(contents2
, expected_title2
);
424 handler1
->SetAuth(base::UTF8ToUTF16(username_basic_
),
425 base::UTF8ToUTF16(password_
));
426 handler2
->SetAuth(base::UTF8ToUTF16(username_digest_
),
427 base::UTF8ToUTF16(password_
));
429 EXPECT_EQ(expected_title1
, title_watcher1
.WaitAndGetTitle());
430 EXPECT_EQ(expected_title2
, title_watcher2
.WaitAndGetTitle());
433 // Test login prompt cancellation.
434 IN_PROC_BROWSER_TEST_F(LoginPromptBrowserTest
, TestCancelAuth
) {
435 ASSERT_TRUE(test_server()->Start());
436 GURL auth_page
= test_server()->GetURL(kAuthBasicPage
);
437 GURL no_auth_page_1
= test_server()->GetURL("a");
438 GURL no_auth_page_2
= test_server()->GetURL("b");
439 GURL no_auth_page_3
= test_server()->GetURL("c");
441 content::WebContents
* contents
=
442 browser()->tab_strip_model()->GetActiveWebContents();
443 NavigationController
* controller
= &contents
->GetController();
445 LoginPromptBrowserTestObserver observer
;
446 observer
.Register(content::Source
<NavigationController
>(controller
));
448 // First navigate to an unauthenticated page so we have something to
450 ui_test_utils::NavigateToURL(browser(), no_auth_page_1
);
452 // Navigating while auth is requested is the same as cancelling.
454 // We need to wait for two LOAD_STOP events. One for auth_page and one for
456 WindowedLoadStopObserver
load_stop_waiter(controller
, 2);
457 WindowedAuthNeededObserver
auth_needed_waiter(controller
);
458 browser()->OpenURL(OpenURLParams(
459 auth_page
, Referrer(), CURRENT_TAB
, content::PAGE_TRANSITION_TYPED
,
461 auth_needed_waiter
.Wait();
462 WindowedAuthCancelledObserver
auth_cancelled_waiter(controller
);
463 browser()->OpenURL(OpenURLParams(
464 no_auth_page_2
, Referrer(), CURRENT_TAB
, content::PAGE_TRANSITION_TYPED
,
466 auth_cancelled_waiter
.Wait();
467 load_stop_waiter
.Wait();
468 EXPECT_TRUE(observer
.handlers_
.empty());
471 // Try navigating backwards.
473 // As above, we wait for two LOAD_STOP events; one for each navigation.
474 WindowedLoadStopObserver
load_stop_waiter(controller
, 2);
475 WindowedAuthNeededObserver
auth_needed_waiter(controller
);
476 browser()->OpenURL(OpenURLParams(
477 auth_page
, Referrer(), CURRENT_TAB
, content::PAGE_TRANSITION_TYPED
,
479 auth_needed_waiter
.Wait();
480 WindowedAuthCancelledObserver
auth_cancelled_waiter(controller
);
481 ASSERT_TRUE(chrome::CanGoBack(browser()));
482 chrome::GoBack(browser(), CURRENT_TAB
);
483 auth_cancelled_waiter
.Wait();
484 load_stop_waiter
.Wait();
485 EXPECT_TRUE(observer
.handlers_
.empty());
488 // Now add a page and go back, so we have something to go forward to.
489 ui_test_utils::NavigateToURL(browser(), no_auth_page_3
);
491 WindowedLoadStopObserver
load_stop_waiter(controller
, 1);
492 chrome::GoBack(browser(), CURRENT_TAB
); // Should take us to page 1
493 load_stop_waiter
.Wait();
497 // We wait for two LOAD_STOP events; one for each navigation.
498 WindowedLoadStopObserver
load_stop_waiter(controller
, 2);
499 WindowedAuthNeededObserver
auth_needed_waiter(controller
);
500 browser()->OpenURL(OpenURLParams(
501 auth_page
, Referrer(), CURRENT_TAB
, content::PAGE_TRANSITION_TYPED
,
503 auth_needed_waiter
.Wait();
504 WindowedAuthCancelledObserver
auth_cancelled_waiter(controller
);
505 ASSERT_TRUE(chrome::CanGoForward(browser()));
506 chrome::GoForward(browser(), CURRENT_TAB
); // Should take us to page 3
507 auth_cancelled_waiter
.Wait();
508 load_stop_waiter
.Wait();
509 EXPECT_TRUE(observer
.handlers_
.empty());
512 // Now test that cancelling works as expected.
514 WindowedLoadStopObserver
load_stop_waiter(controller
, 1);
515 WindowedAuthNeededObserver
auth_needed_waiter(controller
);
516 browser()->OpenURL(OpenURLParams(
517 auth_page
, Referrer(), CURRENT_TAB
, content::PAGE_TRANSITION_TYPED
,
519 auth_needed_waiter
.Wait();
520 WindowedAuthCancelledObserver
auth_cancelled_waiter(controller
);
521 LoginHandler
* handler
= *observer
.handlers_
.begin();
522 ASSERT_TRUE(handler
);
523 handler
->CancelAuth();
524 auth_cancelled_waiter
.Wait();
525 load_stop_waiter
.Wait();
526 EXPECT_TRUE(observer
.handlers_
.empty());
530 // Test handling of resources that require authentication even though
531 // the page they are included on doesn't. In this case we should only
532 // present the minimal number of prompts necessary for successfully
533 // displaying the page. First we check whether cancelling works as
535 IN_PROC_BROWSER_TEST_F(LoginPromptBrowserTest
, MultipleRealmCancellation
) {
536 ASSERT_TRUE(test_server()->Start());
537 GURL test_page
= test_server()->GetURL(kMultiRealmTestPage
);
539 content::WebContents
* contents
=
540 browser()->tab_strip_model()->GetActiveWebContents();
541 NavigationController
* controller
= &contents
->GetController();
542 LoginPromptBrowserTestObserver observer
;
544 observer
.Register(content::Source
<NavigationController
>(controller
));
546 WindowedLoadStopObserver
load_stop_waiter(controller
, 1);
549 WindowedAuthNeededObserver
auth_needed_waiter(controller
);
550 browser()->OpenURL(OpenURLParams(
551 test_page
, Referrer(), CURRENT_TAB
, content::PAGE_TRANSITION_TYPED
,
553 auth_needed_waiter
.Wait();
558 while (n_handlers
< kMultiRealmTestRealmCount
) {
559 WindowedAuthNeededObserver
auth_needed_waiter(controller
);
561 while (!observer
.handlers_
.empty()) {
562 WindowedAuthCancelledObserver
auth_cancelled_waiter(controller
);
563 LoginHandler
* handler
= *observer
.handlers_
.begin();
565 ASSERT_TRUE(handler
);
567 handler
->CancelAuth();
568 auth_cancelled_waiter
.Wait();
571 if (n_handlers
< kMultiRealmTestRealmCount
)
572 auth_needed_waiter
.Wait();
575 load_stop_waiter
.Wait();
577 EXPECT_EQ(kMultiRealmTestRealmCount
, n_handlers
);
578 EXPECT_EQ(0, observer
.auth_supplied_count_
);
579 EXPECT_LT(0, observer
.auth_needed_count_
);
580 EXPECT_LT(0, observer
.auth_cancelled_count_
);
581 EXPECT_TRUE(test_server()->Stop());
584 // Similar to the MultipleRealmCancellation test above, but tests
585 // whether supplying credentials work as exepcted.
586 IN_PROC_BROWSER_TEST_F(LoginPromptBrowserTest
, MultipleRealmConfirmation
) {
587 ASSERT_TRUE(test_server()->Start());
588 GURL test_page
= test_server()->GetURL(kMultiRealmTestPage
);
590 content::WebContents
* contents
=
591 browser()->tab_strip_model()->GetActiveWebContents();
592 NavigationController
* controller
= &contents
->GetController();
593 LoginPromptBrowserTestObserver observer
;
595 observer
.Register(content::Source
<NavigationController
>(controller
));
597 WindowedLoadStopObserver
load_stop_waiter(controller
, 1);
601 WindowedAuthNeededObserver
auth_needed_waiter(controller
);
603 browser()->OpenURL(OpenURLParams(
604 test_page
, Referrer(), CURRENT_TAB
, content::PAGE_TRANSITION_TYPED
,
606 auth_needed_waiter
.Wait();
609 while (n_handlers
< kMultiRealmTestRealmCount
) {
610 WindowedAuthNeededObserver
auth_needed_waiter(controller
);
612 while (!observer
.handlers_
.empty()) {
613 WindowedAuthSuppliedObserver
auth_supplied_waiter(controller
);
614 LoginHandler
* handler
= *observer
.handlers_
.begin();
616 ASSERT_TRUE(handler
);
619 auth_supplied_waiter
.Wait();
622 if (n_handlers
< kMultiRealmTestRealmCount
)
623 auth_needed_waiter
.Wait();
626 load_stop_waiter
.Wait();
628 EXPECT_EQ(kMultiRealmTestRealmCount
, n_handlers
);
629 EXPECT_LT(0, observer
.auth_needed_count_
);
630 EXPECT_LT(0, observer
.auth_supplied_count_
);
631 EXPECT_EQ(0, observer
.auth_cancelled_count_
);
632 EXPECT_TRUE(test_server()->Stop());
635 // Testing for recovery from an incorrect password for the case where
636 // there are multiple authenticated resources.
637 IN_PROC_BROWSER_TEST_F(LoginPromptBrowserTest
, IncorrectConfirmation
) {
638 ASSERT_TRUE(test_server()->Start());
639 GURL test_page
= test_server()->GetURL(kSingleRealmTestPage
);
641 content::WebContents
* contents
=
642 browser()->tab_strip_model()->GetActiveWebContents();
643 NavigationController
* controller
= &contents
->GetController();
644 LoginPromptBrowserTestObserver observer
;
646 observer
.Register(content::Source
<NavigationController
>(controller
));
649 WindowedAuthNeededObserver
auth_needed_waiter(controller
);
650 browser()->OpenURL(OpenURLParams(
651 test_page
, Referrer(), CURRENT_TAB
, content::PAGE_TRANSITION_TYPED
,
653 auth_needed_waiter
.Wait();
656 EXPECT_FALSE(observer
.handlers_
.empty());
658 if (!observer
.handlers_
.empty()) {
659 WindowedAuthNeededObserver
auth_needed_waiter(controller
);
660 WindowedAuthSuppliedObserver
auth_supplied_waiter(controller
);
661 LoginHandler
* handler
= *observer
.handlers_
.begin();
663 ASSERT_TRUE(handler
);
664 handler
->SetAuth(base::UTF8ToUTF16(bad_username_
),
665 base::UTF8ToUTF16(bad_password_
));
666 auth_supplied_waiter
.Wait();
668 // The request should be retried after the incorrect password is
669 // supplied. This should result in a new AUTH_NEEDED notification
670 // for the same realm.
671 auth_needed_waiter
.Wait();
676 while (n_handlers
< 1) {
677 WindowedAuthNeededObserver
auth_needed_waiter(controller
);
679 while (!observer
.handlers_
.empty()) {
680 WindowedAuthSuppliedObserver
auth_supplied_waiter(controller
);
681 LoginHandler
* handler
= *observer
.handlers_
.begin();
683 ASSERT_TRUE(handler
);
686 auth_supplied_waiter
.Wait();
690 auth_needed_waiter
.Wait();
693 // The single realm test has only one realm, and thus only one login
695 EXPECT_EQ(1, n_handlers
);
696 EXPECT_LT(0, observer
.auth_needed_count_
);
697 EXPECT_EQ(0, observer
.auth_cancelled_count_
);
698 EXPECT_EQ(observer
.auth_needed_count_
, observer
.auth_supplied_count_
);
699 EXPECT_TRUE(test_server()->Stop());
702 // If the favicon is an authenticated resource, we shouldn't prompt
703 // for credentials. The same URL, if requested elsewhere should
704 // prompt for credentials.
705 IN_PROC_BROWSER_TEST_F(LoginPromptBrowserTest
, NoLoginPromptForFavicon
) {
706 const char* kFaviconTestPage
= "files/login/has_favicon.html";
707 const char* kFaviconResource
= "auth-basic/favicon.gif";
709 ASSERT_TRUE(test_server()->Start());
711 content::WebContents
* contents
=
712 browser()->tab_strip_model()->GetActiveWebContents();
713 NavigationController
* controller
= &contents
->GetController();
714 LoginPromptBrowserTestObserver observer
;
716 observer
.Register(content::Source
<NavigationController
>(controller
));
718 // First load a page that has a favicon that requires
719 // authentication. There should be no login prompt.
721 GURL test_page
= test_server()->GetURL(kFaviconTestPage
);
722 WindowedLoadStopObserver
load_stop_waiter(controller
, 1);
723 browser()->OpenURL(OpenURLParams(
724 test_page
, Referrer(), CURRENT_TAB
, content::PAGE_TRANSITION_TYPED
,
726 load_stop_waiter
.Wait();
729 // Now request the same favicon, but directly as the document.
730 // There should be one login prompt.
732 GURL test_page
= test_server()->GetURL(kFaviconResource
);
733 WindowedLoadStopObserver
load_stop_waiter(controller
, 1);
734 WindowedAuthNeededObserver
auth_needed_waiter(controller
);
735 browser()->OpenURL(OpenURLParams(
736 test_page
, Referrer(), CURRENT_TAB
, content::PAGE_TRANSITION_TYPED
,
738 auth_needed_waiter
.Wait();
739 ASSERT_EQ(1u, observer
.handlers_
.size());
741 while (!observer
.handlers_
.empty()) {
742 WindowedAuthCancelledObserver
auth_cancelled_waiter(controller
);
743 LoginHandler
* handler
= *observer
.handlers_
.begin();
745 ASSERT_TRUE(handler
);
746 handler
->CancelAuth();
747 auth_cancelled_waiter
.Wait();
750 load_stop_waiter
.Wait();
753 EXPECT_EQ(0, observer
.auth_supplied_count_
);
754 EXPECT_EQ(1, observer
.auth_needed_count_
);
755 EXPECT_EQ(1, observer
.auth_cancelled_count_
);
756 EXPECT_TRUE(test_server()->Stop());
759 // Block crossdomain image login prompting as a phishing defense.
760 IN_PROC_BROWSER_TEST_F(LoginPromptBrowserTest
,
761 BlockCrossdomainPrompt
) {
762 const char* kTestPage
= "files/login/load_img_from_b.html";
764 host_resolver()->AddRule("www.a.com", "127.0.0.1");
765 host_resolver()->AddRule("www.b.com", "127.0.0.1");
766 ASSERT_TRUE(test_server()->Start());
768 content::WebContents
* contents
=
769 browser()->tab_strip_model()->GetActiveWebContents();
770 NavigationController
* controller
= &contents
->GetController();
771 LoginPromptBrowserTestObserver observer
;
772 observer
.Register(content::Source
<NavigationController
>(controller
));
774 // Load a page that has a cross-domain sub-resource authentication.
775 // There should be no login prompt.
777 GURL test_page
= test_server()->GetURL(kTestPage
);
778 ASSERT_EQ("127.0.0.1", test_page
.host());
780 // Change the host from 127.0.0.1 to www.a.com so that when the
781 // page tries to load from b, it will be cross-origin.
782 std::string
new_host("www.a.com");
783 GURL::Replacements replacements
;
784 replacements
.SetHostStr(new_host
);
785 test_page
= test_page
.ReplaceComponents(replacements
);
787 WindowedLoadStopObserver
load_stop_waiter(controller
, 1);
788 browser()->OpenURL(OpenURLParams(
789 test_page
, Referrer(), CURRENT_TAB
, content::PAGE_TRANSITION_TYPED
,
791 load_stop_waiter
.Wait();
794 EXPECT_EQ(0, observer
.auth_needed_count_
);
796 // Now request the same page, but from the same origin.
797 // There should be one login prompt.
799 GURL test_page
= test_server()->GetURL(kTestPage
);
800 ASSERT_EQ("127.0.0.1", test_page
.host());
802 // Change the host from 127.0.0.1 to www.b.com so that when the
803 // page tries to load from b, it will be same-origin.
804 std::string
new_host("www.b.com");
805 GURL::Replacements replacements
;
806 replacements
.SetHostStr(new_host
);
807 test_page
= test_page
.ReplaceComponents(replacements
);
809 WindowedAuthNeededObserver
auth_needed_waiter(controller
);
810 browser()->OpenURL(OpenURLParams(
811 test_page
, Referrer(), CURRENT_TAB
, content::PAGE_TRANSITION_TYPED
,
813 auth_needed_waiter
.Wait();
814 ASSERT_EQ(1u, observer
.handlers_
.size());
816 while (!observer
.handlers_
.empty()) {
817 WindowedAuthCancelledObserver
auth_cancelled_waiter(controller
);
818 LoginHandler
* handler
= *observer
.handlers_
.begin();
820 ASSERT_TRUE(handler
);
821 handler
->CancelAuth();
822 auth_cancelled_waiter
.Wait();
826 EXPECT_EQ(1, observer
.auth_needed_count_
);
827 EXPECT_TRUE(test_server()->Stop());
830 // Allow crossdomain iframe login prompting despite the above.
831 IN_PROC_BROWSER_TEST_F(LoginPromptBrowserTest
,
832 AllowCrossdomainPrompt
) {
833 const char* kTestPage
= "files/login/load_iframe_from_b.html";
835 host_resolver()->AddRule("www.a.com", "127.0.0.1");
836 host_resolver()->AddRule("www.b.com", "127.0.0.1");
837 ASSERT_TRUE(test_server()->Start());
839 content::WebContents
* contents
=
840 browser()->tab_strip_model()->GetActiveWebContents();
841 NavigationController
* controller
= &contents
->GetController();
842 LoginPromptBrowserTestObserver observer
;
843 observer
.Register(content::Source
<NavigationController
>(controller
));
845 // Load a page that has a cross-domain iframe authentication.
847 GURL test_page
= test_server()->GetURL(kTestPage
);
848 ASSERT_EQ("127.0.0.1", test_page
.host());
850 // Change the host from 127.0.0.1 to www.a.com so that when the
851 // page tries to load from b, it will be cross-origin.
852 std::string
new_host("www.a.com");
853 GURL::Replacements replacements
;
854 replacements
.SetHostStr(new_host
);
855 test_page
= test_page
.ReplaceComponents(replacements
);
857 WindowedAuthNeededObserver
auth_needed_waiter(controller
);
858 browser()->OpenURL(OpenURLParams(
859 test_page
, Referrer(), CURRENT_TAB
, content::PAGE_TRANSITION_TYPED
,
861 auth_needed_waiter
.Wait();
862 ASSERT_EQ(1u, observer
.handlers_
.size());
864 while (!observer
.handlers_
.empty()) {
865 WindowedAuthCancelledObserver
auth_cancelled_waiter(controller
);
866 LoginHandler
* handler
= *observer
.handlers_
.begin();
868 ASSERT_TRUE(handler
);
869 handler
->CancelAuth();
870 auth_cancelled_waiter
.Wait();
874 EXPECT_EQ(1, observer
.auth_needed_count_
);
875 EXPECT_TRUE(test_server()->Stop());
878 IN_PROC_BROWSER_TEST_F(LoginPromptBrowserTest
, SupplyRedundantAuths
) {
879 ASSERT_TRUE(test_server()->Start());
881 // Get NavigationController for tab 1.
882 content::WebContents
* contents_1
=
883 browser()->tab_strip_model()->GetActiveWebContents();
884 NavigationController
* controller_1
= &contents_1
->GetController();
887 ui_test_utils::NavigateToURLWithDisposition(
891 ui_test_utils::BROWSER_TEST_WAIT_FOR_TAB
);
893 // Get NavigationController for tab 2.
894 content::WebContents
* contents_2
=
895 browser()->tab_strip_model()->GetActiveWebContents();
896 ASSERT_NE(contents_1
, contents_2
);
897 NavigationController
* controller_2
= &contents_2
->GetController();
899 LoginPromptBrowserTestObserver observer
;
900 observer
.Register(content::Source
<NavigationController
>(controller_1
));
901 observer
.Register(content::Source
<NavigationController
>(controller_2
));
904 // Open different auth urls in each tab.
905 WindowedAuthNeededObserver
auth_needed_waiter_1(controller_1
);
906 WindowedAuthNeededObserver
auth_needed_waiter_2(controller_2
);
907 contents_1
->OpenURL(OpenURLParams(
908 test_server()->GetURL("auth-basic/1"),
911 content::PAGE_TRANSITION_TYPED
,
913 contents_2
->OpenURL(OpenURLParams(
914 test_server()->GetURL("auth-basic/2"),
917 content::PAGE_TRANSITION_TYPED
,
919 auth_needed_waiter_1
.Wait();
920 auth_needed_waiter_2
.Wait();
922 ASSERT_EQ(2U, observer
.handlers_
.size());
924 // Supply auth in one of the tabs.
925 WindowedAuthSuppliedObserver
auth_supplied_waiter_1(controller_1
);
926 WindowedAuthSuppliedObserver
auth_supplied_waiter_2(controller_2
);
927 LoginHandler
* handler_1
= *observer
.handlers_
.begin();
928 ASSERT_TRUE(handler_1
);
929 SetAuthFor(handler_1
);
931 // Both tabs should be authenticated.
932 auth_supplied_waiter_1
.Wait();
933 auth_supplied_waiter_2
.Wait();
936 EXPECT_EQ(2, observer
.auth_needed_count_
);
937 EXPECT_EQ(2, observer
.auth_supplied_count_
);
938 EXPECT_EQ(0, observer
.auth_cancelled_count_
);
939 EXPECT_TRUE(test_server()->Stop());
942 IN_PROC_BROWSER_TEST_F(LoginPromptBrowserTest
, CancelRedundantAuths
) {
943 ASSERT_TRUE(test_server()->Start());
945 // Get NavigationController for tab 1.
946 content::WebContents
* contents_1
=
947 browser()->tab_strip_model()->GetActiveWebContents();
948 NavigationController
* controller_1
= &contents_1
->GetController();
951 ui_test_utils::NavigateToURLWithDisposition(
955 ui_test_utils::BROWSER_TEST_WAIT_FOR_TAB
);
957 // Get NavigationController for tab 2.
958 content::WebContents
* contents_2
=
959 browser()->tab_strip_model()->GetActiveWebContents();
960 ASSERT_NE(contents_1
, contents_2
);
961 NavigationController
* controller_2
= &contents_2
->GetController();
963 LoginPromptBrowserTestObserver observer
;
964 observer
.Register(content::Source
<NavigationController
>(controller_1
));
965 observer
.Register(content::Source
<NavigationController
>(controller_2
));
968 // Open different auth urls in each tab.
969 WindowedAuthNeededObserver
auth_needed_waiter_1(controller_1
);
970 WindowedAuthNeededObserver
auth_needed_waiter_2(controller_2
);
971 contents_1
->OpenURL(OpenURLParams(
972 test_server()->GetURL("auth-basic/1"),
975 content::PAGE_TRANSITION_TYPED
,
977 contents_2
->OpenURL(OpenURLParams(
978 test_server()->GetURL("auth-basic/2"),
981 content::PAGE_TRANSITION_TYPED
,
983 auth_needed_waiter_1
.Wait();
984 auth_needed_waiter_2
.Wait();
986 ASSERT_EQ(2U, observer
.handlers_
.size());
988 // Cancel auth in one of the tabs.
989 WindowedAuthCancelledObserver
auth_cancelled_waiter_1(controller_1
);
990 WindowedAuthCancelledObserver
auth_cancelled_waiter_2(controller_2
);
991 LoginHandler
* handler_1
= *observer
.handlers_
.begin();
992 ASSERT_TRUE(handler_1
);
993 handler_1
->CancelAuth();
995 // Both tabs should cancel auth.
996 auth_cancelled_waiter_1
.Wait();
997 auth_cancelled_waiter_2
.Wait();
1000 EXPECT_EQ(2, observer
.auth_needed_count_
);
1001 EXPECT_EQ(0, observer
.auth_supplied_count_
);
1002 EXPECT_EQ(2, observer
.auth_cancelled_count_
);
1003 EXPECT_TRUE(test_server()->Stop());
1006 IN_PROC_BROWSER_TEST_F(LoginPromptBrowserTest
,
1007 SupplyRedundantAuthsMultiProfile
) {
1008 ASSERT_TRUE(test_server()->Start());
1010 // Get NavigationController for regular tab.
1011 content::WebContents
* contents
=
1012 browser()->tab_strip_model()->GetActiveWebContents();
1013 NavigationController
* controller
= &contents
->GetController();
1015 // Open an incognito window.
1016 Browser
* browser_incognito
= CreateIncognitoBrowser();
1018 // Get NavigationController for incognito tab.
1019 content::WebContents
* contents_incognito
=
1020 browser_incognito
->tab_strip_model()->GetActiveWebContents();
1021 ASSERT_NE(contents
, contents_incognito
);
1022 NavigationController
* controller_incognito
=
1023 &contents_incognito
->GetController();
1025 LoginPromptBrowserTestObserver observer
;
1026 observer
.Register(content::Source
<NavigationController
>(controller
));
1027 LoginPromptBrowserTestObserver observer_incognito
;
1028 observer_incognito
.Register(
1029 content::Source
<NavigationController
>(controller_incognito
));
1032 // Open an auth url in each window.
1033 WindowedAuthNeededObserver
auth_needed_waiter(controller
);
1034 WindowedAuthNeededObserver
auth_needed_waiter_incognito(
1035 controller_incognito
);
1036 contents
->OpenURL(OpenURLParams(
1037 test_server()->GetURL("auth-basic/1"),
1038 content::Referrer(),
1040 content::PAGE_TRANSITION_TYPED
,
1042 contents_incognito
->OpenURL(OpenURLParams(
1043 test_server()->GetURL("auth-basic/2"),
1044 content::Referrer(),
1046 content::PAGE_TRANSITION_TYPED
,
1048 auth_needed_waiter
.Wait();
1049 auth_needed_waiter_incognito
.Wait();
1051 ASSERT_EQ(1U, observer
.handlers_
.size());
1052 ASSERT_EQ(1U, observer_incognito
.handlers_
.size());
1054 // Supply auth in regular tab.
1055 WindowedAuthSuppliedObserver
auth_supplied_waiter(controller
);
1056 LoginHandler
* handler
= *observer
.handlers_
.begin();
1057 ASSERT_TRUE(handler
);
1058 SetAuthFor(handler
);
1060 // Regular tab should be authenticated.
1061 auth_supplied_waiter
.Wait();
1063 // There's not really a way to wait for the incognito window to "do
1064 // nothing". Run anything pending in the message loop just to be sure.
1065 // (This shouldn't be necessary since notifications are synchronous, but
1066 // maybe it will help avoid flake someday in the future..)
1067 content::RunAllPendingInMessageLoop();
1070 EXPECT_EQ(1, observer
.auth_needed_count_
);
1071 EXPECT_EQ(1, observer
.auth_supplied_count_
);
1072 EXPECT_EQ(0, observer
.auth_cancelled_count_
);
1073 EXPECT_EQ(1, observer_incognito
.auth_needed_count_
);
1074 EXPECT_EQ(0, observer_incognito
.auth_supplied_count_
);
1075 EXPECT_EQ(0, observer_incognito
.auth_cancelled_count_
);
1076 EXPECT_TRUE(test_server()->Stop());