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