| // Copyright 2021 The Chromium Authors |
| // Use of this source code is governed by a BSD-style license that can be |
| // found in the LICENSE file. |
| |
| #include "content/browser/renderer_host/navigation_policy_container_builder.h" |
| |
| #include <iosfwd> |
| #include <utility> |
| |
| #include "base/files/file_path.h" |
| #include "base/test/bind.h" |
| #include "base/test/gtest_util.h" |
| #include "base/test/scoped_feature_list.h" |
| #include "content/public/browser/browser_thread.h" |
| #include "content/public/test/mock_navigation_handle.h" |
| #include "content/public/test/navigation_simulator.h" |
| #include "content/test/test_render_view_host.h" |
| #include "content/test/test_web_contents.h" |
| #include "net/test/embedded_test_server/embedded_test_server.h" |
| #include "services/network/public/mojom/content_security_policy.mojom.h" |
| #include "services/network/public/mojom/referrer_policy.mojom-shared.h" |
| #include "testing/gmock/include/gmock/gmock.h" |
| #include "testing/gtest/include/gtest/gtest.h" |
| #include "url/url_constants.h" |
| |
| namespace content { |
| namespace { |
| |
| using ::testing::ByRef; |
| using ::testing::Eq; |
| using ::testing::IsNull; |
| using ::testing::NotNull; |
| using ::testing::Pointee; |
| using ::testing::SizeIs; |
| |
| network::mojom::ContentSecurityPolicyPtr MakeTestCSP() { |
| auto csp = network::mojom::ContentSecurityPolicy::New(); |
| csp->header = network::mojom::ContentSecurityPolicyHeader::New(); |
| csp->header->header_value = "some-directive some-value"; |
| return csp; |
| } |
| |
| // Returns non-default policies for use in tests. |
| PolicyContainerPolicies MakeTestPolicies() { |
| std::vector<network::mojom::ContentSecurityPolicyPtr> csp_list; |
| csp_list.push_back(MakeTestCSP()); |
| return PolicyContainerPolicies( |
| network::mojom::ReferrerPolicy::kAlways, |
| network::mojom::IPAddressSpace::kPublic, |
| /*is_web_secure_context=*/true, std::move(csp_list), |
| network::CrossOriginOpenerPolicy(), network::CrossOriginEmbedderPolicy(), |
| network::DocumentIsolationPolicy(), network::IntegrityPolicy(), |
| network::IntegrityPolicy(), network::mojom::WebSandboxFlags::kNone, |
| /*is_credentialless=*/false, |
| /*can_navigate_top_without_user_gesture=*/true, |
| /*cross_origin_isolation_enabled_by_dip=*/false); |
| } |
| |
| // Shorthand. |
| scoped_refptr<PolicyContainerHost> NewHost(PolicyContainerPolicies policies) { |
| return base::MakeRefCounted<PolicyContainerHost>(std::move(policies)); |
| } |
| |
| GURL AboutBlankUrl() { |
| return GURL(url::kAboutBlankURL); |
| } |
| |
| GURL AboutSrcdocUrl() { |
| return GURL(url::kAboutSrcdocURL); |
| } |
| |
| // RenderViewHostImplTestHarness allows interacting with RenderFrameHosts in the |
| // form of TestRenderFrameHosts. This allows us to easily set policies on frames |
| // for testing. It also instantiates a BrowserTaskEnvironment so that tests are |
| // executed "on the UI thread". |
| // |
| // This test fixture is moderately expensive to set up (~100ms overhead per |
| // test), but still an order of magnitude faster than browser tests. |
| class NavigationPolicyContainerBuilderTest |
| : public RenderViewHostImplTestHarness { |
| protected: |
| void SetUp() override { |
| RenderViewHostImplTestHarness::SetUp(); |
| contents()->GetPrimaryMainFrame()->InitializeRenderFrameIfNeeded(); |
| } |
| }; |
| |
| // Verifies that the initial delivered policies are default-constructed. |
| TEST_F(NavigationPolicyContainerBuilderTest, DefaultDeliveredPolicies) { |
| EXPECT_EQ( |
| NavigationPolicyContainerBuilder( |
| nullptr, nullptr, kInvalidChildProcessUniqueId, nullptr, nullptr) |
| .DeliveredPoliciesForTesting(), |
| PolicyContainerPolicies()); |
| } |
| |
| // Verifies that SetIPAddressSpace sets the address space in the builder's |
| // delivered policies. |
| TEST_F(NavigationPolicyContainerBuilderTest, SetIPAddressSpace) { |
| NavigationPolicyContainerBuilder builder( |
| nullptr, nullptr, kInvalidChildProcessUniqueId, nullptr, nullptr); |
| builder.SetIPAddressSpace(network::mojom::IPAddressSpace::kPublic); |
| |
| PolicyContainerPolicies expected_policies; |
| expected_policies.ip_address_space = network::mojom::IPAddressSpace::kPublic; |
| |
| EXPECT_EQ(builder.DeliveredPoliciesForTesting(), expected_policies); |
| } |
| |
| // Verifies that SetIsOriginPotentiallyTrustworthy sets the secure context bit |
| // in the builder's delivered policies. |
| TEST_F(NavigationPolicyContainerBuilderTest, |
| SetIsOriginPotentiallyTrustworthy) { |
| NavigationPolicyContainerBuilder builder( |
| nullptr, nullptr, kInvalidChildProcessUniqueId, nullptr, nullptr); |
| builder.SetIsOriginPotentiallyTrustworthy(true); |
| |
| PolicyContainerPolicies expected_policies; |
| expected_policies.is_web_secure_context = true; |
| |
| EXPECT_EQ(builder.DeliveredPoliciesForTesting(), expected_policies); |
| |
| builder.SetIsOriginPotentiallyTrustworthy(false); |
| |
| expected_policies.is_web_secure_context = false; |
| EXPECT_EQ(builder.DeliveredPoliciesForTesting(), expected_policies); |
| } |
| |
| // Verifies that SetCrossOriginOpenerPolicy sets the cross-origin-opener-policy |
| // in the builder's delivered policies. |
| TEST_F(NavigationPolicyContainerBuilderTest, SetCrossOriginOpenerPolicy) { |
| NavigationPolicyContainerBuilder builder( |
| nullptr, nullptr, kInvalidChildProcessUniqueId, nullptr, nullptr); |
| |
| network::CrossOriginOpenerPolicy coop; |
| coop.value = network::mojom::CrossOriginOpenerPolicyValue::kSameOrigin; |
| coop.report_only_value = |
| network::mojom::CrossOriginOpenerPolicyValue::kSameOriginAllowPopups; |
| coop.reporting_endpoint = "A"; |
| coop.report_only_reporting_endpoint = "B"; |
| |
| builder.SetCrossOriginOpenerPolicy(coop); |
| |
| PolicyContainerPolicies expected_policies; |
| expected_policies.cross_origin_opener_policy = coop; |
| |
| EXPECT_EQ(builder.DeliveredPoliciesForTesting(), expected_policies); |
| } |
| |
| // Verifies that SetDocumentIsolationPolicy sets the document-isolation-policy |
| // in the builder's delivered policies. |
| TEST_F(NavigationPolicyContainerBuilderTest, SetDocumentIsolationPolicy) { |
| NavigationPolicyContainerBuilder builder( |
| nullptr, nullptr, kInvalidChildProcessUniqueId, nullptr, nullptr); |
| |
| network::DocumentIsolationPolicy dip; |
| dip.value = |
| network::mojom::DocumentIsolationPolicyValue::kIsolateAndRequireCorp; |
| dip.report_only_value = |
| network::mojom::DocumentIsolationPolicyValue::kIsolateAndCredentialless; |
| dip.reporting_endpoint = "A"; |
| dip.report_only_reporting_endpoint = "B"; |
| |
| builder.SetDocumentIsolationPolicy(dip); |
| |
| PolicyContainerPolicies expected_policies; |
| expected_policies.document_isolation_policy = dip; |
| |
| EXPECT_EQ(builder.DeliveredPoliciesForTesting(), expected_policies); |
| } |
| |
| // Verifies that the default final policies of a builder are |
| // default-constructed, and are equal to the policies of the builder's policy |
| // container host. |
| TEST_F(NavigationPolicyContainerBuilderTest, DefaultFinalPolicies) { |
| NavigationPolicyContainerBuilder builder( |
| nullptr, nullptr, kInvalidChildProcessUniqueId, nullptr, nullptr); |
| MockNavigationHandle navigation_handle(GURL(), nullptr); |
| builder.ComputePolicies(&navigation_handle, false, |
| network::mojom::WebSandboxFlags::kNone, |
| /*is_credentialless=*/false); |
| |
| PolicyContainerPolicies expected_policies; |
| EXPECT_EQ(builder.FinalPolicies(), expected_policies); |
| |
| scoped_refptr<PolicyContainerHost> cloned_host = |
| builder.GetPolicyContainerHost(); |
| ASSERT_THAT(cloned_host, NotNull()); |
| EXPECT_EQ(cloned_host->policies(), expected_policies); |
| |
| scoped_refptr<PolicyContainerHost> host = |
| std::move(builder).TakePolicyContainerHost(); |
| ASSERT_THAT(host, NotNull()); |
| EXPECT_EQ(host->policies(), expected_policies); |
| ASSERT_THAT(cloned_host, NotNull()); |
| } |
| |
| // Verifies that when the URL of the document to commit does not have a local |
| // scheme, then the final policies are copied from the delivered policies. |
| TEST_F(NavigationPolicyContainerBuilderTest, FinalPoliciesNormalUrl) { |
| NavigationPolicyContainerBuilder builder( |
| nullptr, nullptr, kInvalidChildProcessUniqueId, nullptr, nullptr); |
| |
| builder.SetIPAddressSpace(network::mojom::IPAddressSpace::kPublic); |
| builder.AddContentSecurityPolicy(MakeTestCSP()); |
| PolicyContainerPolicies delivered_policies = |
| builder.DeliveredPoliciesForTesting().Clone(); |
| MockNavigationHandle navigation_handle(GURL("https://foo.test"), nullptr); |
| builder.ComputePolicies(&navigation_handle, false, |
| network::mojom::WebSandboxFlags::kNone, |
| /*is_credentialless=*/false); |
| |
| EXPECT_EQ(builder.FinalPolicies(), delivered_policies); |
| } |
| |
| // Verifies the final policies when the URL of the document to commit is |
| // `about:blank` but there is no initiator. |
| TEST_F(NavigationPolicyContainerBuilderTest, |
| FinalPoliciesAboutBlankWithoutInitiator) { |
| NavigationPolicyContainerBuilder builder( |
| nullptr, nullptr, kInvalidChildProcessUniqueId, nullptr, nullptr); |
| builder.SetIPAddressSpace(network::mojom::IPAddressSpace::kPublic); |
| PolicyContainerPolicies delivered_policies = |
| builder.DeliveredPoliciesForTesting().Clone(); |
| MockNavigationHandle navigation_handle(AboutBlankUrl(), nullptr); |
| builder.ComputePolicies(&navigation_handle, false, |
| network::mojom::WebSandboxFlags::kNone, |
| /*is_credentialless=*/false); |
| |
| EXPECT_EQ(builder.FinalPolicies(), delivered_policies); |
| } |
| |
| TEST_F(NavigationPolicyContainerBuilderTest, MHTMLSandboxFlags) { |
| NavigationPolicyContainerBuilder builder( |
| nullptr, nullptr, kInvalidChildProcessUniqueId, nullptr, nullptr); |
| builder.SetIPAddressSpace(network::mojom::IPAddressSpace::kLocal); |
| MockNavigationHandle navigation_handle(GURL("file:///my/page.mhtml"), |
| nullptr); |
| builder.ComputePolicies(&navigation_handle, |
| /*is_inside_mhtml=*/true, |
| network::mojom::WebSandboxFlags::kNone, |
| /*is_credentialless=*/false); |
| |
| EXPECT_EQ(builder.FinalPolicies().sandbox_flags, |
| // MHTML archives receive all sandbox flags except these: |
| ~(network::mojom::WebSandboxFlags::kPopups | |
| network::mojom::WebSandboxFlags:: |
| kPropagatesToAuxiliaryBrowsingContexts)); |
| } |
| |
| // When kMHTML_Improvements is enabled, in mhtml, scripts are allowed. |
| TEST_F(NavigationPolicyContainerBuilderTest, |
| MHTMLSandboxFlagsWithMHTMLImprovementsLocalFile) { |
| base::test::ScopedFeatureList features(blink::features::kMHTML_Improvements); |
| NavigationPolicyContainerBuilder builder( |
| nullptr, nullptr, kInvalidChildProcessUniqueId, nullptr, nullptr); |
| builder.SetIPAddressSpace(network::mojom::IPAddressSpace::kLocal); |
| MockNavigationHandle navigation_handle(GURL("file:///my/page.mhtml"), |
| nullptr); |
| builder.ComputePolicies(&navigation_handle, |
| /*is_inside_mhtml=*/true, |
| network::mojom::WebSandboxFlags::kNone, |
| /*is_credentialless=*/false); |
| |
| EXPECT_EQ(builder.FinalPolicies().sandbox_flags, |
| // When kMHTML_Improvements is enabled, MHTML archives receive all |
| // sandbox flags except these: |
| ~(network::mojom::WebSandboxFlags::kPopups | |
| network::mojom::WebSandboxFlags:: |
| kPropagatesToAuxiliaryBrowsingContexts | |
| network::mojom::WebSandboxFlags::kScripts)); |
| } |
| |
| // Verifies the final policies when the URL of the document to commit is |
| // `about:blank` but there is no initiator, and we have some additional CSPs. |
| TEST_F(NavigationPolicyContainerBuilderTest, |
| FinalPoliciesAboutBlankWithoutInitiatorAdditionalCSP) { |
| NavigationPolicyContainerBuilder builder( |
| nullptr, nullptr, kInvalidChildProcessUniqueId, nullptr, nullptr); |
| builder.SetIPAddressSpace(network::mojom::IPAddressSpace::kPublic); |
| builder.AddContentSecurityPolicy(MakeTestCSP()); |
| PolicyContainerPolicies delivered_policies = |
| builder.DeliveredPoliciesForTesting().Clone(); |
| MockNavigationHandle navigation_handle(AboutBlankUrl(), nullptr); |
| builder.ComputePolicies(&navigation_handle, false, |
| network::mojom::WebSandboxFlags::kNone, |
| /*is_credentialless=*/false); |
| |
| EXPECT_EQ(builder.FinalPolicies(), delivered_policies); |
| } |
| |
| // This test verifies the default final policies on error pages. |
| TEST_F(NavigationPolicyContainerBuilderTest, DefaultFinalPoliciesForErrorPage) { |
| NavigationPolicyContainerBuilder builder( |
| nullptr, nullptr, kInvalidChildProcessUniqueId, nullptr, nullptr); |
| |
| builder.ComputePoliciesForError(); |
| |
| // Error pages commit with default policies, mostly ignoring the delivered |
| // policies and the document's URL. |
| EXPECT_EQ(builder.FinalPolicies(), PolicyContainerPolicies()); |
| } |
| |
| // This test verifies that error pages commit in the same IP address space as |
| // the underlying page would have, had it not failed to load. |
| TEST_F(NavigationPolicyContainerBuilderTest, ErrorPageIPAddressSpace) { |
| NavigationPolicyContainerBuilder builder( |
| nullptr, nullptr, kInvalidChildProcessUniqueId, nullptr, nullptr); |
| |
| builder.SetIPAddressSpace(network::mojom::IPAddressSpace::kPublic); |
| builder.ComputePoliciesForError(); |
| |
| PolicyContainerPolicies expected_policies; |
| expected_policies.ip_address_space = network::mojom::IPAddressSpace::kPublic; |
| EXPECT_EQ(builder.FinalPolicies(), expected_policies); |
| } |
| |
| // Variation of: NavigationPolicyContainerBuilderTest.ErrorPageIPAddressSpace |
| // The decision to commit an error happens after receiving the response. |
| TEST_F(NavigationPolicyContainerBuilderTest, |
| ErrorPageIPAddressSpaceAfterResponse) { |
| NavigationPolicyContainerBuilder builder( |
| nullptr, nullptr, kInvalidChildProcessUniqueId, nullptr, nullptr); |
| |
| builder.SetIPAddressSpace(network::mojom::IPAddressSpace::kPrivate); |
| PolicyContainerPolicies expected_policies; |
| expected_policies.ip_address_space = network::mojom::IPAddressSpace::kPrivate; |
| |
| MockNavigationHandle navigation_handle(GURL("https://foo.test"), nullptr); |
| builder.ComputePolicies(&navigation_handle, false, |
| network::mojom::WebSandboxFlags::kNone, |
| /*is_credentialless=*/false); |
| EXPECT_EQ(builder.FinalPolicies(), expected_policies); |
| |
| builder.ComputePoliciesForError(); |
| EXPECT_EQ(builder.FinalPolicies(), expected_policies); |
| } |
| |
| // CSP delivered by the HTTP response are ignored for error document. |
| TEST_F(NavigationPolicyContainerBuilderTest, |
| DeliveredCSPIgnoredForErrorDocument) { |
| NavigationPolicyContainerBuilder builder( |
| nullptr, nullptr, kInvalidChildProcessUniqueId, nullptr, nullptr); |
| builder.AddContentSecurityPolicy( |
| network::mojom::ContentSecurityPolicy::New()); |
| |
| MockNavigationHandle navigation_handle(GURL("https://foo.test"), nullptr); |
| builder.ComputePolicies(&navigation_handle, false, |
| network::mojom::WebSandboxFlags::kNone, |
| /*is_credentialless=*/false); |
| EXPECT_THAT(builder.FinalPolicies().content_security_policies, SizeIs(1)); |
| |
| builder.ComputePoliciesForError(); |
| EXPECT_THAT(builder.FinalPolicies().content_security_policies, SizeIs(0)); |
| } |
| |
| // Verifies that InitiatorPolicies() returns nullptr in the absence of an |
| // initiator frame token. |
| TEST_F(NavigationPolicyContainerBuilderTest, |
| InitiatorPoliciesWithoutInitiator) { |
| EXPECT_THAT( |
| NavigationPolicyContainerBuilder( |
| nullptr, nullptr, kInvalidChildProcessUniqueId, nullptr, nullptr) |
| .InitiatorPolicies(), |
| IsNull()); |
| } |
| |
| // Verifies that ParentPolicies returns nullptr in the absence of a parent. |
| TEST_F(NavigationPolicyContainerBuilderTest, ParentPoliciesWithoutParent) { |
| EXPECT_THAT( |
| NavigationPolicyContainerBuilder( |
| nullptr, nullptr, kInvalidChildProcessUniqueId, nullptr, nullptr) |
| .ParentPolicies(), |
| IsNull()); |
| } |
| |
| // Verifies that ParentPolicies returns a pointer to a copy of the parent's |
| // policies. |
| TEST_F(NavigationPolicyContainerBuilderTest, ParentPoliciesWithParent) { |
| PolicyContainerPolicies parent_policies = MakeTestPolicies(); |
| |
| TestRenderFrameHost* parent = contents()->GetPrimaryMainFrame(); |
| parent->SetPolicyContainerHost(NewHost(parent_policies.Clone())); |
| |
| NavigationPolicyContainerBuilder builder( |
| parent, nullptr, kInvalidChildProcessUniqueId, nullptr, nullptr); |
| |
| EXPECT_THAT(builder.ParentPolicies(), Pointee(Eq(ByRef(parent_policies)))); |
| } |
| |
| // Verifies that when the the URL of the document to commit is `about:srcdoc`, |
| // the builder's final policies are copied from the parent. |
| TEST_F(NavigationPolicyContainerBuilderTest, |
| FinalPoliciesAboutSrcdocWithParent) { |
| PolicyContainerPolicies parent_policies = MakeTestPolicies(); |
| |
| TestRenderFrameHost* parent = contents()->GetPrimaryMainFrame(); |
| parent->SetPolicyContainerHost(NewHost(parent_policies.Clone())); |
| |
| NavigationPolicyContainerBuilder builder( |
| parent, nullptr, kInvalidChildProcessUniqueId, nullptr, nullptr); |
| MockNavigationHandle navigation_handle(AboutSrcdocUrl(), nullptr); |
| builder.ComputePolicies(&navigation_handle, false, |
| network::mojom::WebSandboxFlags::kNone, |
| /*is_credentialless=*/false); |
| |
| EXPECT_EQ(builder.FinalPolicies(), parent_policies); |
| } |
| |
| // Verifies that when a document has a potentially-trustworthy origin and no |
| // parent, then it is a secure context. |
| TEST_F(NavigationPolicyContainerBuilderTest, |
| IsWebSecureContextTrustworthyOriginNoParent) { |
| NavigationPolicyContainerBuilder builder( |
| nullptr, nullptr, kInvalidChildProcessUniqueId, nullptr, nullptr); |
| |
| builder.SetIsOriginPotentiallyTrustworthy(true); |
| |
| PolicyContainerPolicies delivered_policies = |
| builder.DeliveredPoliciesForTesting().Clone(); |
| EXPECT_TRUE(delivered_policies.is_web_secure_context); |
| |
| MockNavigationHandle navigation_handle(GURL(), nullptr); |
| builder.ComputePolicies(&navigation_handle, false, |
| network::mojom::WebSandboxFlags::kNone, |
| /*is_credentialless=*/false); |
| |
| EXPECT_EQ(builder.FinalPolicies(), delivered_policies); |
| } |
| |
| // Verifies that when a document has a non-potentially-trustworthy origin and no |
| // parent, then it is not a secure context. |
| TEST_F(NavigationPolicyContainerBuilderTest, |
| IsWebSecureContextNonTrustworthyOriginNoParent) { |
| NavigationPolicyContainerBuilder builder( |
| nullptr, nullptr, kInvalidChildProcessUniqueId, nullptr, nullptr); |
| |
| builder.SetIsOriginPotentiallyTrustworthy(false); |
| |
| PolicyContainerPolicies delivered_policies = |
| builder.DeliveredPoliciesForTesting().Clone(); |
| EXPECT_FALSE(delivered_policies.is_web_secure_context); |
| |
| MockNavigationHandle navigation_handle(GURL(), nullptr); |
| builder.ComputePolicies(&navigation_handle, false, |
| network::mojom::WebSandboxFlags::kNone, |
| /*is_credentialless=*/false); |
| |
| EXPECT_EQ(builder.FinalPolicies(), delivered_policies); |
| } |
| |
| // Verifies that when a document has a potentially-trustworthy origin and a |
| // parent that is not a secure context, then it is not a secure context. |
| TEST_F(NavigationPolicyContainerBuilderTest, |
| IsWebSecureContextTrustworthyOriginNonSecureParent) { |
| PolicyContainerPolicies parent_policies = MakeTestPolicies(); |
| parent_policies.is_web_secure_context = false; |
| |
| TestRenderFrameHost* parent = contents()->GetPrimaryMainFrame(); |
| parent->SetPolicyContainerHost(NewHost(std::move(parent_policies))); |
| |
| NavigationPolicyContainerBuilder builder( |
| parent, nullptr, kInvalidChildProcessUniqueId, nullptr, nullptr); |
| |
| builder.SetIsOriginPotentiallyTrustworthy(true); |
| |
| MockNavigationHandle navigation_handle(GURL("https://foo.test"), nullptr); |
| builder.ComputePolicies(&navigation_handle, false, |
| network::mojom::WebSandboxFlags::kNone, |
| /*is_credentialless=*/false); |
| |
| EXPECT_FALSE(builder.FinalPolicies().is_web_secure_context); |
| } |
| |
| // Verifies that when a document has a non-potentially-trustworthy origin and a |
| // parent that is a secure context, then it is not a secure context. |
| TEST_F(NavigationPolicyContainerBuilderTest, |
| IsWebSecureContextNonTrustworthyOriginSecureParent) { |
| PolicyContainerPolicies parent_policies = MakeTestPolicies(); |
| parent_policies.is_web_secure_context = true; |
| |
| TestRenderFrameHost* parent = contents()->GetPrimaryMainFrame(); |
| parent->SetPolicyContainerHost(NewHost(std::move(parent_policies))); |
| |
| NavigationPolicyContainerBuilder builder( |
| parent, nullptr, kInvalidChildProcessUniqueId, nullptr, nullptr); |
| |
| builder.SetIsOriginPotentiallyTrustworthy(false); |
| |
| PolicyContainerPolicies delivered_policies = |
| builder.DeliveredPoliciesForTesting().Clone(); |
| EXPECT_FALSE(delivered_policies.is_web_secure_context); |
| |
| MockNavigationHandle navigation_handle(GURL("http://foo.test"), nullptr); |
| builder.ComputePolicies(&navigation_handle, false, |
| network::mojom::WebSandboxFlags::kNone, |
| /*is_credentialless=*/false); |
| |
| EXPECT_EQ(builder.FinalPolicies(), delivered_policies); |
| } |
| |
| // Verifies that when a document has a potentially-trustworthy origin and a |
| // parent that is a secure context, then it is a secure context. |
| TEST_F(NavigationPolicyContainerBuilderTest, |
| IsWebSecureContextTrustworthyOriginSecureParent) { |
| PolicyContainerPolicies parent_policies = MakeTestPolicies(); |
| parent_policies.is_web_secure_context = true; |
| |
| TestRenderFrameHost* parent = contents()->GetPrimaryMainFrame(); |
| parent->SetPolicyContainerHost(NewHost(std::move(parent_policies))); |
| |
| NavigationPolicyContainerBuilder builder( |
| parent, nullptr, kInvalidChildProcessUniqueId, nullptr, nullptr); |
| |
| builder.SetIsOriginPotentiallyTrustworthy(true); |
| |
| PolicyContainerPolicies delivered_policies = |
| builder.DeliveredPoliciesForTesting().Clone(); |
| EXPECT_TRUE(delivered_policies.is_web_secure_context); |
| |
| MockNavigationHandle navigation_handle(GURL("https://foo.test"), nullptr); |
| builder.ComputePolicies(&navigation_handle, false, |
| network::mojom::WebSandboxFlags::kNone, |
| /*is_credentialless=*/false); |
| |
| EXPECT_EQ(builder.FinalPolicies(), delivered_policies); |
| } |
| |
| // Verifies that when the the URL of the document to commit is `about:srcdoc`, |
| // the builder's final policies are copied from the parent, and additional |
| // delivered policies are merged. |
| TEST_F(NavigationPolicyContainerBuilderTest, |
| FinalPoliciesAboutSrcdocWithParentAndAdditionalCSP) { |
| PolicyContainerPolicies parent_policies = MakeTestPolicies(); |
| |
| TestRenderFrameHost* parent = contents()->GetPrimaryMainFrame(); |
| parent->SetPolicyContainerHost(NewHost(parent_policies.Clone())); |
| |
| NavigationPolicyContainerBuilder builder( |
| parent, nullptr, kInvalidChildProcessUniqueId, nullptr, nullptr); |
| |
| // Add some CSP. |
| network::mojom::ContentSecurityPolicyPtr test_csp = MakeTestCSP(); |
| builder.AddContentSecurityPolicy(test_csp.Clone()); |
| MockNavigationHandle navigation_handle(AboutSrcdocUrl(), nullptr); |
| builder.ComputePolicies(&navigation_handle, false, |
| network::mojom::WebSandboxFlags::kNone, |
| /*is_credentialless=*/false); |
| |
| parent_policies.content_security_policies.push_back(std::move(test_csp)); |
| EXPECT_EQ(builder.FinalPolicies(), parent_policies); |
| } |
| |
| // Calling ComputePolicies() twice triggers a DCHECK. |
| TEST_F(NavigationPolicyContainerBuilderTest, ComputePoliciesTwiceDCHECK) { |
| NavigationPolicyContainerBuilder builder( |
| nullptr, nullptr, kInvalidChildProcessUniqueId, nullptr, nullptr); |
| MockNavigationHandle navigation_handle(GURL("https://foo.test"), nullptr); |
| builder.ComputePolicies(&navigation_handle, false, |
| network::mojom::WebSandboxFlags::kNone, |
| /*is_credentialless=*/false); |
| EXPECT_DCHECK_DEATH(builder.ComputePolicies( |
| &navigation_handle, false, network::mojom::WebSandboxFlags::kNone, |
| /*is_credentialless=*/false)); |
| } |
| |
| // Calling ComputePolicies() followed by ComputePoliciesForError() is supported. |
| TEST_F(NavigationPolicyContainerBuilderTest, ComputePoliciesThenError) { |
| NavigationPolicyContainerBuilder builder( |
| nullptr, nullptr, kInvalidChildProcessUniqueId, nullptr, nullptr); |
| MockNavigationHandle navigation_handle(GURL("https://foo.test"), nullptr); |
| builder.ComputePolicies(&navigation_handle, false, |
| network::mojom::WebSandboxFlags::kNone, |
| /*is_credentialless=*/false); |
| builder.ComputePoliciesForError(); |
| } |
| |
| // After ComputePolicies() or ComputePoliciesForError(), the parent |
| // policies are still accessible. |
| TEST_F(NavigationPolicyContainerBuilderTest, |
| AccessParentAfterComputingPolicies) { |
| PolicyContainerPolicies parent_policies = MakeTestPolicies(); |
| TestRenderFrameHost* parent = contents()->GetPrimaryMainFrame(); |
| parent->SetPolicyContainerHost(NewHost(parent_policies.Clone())); |
| |
| NavigationPolicyContainerBuilder builder( |
| parent, nullptr, kInvalidChildProcessUniqueId, nullptr, nullptr); |
| EXPECT_THAT(builder.ParentPolicies(), Pointee(Eq(ByRef(parent_policies)))); |
| |
| MockNavigationHandle navigation_handle(GURL("https://foo.test"), nullptr); |
| builder.ComputePolicies(&navigation_handle, false, |
| network::mojom::WebSandboxFlags::kNone, |
| /*is_credentialless=*/false); |
| EXPECT_THAT(builder.ParentPolicies(), Pointee(Eq(ByRef(parent_policies)))); |
| |
| builder.ComputePoliciesForError(); |
| EXPECT_THAT(builder.ParentPolicies(), Pointee(Eq(ByRef(parent_policies)))); |
| } |
| |
| // Verifies that the parent policies are preserved on |
| // ResetForCrossDocumentRestart. |
| TEST_F(NavigationPolicyContainerBuilderTest, |
| ResetForCrossDocumentRestartParentPolicies) { |
| PolicyContainerPolicies parent_policies = MakeTestPolicies(); |
| |
| TestRenderFrameHost* parent = contents()->GetPrimaryMainFrame(); |
| parent->SetPolicyContainerHost(NewHost(parent_policies.Clone())); |
| |
| NavigationPolicyContainerBuilder builder( |
| parent, nullptr, kInvalidChildProcessUniqueId, nullptr, nullptr); |
| MockNavigationHandle navigation_handle(GURL("https://foo.test"), nullptr); |
| builder.ComputePolicies(&navigation_handle, false, |
| network::mojom::WebSandboxFlags::kNone, |
| /*is_credentialless=*/false); |
| EXPECT_EQ(builder.FinalPolicies(), PolicyContainerPolicies()); |
| |
| builder.ResetForCrossDocumentRestart(); |
| EXPECT_THAT(builder.ParentPolicies(), Pointee(Eq(ByRef(parent_policies)))); |
| |
| navigation_handle.set_url(AboutSrcdocUrl()); |
| builder.ComputePolicies(&navigation_handle, false, |
| network::mojom::WebSandboxFlags::kNone, |
| /*is_credentialless=*/false); |
| EXPECT_EQ(builder.FinalPolicies(), parent_policies); |
| } |
| |
| } // namespace |
| } // namespace content |