| Index: chrome/browser/ssl/ssl_browser_tests.cc
|
| diff --git a/chrome/browser/ssl/ssl_browser_tests.cc b/chrome/browser/ssl/ssl_browser_tests.cc
|
| index 31a3f6a13dbca0299249c2e0d90f7547f2626427..a34b1f7a4c838aeaac2d3a4eb29ed1d89da19489 100644
|
| --- a/chrome/browser/ssl/ssl_browser_tests.cc
|
| +++ b/chrome/browser/ssl/ssl_browser_tests.cc
|
| @@ -26,7 +26,9 @@
|
| #include "chrome/browser/ssl/certificate_error_report.h"
|
| #include "chrome/browser/ssl/certificate_reporting_test_utils.h"
|
| #include "chrome/browser/ssl/chrome_ssl_host_state_delegate.h"
|
| +#include "chrome/browser/ssl/common_name_mismatch_handler.h"
|
| #include "chrome/browser/ssl/ssl_blocking_page.h"
|
| +#include "chrome/browser/ssl/ssl_error_handler.h"
|
| #include "chrome/browser/ui/browser.h"
|
| #include "chrome/browser/ui/browser_commands.h"
|
| #include "chrome/browser/ui/browser_navigator.h"
|
| @@ -54,14 +56,17 @@
|
| #include "content/public/common/ssl_status.h"
|
| #include "content/public/test/browser_test_utils.h"
|
| #include "content/public/test/download_test_observer.h"
|
| +#include "content/public/test/test_navigation_observer.h"
|
| #include "content/public/test/test_renderer_host.h"
|
| #include "net/base/host_port_pair.h"
|
| #include "net/base/net_errors.h"
|
| #include "net/base/test_data_directory.h"
|
| #include "net/cert/cert_status_flags.h"
|
| #include "net/cert/x509_certificate.h"
|
| +#include "net/dns/mock_host_resolver.h"
|
| #include "net/ssl/ssl_info.h"
|
| #include "net/test/spawned_test_server/spawned_test_server.h"
|
| +#include "net/test/test_certificate_data.h"
|
| #include "net/url_request/url_request_context.h"
|
|
|
| #if defined(USE_NSS_CERTS)
|
| @@ -207,7 +212,15 @@ class SSLUITest
|
| base::FilePath(kDocRoot)),
|
| wss_server_expired_(net::SpawnedTestServer::TYPE_WSS,
|
| SSLOptions(SSLOptions::CERT_EXPIRED),
|
| - net::GetWebSocketTestDataDirectory()) {}
|
| + net::GetWebSocketTestDataDirectory()),
|
| + https_server_example_domain_(
|
| + net::SpawnedTestServer::TYPE_HTTPS,
|
| + SSLOptions(SSLOptions::CERT_EXAMPLE_DOMAIN),
|
| + base::FilePath(kDocRoot)),
|
| + https_server_www_example_domain_(
|
| + net::SpawnedTestServer::TYPE_HTTPS,
|
| + SSLOptions(SSLOptions::CERT_WWW_EXAMPLE_DOMAIN),
|
| + base::FilePath(kDocRoot)) {}
|
|
|
| void SetUpCommandLine(base::CommandLine* command_line) override {
|
| // Browser will both run and display insecure content.
|
| @@ -426,6 +439,8 @@ class SSLUITest
|
| net::SpawnedTestServer https_server_expired_;
|
| net::SpawnedTestServer https_server_mismatched_;
|
| net::SpawnedTestServer wss_server_expired_;
|
| + net::SpawnedTestServer https_server_example_domain_;
|
| + net::SpawnedTestServer https_server_www_example_domain_;
|
|
|
| private:
|
| typedef net::SpawnedTestServer::SSLOptions SSLOptions;
|
| @@ -2224,6 +2239,300 @@ IN_PROC_BROWSER_TEST_F(SSLUITest, BadCertFollowedByGoodCert) {
|
| EXPECT_FALSE(state->HasAllowException(https_server_host));
|
| }
|
|
|
| +// Verifies that invoking the SSL Blocking page with a suggested URL displays
|
| +// the common name mismatch interstitial with a link to suggested URL.
|
| +IN_PROC_BROWSER_TEST_F(SSLUITest, SSLBlockingPageWithSuggestedURL) {
|
| + content::WebContents* contents =
|
| + browser()->tab_strip_model()->GetActiveWebContents();
|
| + net::SSLInfo ssl_info;
|
| + ssl_info.cert = net::X509Certificate::CreateFromBytes(
|
| + reinterpret_cast<const char*>(google_der), sizeof(google_der));
|
| + // Create a new SSL blocking page for https://example.com with
|
| + // https://www.example.com as the suggested URL.
|
| + SSLBlockingPage* blocking_page = new SSLBlockingPage(
|
| + contents, net::ERR_CERT_COMMON_NAME_INVALID, ssl_info,
|
| + GURL("https://example.com"), 0, base::Time::NowFromSystemTime(), nullptr,
|
| + base::Callback<void(bool)>(), GURL("https://www.example.com"));
|
| + blocking_page->Show();
|
| +
|
| + WaitForInterstitialAttach(contents);
|
| +
|
| + EXPECT_TRUE(
|
| + WaitForRenderFrameReady(contents->GetInterstitialPage()->GetMainFrame()));
|
| + // The interstitial should display a link to www.example.com
|
| + EXPECT_TRUE(chrome_browser_interstitials::IsInterstitialDisplayingText(
|
| + contents->GetInterstitialPage(), "www.example.com"));
|
| + // Verify that the link has the text "suggest-link", the id of the
|
| + // link element displayed.
|
| + EXPECT_TRUE(chrome_browser_interstitials::IsInterstitialDisplayingText(
|
| + contents->GetInterstitialPage(), "suggest-link"));
|
| +}
|
| +
|
| +// Visit the URL www.example.com on a server that presents a valid certificate
|
| +// for example.com. Verify that the common name mismatch interstitial is
|
| +// displayed with a link to example.com. Click the suggested URL link
|
| +// and make sure the page navigates to suggested URL.
|
| +IN_PROC_BROWSER_TEST_F(SSLUITest, ShouldShowWWWSubdomainMismatchInterstitial) {
|
| + // Starts a server with a valid certificate for "example.com".
|
| + ASSERT_TRUE(https_server_example_domain_.Start());
|
| +
|
| + host_resolver()->AddRule("example.com", "127.0.0.1");
|
| + host_resolver()->AddRule("www.example.com", "127.0.0.1");
|
| +
|
| + // The path does not matter.
|
| + GURL https_server_url =
|
| + https_server_example_domain_.GetURL("files/ssl/google.html?a=b");
|
| + GURL::Replacements replacements;
|
| + replacements.SetHostStr("www.example.com");
|
| + GURL https_server_mismatched_url =
|
| + https_server_url.ReplaceComponents(replacements);
|
| +
|
| + ui_test_utils::NavigateToURL(browser(), https_server_mismatched_url);
|
| +
|
| + WebContents* contents = browser()->tab_strip_model()->GetActiveWebContents();
|
| + WaitForInterstitialAttach(contents);
|
| + // An interstitial should be displayed with a
|
| + // |CERT_STATUS_COMMON_NAME_INVALID| error.
|
| + CheckAuthenticationBrokenState(contents, net::CERT_STATUS_COMMON_NAME_INVALID,
|
| + AuthState::SHOWING_INTERSTITIAL);
|
| + EXPECT_EQ(SSLBlockingPage::kTypeForTesting, contents->GetInterstitialPage()
|
| + ->GetDelegateForTesting()
|
| + ->GetTypeForTesting());
|
| +
|
| + content::RenderFrameHost* rfh =
|
| + contents->GetInterstitialPage()->GetMainFrame();
|
| + EXPECT_TRUE(WaitForRenderFrameReady(rfh));
|
| + // The interstitial should display a link to www.example.com
|
| + EXPECT_TRUE(chrome_browser_interstitials::IsInterstitialDisplayingText(
|
| + contents->GetInterstitialPage(), "example.com"));
|
| + // Verify that the link has the text "suggest-link", the id of the
|
| + // link element displayed.
|
| + EXPECT_TRUE(chrome_browser_interstitials::IsInterstitialDisplayingText(
|
| + contents->GetInterstitialPage(), "suggest-link"));
|
| +
|
| + const char kOpenSuggestedLinkJS[] =
|
| + "document.getElementById('suggest-link').click();";
|
| + content::TestNavigationObserver observer(contents, 1);
|
| + EXPECT_TRUE(content::ExecuteScript(rfh, kClickConnectButtonJS));
|
| + observer.Wait();
|
| +
|
| + CheckAuthenticatedState(contents, AuthState::NONE);
|
| + replacements.SetHostStr("example.com");
|
| + GURL https_server_new_url = https_server_url.ReplaceComponents(replacements);
|
| + // Verify that the current URL is the suggested URL.
|
| + EXPECT_EQ(https_server_new_url.spec(),
|
| + contents->GetLastCommittedURL().spec());
|
| +}
|
| +
|
| +// Visit the URL example.com on a server that presents a valid certificate
|
| +// for www.example.com. Verify that the common name mismatch interstitial is
|
| +// displayed with a link to www.example.com.
|
| +IN_PROC_BROWSER_TEST_F(SSLUITest, CheckWWWSubdomainMismatchInverse) {
|
| + // Starts a server with a valid certificate for "example.com".
|
| + ASSERT_TRUE(https_server_www_example_domain_.Start());
|
| +
|
| + host_resolver()->AddRule("example.com", "127.0.0.1");
|
| + host_resolver()->AddRule("www.example.com", "127.0.0.1");
|
| +
|
| + GURL https_server_url =
|
| + https_server_www_example_domain_.GetURL("files/ssl/google.html?a=b");
|
| + GURL::Replacements replacements;
|
| + replacements.SetHostStr("example.com");
|
| + GURL https_server_mismatched_url =
|
| + https_server_url.ReplaceComponents(replacements);
|
| +
|
| + ui_test_utils::NavigateToURL(browser(), https_server_mismatched_url);
|
| +
|
| + WebContents* contents = browser()->tab_strip_model()->GetActiveWebContents();
|
| + WaitForInterstitialAttach(contents);
|
| + CheckAuthenticationBrokenState(contents, net::CERT_STATUS_COMMON_NAME_INVALID,
|
| + AuthState::SHOWING_INTERSTITIAL);
|
| + EXPECT_EQ(SSLBlockingPage::kTypeForTesting, contents->GetInterstitialPage()
|
| + ->GetDelegateForTesting()
|
| + ->GetTypeForTesting());
|
| +
|
| + EXPECT_TRUE(
|
| + WaitForRenderFrameReady(contents->GetInterstitialPage()->GetMainFrame()));
|
| + // The interstitial should display a link to www.example.com
|
| + EXPECT_TRUE(chrome_browser_interstitials::IsInterstitialDisplayingText(
|
| + contents->GetInterstitialPage(), "www.example.com"));
|
| + // Verify that the link has the text "suggest-link", the id of the
|
| + // link element displayed.
|
| + EXPECT_TRUE(chrome_browser_interstitials::IsInterstitialDisplayingText(
|
| + contents->GetInterstitialPage(), "suggest-link"));
|
| +}
|
| +
|
| +// This observer waits for the SSLErrorHandler to start an interstitial timer
|
| +// for the given web contents.
|
| +class SSLInterstitialTimerObserver {
|
| + public:
|
| + explicit SSLInterstitialTimerObserver(content::WebContents* web_contents);
|
| + ~SSLInterstitialTimerObserver();
|
| +
|
| + // Waits until the interstitial delay timer in SSLErrorHandler is started.
|
| + void WaitForTimerStarted();
|
| +
|
| + private:
|
| + void OnTimerStarted(content::WebContents* web_contents);
|
| +
|
| + const content::WebContents* web_contents_;
|
| + SSLErrorHandler::TimerStartedCallback callback_;
|
| +
|
| + scoped_refptr<content::MessageLoopRunner> message_loop_runner_;
|
| +
|
| + DISALLOW_COPY_AND_ASSIGN(SSLInterstitialTimerObserver);
|
| +};
|
| +
|
| +SSLInterstitialTimerObserver::SSLInterstitialTimerObserver(
|
| + content::WebContents* web_contents)
|
| + : web_contents_(web_contents),
|
| + message_loop_runner_(new content::MessageLoopRunner) {
|
| + callback_ = base::Bind(&SSLInterstitialTimerObserver::OnTimerStarted,
|
| + base::Unretained(this));
|
| + SSLErrorHandler::SetInterstitialTimerStartedCallbackForTest(&callback_);
|
| +}
|
| +
|
| +SSLInterstitialTimerObserver::~SSLInterstitialTimerObserver() {
|
| + SSLErrorHandler::SetInterstitialTimerStartedCallbackForTest(nullptr);
|
| +}
|
| +
|
| +void SSLInterstitialTimerObserver::WaitForTimerStarted() {
|
| + message_loop_runner_->Run();
|
| +}
|
| +
|
| +void SSLInterstitialTimerObserver::OnTimerStarted(
|
| + content::WebContents* web_contents) {
|
| + if (web_contents_ == web_contents && message_loop_runner_.get())
|
| + message_loop_runner_->Quit();
|
| +}
|
| +
|
| +// Tests this scenario:
|
| +// - |CommonNameMismatchHandler| does not give a callback as it's set into the
|
| +// state |IGNORE_REQUESTS_FOR_TESTING|. So no suggested URL check result can
|
| +// arrive.
|
| +// - A cert error triggers an interstitial timer with a very long timeout.
|
| +// - No suggested URL check results arrive, causing the tab to appear as loading
|
| +// indefinitely (also because the timer has a long timeout).
|
| +// - Stopping the page load shouldn't result in any interstitials.
|
| +IN_PROC_BROWSER_TEST_F(SSLUITest, InterstitialStopNavigationWhileLoading) {
|
| + // Starts a server with a valid certificate for "example.com".
|
| + ASSERT_TRUE(https_server_example_domain_.Start());
|
| +
|
| + host_resolver()->AddRule("example.com", "127.0.0.1");
|
| + host_resolver()->AddRule("www.example.com", "127.0.0.1");
|
| +
|
| + GURL https_server_url =
|
| + https_server_example_domain_.GetURL("files/ssl/google.html?a=b");
|
| + GURL::Replacements replacements;
|
| + replacements.SetHostStr("www.example.com");
|
| + GURL https_server_mismatched_url =
|
| + https_server_url.ReplaceComponents(replacements);
|
| +
|
| + WebContents* contents = browser()->tab_strip_model()->GetActiveWebContents();
|
| + CommonNameMismatchHandler::set_state_for_testing(
|
| + CommonNameMismatchHandler::IGNORE_REQUESTS_FOR_TESTING);
|
| + SSLInterstitialTimerObserver interstitial_timer_observer(contents);
|
| +
|
| + ui_test_utils::NavigateToURLWithDisposition(
|
| + browser(), https_server_mismatched_url, CURRENT_TAB,
|
| + ui_test_utils::BROWSER_TEST_NONE);
|
| + interstitial_timer_observer.WaitForTimerStarted();
|
| +
|
| + EXPECT_TRUE(contents->IsLoading());
|
| + content::WindowedNotificationObserver observer(
|
| + content::NOTIFICATION_LOAD_STOP,
|
| + content::NotificationService::AllSources());
|
| + contents->Stop();
|
| + observer.Wait();
|
| +
|
| + SSLErrorHandler* ssl_error_handler =
|
| + SSLErrorHandler::FromWebContents(contents);
|
| + // Make sure that the |SSLErrorHandler| is deleted.
|
| + EXPECT_FALSE(ssl_error_handler);
|
| + EXPECT_FALSE(contents->ShowingInterstitialPage());
|
| + EXPECT_FALSE(contents->IsLoading());
|
| +}
|
| +
|
| +// Same as above, but instead of stopping, the loading page is reloaded. The end
|
| +// result is the same. (i.e. page load stops, no interstitials shown)
|
| +IN_PROC_BROWSER_TEST_F(SSLUITest, InterstitialReloadNavigationWhileLoading) {
|
| + // Starts a server with a valid certificate for "example.com".
|
| + ASSERT_TRUE(https_server_example_domain_.Start());
|
| +
|
| + host_resolver()->AddRule("example.com", "127.0.0.1");
|
| + host_resolver()->AddRule("www.example.com", "127.0.0.1");
|
| +
|
| + GURL https_server_url =
|
| + https_server_example_domain_.GetURL("files/ssl/google.html?a=b");
|
| + GURL::Replacements replacements;
|
| + replacements.SetHostStr("www.example.com");
|
| + GURL https_server_mismatched_url =
|
| + https_server_url.ReplaceComponents(replacements);
|
| +
|
| + WebContents* contents = browser()->tab_strip_model()->GetActiveWebContents();
|
| + CommonNameMismatchHandler::set_state_for_testing(
|
| + CommonNameMismatchHandler::IGNORE_REQUESTS_FOR_TESTING);
|
| + SSLInterstitialTimerObserver interstitial_timer_observer(contents);
|
| +
|
| + ui_test_utils::NavigateToURLWithDisposition(
|
| + browser(), https_server_mismatched_url, CURRENT_TAB,
|
| + ui_test_utils::BROWSER_TEST_NONE);
|
| + interstitial_timer_observer.WaitForTimerStarted();
|
| +
|
| + EXPECT_TRUE(contents->IsLoading());
|
| + content::TestNavigationObserver observer(contents, 1);
|
| + chrome::Reload(browser(), CURRENT_TAB);
|
| + observer.Wait();
|
| +
|
| + SSLErrorHandler* ssl_error_handler =
|
| + SSLErrorHandler::FromWebContents(contents);
|
| + // Make sure that the |SSLErrorHandler| is deleted.
|
| + EXPECT_FALSE(ssl_error_handler);
|
| + EXPECT_FALSE(contents->ShowingInterstitialPage());
|
| + EXPECT_FALSE(contents->IsLoading());
|
| +}
|
| +
|
| +// Same as above, but instead of reloading, the page is navigated away. The
|
| +// new page should load, and no interstitials should be shown.
|
| +IN_PROC_BROWSER_TEST_F(SSLUITest, InterstitialNavigateAwayWhileLoading) {
|
| + // Starts a server with a valid certificate for "example.com".
|
| + ASSERT_TRUE(https_server_example_domain_.Start());
|
| +
|
| + host_resolver()->AddRule("example.com", "127.0.0.1");
|
| + host_resolver()->AddRule("www.example.com", "127.0.0.1");
|
| +
|
| + GURL https_server_url =
|
| + https_server_example_domain_.GetURL("files/ssl/google.html?a=b");
|
| + GURL::Replacements replacements;
|
| + replacements.SetHostStr("www.example.com");
|
| + GURL https_server_mismatched_url =
|
| + https_server_url.ReplaceComponents(replacements);
|
| +
|
| + WebContents* contents = browser()->tab_strip_model()->GetActiveWebContents();
|
| + CommonNameMismatchHandler::set_state_for_testing(
|
| + CommonNameMismatchHandler::IGNORE_REQUESTS_FOR_TESTING);
|
| + SSLInterstitialTimerObserver interstitial_timer_observer(contents);
|
| +
|
| + ui_test_utils::NavigateToURLWithDisposition(
|
| + browser(), https_server_mismatched_url, CURRENT_TAB,
|
| + ui_test_utils::BROWSER_TEST_NONE);
|
| + interstitial_timer_observer.WaitForTimerStarted();
|
| +
|
| + EXPECT_TRUE(contents->IsLoading());
|
| + content::TestNavigationObserver observer(contents, 1);
|
| + browser()->OpenURL(content::OpenURLParams(GURL("https://google.com"),
|
| + content::Referrer(), CURRENT_TAB,
|
| + ui::PAGE_TRANSITION_TYPED, false));
|
| + observer.Wait();
|
| +
|
| + SSLErrorHandler* ssl_error_handler =
|
| + SSLErrorHandler::FromWebContents(contents);
|
| + // Make sure that the |SSLErrorHandler| is deleted.
|
| + EXPECT_FALSE(ssl_error_handler);
|
| + EXPECT_FALSE(contents->ShowingInterstitialPage());
|
| + EXPECT_FALSE(contents->IsLoading());
|
| +}
|
| +
|
| class SSLBlockingPageIDNTest : public SecurityInterstitialIDNTest {
|
| protected:
|
| // SecurityInterstitialIDNTest implementation
|
| @@ -2233,9 +2542,10 @@ class SSLBlockingPageIDNTest : public SecurityInterstitialIDNTest {
|
| net::SSLInfo ssl_info;
|
| ssl_info.cert = new net::X509Certificate(
|
| request_url.host(), "CA", base::Time::Max(), base::Time::Max());
|
| - return new SSLBlockingPage(
|
| - contents, net::ERR_CERT_CONTAINS_ERRORS, ssl_info, request_url, 0,
|
| - base::Time::NowFromSystemTime(), nullptr, base::Callback<void(bool)>());
|
| + return new SSLBlockingPage(contents, net::ERR_CERT_CONTAINS_ERRORS,
|
| + ssl_info, request_url, 0,
|
| + base::Time::NowFromSystemTime(), nullptr,
|
| + base::Callback<void(bool)>(), GURL());
|
| }
|
| };
|
|
|
|
|