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