| 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 581ebe48479e46f40bc3af9fd44f194f7e745bbc..0a5168907416722728331e4738e68f009d94bc38 100644
|
| --- a/chrome/browser/ssl/ssl_browser_tests.cc
|
| +++ b/chrome/browser/ssl/ssl_browser_tests.cc
|
| @@ -11,8 +11,12 @@
|
| #include "base/strings/utf_string_conversions.h"
|
| #include "base/time/time.h"
|
| #include "chrome/app/chrome_command_ids.h"
|
| +#include "chrome/browser/browser_process.h"
|
| #include "chrome/browser/chrome_notification_types.h"
|
| +#include "chrome/browser/net/certificate_error_reporter.h"
|
| #include "chrome/browser/profiles/profile.h"
|
| +#include "chrome/browser/safe_browsing/ping_manager.h"
|
| +#include "chrome/browser/safe_browsing/safe_browsing_service.h"
|
| #include "chrome/browser/ssl/ssl_blocking_page.h"
|
| #include "chrome/browser/ui/browser.h"
|
| #include "chrome/browser/ui/browser_commands.h"
|
| @@ -45,6 +49,7 @@
|
| #include "net/base/test_data_directory.h"
|
| #include "net/cert/cert_status_flags.h"
|
| #include "net/test/spawned_test_server/spawned_test_server.h"
|
| +#include "net/url_request/url_request_context.h"
|
|
|
| #if defined(USE_NSS)
|
| #include "chrome/browser/net/nss_context.h"
|
| @@ -53,6 +58,7 @@
|
| #endif // defined(USE_NSS)
|
|
|
| using base::ASCIIToUTF16;
|
| +using chrome_browser_net::CertificateErrorReporter;
|
| using content::InterstitialPage;
|
| using content::NavigationController;
|
| using content::NavigationEntry;
|
| @@ -169,6 +175,45 @@ void CheckSecurityState(WebContents* tab,
|
| AuthState::Check(*entry, expected_authentication_state);
|
| }
|
|
|
| +namespace CertificateReporting {
|
| +
|
| +enum OptIn { EXTENDED_REPORTING_OPT_IN, EXTENDED_REPORTING_DO_NOT_OPT_IN };
|
| +
|
| +enum Proceed { SSL_INTERSTITIAL_PROCEED, SSL_INTERSTITIAL_DO_NOT_PROCEED };
|
| +
|
| +enum ExpectReport { CERT_REPORT_EXPECTED, CERT_REPORT_NOT_EXPECTED };
|
| +
|
| +// This class is used to test invalid certificate chain reporting when
|
| +// the user opts in to do so on the interstitial.
|
| +class MockReporter : public CertificateErrorReporter {
|
| + public:
|
| + explicit MockReporter(net::URLRequestContext* request_context,
|
| + const GURL& upload_url)
|
| + : CertificateErrorReporter(request_context, upload_url) {}
|
| +
|
| + void SendReport(CertificateErrorReporter::ReportType type,
|
| + const std::string& hostname,
|
| + const net::SSLInfo& ssl_info) override {
|
| + EXPECT_EQ(CertificateErrorReporter::REPORT_TYPE_EXTENDED_REPORTING, type);
|
| + latest_hostname_reported_ = hostname;
|
| + }
|
| +
|
| + const std::string& latest_hostname_reported() {
|
| + return latest_hostname_reported_;
|
| + }
|
| +
|
| + private:
|
| + std::string latest_hostname_reported_;
|
| +};
|
| +
|
| +void SetUpMockReporter(SafeBrowsingService* safe_browsing_service,
|
| + MockReporter* reporter) {
|
| + safe_browsing_service->ping_manager()->SetCertificateErrorReporterForTesting(
|
| + scoped_ptr<CertificateErrorReporter>(reporter));
|
| +}
|
| +
|
| +} // namespace CertificateReporting
|
| +
|
| } // namespace
|
|
|
| class SSLUITest : public InProcessBrowserTest {
|
| @@ -187,6 +232,23 @@ class SSLUITest : public InProcessBrowserTest {
|
| SSLOptions(SSLOptions::CERT_EXPIRED),
|
| net::GetWebSocketTestDataDirectory()) {}
|
|
|
| + void SetUpOnMainThread() override {
|
| + // Set up the mock reporter to track the hostnames that reports get
|
| + // sent for. The request_context argument is NULL here
|
| + // because the MockReporter doesn't actually use a
|
| + // request_context. (In order to pass a real request_context, the
|
| + // reporter would have to be constructed on the IO thread.)
|
| + reporter_ = new CertificateReporting::MockReporter(
|
| + NULL, GURL("http://example.test"));
|
| + scoped_refptr<SafeBrowsingService> safe_browsing_service =
|
| + g_browser_process->safe_browsing_service();
|
| + ASSERT_TRUE(safe_browsing_service);
|
| + content::BrowserThread::PostTask(
|
| + content::BrowserThread::IO, FROM_HERE,
|
| + base::Bind(CertificateReporting::SetUpMockReporter,
|
| + safe_browsing_service, reporter_));
|
| + }
|
| +
|
| void SetUpCommandLine(base::CommandLine* command_line) override {
|
| // Browser will both run and display insecure content.
|
| command_line->AppendSwitch(switches::kAllowRunningInsecureContent);
|
| @@ -351,6 +413,57 @@ class SSLUITest : public InProcessBrowserTest {
|
| page_with_unsafe_worker_path);
|
| }
|
|
|
| + // Helper function for testing invalid certificate chain reporting.
|
| + void TestBrokenHTTPSReporting(
|
| + CertificateReporting::OptIn opt_in,
|
| + CertificateReporting::Proceed proceed,
|
| + CertificateReporting::ExpectReport expect_report,
|
| + Browser* browser) {
|
| + ASSERT_TRUE(https_server_expired_.Start());
|
| +
|
| + // Opt in to sending reports for invalid certificate chains.
|
| + browser->profile()->GetPrefs()->SetBoolean(
|
| + prefs::kSafeBrowsingExtendedReportingEnabled,
|
| + opt_in == CertificateReporting::EXTENDED_REPORTING_OPT_IN);
|
| +
|
| + ui_test_utils::NavigateToURL(browser, https_server_expired_.GetURL("/"));
|
| +
|
| + WebContents* tab = browser->tab_strip_model()->GetActiveWebContents();
|
| + CheckAuthenticationBrokenState(tab, net::CERT_STATUS_DATE_INVALID,
|
| + AuthState::SHOWING_INTERSTITIAL);
|
| +
|
| + // Set up a callback so that the test is notified when the report
|
| + // has been sent on the IO thread (or not sent).
|
| + base::RunLoop report_run_loop;
|
| + base::Closure report_callback = report_run_loop.QuitClosure();
|
| + SSLBlockingPage* interstitial_page = static_cast<SSLBlockingPage*>(
|
| + tab->GetInterstitialPage()->GetDelegateForTesting());
|
| + interstitial_page->SetCertificateReportCallbackForTesting(report_callback);
|
| +
|
| + EXPECT_EQ(std::string(), reporter_->latest_hostname_reported());
|
| +
|
| + // Leave the interstitial (either by proceeding or going back)
|
| + if (proceed == CertificateReporting::SSL_INTERSTITIAL_PROCEED) {
|
| + ProceedThroughInterstitial(tab);
|
| + } else {
|
| + // Click "Take me back"
|
| + InterstitialPage* interstitial_page = tab->GetInterstitialPage();
|
| + ASSERT_TRUE(interstitial_page);
|
| + interstitial_page->DontProceed();
|
| + }
|
| +
|
| + // Wait until the report has been sent on the IO thread.
|
| + report_run_loop.Run();
|
| +
|
| + if (expect_report == CertificateReporting::CERT_REPORT_EXPECTED) {
|
| + // Check that the mock reporter received a request to send a report.
|
| + EXPECT_EQ(https_server_expired_.GetURL("/").host(),
|
| + reporter_->latest_hostname_reported());
|
| + } else {
|
| + EXPECT_EQ(std::string(), reporter_->latest_hostname_reported());
|
| + }
|
| + }
|
| +
|
| net::SpawnedTestServer https_server_;
|
| net::SpawnedTestServer https_server_expired_;
|
| net::SpawnedTestServer https_server_mismatched_;
|
| @@ -358,6 +471,7 @@ class SSLUITest : public InProcessBrowserTest {
|
|
|
| private:
|
| typedef net::SpawnedTestServer::SSLOptions SSLOptions;
|
| + CertificateReporting::MockReporter* reporter_;
|
|
|
| DISALLOW_COPY_AND_ASSIGN(SSLUITest);
|
| };
|
| @@ -392,6 +506,17 @@ class SSLUITestIgnoreLocalhostCertErrors : public SSLUITest {
|
| }
|
| };
|
|
|
| +class SSLUITestWithExtendedReporting : public SSLUITest {
|
| + public:
|
| + SSLUITestWithExtendedReporting() : SSLUITest() {}
|
| +
|
| + void SetUpCommandLine(base::CommandLine* command_line) override {
|
| + // Enable a checkbox on SSL interstitials that allows users to opt
|
| + // in to reporting invalid certificate chains.
|
| + command_line->AppendSwitch(switches::kEnableInvalidCertCollection);
|
| + }
|
| +};
|
| +
|
| // Visits a regular page over http.
|
| IN_PROC_BROWSER_TEST_F(SSLUITest, TestHTTP) {
|
| ASSERT_TRUE(test_server()->Start());
|
| @@ -989,6 +1114,73 @@ IN_PROC_BROWSER_TEST_F(SSLUITest, MAYBE_TestDisplaysInsecureContent) {
|
| AuthState::DISPLAYED_INSECURE_CONTENT);
|
| }
|
|
|
| +// Test that when the checkbox is checked and the user proceeds through
|
| +// the interstitial, the FraudulentCertificateReporter sees a request to
|
| +// send a report.
|
| +IN_PROC_BROWSER_TEST_F(SSLUITestWithExtendedReporting,
|
| + TestBrokenHTTPSProceedWithReporting) {
|
| + TestBrokenHTTPSReporting(CertificateReporting::EXTENDED_REPORTING_OPT_IN,
|
| + CertificateReporting::SSL_INTERSTITIAL_PROCEED,
|
| + CertificateReporting::CERT_REPORT_EXPECTED,
|
| + browser());
|
| +}
|
| +
|
| +// Test that when the checkbox is checked and the user goes back (does
|
| +// not proceed through the interstitial), the
|
| +// FraudulentCertificateReporter sees a request to send a report.
|
| +IN_PROC_BROWSER_TEST_F(SSLUITestWithExtendedReporting,
|
| + TestBrokenHTTPSGoBackWithReporting) {
|
| + TestBrokenHTTPSReporting(
|
| + CertificateReporting::EXTENDED_REPORTING_OPT_IN,
|
| + CertificateReporting::SSL_INTERSTITIAL_DO_NOT_PROCEED,
|
| + CertificateReporting::CERT_REPORT_EXPECTED, browser());
|
| +}
|
| +
|
| +// Test that when the checkbox is not checked and the user proceeds
|
| +// through the interstitial, the FraudulentCertificateReporter does not
|
| +// see a request to send a report.
|
| +IN_PROC_BROWSER_TEST_F(SSLUITestWithExtendedReporting,
|
| + TestBrokenHTTPSProceedWithNoReporting) {
|
| + TestBrokenHTTPSReporting(
|
| + CertificateReporting::EXTENDED_REPORTING_DO_NOT_OPT_IN,
|
| + CertificateReporting::SSL_INTERSTITIAL_PROCEED,
|
| + CertificateReporting::CERT_REPORT_NOT_EXPECTED, browser());
|
| +}
|
| +
|
| +// Test that when the checkbox is not checked and the user does not proceed
|
| +// through the interstitial, the FraudulentCertificateReporter does not
|
| +// see a request to send a report.
|
| +IN_PROC_BROWSER_TEST_F(SSLUITestWithExtendedReporting,
|
| + TestBrokenHTTPSGoBackWithNoReporting) {
|
| + TestBrokenHTTPSReporting(
|
| + CertificateReporting::EXTENDED_REPORTING_DO_NOT_OPT_IN,
|
| + CertificateReporting::SSL_INTERSTITIAL_DO_NOT_PROCEED,
|
| + CertificateReporting::CERT_REPORT_NOT_EXPECTED, browser());
|
| +}
|
| +
|
| +// Test that when the command-line switch for reporting invalid cert
|
| +// chains is not enabled, reports don't get sent, even if the opt-in
|
| +// preference is set. (i.e. if a user enables invalid cert collection in
|
| +// chrome://flags, checks the box on an interstitial, and then disables
|
| +// the flag in chrome://flags, reports shouldn't be sent on the next
|
| +// interstitial).
|
| +IN_PROC_BROWSER_TEST_F(SSLUITest, TestBrokenHTTPSNoReportingWithoutSwitch) {
|
| + TestBrokenHTTPSReporting(CertificateReporting::EXTENDED_REPORTING_OPT_IN,
|
| + CertificateReporting::SSL_INTERSTITIAL_PROCEED,
|
| + CertificateReporting::CERT_REPORT_NOT_EXPECTED,
|
| + browser());
|
| +}
|
| +
|
| +// Test that reports don't get sent in incognito mode even if the opt-in
|
| +// preference is set and the command-line switch is enabled.
|
| +IN_PROC_BROWSER_TEST_F(SSLUITestWithExtendedReporting,
|
| + TestBrokenHTTPSNoReportingInIncognito) {
|
| + TestBrokenHTTPSReporting(CertificateReporting::EXTENDED_REPORTING_OPT_IN,
|
| + CertificateReporting::SSL_INTERSTITIAL_PROCEED,
|
| + CertificateReporting::CERT_REPORT_NOT_EXPECTED,
|
| + CreateIncognitoBrowser());
|
| +}
|
| +
|
| // Visits a page that runs insecure content and tries to suppress the insecure
|
| // content warnings by randomizing location.hash.
|
| // Based on http://crbug.com/8706
|
|
|