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