Disable view source for Developer Tools.
[chromium-blink-merge.git] / chrome / browser / ui / login / login_prompt_browsertest.cc
blob8f0d5327390e6ddd439fcf1cb9afe6d952d850c3
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.
5 #include <algorithm>
6 #include <list>
7 #include <map>
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;
30 namespace {
32 class LoginPromptBrowserTest : public InProcessBrowserTest {
33 public:
34 LoginPromptBrowserTest()
35 : bad_password_("incorrect"),
36 bad_username_("nouser"),
37 password_("secret"),
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_);
45 protected:
46 struct AuthInfo {
47 std::string username_;
48 std::string password_;
50 AuthInfo() {}
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);
61 AuthMap auth_map_;
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 {
85 public:
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_;
111 private:
112 content::NotificationRegistrar registrar_;
114 DISALLOW_COPY_AND_ASSIGN(LoginPromptBrowserTestObserver);
117 void LoginPromptBrowserTestObserver::Observe(
118 int type,
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(),
141 handlers_.end(),
142 handler);
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(),
150 handlers_.end(),
151 handler);
152 EXPECT_TRUE(i != handlers_.end());
153 if (i != handlers_.end())
154 handlers_.erase(i);
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);
164 template <int T>
165 class WindowedNavigationObserver
166 : public content::WindowedNotificationObserver {
167 public:
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> {
177 public:
178 WindowedLoadStopObserver(NavigationController* controller,
179 int notification_count)
180 : WindowedNavigationObserver<content::NOTIFICATION_LOAD_STOP>(controller),
181 remaining_notification_count_(notification_count) {}
182 protected:
183 virtual void Observe(int type,
184 const content::NotificationSource& source,
185 const content::NotificationDetails& details) OVERRIDE;
186 private:
187 int remaining_notification_count_; // Number of notifications remaining.
190 void WindowedLoadStopObserver::Observe(
191 int type,
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 {
237 public:
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_);
251 private:
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,
265 false));
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,
288 false));
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();
312 SetAuthFor(handler);
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,
338 false));
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));
383 // Open a new tab.
384 ui_test_utils::NavigateToURLWithDisposition(
385 browser(),
386 GURL("about:blank"),
387 NEW_FOREGROUND_TAB,
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
449 // go back 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
455 // no_auth_page_2.
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,
460 false));
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,
465 false));
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,
478 false));
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,
502 false));
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,
518 false));
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
534 // expected.
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,
552 false));
553 auth_needed_waiter.Wait();
556 int n_handlers = 0;
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);
566 n_handlers++;
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);
598 int n_handlers = 0;
601 WindowedAuthNeededObserver auth_needed_waiter(controller);
603 browser()->OpenURL(OpenURLParams(
604 test_page, Referrer(), CURRENT_TAB, content::PAGE_TRANSITION_TYPED,
605 false));
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);
617 n_handlers++;
618 SetAuthFor(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,
652 false));
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();
674 int n_handlers = 0;
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);
684 n_handlers++;
685 SetAuthFor(handler);
686 auth_supplied_waiter.Wait();
689 if (n_handlers < 1)
690 auth_needed_waiter.Wait();
693 // The single realm test has only one realm, and thus only one login
694 // prompt.
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,
725 false));
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,
737 false));
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,
790 false));
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,
812 false));
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,
860 false));
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();
886 // Open a new tab.
887 ui_test_utils::NavigateToURLWithDisposition(
888 browser(),
889 GURL("about:blank"),
890 NEW_FOREGROUND_TAB,
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"),
909 content::Referrer(),
910 CURRENT_TAB,
911 content::PAGE_TRANSITION_TYPED,
912 false));
913 contents_2->OpenURL(OpenURLParams(
914 test_server()->GetURL("auth-basic/2"),
915 content::Referrer(),
916 CURRENT_TAB,
917 content::PAGE_TRANSITION_TYPED,
918 false));
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();
950 // Open a new tab.
951 ui_test_utils::NavigateToURLWithDisposition(
952 browser(),
953 GURL("about:blank"),
954 NEW_FOREGROUND_TAB,
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"),
973 content::Referrer(),
974 CURRENT_TAB,
975 content::PAGE_TRANSITION_TYPED,
976 false));
977 contents_2->OpenURL(OpenURLParams(
978 test_server()->GetURL("auth-basic/2"),
979 content::Referrer(),
980 CURRENT_TAB,
981 content::PAGE_TRANSITION_TYPED,
982 false));
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(),
1039 CURRENT_TAB,
1040 content::PAGE_TRANSITION_TYPED,
1041 false));
1042 contents_incognito->OpenURL(OpenURLParams(
1043 test_server()->GetURL("auth-basic/2"),
1044 content::Referrer(),
1045 CURRENT_TAB,
1046 content::PAGE_TRANSITION_TYPED,
1047 false));
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());
1079 } // namespace