Bug 1474673 [wpt PR 11889] - Origin Policy: Web Platform Tests for Origin Policy w/ CSP., a=testonly
authorDaniel Vogelheim <vogelheim@chromium.org>
Wed, 08 Aug 2018 12:18:45 +0000
changeset 430945 d5849a51fa4976dd0352d95da0399edfd270c161
parent 430944 45e89feb5a66dfb031ec3c00fa785f3df4bdeb0b
child 430946 8bd1c6572b6ba9ce6265e9524562c56ab805a063
push id34417
push usernbeleuzu@mozilla.com
push dateFri, 10 Aug 2018 16:00:49 +0000
treeherdermozilla-central@61e553ff703e [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewerstestonly
bugs1474673, 11889, 751996, 1130531, 580876
milestone63.0a1
first release with
nightly linux32
nightly linux64
nightly mac
nightly win32
nightly win64
last release without
nightly linux32
nightly linux64
nightly mac
nightly win32
nightly win64
Bug 1474673 [wpt PR 11889] - Origin Policy: Web Platform Tests for Origin Policy w/ CSP., a=testonly Automatic update from web-platform-testsOrigin 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 <mkwst@chromium.org> Commit-Queue: Daniel Vogelheim <vogelheim@chromium.org> Cr-Commit-Position: refs/heads/master@{#580876} -- wpt-commits: d93204236e8ea2569900a546fe83ceb54b301e6a wpt-pr: 11889
testing/web-platform/meta/MANIFEST.json
testing/web-platform/tests/.well-known/origin-policy/policy-csp-1
testing/web-platform/tests/.well-known/origin-policy/policy-csp-2
testing/web-platform/tests/.well-known/origin-policy/policy-noimg
testing/web-platform/tests/origin-policy/origin-policy-single-report.https.tentative.html
testing/web-platform/tests/origin-policy/origin-policy-single-report.https.tentative.html.headers
testing/web-platform/tests/origin-policy/origin-policy.https.tentative.html
testing/web-platform/tests/origin-policy/sec-origin-policy-header.html.py
--- a/testing/web-platform/meta/MANIFEST.json
+++ b/testing/web-platform/meta/MANIFEST.json
@@ -190382,16 +190382,31 @@
      {}
     ]
    ],
    ".well-known/idp-proxy/mock-idp.js": [
     [
      {}
     ]
    ],
+   ".well-known/origin-policy/policy-csp-1": [
+    [
+     {}
+    ]
+   ],
+   ".well-known/origin-policy/policy-csp-2": [
+    [
+     {}
+    ]
+   ],
+   ".well-known/origin-policy/policy-noimg": [
+    [
+     {}
+    ]
+   ],
    "2dcontext/2x2.png": [
     [
      {}
     ]
    ],
    "2dcontext/2x4.png": [
     [
      {}
@@ -291102,16 +291117,26 @@
      {}
     ]
    ],
    "orientation-sensor/orientation-sensor-tests.js": [
     [
      {}
     ]
    ],
+   "origin-policy/origin-policy-single-report.https.tentative.html.headers": [
+    [
+     {}
+    ]
+   ],
+   "origin-policy/sec-origin-policy-header.html.py": [
+    [
+     {}
+    ]
+   ],
    "page-visibility/META.yml": [
     [
      {}
     ]
    ],
    "page-visibility/resources/blank_page_green.html": [
     [
      {}
@@ -376705,16 +376730,28 @@
     ]
    ],
    "orientation-sensor/idlharness.https.window.js": [
     [
      "/orientation-sensor/idlharness.https.window.html",
      {}
     ]
    ],
+   "origin-policy/origin-policy-single-report.https.tentative.html": [
+    [
+     "/origin-policy/origin-policy-single-report.https.tentative.html",
+     {}
+    ]
+   ],
+   "origin-policy/origin-policy.https.tentative.html": [
+    [
+     "/origin-policy/origin-policy.https.tentative.html",
+     {}
+    ]
+   ],
    "page-visibility/idlharness.window.js": [
     [
      "/page-visibility/idlharness.window.html",
      {}
     ]
    ],
    "page-visibility/iframe-unload.html": [
     [
@@ -421224,16 +421261,28 @@
   ".well-known/idp-proxy/README.md": [
    "dc5795cf8181178c00da9e73a4d5027cc931a64a",
    "support"
   ],
   ".well-known/idp-proxy/mock-idp.js": [
    "242b4ef56f60a3472899939426246e764e842a65",
    "support"
   ],
+  ".well-known/origin-policy/policy-csp-1": [
+   "adbfc362580842fa933bb136a9c66c9a913e6eb1",
+   "support"
+  ],
+  ".well-known/origin-policy/policy-csp-2": [
+   "e896da36303c72f1afa5ba2fdd0361e650f3125e",
+   "support"
+  ],
+  ".well-known/origin-policy/policy-noimg": [
+   "fce2d40c6e054b88938606ba9a28da94d308149a",
+   "support"
+  ],
   "2dcontext/2x2.png": [
    "9be31562b3fccadab6d36d9e892713fd4db8d476",
    "support"
   ],
   "2dcontext/2x4.png": [
    "f5589a731840441ee6052912763f3ea0436a563f",
    "support"
   ],
@@ -614828,16 +614877,32 @@
   "orientation-sensor/idlharness.https.window.js": [
    "39217fcc627653c6b6e6585bbbd6c7d46c2f7460",
    "testharness"
   ],
   "orientation-sensor/orientation-sensor-tests.js": [
    "74e360a041a90b8f72db5a88da150cf0e5fe6986",
    "support"
   ],
+  "origin-policy/origin-policy-single-report.https.tentative.html": [
+   "24ee89990548ade02ff38ab4c87d873162a88613",
+   "testharness"
+  ],
+  "origin-policy/origin-policy-single-report.https.tentative.html.headers": [
+   "cb596cf27571a57bc4826eee377fb73115f08cb7",
+   "support"
+  ],
+  "origin-policy/origin-policy.https.tentative.html": [
+   "34a71fe40a192418a3f9a5792d7ee5fdecf970dd",
+   "testharness"
+  ],
+  "origin-policy/sec-origin-policy-header.html.py": [
+   "8e62b6c2a635217b6fa02e049a68991a548c74ff",
+   "support"
+  ],
   "page-visibility/META.yml": [
    "509936c371b7de3e7e0e5f7e41d10cffba9f5d2a",
    "support"
   ],
   "page-visibility/idlharness.window.js": [
    "8ef2561b9f81d7408e45d8b7611c603f44700346",
    "testharness"
   ],
new file mode 100644
--- /dev/null
+++ b/testing/web-platform/tests/.well-known/origin-policy/policy-csp-1
@@ -0,0 +1,3 @@
+{
+  "content-security-policy": [{ "policy": "script-src 'self' 'unsafe-inline'" }]
+}
new file mode 100644
--- /dev/null
+++ b/testing/web-platform/tests/.well-known/origin-policy/policy-csp-2
@@ -0,0 +1,5 @@
+{
+  "content-security-policy": [{
+    "policy": "script-src 'self' 'nonce-test'"
+  }]
+}
new file mode 100644
--- /dev/null
+++ b/testing/web-platform/tests/.well-known/origin-policy/policy-noimg
@@ -0,0 +1,3 @@
+{
+  "content-security-policy": [{ "policy": "img-src 'none'" }]
+}
new file mode 100644
--- /dev/null
+++ b/testing/web-platform/tests/origin-policy/origin-policy-single-report.https.tentative.html
@@ -0,0 +1,30 @@
+<!DOCTYPE HTML>
+<html>
+<head>
+  <script src='/resources/testharness.js'></script>
+  <script src='/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>
new file mode 100644
--- /dev/null
+++ b/testing/web-platform/tests/origin-policy/origin-policy-single-report.https.tentative.html.headers
@@ -0,0 +1,1 @@
+Sec-Origin-Policy: policy-noimg
new file mode 100644
--- /dev/null
+++ b/testing/web-platform/tests/origin-policy/origin-policy.https.tentative.html
@@ -0,0 +1,143 @@
+<!DOCTYPE HTML>
+<html>
+<head>
+  <script src='/resources/testharness.js'></script>
+  <script src='/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>
new file mode 100644
--- /dev/null
+++ b/testing/web-platform/tests/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>
+  """
+