| OLD | NEW |
| (Empty) |
| 1 // Copyright 2015 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 "chrome/browser/ssl/chrome_security_state_model_client.h" | |
| 6 | |
| 7 #include "base/command_line.h" | |
| 8 #include "base/files/file_path.h" | |
| 9 #include "base/macros.h" | |
| 10 #include "base/strings/string_split.h" | |
| 11 #include "base/strings/utf_string_conversions.h" | |
| 12 #include "chrome/browser/ssl/cert_verifier_browser_test.h" | |
| 13 #include "chrome/browser/ssl/chrome_security_state_model_client.h" | |
| 14 #include "chrome/browser/ssl/ssl_blocking_page.h" | |
| 15 #include "chrome/browser/ui/browser.h" | |
| 16 #include "chrome/browser/ui/browser_commands.h" | |
| 17 #include "chrome/browser/ui/tabs/tab_strip_model.h" | |
| 18 #include "chrome/common/chrome_paths.h" | |
| 19 #include "chrome/common/chrome_switches.h" | |
| 20 #include "chrome/common/pref_names.h" | |
| 21 #include "chrome/grit/generated_resources.h" | |
| 22 #include "chrome/test/base/in_process_browser_test.h" | |
| 23 #include "chrome/test/base/ui_test_utils.h" | |
| 24 #include "components/prefs/pref_service.h" | |
| 25 #include "components/security_state/switches.h" | |
| 26 #include "content/public/browser/interstitial_page.h" | |
| 27 #include "content/public/browser/navigation_controller.h" | |
| 28 #include "content/public/browser/navigation_entry.h" | |
| 29 #include "content/public/browser/notification_service.h" | |
| 30 #include "content/public/browser/notification_types.h" | |
| 31 #include "content/public/browser/security_style_explanation.h" | |
| 32 #include "content/public/browser/security_style_explanations.h" | |
| 33 #include "content/public/browser/ssl_status.h" | |
| 34 #include "content/public/browser/web_contents.h" | |
| 35 #include "content/public/common/referrer.h" | |
| 36 #include "content/public/test/browser_test_utils.h" | |
| 37 #include "net/base/net_errors.h" | |
| 38 #include "net/cert/cert_status_flags.h" | |
| 39 #include "net/cert/cert_verify_result.h" | |
| 40 #include "net/cert/mock_cert_verifier.h" | |
| 41 #include "net/cert/sct_status_flags.h" | |
| 42 #include "net/cert/signed_certificate_timestamp.h" | |
| 43 #include "net/cert/signed_certificate_timestamp_and_status.h" | |
| 44 #include "net/cert/x509_certificate.h" | |
| 45 #include "net/dns/mock_host_resolver.h" | |
| 46 #include "net/ssl/ssl_cipher_suite_names.h" | |
| 47 #include "net/ssl/ssl_connection_status_flags.h" | |
| 48 #include "net/test/cert_test_util.h" | |
| 49 #include "net/test/embedded_test_server/embedded_test_server.h" | |
| 50 #include "net/test/embedded_test_server/request_handler_util.h" | |
| 51 #include "net/test/test_data_directory.h" | |
| 52 #include "net/test/url_request/url_request_failed_job.h" | |
| 53 #include "net/test/url_request/url_request_mock_http_job.h" | |
| 54 #include "net/url_request/url_request_filter.h" | |
| 55 #include "net/url_request/url_request_test_util.h" | |
| 56 #include "third_party/boringssl/src/include/openssl/ssl.h" | |
| 57 #include "ui/base/l10n/l10n_util.h" | |
| 58 | |
| 59 using security_state::SecurityStateModel; | |
| 60 | |
| 61 namespace { | |
| 62 | |
| 63 enum CertificateStatus { VALID_CERTIFICATE, INVALID_CERTIFICATE }; | |
| 64 | |
| 65 const base::FilePath::CharType kDocRoot[] = | |
| 66 FILE_PATH_LITERAL("chrome/test/data"); | |
| 67 | |
| 68 // A WebContentsObserver useful for testing the SecurityStyleChanged() | |
| 69 // method: it keeps track of the latest security style and explanation | |
| 70 // that was fired. | |
| 71 class SecurityStyleTestObserver : public content::WebContentsObserver { | |
| 72 public: | |
| 73 explicit SecurityStyleTestObserver(content::WebContents* web_contents) | |
| 74 : content::WebContentsObserver(web_contents), | |
| 75 latest_security_style_(blink::WebSecurityStyleUnknown) {} | |
| 76 ~SecurityStyleTestObserver() override {} | |
| 77 | |
| 78 void SecurityStyleChanged(blink::WebSecurityStyle security_style, | |
| 79 const content::SecurityStyleExplanations& | |
| 80 security_style_explanations) override { | |
| 81 latest_security_style_ = security_style; | |
| 82 latest_explanations_ = security_style_explanations; | |
| 83 } | |
| 84 | |
| 85 blink::WebSecurityStyle latest_security_style() const { | |
| 86 return latest_security_style_; | |
| 87 } | |
| 88 | |
| 89 const content::SecurityStyleExplanations& latest_explanations() const { | |
| 90 return latest_explanations_; | |
| 91 } | |
| 92 | |
| 93 void ClearLatestSecurityStyleAndExplanations() { | |
| 94 latest_security_style_ = blink::WebSecurityStyleUnknown; | |
| 95 latest_explanations_ = content::SecurityStyleExplanations(); | |
| 96 } | |
| 97 | |
| 98 private: | |
| 99 blink::WebSecurityStyle latest_security_style_; | |
| 100 content::SecurityStyleExplanations latest_explanations_; | |
| 101 | |
| 102 DISALLOW_COPY_AND_ASSIGN(SecurityStyleTestObserver); | |
| 103 }; | |
| 104 | |
| 105 // Check that |observer|'s latest event was for an expired certificate | |
| 106 // and that it saw the proper SecurityStyle and explanations. | |
| 107 void CheckBrokenSecurityStyle(const SecurityStyleTestObserver& observer, | |
| 108 int error, | |
| 109 Browser* browser, | |
| 110 net::X509Certificate* expected_cert) { | |
| 111 EXPECT_EQ(blink::WebSecurityStyleAuthenticationBroken, | |
| 112 observer.latest_security_style()); | |
| 113 | |
| 114 const content::SecurityStyleExplanations& expired_explanation = | |
| 115 observer.latest_explanations(); | |
| 116 EXPECT_EQ(0u, expired_explanation.unauthenticated_explanations.size()); | |
| 117 ASSERT_EQ(1u, expired_explanation.broken_explanations.size()); | |
| 118 EXPECT_FALSE(expired_explanation.pkp_bypassed); | |
| 119 EXPECT_TRUE(expired_explanation.info_explanations.empty()); | |
| 120 | |
| 121 // Check that the summary and description are as expected. | |
| 122 EXPECT_EQ(l10n_util::GetStringUTF8(IDS_CERTIFICATE_CHAIN_ERROR), | |
| 123 expired_explanation.broken_explanations[0].summary); | |
| 124 | |
| 125 base::string16 error_string = base::UTF8ToUTF16(net::ErrorToString(error)); | |
| 126 EXPECT_EQ(l10n_util::GetStringFUTF8( | |
| 127 IDS_CERTIFICATE_CHAIN_ERROR_DESCRIPTION_FORMAT, error_string), | |
| 128 expired_explanation.broken_explanations[0].description); | |
| 129 | |
| 130 // Check the associated certificate. | |
| 131 net::X509Certificate* cert = browser->tab_strip_model() | |
| 132 ->GetActiveWebContents() | |
| 133 ->GetController() | |
| 134 .GetActiveEntry() | |
| 135 ->GetSSL() | |
| 136 .certificate.get(); | |
| 137 EXPECT_TRUE(cert->Equals(expected_cert)); | |
| 138 EXPECT_TRUE(expired_explanation.broken_explanations[0].has_certificate); | |
| 139 } | |
| 140 | |
| 141 // Checks that the given |secure_explanations| contains an appropriate | |
| 142 // explanation if the certificate status is valid. | |
| 143 void CheckSecureExplanations( | |
| 144 const std::vector<content::SecurityStyleExplanation>& secure_explanations, | |
| 145 CertificateStatus cert_status, | |
| 146 Browser* browser, | |
| 147 net::X509Certificate* expected_cert) { | |
| 148 ASSERT_EQ(cert_status == VALID_CERTIFICATE ? 2u : 1u, | |
| 149 secure_explanations.size()); | |
| 150 if (cert_status == VALID_CERTIFICATE) { | |
| 151 EXPECT_EQ(l10n_util::GetStringUTF8(IDS_VALID_SERVER_CERTIFICATE), | |
| 152 secure_explanations[0].summary); | |
| 153 EXPECT_EQ( | |
| 154 l10n_util::GetStringUTF8(IDS_VALID_SERVER_CERTIFICATE_DESCRIPTION), | |
| 155 secure_explanations[0].description); | |
| 156 net::X509Certificate* cert = browser->tab_strip_model() | |
| 157 ->GetActiveWebContents() | |
| 158 ->GetController() | |
| 159 .GetActiveEntry() | |
| 160 ->GetSSL() | |
| 161 .certificate.get(); | |
| 162 EXPECT_TRUE(cert->Equals(expected_cert)); | |
| 163 EXPECT_TRUE(secure_explanations[0].has_certificate); | |
| 164 } | |
| 165 | |
| 166 EXPECT_EQ(l10n_util::GetStringUTF8(IDS_STRONG_SSL_SUMMARY), | |
| 167 secure_explanations.back().summary); | |
| 168 | |
| 169 content::WebContents* web_contents = | |
| 170 browser->tab_strip_model()->GetActiveWebContents(); | |
| 171 SecurityStateModel::SecurityInfo security_info; | |
| 172 ChromeSecurityStateModelClient::FromWebContents(web_contents) | |
| 173 ->GetSecurityInfo(&security_info); | |
| 174 | |
| 175 const char *protocol, *key_exchange, *cipher, *mac; | |
| 176 int ssl_version = | |
| 177 net::SSLConnectionStatusToVersion(security_info.connection_status); | |
| 178 net::SSLVersionToString(&protocol, ssl_version); | |
| 179 bool is_aead, is_tls13; | |
| 180 uint16_t cipher_suite = | |
| 181 net::SSLConnectionStatusToCipherSuite(security_info.connection_status); | |
| 182 net::SSLCipherSuiteToStrings(&key_exchange, &cipher, &mac, &is_aead, | |
| 183 &is_tls13, cipher_suite); | |
| 184 EXPECT_TRUE(is_aead); | |
| 185 EXPECT_EQ(nullptr, mac); // The default secure cipher does not have a MAC. | |
| 186 EXPECT_FALSE(is_tls13); // The default secure cipher is not TLS 1.3. | |
| 187 | |
| 188 base::string16 key_exchange_name = base::ASCIIToUTF16(key_exchange); | |
| 189 if (security_info.key_exchange_group != 0) { | |
| 190 key_exchange_name = l10n_util::GetStringFUTF16( | |
| 191 IDS_SSL_KEY_EXCHANGE_WITH_GROUP, key_exchange_name, | |
| 192 base::ASCIIToUTF16( | |
| 193 SSL_get_curve_name(security_info.key_exchange_group))); | |
| 194 } | |
| 195 | |
| 196 std::vector<base::string16> description_replacements; | |
| 197 description_replacements.push_back(base::ASCIIToUTF16(protocol)); | |
| 198 description_replacements.push_back(key_exchange_name); | |
| 199 description_replacements.push_back(base::ASCIIToUTF16(cipher)); | |
| 200 base::string16 secure_description = l10n_util::GetStringFUTF16( | |
| 201 IDS_STRONG_SSL_DESCRIPTION, description_replacements, nullptr); | |
| 202 | |
| 203 EXPECT_EQ(secure_description, | |
| 204 base::ASCIIToUTF16(secure_explanations.back().description)); | |
| 205 } | |
| 206 | |
| 207 void CheckSecurityInfoForSecure( | |
| 208 content::WebContents* contents, | |
| 209 SecurityStateModel::SecurityLevel expect_security_level, | |
| 210 SecurityStateModel::SHA1DeprecationStatus expect_sha1_status, | |
| 211 SecurityStateModel::ContentStatus expect_mixed_content_status, | |
| 212 bool pkp_bypassed, | |
| 213 bool expect_cert_error) { | |
| 214 ASSERT_TRUE(contents); | |
| 215 | |
| 216 ChromeSecurityStateModelClient* model_client = | |
| 217 ChromeSecurityStateModelClient::FromWebContents(contents); | |
| 218 ASSERT_TRUE(model_client); | |
| 219 SecurityStateModel::SecurityInfo security_info; | |
| 220 model_client->GetSecurityInfo(&security_info); | |
| 221 EXPECT_EQ(expect_security_level, security_info.security_level); | |
| 222 EXPECT_EQ(expect_sha1_status, security_info.sha1_deprecation_status); | |
| 223 EXPECT_EQ(expect_mixed_content_status, security_info.mixed_content_status); | |
| 224 EXPECT_TRUE(security_info.sct_verify_statuses.empty()); | |
| 225 EXPECT_TRUE(security_info.scheme_is_cryptographic); | |
| 226 EXPECT_EQ(pkp_bypassed, security_info.pkp_bypassed); | |
| 227 EXPECT_EQ(expect_cert_error, | |
| 228 net::IsCertStatusError(security_info.cert_status)); | |
| 229 EXPECT_GT(security_info.security_bits, 0); | |
| 230 EXPECT_TRUE(!!security_info.certificate); | |
| 231 } | |
| 232 | |
| 233 void CheckSecurityInfoForNonSecure(content::WebContents* contents) { | |
| 234 ASSERT_TRUE(contents); | |
| 235 | |
| 236 ChromeSecurityStateModelClient* model_client = | |
| 237 ChromeSecurityStateModelClient::FromWebContents(contents); | |
| 238 ASSERT_TRUE(model_client); | |
| 239 SecurityStateModel::SecurityInfo security_info; | |
| 240 model_client->GetSecurityInfo(&security_info); | |
| 241 EXPECT_EQ(SecurityStateModel::NONE, security_info.security_level); | |
| 242 EXPECT_EQ(SecurityStateModel::NO_DEPRECATED_SHA1, | |
| 243 security_info.sha1_deprecation_status); | |
| 244 EXPECT_EQ(SecurityStateModel::CONTENT_STATUS_NONE, | |
| 245 security_info.mixed_content_status); | |
| 246 EXPECT_TRUE(security_info.sct_verify_statuses.empty()); | |
| 247 EXPECT_FALSE(security_info.scheme_is_cryptographic); | |
| 248 EXPECT_FALSE(net::IsCertStatusError(security_info.cert_status)); | |
| 249 EXPECT_EQ(-1, security_info.security_bits); | |
| 250 EXPECT_FALSE(!!security_info.certificate); | |
| 251 } | |
| 252 | |
| 253 void ProceedThroughInterstitial(content::WebContents* tab) { | |
| 254 content::InterstitialPage* interstitial_page = tab->GetInterstitialPage(); | |
| 255 ASSERT_TRUE(interstitial_page); | |
| 256 ASSERT_EQ(SSLBlockingPage::kTypeForTesting, | |
| 257 interstitial_page->GetDelegateForTesting()->GetTypeForTesting()); | |
| 258 content::WindowedNotificationObserver observer( | |
| 259 content::NOTIFICATION_LOAD_STOP, | |
| 260 content::Source<content::NavigationController>(&tab->GetController())); | |
| 261 interstitial_page->Proceed(); | |
| 262 observer.Wait(); | |
| 263 } | |
| 264 | |
| 265 void GetFilePathWithHostAndPortReplacement( | |
| 266 const std::string& original_file_path, | |
| 267 const net::HostPortPair& host_port_pair, | |
| 268 std::string* replacement_path) { | |
| 269 base::StringPairs replacement_text; | |
| 270 replacement_text.push_back( | |
| 271 make_pair("REPLACE_WITH_HOST_AND_PORT", host_port_pair.ToString())); | |
| 272 net::test_server::GetFilePathWithReplacements( | |
| 273 original_file_path, replacement_text, replacement_path); | |
| 274 } | |
| 275 | |
| 276 class ChromeSecurityStateModelClientTest : public CertVerifierBrowserTest { | |
| 277 public: | |
| 278 ChromeSecurityStateModelClientTest() | |
| 279 : https_server_(net::EmbeddedTestServer::TYPE_HTTPS) { | |
| 280 https_server_.ServeFilesFromSourceDirectory(base::FilePath(kDocRoot)); | |
| 281 } | |
| 282 | |
| 283 void SetUpCommandLine(base::CommandLine* command_line) override { | |
| 284 // Browser will both run and display insecure content. | |
| 285 command_line->AppendSwitch(switches::kAllowRunningInsecureContent); | |
| 286 } | |
| 287 | |
| 288 protected: | |
| 289 void SetUpMockCertVerifierForHttpsServer(net::CertStatus cert_status, | |
| 290 int net_result) { | |
| 291 scoped_refptr<net::X509Certificate> cert(https_server_.GetCertificate()); | |
| 292 net::CertVerifyResult verify_result; | |
| 293 verify_result.is_issued_by_known_root = true; | |
| 294 verify_result.verified_cert = cert; | |
| 295 verify_result.cert_status = cert_status; | |
| 296 | |
| 297 mock_cert_verifier()->AddResultForCert(cert, verify_result, net_result); | |
| 298 } | |
| 299 | |
| 300 net::EmbeddedTestServer https_server_; | |
| 301 | |
| 302 private: | |
| 303 DISALLOW_COPY_AND_ASSIGN(ChromeSecurityStateModelClientTest); | |
| 304 }; | |
| 305 | |
| 306 GURL GetURLWithNonLocalHostname(net::EmbeddedTestServer* server, | |
| 307 const std::string& path) { | |
| 308 GURL::Replacements replace_host; | |
| 309 replace_host.SetHostStr("example.test"); | |
| 310 return server->GetURL(path).ReplaceComponents(replace_host); | |
| 311 } | |
| 312 | |
| 313 class ChromeSecurityStateModelClientTestWithPasswordCcSwitch | |
| 314 : public ChromeSecurityStateModelClientTest { | |
| 315 public: | |
| 316 ChromeSecurityStateModelClientTestWithPasswordCcSwitch() | |
| 317 : ChromeSecurityStateModelClientTest() {} | |
| 318 | |
| 319 void SetUpOnMainThread() override { | |
| 320 ASSERT_TRUE(embedded_test_server()->Start()); | |
| 321 ASSERT_TRUE(https_server_.Start()); | |
| 322 host_resolver()->AddRule("*", embedded_test_server()->GetURL("/").host()); | |
| 323 SetUpMockCertVerifierForHttpsServer(0, net::OK); | |
| 324 } | |
| 325 | |
| 326 void SetUpCommandLine(base::CommandLine* command_line) override { | |
| 327 ChromeSecurityStateModelClientTest::SetUpCommandLine(command_line); | |
| 328 command_line->AppendSwitchASCII( | |
| 329 security_state::switches::kMarkHttpAs, | |
| 330 security_state::switches::kMarkHttpWithPasswordsOrCcWithChip); | |
| 331 } | |
| 332 | |
| 333 private: | |
| 334 DISALLOW_COPY_AND_ASSIGN( | |
| 335 ChromeSecurityStateModelClientTestWithPasswordCcSwitch); | |
| 336 }; | |
| 337 | |
| 338 class SecurityStyleChangedTest : public InProcessBrowserTest { | |
| 339 public: | |
| 340 SecurityStyleChangedTest() | |
| 341 : https_server_(net::EmbeddedTestServer::TYPE_HTTPS) { | |
| 342 https_server_.ServeFilesFromSourceDirectory(base::FilePath(kDocRoot)); | |
| 343 } | |
| 344 | |
| 345 void SetUpCommandLine(base::CommandLine* command_line) override { | |
| 346 // Browser will both run and display insecure content. | |
| 347 command_line->AppendSwitch(switches::kAllowRunningInsecureContent); | |
| 348 } | |
| 349 | |
| 350 protected: | |
| 351 net::EmbeddedTestServer https_server_; | |
| 352 | |
| 353 private: | |
| 354 DISALLOW_COPY_AND_ASSIGN(SecurityStyleChangedTest); | |
| 355 }; | |
| 356 | |
| 357 IN_PROC_BROWSER_TEST_F(ChromeSecurityStateModelClientTest, HttpPage) { | |
| 358 ASSERT_TRUE(embedded_test_server()->Start()); | |
| 359 ui_test_utils::NavigateToURL( | |
| 360 browser(), embedded_test_server()->GetURL("/ssl/google.html")); | |
| 361 content::WebContents* contents = | |
| 362 browser()->tab_strip_model()->GetActiveWebContents(); | |
| 363 ASSERT_TRUE(contents); | |
| 364 | |
| 365 ChromeSecurityStateModelClient* model_client = | |
| 366 ChromeSecurityStateModelClient::FromWebContents(contents); | |
| 367 ASSERT_TRUE(model_client); | |
| 368 SecurityStateModel::SecurityInfo security_info; | |
| 369 model_client->GetSecurityInfo(&security_info); | |
| 370 EXPECT_EQ(SecurityStateModel::NONE, security_info.security_level); | |
| 371 EXPECT_EQ(SecurityStateModel::NO_DEPRECATED_SHA1, | |
| 372 security_info.sha1_deprecation_status); | |
| 373 EXPECT_EQ(SecurityStateModel::CONTENT_STATUS_NONE, | |
| 374 security_info.mixed_content_status); | |
| 375 EXPECT_TRUE(security_info.sct_verify_statuses.empty()); | |
| 376 EXPECT_FALSE(security_info.scheme_is_cryptographic); | |
| 377 EXPECT_FALSE(net::IsCertStatusError(security_info.cert_status)); | |
| 378 EXPECT_FALSE(!!security_info.certificate); | |
| 379 EXPECT_EQ(-1, security_info.security_bits); | |
| 380 EXPECT_EQ(0, security_info.connection_status); | |
| 381 } | |
| 382 | |
| 383 IN_PROC_BROWSER_TEST_F(ChromeSecurityStateModelClientTest, HttpsPage) { | |
| 384 ASSERT_TRUE(https_server_.Start()); | |
| 385 SetUpMockCertVerifierForHttpsServer(0, net::OK); | |
| 386 | |
| 387 ui_test_utils::NavigateToURL(browser(), | |
| 388 https_server_.GetURL("/ssl/google.html")); | |
| 389 CheckSecurityInfoForSecure( | |
| 390 browser()->tab_strip_model()->GetActiveWebContents(), | |
| 391 SecurityStateModel::SECURE, SecurityStateModel::NO_DEPRECATED_SHA1, | |
| 392 SecurityStateModel::CONTENT_STATUS_NONE, false, | |
| 393 false /* expect cert status error */); | |
| 394 } | |
| 395 | |
| 396 IN_PROC_BROWSER_TEST_F(ChromeSecurityStateModelClientTest, SHA1Broken) { | |
| 397 ASSERT_TRUE(https_server_.Start()); | |
| 398 // The test server uses a long-lived cert by default, so a SHA1 | |
| 399 // signature in it will register as a "broken" condition rather than | |
| 400 // "warning". | |
| 401 SetUpMockCertVerifierForHttpsServer(net::CERT_STATUS_SHA1_SIGNATURE_PRESENT, | |
| 402 net::OK); | |
| 403 | |
| 404 ui_test_utils::NavigateToURL(browser(), | |
| 405 https_server_.GetURL("/ssl/google.html")); | |
| 406 CheckSecurityInfoForSecure( | |
| 407 browser()->tab_strip_model()->GetActiveWebContents(), | |
| 408 SecurityStateModel::DANGEROUS, SecurityStateModel::DEPRECATED_SHA1_MAJOR, | |
| 409 SecurityStateModel::CONTENT_STATUS_NONE, false, | |
| 410 false /* expect cert status error */); | |
| 411 } | |
| 412 | |
| 413 IN_PROC_BROWSER_TEST_F(ChromeSecurityStateModelClientTest, MixedContent) { | |
| 414 ASSERT_TRUE(embedded_test_server()->Start()); | |
| 415 ASSERT_TRUE(https_server_.Start()); | |
| 416 SetUpMockCertVerifierForHttpsServer(0, net::OK); | |
| 417 host_resolver()->AddRule("example.test", | |
| 418 https_server_.GetURL("/title1.html").host()); | |
| 419 | |
| 420 net::HostPortPair replacement_pair = embedded_test_server()->host_port_pair(); | |
| 421 replacement_pair.set_host("example.test"); | |
| 422 | |
| 423 // Navigate to an HTTPS page that displays mixed content. | |
| 424 std::string replacement_path; | |
| 425 GetFilePathWithHostAndPortReplacement( | |
| 426 "/ssl/page_displays_insecure_content.html", | |
| 427 replacement_pair, &replacement_path); | |
| 428 ui_test_utils::NavigateToURL(browser(), | |
| 429 https_server_.GetURL(replacement_path)); | |
| 430 CheckSecurityInfoForSecure( | |
| 431 browser()->tab_strip_model()->GetActiveWebContents(), | |
| 432 SecurityStateModel::NONE, SecurityStateModel::NO_DEPRECATED_SHA1, | |
| 433 SecurityStateModel::CONTENT_STATUS_DISPLAYED, false, | |
| 434 false /* expect cert status error */); | |
| 435 | |
| 436 // Navigate to an HTTPS page that displays mixed content dynamically. | |
| 437 GetFilePathWithHostAndPortReplacement( | |
| 438 "/ssl/page_with_dynamic_insecure_content.html", | |
| 439 replacement_pair, &replacement_path); | |
| 440 ui_test_utils::NavigateToURL(browser(), | |
| 441 https_server_.GetURL(replacement_path)); | |
| 442 CheckSecurityInfoForSecure( | |
| 443 browser()->tab_strip_model()->GetActiveWebContents(), | |
| 444 SecurityStateModel::SECURE, SecurityStateModel::NO_DEPRECATED_SHA1, | |
| 445 SecurityStateModel::CONTENT_STATUS_NONE, false, | |
| 446 false /* expect cert status error */); | |
| 447 // Load the insecure image. | |
| 448 bool js_result = false; | |
| 449 EXPECT_TRUE(content::ExecuteScriptAndExtractBool( | |
| 450 browser()->tab_strip_model()->GetActiveWebContents(), "loadBadImage();", | |
| 451 &js_result)); | |
| 452 EXPECT_TRUE(js_result); | |
| 453 CheckSecurityInfoForSecure( | |
| 454 browser()->tab_strip_model()->GetActiveWebContents(), | |
| 455 SecurityStateModel::NONE, SecurityStateModel::NO_DEPRECATED_SHA1, | |
| 456 SecurityStateModel::CONTENT_STATUS_DISPLAYED, false, | |
| 457 false /* expect cert status error */); | |
| 458 | |
| 459 // Navigate to an HTTPS page that runs mixed content. | |
| 460 GetFilePathWithHostAndPortReplacement( | |
| 461 "/ssl/page_runs_insecure_content.html", | |
| 462 replacement_pair, &replacement_path); | |
| 463 ui_test_utils::NavigateToURL(browser(), | |
| 464 https_server_.GetURL(replacement_path)); | |
| 465 CheckSecurityInfoForSecure( | |
| 466 browser()->tab_strip_model()->GetActiveWebContents(), | |
| 467 SecurityStateModel::DANGEROUS, SecurityStateModel::NO_DEPRECATED_SHA1, | |
| 468 SecurityStateModel::CONTENT_STATUS_RAN, false, | |
| 469 false /* expect cert status error */); | |
| 470 | |
| 471 // Navigate to an HTTPS page that runs and displays mixed content. | |
| 472 GetFilePathWithHostAndPortReplacement( | |
| 473 "/ssl/page_runs_and_displays_insecure_content.html", | |
| 474 replacement_pair, &replacement_path); | |
| 475 ui_test_utils::NavigateToURL(browser(), | |
| 476 https_server_.GetURL(replacement_path)); | |
| 477 CheckSecurityInfoForSecure( | |
| 478 browser()->tab_strip_model()->GetActiveWebContents(), | |
| 479 SecurityStateModel::DANGEROUS, SecurityStateModel::NO_DEPRECATED_SHA1, | |
| 480 SecurityStateModel::CONTENT_STATUS_DISPLAYED_AND_RAN, false, | |
| 481 false /* expect cert status error */); | |
| 482 | |
| 483 // Navigate to an HTTPS page that runs mixed content in an iframe. | |
| 484 net::HostPortPair host_port_pair = | |
| 485 net::HostPortPair::FromURL(https_server_.GetURL("/title1.html")); | |
| 486 host_port_pair.set_host("different-host.test"); | |
| 487 host_resolver()->AddRule("different-host.test", | |
| 488 https_server_.GetURL("/title1.html").host()); | |
| 489 host_resolver()->AddRule( | |
| 490 "different-http-host.test", | |
| 491 embedded_test_server()->GetURL("/title1.html").host()); | |
| 492 GetFilePathWithHostAndPortReplacement( | |
| 493 "/ssl/page_runs_insecure_content_in_iframe.html", host_port_pair, | |
| 494 &replacement_path); | |
| 495 ui_test_utils::NavigateToURL(browser(), | |
| 496 https_server_.GetURL(replacement_path)); | |
| 497 CheckSecurityInfoForSecure( | |
| 498 browser()->tab_strip_model()->GetActiveWebContents(), | |
| 499 SecurityStateModel::DANGEROUS, SecurityStateModel::NO_DEPRECATED_SHA1, | |
| 500 SecurityStateModel::CONTENT_STATUS_RAN, false, | |
| 501 false /* expect cert status error */); | |
| 502 } | |
| 503 | |
| 504 IN_PROC_BROWSER_TEST_F(ChromeSecurityStateModelClientTest, | |
| 505 ActiveContentWithCertErrors) { | |
| 506 ASSERT_TRUE(https_server_.Start()); | |
| 507 SetUpMockCertVerifierForHttpsServer(0, net::OK); | |
| 508 | |
| 509 // Navigate to an HTTPS page and simulate active content with | |
| 510 // certificate errors. | |
| 511 ui_test_utils::NavigateToURL(browser(), https_server_.GetURL("/title1.html")); | |
| 512 content::WebContents* web_contents = | |
| 513 browser()->tab_strip_model()->GetActiveWebContents(); | |
| 514 ASSERT_TRUE(web_contents); | |
| 515 content::NavigationEntry* entry = | |
| 516 web_contents->GetController().GetVisibleEntry(); | |
| 517 ASSERT_TRUE(entry); | |
| 518 entry->GetSSL().content_status |= | |
| 519 content::SSLStatus::RAN_CONTENT_WITH_CERT_ERRORS; | |
| 520 | |
| 521 ChromeSecurityStateModelClient* model_client = | |
| 522 ChromeSecurityStateModelClient::FromWebContents(web_contents); | |
| 523 ASSERT_TRUE(model_client); | |
| 524 SecurityStateModel::SecurityInfo security_info; | |
| 525 model_client->GetSecurityInfo(&security_info); | |
| 526 | |
| 527 EXPECT_FALSE(net::IsCertStatusError(security_info.cert_status)); | |
| 528 EXPECT_EQ(SecurityStateModel::DANGEROUS, security_info.security_level); | |
| 529 EXPECT_EQ(SecurityStateModel::CONTENT_STATUS_RAN, | |
| 530 security_info.content_with_cert_errors_status); | |
| 531 } | |
| 532 | |
| 533 IN_PROC_BROWSER_TEST_F(ChromeSecurityStateModelClientTest, | |
| 534 PassiveContentWithCertErrors) { | |
| 535 ASSERT_TRUE(https_server_.Start()); | |
| 536 SetUpMockCertVerifierForHttpsServer(0, net::OK); | |
| 537 | |
| 538 // Navigate to an HTTPS page and simulate passive content with | |
| 539 // certificate errors. | |
| 540 ui_test_utils::NavigateToURL(browser(), https_server_.GetURL("/title1.html")); | |
| 541 content::WebContents* web_contents = | |
| 542 browser()->tab_strip_model()->GetActiveWebContents(); | |
| 543 ASSERT_TRUE(web_contents); | |
| 544 content::NavigationEntry* entry = | |
| 545 web_contents->GetController().GetVisibleEntry(); | |
| 546 ASSERT_TRUE(entry); | |
| 547 entry->GetSSL().content_status |= | |
| 548 content::SSLStatus::DISPLAYED_CONTENT_WITH_CERT_ERRORS; | |
| 549 | |
| 550 ChromeSecurityStateModelClient* model_client = | |
| 551 ChromeSecurityStateModelClient::FromWebContents(web_contents); | |
| 552 ASSERT_TRUE(model_client); | |
| 553 SecurityStateModel::SecurityInfo security_info; | |
| 554 model_client->GetSecurityInfo(&security_info); | |
| 555 | |
| 556 EXPECT_FALSE(net::IsCertStatusError(security_info.cert_status)); | |
| 557 EXPECT_EQ(SecurityStateModel::NONE, security_info.security_level); | |
| 558 EXPECT_EQ(SecurityStateModel::CONTENT_STATUS_DISPLAYED, | |
| 559 security_info.content_with_cert_errors_status); | |
| 560 } | |
| 561 | |
| 562 IN_PROC_BROWSER_TEST_F(ChromeSecurityStateModelClientTest, | |
| 563 ActiveAndPassiveContentWithCertErrors) { | |
| 564 ASSERT_TRUE(https_server_.Start()); | |
| 565 SetUpMockCertVerifierForHttpsServer(0, net::OK); | |
| 566 | |
| 567 // Navigate to an HTTPS page and simulate active and passive content | |
| 568 // with certificate errors. | |
| 569 ui_test_utils::NavigateToURL(browser(), https_server_.GetURL("/title1.html")); | |
| 570 content::WebContents* web_contents = | |
| 571 browser()->tab_strip_model()->GetActiveWebContents(); | |
| 572 ASSERT_TRUE(web_contents); | |
| 573 content::NavigationEntry* entry = | |
| 574 web_contents->GetController().GetVisibleEntry(); | |
| 575 ASSERT_TRUE(entry); | |
| 576 entry->GetSSL().content_status |= | |
| 577 content::SSLStatus::RAN_CONTENT_WITH_CERT_ERRORS; | |
| 578 entry->GetSSL().content_status |= | |
| 579 content::SSLStatus::DISPLAYED_CONTENT_WITH_CERT_ERRORS; | |
| 580 | |
| 581 ChromeSecurityStateModelClient* model_client = | |
| 582 ChromeSecurityStateModelClient::FromWebContents(web_contents); | |
| 583 ASSERT_TRUE(model_client); | |
| 584 SecurityStateModel::SecurityInfo security_info; | |
| 585 model_client->GetSecurityInfo(&security_info); | |
| 586 | |
| 587 EXPECT_FALSE(net::IsCertStatusError(security_info.cert_status)); | |
| 588 EXPECT_EQ(SecurityStateModel::DANGEROUS, security_info.security_level); | |
| 589 EXPECT_EQ(SecurityStateModel::CONTENT_STATUS_DISPLAYED_AND_RAN, | |
| 590 security_info.content_with_cert_errors_status); | |
| 591 } | |
| 592 | |
| 593 // Same as the test above but with a long-lived SHA1 cert. | |
| 594 IN_PROC_BROWSER_TEST_F(ChromeSecurityStateModelClientTest, | |
| 595 MixedContentWithBrokenSHA1) { | |
| 596 ASSERT_TRUE(embedded_test_server()->Start()); | |
| 597 ASSERT_TRUE(https_server_.Start()); | |
| 598 // The test server uses a long-lived cert by default, so a SHA1 | |
| 599 // signature in it will register as a "broken" condition rather than | |
| 600 // "warning". | |
| 601 SetUpMockCertVerifierForHttpsServer(net::CERT_STATUS_SHA1_SIGNATURE_PRESENT, | |
| 602 net::OK); | |
| 603 | |
| 604 host_resolver()->AddRule("example.test", | |
| 605 https_server_.GetURL("/title1.html").host()); | |
| 606 | |
| 607 net::HostPortPair replacement_pair = embedded_test_server()->host_port_pair(); | |
| 608 replacement_pair.set_host("example.test"); | |
| 609 | |
| 610 // Navigate to an HTTPS page that displays mixed content. | |
| 611 std::string replacement_path; | |
| 612 GetFilePathWithHostAndPortReplacement( | |
| 613 "/ssl/page_displays_insecure_content.html", | |
| 614 replacement_pair, &replacement_path); | |
| 615 ui_test_utils::NavigateToURL(browser(), | |
| 616 https_server_.GetURL(replacement_path)); | |
| 617 CheckSecurityInfoForSecure( | |
| 618 browser()->tab_strip_model()->GetActiveWebContents(), | |
| 619 SecurityStateModel::DANGEROUS, SecurityStateModel::DEPRECATED_SHA1_MAJOR, | |
| 620 SecurityStateModel::CONTENT_STATUS_DISPLAYED, false, | |
| 621 false /* expect cert status error */); | |
| 622 | |
| 623 // Navigate to an HTTPS page that displays mixed content dynamically. | |
| 624 GetFilePathWithHostAndPortReplacement( | |
| 625 "/ssl/page_with_dynamic_insecure_content.html", | |
| 626 replacement_pair, &replacement_path); | |
| 627 ui_test_utils::NavigateToURL(browser(), | |
| 628 https_server_.GetURL(replacement_path)); | |
| 629 CheckSecurityInfoForSecure( | |
| 630 browser()->tab_strip_model()->GetActiveWebContents(), | |
| 631 SecurityStateModel::DANGEROUS, SecurityStateModel::DEPRECATED_SHA1_MAJOR, | |
| 632 SecurityStateModel::CONTENT_STATUS_NONE, false, | |
| 633 false /* expect cert status error */); | |
| 634 // Load the insecure image. | |
| 635 bool js_result = false; | |
| 636 EXPECT_TRUE(content::ExecuteScriptAndExtractBool( | |
| 637 browser()->tab_strip_model()->GetActiveWebContents(), "loadBadImage();", | |
| 638 &js_result)); | |
| 639 EXPECT_TRUE(js_result); | |
| 640 CheckSecurityInfoForSecure( | |
| 641 browser()->tab_strip_model()->GetActiveWebContents(), | |
| 642 SecurityStateModel::DANGEROUS, SecurityStateModel::DEPRECATED_SHA1_MAJOR, | |
| 643 SecurityStateModel::CONTENT_STATUS_DISPLAYED, false, | |
| 644 false /* expect cert status error */); | |
| 645 | |
| 646 // Navigate to an HTTPS page that runs mixed content. | |
| 647 GetFilePathWithHostAndPortReplacement( | |
| 648 "/ssl/page_runs_insecure_content.html", | |
| 649 replacement_pair, &replacement_path); | |
| 650 ui_test_utils::NavigateToURL(browser(), | |
| 651 https_server_.GetURL(replacement_path)); | |
| 652 CheckSecurityInfoForSecure( | |
| 653 browser()->tab_strip_model()->GetActiveWebContents(), | |
| 654 SecurityStateModel::DANGEROUS, SecurityStateModel::DEPRECATED_SHA1_MAJOR, | |
| 655 SecurityStateModel::CONTENT_STATUS_RAN, false, | |
| 656 false /* expect cert status error */); | |
| 657 | |
| 658 // Navigate to an HTTPS page that runs and displays mixed content. | |
| 659 GetFilePathWithHostAndPortReplacement( | |
| 660 "/ssl/page_runs_and_displays_insecure_content.html", | |
| 661 replacement_pair, &replacement_path); | |
| 662 ui_test_utils::NavigateToURL(browser(), | |
| 663 https_server_.GetURL(replacement_path)); | |
| 664 CheckSecurityInfoForSecure( | |
| 665 browser()->tab_strip_model()->GetActiveWebContents(), | |
| 666 SecurityStateModel::DANGEROUS, SecurityStateModel::DEPRECATED_SHA1_MAJOR, | |
| 667 SecurityStateModel::CONTENT_STATUS_DISPLAYED_AND_RAN, false, | |
| 668 false /* expect cert status error */); | |
| 669 } | |
| 670 | |
| 671 // Tests that the Content Security Policy block-all-mixed-content | |
| 672 // directive stops mixed content from running. | |
| 673 IN_PROC_BROWSER_TEST_F(ChromeSecurityStateModelClientTest, | |
| 674 MixedContentStrictBlocking) { | |
| 675 ASSERT_TRUE(https_server_.Start()); | |
| 676 SetUpMockCertVerifierForHttpsServer(0, net::OK); | |
| 677 | |
| 678 // Navigate to an HTTPS page that tries to run mixed content in an | |
| 679 // iframe, with strict mixed content blocking. | |
| 680 std::string replacement_path; | |
| 681 net::HostPortPair host_port_pair = | |
| 682 net::HostPortPair::FromURL(https_server_.GetURL("/title1.html")); | |
| 683 host_port_pair.set_host("different-host.test"); | |
| 684 host_resolver()->AddRule("different-host.test", | |
| 685 https_server_.GetURL("/title1.html").host()); | |
| 686 GetFilePathWithHostAndPortReplacement( | |
| 687 "/ssl/page_runs_insecure_content_in_iframe_with_strict_blocking.html", | |
| 688 host_port_pair, &replacement_path); | |
| 689 ui_test_utils::NavigateToURL(browser(), | |
| 690 https_server_.GetURL(replacement_path)); | |
| 691 CheckSecurityInfoForSecure( | |
| 692 browser()->tab_strip_model()->GetActiveWebContents(), | |
| 693 SecurityStateModel::SECURE, SecurityStateModel::NO_DEPRECATED_SHA1, | |
| 694 SecurityStateModel::CONTENT_STATUS_NONE, false, | |
| 695 false /* expect cert status error */); | |
| 696 } | |
| 697 | |
| 698 IN_PROC_BROWSER_TEST_F(ChromeSecurityStateModelClientTest, BrokenHTTPS) { | |
| 699 ASSERT_TRUE(embedded_test_server()->Start()); | |
| 700 ASSERT_TRUE(https_server_.Start()); | |
| 701 SetUpMockCertVerifierForHttpsServer(net::CERT_STATUS_DATE_INVALID, | |
| 702 net::ERR_CERT_DATE_INVALID); | |
| 703 | |
| 704 ui_test_utils::NavigateToURL(browser(), | |
| 705 https_server_.GetURL("/ssl/google.html")); | |
| 706 CheckSecurityInfoForSecure( | |
| 707 browser()->tab_strip_model()->GetActiveWebContents(), | |
| 708 SecurityStateModel::DANGEROUS, SecurityStateModel::NO_DEPRECATED_SHA1, | |
| 709 SecurityStateModel::CONTENT_STATUS_NONE, false, | |
| 710 true /* expect cert status error */); | |
| 711 | |
| 712 ProceedThroughInterstitial( | |
| 713 browser()->tab_strip_model()->GetActiveWebContents()); | |
| 714 | |
| 715 CheckSecurityInfoForSecure( | |
| 716 browser()->tab_strip_model()->GetActiveWebContents(), | |
| 717 SecurityStateModel::DANGEROUS, SecurityStateModel::NO_DEPRECATED_SHA1, | |
| 718 SecurityStateModel::CONTENT_STATUS_NONE, false, | |
| 719 true /* expect cert status error */); | |
| 720 | |
| 721 // Navigate to a broken HTTPS page that displays mixed content. | |
| 722 std::string replacement_path; | |
| 723 GetFilePathWithHostAndPortReplacement( | |
| 724 "/ssl/page_displays_insecure_content.html", | |
| 725 embedded_test_server()->host_port_pair(), &replacement_path); | |
| 726 ui_test_utils::NavigateToURL(browser(), | |
| 727 https_server_.GetURL(replacement_path)); | |
| 728 CheckSecurityInfoForSecure( | |
| 729 browser()->tab_strip_model()->GetActiveWebContents(), | |
| 730 SecurityStateModel::DANGEROUS, SecurityStateModel::NO_DEPRECATED_SHA1, | |
| 731 SecurityStateModel::CONTENT_STATUS_DISPLAYED, false, | |
| 732 true /* expect cert status error */); | |
| 733 } | |
| 734 | |
| 735 const char kReportURI[] = "https://report-hpkp.test"; | |
| 736 | |
| 737 class PKPModelClientTest : public ChromeSecurityStateModelClientTest { | |
| 738 public: | |
| 739 void SetUpOnMainThread() override { | |
| 740 ASSERT_TRUE(https_server_.Start()); | |
| 741 url_request_context_getter_ = browser()->profile()->GetRequestContext(); | |
| 742 content::BrowserThread::PostTask( | |
| 743 content::BrowserThread::IO, FROM_HERE, | |
| 744 base::Bind(&PKPModelClientTest::SetUpOnIOThread, | |
| 745 base::Unretained(this))); | |
| 746 } | |
| 747 | |
| 748 void SetUpOnIOThread() { | |
| 749 net::URLRequestContext* request_context = | |
| 750 url_request_context_getter_->GetURLRequestContext(); | |
| 751 net::TransportSecurityState* security_state = | |
| 752 request_context->transport_security_state(); | |
| 753 | |
| 754 base::Time expiration = | |
| 755 base::Time::Now() + base::TimeDelta::FromSeconds(10000); | |
| 756 | |
| 757 net::HashValue hash(net::HASH_VALUE_SHA256); | |
| 758 memset(hash.data(), 0x99, hash.size()); | |
| 759 net::HashValueVector hashes; | |
| 760 hashes.push_back(hash); | |
| 761 | |
| 762 security_state->AddHPKP(https_server_.host_port_pair().host(), expiration, | |
| 763 true, hashes, GURL(kReportURI)); | |
| 764 } | |
| 765 | |
| 766 protected: | |
| 767 scoped_refptr<net::URLRequestContextGetter> url_request_context_getter_; | |
| 768 }; | |
| 769 | |
| 770 IN_PROC_BROWSER_TEST_F(PKPModelClientTest, PKPBypass) { | |
| 771 content::WebContents* web_contents = | |
| 772 browser()->tab_strip_model()->GetActiveWebContents(); | |
| 773 SecurityStyleTestObserver observer(web_contents); | |
| 774 | |
| 775 scoped_refptr<net::X509Certificate> cert(https_server_.GetCertificate()); | |
| 776 net::CertVerifyResult verify_result; | |
| 777 // PKP is bypassed when |is_issued_by_known_root| is false. | |
| 778 verify_result.is_issued_by_known_root = false; | |
| 779 verify_result.verified_cert = cert; | |
| 780 net::HashValue hash(net::HASH_VALUE_SHA256); | |
| 781 memset(hash.data(), 1, hash.size()); | |
| 782 verify_result.public_key_hashes.push_back(hash); | |
| 783 | |
| 784 mock_cert_verifier()->AddResultForCert(cert, verify_result, net::OK); | |
| 785 | |
| 786 ui_test_utils::NavigateToURL(browser(), | |
| 787 https_server_.GetURL("/ssl/google.html")); | |
| 788 | |
| 789 CheckSecurityInfoForSecure( | |
| 790 browser()->tab_strip_model()->GetActiveWebContents(), | |
| 791 SecurityStateModel::SECURE, SecurityStateModel::NO_DEPRECATED_SHA1, | |
| 792 SecurityStateModel::CONTENT_STATUS_NONE, true, false); | |
| 793 | |
| 794 const content::SecurityStyleExplanations& explanation = | |
| 795 observer.latest_explanations(); | |
| 796 EXPECT_TRUE(explanation.pkp_bypassed); | |
| 797 EXPECT_FALSE(explanation.info_explanations.empty()); | |
| 798 } | |
| 799 | |
| 800 IN_PROC_BROWSER_TEST_F(PKPModelClientTest, PKPEnforced) { | |
| 801 content::WebContents* web_contents = | |
| 802 browser()->tab_strip_model()->GetActiveWebContents(); | |
| 803 SecurityStyleTestObserver observer(web_contents); | |
| 804 | |
| 805 scoped_refptr<net::X509Certificate> cert(https_server_.GetCertificate()); | |
| 806 net::CertVerifyResult verify_result; | |
| 807 // PKP requires |is_issued_by_known_root| to be true. | |
| 808 verify_result.is_issued_by_known_root = true; | |
| 809 verify_result.verified_cert = cert; | |
| 810 net::HashValue hash(net::HASH_VALUE_SHA256); | |
| 811 memset(hash.data(), 1, hash.size()); | |
| 812 verify_result.public_key_hashes.push_back(hash); | |
| 813 | |
| 814 mock_cert_verifier()->AddResultForCert(cert, verify_result, net::OK); | |
| 815 | |
| 816 ui_test_utils::NavigateToURL(browser(), | |
| 817 https_server_.GetURL("/ssl/google.html")); | |
| 818 CheckBrokenSecurityStyle(observer, net::ERR_SSL_PINNED_KEY_NOT_IN_CERT_CHAIN, | |
| 819 browser(), cert.get()); | |
| 820 } | |
| 821 | |
| 822 // Fails requests with ERR_IO_PENDING. Can be used to simulate a navigation | |
| 823 // that never stops loading. | |
| 824 class PendingJobInterceptor : public net::URLRequestInterceptor { | |
| 825 public: | |
| 826 PendingJobInterceptor() {} | |
| 827 ~PendingJobInterceptor() override {} | |
| 828 | |
| 829 // URLRequestInterceptor implementation | |
| 830 net::URLRequestJob* MaybeInterceptRequest( | |
| 831 net::URLRequest* request, | |
| 832 net::NetworkDelegate* network_delegate) const override { | |
| 833 return new net::URLRequestFailedJob(request, network_delegate, | |
| 834 net::ERR_IO_PENDING); | |
| 835 } | |
| 836 | |
| 837 private: | |
| 838 DISALLOW_COPY_AND_ASSIGN(PendingJobInterceptor); | |
| 839 }; | |
| 840 | |
| 841 void InstallLoadingInterceptor(const std::string& host) { | |
| 842 net::URLRequestFilter* filter = net::URLRequestFilter::GetInstance(); | |
| 843 filter->AddHostnameInterceptor( | |
| 844 "http", host, | |
| 845 std::unique_ptr<net::URLRequestInterceptor>(new PendingJobInterceptor())); | |
| 846 } | |
| 847 | |
| 848 class SecurityStateModelLoadingTest | |
| 849 : public ChromeSecurityStateModelClientTest { | |
| 850 public: | |
| 851 SecurityStateModelLoadingTest() : ChromeSecurityStateModelClientTest() {} | |
| 852 ~SecurityStateModelLoadingTest() override{}; | |
| 853 | |
| 854 protected: | |
| 855 void SetUpOnMainThread() override { | |
| 856 ASSERT_TRUE(embedded_test_server()->Start()); | |
| 857 | |
| 858 content::BrowserThread::PostTask( | |
| 859 content::BrowserThread::IO, FROM_HERE, | |
| 860 base::Bind(&InstallLoadingInterceptor, | |
| 861 embedded_test_server()->GetURL("/title1.html").host())); | |
| 862 } | |
| 863 | |
| 864 DISALLOW_COPY_AND_ASSIGN(SecurityStateModelLoadingTest); | |
| 865 }; | |
| 866 | |
| 867 // Tests that navigation state changes cause the security state to be | |
| 868 // updated. | |
| 869 IN_PROC_BROWSER_TEST_F(SecurityStateModelLoadingTest, NavigationStateChanges) { | |
| 870 ASSERT_TRUE(https_server_.Start()); | |
| 871 SetUpMockCertVerifierForHttpsServer(0, net::OK); | |
| 872 | |
| 873 // Navigate to an HTTPS page. | |
| 874 ui_test_utils::NavigateToURL(browser(), | |
| 875 https_server_.GetURL("/ssl/google.html")); | |
| 876 CheckSecurityInfoForSecure( | |
| 877 browser()->tab_strip_model()->GetActiveWebContents(), | |
| 878 SecurityStateModel::SECURE, SecurityStateModel::NO_DEPRECATED_SHA1, | |
| 879 SecurityStateModel::CONTENT_STATUS_NONE, false, | |
| 880 false /* expect cert status error */); | |
| 881 | |
| 882 // Navigate to a page that doesn't finish loading. Test that the | |
| 883 // security state is neutral while the page is loading. | |
| 884 browser()->OpenURL(content::OpenURLParams( | |
| 885 embedded_test_server()->GetURL("/title1.html"), content::Referrer(), | |
| 886 WindowOpenDisposition::CURRENT_TAB, ui::PAGE_TRANSITION_TYPED, false)); | |
| 887 CheckSecurityInfoForNonSecure( | |
| 888 browser()->tab_strip_model()->GetActiveWebContents()); | |
| 889 } | |
| 890 | |
| 891 // Tests that the NavigationEntry's flags for nonsecure password/credit | |
| 892 // card inputs are reflected in the VisibleSecurityState. | |
| 893 IN_PROC_BROWSER_TEST_F(ChromeSecurityStateModelClientTest, | |
| 894 VisibleSecurityStateNonsecureFormInputs) { | |
| 895 ASSERT_TRUE(https_server_.Start()); | |
| 896 ui_test_utils::NavigateToURL(browser(), | |
| 897 https_server_.GetURL("/ssl/google.html")); | |
| 898 | |
| 899 content::WebContents* contents = | |
| 900 browser()->tab_strip_model()->GetActiveWebContents(); | |
| 901 ASSERT_TRUE(contents); | |
| 902 | |
| 903 ChromeSecurityStateModelClient* model_client = | |
| 904 ChromeSecurityStateModelClient::FromWebContents(contents); | |
| 905 ASSERT_TRUE(model_client); | |
| 906 | |
| 907 // First, test that if the flags aren't set on the NavigationEntry, | |
| 908 // then they also aren't set on the VisibleSecurityState. | |
| 909 content::SSLStatus& ssl_status = | |
| 910 contents->GetController().GetVisibleEntry()->GetSSL(); | |
| 911 ASSERT_FALSE(ssl_status.content_status & | |
| 912 content::SSLStatus::DISPLAYED_PASSWORD_FIELD_ON_HTTP); | |
| 913 ASSERT_FALSE(ssl_status.content_status & | |
| 914 content::SSLStatus::DISPLAYED_CREDIT_CARD_FIELD_ON_HTTP); | |
| 915 SecurityStateModel::VisibleSecurityState | |
| 916 visible_security_state_no_sensitive_inputs; | |
| 917 model_client->GetVisibleSecurityState( | |
| 918 &visible_security_state_no_sensitive_inputs); | |
| 919 EXPECT_FALSE(visible_security_state_no_sensitive_inputs | |
| 920 .displayed_password_field_on_http); | |
| 921 EXPECT_FALSE(visible_security_state_no_sensitive_inputs | |
| 922 .displayed_credit_card_field_on_http); | |
| 923 | |
| 924 // Now, set the flags on the NavigationEntry and test that they are | |
| 925 // reflected in the VisibleSecurityState. | |
| 926 ssl_status.content_status |= | |
| 927 content::SSLStatus::DISPLAYED_PASSWORD_FIELD_ON_HTTP; | |
| 928 ssl_status.content_status |= | |
| 929 content::SSLStatus::DISPLAYED_CREDIT_CARD_FIELD_ON_HTTP; | |
| 930 SecurityStateModel::VisibleSecurityState | |
| 931 visible_security_state_sensitive_inputs; | |
| 932 model_client->GetVisibleSecurityState( | |
| 933 &visible_security_state_sensitive_inputs); | |
| 934 EXPECT_TRUE( | |
| 935 visible_security_state_sensitive_inputs.displayed_password_field_on_http); | |
| 936 EXPECT_TRUE(visible_security_state_sensitive_inputs | |
| 937 .displayed_credit_card_field_on_http); | |
| 938 } | |
| 939 | |
| 940 // Tests that when a visible password field is detected on an HTTP page | |
| 941 // load, and when the command-line flag is set, the security level is | |
| 942 // downgraded to HTTP_SHOW_WARNING. | |
| 943 IN_PROC_BROWSER_TEST_F(ChromeSecurityStateModelClientTestWithPasswordCcSwitch, | |
| 944 PasswordSecurityLevelDowngraded) { | |
| 945 content::WebContents* contents = | |
| 946 browser()->tab_strip_model()->GetActiveWebContents(); | |
| 947 ASSERT_TRUE(contents); | |
| 948 | |
| 949 ChromeSecurityStateModelClient* model_client = | |
| 950 ChromeSecurityStateModelClient::FromWebContents(contents); | |
| 951 ASSERT_TRUE(model_client); | |
| 952 | |
| 953 ui_test_utils::NavigateToURL( | |
| 954 browser(), GetURLWithNonLocalHostname(embedded_test_server(), | |
| 955 "/password/simple_password.html")); | |
| 956 security_state::SecurityStateModel::SecurityInfo security_info; | |
| 957 model_client->GetSecurityInfo(&security_info); | |
| 958 EXPECT_EQ(security_state::SecurityStateModel::HTTP_SHOW_WARNING, | |
| 959 security_info.security_level); | |
| 960 | |
| 961 content::NavigationEntry* entry = contents->GetController().GetVisibleEntry(); | |
| 962 ASSERT_TRUE(entry); | |
| 963 EXPECT_TRUE(entry->GetSSL().content_status & | |
| 964 content::SSLStatus::DISPLAYED_PASSWORD_FIELD_ON_HTTP); | |
| 965 } | |
| 966 | |
| 967 // Tests that when an invisible password field is present on an HTTP page | |
| 968 // load, and when the command-line flag is set, the security level is | |
| 969 // *not* downgraded to HTTP_SHOW_WARNING. | |
| 970 IN_PROC_BROWSER_TEST_F(ChromeSecurityStateModelClientTestWithPasswordCcSwitch, | |
| 971 PasswordSecurityLevelNotDowngradedForInvisibleInput) { | |
| 972 content::WebContents* contents = | |
| 973 browser()->tab_strip_model()->GetActiveWebContents(); | |
| 974 ASSERT_TRUE(contents); | |
| 975 | |
| 976 ChromeSecurityStateModelClient* model_client = | |
| 977 ChromeSecurityStateModelClient::FromWebContents(contents); | |
| 978 ASSERT_TRUE(model_client); | |
| 979 | |
| 980 ui_test_utils::NavigateToURL( | |
| 981 browser(), | |
| 982 GetURLWithNonLocalHostname(embedded_test_server(), | |
| 983 "/password/invisible_password.html")); | |
| 984 security_state::SecurityStateModel::SecurityInfo security_info; | |
| 985 model_client->GetSecurityInfo(&security_info); | |
| 986 EXPECT_EQ(security_state::SecurityStateModel::NONE, | |
| 987 security_info.security_level); | |
| 988 | |
| 989 content::NavigationEntry* entry = contents->GetController().GetVisibleEntry(); | |
| 990 ASSERT_TRUE(entry); | |
| 991 EXPECT_FALSE(entry->GetSSL().content_status & | |
| 992 content::SSLStatus::DISPLAYED_PASSWORD_FIELD_ON_HTTP); | |
| 993 } | |
| 994 | |
| 995 // Tests that when a visible password field is detected inside an iframe | |
| 996 // on an HTTP page load, and when the command-line flag is set, the | |
| 997 // security level is downgraded to HTTP_SHOW_WARNING. | |
| 998 IN_PROC_BROWSER_TEST_F(ChromeSecurityStateModelClientTestWithPasswordCcSwitch, | |
| 999 PasswordSecurityLevelDowngradedFromIframe) { | |
| 1000 content::WebContents* contents = | |
| 1001 browser()->tab_strip_model()->GetActiveWebContents(); | |
| 1002 ASSERT_TRUE(contents); | |
| 1003 | |
| 1004 ChromeSecurityStateModelClient* model_client = | |
| 1005 ChromeSecurityStateModelClient::FromWebContents(contents); | |
| 1006 ASSERT_TRUE(model_client); | |
| 1007 | |
| 1008 ui_test_utils::NavigateToURL( | |
| 1009 browser(), | |
| 1010 GetURLWithNonLocalHostname(embedded_test_server(), | |
| 1011 "/password/simple_password_in_iframe.html")); | |
| 1012 security_state::SecurityStateModel::SecurityInfo security_info; | |
| 1013 model_client->GetSecurityInfo(&security_info); | |
| 1014 EXPECT_EQ(security_state::SecurityStateModel::HTTP_SHOW_WARNING, | |
| 1015 security_info.security_level); | |
| 1016 | |
| 1017 content::NavigationEntry* entry = contents->GetController().GetVisibleEntry(); | |
| 1018 ASSERT_TRUE(entry); | |
| 1019 EXPECT_TRUE(entry->GetSSL().content_status & | |
| 1020 content::SSLStatus::DISPLAYED_PASSWORD_FIELD_ON_HTTP); | |
| 1021 } | |
| 1022 | |
| 1023 // Tests that when a visible password field is detected inside an iframe | |
| 1024 // on an HTTP page load, and when the command-line flag is set, the | |
| 1025 // security level is downgraded to HTTP_SHOW_WARNING, even if the iframe | |
| 1026 // itself was loaded over HTTPS. | |
| 1027 IN_PROC_BROWSER_TEST_F(ChromeSecurityStateModelClientTestWithPasswordCcSwitch, | |
| 1028 PasswordSecurityLevelDowngradedFromHttpsIframe) { | |
| 1029 content::WebContents* contents = | |
| 1030 browser()->tab_strip_model()->GetActiveWebContents(); | |
| 1031 ASSERT_TRUE(contents); | |
| 1032 | |
| 1033 ChromeSecurityStateModelClient* model_client = | |
| 1034 ChromeSecurityStateModelClient::FromWebContents(contents); | |
| 1035 ASSERT_TRUE(model_client); | |
| 1036 | |
| 1037 // Navigate to an HTTP URL, which loads an iframe using the host and port of | |
| 1038 // |https_server_|. | |
| 1039 std::string replacement_path; | |
| 1040 GetFilePathWithHostAndPortReplacement( | |
| 1041 "/password/simple_password_in_https_iframe.html", | |
| 1042 https_server_.host_port_pair(), &replacement_path); | |
| 1043 ui_test_utils::NavigateToURL( | |
| 1044 browser(), | |
| 1045 GetURLWithNonLocalHostname(embedded_test_server(), replacement_path)); | |
| 1046 security_state::SecurityStateModel::SecurityInfo security_info; | |
| 1047 model_client->GetSecurityInfo(&security_info); | |
| 1048 EXPECT_EQ(security_state::SecurityStateModel::HTTP_SHOW_WARNING, | |
| 1049 security_info.security_level); | |
| 1050 | |
| 1051 content::NavigationEntry* entry = contents->GetController().GetVisibleEntry(); | |
| 1052 ASSERT_TRUE(entry); | |
| 1053 EXPECT_TRUE(entry->GetSSL().content_status & | |
| 1054 content::SSLStatus::DISPLAYED_PASSWORD_FIELD_ON_HTTP); | |
| 1055 } | |
| 1056 | |
| 1057 // Tests that when a visible password field is detected on an HTTP page | |
| 1058 // load, and when the command-line flag is *not* set, the security level is | |
| 1059 // *not* downgraded to HTTP_SHOW_WARNING. | |
| 1060 IN_PROC_BROWSER_TEST_F(ChromeSecurityStateModelClientTest, | |
| 1061 PasswordSecurityLevelNotDowngradedWithoutSwitch) { | |
| 1062 ASSERT_TRUE(embedded_test_server()->Start()); | |
| 1063 host_resolver()->AddRule("*", embedded_test_server()->GetURL("/").host()); | |
| 1064 | |
| 1065 content::WebContents* contents = | |
| 1066 browser()->tab_strip_model()->GetActiveWebContents(); | |
| 1067 ASSERT_TRUE(contents); | |
| 1068 | |
| 1069 ChromeSecurityStateModelClient* model_client = | |
| 1070 ChromeSecurityStateModelClient::FromWebContents(contents); | |
| 1071 ASSERT_TRUE(model_client); | |
| 1072 | |
| 1073 ui_test_utils::NavigateToURL( | |
| 1074 browser(), GetURLWithNonLocalHostname(embedded_test_server(), | |
| 1075 "/password/simple_password.html")); | |
| 1076 // The security level should not be HTTP_SHOW_WARNING, because the | |
| 1077 // command-line switch was not set. | |
| 1078 security_state::SecurityStateModel::SecurityInfo security_info; | |
| 1079 model_client->GetSecurityInfo(&security_info); | |
| 1080 EXPECT_EQ(security_state::SecurityStateModel::NONE, | |
| 1081 security_info.security_level); | |
| 1082 | |
| 1083 // The appropriate SSLStatus flags should be set, however. | |
| 1084 content::NavigationEntry* entry = contents->GetController().GetVisibleEntry(); | |
| 1085 ASSERT_TRUE(entry); | |
| 1086 EXPECT_TRUE(entry->GetSSL().content_status & | |
| 1087 content::SSLStatus::DISPLAYED_PASSWORD_FIELD_ON_HTTP); | |
| 1088 } | |
| 1089 | |
| 1090 // Tests that when a visible password field is detected on an HTTPS page | |
| 1091 // load, and when the command-line flag is set, the security level is | |
| 1092 // *not* downgraded to HTTP_SHOW_WARNING. | |
| 1093 IN_PROC_BROWSER_TEST_F(ChromeSecurityStateModelClientTestWithPasswordCcSwitch, | |
| 1094 PasswordSecurityLevelNotDowngradedOnHttps) { | |
| 1095 content::WebContents* contents = | |
| 1096 browser()->tab_strip_model()->GetActiveWebContents(); | |
| 1097 ASSERT_TRUE(contents); | |
| 1098 | |
| 1099 ChromeSecurityStateModelClient* model_client = | |
| 1100 ChromeSecurityStateModelClient::FromWebContents(contents); | |
| 1101 ASSERT_TRUE(model_client); | |
| 1102 | |
| 1103 GURL url = GetURLWithNonLocalHostname(&https_server_, | |
| 1104 "/password/simple_password.html"); | |
| 1105 ui_test_utils::NavigateToURL(browser(), url); | |
| 1106 // The security level should not be HTTP_SHOW_WARNING, because the page was | |
| 1107 // HTTPS instead of HTTP. | |
| 1108 security_state::SecurityStateModel::SecurityInfo security_info; | |
| 1109 model_client->GetSecurityInfo(&security_info); | |
| 1110 EXPECT_EQ(security_state::SecurityStateModel::SECURE, | |
| 1111 security_info.security_level); | |
| 1112 | |
| 1113 // The SSLStatus flags should only be set if the top-level page load was HTTP, | |
| 1114 // which it was not in this case. | |
| 1115 content::NavigationEntry* entry = contents->GetController().GetVisibleEntry(); | |
| 1116 ASSERT_TRUE(entry); | |
| 1117 EXPECT_FALSE(entry->GetSSL().content_status & | |
| 1118 content::SSLStatus::DISPLAYED_PASSWORD_FIELD_ON_HTTP); | |
| 1119 } | |
| 1120 | |
| 1121 // A Browser subclass that keeps track of messages that have been | |
| 1122 // added to the console. Messages can be retrieved or cleared with | |
| 1123 // console_messages() and ClearConsoleMessages(). The user of this class | |
| 1124 // can set a callback to run when the next console message notification | |
| 1125 // arrives. | |
| 1126 class ConsoleWebContentsDelegate : public Browser { | |
| 1127 public: | |
| 1128 explicit ConsoleWebContentsDelegate(const Browser::CreateParams& params) | |
| 1129 : Browser(params) {} | |
| 1130 ~ConsoleWebContentsDelegate() override {} | |
| 1131 | |
| 1132 const std::vector<base::string16>& console_messages() const { | |
| 1133 return console_messages_; | |
| 1134 } | |
| 1135 | |
| 1136 void set_console_message_callback(const base::Closure& callback) { | |
| 1137 console_message_callback_ = callback; | |
| 1138 } | |
| 1139 | |
| 1140 void ClearConsoleMessages() { console_messages_.clear(); } | |
| 1141 | |
| 1142 // content::WebContentsDelegate | |
| 1143 bool AddMessageToConsole(content::WebContents* source, | |
| 1144 int32_t level, | |
| 1145 const base::string16& message, | |
| 1146 int32_t line_no, | |
| 1147 const base::string16& source_id) override { | |
| 1148 console_messages_.push_back(message); | |
| 1149 if (!console_message_callback_.is_null()) { | |
| 1150 console_message_callback_.Run(); | |
| 1151 console_message_callback_.Reset(); | |
| 1152 } | |
| 1153 return true; | |
| 1154 } | |
| 1155 | |
| 1156 private: | |
| 1157 std::vector<base::string16> console_messages_; | |
| 1158 base::Closure console_message_callback_; | |
| 1159 | |
| 1160 DISALLOW_COPY_AND_ASSIGN(ConsoleWebContentsDelegate); | |
| 1161 }; | |
| 1162 | |
| 1163 // Checks that |delegate| has observed exactly one console message for | |
| 1164 // HTTP_SHOW_WARNING. To avoid brittleness, this just looks for keywords | |
| 1165 // in the string rather than the exact text. | |
| 1166 void CheckForOneHttpWarningConsoleMessage( | |
| 1167 ConsoleWebContentsDelegate* delegate) { | |
| 1168 const std::vector<base::string16>& messages = delegate->console_messages(); | |
| 1169 ASSERT_EQ(1u, messages.size()); | |
| 1170 EXPECT_NE(base::string16::npos, | |
| 1171 messages[0].find(base::ASCIIToUTF16("warning has been added"))); | |
| 1172 } | |
| 1173 | |
| 1174 // Checks that |delegate| has observed exactly one console message for | |
| 1175 // NONE that will be HTTP_SHOW_WARNING in future. To avoid brittleness, | |
| 1176 // this just looks for keywords in the string rather than the exact | |
| 1177 // text. | |
| 1178 void CheckForOneFutureHttpWarningConsoleMessage( | |
| 1179 ConsoleWebContentsDelegate* delegate) { | |
| 1180 const std::vector<base::string16>& messages = delegate->console_messages(); | |
| 1181 ASSERT_EQ(1u, messages.size()); | |
| 1182 EXPECT_NE(base::string16::npos, | |
| 1183 messages[0].find(base::ASCIIToUTF16("warning will be added"))); | |
| 1184 } | |
| 1185 | |
| 1186 // Tests that console messages are printed upon a call to | |
| 1187 // GetSecurityInfo() on an HTTP_SHOW_WARNING page, exactly once per | |
| 1188 // main-frame navigation. | |
| 1189 IN_PROC_BROWSER_TEST_F(ChromeSecurityStateModelClientTestWithPasswordCcSwitch, | |
| 1190 ConsoleMessage) { | |
| 1191 ConsoleWebContentsDelegate* delegate = new ConsoleWebContentsDelegate( | |
| 1192 Browser::CreateParams(browser()->profile())); | |
| 1193 content::WebContents* original_contents = | |
| 1194 browser()->tab_strip_model()->GetActiveWebContents(); | |
| 1195 content::WebContents* contents = | |
| 1196 content::WebContents::Create(content::WebContents::CreateParams( | |
| 1197 original_contents->GetBrowserContext())); | |
| 1198 ASSERT_TRUE(contents); | |
| 1199 contents->SetDelegate(delegate); | |
| 1200 delegate->tab_strip_model()->AppendWebContents(contents, true); | |
| 1201 int index = delegate->tab_strip_model()->GetIndexOfWebContents(contents); | |
| 1202 delegate->tab_strip_model()->ActivateTabAt(index, true); | |
| 1203 ASSERT_EQ(contents, delegate->tab_strip_model()->GetActiveWebContents()); | |
| 1204 | |
| 1205 // Navigate to an HTTP page. Use a non-local hostname so that is it | |
| 1206 // not considered secure. | |
| 1207 GURL http_url = | |
| 1208 GetURLWithNonLocalHostname(embedded_test_server(), "/title1.html"); | |
| 1209 ui_test_utils::NavigateToURL(delegate, http_url); | |
| 1210 content::NavigationEntry* entry = contents->GetController().GetVisibleEntry(); | |
| 1211 ASSERT_TRUE(entry); | |
| 1212 EXPECT_EQ(http_url, entry->GetURL()); | |
| 1213 EXPECT_TRUE(delegate->console_messages().empty()); | |
| 1214 | |
| 1215 // Trigger the HTTP_SHOW_WARNING state. | |
| 1216 base::RunLoop first_message; | |
| 1217 delegate->set_console_message_callback(first_message.QuitClosure()); | |
| 1218 contents->OnPasswordInputShownOnHttp(); | |
| 1219 first_message.Run(); | |
| 1220 | |
| 1221 // Check that the HTTP_SHOW_WARNING state was actually triggered. | |
| 1222 ChromeSecurityStateModelClient* client = | |
| 1223 ChromeSecurityStateModelClient::FromWebContents(contents); | |
| 1224 ASSERT_TRUE(client); | |
| 1225 security_state::SecurityStateModel::SecurityInfo security_info; | |
| 1226 client->GetSecurityInfo(&security_info); | |
| 1227 EXPECT_EQ(security_state::SecurityStateModel::HTTP_SHOW_WARNING, | |
| 1228 security_info.security_level); | |
| 1229 | |
| 1230 // Check that the expected console message is present. | |
| 1231 ASSERT_NO_FATAL_FAILURE(CheckForOneHttpWarningConsoleMessage(delegate)); | |
| 1232 delegate->ClearConsoleMessages(); | |
| 1233 | |
| 1234 // Two subsequent triggers of VisibleSecurityStateChanged -- one on the | |
| 1235 // same navigation and one on another navigation -- should only result | |
| 1236 // in one additional console message. | |
| 1237 contents->OnCreditCardInputShownOnHttp(); | |
| 1238 GURL second_http_url = | |
| 1239 GetURLWithNonLocalHostname(embedded_test_server(), "/title2.html"); | |
| 1240 ui_test_utils::NavigateToURL(delegate, second_http_url); | |
| 1241 entry = contents->GetController().GetVisibleEntry(); | |
| 1242 ASSERT_TRUE(entry); | |
| 1243 EXPECT_EQ(second_http_url, entry->GetURL()); | |
| 1244 | |
| 1245 base::RunLoop second_message; | |
| 1246 delegate->set_console_message_callback(second_message.QuitClosure()); | |
| 1247 contents->OnPasswordInputShownOnHttp(); | |
| 1248 second_message.Run(); | |
| 1249 | |
| 1250 client->GetSecurityInfo(&security_info); | |
| 1251 EXPECT_EQ(security_state::SecurityStateModel::HTTP_SHOW_WARNING, | |
| 1252 security_info.security_level); | |
| 1253 | |
| 1254 ASSERT_NO_FATAL_FAILURE(CheckForOneHttpWarningConsoleMessage(delegate)); | |
| 1255 } | |
| 1256 | |
| 1257 // Tests that console messages are printed upon a call to | |
| 1258 // GetSecurityInfo() on a NONE page that will be marked | |
| 1259 // HTTP_SHOW_WARNING in future, exactly once per main-frame navigation. | |
| 1260 IN_PROC_BROWSER_TEST_F(ChromeSecurityStateModelClientTest, ConsoleMessage) { | |
| 1261 ASSERT_TRUE(embedded_test_server()->Start()); | |
| 1262 host_resolver()->AddRule("*", embedded_test_server()->GetURL("/").host()); | |
| 1263 ConsoleWebContentsDelegate* delegate = new ConsoleWebContentsDelegate( | |
| 1264 Browser::CreateParams(browser()->profile())); | |
| 1265 content::WebContents* original_contents = | |
| 1266 browser()->tab_strip_model()->GetActiveWebContents(); | |
| 1267 content::WebContents* contents = | |
| 1268 content::WebContents::Create(content::WebContents::CreateParams( | |
| 1269 original_contents->GetBrowserContext())); | |
| 1270 ASSERT_TRUE(contents); | |
| 1271 contents->SetDelegate(delegate); | |
| 1272 delegate->tab_strip_model()->AppendWebContents(contents, true); | |
| 1273 int index = delegate->tab_strip_model()->GetIndexOfWebContents(contents); | |
| 1274 delegate->tab_strip_model()->ActivateTabAt(index, true); | |
| 1275 ASSERT_EQ(contents, delegate->tab_strip_model()->GetActiveWebContents()); | |
| 1276 | |
| 1277 // Navigate to an HTTP page. Use a non-local hostname so that is it | |
| 1278 // not considered secure. | |
| 1279 GURL http_url = | |
| 1280 GetURLWithNonLocalHostname(embedded_test_server(), "/title1.html"); | |
| 1281 ui_test_utils::NavigateToURL(delegate, http_url); | |
| 1282 content::NavigationEntry* entry = contents->GetController().GetVisibleEntry(); | |
| 1283 ASSERT_TRUE(entry); | |
| 1284 EXPECT_EQ(http_url, entry->GetURL()); | |
| 1285 EXPECT_TRUE(delegate->console_messages().empty()); | |
| 1286 | |
| 1287 // Trigger the a state that will be marked as HTTP_SHOW_WARNING in future. | |
| 1288 base::RunLoop first_message; | |
| 1289 delegate->set_console_message_callback(first_message.QuitClosure()); | |
| 1290 contents->OnPasswordInputShownOnHttp(); | |
| 1291 first_message.Run(); | |
| 1292 | |
| 1293 // Check that the correct state was actually triggered. | |
| 1294 ChromeSecurityStateModelClient* client = | |
| 1295 ChromeSecurityStateModelClient::FromWebContents(contents); | |
| 1296 ASSERT_TRUE(client); | |
| 1297 security_state::SecurityStateModel::SecurityInfo security_info; | |
| 1298 client->GetSecurityInfo(&security_info); | |
| 1299 EXPECT_EQ(security_state::SecurityStateModel::NONE, | |
| 1300 security_info.security_level); | |
| 1301 EXPECT_TRUE(security_info.displayed_private_user_data_input_on_http); | |
| 1302 | |
| 1303 // Check that the expected console message is present. | |
| 1304 ASSERT_NO_FATAL_FAILURE(CheckForOneFutureHttpWarningConsoleMessage(delegate)); | |
| 1305 delegate->ClearConsoleMessages(); | |
| 1306 | |
| 1307 // Two subsequent triggers of VisibleSecurityStateChanged -- one on the | |
| 1308 // same navigation and one on another navigation -- should only result | |
| 1309 // in one additional console message. | |
| 1310 contents->OnCreditCardInputShownOnHttp(); | |
| 1311 GURL second_http_url = | |
| 1312 GetURLWithNonLocalHostname(embedded_test_server(), "/title2.html"); | |
| 1313 ui_test_utils::NavigateToURL(delegate, second_http_url); | |
| 1314 entry = contents->GetController().GetVisibleEntry(); | |
| 1315 ASSERT_TRUE(entry); | |
| 1316 EXPECT_EQ(second_http_url, entry->GetURL()); | |
| 1317 | |
| 1318 base::RunLoop second_message; | |
| 1319 delegate->set_console_message_callback(second_message.QuitClosure()); | |
| 1320 contents->OnPasswordInputShownOnHttp(); | |
| 1321 second_message.Run(); | |
| 1322 | |
| 1323 client->GetSecurityInfo(&security_info); | |
| 1324 EXPECT_EQ(security_state::SecurityStateModel::NONE, | |
| 1325 security_info.security_level); | |
| 1326 EXPECT_TRUE(security_info.displayed_private_user_data_input_on_http); | |
| 1327 | |
| 1328 ASSERT_NO_FATAL_FAILURE(CheckForOneFutureHttpWarningConsoleMessage(delegate)); | |
| 1329 } | |
| 1330 | |
| 1331 // Tests that additional HTTP_SHOW_WARNING console messages are not | |
| 1332 // printed after subframe navigations. | |
| 1333 IN_PROC_BROWSER_TEST_F(ChromeSecurityStateModelClientTestWithPasswordCcSwitch, | |
| 1334 ConsoleMessageNotPrintedForFrameNavigation) { | |
| 1335 ConsoleWebContentsDelegate* delegate = new ConsoleWebContentsDelegate( | |
| 1336 Browser::CreateParams(browser()->profile())); | |
| 1337 content::WebContents* original_contents = | |
| 1338 browser()->tab_strip_model()->GetActiveWebContents(); | |
| 1339 content::WebContents* contents = | |
| 1340 content::WebContents::Create(content::WebContents::CreateParams( | |
| 1341 original_contents->GetBrowserContext())); | |
| 1342 ASSERT_TRUE(contents); | |
| 1343 contents->SetDelegate(delegate); | |
| 1344 delegate->tab_strip_model()->AppendWebContents(contents, true); | |
| 1345 int index = delegate->tab_strip_model()->GetIndexOfWebContents(contents); | |
| 1346 delegate->tab_strip_model()->ActivateTabAt(index, true); | |
| 1347 ASSERT_EQ(contents, delegate->tab_strip_model()->GetActiveWebContents()); | |
| 1348 | |
| 1349 // Navigate to an HTTP page. Use a non-local hostname so that is it | |
| 1350 // not considered secure. | |
| 1351 GURL http_url = GetURLWithNonLocalHostname(embedded_test_server(), | |
| 1352 "/ssl/page_with_frame.html"); | |
| 1353 ui_test_utils::NavigateToURL(delegate, http_url); | |
| 1354 content::NavigationEntry* entry = contents->GetController().GetVisibleEntry(); | |
| 1355 ASSERT_TRUE(entry); | |
| 1356 EXPECT_EQ(http_url, entry->GetURL()); | |
| 1357 EXPECT_TRUE(delegate->console_messages().empty()); | |
| 1358 | |
| 1359 // Trigger the HTTP_SHOW_WARNING state. | |
| 1360 base::RunLoop first_message; | |
| 1361 delegate->set_console_message_callback(first_message.QuitClosure()); | |
| 1362 contents->OnPasswordInputShownOnHttp(); | |
| 1363 first_message.Run(); | |
| 1364 | |
| 1365 // Check that the HTTP_SHOW_WARNING state was actually triggered. | |
| 1366 ChromeSecurityStateModelClient* client = | |
| 1367 ChromeSecurityStateModelClient::FromWebContents(contents); | |
| 1368 ASSERT_TRUE(client); | |
| 1369 security_state::SecurityStateModel::SecurityInfo security_info; | |
| 1370 client->GetSecurityInfo(&security_info); | |
| 1371 EXPECT_EQ(security_state::SecurityStateModel::HTTP_SHOW_WARNING, | |
| 1372 security_info.security_level); | |
| 1373 | |
| 1374 // Check that the expected console message is present. | |
| 1375 ASSERT_NO_FATAL_FAILURE(CheckForOneHttpWarningConsoleMessage(delegate)); | |
| 1376 delegate->ClearConsoleMessages(); | |
| 1377 | |
| 1378 // Navigate the subframe and trigger VisibleSecurityStateChanged | |
| 1379 // again. While the security level is still HTTP_SHOW_WARNING, an | |
| 1380 // additional console message should not be logged because there was | |
| 1381 // already a console message logged for the current main-frame | |
| 1382 // navigation. | |
| 1383 content::WindowedNotificationObserver subframe_observer( | |
| 1384 content::NOTIFICATION_LOAD_STOP, | |
| 1385 content::Source<content::NavigationController>( | |
| 1386 &contents->GetController())); | |
| 1387 EXPECT_TRUE(content::ExecuteScript( | |
| 1388 contents, "document.getElementById('navFrame').src = '/title2.html';")); | |
| 1389 subframe_observer.Wait(); | |
| 1390 contents->OnCreditCardInputShownOnHttp(); | |
| 1391 EXPECT_EQ(security_state::SecurityStateModel::HTTP_SHOW_WARNING, | |
| 1392 security_info.security_level); | |
| 1393 | |
| 1394 // Do a main frame navigation and then trigger HTTP_SHOW_WARNING | |
| 1395 // again. From the above subframe navigation and this main-frame | |
| 1396 // navigation, exactly one console message is expected. | |
| 1397 GURL second_http_url = | |
| 1398 GetURLWithNonLocalHostname(embedded_test_server(), "/title2.html"); | |
| 1399 ui_test_utils::NavigateToURL(delegate, second_http_url); | |
| 1400 entry = contents->GetController().GetVisibleEntry(); | |
| 1401 ASSERT_TRUE(entry); | |
| 1402 EXPECT_EQ(second_http_url, entry->GetURL()); | |
| 1403 | |
| 1404 base::RunLoop second_message; | |
| 1405 delegate->set_console_message_callback(second_message.QuitClosure()); | |
| 1406 contents->OnPasswordInputShownOnHttp(); | |
| 1407 second_message.Run(); | |
| 1408 | |
| 1409 client->GetSecurityInfo(&security_info); | |
| 1410 EXPECT_EQ(security_state::SecurityStateModel::HTTP_SHOW_WARNING, | |
| 1411 security_info.security_level); | |
| 1412 ASSERT_NO_FATAL_FAILURE(CheckForOneHttpWarningConsoleMessage(delegate)); | |
| 1413 } | |
| 1414 | |
| 1415 // Tests that additional HTTP_SHOW_WARNING console messages are not | |
| 1416 // printed after pushState navigations. | |
| 1417 IN_PROC_BROWSER_TEST_F(ChromeSecurityStateModelClientTestWithPasswordCcSwitch, | |
| 1418 ConsoleMessageNotPrintedForPushStateNavigation) { | |
| 1419 ConsoleWebContentsDelegate* delegate = new ConsoleWebContentsDelegate( | |
| 1420 Browser::CreateParams(browser()->profile())); | |
| 1421 content::WebContents* original_contents = | |
| 1422 browser()->tab_strip_model()->GetActiveWebContents(); | |
| 1423 content::WebContents* contents = | |
| 1424 content::WebContents::Create(content::WebContents::CreateParams( | |
| 1425 original_contents->GetBrowserContext())); | |
| 1426 ASSERT_TRUE(contents); | |
| 1427 contents->SetDelegate(delegate); | |
| 1428 delegate->tab_strip_model()->AppendWebContents(contents, true); | |
| 1429 int index = delegate->tab_strip_model()->GetIndexOfWebContents(contents); | |
| 1430 delegate->tab_strip_model()->ActivateTabAt(index, true); | |
| 1431 ASSERT_EQ(contents, delegate->tab_strip_model()->GetActiveWebContents()); | |
| 1432 | |
| 1433 // Navigate to an HTTP page. Use a non-local hostname so that is it | |
| 1434 // not considered secure. | |
| 1435 GURL http_url = | |
| 1436 GetURLWithNonLocalHostname(embedded_test_server(), "/title1.html"); | |
| 1437 ui_test_utils::NavigateToURL(delegate, http_url); | |
| 1438 content::NavigationEntry* entry = contents->GetController().GetVisibleEntry(); | |
| 1439 ASSERT_TRUE(entry); | |
| 1440 EXPECT_EQ(http_url, entry->GetURL()); | |
| 1441 EXPECT_TRUE(delegate->console_messages().empty()); | |
| 1442 | |
| 1443 // Trigger the HTTP_SHOW_WARNING state. | |
| 1444 base::RunLoop first_message; | |
| 1445 delegate->set_console_message_callback(first_message.QuitClosure()); | |
| 1446 contents->OnPasswordInputShownOnHttp(); | |
| 1447 first_message.Run(); | |
| 1448 | |
| 1449 // Check that the HTTP_SHOW_WARNING state was actually triggered. | |
| 1450 ChromeSecurityStateModelClient* client = | |
| 1451 ChromeSecurityStateModelClient::FromWebContents(contents); | |
| 1452 ASSERT_TRUE(client); | |
| 1453 security_state::SecurityStateModel::SecurityInfo security_info; | |
| 1454 client->GetSecurityInfo(&security_info); | |
| 1455 EXPECT_EQ(security_state::SecurityStateModel::HTTP_SHOW_WARNING, | |
| 1456 security_info.security_level); | |
| 1457 | |
| 1458 // Check that the expected console message is present. | |
| 1459 ASSERT_NO_FATAL_FAILURE(CheckForOneHttpWarningConsoleMessage(delegate)); | |
| 1460 delegate->ClearConsoleMessages(); | |
| 1461 | |
| 1462 // Navigate with pushState and trigger VisibleSecurityStateChanged | |
| 1463 // again. While the security level is still HTTP_SHOW_WARNING, an | |
| 1464 // additional console message should not be logged because there was | |
| 1465 // already a console message logged for the current main-frame | |
| 1466 // navigation. | |
| 1467 EXPECT_TRUE(content::ExecuteScript( | |
| 1468 contents, "history.pushState({ foo: 'bar' }, 'foo', 'bar');")); | |
| 1469 contents->OnCreditCardInputShownOnHttp(); | |
| 1470 EXPECT_EQ(security_state::SecurityStateModel::HTTP_SHOW_WARNING, | |
| 1471 security_info.security_level); | |
| 1472 | |
| 1473 // Do a main frame navigation and then trigger HTTP_SHOW_WARNING | |
| 1474 // again. From the above pushState navigation and this main-frame | |
| 1475 // navigation, exactly one console message is expected. | |
| 1476 GURL second_http_url = | |
| 1477 GetURLWithNonLocalHostname(embedded_test_server(), "/title2.html"); | |
| 1478 ui_test_utils::NavigateToURL(delegate, second_http_url); | |
| 1479 entry = contents->GetController().GetVisibleEntry(); | |
| 1480 ASSERT_TRUE(entry); | |
| 1481 EXPECT_EQ(second_http_url, entry->GetURL()); | |
| 1482 | |
| 1483 base::RunLoop second_message; | |
| 1484 delegate->set_console_message_callback(second_message.QuitClosure()); | |
| 1485 contents->OnPasswordInputShownOnHttp(); | |
| 1486 second_message.Run(); | |
| 1487 | |
| 1488 client->GetSecurityInfo(&security_info); | |
| 1489 EXPECT_EQ(security_state::SecurityStateModel::HTTP_SHOW_WARNING, | |
| 1490 security_info.security_level); | |
| 1491 ASSERT_NO_FATAL_FAILURE(CheckForOneHttpWarningConsoleMessage(delegate)); | |
| 1492 } | |
| 1493 | |
| 1494 // Tests that the SecurityStateModel for a WebContents is up to date | |
| 1495 // when the WebContents is inserted into a Browser's TabStripModel. | |
| 1496 IN_PROC_BROWSER_TEST_F(ChromeSecurityStateModelClientTest, AddedTab) { | |
| 1497 ASSERT_TRUE(https_server_.Start()); | |
| 1498 SetUpMockCertVerifierForHttpsServer(0, net::OK); | |
| 1499 | |
| 1500 content::WebContents* tab = | |
| 1501 browser()->tab_strip_model()->GetActiveWebContents(); | |
| 1502 ASSERT_TRUE(tab); | |
| 1503 | |
| 1504 content::WebContents* new_contents = content::WebContents::Create( | |
| 1505 content::WebContents::CreateParams(tab->GetBrowserContext())); | |
| 1506 content::NavigationController& controller = new_contents->GetController(); | |
| 1507 ChromeSecurityStateModelClient::CreateForWebContents(new_contents); | |
| 1508 CheckSecurityInfoForNonSecure(new_contents); | |
| 1509 controller.LoadURL(https_server_.GetURL("/title1.html"), content::Referrer(), | |
| 1510 ui::PAGE_TRANSITION_TYPED, std::string()); | |
| 1511 EXPECT_TRUE(content::WaitForLoadStop(new_contents)); | |
| 1512 CheckSecurityInfoForSecure(new_contents, SecurityStateModel::SECURE, | |
| 1513 SecurityStateModel::NO_DEPRECATED_SHA1, | |
| 1514 SecurityStateModel::CONTENT_STATUS_NONE, false, | |
| 1515 false /* expect cert status error */); | |
| 1516 | |
| 1517 browser()->tab_strip_model()->InsertWebContentsAt(0, new_contents, | |
| 1518 TabStripModel::ADD_NONE); | |
| 1519 CheckSecurityInfoForSecure(new_contents, SecurityStateModel::SECURE, | |
| 1520 SecurityStateModel::NO_DEPRECATED_SHA1, | |
| 1521 SecurityStateModel::CONTENT_STATUS_NONE, false, | |
| 1522 false /* expect cert status error */); | |
| 1523 } | |
| 1524 | |
| 1525 // Tests that the WebContentsObserver::SecurityStyleChanged event fires | |
| 1526 // with the current style on HTTP, broken HTTPS, and valid HTTPS pages. | |
| 1527 IN_PROC_BROWSER_TEST_F(SecurityStyleChangedTest, SecurityStyleChangedObserver) { | |
| 1528 ASSERT_TRUE(https_server_.Start()); | |
| 1529 ASSERT_TRUE(embedded_test_server()->Start()); | |
| 1530 | |
| 1531 net::EmbeddedTestServer https_test_server_expired( | |
| 1532 net::EmbeddedTestServer::TYPE_HTTPS); | |
| 1533 https_test_server_expired.SetSSLConfig(net::EmbeddedTestServer::CERT_EXPIRED); | |
| 1534 https_test_server_expired.ServeFilesFromSourceDirectory( | |
| 1535 base::FilePath(kDocRoot)); | |
| 1536 ASSERT_TRUE(https_test_server_expired.Start()); | |
| 1537 | |
| 1538 content::WebContents* web_contents = | |
| 1539 browser()->tab_strip_model()->GetActiveWebContents(); | |
| 1540 SecurityStyleTestObserver observer(web_contents); | |
| 1541 | |
| 1542 // Visit an HTTP url. | |
| 1543 GURL http_url(embedded_test_server()->GetURL("/title1.html")); | |
| 1544 ui_test_utils::NavigateToURL(browser(), http_url); | |
| 1545 EXPECT_EQ(blink::WebSecurityStyleUnauthenticated, | |
| 1546 observer.latest_security_style()); | |
| 1547 EXPECT_EQ(0u, | |
| 1548 observer.latest_explanations().unauthenticated_explanations.size()); | |
| 1549 EXPECT_EQ(0u, observer.latest_explanations().broken_explanations.size()); | |
| 1550 EXPECT_EQ(0u, observer.latest_explanations().secure_explanations.size()); | |
| 1551 EXPECT_FALSE(observer.latest_explanations().scheme_is_cryptographic); | |
| 1552 EXPECT_FALSE(observer.latest_explanations().pkp_bypassed); | |
| 1553 EXPECT_TRUE(observer.latest_explanations().info_explanations.empty()); | |
| 1554 EXPECT_FALSE(observer.latest_explanations().ran_mixed_content); | |
| 1555 EXPECT_FALSE(observer.latest_explanations().displayed_mixed_content); | |
| 1556 | |
| 1557 // Visit an (otherwise valid) HTTPS page that displays mixed content. | |
| 1558 std::string replacement_path; | |
| 1559 GetFilePathWithHostAndPortReplacement( | |
| 1560 "/ssl/page_displays_insecure_content.html", | |
| 1561 embedded_test_server()->host_port_pair(), &replacement_path); | |
| 1562 | |
| 1563 GURL mixed_content_url(https_server_.GetURL(replacement_path)); | |
| 1564 ui_test_utils::NavigateToURL(browser(), mixed_content_url); | |
| 1565 EXPECT_EQ(blink::WebSecurityStyleUnauthenticated, | |
| 1566 observer.latest_security_style()); | |
| 1567 | |
| 1568 const content::SecurityStyleExplanations& mixed_content_explanation = | |
| 1569 observer.latest_explanations(); | |
| 1570 ASSERT_EQ(0u, mixed_content_explanation.unauthenticated_explanations.size()); | |
| 1571 ASSERT_EQ(0u, mixed_content_explanation.broken_explanations.size()); | |
| 1572 CheckSecureExplanations(mixed_content_explanation.secure_explanations, | |
| 1573 VALID_CERTIFICATE, browser(), | |
| 1574 https_server_.GetCertificate().get()); | |
| 1575 EXPECT_TRUE(mixed_content_explanation.scheme_is_cryptographic); | |
| 1576 EXPECT_FALSE(observer.latest_explanations().pkp_bypassed); | |
| 1577 EXPECT_TRUE(observer.latest_explanations().info_explanations.empty()); | |
| 1578 EXPECT_TRUE(mixed_content_explanation.displayed_mixed_content); | |
| 1579 EXPECT_FALSE(mixed_content_explanation.ran_mixed_content); | |
| 1580 EXPECT_EQ(blink::WebSecurityStyleUnauthenticated, | |
| 1581 mixed_content_explanation.displayed_insecure_content_style); | |
| 1582 EXPECT_EQ(blink::WebSecurityStyleAuthenticationBroken, | |
| 1583 mixed_content_explanation.ran_insecure_content_style); | |
| 1584 | |
| 1585 // Visit a broken HTTPS url. | |
| 1586 GURL expired_url(https_test_server_expired.GetURL("/title1.html")); | |
| 1587 ui_test_utils::NavigateToURL(browser(), expired_url); | |
| 1588 | |
| 1589 // An interstitial should show, and an event for the lock icon on the | |
| 1590 // interstitial should fire. | |
| 1591 content::WaitForInterstitialAttach(web_contents); | |
| 1592 EXPECT_TRUE(web_contents->ShowingInterstitialPage()); | |
| 1593 CheckBrokenSecurityStyle(observer, net::ERR_CERT_DATE_INVALID, browser(), | |
| 1594 https_test_server_expired.GetCertificate().get()); | |
| 1595 CheckSecureExplanations(observer.latest_explanations().secure_explanations, | |
| 1596 INVALID_CERTIFICATE, browser(), | |
| 1597 https_test_server_expired.GetCertificate().get()); | |
| 1598 EXPECT_TRUE(observer.latest_explanations().scheme_is_cryptographic); | |
| 1599 EXPECT_FALSE(observer.latest_explanations().pkp_bypassed); | |
| 1600 EXPECT_TRUE(observer.latest_explanations().info_explanations.empty()); | |
| 1601 EXPECT_FALSE(observer.latest_explanations().displayed_mixed_content); | |
| 1602 EXPECT_FALSE(observer.latest_explanations().ran_mixed_content); | |
| 1603 | |
| 1604 // Before clicking through, navigate to a different page, and then go | |
| 1605 // back to the interstitial. | |
| 1606 GURL valid_https_url(https_server_.GetURL("/title1.html")); | |
| 1607 ui_test_utils::NavigateToURL(browser(), valid_https_url); | |
| 1608 EXPECT_EQ(blink::WebSecurityStyleAuthenticated, | |
| 1609 observer.latest_security_style()); | |
| 1610 EXPECT_EQ(0u, | |
| 1611 observer.latest_explanations().unauthenticated_explanations.size()); | |
| 1612 EXPECT_EQ(0u, observer.latest_explanations().broken_explanations.size()); | |
| 1613 CheckSecureExplanations(observer.latest_explanations().secure_explanations, | |
| 1614 VALID_CERTIFICATE, browser(), | |
| 1615 https_server_.GetCertificate().get()); | |
| 1616 EXPECT_TRUE(observer.latest_explanations().scheme_is_cryptographic); | |
| 1617 EXPECT_FALSE(observer.latest_explanations().pkp_bypassed); | |
| 1618 EXPECT_TRUE(observer.latest_explanations().info_explanations.empty()); | |
| 1619 EXPECT_FALSE(observer.latest_explanations().displayed_mixed_content); | |
| 1620 EXPECT_FALSE(observer.latest_explanations().ran_mixed_content); | |
| 1621 | |
| 1622 // After going back to the interstitial, an event for a broken lock | |
| 1623 // icon should fire again. | |
| 1624 ui_test_utils::NavigateToURL(browser(), expired_url); | |
| 1625 content::WaitForInterstitialAttach(web_contents); | |
| 1626 EXPECT_TRUE(web_contents->ShowingInterstitialPage()); | |
| 1627 CheckBrokenSecurityStyle(observer, net::ERR_CERT_DATE_INVALID, browser(), | |
| 1628 https_test_server_expired.GetCertificate().get()); | |
| 1629 CheckSecureExplanations(observer.latest_explanations().secure_explanations, | |
| 1630 INVALID_CERTIFICATE, browser(), | |
| 1631 https_test_server_expired.GetCertificate().get()); | |
| 1632 EXPECT_TRUE(observer.latest_explanations().scheme_is_cryptographic); | |
| 1633 EXPECT_FALSE(observer.latest_explanations().pkp_bypassed); | |
| 1634 EXPECT_TRUE(observer.latest_explanations().info_explanations.empty()); | |
| 1635 EXPECT_FALSE(observer.latest_explanations().displayed_mixed_content); | |
| 1636 EXPECT_FALSE(observer.latest_explanations().ran_mixed_content); | |
| 1637 | |
| 1638 // Since the next expected style is the same as the previous, clear | |
| 1639 // the observer (to make sure that the event fires twice and we don't | |
| 1640 // just see the previous event's style). | |
| 1641 observer.ClearLatestSecurityStyleAndExplanations(); | |
| 1642 | |
| 1643 // Other conditions cannot be tested on this host after clicking | |
| 1644 // through because once the interstitial is clicked through, all URLs | |
| 1645 // for this host will remain in a broken state. | |
| 1646 ProceedThroughInterstitial(web_contents); | |
| 1647 CheckBrokenSecurityStyle(observer, net::ERR_CERT_DATE_INVALID, browser(), | |
| 1648 https_test_server_expired.GetCertificate().get()); | |
| 1649 CheckSecureExplanations(observer.latest_explanations().secure_explanations, | |
| 1650 INVALID_CERTIFICATE, browser(), | |
| 1651 https_test_server_expired.GetCertificate().get()); | |
| 1652 EXPECT_TRUE(observer.latest_explanations().scheme_is_cryptographic); | |
| 1653 EXPECT_FALSE(observer.latest_explanations().pkp_bypassed); | |
| 1654 EXPECT_TRUE(observer.latest_explanations().info_explanations.empty()); | |
| 1655 EXPECT_FALSE(observer.latest_explanations().displayed_mixed_content); | |
| 1656 EXPECT_FALSE(observer.latest_explanations().ran_mixed_content); | |
| 1657 } | |
| 1658 | |
| 1659 // Visit a valid HTTPS page, then a broken HTTPS page, and then go back, | |
| 1660 // and test that the observed security style matches. | |
| 1661 #if defined(OS_CHROMEOS) | |
| 1662 // Flaky on Chrome OS. See https://crbug.com/638576. | |
| 1663 #define MAYBE_SecurityStyleChangedObserverGoBack \ | |
| 1664 DISABLED_SecurityStyleChangedObserverGoBack | |
| 1665 #else | |
| 1666 #define MAYBE_SecurityStyleChangedObserverGoBack \ | |
| 1667 SecurityStyleChangedObserverGoBack | |
| 1668 #endif | |
| 1669 IN_PROC_BROWSER_TEST_F(SecurityStyleChangedTest, | |
| 1670 MAYBE_SecurityStyleChangedObserverGoBack) { | |
| 1671 ASSERT_TRUE(https_server_.Start()); | |
| 1672 | |
| 1673 net::EmbeddedTestServer https_test_server_expired( | |
| 1674 net::EmbeddedTestServer::TYPE_HTTPS); | |
| 1675 https_test_server_expired.SetSSLConfig(net::EmbeddedTestServer::CERT_EXPIRED); | |
| 1676 https_test_server_expired.ServeFilesFromSourceDirectory( | |
| 1677 base::FilePath(kDocRoot)); | |
| 1678 ASSERT_TRUE(https_test_server_expired.Start()); | |
| 1679 | |
| 1680 content::WebContents* web_contents = | |
| 1681 browser()->tab_strip_model()->GetActiveWebContents(); | |
| 1682 SecurityStyleTestObserver observer(web_contents); | |
| 1683 | |
| 1684 // Visit a valid HTTPS url. | |
| 1685 GURL valid_https_url(https_server_.GetURL("/title1.html")); | |
| 1686 ui_test_utils::NavigateToURL(browser(), valid_https_url); | |
| 1687 EXPECT_EQ(blink::WebSecurityStyleAuthenticated, | |
| 1688 observer.latest_security_style()); | |
| 1689 EXPECT_EQ(0u, | |
| 1690 observer.latest_explanations().unauthenticated_explanations.size()); | |
| 1691 EXPECT_EQ(0u, observer.latest_explanations().broken_explanations.size()); | |
| 1692 CheckSecureExplanations(observer.latest_explanations().secure_explanations, | |
| 1693 VALID_CERTIFICATE, browser(), | |
| 1694 https_server_.GetCertificate().get()); | |
| 1695 EXPECT_TRUE(observer.latest_explanations().scheme_is_cryptographic); | |
| 1696 EXPECT_FALSE(observer.latest_explanations().pkp_bypassed); | |
| 1697 EXPECT_TRUE(observer.latest_explanations().info_explanations.empty()); | |
| 1698 EXPECT_FALSE(observer.latest_explanations().displayed_mixed_content); | |
| 1699 EXPECT_FALSE(observer.latest_explanations().ran_mixed_content); | |
| 1700 | |
| 1701 // Navigate to a bad HTTPS page on a different host, and then click | |
| 1702 // Back to verify that the previous good security style is seen again. | |
| 1703 GURL expired_https_url(https_test_server_expired.GetURL("/title1.html")); | |
| 1704 host_resolver()->AddRule("www.example_broken.test", "127.0.0.1"); | |
| 1705 GURL::Replacements replace_host; | |
| 1706 replace_host.SetHostStr("www.example_broken.test"); | |
| 1707 GURL https_url_different_host = | |
| 1708 expired_https_url.ReplaceComponents(replace_host); | |
| 1709 | |
| 1710 ui_test_utils::NavigateToURL(browser(), https_url_different_host); | |
| 1711 | |
| 1712 content::WaitForInterstitialAttach(web_contents); | |
| 1713 EXPECT_TRUE(web_contents->ShowingInterstitialPage()); | |
| 1714 CheckBrokenSecurityStyle(observer, net::ERR_CERT_COMMON_NAME_INVALID, | |
| 1715 browser(), | |
| 1716 https_test_server_expired.GetCertificate().get()); | |
| 1717 ProceedThroughInterstitial(web_contents); | |
| 1718 CheckBrokenSecurityStyle(observer, net::ERR_CERT_COMMON_NAME_INVALID, | |
| 1719 browser(), | |
| 1720 https_test_server_expired.GetCertificate().get()); | |
| 1721 CheckSecureExplanations(observer.latest_explanations().secure_explanations, | |
| 1722 INVALID_CERTIFICATE, browser(), | |
| 1723 https_test_server_expired.GetCertificate().get()); | |
| 1724 EXPECT_TRUE(observer.latest_explanations().scheme_is_cryptographic); | |
| 1725 EXPECT_FALSE(observer.latest_explanations().pkp_bypassed); | |
| 1726 EXPECT_TRUE(observer.latest_explanations().info_explanations.empty()); | |
| 1727 EXPECT_FALSE(observer.latest_explanations().displayed_mixed_content); | |
| 1728 EXPECT_FALSE(observer.latest_explanations().ran_mixed_content); | |
| 1729 | |
| 1730 content::WindowedNotificationObserver back_nav_load_observer( | |
| 1731 content::NOTIFICATION_LOAD_STOP, | |
| 1732 content::Source<content::NavigationController>( | |
| 1733 &web_contents->GetController())); | |
| 1734 chrome::GoBack(browser(), WindowOpenDisposition::CURRENT_TAB); | |
| 1735 back_nav_load_observer.Wait(); | |
| 1736 | |
| 1737 EXPECT_EQ(blink::WebSecurityStyleAuthenticated, | |
| 1738 observer.latest_security_style()); | |
| 1739 EXPECT_EQ(0u, | |
| 1740 observer.latest_explanations().unauthenticated_explanations.size()); | |
| 1741 EXPECT_EQ(0u, observer.latest_explanations().broken_explanations.size()); | |
| 1742 CheckSecureExplanations(observer.latest_explanations().secure_explanations, | |
| 1743 VALID_CERTIFICATE, browser(), | |
| 1744 https_server_.GetCertificate().get()); | |
| 1745 EXPECT_TRUE(observer.latest_explanations().scheme_is_cryptographic); | |
| 1746 EXPECT_FALSE(observer.latest_explanations().pkp_bypassed); | |
| 1747 EXPECT_TRUE(observer.latest_explanations().info_explanations.empty()); | |
| 1748 EXPECT_FALSE(observer.latest_explanations().displayed_mixed_content); | |
| 1749 EXPECT_FALSE(observer.latest_explanations().ran_mixed_content); | |
| 1750 } | |
| 1751 | |
| 1752 // After AddNonsecureUrlHandler() is called, requests to this hostname | |
| 1753 // will use obsolete TLS settings. | |
| 1754 const char kMockNonsecureHostname[] = "example-nonsecure.test"; | |
| 1755 const int kObsoleteTLSVersion = net::SSL_CONNECTION_VERSION_TLS1_1; | |
| 1756 // ECDHE_RSA + AES_128_CBC with HMAC-SHA1 | |
| 1757 const uint16_t kObsoleteCipherSuite = 0xc013; | |
| 1758 | |
| 1759 // A URLRequestMockHTTPJob that mocks a TLS connection with the obsolete | |
| 1760 // TLS settings specified in kObsoleteTLSVersion and | |
| 1761 // kObsoleteCipherSuite. | |
| 1762 class URLRequestObsoleteTLSJob : public net::URLRequestMockHTTPJob { | |
| 1763 public: | |
| 1764 URLRequestObsoleteTLSJob(net::URLRequest* request, | |
| 1765 net::NetworkDelegate* network_delegate, | |
| 1766 const base::FilePath& file_path, | |
| 1767 scoped_refptr<net::X509Certificate> cert, | |
| 1768 scoped_refptr<base::TaskRunner> task_runner) | |
| 1769 : net::URLRequestMockHTTPJob(request, | |
| 1770 network_delegate, | |
| 1771 file_path, | |
| 1772 task_runner), | |
| 1773 cert_(std::move(cert)) {} | |
| 1774 | |
| 1775 void GetResponseInfo(net::HttpResponseInfo* info) override { | |
| 1776 net::URLRequestMockHTTPJob::GetResponseInfo(info); | |
| 1777 net::SSLConnectionStatusSetVersion(kObsoleteTLSVersion, | |
| 1778 &info->ssl_info.connection_status); | |
| 1779 net::SSLConnectionStatusSetCipherSuite(kObsoleteCipherSuite, | |
| 1780 &info->ssl_info.connection_status); | |
| 1781 info->ssl_info.cert = cert_; | |
| 1782 } | |
| 1783 | |
| 1784 protected: | |
| 1785 ~URLRequestObsoleteTLSJob() override {} | |
| 1786 | |
| 1787 private: | |
| 1788 const scoped_refptr<net::X509Certificate> cert_; | |
| 1789 | |
| 1790 DISALLOW_COPY_AND_ASSIGN(URLRequestObsoleteTLSJob); | |
| 1791 }; | |
| 1792 | |
| 1793 // A URLRequestInterceptor that handles requests with | |
| 1794 // URLRequestObsoleteTLSJob jobs. | |
| 1795 class URLRequestNonsecureInterceptor : public net::URLRequestInterceptor { | |
| 1796 public: | |
| 1797 URLRequestNonsecureInterceptor( | |
| 1798 const base::FilePath& base_path, | |
| 1799 scoped_refptr<base::SequencedWorkerPool> worker_pool, | |
| 1800 scoped_refptr<net::X509Certificate> cert) | |
| 1801 : base_path_(base_path), | |
| 1802 worker_pool_(std::move(worker_pool)), | |
| 1803 cert_(std::move(cert)) {} | |
| 1804 | |
| 1805 ~URLRequestNonsecureInterceptor() override {} | |
| 1806 | |
| 1807 // net::URLRequestInterceptor: | |
| 1808 net::URLRequestJob* MaybeInterceptRequest( | |
| 1809 net::URLRequest* request, | |
| 1810 net::NetworkDelegate* network_delegate) const override { | |
| 1811 return new URLRequestObsoleteTLSJob( | |
| 1812 request, network_delegate, base_path_, cert_, | |
| 1813 worker_pool_->GetTaskRunnerWithShutdownBehavior( | |
| 1814 base::SequencedWorkerPool::SKIP_ON_SHUTDOWN)); | |
| 1815 } | |
| 1816 | |
| 1817 private: | |
| 1818 const base::FilePath base_path_; | |
| 1819 const scoped_refptr<base::SequencedWorkerPool> worker_pool_; | |
| 1820 const scoped_refptr<net::X509Certificate> cert_; | |
| 1821 | |
| 1822 DISALLOW_COPY_AND_ASSIGN(URLRequestNonsecureInterceptor); | |
| 1823 }; | |
| 1824 | |
| 1825 // Installs a handler to serve HTTPS requests to | |
| 1826 // |kMockNonsecureHostname| with connections that have obsolete TLS | |
| 1827 // settings. | |
| 1828 void AddNonsecureUrlHandler( | |
| 1829 const base::FilePath& base_path, | |
| 1830 scoped_refptr<net::X509Certificate> cert, | |
| 1831 scoped_refptr<base::SequencedWorkerPool> worker_pool) { | |
| 1832 net::URLRequestFilter* filter = net::URLRequestFilter::GetInstance(); | |
| 1833 filter->AddHostnameInterceptor( | |
| 1834 "https", kMockNonsecureHostname, | |
| 1835 std::unique_ptr<net::URLRequestInterceptor>( | |
| 1836 new URLRequestNonsecureInterceptor(base_path, worker_pool, cert))); | |
| 1837 } | |
| 1838 | |
| 1839 class BrowserTestNonsecureURLRequest : public InProcessBrowserTest { | |
| 1840 public: | |
| 1841 BrowserTestNonsecureURLRequest() : InProcessBrowserTest(), cert_(nullptr) {} | |
| 1842 | |
| 1843 void SetUpInProcessBrowserTestFixture() override { | |
| 1844 cert_ = | |
| 1845 net::ImportCertFromFile(net::GetTestCertsDirectory(), "ok_cert.pem"); | |
| 1846 ASSERT_TRUE(cert_); | |
| 1847 } | |
| 1848 | |
| 1849 void SetUpOnMainThread() override { | |
| 1850 base::FilePath serve_file; | |
| 1851 PathService::Get(chrome::DIR_TEST_DATA, &serve_file); | |
| 1852 serve_file = serve_file.Append(FILE_PATH_LITERAL("title1.html")); | |
| 1853 content::BrowserThread::PostTask( | |
| 1854 content::BrowserThread::IO, FROM_HERE, | |
| 1855 base::Bind( | |
| 1856 &AddNonsecureUrlHandler, serve_file, cert_, | |
| 1857 make_scoped_refptr(content::BrowserThread::GetBlockingPool()))); | |
| 1858 } | |
| 1859 | |
| 1860 private: | |
| 1861 scoped_refptr<net::X509Certificate> cert_; | |
| 1862 | |
| 1863 DISALLOW_COPY_AND_ASSIGN(BrowserTestNonsecureURLRequest); | |
| 1864 }; | |
| 1865 | |
| 1866 // Tests that a connection with obsolete TLS settings does not get a | |
| 1867 // secure connection explanation. | |
| 1868 IN_PROC_BROWSER_TEST_F(BrowserTestNonsecureURLRequest, | |
| 1869 SecurityStyleChangedObserverNonsecureConnection) { | |
| 1870 content::WebContents* web_contents = | |
| 1871 browser()->tab_strip_model()->GetActiveWebContents(); | |
| 1872 SecurityStyleTestObserver observer(web_contents); | |
| 1873 | |
| 1874 ui_test_utils::NavigateToURL( | |
| 1875 browser(), GURL(std::string("https://") + kMockNonsecureHostname)); | |
| 1876 | |
| 1877 // The security style of the page doesn't get downgraded for obsolete | |
| 1878 // TLS settings, so it should remain at WebSecurityStyleAuthenticated. | |
| 1879 EXPECT_EQ(blink::WebSecurityStyleAuthenticated, | |
| 1880 observer.latest_security_style()); | |
| 1881 | |
| 1882 // The messages explaining the security style do, however, get | |
| 1883 // downgraded: SECURE_PROTOCOL_AND_CIPHERSUITE should not show up when | |
| 1884 // the TLS settings are obsolete. | |
| 1885 for (const auto& explanation : | |
| 1886 observer.latest_explanations().secure_explanations) { | |
| 1887 EXPECT_NE(l10n_util::GetStringUTF8(IDS_STRONG_SSL_SUMMARY), | |
| 1888 explanation.summary); | |
| 1889 } | |
| 1890 | |
| 1891 // Populate description string replacement with values corresponding | |
| 1892 // to test constants. | |
| 1893 std::vector<base::string16> description_replacements; | |
| 1894 description_replacements.push_back( | |
| 1895 l10n_util::GetStringUTF16(IDS_SSL_AN_OBSOLETE_PROTOCOL)); | |
| 1896 description_replacements.push_back(base::ASCIIToUTF16("TLS 1.1")); | |
| 1897 description_replacements.push_back( | |
| 1898 l10n_util::GetStringUTF16(IDS_SSL_A_STRONG_KEY_EXCHANGE)); | |
| 1899 description_replacements.push_back(base::ASCIIToUTF16("ECDHE_RSA")); | |
| 1900 description_replacements.push_back( | |
| 1901 l10n_util::GetStringUTF16(IDS_SSL_AN_OBSOLETE_CIPHER)); | |
| 1902 description_replacements.push_back( | |
| 1903 base::ASCIIToUTF16("AES_128_CBC with HMAC-SHA1")); | |
| 1904 base::string16 obsolete_description = l10n_util::GetStringFUTF16( | |
| 1905 IDS_OBSOLETE_SSL_DESCRIPTION, description_replacements, nullptr); | |
| 1906 | |
| 1907 EXPECT_EQ( | |
| 1908 obsolete_description, | |
| 1909 base::ASCIIToUTF16( | |
| 1910 observer.latest_explanations().info_explanations[0].description)); | |
| 1911 } | |
| 1912 | |
| 1913 // After AddSCTUrlHandler() is called, requests to this hostname | |
| 1914 // will be served with Signed Certificate Timestamps. | |
| 1915 const char kMockHostnameWithSCTs[] = "example-scts.test"; | |
| 1916 | |
| 1917 // URLRequestJobWithSCTs mocks a connection that includes a set of dummy | |
| 1918 // SCTs with these statuses. | |
| 1919 const std::vector<net::ct::SCTVerifyStatus> kTestSCTStatuses{ | |
| 1920 net::ct::SCT_STATUS_OK, net::ct::SCT_STATUS_LOG_UNKNOWN, | |
| 1921 net::ct::SCT_STATUS_OK}; | |
| 1922 | |
| 1923 // A URLRequestMockHTTPJob that mocks a TLS connection with SCTs | |
| 1924 // attached to it. The SCTs will have verification statuses | |
| 1925 // |kTestSCTStatuses|. | |
| 1926 class URLRequestJobWithSCTs : public net::URLRequestMockHTTPJob { | |
| 1927 public: | |
| 1928 URLRequestJobWithSCTs(net::URLRequest* request, | |
| 1929 net::NetworkDelegate* network_delegate, | |
| 1930 const base::FilePath& file_path, | |
| 1931 scoped_refptr<net::X509Certificate> cert, | |
| 1932 scoped_refptr<base::TaskRunner> task_runner) | |
| 1933 : net::URLRequestMockHTTPJob(request, | |
| 1934 network_delegate, | |
| 1935 file_path, | |
| 1936 task_runner), | |
| 1937 cert_(std::move(cert)) {} | |
| 1938 | |
| 1939 void GetResponseInfo(net::HttpResponseInfo* info) override { | |
| 1940 net::URLRequestMockHTTPJob::GetResponseInfo(info); | |
| 1941 for (const auto& status : kTestSCTStatuses) { | |
| 1942 scoped_refptr<net::ct::SignedCertificateTimestamp> dummy_sct = | |
| 1943 new net::ct::SignedCertificateTimestamp(); | |
| 1944 info->ssl_info.signed_certificate_timestamps.push_back( | |
| 1945 net::SignedCertificateTimestampAndStatus(dummy_sct, status)); | |
| 1946 } | |
| 1947 info->ssl_info.cert = cert_; | |
| 1948 } | |
| 1949 | |
| 1950 protected: | |
| 1951 ~URLRequestJobWithSCTs() override {} | |
| 1952 | |
| 1953 private: | |
| 1954 const scoped_refptr<net::X509Certificate> cert_; | |
| 1955 | |
| 1956 DISALLOW_COPY_AND_ASSIGN(URLRequestJobWithSCTs); | |
| 1957 }; | |
| 1958 | |
| 1959 // A URLRequestInterceptor that handles requests with | |
| 1960 // URLRequestJobWithSCTs jobs. | |
| 1961 class URLRequestWithSCTsInterceptor : public net::URLRequestInterceptor { | |
| 1962 public: | |
| 1963 URLRequestWithSCTsInterceptor( | |
| 1964 const base::FilePath& base_path, | |
| 1965 scoped_refptr<base::SequencedWorkerPool> worker_pool, | |
| 1966 scoped_refptr<net::X509Certificate> cert) | |
| 1967 : base_path_(base_path), | |
| 1968 worker_pool_(std::move(worker_pool)), | |
| 1969 cert_(std::move(cert)) {} | |
| 1970 | |
| 1971 ~URLRequestWithSCTsInterceptor() override {} | |
| 1972 | |
| 1973 // net::URLRequestInterceptor: | |
| 1974 net::URLRequestJob* MaybeInterceptRequest( | |
| 1975 net::URLRequest* request, | |
| 1976 net::NetworkDelegate* network_delegate) const override { | |
| 1977 return new URLRequestJobWithSCTs( | |
| 1978 request, network_delegate, base_path_, cert_, | |
| 1979 worker_pool_->GetTaskRunnerWithShutdownBehavior( | |
| 1980 base::SequencedWorkerPool::SKIP_ON_SHUTDOWN)); | |
| 1981 } | |
| 1982 | |
| 1983 private: | |
| 1984 const base::FilePath base_path_; | |
| 1985 const scoped_refptr<base::SequencedWorkerPool> worker_pool_; | |
| 1986 const scoped_refptr<net::X509Certificate> cert_; | |
| 1987 | |
| 1988 DISALLOW_COPY_AND_ASSIGN(URLRequestWithSCTsInterceptor); | |
| 1989 }; | |
| 1990 | |
| 1991 // Installs a handler to serve HTTPS requests to |kMockHostnameWithSCTs| | |
| 1992 // with connections that have SCTs. | |
| 1993 void AddSCTUrlHandler(const base::FilePath& base_path, | |
| 1994 scoped_refptr<net::X509Certificate> cert, | |
| 1995 scoped_refptr<base::SequencedWorkerPool> worker_pool) { | |
| 1996 net::URLRequestFilter* filter = net::URLRequestFilter::GetInstance(); | |
| 1997 filter->AddHostnameInterceptor( | |
| 1998 "https", kMockHostnameWithSCTs, | |
| 1999 std::unique_ptr<net::URLRequestInterceptor>( | |
| 2000 new URLRequestWithSCTsInterceptor(base_path, worker_pool, cert))); | |
| 2001 } | |
| 2002 | |
| 2003 class BrowserTestURLRequestWithSCTs : public InProcessBrowserTest { | |
| 2004 public: | |
| 2005 BrowserTestURLRequestWithSCTs() : InProcessBrowserTest(), cert_(nullptr) {} | |
| 2006 | |
| 2007 void SetUpInProcessBrowserTestFixture() override { | |
| 2008 cert_ = | |
| 2009 net::ImportCertFromFile(net::GetTestCertsDirectory(), "ok_cert.pem"); | |
| 2010 ASSERT_TRUE(cert_); | |
| 2011 } | |
| 2012 | |
| 2013 void SetUpOnMainThread() override { | |
| 2014 base::FilePath serve_file; | |
| 2015 PathService::Get(chrome::DIR_TEST_DATA, &serve_file); | |
| 2016 serve_file = serve_file.Append(FILE_PATH_LITERAL("title1.html")); | |
| 2017 content::BrowserThread::PostTask( | |
| 2018 content::BrowserThread::IO, FROM_HERE, | |
| 2019 base::Bind( | |
| 2020 &AddSCTUrlHandler, serve_file, cert_, | |
| 2021 make_scoped_refptr(content::BrowserThread::GetBlockingPool()))); | |
| 2022 } | |
| 2023 | |
| 2024 private: | |
| 2025 scoped_refptr<net::X509Certificate> cert_; | |
| 2026 | |
| 2027 DISALLOW_COPY_AND_ASSIGN(BrowserTestURLRequestWithSCTs); | |
| 2028 }; | |
| 2029 | |
| 2030 // Tests that, when Signed Certificate Timestamps (SCTs) are served on a | |
| 2031 // connection, the SCTs verification statuses are exposed on the | |
| 2032 // SecurityInfo. | |
| 2033 IN_PROC_BROWSER_TEST_F(BrowserTestURLRequestWithSCTs, | |
| 2034 SecurityInfoWithSCTsAttached) { | |
| 2035 ui_test_utils::NavigateToURL( | |
| 2036 browser(), GURL(std::string("https://") + kMockHostnameWithSCTs)); | |
| 2037 | |
| 2038 content::WebContents* web_contents = | |
| 2039 browser()->tab_strip_model()->GetActiveWebContents(); | |
| 2040 ASSERT_TRUE(web_contents); | |
| 2041 ChromeSecurityStateModelClient* model_client = | |
| 2042 ChromeSecurityStateModelClient::FromWebContents(web_contents); | |
| 2043 ASSERT_TRUE(model_client); | |
| 2044 SecurityStateModel::SecurityInfo security_info; | |
| 2045 model_client->GetSecurityInfo(&security_info); | |
| 2046 EXPECT_EQ(SecurityStateModel::SECURE, security_info.security_level); | |
| 2047 EXPECT_EQ(kTestSCTStatuses, security_info.sct_verify_statuses); | |
| 2048 } | |
| 2049 | |
| 2050 } // namespace | |
| OLD | NEW |