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