| OLD | NEW |
| 1 // Copyright (c) 2012 The Chromium Authors. All rights reserved. | 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 | 2 // Use of this source code is governed by a BSD-style license that can be |
| 3 // found in the LICENSE file. | 3 // found in the LICENSE file. |
| 4 | 4 |
| 5 #include <algorithm> | 5 #include <algorithm> |
| 6 #include <list> | 6 #include <list> |
| 7 #include <map> | 7 #include <map> |
| 8 | 8 |
| 9 #include "base/metrics/field_trial.h" | 9 #include "base/metrics/field_trial.h" |
| 10 #include "base/strings/stringprintf.h" |
| 10 #include "base/strings/utf_string_conversions.h" | 11 #include "base/strings/utf_string_conversions.h" |
| 11 #include "chrome/browser/chrome_notification_types.h" | 12 #include "chrome/browser/chrome_notification_types.h" |
| 12 #include "chrome/browser/prerender/prerender_manager.h" | 13 #include "chrome/browser/prerender/prerender_manager.h" |
| 13 #include "chrome/browser/ssl/ssl_blocking_page.h" | 14 #include "chrome/browser/ssl/ssl_blocking_page.h" |
| 14 #include "chrome/browser/ui/browser.h" | 15 #include "chrome/browser/ui/browser.h" |
| 15 #include "chrome/browser/ui/browser_commands.h" | 16 #include "chrome/browser/ui/browser_commands.h" |
| 16 #include "chrome/browser/ui/login/login_interstitial_delegate.h" | 17 #include "chrome/browser/ui/login/login_interstitial_delegate.h" |
| 17 #include "chrome/browser/ui/login/login_prompt.h" | 18 #include "chrome/browser/ui/login/login_prompt.h" |
| 18 #include "chrome/browser/ui/login/login_prompt_test_utils.h" | 19 #include "chrome/browser/ui/login/login_prompt_test_utils.h" |
| 19 #include "chrome/browser/ui/tabs/tab_strip_model.h" | 20 #include "chrome/browser/ui/tabs/tab_strip_model.h" |
| 20 #include "chrome/test/base/in_process_browser_test.h" | 21 #include "chrome/test/base/in_process_browser_test.h" |
| 21 #include "chrome/test/base/ui_test_utils.h" | 22 #include "chrome/test/base/ui_test_utils.h" |
| 22 #include "content/public/browser/interstitial_page.h" | 23 #include "content/public/browser/interstitial_page.h" |
| 24 #include "content/public/browser/navigation_entry.h" |
| 23 #include "content/public/browser/notification_details.h" | 25 #include "content/public/browser/notification_details.h" |
| 24 #include "content/public/browser/notification_source.h" | 26 #include "content/public/browser/notification_source.h" |
| 25 #include "content/public/browser/web_contents.h" | 27 #include "content/public/browser/web_contents.h" |
| 28 #include "content/public/common/ssl_status.h" |
| 26 #include "content/public/test/browser_test_utils.h" | 29 #include "content/public/test/browser_test_utils.h" |
| 27 #include "content/public/test/test_navigation_observer.h" | 30 #include "content/public/test/test_navigation_observer.h" |
| 28 #include "net/base/auth.h" | 31 #include "net/base/auth.h" |
| 32 #include "net/base/filename_util.h" |
| 29 #include "net/dns/mock_host_resolver.h" | 33 #include "net/dns/mock_host_resolver.h" |
| 30 #include "net/test/spawned_test_server/spawned_test_server.h" | 34 #include "net/test/spawned_test_server/spawned_test_server.h" |
| 31 | 35 |
| 32 using content::NavigationController; | 36 using content::NavigationController; |
| 33 using content::OpenURLParams; | 37 using content::OpenURLParams; |
| 34 using content::Referrer; | 38 using content::Referrer; |
| 35 | 39 |
| 36 namespace { | 40 namespace { |
| 37 | 41 |
| 42 enum ExpectedSSLStatus { SSL_STATUS_NONE, SSL_STATUS_OK, SSL_STATUS_BROKEN }; |
| 43 |
| 38 class LoginPromptBrowserTest : public InProcessBrowserTest { | 44 class LoginPromptBrowserTest : public InProcessBrowserTest { |
| 39 public: | 45 public: |
| 40 LoginPromptBrowserTest() | 46 LoginPromptBrowserTest() |
| 41 : bad_password_("incorrect"), | 47 : bad_password_("incorrect"), |
| 42 bad_username_("nouser"), | 48 bad_username_("nouser"), |
| 43 password_("secret"), | 49 password_("secret"), |
| 44 username_basic_("basicuser"), | 50 username_basic_("basicuser"), |
| 45 username_digest_("digestuser") { | 51 username_digest_("digestuser") { |
| 46 auth_map_["foo"] = AuthInfo("testuser", "foopassword"); | 52 auth_map_["foo"] = AuthInfo("testuser", "foopassword"); |
| 47 auth_map_["bar"] = AuthInfo("testuser", "barpassword"); | 53 auth_map_["bar"] = AuthInfo("testuser", "barpassword"); |
| 48 auth_map_["testrealm"] = AuthInfo(username_basic_, password_); | 54 auth_map_["testrealm"] = AuthInfo(username_basic_, password_); |
| 49 } | 55 } |
| 50 | 56 |
| 51 protected: | 57 protected: |
| 52 struct AuthInfo { | 58 struct AuthInfo { |
| 53 std::string username_; | 59 std::string username_; |
| 54 std::string password_; | 60 std::string password_; |
| 55 | 61 |
| 56 AuthInfo() {} | 62 AuthInfo() {} |
| 57 | 63 |
| 58 AuthInfo(const std::string& username, | 64 AuthInfo(const std::string& username, |
| 59 const std::string& password) | 65 const std::string& password) |
| 60 : username_(username), password_(password) {} | 66 : username_(username), password_(password) {} |
| 61 }; | 67 }; |
| 62 | 68 |
| 63 typedef std::map<std::string, AuthInfo> AuthMap; | 69 typedef std::map<std::string, AuthInfo> AuthMap; |
| 64 | 70 |
| 65 void SetAuthFor(LoginHandler* handler); | 71 void SetAuthFor(LoginHandler* handler) const; |
| 66 | 72 |
| 67 void TestCrossOriginPrompt(const GURL& visit_url, | 73 void TestCrossOriginPrompt(const GURL& visit_url, |
| 68 const std::string& landing_host) const; | 74 const std::string& landing_host) const; |
| 69 | 75 |
| 76 void TestSSLState(Browser* browser, |
| 77 const GURL& test_page, |
| 78 bool has_redirect, |
| 79 int expected_ssl_status) const; |
| 80 |
| 70 AuthMap auth_map_; | 81 AuthMap auth_map_; |
| 71 std::string bad_password_; | 82 std::string bad_password_; |
| 72 std::string bad_username_; | 83 std::string bad_username_; |
| 73 std::string password_; | 84 std::string password_; |
| 74 std::string username_basic_; | 85 std::string username_basic_; |
| 75 std::string username_digest_; | 86 std::string username_digest_; |
| 76 }; | 87 }; |
| 77 | 88 |
| 78 void LoginPromptBrowserTest::SetAuthFor(LoginHandler* handler) { | 89 void LoginPromptBrowserTest::SetAuthFor(LoginHandler* handler) const { |
| 79 const net::AuthChallengeInfo* challenge = handler->auth_info(); | 90 const net::AuthChallengeInfo* challenge = handler->auth_info(); |
| 80 | 91 |
| 81 ASSERT_TRUE(challenge); | 92 ASSERT_TRUE(challenge); |
| 82 AuthMap::iterator i = auth_map_.find(challenge->realm); | 93 AuthMap::const_iterator i = auth_map_.find(challenge->realm); |
| 83 EXPECT_TRUE(auth_map_.end() != i); | 94 EXPECT_TRUE(auth_map_.end() != i); |
| 84 if (i != auth_map_.end()) { | 95 if (i != auth_map_.end()) { |
| 85 const AuthInfo& info = i->second; | 96 const AuthInfo& info = i->second; |
| 86 handler->SetAuth(base::UTF8ToUTF16(info.username_), | 97 handler->SetAuth(base::UTF8ToUTF16(info.username_), |
| 87 base::UTF8ToUTF16(info.password_)); | 98 base::UTF8ToUTF16(info.password_)); |
| 88 } | 99 } |
| 89 } | 100 } |
| 90 | 101 |
| 102 void CheckSSLState(content::WebContents* contents, int expected_ssl_status) { |
| 103 NavigationController* controller = &contents->GetController(); |
| 104 content::NavigationEntry* entry = controller->GetVisibleEntry(); |
| 105 const content::SSLStatus& ssl_status = entry->GetSSL(); |
| 106 EXPECT_EQ(content::SSLStatus::NORMAL_CONTENT, ssl_status.content_status); |
| 107 EXPECT_EQ(128, ssl_status.security_bits); |
| 108 switch (expected_ssl_status) { |
| 109 case SSL_STATUS_OK: |
| 110 EXPECT_EQ(content::SECURITY_STYLE_AUTHENTICATED, |
| 111 ssl_status.security_style); |
| 112 break; |
| 113 case SSL_STATUS_BROKEN: |
| 114 EXPECT_EQ(content::SECURITY_STYLE_AUTHENTICATION_BROKEN, |
| 115 ssl_status.security_style); |
| 116 break; |
| 117 default: |
| 118 NOTREACHED(); |
| 119 } |
| 120 } |
| 121 |
| 122 void CancelAndWaitForInterstitialDetach(LoginHandler* handler, |
| 123 content::WebContents* contents) { |
| 124 RunTaskAndWaitForInterstitialDetach( |
| 125 contents, base::Bind(&LoginHandler::CancelAuth, handler)); |
| 126 } |
| 127 |
| 91 const char kPrefetchAuthPage[] = "files/login/prefetch.html"; | 128 const char kPrefetchAuthPage[] = "files/login/prefetch.html"; |
| 92 | 129 |
| 93 const char kMultiRealmTestPage[] = "files/login/multi_realm.html"; | 130 const char kMultiRealmTestPage[] = "files/login/multi_realm.html"; |
| 94 const int kMultiRealmTestRealmCount = 2; | 131 const int kMultiRealmTestRealmCount = 2; |
| 95 | 132 |
| 96 const char kSingleRealmTestPage[] = "files/login/single_realm.html"; | 133 const char kSingleRealmTestPage[] = "files/login/single_realm.html"; |
| 97 | 134 |
| 98 const char* kAuthBasicPage = "auth-basic"; | 135 const char* kAuthBasicPage = "auth-basic"; |
| 99 const char* kAuthDigestPage = "auth-digest"; | 136 const char* kAuthDigestPage = "auth-digest"; |
| 100 | 137 |
| (...skipping 1267 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 1368 auth_needed_waiter.Wait(); | 1405 auth_needed_waiter.Wait(); |
| 1369 ASSERT_EQ(1u, observer.handlers().size()); | 1406 ASSERT_EQ(1u, observer.handlers().size()); |
| 1370 content::WaitForInterstitialAttach(contents); | 1407 content::WaitForInterstitialAttach(contents); |
| 1371 EXPECT_EQ(LoginInterstitialDelegate::kTypeForTesting, | 1408 EXPECT_EQ(LoginInterstitialDelegate::kTypeForTesting, |
| 1372 contents->GetInterstitialPage() | 1409 contents->GetInterstitialPage() |
| 1373 ->GetDelegateForTesting() | 1410 ->GetDelegateForTesting() |
| 1374 ->GetTypeForTesting()); | 1411 ->GetTypeForTesting()); |
| 1375 } | 1412 } |
| 1376 } | 1413 } |
| 1377 | 1414 |
| 1415 // Navigates the active tab to |test_page| which should end up at a URL with |
| 1416 // HTTP auth, and checks if the SSL information at this final URL is set |
| 1417 // correctly. |
| 1418 // If |has_redirect| is true, |test_page| redirects to the HTTP auth URL. |
| 1419 // If |has_redirect| is false, |test_page| is the final HTTP auth URL. |
| 1420 void LoginPromptBrowserTest::TestSSLState(Browser* browser, |
| 1421 const GURL& test_page, |
| 1422 bool has_redirect, |
| 1423 int expected_ssl_status) const { |
| 1424 content::WebContents* contents = |
| 1425 browser->tab_strip_model()->GetActiveWebContents(); |
| 1426 NavigationController* controller = &contents->GetController(); |
| 1427 LoginPromptBrowserTestObserver observer; |
| 1428 |
| 1429 observer.Register(content::Source<NavigationController>(controller)); |
| 1430 { |
| 1431 WindowedAuthNeededObserver auth_needed_waiter(controller); |
| 1432 ui_test_utils::NavigateToURLBlockUntilNavigationsComplete( |
| 1433 browser, test_page, has_redirect ? 2 : 1); |
| 1434 // After redirects etc., the page should end up at the HTTPS url. |
| 1435 ASSERT_EQ("127.0.0.1", contents->GetURL().host()); |
| 1436 if (expected_ssl_status == SSL_STATUS_BROKEN) { |
| 1437 // Wait for the broken SSL interstitial and proceed through it. |
| 1438 WaitForInterstitialAttach(contents); |
| 1439 EXPECT_TRUE(contents->ShowingInterstitialPage()); |
| 1440 EXPECT_EQ(SSLBlockingPage::kTypeForTesting, |
| 1441 contents->GetInterstitialPage() |
| 1442 ->GetDelegateForTesting() |
| 1443 ->GetTypeForTesting()); |
| 1444 contents->GetInterstitialPage()->Proceed(); |
| 1445 } |
| 1446 |
| 1447 // The auth prompt should show with the blank login interstitial, and the |
| 1448 // SSL status should be available (but broken). |
| 1449 auth_needed_waiter.Wait(); |
| 1450 ASSERT_EQ(1u, observer.handlers().size()); |
| 1451 WaitForInterstitialAttach(contents); |
| 1452 EXPECT_TRUE(contents->ShowingInterstitialPage()); |
| 1453 EXPECT_EQ(LoginInterstitialDelegate::kTypeForTesting, |
| 1454 contents->GetInterstitialPage() |
| 1455 ->GetDelegateForTesting() |
| 1456 ->GetTypeForTesting()); |
| 1457 // Navigation not committed yet when the auth dialog is displayed. |
| 1458 EXPECT_EQ("", contents->GetLastCommittedURL().host()); |
| 1459 EXPECT_EQ("127.0.0.1", contents->GetVisibleURL().host()); |
| 1460 CheckSSLState(contents, expected_ssl_status); |
| 1461 |
| 1462 // Cancelling the login prompt should detach the interstitial while keeping |
| 1463 // the correct origin and SSL state. |
| 1464 CancelAndWaitForInterstitialDetach(*observer.handlers().begin(), contents); |
| 1465 EXPECT_EQ("127.0.0.1", contents->GetVisibleURL().host()); |
| 1466 EXPECT_EQ("127.0.0.1", contents->GetLastCommittedURL().host()); |
| 1467 EXPECT_FALSE(contents->ShowingInterstitialPage()); |
| 1468 CheckSSLState(contents, expected_ssl_status); |
| 1469 } |
| 1470 } |
| 1471 |
| 1472 // Omnibox and connection tab should reflect the correct SSL State when login |
| 1473 // prompt is displayed in the main frame. |
| 1474 // This is simply the scenario where the user enters an HTTPS url that ends up |
| 1475 // with an HTTP auth dialog. |
| 1476 IN_PROC_BROWSER_TEST_F(LoginPromptBrowserTest, |
| 1477 SSLStateShouldUpdateOnDirectNavigation) { |
| 1478 net::SpawnedTestServer https_server( |
| 1479 net::SpawnedTestServer::TYPE_HTTPS, |
| 1480 net::SpawnedTestServer::SSLOptions( |
| 1481 net::SpawnedTestServer::SSLOptions::CERT_OK), |
| 1482 base::FilePath()); |
| 1483 ASSERT_TRUE(https_server.Start()); |
| 1484 GURL test_page = https_server.GetURL(kAuthBasicPage); |
| 1485 ASSERT_EQ("127.0.0.1", test_page.host()); |
| 1486 TestSSLState(browser(), test_page, false, SSL_STATUS_OK); |
| 1487 } |
| 1488 |
| 1489 // Same as above, except the HTTPS url has a cert error. When the user proceeds |
| 1490 // through the SSL interstitial, HTTP auth dialog should be displayed with the |
| 1491 // correct (i.e. broken) SSL information. |
| 1492 IN_PROC_BROWSER_TEST_F(LoginPromptBrowserTest, |
| 1493 SSLStateShouldUpdateOnDirectNavigation_BrokenSSL) { |
| 1494 net::SpawnedTestServer https_server( |
| 1495 net::SpawnedTestServer::TYPE_HTTPS, |
| 1496 net::SpawnedTestServer::SSLOptions( |
| 1497 net::SpawnedTestServer::SSLOptions::CERT_CHAIN_WRONG_ROOT), |
| 1498 base::FilePath()); |
| 1499 ASSERT_TRUE(https_server.Start()); |
| 1500 GURL test_page = https_server.GetURL(kAuthBasicPage); |
| 1501 ASSERT_EQ("127.0.0.1", test_page.host()); |
| 1502 TestSSLState(browser(), test_page, false, SSL_STATUS_BROKEN); |
| 1503 } |
| 1504 |
| 1505 // Same as |SSLStateShouldUpdateOnDirectNavigation|, except the user doesn't |
| 1506 // navigate directly to the HTTPS page. Instead, another page redirects to the |
| 1507 // HTTPS page. |
| 1508 IN_PROC_BROWSER_TEST_F(LoginPromptBrowserTest, SSLStateShouldUpdateOnRedirect) { |
| 1509 net::SpawnedTestServer https_server( |
| 1510 net::SpawnedTestServer::TYPE_HTTPS, |
| 1511 net::SpawnedTestServer::SSLOptions( |
| 1512 net::SpawnedTestServer::SSLOptions::CERT_OK), |
| 1513 base::FilePath()); |
| 1514 ASSERT_TRUE(https_server.Start()); |
| 1515 GURL https_url = https_server.GetURL(kAuthBasicPage); |
| 1516 ASSERT_EQ("127.0.0.1", https_url.host()); |
| 1517 |
| 1518 // Write an HTML file that redirects to the HTTPS url above. |
| 1519 base::ScopedTempDir temp_directory; |
| 1520 ASSERT_TRUE(temp_directory.CreateUniqueTempDir()); |
| 1521 base::FilePath temp_file; |
| 1522 ASSERT_TRUE( |
| 1523 base::CreateTemporaryFileInDir(temp_directory.path(), &temp_file)); |
| 1524 std::string html = base::StringPrintf( |
| 1525 "<html>" |
| 1526 "<script>window.location = '%s';</script>" |
| 1527 "</html>", |
| 1528 https_url.spec().c_str()); |
| 1529 ASSERT_EQ(static_cast<int>(html.size()), |
| 1530 base::WriteFile(temp_file, html.data(), html.size())); |
| 1531 TestSSLState(browser(), net::FilePathToFileURL(temp_file), true, |
| 1532 SSL_STATUS_OK); |
| 1533 } |
| 1534 |
| 1535 // Same as |SSLStateShouldUpdateOnDirectNavigation_BrokenSSL|, except the user |
| 1536 // doesn't navigate directly to the HTTPS page. Instead, another page redirects |
| 1537 // to the HTTPS page. |
| 1538 IN_PROC_BROWSER_TEST_F(LoginPromptBrowserTest, |
| 1539 SSLStateShouldUpdateOnRedirect_BrokenSSL) { |
| 1540 net::SpawnedTestServer https_server( |
| 1541 net::SpawnedTestServer::TYPE_HTTPS, |
| 1542 net::SpawnedTestServer::SSLOptions( |
| 1543 net::SpawnedTestServer::SSLOptions::CERT_CHAIN_WRONG_ROOT), |
| 1544 base::FilePath()); |
| 1545 ASSERT_TRUE(https_server.Start()); |
| 1546 GURL https_url = https_server.GetURL(kAuthBasicPage); |
| 1547 ASSERT_EQ("127.0.0.1", https_url.host()); |
| 1548 |
| 1549 // Write an HTML file that redirects to the HTTPS url above. |
| 1550 base::ScopedTempDir temp_directory; |
| 1551 ASSERT_TRUE(temp_directory.CreateUniqueTempDir()); |
| 1552 base::FilePath temp_file; |
| 1553 ASSERT_TRUE( |
| 1554 base::CreateTemporaryFileInDir(temp_directory.path(), &temp_file)); |
| 1555 std::string html = base::StringPrintf( |
| 1556 "<html>" |
| 1557 "<script>window.location = '%s';</script>" |
| 1558 "</html>", |
| 1559 https_url.spec().c_str()); |
| 1560 ASSERT_EQ(static_cast<int>(html.size()), |
| 1561 base::WriteFile(temp_file, html.data(), html.size())); |
| 1562 TestSSLState(browser(), net::FilePathToFileURL(temp_file), true, |
| 1563 SSL_STATUS_BROKEN); |
| 1564 } |
| 1565 |
| 1378 } // namespace | 1566 } // namespace |
| OLD | NEW |