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/ssl/ssl_blocking_page.h"
14 #include "chrome/browser/ui/browser.h"
15 #include "chrome/browser/ui/browser_commands.h"
16 #include "chrome/browser/ui/login/login_interstitial_delegate.h"
17 #include "chrome/browser/ui/login/login_prompt.h"
18 #include "chrome/browser/ui/login/login_prompt_test_utils.h"
19 #include "chrome/browser/ui/tabs/tab_strip_model.h"
20 #include "chrome/test/base/in_process_browser_test.h"
21 #include "chrome/test/base/ui_test_utils.h"
22 #include "content/public/browser/interstitial_page.h"
23 #include "content/public/browser/notification_details.h"
24 #include "content/public/browser/notification_source.h"
25 #include "content/public/browser/web_contents.h"
26 #include "content/public/test/browser_test_utils.h"
27 #include "content/public/test/test_navigation_observer.h"
28 #include "net/base/auth.h"
29 #include "net/dns/mock_host_resolver.h"
30 #include "net/test/spawned_test_server/spawned_test_server.h"
32 using content::NavigationController
;
33 using content::OpenURLParams
;
34 using content::Referrer
;
38 class LoginPromptBrowserTest
: public InProcessBrowserTest
{
40 LoginPromptBrowserTest()
41 : bad_password_("incorrect"),
42 bad_username_("nouser"),
44 username_basic_("basicuser"),
45 username_digest_("digestuser") {
46 auth_map_
["foo"] = AuthInfo("testuser", "foopassword");
47 auth_map_
["bar"] = AuthInfo("testuser", "barpassword");
48 auth_map_
["testrealm"] = AuthInfo(username_basic_
, password_
);
53 std::string username_
;
54 std::string password_
;
58 AuthInfo(const std::string
& username
,
59 const std::string
& password
)
60 : username_(username
), password_(password
) {}
63 typedef std::map
<std::string
, AuthInfo
> AuthMap
;
65 void SetAuthFor(LoginHandler
* handler
);
67 void TestCrossOriginPrompt(const GURL
& visit_url
,
68 const std::string
& landing_host
) const;
71 std::string bad_password_
;
72 std::string bad_username_
;
73 std::string password_
;
74 std::string username_basic_
;
75 std::string username_digest_
;
78 void LoginPromptBrowserTest::SetAuthFor(LoginHandler
* handler
) {
79 const net::AuthChallengeInfo
* challenge
= handler
->auth_info();
81 ASSERT_TRUE(challenge
);
82 AuthMap::iterator i
= auth_map_
.find(challenge
->realm
);
83 EXPECT_TRUE(auth_map_
.end() != i
);
84 if (i
!= auth_map_
.end()) {
85 const AuthInfo
& info
= i
->second
;
86 handler
->SetAuth(base::UTF8ToUTF16(info
.username_
),
87 base::UTF8ToUTF16(info
.password_
));
91 const char kPrefetchAuthPage
[] = "files/login/prefetch.html";
93 const char kMultiRealmTestPage
[] = "files/login/multi_realm.html";
94 const int kMultiRealmTestRealmCount
= 2;
96 const char kSingleRealmTestPage
[] = "files/login/single_realm.html";
98 const char* kAuthBasicPage
= "auth-basic";
99 const char* kAuthDigestPage
= "auth-digest";
101 base::string16
ExpectedTitleFromAuth(const base::string16
& username
,
102 const base::string16
& password
) {
103 // The TestServer sets the title to username/password on successful login.
104 return username
+ base::UTF8ToUTF16("/") + password
;
107 // Confirm that <link rel="prefetch"> targetting an auth required
108 // resource does not provide a login dialog. These types of requests
109 // should instead just cancel the auth.
111 // Unfortunately, this test doesn't assert on anything for its
112 // correctness. Instead, it relies on the auth dialog blocking the
113 // browser, and triggering a timeout to cause failure when the
114 // prefetch resource requires authorization.
115 IN_PROC_BROWSER_TEST_F(LoginPromptBrowserTest
, PrefetchAuthCancels
) {
116 ASSERT_TRUE(test_server()->Start());
118 GURL test_page
= test_server()->GetURL(kPrefetchAuthPage
);
120 class SetPrefetchForTest
{
122 explicit SetPrefetchForTest(bool prefetch
)
123 : old_prerender_mode_(prerender::PrerenderManager::GetMode()) {
124 std::string exp_group
= prefetch
? "ExperimentYes" : "ExperimentNo";
125 base::FieldTrialList::CreateFieldTrial("Prefetch", exp_group
);
126 // Disable prerender so this is just a prefetch of the top-level page.
127 prerender::PrerenderManager::SetMode(
128 prerender::PrerenderManager::PRERENDER_MODE_DISABLED
);
131 ~SetPrefetchForTest() {
132 prerender::PrerenderManager::SetMode(old_prerender_mode_
);
136 prerender::PrerenderManager::PrerenderManagerMode old_prerender_mode_
;
137 } set_prefetch_for_test(true);
139 content::WebContents
* contents
=
140 browser()->tab_strip_model()->GetActiveWebContents();
141 NavigationController
* controller
= &contents
->GetController();
142 LoginPromptBrowserTestObserver observer
;
144 observer
.Register(content::Source
<NavigationController
>(controller
));
146 WindowedLoadStopObserver
load_stop_waiter(controller
, 1);
147 browser()->OpenURL(OpenURLParams(
148 test_page
, Referrer(), CURRENT_TAB
, ui::PAGE_TRANSITION_TYPED
,
151 load_stop_waiter
.Wait();
152 EXPECT_TRUE(observer
.handlers().empty());
153 EXPECT_TRUE(test_server()->Stop());
156 // Test that "Basic" HTTP authentication works.
157 IN_PROC_BROWSER_TEST_F(LoginPromptBrowserTest
, TestBasicAuth
) {
158 ASSERT_TRUE(test_server()->Start());
159 GURL test_page
= test_server()->GetURL(kAuthBasicPage
);
161 content::WebContents
* contents
=
162 browser()->tab_strip_model()->GetActiveWebContents();
163 NavigationController
* controller
= &contents
->GetController();
164 LoginPromptBrowserTestObserver observer
;
166 observer
.Register(content::Source
<NavigationController
>(controller
));
169 WindowedAuthNeededObserver
auth_needed_waiter(controller
);
170 browser()->OpenURL(OpenURLParams(
171 test_page
, Referrer(), CURRENT_TAB
, ui::PAGE_TRANSITION_TYPED
,
173 auth_needed_waiter
.Wait();
176 ASSERT_FALSE(observer
.handlers().empty());
178 WindowedAuthNeededObserver
auth_needed_waiter(controller
);
179 WindowedAuthSuppliedObserver
auth_supplied_waiter(controller
);
180 LoginHandler
* handler
= *observer
.handlers().begin();
182 ASSERT_TRUE(handler
);
183 handler
->SetAuth(base::UTF8ToUTF16(bad_username_
),
184 base::UTF8ToUTF16(bad_password_
));
185 auth_supplied_waiter
.Wait();
187 // The request should be retried after the incorrect password is
188 // supplied. This should result in a new AUTH_NEEDED notification
189 // for the same realm.
190 auth_needed_waiter
.Wait();
193 ASSERT_EQ(1u, observer
.handlers().size());
194 WindowedAuthSuppliedObserver
auth_supplied_waiter(controller
);
195 LoginHandler
* handler
= *observer
.handlers().begin();
197 auth_supplied_waiter
.Wait();
199 base::string16 expected_title
=
200 ExpectedTitleFromAuth(base::ASCIIToUTF16("basicuser"),
201 base::ASCIIToUTF16("secret"));
202 content::TitleWatcher
title_watcher(contents
, expected_title
);
203 EXPECT_EQ(expected_title
, title_watcher
.WaitAndGetTitle());
206 // Test that "Digest" HTTP authentication works.
207 IN_PROC_BROWSER_TEST_F(LoginPromptBrowserTest
, TestDigestAuth
) {
208 ASSERT_TRUE(test_server()->Start());
209 GURL test_page
= test_server()->GetURL(kAuthDigestPage
);
211 content::WebContents
* contents
=
212 browser()->tab_strip_model()->GetActiveWebContents();
213 NavigationController
* controller
= &contents
->GetController();
214 LoginPromptBrowserTestObserver observer
;
216 observer
.Register(content::Source
<NavigationController
>(controller
));
219 WindowedAuthNeededObserver
auth_needed_waiter(controller
);
220 browser()->OpenURL(OpenURLParams(
221 test_page
, Referrer(), CURRENT_TAB
, ui::PAGE_TRANSITION_TYPED
,
223 auth_needed_waiter
.Wait();
226 ASSERT_FALSE(observer
.handlers().empty());
228 WindowedAuthNeededObserver
auth_needed_waiter(controller
);
229 WindowedAuthSuppliedObserver
auth_supplied_waiter(controller
);
230 LoginHandler
* handler
= *observer
.handlers().begin();
232 ASSERT_TRUE(handler
);
233 handler
->SetAuth(base::UTF8ToUTF16(bad_username_
),
234 base::UTF8ToUTF16(bad_password_
));
235 auth_supplied_waiter
.Wait();
237 // The request should be retried after the incorrect password is
238 // supplied. This should result in a new AUTH_NEEDED notification
239 // for the same realm.
240 auth_needed_waiter
.Wait();
243 ASSERT_EQ(1u, observer
.handlers().size());
244 WindowedAuthSuppliedObserver
auth_supplied_waiter(controller
);
245 LoginHandler
* handler
= *observer
.handlers().begin();
247 base::string16
username(base::UTF8ToUTF16(username_digest_
));
248 base::string16
password(base::UTF8ToUTF16(password_
));
249 handler
->SetAuth(username
, password
);
250 auth_supplied_waiter
.Wait();
252 base::string16 expected_title
= ExpectedTitleFromAuth(username
, password
);
253 content::TitleWatcher
title_watcher(contents
, expected_title
);
254 EXPECT_EQ(expected_title
, title_watcher
.WaitAndGetTitle());
257 IN_PROC_BROWSER_TEST_F(LoginPromptBrowserTest
, TestTwoAuths
) {
258 ASSERT_TRUE(test_server()->Start());
260 content::WebContents
* contents1
=
261 browser()->tab_strip_model()->GetActiveWebContents();
262 NavigationController
* controller1
= &contents1
->GetController();
263 LoginPromptBrowserTestObserver observer
;
265 observer
.Register(content::Source
<NavigationController
>(controller1
));
268 ui_test_utils::NavigateToURLWithDisposition(
272 ui_test_utils::BROWSER_TEST_WAIT_FOR_TAB
);
274 content::WebContents
* contents2
=
275 browser()->tab_strip_model()->GetActiveWebContents();
276 ASSERT_NE(contents1
, contents2
);
277 NavigationController
* controller2
= &contents2
->GetController();
278 observer
.Register(content::Source
<NavigationController
>(controller2
));
281 WindowedAuthNeededObserver
auth_needed_waiter(controller1
);
282 contents1
->OpenURL(OpenURLParams(
283 test_server()->GetURL(kAuthBasicPage
), Referrer(),
284 CURRENT_TAB
, ui::PAGE_TRANSITION_TYPED
, false));
285 auth_needed_waiter
.Wait();
289 WindowedAuthNeededObserver
auth_needed_waiter(controller2
);
290 contents2
->OpenURL(OpenURLParams(
291 test_server()->GetURL(kAuthDigestPage
), Referrer(),
292 CURRENT_TAB
, ui::PAGE_TRANSITION_TYPED
, false));
293 auth_needed_waiter
.Wait();
296 ASSERT_EQ(2u, observer
.handlers().size());
298 LoginHandler
* handler1
= *observer
.handlers().begin();
299 LoginHandler
* handler2
= *(++(observer
.handlers().begin()));
301 base::string16 expected_title1
= ExpectedTitleFromAuth(
302 base::UTF8ToUTF16(username_basic_
), base::UTF8ToUTF16(password_
));
303 base::string16 expected_title2
= ExpectedTitleFromAuth(
304 base::UTF8ToUTF16(username_digest_
), base::UTF8ToUTF16(password_
));
305 content::TitleWatcher
title_watcher1(contents1
, expected_title1
);
306 content::TitleWatcher
title_watcher2(contents2
, expected_title2
);
308 handler1
->SetAuth(base::UTF8ToUTF16(username_basic_
),
309 base::UTF8ToUTF16(password_
));
310 handler2
->SetAuth(base::UTF8ToUTF16(username_digest_
),
311 base::UTF8ToUTF16(password_
));
313 EXPECT_EQ(expected_title1
, title_watcher1
.WaitAndGetTitle());
314 EXPECT_EQ(expected_title2
, title_watcher2
.WaitAndGetTitle());
317 // Test login prompt cancellation.
318 IN_PROC_BROWSER_TEST_F(LoginPromptBrowserTest
, TestCancelAuth
) {
319 ASSERT_TRUE(test_server()->Start());
320 GURL auth_page
= test_server()->GetURL(kAuthBasicPage
);
321 GURL no_auth_page_1
= test_server()->GetURL("a");
322 GURL no_auth_page_2
= test_server()->GetURL("b");
323 GURL no_auth_page_3
= test_server()->GetURL("c");
325 content::WebContents
* contents
=
326 browser()->tab_strip_model()->GetActiveWebContents();
327 NavigationController
* controller
= &contents
->GetController();
329 LoginPromptBrowserTestObserver observer
;
330 observer
.Register(content::Source
<NavigationController
>(controller
));
332 // First navigate to an unauthenticated page so we have something to
334 ui_test_utils::NavigateToURL(browser(), no_auth_page_1
);
336 // Navigating while auth is requested is the same as cancelling.
338 // We need to wait for two LOAD_STOP events. One for auth_page and one for
340 WindowedLoadStopObserver
load_stop_waiter(controller
, 2);
341 WindowedAuthNeededObserver
auth_needed_waiter(controller
);
342 browser()->OpenURL(OpenURLParams(
343 auth_page
, Referrer(), CURRENT_TAB
, ui::PAGE_TRANSITION_TYPED
,
345 auth_needed_waiter
.Wait();
346 WindowedAuthCancelledObserver
auth_cancelled_waiter(controller
);
347 browser()->OpenURL(OpenURLParams(
348 no_auth_page_2
, Referrer(), CURRENT_TAB
, ui::PAGE_TRANSITION_TYPED
,
350 auth_cancelled_waiter
.Wait();
351 load_stop_waiter
.Wait();
352 EXPECT_TRUE(observer
.handlers().empty());
355 // Try navigating backwards.
357 // As above, we wait for two LOAD_STOP events; one for each navigation.
358 WindowedLoadStopObserver
load_stop_waiter(controller
, 2);
359 WindowedAuthNeededObserver
auth_needed_waiter(controller
);
360 browser()->OpenURL(OpenURLParams(
361 auth_page
, Referrer(), CURRENT_TAB
, ui::PAGE_TRANSITION_TYPED
,
363 auth_needed_waiter
.Wait();
364 WindowedAuthCancelledObserver
auth_cancelled_waiter(controller
);
365 ASSERT_TRUE(chrome::CanGoBack(browser()));
366 chrome::GoBack(browser(), CURRENT_TAB
);
367 auth_cancelled_waiter
.Wait();
368 load_stop_waiter
.Wait();
369 EXPECT_TRUE(observer
.handlers().empty());
372 // Now add a page and go back, so we have something to go forward to.
373 ui_test_utils::NavigateToURL(browser(), no_auth_page_3
);
375 WindowedLoadStopObserver
load_stop_waiter(controller
, 1);
376 chrome::GoBack(browser(), CURRENT_TAB
); // Should take us to page 1
377 load_stop_waiter
.Wait();
381 // We wait for two LOAD_STOP events; one for each navigation.
382 WindowedLoadStopObserver
load_stop_waiter(controller
, 2);
383 WindowedAuthNeededObserver
auth_needed_waiter(controller
);
384 browser()->OpenURL(OpenURLParams(
385 auth_page
, Referrer(), CURRENT_TAB
, ui::PAGE_TRANSITION_TYPED
,
387 auth_needed_waiter
.Wait();
388 WindowedAuthCancelledObserver
auth_cancelled_waiter(controller
);
389 ASSERT_TRUE(chrome::CanGoForward(browser()));
390 chrome::GoForward(browser(), CURRENT_TAB
); // Should take us to page 3
391 auth_cancelled_waiter
.Wait();
392 load_stop_waiter
.Wait();
393 EXPECT_TRUE(observer
.handlers().empty());
396 // Now test that cancelling works as expected.
398 WindowedLoadStopObserver
load_stop_waiter(controller
, 1);
399 WindowedAuthNeededObserver
auth_needed_waiter(controller
);
400 browser()->OpenURL(OpenURLParams(
401 auth_page
, Referrer(), CURRENT_TAB
, ui::PAGE_TRANSITION_TYPED
,
403 auth_needed_waiter
.Wait();
404 WindowedAuthCancelledObserver
auth_cancelled_waiter(controller
);
405 LoginHandler
* handler
= *observer
.handlers().begin();
406 ASSERT_TRUE(handler
);
407 handler
->CancelAuth();
408 auth_cancelled_waiter
.Wait();
409 load_stop_waiter
.Wait();
410 EXPECT_TRUE(observer
.handlers().empty());
414 // Test handling of resources that require authentication even though
415 // the page they are included on doesn't. In this case we should only
416 // present the minimal number of prompts necessary for successfully
417 // displaying the page. First we check whether cancelling works as
419 IN_PROC_BROWSER_TEST_F(LoginPromptBrowserTest
, MultipleRealmCancellation
) {
420 ASSERT_TRUE(test_server()->Start());
421 GURL test_page
= test_server()->GetURL(kMultiRealmTestPage
);
423 content::WebContents
* contents
=
424 browser()->tab_strip_model()->GetActiveWebContents();
425 NavigationController
* controller
= &contents
->GetController();
426 LoginPromptBrowserTestObserver observer
;
428 observer
.Register(content::Source
<NavigationController
>(controller
));
430 WindowedLoadStopObserver
load_stop_waiter(controller
, 1);
433 WindowedAuthNeededObserver
auth_needed_waiter(controller
);
434 browser()->OpenURL(OpenURLParams(
435 test_page
, Referrer(), CURRENT_TAB
, ui::PAGE_TRANSITION_TYPED
,
437 auth_needed_waiter
.Wait();
442 while (n_handlers
< kMultiRealmTestRealmCount
) {
443 WindowedAuthNeededObserver
auth_needed_waiter(controller
);
445 while (!observer
.handlers().empty()) {
446 WindowedAuthCancelledObserver
auth_cancelled_waiter(controller
);
447 LoginHandler
* handler
= *observer
.handlers().begin();
449 ASSERT_TRUE(handler
);
451 handler
->CancelAuth();
452 auth_cancelled_waiter
.Wait();
455 if (n_handlers
< kMultiRealmTestRealmCount
)
456 auth_needed_waiter
.Wait();
459 load_stop_waiter
.Wait();
461 EXPECT_EQ(kMultiRealmTestRealmCount
, n_handlers
);
462 EXPECT_EQ(0, observer
.auth_supplied_count());
463 EXPECT_LT(0, observer
.auth_needed_count());
464 EXPECT_LT(0, observer
.auth_cancelled_count());
465 EXPECT_TRUE(test_server()->Stop());
468 // Similar to the MultipleRealmCancellation test above, but tests
469 // whether supplying credentials work as exepcted.
470 IN_PROC_BROWSER_TEST_F(LoginPromptBrowserTest
, MultipleRealmConfirmation
) {
471 ASSERT_TRUE(test_server()->Start());
472 GURL test_page
= test_server()->GetURL(kMultiRealmTestPage
);
474 content::WebContents
* contents
=
475 browser()->tab_strip_model()->GetActiveWebContents();
476 NavigationController
* controller
= &contents
->GetController();
477 LoginPromptBrowserTestObserver observer
;
479 observer
.Register(content::Source
<NavigationController
>(controller
));
481 WindowedLoadStopObserver
load_stop_waiter(controller
, 1);
485 WindowedAuthNeededObserver
auth_needed_waiter(controller
);
487 browser()->OpenURL(OpenURLParams(
488 test_page
, Referrer(), CURRENT_TAB
, ui::PAGE_TRANSITION_TYPED
,
490 auth_needed_waiter
.Wait();
493 while (n_handlers
< kMultiRealmTestRealmCount
) {
494 WindowedAuthNeededObserver
auth_needed_waiter(controller
);
496 while (!observer
.handlers().empty()) {
497 WindowedAuthSuppliedObserver
auth_supplied_waiter(controller
);
498 LoginHandler
* handler
= *observer
.handlers().begin();
500 ASSERT_TRUE(handler
);
503 auth_supplied_waiter
.Wait();
506 if (n_handlers
< kMultiRealmTestRealmCount
)
507 auth_needed_waiter
.Wait();
510 load_stop_waiter
.Wait();
512 EXPECT_EQ(kMultiRealmTestRealmCount
, n_handlers
);
513 EXPECT_LT(0, observer
.auth_needed_count());
514 EXPECT_LT(0, observer
.auth_supplied_count());
515 EXPECT_EQ(0, observer
.auth_cancelled_count());
516 EXPECT_TRUE(test_server()->Stop());
519 // Testing for recovery from an incorrect password for the case where
520 // there are multiple authenticated resources.
521 IN_PROC_BROWSER_TEST_F(LoginPromptBrowserTest
, IncorrectConfirmation
) {
522 ASSERT_TRUE(test_server()->Start());
523 GURL test_page
= test_server()->GetURL(kSingleRealmTestPage
);
525 content::WebContents
* contents
=
526 browser()->tab_strip_model()->GetActiveWebContents();
527 NavigationController
* controller
= &contents
->GetController();
528 LoginPromptBrowserTestObserver observer
;
530 observer
.Register(content::Source
<NavigationController
>(controller
));
533 WindowedAuthNeededObserver
auth_needed_waiter(controller
);
534 browser()->OpenURL(OpenURLParams(
535 test_page
, Referrer(), CURRENT_TAB
, ui::PAGE_TRANSITION_TYPED
,
537 auth_needed_waiter
.Wait();
540 EXPECT_FALSE(observer
.handlers().empty());
542 if (!observer
.handlers().empty()) {
543 WindowedAuthNeededObserver
auth_needed_waiter(controller
);
544 WindowedAuthSuppliedObserver
auth_supplied_waiter(controller
);
545 LoginHandler
* handler
= *observer
.handlers().begin();
547 ASSERT_TRUE(handler
);
548 handler
->SetAuth(base::UTF8ToUTF16(bad_username_
),
549 base::UTF8ToUTF16(bad_password_
));
550 auth_supplied_waiter
.Wait();
552 // The request should be retried after the incorrect password is
553 // supplied. This should result in a new AUTH_NEEDED notification
554 // for the same realm.
555 auth_needed_waiter
.Wait();
560 while (n_handlers
< 1) {
561 WindowedAuthNeededObserver
auth_needed_waiter(controller
);
563 while (!observer
.handlers().empty()) {
564 WindowedAuthSuppliedObserver
auth_supplied_waiter(controller
);
565 LoginHandler
* handler
= *observer
.handlers().begin();
567 ASSERT_TRUE(handler
);
570 auth_supplied_waiter
.Wait();
574 auth_needed_waiter
.Wait();
577 // The single realm test has only one realm, and thus only one login
579 EXPECT_EQ(1, n_handlers
);
580 EXPECT_LT(0, observer
.auth_needed_count());
581 EXPECT_EQ(0, observer
.auth_cancelled_count());
582 EXPECT_EQ(observer
.auth_needed_count(), observer
.auth_supplied_count());
583 EXPECT_TRUE(test_server()->Stop());
586 // If the favicon is an authenticated resource, we shouldn't prompt
587 // for credentials. The same URL, if requested elsewhere should
588 // prompt for credentials.
589 IN_PROC_BROWSER_TEST_F(LoginPromptBrowserTest
, NoLoginPromptForFavicon
) {
590 const char* kFaviconTestPage
= "files/login/has_favicon.html";
591 const char* kFaviconResource
= "auth-basic/favicon.gif";
593 ASSERT_TRUE(test_server()->Start());
595 content::WebContents
* contents
=
596 browser()->tab_strip_model()->GetActiveWebContents();
597 NavigationController
* controller
= &contents
->GetController();
598 LoginPromptBrowserTestObserver observer
;
600 observer
.Register(content::Source
<NavigationController
>(controller
));
602 // First load a page that has a favicon that requires
603 // authentication. There should be no login prompt.
605 GURL test_page
= test_server()->GetURL(kFaviconTestPage
);
606 WindowedLoadStopObserver
load_stop_waiter(controller
, 1);
607 browser()->OpenURL(OpenURLParams(
608 test_page
, Referrer(), CURRENT_TAB
, ui::PAGE_TRANSITION_TYPED
,
610 load_stop_waiter
.Wait();
613 // Now request the same favicon, but directly as the document.
614 // There should be one login prompt.
616 GURL test_page
= test_server()->GetURL(kFaviconResource
);
617 WindowedLoadStopObserver
load_stop_waiter(controller
, 1);
618 WindowedAuthNeededObserver
auth_needed_waiter(controller
);
619 browser()->OpenURL(OpenURLParams(
620 test_page
, Referrer(), CURRENT_TAB
, ui::PAGE_TRANSITION_TYPED
,
622 auth_needed_waiter
.Wait();
623 ASSERT_EQ(1u, observer
.handlers().size());
625 while (!observer
.handlers().empty()) {
626 WindowedAuthCancelledObserver
auth_cancelled_waiter(controller
);
627 LoginHandler
* handler
= *observer
.handlers().begin();
629 ASSERT_TRUE(handler
);
630 handler
->CancelAuth();
631 auth_cancelled_waiter
.Wait();
634 load_stop_waiter
.Wait();
637 EXPECT_EQ(0, observer
.auth_supplied_count());
638 EXPECT_EQ(1, observer
.auth_needed_count());
639 EXPECT_EQ(1, observer
.auth_cancelled_count());
640 EXPECT_TRUE(test_server()->Stop());
643 // Block crossdomain image login prompting as a phishing defense.
644 IN_PROC_BROWSER_TEST_F(LoginPromptBrowserTest
,
645 BlockCrossdomainPromptForSubresources
) {
646 const char* kTestPage
= "files/login/load_img_from_b.html";
648 host_resolver()->AddRule("www.a.com", "127.0.0.1");
649 host_resolver()->AddRule("www.b.com", "127.0.0.1");
650 ASSERT_TRUE(test_server()->Start());
652 content::WebContents
* contents
=
653 browser()->tab_strip_model()->GetActiveWebContents();
654 NavigationController
* controller
= &contents
->GetController();
655 LoginPromptBrowserTestObserver observer
;
656 observer
.Register(content::Source
<NavigationController
>(controller
));
658 // Load a page that has a cross-domain sub-resource authentication.
659 // There should be no login prompt.
661 GURL test_page
= test_server()->GetURL(kTestPage
);
662 ASSERT_EQ("127.0.0.1", test_page
.host());
664 // Change the host from 127.0.0.1 to www.a.com so that when the
665 // page tries to load from b, it will be cross-origin.
666 GURL::Replacements replacements
;
667 replacements
.SetHostStr("www.a.com");
668 test_page
= test_page
.ReplaceComponents(replacements
);
670 WindowedLoadStopObserver
load_stop_waiter(controller
, 1);
671 browser()->OpenURL(OpenURLParams(
672 test_page
, Referrer(), CURRENT_TAB
, ui::PAGE_TRANSITION_TYPED
,
674 load_stop_waiter
.Wait();
677 EXPECT_EQ(0, observer
.auth_needed_count());
679 // Now request the same page, but from the same origin.
680 // There should be one login prompt.
682 GURL test_page
= test_server()->GetURL(kTestPage
);
683 ASSERT_EQ("127.0.0.1", test_page
.host());
685 // Change the host from 127.0.0.1 to www.b.com so that when the
686 // page tries to load from b, it will be same-origin.
687 GURL::Replacements replacements
;
688 replacements
.SetHostStr("www.b.com");
689 test_page
= test_page
.ReplaceComponents(replacements
);
691 WindowedAuthNeededObserver
auth_needed_waiter(controller
);
692 browser()->OpenURL(OpenURLParams(
693 test_page
, Referrer(), CURRENT_TAB
, ui::PAGE_TRANSITION_TYPED
,
695 auth_needed_waiter
.Wait();
696 ASSERT_EQ(1u, observer
.handlers().size());
698 while (!observer
.handlers().empty()) {
699 WindowedAuthCancelledObserver
auth_cancelled_waiter(controller
);
700 LoginHandler
* handler
= *observer
.handlers().begin();
702 ASSERT_TRUE(handler
);
703 handler
->CancelAuth();
704 auth_cancelled_waiter
.Wait();
708 EXPECT_EQ(1, observer
.auth_needed_count());
709 EXPECT_TRUE(test_server()->Stop());
712 // Allow crossdomain iframe login prompting despite the above.
713 IN_PROC_BROWSER_TEST_F(LoginPromptBrowserTest
,
714 AllowCrossdomainPromptForSubframes
) {
715 const char* kTestPage
= "files/login/load_iframe_from_b.html";
717 host_resolver()->AddRule("www.a.com", "127.0.0.1");
718 host_resolver()->AddRule("www.b.com", "127.0.0.1");
719 ASSERT_TRUE(test_server()->Start());
721 content::WebContents
* contents
=
722 browser()->tab_strip_model()->GetActiveWebContents();
723 NavigationController
* controller
= &contents
->GetController();
724 LoginPromptBrowserTestObserver observer
;
725 observer
.Register(content::Source
<NavigationController
>(controller
));
727 // Load a page that has a cross-domain iframe authentication.
729 GURL test_page
= test_server()->GetURL(kTestPage
);
730 ASSERT_EQ("127.0.0.1", test_page
.host());
732 // Change the host from 127.0.0.1 to www.a.com so that when the
733 // page tries to load from b, it will be cross-origin.
734 static const char kNewHost
[] = "www.a.com";
735 GURL::Replacements replacements
;
736 replacements
.SetHostStr(kNewHost
);
737 test_page
= test_page
.ReplaceComponents(replacements
);
739 WindowedAuthNeededObserver
auth_needed_waiter(controller
);
740 browser()->OpenURL(OpenURLParams(
741 test_page
, Referrer(), CURRENT_TAB
, ui::PAGE_TRANSITION_TYPED
,
743 auth_needed_waiter
.Wait();
744 ASSERT_EQ(1u, observer
.handlers().size());
746 while (!observer
.handlers().empty()) {
747 WindowedAuthCancelledObserver
auth_cancelled_waiter(controller
);
748 LoginHandler
* handler
= *observer
.handlers().begin();
750 ASSERT_TRUE(handler
);
751 // When a cross origin iframe displays a login prompt, the blank
752 // interstitial shouldn't be displayed and the omnibox should show the
753 // main frame's url, not the iframe's.
754 EXPECT_EQ(kNewHost
, contents
->GetVisibleURL().host());
756 handler
->CancelAuth();
757 auth_cancelled_waiter
.Wait();
761 // Should stay on the main frame's url once the prompt the iframe is closed.
762 EXPECT_EQ("www.a.com", contents
->GetVisibleURL().host());
764 EXPECT_EQ(1, observer
.auth_needed_count());
765 EXPECT_TRUE(test_server()->Stop());
768 IN_PROC_BROWSER_TEST_F(LoginPromptBrowserTest
, SupplyRedundantAuths
) {
769 ASSERT_TRUE(test_server()->Start());
771 // Get NavigationController for tab 1.
772 content::WebContents
* contents_1
=
773 browser()->tab_strip_model()->GetActiveWebContents();
774 NavigationController
* controller_1
= &contents_1
->GetController();
777 ui_test_utils::NavigateToURLWithDisposition(
781 ui_test_utils::BROWSER_TEST_WAIT_FOR_TAB
);
783 // Get NavigationController for tab 2.
784 content::WebContents
* contents_2
=
785 browser()->tab_strip_model()->GetActiveWebContents();
786 ASSERT_NE(contents_1
, contents_2
);
787 NavigationController
* controller_2
= &contents_2
->GetController();
789 LoginPromptBrowserTestObserver observer
;
790 observer
.Register(content::Source
<NavigationController
>(controller_1
));
791 observer
.Register(content::Source
<NavigationController
>(controller_2
));
794 // Open different auth urls in each tab.
795 WindowedAuthNeededObserver
auth_needed_waiter_1(controller_1
);
796 WindowedAuthNeededObserver
auth_needed_waiter_2(controller_2
);
797 contents_1
->OpenURL(OpenURLParams(
798 test_server()->GetURL("auth-basic/1"),
801 ui::PAGE_TRANSITION_TYPED
,
803 contents_2
->OpenURL(OpenURLParams(
804 test_server()->GetURL("auth-basic/2"),
807 ui::PAGE_TRANSITION_TYPED
,
809 auth_needed_waiter_1
.Wait();
810 auth_needed_waiter_2
.Wait();
812 ASSERT_EQ(2U, observer
.handlers().size());
814 // Supply auth in one of the tabs.
815 WindowedAuthSuppliedObserver
auth_supplied_waiter_1(controller_1
);
816 WindowedAuthSuppliedObserver
auth_supplied_waiter_2(controller_2
);
817 LoginHandler
* handler_1
= *observer
.handlers().begin();
818 ASSERT_TRUE(handler_1
);
819 SetAuthFor(handler_1
);
821 // Both tabs should be authenticated.
822 auth_supplied_waiter_1
.Wait();
823 auth_supplied_waiter_2
.Wait();
826 EXPECT_EQ(2, observer
.auth_needed_count());
827 EXPECT_EQ(2, observer
.auth_supplied_count());
828 EXPECT_EQ(0, observer
.auth_cancelled_count());
829 EXPECT_TRUE(test_server()->Stop());
832 IN_PROC_BROWSER_TEST_F(LoginPromptBrowserTest
, CancelRedundantAuths
) {
833 ASSERT_TRUE(test_server()->Start());
835 // Get NavigationController for tab 1.
836 content::WebContents
* contents_1
=
837 browser()->tab_strip_model()->GetActiveWebContents();
838 NavigationController
* controller_1
= &contents_1
->GetController();
841 ui_test_utils::NavigateToURLWithDisposition(
845 ui_test_utils::BROWSER_TEST_WAIT_FOR_TAB
);
847 // Get NavigationController for tab 2.
848 content::WebContents
* contents_2
=
849 browser()->tab_strip_model()->GetActiveWebContents();
850 ASSERT_NE(contents_1
, contents_2
);
851 NavigationController
* controller_2
= &contents_2
->GetController();
853 LoginPromptBrowserTestObserver observer
;
854 observer
.Register(content::Source
<NavigationController
>(controller_1
));
855 observer
.Register(content::Source
<NavigationController
>(controller_2
));
858 // Open different auth urls in each tab.
859 WindowedAuthNeededObserver
auth_needed_waiter_1(controller_1
);
860 WindowedAuthNeededObserver
auth_needed_waiter_2(controller_2
);
861 contents_1
->OpenURL(OpenURLParams(
862 test_server()->GetURL("auth-basic/1"),
865 ui::PAGE_TRANSITION_TYPED
,
867 contents_2
->OpenURL(OpenURLParams(
868 test_server()->GetURL("auth-basic/2"),
871 ui::PAGE_TRANSITION_TYPED
,
873 auth_needed_waiter_1
.Wait();
874 auth_needed_waiter_2
.Wait();
876 ASSERT_EQ(2U, observer
.handlers().size());
878 // Cancel auth in one of the tabs.
879 WindowedAuthCancelledObserver
auth_cancelled_waiter_1(controller_1
);
880 WindowedAuthCancelledObserver
auth_cancelled_waiter_2(controller_2
);
881 LoginHandler
* handler_1
= *observer
.handlers().begin();
882 ASSERT_TRUE(handler_1
);
883 handler_1
->CancelAuth();
885 // Both tabs should cancel auth.
886 auth_cancelled_waiter_1
.Wait();
887 auth_cancelled_waiter_2
.Wait();
890 EXPECT_EQ(2, observer
.auth_needed_count());
891 EXPECT_EQ(0, observer
.auth_supplied_count());
892 EXPECT_EQ(2, observer
.auth_cancelled_count());
893 EXPECT_TRUE(test_server()->Stop());
896 IN_PROC_BROWSER_TEST_F(LoginPromptBrowserTest
,
897 SupplyRedundantAuthsMultiProfile
) {
898 ASSERT_TRUE(test_server()->Start());
900 // Get NavigationController for regular tab.
901 content::WebContents
* contents
=
902 browser()->tab_strip_model()->GetActiveWebContents();
903 NavigationController
* controller
= &contents
->GetController();
905 // Open an incognito window.
906 Browser
* browser_incognito
= CreateIncognitoBrowser();
908 // Get NavigationController for incognito tab.
909 content::WebContents
* contents_incognito
=
910 browser_incognito
->tab_strip_model()->GetActiveWebContents();
911 ASSERT_NE(contents
, contents_incognito
);
912 NavigationController
* controller_incognito
=
913 &contents_incognito
->GetController();
915 LoginPromptBrowserTestObserver observer
;
916 observer
.Register(content::Source
<NavigationController
>(controller
));
917 LoginPromptBrowserTestObserver observer_incognito
;
918 observer_incognito
.Register(
919 content::Source
<NavigationController
>(controller_incognito
));
922 // Open an auth url in each window.
923 WindowedAuthNeededObserver
auth_needed_waiter(controller
);
924 WindowedAuthNeededObserver
auth_needed_waiter_incognito(
925 controller_incognito
);
926 contents
->OpenURL(OpenURLParams(
927 test_server()->GetURL("auth-basic/1"),
930 ui::PAGE_TRANSITION_TYPED
,
932 contents_incognito
->OpenURL(OpenURLParams(
933 test_server()->GetURL("auth-basic/2"),
936 ui::PAGE_TRANSITION_TYPED
,
938 auth_needed_waiter
.Wait();
939 auth_needed_waiter_incognito
.Wait();
941 ASSERT_EQ(1U, observer
.handlers().size());
942 ASSERT_EQ(1U, observer_incognito
.handlers().size());
944 // Supply auth in regular tab.
945 WindowedAuthSuppliedObserver
auth_supplied_waiter(controller
);
946 LoginHandler
* handler
= *observer
.handlers().begin();
947 ASSERT_TRUE(handler
);
950 // Regular tab should be authenticated.
951 auth_supplied_waiter
.Wait();
953 // There's not really a way to wait for the incognito window to "do
954 // nothing". Run anything pending in the message loop just to be sure.
955 // (This shouldn't be necessary since notifications are synchronous, but
956 // maybe it will help avoid flake someday in the future..)
957 content::RunAllPendingInMessageLoop();
960 EXPECT_EQ(1, observer
.auth_needed_count());
961 EXPECT_EQ(1, observer
.auth_supplied_count());
962 EXPECT_EQ(0, observer
.auth_cancelled_count());
963 EXPECT_EQ(1, observer_incognito
.auth_needed_count());
964 EXPECT_EQ(0, observer_incognito
.auth_supplied_count());
965 EXPECT_EQ(0, observer_incognito
.auth_cancelled_count());
966 EXPECT_TRUE(test_server()->Stop());
969 // If an XMLHttpRequest is made with incorrect credentials, there should be no
970 // login prompt; instead the 401 status should be returned to the script.
971 IN_PROC_BROWSER_TEST_F(LoginPromptBrowserTest
,
972 NoLoginPromptForXHRWithBadCredentials
) {
973 const char* kXHRTestPage
= "files/login/xhr_with_credentials.html#incorrect";
975 ASSERT_TRUE(test_server()->Start());
977 content::WebContents
* contents
=
978 browser()->tab_strip_model()->GetActiveWebContents();
979 NavigationController
* controller
= &contents
->GetController();
980 LoginPromptBrowserTestObserver observer
;
982 observer
.Register(content::Source
<NavigationController
>(controller
));
984 // Load a page which makes a synchronous XMLHttpRequest for an authenticated
985 // resource with the wrong credentials. There should be no login prompt.
987 GURL test_page
= test_server()->GetURL(kXHRTestPage
);
988 WindowedLoadStopObserver
load_stop_waiter(controller
, 1);
989 browser()->OpenURL(OpenURLParams(
990 test_page
, Referrer(), CURRENT_TAB
, ui::PAGE_TRANSITION_TYPED
,
992 load_stop_waiter
.Wait();
995 base::string16
expected_title(base::UTF8ToUTF16("status=401"));
997 EXPECT_EQ(expected_title
, contents
->GetTitle());
998 EXPECT_EQ(0, observer
.auth_supplied_count());
999 EXPECT_EQ(0, observer
.auth_needed_count());
1000 EXPECT_EQ(0, observer
.auth_cancelled_count());
1001 EXPECT_TRUE(test_server()->Stop());
1004 // If an XMLHttpRequest is made with correct credentials, there should be no
1005 // login prompt either.
1006 IN_PROC_BROWSER_TEST_F(LoginPromptBrowserTest
,
1007 NoLoginPromptForXHRWithGoodCredentials
) {
1008 const char* kXHRTestPage
= "files/login/xhr_with_credentials.html#secret";
1010 ASSERT_TRUE(test_server()->Start());
1012 content::WebContents
* contents
=
1013 browser()->tab_strip_model()->GetActiveWebContents();
1014 NavigationController
* controller
= &contents
->GetController();
1015 LoginPromptBrowserTestObserver observer
;
1017 observer
.Register(content::Source
<NavigationController
>(controller
));
1019 // Load a page which makes a synchronous XMLHttpRequest for an authenticated
1020 // resource with the wrong credentials. There should be no login prompt.
1022 GURL test_page
= test_server()->GetURL(kXHRTestPage
);
1023 WindowedLoadStopObserver
load_stop_waiter(controller
, 1);
1024 browser()->OpenURL(OpenURLParams(
1025 test_page
, Referrer(), CURRENT_TAB
, ui::PAGE_TRANSITION_TYPED
,
1027 load_stop_waiter
.Wait();
1030 base::string16
expected_title(base::UTF8ToUTF16("status=200"));
1032 EXPECT_EQ(expected_title
, contents
->GetTitle());
1033 EXPECT_EQ(0, observer
.auth_supplied_count());
1034 EXPECT_EQ(0, observer
.auth_needed_count());
1035 EXPECT_EQ(0, observer
.auth_cancelled_count());
1036 EXPECT_TRUE(test_server()->Stop());
1039 // If an XMLHttpRequest is made without credentials, there should be a login
1041 IN_PROC_BROWSER_TEST_F(LoginPromptBrowserTest
,
1042 LoginPromptForXHRWithoutCredentials
) {
1043 const char* kXHRTestPage
= "files/login/xhr_without_credentials.html";
1045 ASSERT_TRUE(test_server()->Start());
1047 content::WebContents
* contents
=
1048 browser()->tab_strip_model()->GetActiveWebContents();
1049 NavigationController
* controller
= &contents
->GetController();
1050 LoginPromptBrowserTestObserver observer
;
1052 observer
.Register(content::Source
<NavigationController
>(controller
));
1054 // Load a page which makes a synchronous XMLHttpRequest for an authenticated
1055 // resource with the wrong credentials. There should be no login prompt.
1057 GURL test_page
= test_server()->GetURL(kXHRTestPage
);
1058 WindowedAuthNeededObserver
auth_needed_waiter(controller
);
1059 browser()->OpenURL(OpenURLParams(
1060 test_page
, Referrer(), CURRENT_TAB
, ui::PAGE_TRANSITION_TYPED
,
1062 auth_needed_waiter
.Wait();
1065 ASSERT_FALSE(observer
.handlers().empty());
1067 WindowedAuthNeededObserver
auth_needed_waiter(controller
);
1068 WindowedAuthSuppliedObserver
auth_supplied_waiter(controller
);
1069 LoginHandler
* handler
= *observer
.handlers().begin();
1071 ASSERT_TRUE(handler
);
1072 handler
->SetAuth(base::UTF8ToUTF16(bad_username_
),
1073 base::UTF8ToUTF16(bad_password_
));
1074 auth_supplied_waiter
.Wait();
1076 // The request should be retried after the incorrect password is
1077 // supplied. This should result in a new AUTH_NEEDED notification
1078 // for the same realm.
1079 auth_needed_waiter
.Wait();
1082 ASSERT_EQ(1u, observer
.handlers().size());
1083 WindowedAuthSuppliedObserver
auth_supplied_waiter(controller
);
1084 LoginHandler
* handler
= *observer
.handlers().begin();
1086 base::string16
username(base::UTF8ToUTF16(username_digest_
));
1087 base::string16
password(base::UTF8ToUTF16(password_
));
1088 handler
->SetAuth(username
, password
);
1089 auth_supplied_waiter
.Wait();
1091 WindowedLoadStopObserver
load_stop_waiter(controller
, 1);
1092 load_stop_waiter
.Wait();
1094 base::string16
expected_title(base::UTF8ToUTF16("status=200"));
1096 EXPECT_EQ(expected_title
, contents
->GetTitle());
1097 EXPECT_EQ(2, observer
.auth_supplied_count());
1098 EXPECT_EQ(2, observer
.auth_needed_count());
1099 EXPECT_EQ(0, observer
.auth_cancelled_count());
1100 EXPECT_TRUE(test_server()->Stop());
1103 // If an XMLHttpRequest is made without credentials, there should be a login
1104 // prompt. If it's cancelled, the script should get a 401 status.
1105 IN_PROC_BROWSER_TEST_F(LoginPromptBrowserTest
,
1106 LoginPromptForXHRWithoutCredentialsCancelled
) {
1107 const char* kXHRTestPage
= "files/login/xhr_without_credentials.html";
1109 ASSERT_TRUE(test_server()->Start());
1111 content::WebContents
* contents
=
1112 browser()->tab_strip_model()->GetActiveWebContents();
1113 NavigationController
* controller
= &contents
->GetController();
1114 LoginPromptBrowserTestObserver observer
;
1116 observer
.Register(content::Source
<NavigationController
>(controller
));
1118 // Load a page which makes a synchronous XMLHttpRequest for an authenticated
1119 // resource with the wrong credentials. There should be no login prompt.
1121 GURL test_page
= test_server()->GetURL(kXHRTestPage
);
1122 WindowedAuthNeededObserver
auth_needed_waiter(controller
);
1123 browser()->OpenURL(OpenURLParams(
1124 test_page
, Referrer(), CURRENT_TAB
, ui::PAGE_TRANSITION_TYPED
,
1126 auth_needed_waiter
.Wait();
1129 ASSERT_EQ(1u, observer
.handlers().size());
1130 WindowedAuthCancelledObserver
auth_cancelled_waiter(controller
);
1131 LoginHandler
* handler
= *observer
.handlers().begin();
1133 handler
->CancelAuth();
1134 auth_cancelled_waiter
.Wait();
1136 WindowedLoadStopObserver
load_stop_waiter(controller
, 1);
1137 load_stop_waiter
.Wait();
1139 base::string16
expected_title(base::UTF8ToUTF16("status=401"));
1141 EXPECT_EQ(expected_title
, contents
->GetTitle());
1142 EXPECT_EQ(0, observer
.auth_supplied_count());
1143 EXPECT_EQ(1, observer
.auth_needed_count());
1144 EXPECT_EQ(1, observer
.auth_cancelled_count());
1145 EXPECT_TRUE(test_server()->Stop());
1148 // If a cross origin navigation triggers a login prompt, the destination URL
1149 // should be shown in the omnibox.
1150 void LoginPromptBrowserTest::TestCrossOriginPrompt(
1151 const GURL
& visit_url
,
1152 const std::string
& auth_host
) const {
1153 content::WebContents
* contents
=
1154 browser()->tab_strip_model()->GetActiveWebContents();
1155 NavigationController
* controller
= &contents
->GetController();
1156 LoginPromptBrowserTestObserver observer
;
1158 observer
.Register(content::Source
<NavigationController
>(controller
));
1160 // Load a page which will trigger a login prompt.
1162 WindowedAuthNeededObserver
auth_needed_waiter(controller
);
1163 browser()->OpenURL(OpenURLParams(
1164 visit_url
, Referrer(), CURRENT_TAB
, ui::PAGE_TRANSITION_TYPED
,
1166 ASSERT_EQ(visit_url
.host(), contents
->GetVisibleURL().host());
1167 auth_needed_waiter
.Wait();
1168 ASSERT_EQ(1u, observer
.handlers().size());
1169 content::WaitForInterstitialAttach(contents
);
1171 // The omnibox should show the correct origin for the new page when the
1172 // login prompt is shown.
1173 EXPECT_EQ(auth_host
, contents
->GetVisibleURL().host());
1174 EXPECT_TRUE(contents
->ShowingInterstitialPage());
1175 EXPECT_EQ(LoginInterstitialDelegate::kTypeForTesting
,
1176 contents
->GetInterstitialPage()
1177 ->GetDelegateForTesting()
1178 ->GetTypeForTesting());
1180 // Cancel and wait for the interstitial to detach.
1181 LoginHandler
* handler
= *observer
.handlers().begin();
1182 content::RunTaskAndWaitForInterstitialDetach(
1183 contents
, base::Bind(&LoginHandler::CancelAuth
, handler
));
1185 EXPECT_EQ(auth_host
, contents
->GetVisibleURL().host());
1186 EXPECT_FALSE(contents
->ShowingInterstitialPage());
1190 // If a cross origin direct navigation triggers a login prompt, the login
1191 // interstitial should be shown.
1192 IN_PROC_BROWSER_TEST_F(LoginPromptBrowserTest
,
1193 ShowCorrectUrlForCrossOriginMainFrameRequests
) {
1194 ASSERT_TRUE(test_server()->Start());
1196 GURL test_page
= test_server()->GetURL(kAuthBasicPage
);
1197 ASSERT_EQ("127.0.0.1", test_page
.host());
1198 std::string
auth_host("127.0.0.1");
1199 TestCrossOriginPrompt(test_page
, auth_host
);
1202 // If a cross origin redirect triggers a login prompt, the destination URL
1203 // should be shown in the omnibox when the auth dialog is displayed.
1204 IN_PROC_BROWSER_TEST_F(LoginPromptBrowserTest
,
1205 ShowCorrectUrlForCrossOriginMainFrameRedirects
) {
1206 host_resolver()->AddRule("www.a.com", "127.0.0.1");
1207 ASSERT_TRUE(test_server()->Start());
1209 const char* kTestPage
= "files/login/cross_origin.html";
1210 GURL test_page
= test_server()->GetURL(kTestPage
);
1211 ASSERT_EQ("127.0.0.1", test_page
.host());
1212 std::string
auth_host("www.a.com");
1213 TestCrossOriginPrompt(test_page
, auth_host
);
1216 // Test the scenario where proceeding through a different type of interstitial
1217 // that ends up with an auth URL works fine. This can happen if a URL that
1218 // triggers the auth dialog can also trigger an SSL interstitial (or any other
1219 // type of interstitial).
1220 IN_PROC_BROWSER_TEST_F(
1221 LoginPromptBrowserTest
,
1222 DISABLED_LoginInterstitialShouldReplaceExistingInterstitial
) {
1223 net::SpawnedTestServer
https_server(
1224 net::SpawnedTestServer::TYPE_HTTPS
,
1225 net::SpawnedTestServer::SSLOptions(
1226 net::SpawnedTestServer::SSLOptions::CERT_EXPIRED
),
1228 ASSERT_TRUE(https_server
.Start());
1230 content::WebContents
* contents
=
1231 browser()->tab_strip_model()->GetActiveWebContents();
1232 NavigationController
* controller
= &contents
->GetController();
1233 LoginPromptBrowserTestObserver observer
;
1235 observer
.Register(content::Source
<NavigationController
>(controller
));
1237 // Load a page which triggers an SSL interstitial. Proceeding through it
1238 // should show the login page with the blank interstitial.
1240 GURL test_page
= https_server
.GetURL(kAuthBasicPage
);
1241 ASSERT_EQ("127.0.0.1", test_page
.host());
1243 WindowedAuthNeededObserver
auth_needed_waiter(controller
);
1244 browser()->OpenURL(OpenURLParams(
1245 test_page
, Referrer(), CURRENT_TAB
, ui::PAGE_TRANSITION_TYPED
,
1247 ASSERT_EQ("127.0.0.1", contents
->GetURL().host());
1248 content::WaitForInterstitialAttach(contents
);
1250 EXPECT_EQ(SSLBlockingPage::kTypeForTesting
, contents
->GetInterstitialPage()
1251 ->GetDelegateForTesting()
1252 ->GetTypeForTesting());
1253 // An overrideable SSL interstitial is now being displayed. Proceed through
1254 // the interstitial to see the login prompt.
1255 contents
->GetInterstitialPage()->Proceed();
1256 auth_needed_waiter
.Wait();
1257 ASSERT_EQ(1u, observer
.handlers().size());
1258 content::WaitForInterstitialAttach(contents
);
1260 // The omnibox should show the correct origin while the login prompt is
1262 EXPECT_EQ("127.0.0.1", contents
->GetVisibleURL().host());
1263 EXPECT_TRUE(contents
->ShowingInterstitialPage());
1264 EXPECT_EQ(LoginInterstitialDelegate::kTypeForTesting
,
1265 contents
->GetInterstitialPage()
1266 ->GetDelegateForTesting()
1267 ->GetTypeForTesting());
1269 // Cancelling the login prompt should detach the interstitial while keeping
1270 // the correct origin.
1271 LoginHandler
* handler
= *observer
.handlers().begin();
1272 content::RunTaskAndWaitForInterstitialDetach(
1273 contents
, base::Bind(&LoginHandler::CancelAuth
, handler
));
1275 EXPECT_EQ("127.0.0.1", contents
->GetVisibleURL().host());
1276 EXPECT_FALSE(contents
->ShowingInterstitialPage());
1280 // Test the scenario where an auth interstitial should replace a different type
1281 // of interstitial (e.g. SSL) even though the navigation isn't cross origin.
1282 // This is different than the above scenario in that the last
1283 // committed url is the same as the auth url. This can happen when:
1285 // 1. Tab is navigated to the auth URL and the auth prompt is cancelled.
1286 // 2. Tab is then navigated to an SSL interstitial.
1287 // 3. Tab is again navigated to the same auth URL in (1).
1289 // In this case, the last committed url is the same as the auth URL since the
1290 // navigation at (1) is committed (user clicked cancel and the page loaded), but
1291 // the navigation at (2) isn't (navigations ending up in interstitials don't
1292 // immediately commit). So just checking for cross origin navigation before
1293 // prompting the auth interstitial is not sufficient, must also check if there
1294 // is any other interstitial being displayed.
1295 IN_PROC_BROWSER_TEST_F(LoginPromptBrowserTest
,
1296 ShouldReplaceExistingInterstitialWhenNavigated
) {
1297 ASSERT_TRUE(test_server()->Start());
1298 net::SpawnedTestServer
https_server(
1299 net::SpawnedTestServer::TYPE_HTTPS
,
1300 net::SpawnedTestServer::SSLOptions(
1301 net::SpawnedTestServer::SSLOptions::CERT_EXPIRED
),
1303 ASSERT_TRUE(https_server
.Start());
1305 content::WebContents
* contents
=
1306 browser()->tab_strip_model()->GetActiveWebContents();
1307 NavigationController
* controller
= &contents
->GetController();
1308 LoginPromptBrowserTestObserver observer
;
1310 observer
.Register(content::Source
<NavigationController
>(controller
));
1312 GURL auth_url
= test_server()->GetURL(kAuthBasicPage
);
1313 GURL broken_ssl_page
= https_server
.GetURL("/");
1315 // Navigate to an auth url and wait for the login prompt.
1317 WindowedAuthNeededObserver
auth_needed_waiter(controller
);
1318 browser()->OpenURL(OpenURLParams(auth_url
, Referrer(), CURRENT_TAB
,
1319 ui::PAGE_TRANSITION_TYPED
, false));
1320 ASSERT_EQ("127.0.0.1", contents
->GetURL().host());
1321 ASSERT_TRUE(contents
->GetURL().SchemeIs("http"));
1322 auth_needed_waiter
.Wait();
1323 ASSERT_EQ(1u, observer
.handlers().size());
1324 content::WaitForInterstitialAttach(contents
);
1325 ASSERT_TRUE(contents
->ShowingInterstitialPage());
1326 EXPECT_EQ(LoginInterstitialDelegate::kTypeForTesting
,
1327 contents
->GetInterstitialPage()
1328 ->GetDelegateForTesting()
1329 ->GetTypeForTesting());
1330 // Cancel the auth prompt. This commits the navigation.
1331 LoginHandler
* handler
= *observer
.handlers().begin();
1332 content::RunTaskAndWaitForInterstitialDetach(
1333 contents
, base::Bind(&LoginHandler::CancelAuth
, handler
));
1334 EXPECT_EQ("127.0.0.1", contents
->GetVisibleURL().host());
1335 EXPECT_FALSE(contents
->ShowingInterstitialPage());
1336 EXPECT_EQ(auth_url
, contents
->GetLastCommittedURL());
1339 // Navigate to a broken SSL page. This is a cross origin navigation since
1340 // schemes don't match (http vs https).
1342 ASSERT_EQ("127.0.0.1", broken_ssl_page
.host());
1343 browser()->OpenURL(OpenURLParams(broken_ssl_page
, Referrer(), CURRENT_TAB
,
1344 ui::PAGE_TRANSITION_TYPED
, false));
1345 ASSERT_EQ("127.0.0.1", contents
->GetURL().host());
1346 ASSERT_TRUE(contents
->GetURL().SchemeIs("https"));
1347 content::WaitForInterstitialAttach(contents
);
1348 EXPECT_TRUE(contents
->ShowingInterstitialPage());
1349 EXPECT_EQ(SSLBlockingPage::kTypeForTesting
, contents
->GetInterstitialPage()
1350 ->GetDelegateForTesting()
1351 ->GetTypeForTesting());
1352 EXPECT_EQ(auth_url
, contents
->GetLastCommittedURL());
1355 // An overrideable SSL interstitial is now being displayed. Navigate to the
1356 // auth URL again. This is again a cross origin navigation, but last committed
1357 // URL is the same as the auth URL (since SSL navigation never committed).
1358 // Should still replace SSL interstitial with an auth interstitial even though
1359 // last committed URL and the new URL is the same.
1361 WindowedAuthNeededObserver
auth_needed_waiter(controller
);
1362 browser()->OpenURL(OpenURLParams(auth_url
, Referrer(), CURRENT_TAB
,
1363 ui::PAGE_TRANSITION_TYPED
, false));
1364 ASSERT_EQ("127.0.0.1", contents
->GetURL().host());
1365 ASSERT_TRUE(contents
->GetURL().SchemeIs("http"));
1366 ASSERT_TRUE(contents
->ShowingInterstitialPage());
1368 auth_needed_waiter
.Wait();
1369 ASSERT_EQ(1u, observer
.handlers().size());
1370 content::WaitForInterstitialAttach(contents
);
1371 EXPECT_EQ(LoginInterstitialDelegate::kTypeForTesting
,
1372 contents
->GetInterstitialPage()
1373 ->GetDelegateForTesting()
1374 ->GetTypeForTesting());