Upstream version 10.39.225.0
[platform/framework/web/crosswalk.git] / src / chrome / browser / ui / login / login_prompt_browsertest.cc
1 // Copyright (c) 2012 The Chromium Authors. All rights reserved.
2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file.
4
5 #include <algorithm>
6 #include <list>
7 #include <map>
8
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/login/login_prompt_test_utils.h"
17 #include "chrome/browser/ui/tabs/tab_strip_model.h"
18 #include "chrome/test/base/in_process_browser_test.h"
19 #include "chrome/test/base/ui_test_utils.h"
20 #include "content/public/browser/interstitial_page.h"
21 #include "content/public/browser/notification_details.h"
22 #include "content/public/browser/notification_source.h"
23 #include "content/public/browser/web_contents.h"
24 #include "content/public/test/browser_test_utils.h"
25 #include "content/public/test/test_navigation_observer.h"
26 #include "net/base/auth.h"
27 #include "net/dns/mock_host_resolver.h"
28 #include "net/test/spawned_test_server/spawned_test_server.h"
29
30 using content::NavigationController;
31 using content::OpenURLParams;
32 using content::Referrer;
33
34 namespace {
35
36 class LoginPromptBrowserTest : public InProcessBrowserTest {
37  public:
38   LoginPromptBrowserTest()
39       : bad_password_("incorrect"),
40         bad_username_("nouser"),
41         password_("secret"),
42         username_basic_("basicuser"),
43         username_digest_("digestuser") {
44     auth_map_["foo"] = AuthInfo("testuser", "foopassword");
45     auth_map_["bar"] = AuthInfo("testuser", "barpassword");
46     auth_map_["testrealm"] = AuthInfo(username_basic_, password_);
47   }
48
49  protected:
50   struct AuthInfo {
51     std::string username_;
52     std::string password_;
53
54     AuthInfo() {}
55
56     AuthInfo(const std::string& username,
57              const std::string& password)
58         : username_(username), password_(password) {}
59   };
60
61   typedef std::map<std::string, AuthInfo> AuthMap;
62
63   void SetAuthFor(LoginHandler* handler);
64
65   void TestCrossOriginPrompt(const GURL& visit_url,
66                              const std::string& landing_host) const;
67
68   AuthMap auth_map_;
69   std::string bad_password_;
70   std::string bad_username_;
71   std::string password_;
72   std::string username_basic_;
73   std::string username_digest_;
74 };
75
76 void LoginPromptBrowserTest::SetAuthFor(LoginHandler* handler) {
77   const net::AuthChallengeInfo* challenge = handler->auth_info();
78
79   ASSERT_TRUE(challenge);
80   AuthMap::iterator i = auth_map_.find(challenge->realm);
81   EXPECT_TRUE(auth_map_.end() != i);
82   if (i != auth_map_.end()) {
83     const AuthInfo& info = i->second;
84     handler->SetAuth(base::UTF8ToUTF16(info.username_),
85                      base::UTF8ToUTF16(info.password_));
86   }
87 }
88
89 class InterstitialObserver : public content::WebContentsObserver {
90  public:
91   InterstitialObserver(content::WebContents* web_contents,
92                        const base::Closure& attach_callback,
93                        const base::Closure& detach_callback)
94       : WebContentsObserver(web_contents),
95         attach_callback_(attach_callback),
96         detach_callback_(detach_callback) {
97   }
98
99   virtual void DidAttachInterstitialPage() OVERRIDE {
100     attach_callback_.Run();
101   }
102
103   virtual void DidDetachInterstitialPage() OVERRIDE {
104     detach_callback_.Run();
105   }
106
107  private:
108   base::Closure attach_callback_;
109   base::Closure detach_callback_;
110
111   DISALLOW_COPY_AND_ASSIGN(InterstitialObserver);
112 };
113
114 void WaitForInterstitialAttach(content::WebContents* web_contents) {
115   scoped_refptr<content::MessageLoopRunner> interstitial_attach_loop_runner(
116       new content::MessageLoopRunner);
117   InterstitialObserver observer(
118       web_contents,
119       interstitial_attach_loop_runner->QuitClosure(),
120       base::Closure());
121   if (!content::InterstitialPage::GetInterstitialPage(web_contents))
122     interstitial_attach_loop_runner->Run();
123 }
124
125 const char kPrefetchAuthPage[] = "files/login/prefetch.html";
126
127 const char kMultiRealmTestPage[] = "files/login/multi_realm.html";
128 const int  kMultiRealmTestRealmCount = 2;
129
130 const char kSingleRealmTestPage[] = "files/login/single_realm.html";
131
132 const char* kAuthBasicPage = "auth-basic";
133 const char* kAuthDigestPage = "auth-digest";
134
135 base::string16 ExpectedTitleFromAuth(const base::string16& username,
136                                      const base::string16& password) {
137   // The TestServer sets the title to username/password on successful login.
138   return username + base::UTF8ToUTF16("/") + password;
139 }
140
141 // Confirm that <link rel="prefetch"> targetting an auth required
142 // resource does not provide a login dialog.  These types of requests
143 // should instead just cancel the auth.
144
145 // Unfortunately, this test doesn't assert on anything for its
146 // correctness.  Instead, it relies on the auth dialog blocking the
147 // browser, and triggering a timeout to cause failure when the
148 // prefetch resource requires authorization.
149 IN_PROC_BROWSER_TEST_F(LoginPromptBrowserTest, PrefetchAuthCancels) {
150   ASSERT_TRUE(test_server()->Start());
151
152   GURL test_page = test_server()->GetURL(kPrefetchAuthPage);
153
154   class SetPrefetchForTest {
155    public:
156     explicit SetPrefetchForTest(bool prefetch)
157         : old_prerender_mode_(prerender::PrerenderManager::GetMode()) {
158       std::string exp_group = prefetch ? "ExperimentYes" : "ExperimentNo";
159       base::FieldTrialList::CreateFieldTrial("Prefetch", exp_group);
160       // Disable prerender so this is just a prefetch of the top-level page.
161       prerender::PrerenderManager::SetMode(
162           prerender::PrerenderManager::PRERENDER_MODE_DISABLED);
163     }
164
165     ~SetPrefetchForTest() {
166       prerender::PrerenderManager::SetMode(old_prerender_mode_);
167     }
168
169    private:
170     prerender::PrerenderManager::PrerenderManagerMode old_prerender_mode_;
171   } set_prefetch_for_test(true);
172
173   content::WebContents* contents =
174       browser()->tab_strip_model()->GetActiveWebContents();
175   NavigationController* controller = &contents->GetController();
176   LoginPromptBrowserTestObserver observer;
177
178   observer.Register(content::Source<NavigationController>(controller));
179
180   WindowedLoadStopObserver load_stop_waiter(controller, 1);
181   browser()->OpenURL(OpenURLParams(
182       test_page, Referrer(), CURRENT_TAB, ui::PAGE_TRANSITION_TYPED,
183       false));
184
185   load_stop_waiter.Wait();
186   EXPECT_TRUE(observer.handlers().empty());
187   EXPECT_TRUE(test_server()->Stop());
188 }
189
190 // Test that "Basic" HTTP authentication works.
191 IN_PROC_BROWSER_TEST_F(LoginPromptBrowserTest, TestBasicAuth) {
192   ASSERT_TRUE(test_server()->Start());
193   GURL test_page = test_server()->GetURL(kAuthBasicPage);
194
195   content::WebContents* contents =
196       browser()->tab_strip_model()->GetActiveWebContents();
197   NavigationController* controller = &contents->GetController();
198   LoginPromptBrowserTestObserver observer;
199
200   observer.Register(content::Source<NavigationController>(controller));
201
202   {
203     WindowedAuthNeededObserver auth_needed_waiter(controller);
204     browser()->OpenURL(OpenURLParams(
205         test_page, Referrer(), CURRENT_TAB, ui::PAGE_TRANSITION_TYPED,
206         false));
207     auth_needed_waiter.Wait();
208   }
209
210   ASSERT_FALSE(observer.handlers().empty());
211   {
212     WindowedAuthNeededObserver auth_needed_waiter(controller);
213     WindowedAuthSuppliedObserver auth_supplied_waiter(controller);
214     LoginHandler* handler = *observer.handlers().begin();
215
216     ASSERT_TRUE(handler);
217     handler->SetAuth(base::UTF8ToUTF16(bad_username_),
218                      base::UTF8ToUTF16(bad_password_));
219     auth_supplied_waiter.Wait();
220
221     // The request should be retried after the incorrect password is
222     // supplied.  This should result in a new AUTH_NEEDED notification
223     // for the same realm.
224     auth_needed_waiter.Wait();
225   }
226
227   ASSERT_EQ(1u, observer.handlers().size());
228   WindowedAuthSuppliedObserver auth_supplied_waiter(controller);
229   LoginHandler* handler = *observer.handlers().begin();
230   SetAuthFor(handler);
231   auth_supplied_waiter.Wait();
232
233   base::string16 expected_title =
234       ExpectedTitleFromAuth(base::ASCIIToUTF16("basicuser"),
235                             base::ASCIIToUTF16("secret"));
236   content::TitleWatcher title_watcher(contents, expected_title);
237   EXPECT_EQ(expected_title, title_watcher.WaitAndGetTitle());
238 }
239
240 // Test that "Digest" HTTP authentication works.
241 IN_PROC_BROWSER_TEST_F(LoginPromptBrowserTest, TestDigestAuth) {
242   ASSERT_TRUE(test_server()->Start());
243   GURL test_page = test_server()->GetURL(kAuthDigestPage);
244
245   content::WebContents* contents =
246       browser()->tab_strip_model()->GetActiveWebContents();
247   NavigationController* controller = &contents->GetController();
248   LoginPromptBrowserTestObserver observer;
249
250   observer.Register(content::Source<NavigationController>(controller));
251
252   {
253     WindowedAuthNeededObserver auth_needed_waiter(controller);
254     browser()->OpenURL(OpenURLParams(
255         test_page, Referrer(), CURRENT_TAB, ui::PAGE_TRANSITION_TYPED,
256         false));
257     auth_needed_waiter.Wait();
258   }
259
260   ASSERT_FALSE(observer.handlers().empty());
261   {
262     WindowedAuthNeededObserver auth_needed_waiter(controller);
263     WindowedAuthSuppliedObserver auth_supplied_waiter(controller);
264     LoginHandler* handler = *observer.handlers().begin();
265
266     ASSERT_TRUE(handler);
267     handler->SetAuth(base::UTF8ToUTF16(bad_username_),
268                      base::UTF8ToUTF16(bad_password_));
269     auth_supplied_waiter.Wait();
270
271     // The request should be retried after the incorrect password is
272     // supplied.  This should result in a new AUTH_NEEDED notification
273     // for the same realm.
274     auth_needed_waiter.Wait();
275   }
276
277   ASSERT_EQ(1u, observer.handlers().size());
278   WindowedAuthSuppliedObserver auth_supplied_waiter(controller);
279   LoginHandler* handler = *observer.handlers().begin();
280
281   base::string16 username(base::UTF8ToUTF16(username_digest_));
282   base::string16 password(base::UTF8ToUTF16(password_));
283   handler->SetAuth(username, password);
284   auth_supplied_waiter.Wait();
285
286   base::string16 expected_title = ExpectedTitleFromAuth(username, password);
287   content::TitleWatcher title_watcher(contents, expected_title);
288   EXPECT_EQ(expected_title, title_watcher.WaitAndGetTitle());
289 }
290
291 IN_PROC_BROWSER_TEST_F(LoginPromptBrowserTest, TestTwoAuths) {
292   ASSERT_TRUE(test_server()->Start());
293
294   content::WebContents* contents1 =
295       browser()->tab_strip_model()->GetActiveWebContents();
296   NavigationController* controller1 = &contents1->GetController();
297   LoginPromptBrowserTestObserver observer;
298
299   observer.Register(content::Source<NavigationController>(controller1));
300
301   // Open a new tab.
302   ui_test_utils::NavigateToURLWithDisposition(
303       browser(),
304       GURL("about:blank"),
305       NEW_FOREGROUND_TAB,
306       ui_test_utils::BROWSER_TEST_WAIT_FOR_TAB);
307
308   content::WebContents* contents2 =
309       browser()->tab_strip_model()->GetActiveWebContents();
310   ASSERT_NE(contents1, contents2);
311   NavigationController* controller2 = &contents2->GetController();
312   observer.Register(content::Source<NavigationController>(controller2));
313
314   {
315     WindowedAuthNeededObserver auth_needed_waiter(controller1);
316     contents1->OpenURL(OpenURLParams(
317         test_server()->GetURL(kAuthBasicPage), Referrer(),
318         CURRENT_TAB, ui::PAGE_TRANSITION_TYPED, false));
319     auth_needed_waiter.Wait();
320   }
321
322   {
323     WindowedAuthNeededObserver auth_needed_waiter(controller2);
324     contents2->OpenURL(OpenURLParams(
325         test_server()->GetURL(kAuthDigestPage), Referrer(),
326         CURRENT_TAB, ui::PAGE_TRANSITION_TYPED, false));
327     auth_needed_waiter.Wait();
328   }
329
330   ASSERT_EQ(2u, observer.handlers().size());
331
332   LoginHandler* handler1 = *observer.handlers().begin();
333   LoginHandler* handler2 = *(++(observer.handlers().begin()));
334
335   base::string16 expected_title1 = ExpectedTitleFromAuth(
336       base::UTF8ToUTF16(username_basic_), base::UTF8ToUTF16(password_));
337   base::string16 expected_title2 = ExpectedTitleFromAuth(
338       base::UTF8ToUTF16(username_digest_), base::UTF8ToUTF16(password_));
339   content::TitleWatcher title_watcher1(contents1, expected_title1);
340   content::TitleWatcher title_watcher2(contents2, expected_title2);
341
342   handler1->SetAuth(base::UTF8ToUTF16(username_basic_),
343                     base::UTF8ToUTF16(password_));
344   handler2->SetAuth(base::UTF8ToUTF16(username_digest_),
345                     base::UTF8ToUTF16(password_));
346
347   EXPECT_EQ(expected_title1, title_watcher1.WaitAndGetTitle());
348   EXPECT_EQ(expected_title2, title_watcher2.WaitAndGetTitle());
349 }
350
351 // Test login prompt cancellation.
352 IN_PROC_BROWSER_TEST_F(LoginPromptBrowserTest, TestCancelAuth) {
353   ASSERT_TRUE(test_server()->Start());
354   GURL auth_page = test_server()->GetURL(kAuthBasicPage);
355   GURL no_auth_page_1 = test_server()->GetURL("a");
356   GURL no_auth_page_2 = test_server()->GetURL("b");
357   GURL no_auth_page_3 = test_server()->GetURL("c");
358
359   content::WebContents* contents =
360       browser()->tab_strip_model()->GetActiveWebContents();
361   NavigationController* controller = &contents->GetController();
362
363   LoginPromptBrowserTestObserver observer;
364   observer.Register(content::Source<NavigationController>(controller));
365
366   // First navigate to an unauthenticated page so we have something to
367   // go back to.
368   ui_test_utils::NavigateToURL(browser(), no_auth_page_1);
369
370   // Navigating while auth is requested is the same as cancelling.
371   {
372     // We need to wait for two LOAD_STOP events.  One for auth_page and one for
373     // no_auth_page_2.
374     WindowedLoadStopObserver load_stop_waiter(controller, 2);
375     WindowedAuthNeededObserver auth_needed_waiter(controller);
376     browser()->OpenURL(OpenURLParams(
377         auth_page, Referrer(), CURRENT_TAB, ui::PAGE_TRANSITION_TYPED,
378         false));
379     auth_needed_waiter.Wait();
380     WindowedAuthCancelledObserver auth_cancelled_waiter(controller);
381     browser()->OpenURL(OpenURLParams(
382         no_auth_page_2, Referrer(), CURRENT_TAB, ui::PAGE_TRANSITION_TYPED,
383         false));
384     auth_cancelled_waiter.Wait();
385     load_stop_waiter.Wait();
386     EXPECT_TRUE(observer.handlers().empty());
387   }
388
389   // Try navigating backwards.
390   {
391     // As above, we wait for two LOAD_STOP events; one for each navigation.
392     WindowedLoadStopObserver load_stop_waiter(controller, 2);
393     WindowedAuthNeededObserver auth_needed_waiter(controller);
394     browser()->OpenURL(OpenURLParams(
395         auth_page, Referrer(), CURRENT_TAB, ui::PAGE_TRANSITION_TYPED,
396         false));
397     auth_needed_waiter.Wait();
398     WindowedAuthCancelledObserver auth_cancelled_waiter(controller);
399     ASSERT_TRUE(chrome::CanGoBack(browser()));
400     chrome::GoBack(browser(), CURRENT_TAB);
401     auth_cancelled_waiter.Wait();
402     load_stop_waiter.Wait();
403     EXPECT_TRUE(observer.handlers().empty());
404   }
405
406   // Now add a page and go back, so we have something to go forward to.
407   ui_test_utils::NavigateToURL(browser(), no_auth_page_3);
408   {
409     WindowedLoadStopObserver load_stop_waiter(controller, 1);
410     chrome::GoBack(browser(), CURRENT_TAB);  // Should take us to page 1
411     load_stop_waiter.Wait();
412   }
413
414   {
415     // We wait for two LOAD_STOP events; one for each navigation.
416     WindowedLoadStopObserver load_stop_waiter(controller, 2);
417     WindowedAuthNeededObserver auth_needed_waiter(controller);
418     browser()->OpenURL(OpenURLParams(
419         auth_page, Referrer(), CURRENT_TAB, ui::PAGE_TRANSITION_TYPED,
420         false));
421     auth_needed_waiter.Wait();
422     WindowedAuthCancelledObserver auth_cancelled_waiter(controller);
423     ASSERT_TRUE(chrome::CanGoForward(browser()));
424     chrome::GoForward(browser(), CURRENT_TAB);  // Should take us to page 3
425     auth_cancelled_waiter.Wait();
426     load_stop_waiter.Wait();
427     EXPECT_TRUE(observer.handlers().empty());
428   }
429
430   // Now test that cancelling works as expected.
431   {
432     WindowedLoadStopObserver load_stop_waiter(controller, 1);
433     WindowedAuthNeededObserver auth_needed_waiter(controller);
434     browser()->OpenURL(OpenURLParams(
435         auth_page, Referrer(), CURRENT_TAB, ui::PAGE_TRANSITION_TYPED,
436         false));
437     auth_needed_waiter.Wait();
438     WindowedAuthCancelledObserver auth_cancelled_waiter(controller);
439     LoginHandler* handler = *observer.handlers().begin();
440     ASSERT_TRUE(handler);
441     handler->CancelAuth();
442     auth_cancelled_waiter.Wait();
443     load_stop_waiter.Wait();
444     EXPECT_TRUE(observer.handlers().empty());
445   }
446 }
447
448 // Test handling of resources that require authentication even though
449 // the page they are included on doesn't.  In this case we should only
450 // present the minimal number of prompts necessary for successfully
451 // displaying the page.  First we check whether cancelling works as
452 // expected.
453 IN_PROC_BROWSER_TEST_F(LoginPromptBrowserTest, MultipleRealmCancellation) {
454   ASSERT_TRUE(test_server()->Start());
455   GURL test_page = test_server()->GetURL(kMultiRealmTestPage);
456
457   content::WebContents* contents =
458       browser()->tab_strip_model()->GetActiveWebContents();
459   NavigationController* controller = &contents->GetController();
460   LoginPromptBrowserTestObserver observer;
461
462   observer.Register(content::Source<NavigationController>(controller));
463
464   WindowedLoadStopObserver load_stop_waiter(controller, 1);
465
466   {
467     WindowedAuthNeededObserver auth_needed_waiter(controller);
468     browser()->OpenURL(OpenURLParams(
469         test_page, Referrer(), CURRENT_TAB, ui::PAGE_TRANSITION_TYPED,
470         false));
471     auth_needed_waiter.Wait();
472   }
473
474   int n_handlers = 0;
475
476   while (n_handlers < kMultiRealmTestRealmCount) {
477     WindowedAuthNeededObserver auth_needed_waiter(controller);
478
479     while (!observer.handlers().empty()) {
480       WindowedAuthCancelledObserver auth_cancelled_waiter(controller);
481       LoginHandler* handler = *observer.handlers().begin();
482
483       ASSERT_TRUE(handler);
484       n_handlers++;
485       handler->CancelAuth();
486       auth_cancelled_waiter.Wait();
487     }
488
489     if (n_handlers < kMultiRealmTestRealmCount)
490       auth_needed_waiter.Wait();
491   }
492
493   load_stop_waiter.Wait();
494
495   EXPECT_EQ(kMultiRealmTestRealmCount, n_handlers);
496   EXPECT_EQ(0, observer.auth_supplied_count());
497   EXPECT_LT(0, observer.auth_needed_count());
498   EXPECT_LT(0, observer.auth_cancelled_count());
499   EXPECT_TRUE(test_server()->Stop());
500 }
501
502 // Similar to the MultipleRealmCancellation test above, but tests
503 // whether supplying credentials work as exepcted.
504 IN_PROC_BROWSER_TEST_F(LoginPromptBrowserTest, MultipleRealmConfirmation) {
505   ASSERT_TRUE(test_server()->Start());
506   GURL test_page = test_server()->GetURL(kMultiRealmTestPage);
507
508   content::WebContents* contents =
509       browser()->tab_strip_model()->GetActiveWebContents();
510   NavigationController* controller = &contents->GetController();
511   LoginPromptBrowserTestObserver observer;
512
513   observer.Register(content::Source<NavigationController>(controller));
514
515   WindowedLoadStopObserver load_stop_waiter(controller, 1);
516   int n_handlers = 0;
517
518   {
519     WindowedAuthNeededObserver auth_needed_waiter(controller);
520
521     browser()->OpenURL(OpenURLParams(
522         test_page, Referrer(), CURRENT_TAB, ui::PAGE_TRANSITION_TYPED,
523         false));
524     auth_needed_waiter.Wait();
525   }
526
527   while (n_handlers < kMultiRealmTestRealmCount) {
528     WindowedAuthNeededObserver auth_needed_waiter(controller);
529
530     while (!observer.handlers().empty()) {
531       WindowedAuthSuppliedObserver auth_supplied_waiter(controller);
532       LoginHandler* handler = *observer.handlers().begin();
533
534       ASSERT_TRUE(handler);
535       n_handlers++;
536       SetAuthFor(handler);
537       auth_supplied_waiter.Wait();
538     }
539
540     if (n_handlers < kMultiRealmTestRealmCount)
541       auth_needed_waiter.Wait();
542   }
543
544   load_stop_waiter.Wait();
545
546   EXPECT_EQ(kMultiRealmTestRealmCount, n_handlers);
547   EXPECT_LT(0, observer.auth_needed_count());
548   EXPECT_LT(0, observer.auth_supplied_count());
549   EXPECT_EQ(0, observer.auth_cancelled_count());
550   EXPECT_TRUE(test_server()->Stop());
551 }
552
553 // Testing for recovery from an incorrect password for the case where
554 // there are multiple authenticated resources.
555 IN_PROC_BROWSER_TEST_F(LoginPromptBrowserTest, IncorrectConfirmation) {
556   ASSERT_TRUE(test_server()->Start());
557   GURL test_page = test_server()->GetURL(kSingleRealmTestPage);
558
559   content::WebContents* contents =
560       browser()->tab_strip_model()->GetActiveWebContents();
561   NavigationController* controller = &contents->GetController();
562   LoginPromptBrowserTestObserver observer;
563
564   observer.Register(content::Source<NavigationController>(controller));
565
566   {
567     WindowedAuthNeededObserver auth_needed_waiter(controller);
568     browser()->OpenURL(OpenURLParams(
569         test_page, Referrer(), CURRENT_TAB, ui::PAGE_TRANSITION_TYPED,
570         false));
571     auth_needed_waiter.Wait();
572   }
573
574   EXPECT_FALSE(observer.handlers().empty());
575
576   if (!observer.handlers().empty()) {
577     WindowedAuthNeededObserver auth_needed_waiter(controller);
578     WindowedAuthSuppliedObserver auth_supplied_waiter(controller);
579     LoginHandler* handler = *observer.handlers().begin();
580
581     ASSERT_TRUE(handler);
582     handler->SetAuth(base::UTF8ToUTF16(bad_username_),
583                      base::UTF8ToUTF16(bad_password_));
584     auth_supplied_waiter.Wait();
585
586     // The request should be retried after the incorrect password is
587     // supplied.  This should result in a new AUTH_NEEDED notification
588     // for the same realm.
589     auth_needed_waiter.Wait();
590   }
591
592   int n_handlers = 0;
593
594   while (n_handlers < 1) {
595     WindowedAuthNeededObserver auth_needed_waiter(controller);
596
597     while (!observer.handlers().empty()) {
598       WindowedAuthSuppliedObserver auth_supplied_waiter(controller);
599       LoginHandler* handler = *observer.handlers().begin();
600
601       ASSERT_TRUE(handler);
602       n_handlers++;
603       SetAuthFor(handler);
604       auth_supplied_waiter.Wait();
605     }
606
607     if (n_handlers < 1)
608       auth_needed_waiter.Wait();
609   }
610
611   // The single realm test has only one realm, and thus only one login
612   // prompt.
613   EXPECT_EQ(1, n_handlers);
614   EXPECT_LT(0, observer.auth_needed_count());
615   EXPECT_EQ(0, observer.auth_cancelled_count());
616   EXPECT_EQ(observer.auth_needed_count(), observer.auth_supplied_count());
617   EXPECT_TRUE(test_server()->Stop());
618 }
619
620 // If the favicon is an authenticated resource, we shouldn't prompt
621 // for credentials.  The same URL, if requested elsewhere should
622 // prompt for credentials.
623 IN_PROC_BROWSER_TEST_F(LoginPromptBrowserTest, NoLoginPromptForFavicon) {
624   const char* kFaviconTestPage = "files/login/has_favicon.html";
625   const char* kFaviconResource = "auth-basic/favicon.gif";
626
627   ASSERT_TRUE(test_server()->Start());
628
629   content::WebContents* contents =
630       browser()->tab_strip_model()->GetActiveWebContents();
631   NavigationController* controller = &contents->GetController();
632   LoginPromptBrowserTestObserver observer;
633
634   observer.Register(content::Source<NavigationController>(controller));
635
636   // First load a page that has a favicon that requires
637   // authentication.  There should be no login prompt.
638   {
639     GURL test_page = test_server()->GetURL(kFaviconTestPage);
640     WindowedLoadStopObserver load_stop_waiter(controller, 1);
641     browser()->OpenURL(OpenURLParams(
642         test_page, Referrer(), CURRENT_TAB, ui::PAGE_TRANSITION_TYPED,
643         false));
644     load_stop_waiter.Wait();
645   }
646
647   // Now request the same favicon, but directly as the document.
648   // There should be one login prompt.
649   {
650     GURL test_page = test_server()->GetURL(kFaviconResource);
651     WindowedLoadStopObserver load_stop_waiter(controller, 1);
652     WindowedAuthNeededObserver auth_needed_waiter(controller);
653     browser()->OpenURL(OpenURLParams(
654         test_page, Referrer(), CURRENT_TAB, ui::PAGE_TRANSITION_TYPED,
655         false));
656     auth_needed_waiter.Wait();
657     ASSERT_EQ(1u, observer.handlers().size());
658
659     while (!observer.handlers().empty()) {
660       WindowedAuthCancelledObserver auth_cancelled_waiter(controller);
661       LoginHandler* handler = *observer.handlers().begin();
662
663       ASSERT_TRUE(handler);
664       handler->CancelAuth();
665       auth_cancelled_waiter.Wait();
666     }
667
668     load_stop_waiter.Wait();
669   }
670
671   EXPECT_EQ(0, observer.auth_supplied_count());
672   EXPECT_EQ(1, observer.auth_needed_count());
673   EXPECT_EQ(1, observer.auth_cancelled_count());
674   EXPECT_TRUE(test_server()->Stop());
675 }
676
677 // Block crossdomain image login prompting as a phishing defense.
678 IN_PROC_BROWSER_TEST_F(LoginPromptBrowserTest,
679                        BlockCrossdomainPromptForSubresources) {
680   const char* kTestPage = "files/login/load_img_from_b.html";
681
682   host_resolver()->AddRule("www.a.com", "127.0.0.1");
683   host_resolver()->AddRule("www.b.com", "127.0.0.1");
684   ASSERT_TRUE(test_server()->Start());
685
686   content::WebContents* contents =
687       browser()->tab_strip_model()->GetActiveWebContents();
688   NavigationController* controller = &contents->GetController();
689   LoginPromptBrowserTestObserver observer;
690   observer.Register(content::Source<NavigationController>(controller));
691
692   // Load a page that has a cross-domain sub-resource authentication.
693   // There should be no login prompt.
694   {
695     GURL test_page = test_server()->GetURL(kTestPage);
696     ASSERT_EQ("127.0.0.1", test_page.host());
697
698     // Change the host from 127.0.0.1 to www.a.com so that when the
699     // page tries to load from b, it will be cross-origin.
700     std::string new_host("www.a.com");
701     GURL::Replacements replacements;
702     replacements.SetHostStr(new_host);
703     test_page = test_page.ReplaceComponents(replacements);
704
705     WindowedLoadStopObserver load_stop_waiter(controller, 1);
706     browser()->OpenURL(OpenURLParams(
707         test_page, Referrer(), CURRENT_TAB, ui::PAGE_TRANSITION_TYPED,
708         false));
709     load_stop_waiter.Wait();
710   }
711
712   EXPECT_EQ(0, observer.auth_needed_count());
713
714   // Now request the same page, but from the same origin.
715   // There should be one login prompt.
716   {
717     GURL test_page = test_server()->GetURL(kTestPage);
718     ASSERT_EQ("127.0.0.1", test_page.host());
719
720     // Change the host from 127.0.0.1 to www.b.com so that when the
721     // page tries to load from b, it will be same-origin.
722     std::string new_host("www.b.com");
723     GURL::Replacements replacements;
724     replacements.SetHostStr(new_host);
725     test_page = test_page.ReplaceComponents(replacements);
726
727     WindowedAuthNeededObserver auth_needed_waiter(controller);
728     browser()->OpenURL(OpenURLParams(
729         test_page, Referrer(), CURRENT_TAB, ui::PAGE_TRANSITION_TYPED,
730         false));
731     auth_needed_waiter.Wait();
732     ASSERT_EQ(1u, observer.handlers().size());
733
734     while (!observer.handlers().empty()) {
735       WindowedAuthCancelledObserver auth_cancelled_waiter(controller);
736       LoginHandler* handler = *observer.handlers().begin();
737
738       ASSERT_TRUE(handler);
739       handler->CancelAuth();
740       auth_cancelled_waiter.Wait();
741     }
742   }
743
744   EXPECT_EQ(1, observer.auth_needed_count());
745   EXPECT_TRUE(test_server()->Stop());
746 }
747
748 // Allow crossdomain iframe login prompting despite the above.
749 IN_PROC_BROWSER_TEST_F(LoginPromptBrowserTest,
750                        AllowCrossdomainPromptForSubframes) {
751   const char* kTestPage = "files/login/load_iframe_from_b.html";
752
753   host_resolver()->AddRule("www.a.com", "127.0.0.1");
754   host_resolver()->AddRule("www.b.com", "127.0.0.1");
755   ASSERT_TRUE(test_server()->Start());
756
757   content::WebContents* contents =
758       browser()->tab_strip_model()->GetActiveWebContents();
759   NavigationController* controller = &contents->GetController();
760   LoginPromptBrowserTestObserver observer;
761   observer.Register(content::Source<NavigationController>(controller));
762
763   // Load a page that has a cross-domain iframe authentication.
764   {
765     GURL test_page = test_server()->GetURL(kTestPage);
766     ASSERT_EQ("127.0.0.1", test_page.host());
767
768     // Change the host from 127.0.0.1 to www.a.com so that when the
769     // page tries to load from b, it will be cross-origin.
770     std::string new_host("www.a.com");
771     GURL::Replacements replacements;
772     replacements.SetHostStr(new_host);
773     test_page = test_page.ReplaceComponents(replacements);
774
775     WindowedAuthNeededObserver auth_needed_waiter(controller);
776     browser()->OpenURL(OpenURLParams(
777         test_page, Referrer(), CURRENT_TAB, ui::PAGE_TRANSITION_TYPED,
778         false));
779     auth_needed_waiter.Wait();
780     ASSERT_EQ(1u, observer.handlers().size());
781
782     while (!observer.handlers().empty()) {
783       WindowedAuthCancelledObserver auth_cancelled_waiter(controller);
784       LoginHandler* handler = *observer.handlers().begin();
785
786       ASSERT_TRUE(handler);
787       // When a cross origin iframe displays a login prompt, the blank
788       // interstitial shouldn't be displayed and the omnibox should show the
789       // main frame's url, not the iframe's.
790       EXPECT_EQ(new_host, contents->GetVisibleURL().host());
791
792       handler->CancelAuth();
793       auth_cancelled_waiter.Wait();
794     }
795   }
796
797   // Should stay on the main frame's url once the prompt the iframe is closed.
798   EXPECT_EQ("www.a.com", contents->GetVisibleURL().host());
799
800   EXPECT_EQ(1, observer.auth_needed_count());
801   EXPECT_TRUE(test_server()->Stop());
802 }
803
804 IN_PROC_BROWSER_TEST_F(LoginPromptBrowserTest, SupplyRedundantAuths) {
805   ASSERT_TRUE(test_server()->Start());
806
807   // Get NavigationController for tab 1.
808   content::WebContents* contents_1 =
809       browser()->tab_strip_model()->GetActiveWebContents();
810   NavigationController* controller_1 = &contents_1->GetController();
811
812   // Open a new tab.
813   ui_test_utils::NavigateToURLWithDisposition(
814       browser(),
815       GURL("about:blank"),
816       NEW_FOREGROUND_TAB,
817       ui_test_utils::BROWSER_TEST_WAIT_FOR_TAB);
818
819   // Get NavigationController for tab 2.
820   content::WebContents* contents_2 =
821       browser()->tab_strip_model()->GetActiveWebContents();
822   ASSERT_NE(contents_1, contents_2);
823   NavigationController* controller_2 = &contents_2->GetController();
824
825   LoginPromptBrowserTestObserver observer;
826   observer.Register(content::Source<NavigationController>(controller_1));
827   observer.Register(content::Source<NavigationController>(controller_2));
828
829   {
830     // Open different auth urls in each tab.
831     WindowedAuthNeededObserver auth_needed_waiter_1(controller_1);
832     WindowedAuthNeededObserver auth_needed_waiter_2(controller_2);
833     contents_1->OpenURL(OpenURLParams(
834         test_server()->GetURL("auth-basic/1"),
835         content::Referrer(),
836         CURRENT_TAB,
837         ui::PAGE_TRANSITION_TYPED,
838         false));
839     contents_2->OpenURL(OpenURLParams(
840         test_server()->GetURL("auth-basic/2"),
841         content::Referrer(),
842         CURRENT_TAB,
843         ui::PAGE_TRANSITION_TYPED,
844         false));
845     auth_needed_waiter_1.Wait();
846     auth_needed_waiter_2.Wait();
847
848     ASSERT_EQ(2U, observer.handlers().size());
849
850     // Supply auth in one of the tabs.
851     WindowedAuthSuppliedObserver auth_supplied_waiter_1(controller_1);
852     WindowedAuthSuppliedObserver auth_supplied_waiter_2(controller_2);
853     LoginHandler* handler_1 = *observer.handlers().begin();
854     ASSERT_TRUE(handler_1);
855     SetAuthFor(handler_1);
856
857     // Both tabs should be authenticated.
858     auth_supplied_waiter_1.Wait();
859     auth_supplied_waiter_2.Wait();
860   }
861
862   EXPECT_EQ(2, observer.auth_needed_count());
863   EXPECT_EQ(2, observer.auth_supplied_count());
864   EXPECT_EQ(0, observer.auth_cancelled_count());
865   EXPECT_TRUE(test_server()->Stop());
866 }
867
868 IN_PROC_BROWSER_TEST_F(LoginPromptBrowserTest, CancelRedundantAuths) {
869   ASSERT_TRUE(test_server()->Start());
870
871   // Get NavigationController for tab 1.
872   content::WebContents* contents_1 =
873       browser()->tab_strip_model()->GetActiveWebContents();
874   NavigationController* controller_1 = &contents_1->GetController();
875
876   // Open a new tab.
877   ui_test_utils::NavigateToURLWithDisposition(
878       browser(),
879       GURL("about:blank"),
880       NEW_FOREGROUND_TAB,
881       ui_test_utils::BROWSER_TEST_WAIT_FOR_TAB);
882
883   // Get NavigationController for tab 2.
884   content::WebContents* contents_2 =
885       browser()->tab_strip_model()->GetActiveWebContents();
886   ASSERT_NE(contents_1, contents_2);
887   NavigationController* controller_2 = &contents_2->GetController();
888
889   LoginPromptBrowserTestObserver observer;
890   observer.Register(content::Source<NavigationController>(controller_1));
891   observer.Register(content::Source<NavigationController>(controller_2));
892
893   {
894     // Open different auth urls in each tab.
895     WindowedAuthNeededObserver auth_needed_waiter_1(controller_1);
896     WindowedAuthNeededObserver auth_needed_waiter_2(controller_2);
897     contents_1->OpenURL(OpenURLParams(
898         test_server()->GetURL("auth-basic/1"),
899         content::Referrer(),
900         CURRENT_TAB,
901         ui::PAGE_TRANSITION_TYPED,
902         false));
903     contents_2->OpenURL(OpenURLParams(
904         test_server()->GetURL("auth-basic/2"),
905         content::Referrer(),
906         CURRENT_TAB,
907         ui::PAGE_TRANSITION_TYPED,
908         false));
909     auth_needed_waiter_1.Wait();
910     auth_needed_waiter_2.Wait();
911
912     ASSERT_EQ(2U, observer.handlers().size());
913
914     // Cancel auth in one of the tabs.
915     WindowedAuthCancelledObserver auth_cancelled_waiter_1(controller_1);
916     WindowedAuthCancelledObserver auth_cancelled_waiter_2(controller_2);
917     LoginHandler* handler_1 = *observer.handlers().begin();
918     ASSERT_TRUE(handler_1);
919     handler_1->CancelAuth();
920
921     // Both tabs should cancel auth.
922     auth_cancelled_waiter_1.Wait();
923     auth_cancelled_waiter_2.Wait();
924   }
925
926   EXPECT_EQ(2, observer.auth_needed_count());
927   EXPECT_EQ(0, observer.auth_supplied_count());
928   EXPECT_EQ(2, observer.auth_cancelled_count());
929   EXPECT_TRUE(test_server()->Stop());
930 }
931
932 IN_PROC_BROWSER_TEST_F(LoginPromptBrowserTest,
933                        SupplyRedundantAuthsMultiProfile) {
934   ASSERT_TRUE(test_server()->Start());
935
936   // Get NavigationController for regular tab.
937   content::WebContents* contents =
938       browser()->tab_strip_model()->GetActiveWebContents();
939   NavigationController* controller = &contents->GetController();
940
941   // Open an incognito window.
942   Browser* browser_incognito = CreateIncognitoBrowser();
943
944   // Get NavigationController for incognito tab.
945   content::WebContents* contents_incognito =
946       browser_incognito->tab_strip_model()->GetActiveWebContents();
947   ASSERT_NE(contents, contents_incognito);
948   NavigationController* controller_incognito =
949       &contents_incognito->GetController();
950
951   LoginPromptBrowserTestObserver observer;
952   observer.Register(content::Source<NavigationController>(controller));
953   LoginPromptBrowserTestObserver observer_incognito;
954   observer_incognito.Register(
955       content::Source<NavigationController>(controller_incognito));
956
957   {
958     // Open an auth url in each window.
959     WindowedAuthNeededObserver auth_needed_waiter(controller);
960     WindowedAuthNeededObserver auth_needed_waiter_incognito(
961         controller_incognito);
962     contents->OpenURL(OpenURLParams(
963         test_server()->GetURL("auth-basic/1"),
964         content::Referrer(),
965         CURRENT_TAB,
966         ui::PAGE_TRANSITION_TYPED,
967         false));
968     contents_incognito->OpenURL(OpenURLParams(
969         test_server()->GetURL("auth-basic/2"),
970         content::Referrer(),
971         CURRENT_TAB,
972         ui::PAGE_TRANSITION_TYPED,
973         false));
974     auth_needed_waiter.Wait();
975     auth_needed_waiter_incognito.Wait();
976
977     ASSERT_EQ(1U, observer.handlers().size());
978     ASSERT_EQ(1U, observer_incognito.handlers().size());
979
980     // Supply auth in regular tab.
981     WindowedAuthSuppliedObserver auth_supplied_waiter(controller);
982     LoginHandler* handler = *observer.handlers().begin();
983     ASSERT_TRUE(handler);
984     SetAuthFor(handler);
985
986     // Regular tab should be authenticated.
987     auth_supplied_waiter.Wait();
988
989     // There's not really a way to wait for the incognito window to "do
990     // nothing".  Run anything pending in the message loop just to be sure.
991     // (This shouldn't be necessary since notifications are synchronous, but
992     // maybe it will help avoid flake someday in the future..)
993     content::RunAllPendingInMessageLoop();
994   }
995
996   EXPECT_EQ(1, observer.auth_needed_count());
997   EXPECT_EQ(1, observer.auth_supplied_count());
998   EXPECT_EQ(0, observer.auth_cancelled_count());
999   EXPECT_EQ(1, observer_incognito.auth_needed_count());
1000   EXPECT_EQ(0, observer_incognito.auth_supplied_count());
1001   EXPECT_EQ(0, observer_incognito.auth_cancelled_count());
1002   EXPECT_TRUE(test_server()->Stop());
1003 }
1004
1005 // If an XMLHttpRequest is made with incorrect credentials, there should be no
1006 // login prompt; instead the 401 status should be returned to the script.
1007 IN_PROC_BROWSER_TEST_F(LoginPromptBrowserTest,
1008                        NoLoginPromptForXHRWithBadCredentials) {
1009   const char* kXHRTestPage = "files/login/xhr_with_credentials.html#incorrect";
1010
1011   ASSERT_TRUE(test_server()->Start());
1012
1013   content::WebContents* contents =
1014       browser()->tab_strip_model()->GetActiveWebContents();
1015   NavigationController* controller = &contents->GetController();
1016   LoginPromptBrowserTestObserver observer;
1017
1018   observer.Register(content::Source<NavigationController>(controller));
1019
1020   // Load a page which makes a synchronous XMLHttpRequest for an authenticated
1021   // resource with the wrong credentials.  There should be no login prompt.
1022   {
1023     GURL test_page = test_server()->GetURL(kXHRTestPage);
1024     WindowedLoadStopObserver load_stop_waiter(controller, 1);
1025     browser()->OpenURL(OpenURLParams(
1026         test_page, Referrer(), CURRENT_TAB, ui::PAGE_TRANSITION_TYPED,
1027         false));
1028     load_stop_waiter.Wait();
1029   }
1030
1031   base::string16 expected_title(base::UTF8ToUTF16("status=401"));
1032
1033   EXPECT_EQ(expected_title, contents->GetTitle());
1034   EXPECT_EQ(0, observer.auth_supplied_count());
1035   EXPECT_EQ(0, observer.auth_needed_count());
1036   EXPECT_EQ(0, observer.auth_cancelled_count());
1037   EXPECT_TRUE(test_server()->Stop());
1038 }
1039
1040 // If an XMLHttpRequest is made with correct credentials, there should be no
1041 // login prompt either.
1042 IN_PROC_BROWSER_TEST_F(LoginPromptBrowserTest,
1043                        NoLoginPromptForXHRWithGoodCredentials) {
1044   const char* kXHRTestPage = "files/login/xhr_with_credentials.html#secret";
1045
1046   ASSERT_TRUE(test_server()->Start());
1047
1048   content::WebContents* contents =
1049       browser()->tab_strip_model()->GetActiveWebContents();
1050   NavigationController* controller = &contents->GetController();
1051   LoginPromptBrowserTestObserver observer;
1052
1053   observer.Register(content::Source<NavigationController>(controller));
1054
1055   // Load a page which makes a synchronous XMLHttpRequest for an authenticated
1056   // resource with the wrong credentials.  There should be no login prompt.
1057   {
1058     GURL test_page = test_server()->GetURL(kXHRTestPage);
1059     WindowedLoadStopObserver load_stop_waiter(controller, 1);
1060     browser()->OpenURL(OpenURLParams(
1061         test_page, Referrer(), CURRENT_TAB, ui::PAGE_TRANSITION_TYPED,
1062         false));
1063     load_stop_waiter.Wait();
1064   }
1065
1066   base::string16 expected_title(base::UTF8ToUTF16("status=200"));
1067
1068   EXPECT_EQ(expected_title, contents->GetTitle());
1069   EXPECT_EQ(0, observer.auth_supplied_count());
1070   EXPECT_EQ(0, observer.auth_needed_count());
1071   EXPECT_EQ(0, observer.auth_cancelled_count());
1072   EXPECT_TRUE(test_server()->Stop());
1073 }
1074
1075 // If an XMLHttpRequest is made without credentials, there should be a login
1076 // prompt.
1077 IN_PROC_BROWSER_TEST_F(LoginPromptBrowserTest,
1078                        LoginPromptForXHRWithoutCredentials) {
1079   const char* kXHRTestPage = "files/login/xhr_without_credentials.html";
1080
1081   ASSERT_TRUE(test_server()->Start());
1082
1083   content::WebContents* contents =
1084       browser()->tab_strip_model()->GetActiveWebContents();
1085   NavigationController* controller = &contents->GetController();
1086   LoginPromptBrowserTestObserver observer;
1087
1088   observer.Register(content::Source<NavigationController>(controller));
1089
1090   // Load a page which makes a synchronous XMLHttpRequest for an authenticated
1091   // resource with the wrong credentials.  There should be no login prompt.
1092   {
1093     GURL test_page = test_server()->GetURL(kXHRTestPage);
1094     WindowedAuthNeededObserver auth_needed_waiter(controller);
1095     browser()->OpenURL(OpenURLParams(
1096         test_page, Referrer(), CURRENT_TAB, ui::PAGE_TRANSITION_TYPED,
1097         false));
1098     auth_needed_waiter.Wait();
1099   }
1100
1101   ASSERT_FALSE(observer.handlers().empty());
1102   {
1103     WindowedAuthNeededObserver auth_needed_waiter(controller);
1104     WindowedAuthSuppliedObserver auth_supplied_waiter(controller);
1105     LoginHandler* handler = *observer.handlers().begin();
1106
1107     ASSERT_TRUE(handler);
1108     handler->SetAuth(base::UTF8ToUTF16(bad_username_),
1109                      base::UTF8ToUTF16(bad_password_));
1110     auth_supplied_waiter.Wait();
1111
1112     // The request should be retried after the incorrect password is
1113     // supplied.  This should result in a new AUTH_NEEDED notification
1114     // for the same realm.
1115     auth_needed_waiter.Wait();
1116   }
1117
1118   ASSERT_EQ(1u, observer.handlers().size());
1119   WindowedAuthSuppliedObserver auth_supplied_waiter(controller);
1120   LoginHandler* handler = *observer.handlers().begin();
1121
1122   base::string16 username(base::UTF8ToUTF16(username_digest_));
1123   base::string16 password(base::UTF8ToUTF16(password_));
1124   handler->SetAuth(username, password);
1125   auth_supplied_waiter.Wait();
1126
1127   WindowedLoadStopObserver load_stop_waiter(controller, 1);
1128   load_stop_waiter.Wait();
1129
1130   base::string16 expected_title(base::UTF8ToUTF16("status=200"));
1131
1132   EXPECT_EQ(expected_title, contents->GetTitle());
1133   EXPECT_EQ(2, observer.auth_supplied_count());
1134   EXPECT_EQ(2, observer.auth_needed_count());
1135   EXPECT_EQ(0, observer.auth_cancelled_count());
1136   EXPECT_TRUE(test_server()->Stop());
1137 }
1138
1139 // If an XMLHttpRequest is made without credentials, there should be a login
1140 // prompt.  If it's cancelled, the script should get a 401 status.
1141 IN_PROC_BROWSER_TEST_F(LoginPromptBrowserTest,
1142                        LoginPromptForXHRWithoutCredentialsCancelled) {
1143   const char* kXHRTestPage = "files/login/xhr_without_credentials.html";
1144
1145   ASSERT_TRUE(test_server()->Start());
1146
1147   content::WebContents* contents =
1148       browser()->tab_strip_model()->GetActiveWebContents();
1149   NavigationController* controller = &contents->GetController();
1150   LoginPromptBrowserTestObserver observer;
1151
1152   observer.Register(content::Source<NavigationController>(controller));
1153
1154   // Load a page which makes a synchronous XMLHttpRequest for an authenticated
1155   // resource with the wrong credentials.  There should be no login prompt.
1156   {
1157     GURL test_page = test_server()->GetURL(kXHRTestPage);
1158     WindowedAuthNeededObserver auth_needed_waiter(controller);
1159     browser()->OpenURL(OpenURLParams(
1160         test_page, Referrer(), CURRENT_TAB, ui::PAGE_TRANSITION_TYPED,
1161         false));
1162     auth_needed_waiter.Wait();
1163   }
1164
1165   ASSERT_EQ(1u, observer.handlers().size());
1166   WindowedAuthCancelledObserver auth_cancelled_waiter(controller);
1167   LoginHandler* handler = *observer.handlers().begin();
1168
1169   handler->CancelAuth();
1170   auth_cancelled_waiter.Wait();
1171
1172   WindowedLoadStopObserver load_stop_waiter(controller, 1);
1173   load_stop_waiter.Wait();
1174
1175   base::string16 expected_title(base::UTF8ToUTF16("status=401"));
1176
1177   EXPECT_EQ(expected_title, contents->GetTitle());
1178   EXPECT_EQ(0, observer.auth_supplied_count());
1179   EXPECT_EQ(1, observer.auth_needed_count());
1180   EXPECT_EQ(1, observer.auth_cancelled_count());
1181   EXPECT_TRUE(test_server()->Stop());
1182 }
1183
1184 // If a cross origin navigation triggers a login prompt, the destination URL
1185 // should be shown in the omnibox.
1186 void LoginPromptBrowserTest::TestCrossOriginPrompt(
1187     const GURL& visit_url,
1188     const std::string& auth_host) const {
1189   content::WebContents* contents =
1190       browser()->tab_strip_model()->GetActiveWebContents();
1191   NavigationController* controller = &contents->GetController();
1192   LoginPromptBrowserTestObserver observer;
1193
1194   observer.Register(content::Source<NavigationController>(controller));
1195
1196   // Load a page which will trigger a login prompt.
1197   {
1198     WindowedAuthNeededObserver auth_needed_waiter(controller);
1199     browser()->OpenURL(OpenURLParams(
1200         visit_url, Referrer(), CURRENT_TAB, ui::PAGE_TRANSITION_TYPED,
1201         false));
1202     ASSERT_EQ(visit_url.host(), contents->GetVisibleURL().host());
1203     auth_needed_waiter.Wait();
1204     ASSERT_EQ(1u, observer.handlers().size());
1205     WaitForInterstitialAttach(contents);
1206
1207     // The omnibox should show the correct origin for the new page when the
1208     // login prompt is shown.
1209     EXPECT_EQ(auth_host, contents->GetVisibleURL().host());
1210     EXPECT_TRUE(contents->ShowingInterstitialPage());
1211
1212     // Cancel and wait for the interstitial to detach.
1213     LoginHandler* handler = *observer.handlers().begin();
1214     scoped_refptr<content::MessageLoopRunner> loop_runner(
1215         new content::MessageLoopRunner);
1216     InterstitialObserver interstitial_observer(contents,
1217                                                base::Closure(),
1218                                                loop_runner->QuitClosure());
1219     handler->CancelAuth();
1220     if (content::InterstitialPage::GetInterstitialPage(contents))
1221       loop_runner->Run();
1222     EXPECT_EQ(auth_host, contents->GetVisibleURL().host());
1223     EXPECT_FALSE(contents->ShowingInterstitialPage());
1224   }
1225 }
1226
1227 // If a cross origin direct navigation triggers a login prompt, the login
1228 // interstitial should be shown.
1229 IN_PROC_BROWSER_TEST_F(LoginPromptBrowserTest,
1230                        ShowCorrectUrlForCrossOriginMainFrameRequests) {
1231   ASSERT_TRUE(test_server()->Start());
1232
1233   GURL test_page = test_server()->GetURL(kAuthBasicPage);
1234   ASSERT_EQ("127.0.0.1", test_page.host());
1235   std::string auth_host("127.0.0.1");
1236   TestCrossOriginPrompt(test_page, auth_host);
1237 }
1238
1239 // If a cross origin redirect triggers a login prompt, the destination URL
1240 // should be shown in the omnibox when the auth dialog is displayed.
1241 IN_PROC_BROWSER_TEST_F(LoginPromptBrowserTest,
1242                        ShowCorrectUrlForCrossOriginMainFrameRedirects) {
1243   host_resolver()->AddRule("www.a.com", "127.0.0.1");
1244   ASSERT_TRUE(test_server()->Start());
1245
1246   const char* kTestPage = "files/login/cross_origin.html";
1247   GURL test_page = test_server()->GetURL(kTestPage);
1248   ASSERT_EQ("127.0.0.1", test_page.host());
1249   std::string auth_host("www.a.com");
1250   TestCrossOriginPrompt(test_page, auth_host);
1251 }
1252
1253 IN_PROC_BROWSER_TEST_F(LoginPromptBrowserTest,
1254                        LoginInterstitialShouldReplaceExistingInterstitial) {
1255   net::SpawnedTestServer https_server(
1256       net::SpawnedTestServer::TYPE_HTTPS,
1257       net::SpawnedTestServer::SSLOptions(
1258           net::SpawnedTestServer::SSLOptions::CERT_EXPIRED),
1259       base::FilePath());
1260   ASSERT_TRUE(https_server.Start());
1261
1262   content::WebContents* contents =
1263       browser()->tab_strip_model()->GetActiveWebContents();
1264   NavigationController* controller = &contents->GetController();
1265   LoginPromptBrowserTestObserver observer;
1266
1267   observer.Register(content::Source<NavigationController>(controller));
1268
1269   // Load a page which triggers an SSL interstitial. Proceeding through it
1270   // should show the login page with the blank interstitial.
1271   {
1272     GURL test_page = https_server.GetURL(kAuthBasicPage);
1273     ASSERT_EQ("127.0.0.1", test_page.host());
1274
1275     WindowedAuthNeededObserver auth_needed_waiter(controller);
1276     browser()->OpenURL(OpenURLParams(
1277         test_page, Referrer(), CURRENT_TAB, ui::PAGE_TRANSITION_TYPED,
1278         false));
1279     ASSERT_EQ("127.0.0.1", contents->GetURL().host());
1280     WaitForInterstitialAttach(contents);
1281
1282     // An overrideable SSL interstitial is now being displayed. Proceed through
1283     // the interstitial to see the login prompt.
1284     contents->GetInterstitialPage()->Proceed();
1285     auth_needed_waiter.Wait();
1286     ASSERT_EQ(1u, observer.handlers().size());
1287     WaitForInterstitialAttach(contents);
1288
1289     // The omnibox should show the correct origin while the login prompt is
1290     // being displayed.
1291     EXPECT_EQ("127.0.0.1", contents->GetVisibleURL().host());
1292     EXPECT_TRUE(contents->ShowingInterstitialPage());
1293
1294     // Cancelling the login prompt should detach the interstitial while keeping
1295     // the correct origin.
1296     LoginHandler* handler = *observer.handlers().begin();
1297     scoped_refptr<content::MessageLoopRunner> loop_runner(
1298         new content::MessageLoopRunner);
1299     InterstitialObserver interstitial_observer(contents,
1300                                                base::Closure(),
1301                                                loop_runner->QuitClosure());
1302     handler->CancelAuth();
1303     if (content::InterstitialPage::GetInterstitialPage(contents))
1304       loop_runner->Run();
1305     EXPECT_EQ("127.0.0.1", contents->GetVisibleURL().host());
1306     EXPECT_FALSE(contents->ShowingInterstitialPage());
1307   }
1308 }
1309
1310 }  // namespace