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/strings/utf_string_conversions.h"
10 #include "chrome/browser/chrome_notification_types.h"
11 #include "chrome/browser/prerender/prerender_manager.h"
12 #include "chrome/browser/ui/browser.h"
13 #include "chrome/browser/ui/browser_commands.h"
14 #include "chrome/browser/ui/login/login_prompt.h"
15 #include "chrome/browser/ui/tabs/tab_strip_model.h"
16 #include "chrome/test/base/in_process_browser_test.h"
17 #include "chrome/test/base/ui_test_utils.h"
18 #include "content/public/browser/notification_details.h"
19 #include "content/public/browser/notification_source.h"
20 #include "content/public/browser/web_contents.h"
21 #include "content/public/test/browser_test_utils.h"
22 #include "net/base/auth.h"
23 #include "net/dns/mock_host_resolver.h"
25 using content::NavigationController;
26 using content::OpenURLParams;
27 using content::Referrer;
31 class LoginPromptBrowserTest : public InProcessBrowserTest {
33 LoginPromptBrowserTest()
34 : bad_password_("incorrect"),
35 bad_username_("nouser"),
37 username_basic_("basicuser"),
38 username_digest_("digestuser") {
39 auth_map_["foo"] = AuthInfo("testuser", "foopassword");
40 auth_map_["bar"] = AuthInfo("testuser", "barpassword");
41 auth_map_["testrealm"] = AuthInfo(username_basic_, password_);
46 std::string username_;
47 std::string password_;
51 AuthInfo(const std::string& username,
52 const std::string& password)
53 : username_(username), password_(password) {}
56 typedef std::map<std::string, AuthInfo> AuthMap;
58 void SetAuthFor(LoginHandler* handler);
61 std::string bad_password_;
62 std::string bad_username_;
63 std::string password_;
64 std::string username_basic_;
65 std::string username_digest_;
68 void LoginPromptBrowserTest::SetAuthFor(LoginHandler* handler) {
69 const net::AuthChallengeInfo* challenge = handler->auth_info();
71 ASSERT_TRUE(challenge);
72 AuthMap::iterator i = auth_map_.find(challenge->realm);
73 EXPECT_TRUE(auth_map_.end() != i);
74 if (i != auth_map_.end()) {
75 const AuthInfo& info = i->second;
76 handler->SetAuth(UTF8ToUTF16(info.username_),
77 UTF8ToUTF16(info.password_));
81 // Maintains a set of LoginHandlers that are currently active and
82 // keeps a count of the notifications that were observed.
83 class LoginPromptBrowserTestObserver : public content::NotificationObserver {
85 LoginPromptBrowserTestObserver()
86 : auth_needed_count_(0),
87 auth_supplied_count_(0),
88 auth_cancelled_count_(0) {}
90 virtual void Observe(int type,
91 const content::NotificationSource& source,
92 const content::NotificationDetails& details) OVERRIDE;
94 void AddHandler(LoginHandler* handler);
96 void RemoveHandler(LoginHandler* handler);
98 void Register(const content::NotificationSource& source);
100 std::list<LoginHandler*> handlers_;
102 // The exact number of notifications we receive is depedent on the
103 // number of requests that were dispatched and is subject to a
104 // number of factors that we don't directly control here. The
105 // values below should only be used qualitatively.
106 int auth_needed_count_;
107 int auth_supplied_count_;
108 int auth_cancelled_count_;
111 content::NotificationRegistrar registrar_;
113 DISALLOW_COPY_AND_ASSIGN(LoginPromptBrowserTestObserver);
116 void LoginPromptBrowserTestObserver::Observe(
118 const content::NotificationSource& source,
119 const content::NotificationDetails& details) {
120 if (type == chrome::NOTIFICATION_AUTH_NEEDED) {
121 LoginNotificationDetails* login_details =
122 content::Details<LoginNotificationDetails>(details).ptr();
123 AddHandler(login_details->handler());
124 auth_needed_count_++;
125 } else if (type == chrome::NOTIFICATION_AUTH_SUPPLIED) {
126 AuthSuppliedLoginNotificationDetails* login_details =
127 content::Details<AuthSuppliedLoginNotificationDetails>(details).ptr();
128 RemoveHandler(login_details->handler());
129 auth_supplied_count_++;
130 } else if (type == chrome::NOTIFICATION_AUTH_CANCELLED) {
131 LoginNotificationDetails* login_details =
132 content::Details<LoginNotificationDetails>(details).ptr();
133 RemoveHandler(login_details->handler());
134 auth_cancelled_count_++;
138 void LoginPromptBrowserTestObserver::AddHandler(LoginHandler* handler) {
139 std::list<LoginHandler*>::iterator i = std::find(handlers_.begin(),
142 EXPECT_TRUE(i == handlers_.end());
143 if (i == handlers_.end())
144 handlers_.push_back(handler);
147 void LoginPromptBrowserTestObserver::RemoveHandler(LoginHandler* handler) {
148 std::list<LoginHandler*>::iterator i = std::find(handlers_.begin(),
151 EXPECT_TRUE(i != handlers_.end());
152 if (i != handlers_.end())
156 void LoginPromptBrowserTestObserver::Register(
157 const content::NotificationSource& source) {
158 registrar_.Add(this, chrome::NOTIFICATION_AUTH_NEEDED, source);
159 registrar_.Add(this, chrome::NOTIFICATION_AUTH_SUPPLIED, source);
160 registrar_.Add(this, chrome::NOTIFICATION_AUTH_CANCELLED, source);
164 class WindowedNavigationObserver
165 : public content::WindowedNotificationObserver {
167 explicit WindowedNavigationObserver(NavigationController* controller)
168 : content::WindowedNotificationObserver(
169 T, content::Source<NavigationController>(controller)) {}
172 // LOAD_STOP observer is special since we want to be able to wait for
173 // multiple LOAD_STOP events.
174 class WindowedLoadStopObserver
175 : public WindowedNavigationObserver<content::NOTIFICATION_LOAD_STOP> {
177 WindowedLoadStopObserver(NavigationController* controller,
178 int notification_count)
179 : WindowedNavigationObserver<content::NOTIFICATION_LOAD_STOP>(controller),
180 remaining_notification_count_(notification_count) {}
182 virtual void Observe(int type,
183 const content::NotificationSource& source,
184 const content::NotificationDetails& details) OVERRIDE;
186 int remaining_notification_count_; // Number of notifications remaining.
189 void WindowedLoadStopObserver::Observe(
191 const content::NotificationSource& source,
192 const content::NotificationDetails& details) {
193 if (--remaining_notification_count_ == 0)
194 WindowedNotificationObserver::Observe(type, source, details);
197 typedef WindowedNavigationObserver<chrome::NOTIFICATION_AUTH_NEEDED>
198 WindowedAuthNeededObserver;
200 typedef WindowedNavigationObserver<chrome::NOTIFICATION_AUTH_CANCELLED>
201 WindowedAuthCancelledObserver;
203 typedef WindowedNavigationObserver<chrome::NOTIFICATION_AUTH_SUPPLIED>
204 WindowedAuthSuppliedObserver;
206 const char kPrefetchAuthPage[] = "files/login/prefetch.html";
208 const char kMultiRealmTestPage[] = "files/login/multi_realm.html";
209 const int kMultiRealmTestRealmCount = 2;
211 const char kSingleRealmTestPage[] = "files/login/single_realm.html";
213 const char* kAuthBasicPage = "auth-basic";
214 const char* kAuthDigestPage = "auth-digest";
216 string16 ExpectedTitleFromAuth(const string16& username,
217 const string16& password) {
218 // The TestServer sets the title to username/password on successful login.
219 return username + UTF8ToUTF16("/") + password;
222 // Confirm that <link rel="prefetch"> targetting an auth required
223 // resource does not provide a login dialog. These types of requests
224 // should instead just cancel the auth.
226 // Unfortunately, this test doesn't assert on anything for its
227 // correctness. Instead, it relies on the auth dialog blocking the
228 // browser, and triggering a timeout to cause failure when the
229 // prefetch resource requires authorization.
230 IN_PROC_BROWSER_TEST_F(LoginPromptBrowserTest, PrefetchAuthCancels) {
231 ASSERT_TRUE(test_server()->Start());
233 GURL test_page = test_server()->GetURL(kPrefetchAuthPage);
235 class SetPrefetchForTest {
237 explicit SetPrefetchForTest(bool prefetch)
238 : old_prefetch_state_(prerender::PrerenderManager::IsPrefetchEnabled()),
239 old_mode_(prerender::PrerenderManager::GetMode()) {
240 prerender::PrerenderManager::SetIsPrefetchEnabled(prefetch);
241 // Disable prerender so this is just a prefetch of the top-level page.
242 prerender::PrerenderManager::SetMode(
243 prerender::PrerenderManager::PRERENDER_MODE_DISABLED);
246 ~SetPrefetchForTest() {
247 prerender::PrerenderManager::SetIsPrefetchEnabled(old_prefetch_state_);
248 prerender::PrerenderManager::SetMode(old_mode_);
251 bool old_prefetch_state_;
252 prerender::PrerenderManager::PrerenderManagerMode old_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(UTF8ToUTF16(bad_username_), UTF8ToUTF16(bad_password_));
300 auth_supplied_waiter.Wait();
302 // The request should be retried after the incorrect password is
303 // supplied. This should result in a new AUTH_NEEDED notification
304 // for the same realm.
305 auth_needed_waiter.Wait();
308 ASSERT_EQ(1u, observer.handlers_.size());
309 WindowedAuthSuppliedObserver auth_supplied_waiter(controller);
310 LoginHandler* handler = *observer.handlers_.begin();
312 auth_supplied_waiter.Wait();
314 string16 expected_title =
315 ExpectedTitleFromAuth(ASCIIToUTF16("basicuser"), ASCIIToUTF16("secret"));
316 content::TitleWatcher title_watcher(contents, expected_title);
317 EXPECT_EQ(expected_title, title_watcher.WaitAndGetTitle());
320 // Test that "Digest" HTTP authentication works.
321 IN_PROC_BROWSER_TEST_F(LoginPromptBrowserTest, TestDigestAuth) {
322 ASSERT_TRUE(test_server()->Start());
323 GURL test_page = test_server()->GetURL(kAuthDigestPage);
325 content::WebContents* contents =
326 browser()->tab_strip_model()->GetActiveWebContents();
327 NavigationController* controller = &contents->GetController();
328 LoginPromptBrowserTestObserver observer;
330 observer.Register(content::Source<NavigationController>(controller));
333 WindowedAuthNeededObserver auth_needed_waiter(controller);
334 browser()->OpenURL(OpenURLParams(
335 test_page, Referrer(), CURRENT_TAB, content::PAGE_TRANSITION_TYPED,
337 auth_needed_waiter.Wait();
340 ASSERT_FALSE(observer.handlers_.empty());
342 WindowedAuthNeededObserver auth_needed_waiter(controller);
343 WindowedAuthSuppliedObserver auth_supplied_waiter(controller);
344 LoginHandler* handler = *observer.handlers_.begin();
346 ASSERT_TRUE(handler);
347 handler->SetAuth(UTF8ToUTF16(bad_username_), UTF8ToUTF16(bad_password_));
348 auth_supplied_waiter.Wait();
350 // The request should be retried after the incorrect password is
351 // supplied. This should result in a new AUTH_NEEDED notification
352 // for the same realm.
353 auth_needed_waiter.Wait();
356 ASSERT_EQ(1u, observer.handlers_.size());
357 WindowedAuthSuppliedObserver auth_supplied_waiter(controller);
358 LoginHandler* handler = *observer.handlers_.begin();
360 string16 username(UTF8ToUTF16(username_digest_));
361 string16 password(UTF8ToUTF16(password_));
362 handler->SetAuth(username, password);
363 auth_supplied_waiter.Wait();
365 string16 expected_title = ExpectedTitleFromAuth(username, password);
366 content::TitleWatcher title_watcher(contents, expected_title);
367 EXPECT_EQ(expected_title, title_watcher.WaitAndGetTitle());
370 IN_PROC_BROWSER_TEST_F(LoginPromptBrowserTest, TestTwoAuths) {
371 ASSERT_TRUE(test_server()->Start());
373 content::WebContents* contents1 =
374 browser()->tab_strip_model()->GetActiveWebContents();
375 NavigationController* controller1 = &contents1->GetController();
376 LoginPromptBrowserTestObserver observer;
378 observer.Register(content::Source<NavigationController>(controller1));
381 ui_test_utils::NavigateToURLWithDisposition(
385 ui_test_utils::BROWSER_TEST_WAIT_FOR_TAB);
387 content::WebContents* contents2 =
388 browser()->tab_strip_model()->GetActiveWebContents();
389 ASSERT_NE(contents1, contents2);
390 NavigationController* controller2 = &contents2->GetController();
391 observer.Register(content::Source<NavigationController>(controller2));
394 WindowedAuthNeededObserver auth_needed_waiter(controller1);
395 contents1->OpenURL(OpenURLParams(
396 test_server()->GetURL(kAuthBasicPage), Referrer(),
397 CURRENT_TAB, content::PAGE_TRANSITION_TYPED, false));
398 auth_needed_waiter.Wait();
402 WindowedAuthNeededObserver auth_needed_waiter(controller2);
403 contents2->OpenURL(OpenURLParams(
404 test_server()->GetURL(kAuthDigestPage), Referrer(),
405 CURRENT_TAB, content::PAGE_TRANSITION_TYPED, false));
406 auth_needed_waiter.Wait();
409 ASSERT_EQ(2u, observer.handlers_.size());
411 LoginHandler* handler1 = *observer.handlers_.begin();
412 LoginHandler* handler2 = *(++(observer.handlers_.begin()));
414 string16 expected_title1 = ExpectedTitleFromAuth(
415 UTF8ToUTF16(username_basic_), UTF8ToUTF16(password_));
416 string16 expected_title2 = ExpectedTitleFromAuth(
417 UTF8ToUTF16(username_digest_), UTF8ToUTF16(password_));
418 content::TitleWatcher title_watcher1(contents1, expected_title1);
419 content::TitleWatcher title_watcher2(contents2, expected_title2);
421 handler1->SetAuth(UTF8ToUTF16(username_basic_), UTF8ToUTF16(password_));
422 handler2->SetAuth(UTF8ToUTF16(username_digest_), UTF8ToUTF16(password_));
424 EXPECT_EQ(expected_title1, title_watcher1.WaitAndGetTitle());
425 EXPECT_EQ(expected_title2, title_watcher2.WaitAndGetTitle());
428 // Test login prompt cancellation.
429 IN_PROC_BROWSER_TEST_F(LoginPromptBrowserTest, TestCancelAuth) {
430 ASSERT_TRUE(test_server()->Start());
431 GURL auth_page = test_server()->GetURL(kAuthBasicPage);
432 GURL no_auth_page_1 = test_server()->GetURL("a");
433 GURL no_auth_page_2 = test_server()->GetURL("b");
434 GURL no_auth_page_3 = test_server()->GetURL("c");
436 content::WebContents* contents =
437 browser()->tab_strip_model()->GetActiveWebContents();
438 NavigationController* controller = &contents->GetController();
440 LoginPromptBrowserTestObserver observer;
441 observer.Register(content::Source<NavigationController>(controller));
443 // First navigate to an unauthenticated page so we have something to
445 ui_test_utils::NavigateToURL(browser(), no_auth_page_1);
447 // Navigating while auth is requested is the same as cancelling.
449 // We need to wait for two LOAD_STOP events. One for auth_page and one for
451 WindowedLoadStopObserver load_stop_waiter(controller, 2);
452 WindowedAuthNeededObserver auth_needed_waiter(controller);
453 browser()->OpenURL(OpenURLParams(
454 auth_page, Referrer(), CURRENT_TAB, content::PAGE_TRANSITION_TYPED,
456 auth_needed_waiter.Wait();
457 WindowedAuthCancelledObserver auth_cancelled_waiter(controller);
458 browser()->OpenURL(OpenURLParams(
459 no_auth_page_2, Referrer(), CURRENT_TAB, content::PAGE_TRANSITION_TYPED,
461 auth_cancelled_waiter.Wait();
462 load_stop_waiter.Wait();
463 EXPECT_TRUE(observer.handlers_.empty());
466 // Try navigating backwards.
468 // As above, we wait for two LOAD_STOP events; one for each navigation.
469 WindowedLoadStopObserver load_stop_waiter(controller, 2);
470 WindowedAuthNeededObserver auth_needed_waiter(controller);
471 browser()->OpenURL(OpenURLParams(
472 auth_page, Referrer(), CURRENT_TAB, content::PAGE_TRANSITION_TYPED,
474 auth_needed_waiter.Wait();
475 WindowedAuthCancelledObserver auth_cancelled_waiter(controller);
476 ASSERT_TRUE(chrome::CanGoBack(browser()));
477 chrome::GoBack(browser(), CURRENT_TAB);
478 auth_cancelled_waiter.Wait();
479 load_stop_waiter.Wait();
480 EXPECT_TRUE(observer.handlers_.empty());
483 // Now add a page and go back, so we have something to go forward to.
484 ui_test_utils::NavigateToURL(browser(), no_auth_page_3);
486 WindowedLoadStopObserver load_stop_waiter(controller, 1);
487 chrome::GoBack(browser(), CURRENT_TAB); // Should take us to page 1
488 load_stop_waiter.Wait();
492 // We wait for two LOAD_STOP events; one for each navigation.
493 WindowedLoadStopObserver load_stop_waiter(controller, 2);
494 WindowedAuthNeededObserver auth_needed_waiter(controller);
495 browser()->OpenURL(OpenURLParams(
496 auth_page, Referrer(), CURRENT_TAB, content::PAGE_TRANSITION_TYPED,
498 auth_needed_waiter.Wait();
499 WindowedAuthCancelledObserver auth_cancelled_waiter(controller);
500 ASSERT_TRUE(chrome::CanGoForward(browser()));
501 chrome::GoForward(browser(), CURRENT_TAB); // Should take us to page 3
502 auth_cancelled_waiter.Wait();
503 load_stop_waiter.Wait();
504 EXPECT_TRUE(observer.handlers_.empty());
507 // Now test that cancelling works as expected.
509 WindowedLoadStopObserver load_stop_waiter(controller, 1);
510 WindowedAuthNeededObserver auth_needed_waiter(controller);
511 browser()->OpenURL(OpenURLParams(
512 auth_page, Referrer(), CURRENT_TAB, content::PAGE_TRANSITION_TYPED,
514 auth_needed_waiter.Wait();
515 WindowedAuthCancelledObserver auth_cancelled_waiter(controller);
516 LoginHandler* handler = *observer.handlers_.begin();
517 ASSERT_TRUE(handler);
518 handler->CancelAuth();
519 auth_cancelled_waiter.Wait();
520 load_stop_waiter.Wait();
521 EXPECT_TRUE(observer.handlers_.empty());
525 // Test handling of resources that require authentication even though
526 // the page they are included on doesn't. In this case we should only
527 // present the minimal number of prompts necessary for successfully
528 // displaying the page. First we check whether cancelling works as
530 IN_PROC_BROWSER_TEST_F(LoginPromptBrowserTest, MultipleRealmCancellation) {
531 ASSERT_TRUE(test_server()->Start());
532 GURL test_page = test_server()->GetURL(kMultiRealmTestPage);
534 content::WebContents* contents =
535 browser()->tab_strip_model()->GetActiveWebContents();
536 NavigationController* controller = &contents->GetController();
537 LoginPromptBrowserTestObserver observer;
539 observer.Register(content::Source<NavigationController>(controller));
541 WindowedLoadStopObserver load_stop_waiter(controller, 1);
544 WindowedAuthNeededObserver auth_needed_waiter(controller);
545 browser()->OpenURL(OpenURLParams(
546 test_page, Referrer(), CURRENT_TAB, content::PAGE_TRANSITION_TYPED,
548 auth_needed_waiter.Wait();
553 while (n_handlers < kMultiRealmTestRealmCount) {
554 WindowedAuthNeededObserver auth_needed_waiter(controller);
556 while (!observer.handlers_.empty()) {
557 WindowedAuthCancelledObserver auth_cancelled_waiter(controller);
558 LoginHandler* handler = *observer.handlers_.begin();
560 ASSERT_TRUE(handler);
562 handler->CancelAuth();
563 auth_cancelled_waiter.Wait();
566 if (n_handlers < kMultiRealmTestRealmCount)
567 auth_needed_waiter.Wait();
570 load_stop_waiter.Wait();
572 EXPECT_EQ(kMultiRealmTestRealmCount, n_handlers);
573 EXPECT_EQ(0, observer.auth_supplied_count_);
574 EXPECT_LT(0, observer.auth_needed_count_);
575 EXPECT_LT(0, observer.auth_cancelled_count_);
576 EXPECT_TRUE(test_server()->Stop());
579 // Similar to the MultipleRealmCancellation test above, but tests
580 // whether supplying credentials work as exepcted.
581 IN_PROC_BROWSER_TEST_F(LoginPromptBrowserTest, MultipleRealmConfirmation) {
582 ASSERT_TRUE(test_server()->Start());
583 GURL test_page = test_server()->GetURL(kMultiRealmTestPage);
585 content::WebContents* contents =
586 browser()->tab_strip_model()->GetActiveWebContents();
587 NavigationController* controller = &contents->GetController();
588 LoginPromptBrowserTestObserver observer;
590 observer.Register(content::Source<NavigationController>(controller));
592 WindowedLoadStopObserver load_stop_waiter(controller, 1);
596 WindowedAuthNeededObserver auth_needed_waiter(controller);
598 browser()->OpenURL(OpenURLParams(
599 test_page, Referrer(), CURRENT_TAB, content::PAGE_TRANSITION_TYPED,
601 auth_needed_waiter.Wait();
604 while (n_handlers < kMultiRealmTestRealmCount) {
605 WindowedAuthNeededObserver auth_needed_waiter(controller);
607 while (!observer.handlers_.empty()) {
608 WindowedAuthSuppliedObserver auth_supplied_waiter(controller);
609 LoginHandler* handler = *observer.handlers_.begin();
611 ASSERT_TRUE(handler);
614 auth_supplied_waiter.Wait();
617 if (n_handlers < kMultiRealmTestRealmCount)
618 auth_needed_waiter.Wait();
621 load_stop_waiter.Wait();
623 EXPECT_EQ(kMultiRealmTestRealmCount, n_handlers);
624 EXPECT_LT(0, observer.auth_needed_count_);
625 EXPECT_LT(0, observer.auth_supplied_count_);
626 EXPECT_EQ(0, observer.auth_cancelled_count_);
627 EXPECT_TRUE(test_server()->Stop());
630 // Testing for recovery from an incorrect password for the case where
631 // there are multiple authenticated resources.
632 IN_PROC_BROWSER_TEST_F(LoginPromptBrowserTest, IncorrectConfirmation) {
633 ASSERT_TRUE(test_server()->Start());
634 GURL test_page = test_server()->GetURL(kSingleRealmTestPage);
636 content::WebContents* contents =
637 browser()->tab_strip_model()->GetActiveWebContents();
638 NavigationController* controller = &contents->GetController();
639 LoginPromptBrowserTestObserver observer;
641 observer.Register(content::Source<NavigationController>(controller));
644 WindowedAuthNeededObserver auth_needed_waiter(controller);
645 browser()->OpenURL(OpenURLParams(
646 test_page, Referrer(), CURRENT_TAB, content::PAGE_TRANSITION_TYPED,
648 auth_needed_waiter.Wait();
651 EXPECT_FALSE(observer.handlers_.empty());
653 if (!observer.handlers_.empty()) {
654 WindowedAuthNeededObserver auth_needed_waiter(controller);
655 WindowedAuthSuppliedObserver auth_supplied_waiter(controller);
656 LoginHandler* handler = *observer.handlers_.begin();
658 ASSERT_TRUE(handler);
659 handler->SetAuth(UTF8ToUTF16(bad_username_),
660 UTF8ToUTF16(bad_password_));
661 auth_supplied_waiter.Wait();
663 // The request should be retried after the incorrect password is
664 // supplied. This should result in a new AUTH_NEEDED notification
665 // for the same realm.
666 auth_needed_waiter.Wait();
671 while (n_handlers < 1) {
672 WindowedAuthNeededObserver auth_needed_waiter(controller);
674 while (!observer.handlers_.empty()) {
675 WindowedAuthSuppliedObserver auth_supplied_waiter(controller);
676 LoginHandler* handler = *observer.handlers_.begin();
678 ASSERT_TRUE(handler);
681 auth_supplied_waiter.Wait();
685 auth_needed_waiter.Wait();
688 // The single realm test has only one realm, and thus only one login
690 EXPECT_EQ(1, n_handlers);
691 EXPECT_LT(0, observer.auth_needed_count_);
692 EXPECT_EQ(0, observer.auth_cancelled_count_);
693 EXPECT_EQ(observer.auth_needed_count_, observer.auth_supplied_count_);
694 EXPECT_TRUE(test_server()->Stop());
697 // If the favicon is an authenticated resource, we shouldn't prompt
698 // for credentials. The same URL, if requested elsewhere should
699 // prompt for credentials.
700 IN_PROC_BROWSER_TEST_F(LoginPromptBrowserTest, NoLoginPromptForFavicon) {
701 const char* kFaviconTestPage = "files/login/has_favicon.html";
702 const char* kFaviconResource = "auth-basic/favicon.gif";
704 ASSERT_TRUE(test_server()->Start());
706 content::WebContents* contents =
707 browser()->tab_strip_model()->GetActiveWebContents();
708 NavigationController* controller = &contents->GetController();
709 LoginPromptBrowserTestObserver observer;
711 observer.Register(content::Source<NavigationController>(controller));
713 // First load a page that has a favicon that requires
714 // authentication. There should be no login prompt.
716 GURL test_page = test_server()->GetURL(kFaviconTestPage);
717 WindowedLoadStopObserver load_stop_waiter(controller, 1);
718 browser()->OpenURL(OpenURLParams(
719 test_page, Referrer(), CURRENT_TAB, content::PAGE_TRANSITION_TYPED,
721 load_stop_waiter.Wait();
724 // Now request the same favicon, but directly as the document.
725 // There should be one login prompt.
727 GURL test_page = test_server()->GetURL(kFaviconResource);
728 WindowedLoadStopObserver load_stop_waiter(controller, 1);
729 WindowedAuthNeededObserver auth_needed_waiter(controller);
730 browser()->OpenURL(OpenURLParams(
731 test_page, Referrer(), CURRENT_TAB, content::PAGE_TRANSITION_TYPED,
733 auth_needed_waiter.Wait();
734 ASSERT_EQ(1u, observer.handlers_.size());
736 while (!observer.handlers_.empty()) {
737 WindowedAuthCancelledObserver auth_cancelled_waiter(controller);
738 LoginHandler* handler = *observer.handlers_.begin();
740 ASSERT_TRUE(handler);
741 handler->CancelAuth();
742 auth_cancelled_waiter.Wait();
745 load_stop_waiter.Wait();
748 EXPECT_EQ(0, observer.auth_supplied_count_);
749 EXPECT_EQ(1, observer.auth_needed_count_);
750 EXPECT_EQ(1, observer.auth_cancelled_count_);
751 EXPECT_TRUE(test_server()->Stop());
754 // Block crossdomain image login prompting as a phishing defense.
755 IN_PROC_BROWSER_TEST_F(LoginPromptBrowserTest,
756 BlockCrossdomainPrompt) {
757 const char* kTestPage = "files/login/load_img_from_b.html";
759 host_resolver()->AddRule("www.a.com", "127.0.0.1");
760 host_resolver()->AddRule("www.b.com", "127.0.0.1");
761 ASSERT_TRUE(test_server()->Start());
763 content::WebContents* contents =
764 browser()->tab_strip_model()->GetActiveWebContents();
765 NavigationController* controller = &contents->GetController();
766 LoginPromptBrowserTestObserver observer;
767 observer.Register(content::Source<NavigationController>(controller));
769 // Load a page that has a cross-domain sub-resource authentication.
770 // There should be no login prompt.
772 GURL test_page = test_server()->GetURL(kTestPage);
773 ASSERT_EQ("127.0.0.1", test_page.host());
775 // Change the host from 127.0.0.1 to www.a.com so that when the
776 // page tries to load from b, it will be cross-origin.
777 std::string new_host("www.a.com");
778 GURL::Replacements replacements;
779 replacements.SetHostStr(new_host);
780 test_page = test_page.ReplaceComponents(replacements);
782 WindowedLoadStopObserver load_stop_waiter(controller, 1);
783 browser()->OpenURL(OpenURLParams(
784 test_page, Referrer(), CURRENT_TAB, content::PAGE_TRANSITION_TYPED,
786 load_stop_waiter.Wait();
789 EXPECT_EQ(0, observer.auth_needed_count_);
791 // Now request the same page, but from the same origin.
792 // There should be one login prompt.
794 GURL test_page = test_server()->GetURL(kTestPage);
795 ASSERT_EQ("127.0.0.1", test_page.host());
797 // Change the host from 127.0.0.1 to www.b.com so that when the
798 // page tries to load from b, it will be same-origin.
799 std::string new_host("www.b.com");
800 GURL::Replacements replacements;
801 replacements.SetHostStr(new_host);
802 test_page = test_page.ReplaceComponents(replacements);
804 WindowedAuthNeededObserver auth_needed_waiter(controller);
805 browser()->OpenURL(OpenURLParams(
806 test_page, Referrer(), CURRENT_TAB, content::PAGE_TRANSITION_TYPED,
808 auth_needed_waiter.Wait();
809 ASSERT_EQ(1u, observer.handlers_.size());
811 while (!observer.handlers_.empty()) {
812 WindowedAuthCancelledObserver auth_cancelled_waiter(controller);
813 LoginHandler* handler = *observer.handlers_.begin();
815 ASSERT_TRUE(handler);
816 handler->CancelAuth();
817 auth_cancelled_waiter.Wait();
821 EXPECT_EQ(1, observer.auth_needed_count_);
822 EXPECT_TRUE(test_server()->Stop());
825 // Allow crossdomain iframe login prompting despite the above.
826 IN_PROC_BROWSER_TEST_F(LoginPromptBrowserTest,
827 AllowCrossdomainPrompt) {
828 const char* kTestPage = "files/login/load_iframe_from_b.html";
830 host_resolver()->AddRule("www.a.com", "127.0.0.1");
831 host_resolver()->AddRule("www.b.com", "127.0.0.1");
832 ASSERT_TRUE(test_server()->Start());
834 content::WebContents* contents =
835 browser()->tab_strip_model()->GetActiveWebContents();
836 NavigationController* controller = &contents->GetController();
837 LoginPromptBrowserTestObserver observer;
838 observer.Register(content::Source<NavigationController>(controller));
840 // Load a page that has a cross-domain iframe authentication.
842 GURL test_page = test_server()->GetURL(kTestPage);
843 ASSERT_EQ("127.0.0.1", test_page.host());
845 // Change the host from 127.0.0.1 to www.a.com so that when the
846 // page tries to load from b, it will be cross-origin.
847 std::string new_host("www.a.com");
848 GURL::Replacements replacements;
849 replacements.SetHostStr(new_host);
850 test_page = test_page.ReplaceComponents(replacements);
852 WindowedAuthNeededObserver auth_needed_waiter(controller);
853 browser()->OpenURL(OpenURLParams(
854 test_page, Referrer(), CURRENT_TAB, content::PAGE_TRANSITION_TYPED,
856 auth_needed_waiter.Wait();
857 ASSERT_EQ(1u, observer.handlers_.size());
859 while (!observer.handlers_.empty()) {
860 WindowedAuthCancelledObserver auth_cancelled_waiter(controller);
861 LoginHandler* handler = *observer.handlers_.begin();
863 ASSERT_TRUE(handler);
864 handler->CancelAuth();
865 auth_cancelled_waiter.Wait();
869 EXPECT_EQ(1, observer.auth_needed_count_);
870 EXPECT_TRUE(test_server()->Stop());
873 IN_PROC_BROWSER_TEST_F(LoginPromptBrowserTest, SupplyRedundantAuths) {
874 ASSERT_TRUE(test_server()->Start());
876 // Get NavigationController for tab 1.
877 content::WebContents* contents_1 =
878 browser()->tab_strip_model()->GetActiveWebContents();
879 NavigationController* controller_1 = &contents_1->GetController();
882 ui_test_utils::NavigateToURLWithDisposition(
886 ui_test_utils::BROWSER_TEST_WAIT_FOR_TAB);
888 // Get NavigationController for tab 2.
889 content::WebContents* contents_2 =
890 browser()->tab_strip_model()->GetActiveWebContents();
891 ASSERT_NE(contents_1, contents_2);
892 NavigationController* controller_2 = &contents_2->GetController();
894 LoginPromptBrowserTestObserver observer;
895 observer.Register(content::Source<NavigationController>(controller_1));
896 observer.Register(content::Source<NavigationController>(controller_2));
899 // Open different auth urls in each tab.
900 WindowedAuthNeededObserver auth_needed_waiter_1(controller_1);
901 WindowedAuthNeededObserver auth_needed_waiter_2(controller_2);
902 contents_1->OpenURL(OpenURLParams(
903 test_server()->GetURL("auth-basic/1"),
906 content::PAGE_TRANSITION_TYPED,
908 contents_2->OpenURL(OpenURLParams(
909 test_server()->GetURL("auth-basic/2"),
912 content::PAGE_TRANSITION_TYPED,
914 auth_needed_waiter_1.Wait();
915 auth_needed_waiter_2.Wait();
917 ASSERT_EQ(2U, observer.handlers_.size());
919 // Supply auth in one of the tabs.
920 WindowedAuthSuppliedObserver auth_supplied_waiter_1(controller_1);
921 WindowedAuthSuppliedObserver auth_supplied_waiter_2(controller_2);
922 LoginHandler* handler_1 = *observer.handlers_.begin();
923 ASSERT_TRUE(handler_1);
924 SetAuthFor(handler_1);
926 // Both tabs should be authenticated.
927 auth_supplied_waiter_1.Wait();
928 auth_supplied_waiter_2.Wait();
931 EXPECT_EQ(2, observer.auth_needed_count_);
932 EXPECT_EQ(2, observer.auth_supplied_count_);
933 EXPECT_EQ(0, observer.auth_cancelled_count_);
934 EXPECT_TRUE(test_server()->Stop());
937 IN_PROC_BROWSER_TEST_F(LoginPromptBrowserTest, CancelRedundantAuths) {
938 ASSERT_TRUE(test_server()->Start());
940 // Get NavigationController for tab 1.
941 content::WebContents* contents_1 =
942 browser()->tab_strip_model()->GetActiveWebContents();
943 NavigationController* controller_1 = &contents_1->GetController();
946 ui_test_utils::NavigateToURLWithDisposition(
950 ui_test_utils::BROWSER_TEST_WAIT_FOR_TAB);
952 // Get NavigationController for tab 2.
953 content::WebContents* contents_2 =
954 browser()->tab_strip_model()->GetActiveWebContents();
955 ASSERT_NE(contents_1, contents_2);
956 NavigationController* controller_2 = &contents_2->GetController();
958 LoginPromptBrowserTestObserver observer;
959 observer.Register(content::Source<NavigationController>(controller_1));
960 observer.Register(content::Source<NavigationController>(controller_2));
963 // Open different auth urls in each tab.
964 WindowedAuthNeededObserver auth_needed_waiter_1(controller_1);
965 WindowedAuthNeededObserver auth_needed_waiter_2(controller_2);
966 contents_1->OpenURL(OpenURLParams(
967 test_server()->GetURL("auth-basic/1"),
970 content::PAGE_TRANSITION_TYPED,
972 contents_2->OpenURL(OpenURLParams(
973 test_server()->GetURL("auth-basic/2"),
976 content::PAGE_TRANSITION_TYPED,
978 auth_needed_waiter_1.Wait();
979 auth_needed_waiter_2.Wait();
981 ASSERT_EQ(2U, observer.handlers_.size());
983 // Cancel auth in one of the tabs.
984 WindowedAuthCancelledObserver auth_cancelled_waiter_1(controller_1);
985 WindowedAuthCancelledObserver auth_cancelled_waiter_2(controller_2);
986 LoginHandler* handler_1 = *observer.handlers_.begin();
987 ASSERT_TRUE(handler_1);
988 handler_1->CancelAuth();
990 // Both tabs should cancel auth.
991 auth_cancelled_waiter_1.Wait();
992 auth_cancelled_waiter_2.Wait();
995 EXPECT_EQ(2, observer.auth_needed_count_);
996 EXPECT_EQ(0, observer.auth_supplied_count_);
997 EXPECT_EQ(2, observer.auth_cancelled_count_);
998 EXPECT_TRUE(test_server()->Stop());
1001 IN_PROC_BROWSER_TEST_F(LoginPromptBrowserTest,
1002 SupplyRedundantAuthsMultiProfile) {
1003 ASSERT_TRUE(test_server()->Start());
1005 // Get NavigationController for regular tab.
1006 content::WebContents* contents =
1007 browser()->tab_strip_model()->GetActiveWebContents();
1008 NavigationController* controller = &contents->GetController();
1010 // Open an incognito window.
1011 Browser* browser_incognito = CreateIncognitoBrowser();
1013 // Get NavigationController for incognito tab.
1014 content::WebContents* contents_incognito =
1015 browser_incognito->tab_strip_model()->GetActiveWebContents();
1016 ASSERT_NE(contents, contents_incognito);
1017 NavigationController* controller_incognito =
1018 &contents_incognito->GetController();
1020 LoginPromptBrowserTestObserver observer;
1021 observer.Register(content::Source<NavigationController>(controller));
1022 LoginPromptBrowserTestObserver observer_incognito;
1023 observer_incognito.Register(
1024 content::Source<NavigationController>(controller_incognito));
1027 // Open an auth url in each window.
1028 WindowedAuthNeededObserver auth_needed_waiter(controller);
1029 WindowedAuthNeededObserver auth_needed_waiter_incognito(
1030 controller_incognito);
1031 contents->OpenURL(OpenURLParams(
1032 test_server()->GetURL("auth-basic/1"),
1033 content::Referrer(),
1035 content::PAGE_TRANSITION_TYPED,
1037 contents_incognito->OpenURL(OpenURLParams(
1038 test_server()->GetURL("auth-basic/2"),
1039 content::Referrer(),
1041 content::PAGE_TRANSITION_TYPED,
1043 auth_needed_waiter.Wait();
1044 auth_needed_waiter_incognito.Wait();
1046 ASSERT_EQ(1U, observer.handlers_.size());
1047 ASSERT_EQ(1U, observer_incognito.handlers_.size());
1049 // Supply auth in regular tab.
1050 WindowedAuthSuppliedObserver auth_supplied_waiter(controller);
1051 LoginHandler* handler = *observer.handlers_.begin();
1052 ASSERT_TRUE(handler);
1053 SetAuthFor(handler);
1055 // Regular tab should be authenticated.
1056 auth_supplied_waiter.Wait();
1058 // There's not really a way to wait for the incognito window to "do
1059 // nothing". Run anything pending in the message loop just to be sure.
1060 // (This shouldn't be necessary since notifications are synchronous, but
1061 // maybe it will help avoid flake someday in the future..)
1062 content::RunAllPendingInMessageLoop();
1065 EXPECT_EQ(1, observer.auth_needed_count_);
1066 EXPECT_EQ(1, observer.auth_supplied_count_);
1067 EXPECT_EQ(0, observer.auth_cancelled_count_);
1068 EXPECT_EQ(1, observer_incognito.auth_needed_count_);
1069 EXPECT_EQ(0, observer_incognito.auth_supplied_count_);
1070 EXPECT_EQ(0, observer_incognito.auth_cancelled_count_);
1071 EXPECT_TRUE(test_server()->Stop());