Origin Policy: Web Platform Tests for Origin Policy w/ CSP.
These tests follow the format currently under discussion here:
https://github.com/WICG/origin-policy/pull/39
Bug: 751996
Change-Id: Ief33c794498cb3ed84dac670ecff4ddc366b9592
Reviewed-on: https://chromium-review.googlesource.com/1130531
Reviewed-by: Mike West <[email protected]>
Commit-Queue: Daniel Vogelheim <[email protected]>
Cr-Commit-Position: refs/heads/master@{#580876}
diff --git a/third_party/WebKit/LayoutTests/TestExpectations b/third_party/WebKit/LayoutTests/TestExpectations
index a8dd25f8..2edadf7 100644
--- a/third_party/WebKit/LayoutTests/TestExpectations
+++ b/third_party/WebKit/LayoutTests/TestExpectations
@@ -4623,6 +4623,10 @@
crbug.com/853360 [ Mac ] fast/forms/calendar-picker/month-picker-appearance.html [ Failure ]
crbug.com/853360 [ Mac ] fast/forms/select/menulist-appearance-rtl.html [ Failure ]
+# Origin Policy: Skip tests that rely on --feature-enabled=OriginPolicy, so
+# they can be run via virtual/origin-policy instead.
+crbug.com/751996 external/wpt/origin-policy [ Skip ]
+
# Sheriff 2018-06-18
crbug.com/853852 [ Win7 Linux ] virtual/threaded/external/wpt/feature-policy/experimental-features/vertical-scroll-wheel-block-manual.tentative.html [ Pass Timeout ]
crbug.com/853852 [ Linux ] virtual/video-surface-layer/external/wpt/feature-policy/experimental-features/vertical-scroll-touch-action-manual.tentative.html [ Skip ]
diff --git a/third_party/WebKit/LayoutTests/VirtualTestSuites b/third_party/WebKit/LayoutTests/VirtualTestSuites
index 4bbc2c7..bf3ea3a1 100644
--- a/third_party/WebKit/LayoutTests/VirtualTestSuites
+++ b/third_party/WebKit/LayoutTests/VirtualTestSuites
@@ -712,5 +712,10 @@
"prefix": "mojo-blob-urls",
"base": "external/wpt/FileAPI/url",
"args": ["--enable-features=MojoBlobURLs"]
+ },
+ {
+ "prefix": "origin-policy",
+ "base": "external/wpt/origin-policy",
+ "args": ["--enable-features=OriginPolicy"]
}
]
diff --git a/third_party/WebKit/LayoutTests/external/wpt/.well-known/origin-policy/policy-csp-1 b/third_party/WebKit/LayoutTests/external/wpt/.well-known/origin-policy/policy-csp-1
new file mode 100644
index 0000000..adbfc362
--- /dev/null
+++ b/third_party/WebKit/LayoutTests/external/wpt/.well-known/origin-policy/policy-csp-1
@@ -0,0 +1,3 @@
+{
+ "content-security-policy": [{ "policy": "script-src 'self' 'unsafe-inline'" }]
+}
diff --git a/third_party/WebKit/LayoutTests/external/wpt/.well-known/origin-policy/policy-csp-2 b/third_party/WebKit/LayoutTests/external/wpt/.well-known/origin-policy/policy-csp-2
new file mode 100644
index 0000000..e896da3
--- /dev/null
+++ b/third_party/WebKit/LayoutTests/external/wpt/.well-known/origin-policy/policy-csp-2
@@ -0,0 +1,5 @@
+{
+ "content-security-policy": [{
+ "policy": "script-src 'self' 'nonce-test'"
+ }]
+}
diff --git a/third_party/WebKit/LayoutTests/external/wpt/.well-known/origin-policy/policy-noimg b/third_party/WebKit/LayoutTests/external/wpt/.well-known/origin-policy/policy-noimg
new file mode 100644
index 0000000..fce2d40
--- /dev/null
+++ b/third_party/WebKit/LayoutTests/external/wpt/.well-known/origin-policy/policy-noimg
@@ -0,0 +1,3 @@
+{
+ "content-security-policy": [{ "policy": "img-src 'none'" }]
+}
diff --git a/third_party/WebKit/LayoutTests/external/wpt/origin-policy/origin-policy-single-report.https.tentative.html b/third_party/WebKit/LayoutTests/external/wpt/origin-policy/origin-policy-single-report.https.tentative.html
new file mode 100644
index 0000000..24ee8999
--- /dev/null
+++ b/third_party/WebKit/LayoutTests/external/wpt/origin-policy/origin-policy-single-report.https.tentative.html
@@ -0,0 +1,30 @@
+<!DOCTYPE HTML>
+<html>
+<head>
+ <script src='/https/chromium.googlesource.com/resources/testharness.js'></script>
+ <script src='/https/chromium.googlesource.com/resources/testharnessreport.js'></script>
+</head>
+<body>
+ <iframe id=frame></iframe>
+ <script>
+ async_test(t => {
+ let violations = [];
+ window.addEventListener("message", (e) => {
+ violations.push(e);
+ t.step_timeout(() => {
+ assert_equals(violations.length, 1);
+ t.done();
+ });
+ });
+
+ let forbidden_image = "<img src=https://127.0.0.1:1234/bla.jpg>";
+ let event_bouncer = "<script>document.addEventListener(" +
+ "'securitypolicyviolation'," +
+ "(e) => window.parent.postMessage(e.blockedURI, '*'));</sc" +
+ "ript>";
+ document.getElementById("frame").src =
+ "data:text/html;charset=utf-8," + event_bouncer + forbidden_image;
+ }, "Origin-Policy-based CSP violation should trigger 1 violation event");
+ </script>
+</body>
+</html>
diff --git a/third_party/WebKit/LayoutTests/external/wpt/origin-policy/origin-policy-single-report.https.tentative.html.headers b/third_party/WebKit/LayoutTests/external/wpt/origin-policy/origin-policy-single-report.https.tentative.html.headers
new file mode 100644
index 0000000..cb596cf
--- /dev/null
+++ b/third_party/WebKit/LayoutTests/external/wpt/origin-policy/origin-policy-single-report.https.tentative.html.headers
@@ -0,0 +1 @@
+Sec-Origin-Policy: policy-noimg
diff --git a/third_party/WebKit/LayoutTests/external/wpt/origin-policy/origin-policy.https.tentative.html b/third_party/WebKit/LayoutTests/external/wpt/origin-policy/origin-policy.https.tentative.html
new file mode 100644
index 0000000..34a71fe
--- /dev/null
+++ b/third_party/WebKit/LayoutTests/external/wpt/origin-policy/origin-policy.https.tentative.html
@@ -0,0 +1,143 @@
+<!DOCTYPE HTML>
+<html>
+<head>
+ <script src='/https/chromium.googlesource.com/resources/testharness.js'></script>
+ <script src='/https/chromium.googlesource.com/resources/testharnessreport.js'></script>
+</head>
+<body>
+ <div id=log></div>
+ <iframe id=frame></iframe>
+ <script>
+ // Navigate the frame to a test page with the given policy and wait for
+ // postMessage to arrive. Resolve the result promise with the message.
+ function navigate(policy) {
+ return new Promise(resolve => {
+ window.addEventListener("message", event => { resolve(event.data); },
+ { once: true });
+ document.getElementById("frame").src =
+ "/origin-policy/sec-origin-policy-header.html.py?policy=" + policy;
+ });
+ }
+
+ // Check whether the message returned from the frame meets our expectations.
+ function expect(expect_script, expect_eval, message) {
+ assert_own_property(message, "inline_allowed");
+ assert_own_property(message, "eval_allowed");
+ assert_equals(message.inline_allowed, expect_script);
+ assert_equals(message.eval_allowed, expect_eval);
+ }
+
+ // Generate a more descriptive error message. Re-throw the error.
+ function descriptive_message(policy, expect_inline, expect_eval,
+ index, error) {
+ error.message = `Error occured on entry #${index + 1} ["${policy
+ }", ${expect_inline}, ${expect_eval}]: "${error}".`;
+ throw(error);
+ }
+
+ // Run the navigation + expectation checking for one test case line.
+ function test_case_entry([policy, expect_inline, expect_eval], index) {
+ return navigate(policy)
+ .then(message => expect(expect_inline, expect_eval, message))
+
+ // This catch handler merely logs a more friendly message,
+ // pointing you to the exact line of the failing test.
+ .catch(error => descriptive_message(policy, expect_inline,
+ expect_eval, index, error));
+ }
+
+ function origin_policy_csp_test_case(test_case_list) {
+ return t => {
+ // Setup the promise chain for the test.
+ let chain = Promise.resolve();
+ for ([index, val] of test_case_list.entries())
+ chain = chain.then(test_case_entry.bind(this, val, index));
+
+ // Delete the policy as the last element of the chain, on both
+ // resolve + reject paths, so that a left-over policy won't break
+ // subsequent tests.
+ return chain.then(() => navigate("0"),
+ (error) => { navigate("0"); throw error; });
+ }
+ }
+
+
+ // Sanity check: A request with no policy.
+ promise_test(origin_policy_csp_test_case([
+ ["", true, true], // No policy.
+ ]), "sanity check");
+
+ // Basic functionality. A policy should have an effect.
+ promise_test(origin_policy_csp_test_case([
+ ["", true, true], // No policy.
+ ["policy-csp-1", true, false], // policy-csp-1, which forbids eval.
+ ["0", true, true], // Delete the policy again.
+ ]), "The basics: A policy should have an effect..");
+
+ // Basic functionality. Set a policy. Make sure it "sticks".
+ promise_test(origin_policy_csp_test_case([
+ ["", true, true], // No policy.
+ ["policy-csp-1", true, false], // policy-csp-1, which forbids eval.
+ ["", true, false], // No policy. Should remember p...-csp-1.
+ ["0", true, true], // Delete the policy again.
+ ]), "The basics: A policy should stick.");
+
+ // Set, update, and delete a policy.
+ promise_test(origin_policy_csp_test_case([
+ ["", true, true],
+ ["policy-csp-1", true, false], // policy-csp-1, which forbids eval.
+ ["policy-csp-2", false, false], // policy-csp-2, forbids script + eval.
+ ["0", true, true], // Delete the policy.
+ ]), "Policy set, update, and delete.");
+
+ // Set, update, and delete a policy. Check on each step whether it 'sticks'.
+ promise_test(origin_policy_csp_test_case([
+ ["", true, true],
+ ["policy-csp-1", true, false], // policy-csp-1, which forbids eval.
+ ["", true, false],
+ ["policy-csp-2", false, false], // Forbid script + eval.
+ ["", false, false],
+ ["0", true, true], // Delete the policy.
+ ["", true, true],
+ ]), "Policy set-update-delete cycle with checks.");
+
+ // Set a policy, update, then revert to the old one.
+ promise_test(origin_policy_csp_test_case([
+ ["", true, true],
+ ["policy-csp-1", true, false], // policy-csp-1, which forbids eval.
+ ["policy-csp-2", false, false], // Forbid script + eval.
+ ["policy-csp-1", true, false], // policy-csp-1 again.
+ ["0", true, true],
+ ]), "Policy set-update-delete cycle.");
+
+ // Set, delete, re-set, and re-delete a policy.
+ promise_test(origin_policy_csp_test_case([
+ ["", true, true], // No policy.
+ ["policy-csp-1", true, false], // policy-csp-1, which forbids eval.
+ ["", true, false],
+ ["0", true, true], // Delete the policy.
+ ["", true, true],
+ ["policy-csp-1", true, false], // Set policy after policy was deleted.
+ ["", true, false],
+ ["0", true, true], // Delete the policy again.
+ ["", true, true],
+ ]), "Policy re-set and re-delete.");
+
+ // We've had some bugs with repeated policies being set, so lets just
+ // run through a set-update-delete cycle but with every request being
+ // made twice.
+ promise_test(origin_policy_csp_test_case([
+ ["", true, true],
+ ["", true, true],
+ ["policy-csp-1", true, false],
+ ["policy-csp-1", true, false],
+ ["policy-csp-2", false, false],
+ ["policy-csp-2", false, false],
+ ["0", true, true],
+ ["0", true, true],
+ ["", true, true],
+ ["", true, true],
+ ]), "Double Trouble");
+ </script>
+</body>
+</html>
diff --git a/third_party/WebKit/LayoutTests/external/wpt/origin-policy/sec-origin-policy-header.html.py b/third_party/WebKit/LayoutTests/external/wpt/origin-policy/sec-origin-policy-header.html.py
new file mode 100644
index 0000000..8e62b6c2
--- /dev/null
+++ b/third_party/WebKit/LayoutTests/external/wpt/origin-policy/sec-origin-policy-header.html.py
@@ -0,0 +1,64 @@
+def main(request, response):
+ """Send a response with the origin policy indicated by the ?policy= argument.
+
+ Won't send a policy when the browser doesn't indicate support.
+ The response tests whether inline script and eval are allowed, and will
+ send a corresponding message to the parent frame.
+ For easier debugging, we'll also show the results in-page.
+ """
+ origin_policy_header = "Sec-Origin-Policy"
+ request_policy = request.headers.get(origin_policy_header)
+ response_policy = request.GET.first("policy", default="")
+
+ if request_policy and response_policy:
+ response.headers.set(origin_policy_header, response_policy)
+ response.headers.set("Vary", "sec-origin-policy")
+
+ response.headers.set("Content-Type", "text/html");
+ return """
+ <html>
+ <head>
+ <title>Page with an Origin Policy</title>
+ </head>
+ <body>
+ <script nonce=test>
+ let inlineAllowed = false;
+ let evalAllowed = false;
+ try { eval('evalAllowed = true;'); } catch (e) {};
+ </script>
+ <script>
+ inlineAllowed = true;
+ </script>
+
+ <p>Reveal whether CSP with "unsafe-inline" or "unsafe-eval" is present:</p>
+ <ul>
+ <li>inline script allowed: <span id=inline_allowed></span></li>
+ <li>eval allowed: <span id=eval_allowed></span></li>
+ </ul>
+
+ <script nonce=test>
+ const result = {
+ "inline_allowed": inlineAllowed,
+ "eval_allowed": evalAllowed,
+ };
+
+ // Mirror content into the page for easy debugging:
+ const styles = {
+ true: "font-weight: bold; color: green;",
+ false: "font-weight: bold; color: red",
+ }
+ for (const [key, value] of Object.entries(result)) {
+ let element = document.getElementById(key);
+ element.textContent = value.toString();
+ element.style = styles[value];
+ }
+
+ // Send result to parent frame for evaluation.
+ if (window.parent) {
+ window.parent.postMessage(result, "*");
+ }
+ </script>
+ </body>
+ </html>
+ """
+
diff --git a/third_party/WebKit/LayoutTests/virtual/origin-policy/external/wpt/origin-policy/README.txt b/third_party/WebKit/LayoutTests/virtual/origin-policy/external/wpt/origin-policy/README.txt
new file mode 100644
index 0000000..309d6722
--- /dev/null
+++ b/third_party/WebKit/LayoutTests/virtual/origin-policy/external/wpt/origin-policy/README.txt
@@ -0,0 +1,3 @@
+# This suite runs the tests in external/wpt/origin-policy with
+# --enable-blink-features=OriginPolicy.
+# Origin Policy is being standardized here: https://github.com/WICG/origin-policy