| // Copyright 2018 The Chromium Authors. All rights reserved. |
| // Use of this source code is governed by a BSD-style license that can be |
| // found in the LICENSE file. |
| |
| #include "base/bind.h" |
| #include "base/logging.h" |
| #include "base/test/scoped_feature_list.h" |
| #include "content/public/test/browser_test_utils.h" |
| #include "content/public/test/content_browser_test.h" |
| #include "content/public/test/content_browser_test_utils.h" |
| #include "content/public/test/test_utils.h" |
| #include "content/shell/browser/shell.h" |
| #include "content/shell/browser/shell_content_browser_client.h" |
| #include "net/ssl/ssl_server_config.h" |
| #include "net/test/embedded_test_server/embedded_test_server.h" |
| #include "services/network/public/cpp/features.h" |
| #include "third_party/blink/public/common/features.h" |
| #include "url/gurl.h" |
| |
| namespace content { |
| |
| namespace { |
| enum class ServicifiedFeatures { kNone, kServiceWorker, kNetwork }; |
| } |
| |
| // Tests TLS + service workers. Inspired by |
| // content/browser/worker_host/worker_browsertest.cc. |
| class ServiceWorkerTlsTest |
| : public ContentBrowserTest, |
| public ::testing::WithParamInterface<ServicifiedFeatures> { |
| public: |
| ServiceWorkerTlsTest() = default; |
| |
| void SetUp() override { |
| ServicifiedFeatures param = GetParam(); |
| switch (param) { |
| case ServicifiedFeatures::kNone: |
| scoped_feature_list_.InitWithFeatures( |
| {}, {blink::features::kServiceWorkerServicification, |
| network::features::kNetworkService}); |
| break; |
| case ServicifiedFeatures::kServiceWorker: |
| scoped_feature_list_.InitWithFeatures( |
| {blink::features::kServiceWorkerServicification}, |
| {network::features::kNetworkService}); |
| break; |
| case ServicifiedFeatures::kNetwork: |
| scoped_feature_list_.InitAndEnableFeature( |
| network::features::kNetworkService); |
| break; |
| } |
| ContentBrowserTest::SetUp(); |
| } |
| |
| void SetUpOnMainThread() override { |
| ShellContentBrowserClient::Get()->set_select_client_certificate_callback( |
| base::BindRepeating(&ServiceWorkerTlsTest::OnSelectClientCertificate, |
| base::Unretained(this))); |
| ASSERT_TRUE(embedded_test_server()->Start()); |
| } |
| |
| void TearDownOnMainThread() override { |
| ShellContentBrowserClient::Get()->set_select_client_certificate_callback( |
| base::RepeatingClosure()); |
| } |
| |
| int select_certificate_count() const { return select_certificate_count_; } |
| |
| GURL GetTestURL(const std::string& test_case, const std::string& query) { |
| std::string url_string = "/workers/" + test_case + "?" + query; |
| return embedded_test_server()->GetURL(url_string); |
| } |
| |
| private: |
| void OnSelectClientCertificate() { select_certificate_count_++; } |
| |
| int select_certificate_count_ = 0; |
| base::test::ScopedFeatureList scoped_feature_list_; |
| }; |
| |
| // Tests that TLS client auth prompts for a page controlled by a service |
| // worker, when the service worker calls fetch() for the main resource. |
| IN_PROC_BROWSER_TEST_P(ServiceWorkerTlsTest, ClientAuthFetchMainResource) { |
| // Start an HTTPS server which doesn't need client certs. |
| net::EmbeddedTestServer https_server(net::EmbeddedTestServer::TYPE_HTTPS); |
| https_server.ServeFilesFromSourceDirectory("content/test/data"); |
| net::SSLServerConfig ssl_config; |
| ssl_config.client_cert_type = |
| net::SSLServerConfig::ClientCertType::NO_CLIENT_CERT; |
| https_server.SetSSLConfig(net::EmbeddedTestServer::CERT_OK, ssl_config); |
| ASSERT_TRUE(https_server.Start()); |
| |
| // Load a page that installs the service worker. |
| EXPECT_TRUE(NavigateToURL( |
| shell(), https_server.GetURL("/workers/service_worker_setup.html"))); |
| EXPECT_EQ("ok", EvalJs(shell(), "setup();")); |
| |
| // Set the HTTPS server to require client certs. |
| ssl_config.client_cert_type = |
| net::SSLServerConfig::ClientCertType::REQUIRE_CLIENT_CERT; |
| https_server.ResetSSLConfig(net::EmbeddedTestServer::CERT_OK, ssl_config); |
| |
| // Load a page that the SW intercepts with respondWith(fetch()). It should |
| // prompt client certificate selection. (The navigation fails because |
| // this test doesn't select a client certificate.) |
| EXPECT_FALSE(NavigateToURL( |
| shell(), https_server.GetURL("/workers/simple.html?intercept"))); |
| EXPECT_EQ(1, select_certificate_count()); |
| } |
| |
| // Tests that TLS client auth prompts for a page controlled by a service |
| // worker, when the service worker calls fetch() for a subresource. |
| IN_PROC_BROWSER_TEST_P(ServiceWorkerTlsTest, ClientAuthFetchSubResource) { |
| // Load a page that installs the service worker. |
| EXPECT_TRUE(NavigateToURL( |
| shell(), GetTestURL("service_worker_setup.html", std::string()))); |
| EXPECT_EQ("ok", EvalJs(shell(), "setup();")); |
| |
| // Load a page controlled by the service worker. |
| EXPECT_TRUE(NavigateToURL(shell(), |
| GetTestURL("simple.html?fallback", std::string()))); |
| |
| // Start HTTPS server. |
| net::EmbeddedTestServer https_server(net::EmbeddedTestServer::TYPE_HTTPS); |
| https_server.ServeFilesFromSourceDirectory("content/test/data"); |
| net::SSLServerConfig ssl_config; |
| ASSERT_TRUE(https_server.Start()); |
| ssl_config.client_cert_type = |
| net::SSLServerConfig::ClientCertType::REQUIRE_CLIENT_CERT; |
| https_server.ResetSSLConfig(net::EmbeddedTestServer::CERT_OK, ssl_config); |
| |
| // Perform a fetch from the controlled page to the https server. It should |
| // prompt client certificate selection. (The fetch fails because this test |
| // doesn't select a client certificate.) |
| std::string url = https_server.GetURL("/?intercept").spec(); |
| EXPECT_EQ("TypeError", EvalJs(shell(), "try_fetch('" + url + "');")); |
| EXPECT_EQ(1, select_certificate_count()); |
| } |
| |
| INSTANTIATE_TEST_CASE_P(/* no prefix */, |
| ServiceWorkerTlsTest, |
| ::testing::Values(ServicifiedFeatures::kNone, |
| ServicifiedFeatures::kServiceWorker, |
| ServicifiedFeatures::kNetwork)); |
| |
| } // namespace content |