| 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 void LoginPromptBrowserTest::TestSSLState(Browser* browser, |
| 1416 const GURL& test_page, |
| 1417 bool has_redirect, |
| 1418 int expected_ssl_status) const { |
| 1419 content::WebContents* contents = |
| 1420 browser->tab_strip_model()->GetActiveWebContents(); |
| 1421 NavigationController* controller = &contents->GetController(); |
| 1422 LoginPromptBrowserTestObserver observer; |
| 1423 |
| 1424 observer.Register(content::Source<NavigationController>(controller)); |
| 1425 { |
| 1426 WindowedAuthNeededObserver auth_needed_waiter(controller); |
| 1427 ui_test_utils::NavigateToURLBlockUntilNavigationsComplete( |
| 1428 browser, test_page, has_redirect ? 2 : 1); |
| 1429 // After redirects etc., the page should end up at the HTTPS url. |
| 1430 ASSERT_EQ("127.0.0.1", contents->GetURL().host()); |
| 1431 if (expected_ssl_status == SSL_STATUS_BROKEN) { |
| 1432 // Wait for the broken SSL interstitial and proceed through it. |
| 1433 WaitForInterstitialAttach(contents); |
| 1434 EXPECT_TRUE(contents->ShowingInterstitialPage()); |
| 1435 EXPECT_EQ(SSLBlockingPage::kTypeForTesting, |
| 1436 contents->GetInterstitialPage() |
| 1437 ->GetDelegateForTesting() |
| 1438 ->GetTypeForTesting()); |
| 1439 contents->GetInterstitialPage()->Proceed(); |
| 1440 } |
| 1441 |
| 1442 // The auth prompt should show with the blank login interstitial, and the |
| 1443 // SSL status should be available (but broken). |
| 1444 auth_needed_waiter.Wait(); |
| 1445 ASSERT_EQ(1u, observer.handlers().size()); |
| 1446 WaitForInterstitialAttach(contents); |
| 1447 EXPECT_TRUE(contents->ShowingInterstitialPage()); |
| 1448 EXPECT_EQ(LoginInterstitialDelegate::kTypeForTesting, |
| 1449 contents->GetInterstitialPage() |
| 1450 ->GetDelegateForTesting() |
| 1451 ->GetTypeForTesting()); |
| 1452 // Navigation not committed yet when the auth dialog is displayed. |
| 1453 EXPECT_EQ("", contents->GetLastCommittedURL().host()); |
| 1454 EXPECT_EQ("127.0.0.1", contents->GetVisibleURL().host()); |
| 1455 CheckSSLState(contents, expected_ssl_status); |
| 1456 |
| 1457 // Cancelling the login prompt should detach the interstitial while keeping |
| 1458 // the correct origin and SSL state. |
| 1459 CancelAndWaitForInterstitialDetach(*observer.handlers().begin(), contents); |
| 1460 EXPECT_EQ("127.0.0.1", contents->GetVisibleURL().host()); |
| 1461 EXPECT_EQ("127.0.0.1", contents->GetLastCommittedURL().host()); |
| 1462 EXPECT_FALSE(contents->ShowingInterstitialPage()); |
| 1463 CheckSSLState(contents, expected_ssl_status); |
| 1464 } |
| 1465 } |
| 1466 |
| 1467 // Omnibox and connection tab should reflect the correct SSL State when login |
| 1468 // prompt is displayed in the main frame. |
| 1469 // This is simply the scenario where the user enters an HTTPS url that ends up |
| 1470 // with an HTTP auth dialog. |
| 1471 IN_PROC_BROWSER_TEST_F(LoginPromptBrowserTest, |
| 1472 SSLStateShouldUpdateOnDirectNavigation) { |
| 1473 net::SpawnedTestServer https_server( |
| 1474 net::SpawnedTestServer::TYPE_HTTPS, |
| 1475 net::SpawnedTestServer::SSLOptions( |
| 1476 net::SpawnedTestServer::SSLOptions::CERT_OK), |
| 1477 base::FilePath()); |
| 1478 ASSERT_TRUE(https_server.Start()); |
| 1479 GURL test_page = https_server.GetURL(kAuthBasicPage); |
| 1480 ASSERT_EQ("127.0.0.1", test_page.host()); |
| 1481 TestSSLState(browser(), test_page, false, SSL_STATUS_OK); |
| 1482 } |
| 1483 |
| 1484 // Same as above, except the HTTPS url has a cert error. When the user proceeds |
| 1485 // through the SSL interstitial, HTTP auth dialog should be displayed with the |
| 1486 // correct (i.e. broken) SSL information. |
| 1487 IN_PROC_BROWSER_TEST_F(LoginPromptBrowserTest, |
| 1488 SSLStateShouldUpdateOnDirectNavigation_BrokenSSL) { |
| 1489 net::SpawnedTestServer https_server( |
| 1490 net::SpawnedTestServer::TYPE_HTTPS, |
| 1491 net::SpawnedTestServer::SSLOptions( |
| 1492 net::SpawnedTestServer::SSLOptions::CERT_CHAIN_WRONG_ROOT), |
| 1493 base::FilePath()); |
| 1494 ASSERT_TRUE(https_server.Start()); |
| 1495 GURL test_page = https_server.GetURL(kAuthBasicPage); |
| 1496 ASSERT_EQ("127.0.0.1", test_page.host()); |
| 1497 TestSSLState(browser(), test_page, false, SSL_STATUS_BROKEN); |
| 1498 } |
| 1499 |
| 1500 // Same as |SSLStateShouldUpdateOnDirectNavigation|, except the user doesn't |
| 1501 // navigate directly to the HTTPS page. Instead, another page redirects to the |
| 1502 // HTTPS page. |
| 1503 IN_PROC_BROWSER_TEST_F(LoginPromptBrowserTest, SSLStateShouldUpdateOnRedirect) { |
| 1504 net::SpawnedTestServer https_server( |
| 1505 net::SpawnedTestServer::TYPE_HTTPS, |
| 1506 net::SpawnedTestServer::SSLOptions( |
| 1507 net::SpawnedTestServer::SSLOptions::CERT_OK), |
| 1508 base::FilePath()); |
| 1509 ASSERT_TRUE(https_server.Start()); |
| 1510 GURL https_url = https_server.GetURL(kAuthBasicPage); |
| 1511 ASSERT_EQ("127.0.0.1", https_url.host()); |
| 1512 |
| 1513 // Write an HTML file that redirects to the HTTPS url above. |
| 1514 base::ScopedTempDir temp_directory; |
| 1515 ASSERT_TRUE(temp_directory.CreateUniqueTempDir()); |
| 1516 base::FilePath temp_file; |
| 1517 ASSERT_TRUE( |
| 1518 base::CreateTemporaryFileInDir(temp_directory.path(), &temp_file)); |
| 1519 std::string html = base::StringPrintf( |
| 1520 "<html>" |
| 1521 "<script>window.location = '%s';</script>" |
| 1522 "</html>", |
| 1523 https_url.spec().c_str()); |
| 1524 ASSERT_EQ(static_cast<int>(html.size()), |
| 1525 base::WriteFile(temp_file, html.data(), html.size())); |
| 1526 TestSSLState(browser(), net::FilePathToFileURL(temp_file), true, |
| 1527 SSL_STATUS_OK); |
| 1528 } |
| 1529 |
| 1530 // Same as |SSLStateShouldUpdateOnDirectNavigation_BrokenSSL|, except the user |
| 1531 // doesn't navigate directly to the HTTPS page. Instead, another page redirects |
| 1532 // to the HTTPS page. |
| 1533 IN_PROC_BROWSER_TEST_F(LoginPromptBrowserTest, |
| 1534 SSLStateShouldUpdateOnRedirect_BrokenSSL) { |
| 1535 net::SpawnedTestServer https_server( |
| 1536 net::SpawnedTestServer::TYPE_HTTPS, |
| 1537 net::SpawnedTestServer::SSLOptions( |
| 1538 net::SpawnedTestServer::SSLOptions::CERT_CHAIN_WRONG_ROOT), |
| 1539 base::FilePath()); |
| 1540 ASSERT_TRUE(https_server.Start()); |
| 1541 GURL https_url = https_server.GetURL(kAuthBasicPage); |
| 1542 ASSERT_EQ("127.0.0.1", https_url.host()); |
| 1543 |
| 1544 // Write an HTML file that redirects to the HTTPS url above. |
| 1545 base::ScopedTempDir temp_directory; |
| 1546 ASSERT_TRUE(temp_directory.CreateUniqueTempDir()); |
| 1547 base::FilePath temp_file; |
| 1548 ASSERT_TRUE( |
| 1549 base::CreateTemporaryFileInDir(temp_directory.path(), &temp_file)); |
| 1550 std::string html = base::StringPrintf( |
| 1551 "<html>" |
| 1552 "<script>window.location = '%s';</script>" |
| 1553 "</html>", |
| 1554 https_url.spec().c_str()); |
| 1555 ASSERT_EQ(static_cast<int>(html.size()), |
| 1556 base::WriteFile(temp_file, html.data(), html.size())); |
| 1557 TestSSLState(browser(), net::FilePathToFileURL(temp_file), true, |
| 1558 SSL_STATUS_BROKEN); |
| 1559 } |
| 1560 |
| 1378 } // namespace | 1561 } // namespace |
| OLD | NEW |