Skip to content

Commit

Permalink
Add WPT tests for feature policy
Browse files Browse the repository at this point in the history
1. Added tests for header policy.
    a. document.policy shows correctly parsed policy
    b. local / remote iframes without allow attribute correctly inherit
       document.policy
    c. dynamically update allow attribute updates the policy correctly.

2. Added tests for nested policies.

Bug: 732003
Change-Id: I869449f6bba89fc58997355df27249f403d76808
Reviewed-on: https://chromium-review.googlesource.com/796952
Commit-Queue: Luna Lu <[email protected]>
Reviewed-by: Ian Clelland <[email protected]>
Cr-Commit-Position: refs/heads/master@{#531698}
  • Loading branch information
loonybear authored and chromium-wpt-export-bot committed Jan 24, 2018
1 parent c522284 commit dadaf1a
Show file tree
Hide file tree
Showing 10 changed files with 310 additions and 0 deletions.
62 changes: 62 additions & 0 deletions feature-policy/feature-policy-header-policy.https.sub.html
Original file line number Diff line number Diff line change
@@ -0,0 +1,62 @@
<!DOCTYPE html>
<body>
<script src=/resources/testharness.js></script>
<script src=/resources/testharnessreport.js></script>
<script src=/feature-policy/resources/featurepolicy.js></script>
<script>
'use strict';
var same_origin = 'https://{{domains[]}}:{{ports[https][0]}}';
var cross_origin = 'https://{{domains[www]}}:{{ports[https][0]}}';
var same_origin_src = '/feature-policy/resources/feature-policy-allowedfeatures.html';
var cross_origin_src = cross_origin + same_origin_src;
var allowlists = [
{feature: 'fullscreen', allowlist: ['*']},
{feature: 'payment', allowlist: [same_origin]},
{feature: 'geolocation', allowlist: [same_origin]},
{feature: 'midi', allowlist: []},
{feature: 'camera', allowlist: [same_origin, cross_origin, 'https://www.example.com']}];

test_allowlists(
allowlists,
document.policy,
'Test allowed features in document.policy');

// sub frames should inherit the same policy from the main document.
async_test(t => {
test_allowed_features_for_subframe(
t,
['fullscreen', 'payment', 'geolocation', 'camera'],
['midi'],
same_origin_src)
}, 'Test allowed features in a same-origin iframe');
async_test(t => {
test_allowed_features_for_subframe(
t,
['fullscreen', 'camera'],
// payment and geolocation is only allowed only for self origin.
['midi', 'payment', 'geolocation'],
cross_origin_src)
}, 'Test allowed features in a cross-origin iframe');

// dynamically update sub frame's container policy
var allow = "fullscreen 'self'; payment 'src'; midi 'src'; camera 'none'; geolocation 'self' 'src'"
async_test(t => {
test_allowed_features_for_subframe(
t,
['fullscreen', 'payment', 'geolocation'],
['midi', 'camera'],
same_origin_src,
allow)
}, 'Test allowed features in a same-origin iframe with allow');

async_test(t => {
test_allowed_features_for_subframe(
t,
['payment', 'geolocation'],
['fullscreen', 'midi', 'camera'],
cross_origin_src,
allow)
}, 'Test allowed features in a cross-origin iframe with allow');

</script>
</body>
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
Feature-Policy: fullscreen *; payment 'self'; midi 'none'; camera 'self' https://{{domains[www]}}:{{ports[https][0]}} https://www.example.com; geolocation 'self'
151 changes: 151 additions & 0 deletions feature-policy/feature-policy-nested-header-policy.https.sub.html
Original file line number Diff line number Diff line change
@@ -0,0 +1,151 @@
<!DOCTYPE html>
<body>
<script src=/resources/testharness.js></script>
<script src=/resources/testharnessreport.js></script>
<script src=/feature-policy/resources/featurepolicy.js></script>
<iframe id="local-frame"></iframe>
<iframe id="remote-frame"></iframe>
<script>
'use strict';
var local_origin = 'https://{{domains[]}}:{{ports[https][0]}}';
var cross_origin = 'https://{{domains[www]}}:{{ports[https][0]}}';
var src = '/feature-policy/resources/feature-policy-nested-subframe-policy.https.sub.html'

/*
Top-level Feature Policy:
midi 'none'; payment 'self'; camera *; usb 'self'; vr *;
fullscreen https://{{domains[www]}}:{{ports[https][0]}};
accelerometer https://{{domains[www]}}:{{ports[https][0]}};
1st layer iframe (feature-policy-nested-subframe-policy.https.sub.html) Feature Policy:
midi *; payment 'self'; camera 'self'; usb *; vr 'none'; fullscreen 'self'; accelerometer *;
2nd layer iframe (feature-policy-subframe-policy.https.sub.html) Feature Policy:
midi *; payment 'self'; camera *; usb 'self'; vr *; fullscreen 'self'; accelerometer *;
----------------------------------------------------------------------------
| Top-level Feature Policy |
| ---------------------------------------------------------------------- |
| | 1st layer iframe Feature Policy (same origin / cross origin) | |
| | ---------------------------------------------------------------- | |
| | | 2nd layer iframe Feature Policy (same origin / cross origin) | | |
| | |______________________________________________________________| | |
| |____________________________________________________________________| |
|__________________________________________________________________________|
'payment' is enabled for 'self' at the top-level and through the chain of
same-origin frames but disabled in cross-origin frames and descendents of a
any cross-origin frame.
'fullscreen' is enabled on cross origin at the top-level, then enabled only
for 'self' in the subframes. So a same-origin frame embedded in a
cross-origin frame has 'fullscreen' enabled, but a cross-origin frame
embedded in a cross-origin frame has 'fullscreen' disabled.
'camera' is enabled at the top-level but blocked by subframe.
A-B-A: enabled A-A-B: disabled A-A-A: enabled; A-B-A: enabled
'accelerometer' is only enabled on cross origin at the top-level, but enabled
by cross-origin subframe.
'usb' is only enabled for 'self' at the top-level but then enabled for all
by subframe.
'midi' is disabled everywhere.
'vr' is disabled by the first layer subframe.
*/

async_test(t => {
let local_frame = document.createElement('iframe');
local_frame.src = local_origin + src;
let remote_frame = document.createElement('iframe');
remote_frame.src = cross_origin + src;
var frame_count = 0;

window.addEventListener('message', t.step_func(function handler(evt) {
var data = evt.data;
if (evt.source === local_frame.contentWindow) {
if (data.frame === 'local') {
assert_true(data.allowedfeatures.includes('payment'),
'Top-level>Local-iframe>Local-iframe: payment enabled');
assert_false(data.allowedfeatures.includes('fullscreen'),
'top-level>local-iframe>local-iframe: fullscreen disabled');
assert_true(data.allowedfeatures.includes('camera'),
'Top-level>Local-iframe>Local-iframe: camera enabled');
assert_false(data.allowedfeatures.includes('accelerometer'),
'Top-level>Local-iframe>Local-iframe: accelerometer disabled');
assert_true(data.allowedfeatures.includes('usb'),
'Top-level>Local-iframe>Local-iframe: usb enabled');
assert_false(data.allowedfeatures.includes('midi'),
'top-level>local-iframe>local-iframe: midi disabled');
assert_false(data.allowedfeatures.includes('vr'),
'top-level>local-iframe>local-iframe: vr disabled');
frame_count = frame_count + 1;
}
if (data.frame === 'remote') {
assert_false(data.allowedfeatures.includes('payment'),
'Top-level>Local-iframe>Remote-iframe: payment disabled');
assert_false(data.allowedfeatures.includes('fullscreen'),
'Top-level>Local-iframe>Remote-iframe: fullscreen disabled');
assert_false(data.allowedfeatures.includes('camera'),
'Top-level>Local-iframe>Remote-iframe: camera disabled');
assert_false(data.allowedfeatures.includes('accelerometer'),
'Top-level>Local-iframe>Remote-iframe: accelerometer disabled');
assert_true(data.allowedfeatures.includes('usb'),
'Top-level>Local-iframe>Remote-iframe: usb enabled');
assert_false(data.allowedfeatures.includes('midi'),
'Top-level>Local-iframe>Remote-iframe: midi disabled');
assert_false(data.allowedfeatures.includes('vr'),
'Top-level>Local-iframe>Remote-iframe: vr disabled');
frame_count = frame_count + 1;
}
}
if (evt.source === remote_frame.contentWindow) {
if (data.frame === 'local') {
assert_false(data.allowedfeatures.includes('payment'),
'Top-level>Remote-iframe>Local-iframe: payment disabled');
assert_true(data.allowedfeatures.includes('fullscreen'),
'Top-level>Remote-iframe>Local-iframe: fullscreen enabled');
assert_true(data.allowedfeatures.includes('camera'),
'Top-level>Remote-iframe>Local-iframe: camera enabled');
assert_true(data.allowedfeatures.includes('accelerometer'),
'Top-level>Remote-iframe>Local-iframe: accelerometer enabled');
assert_false(data.allowedfeatures.includes('usb'),
'Top-level>Remote-iframe>Local-iframe: usb disabled');
assert_false(data.allowedfeatures.includes('midi'),
'Top-level>Remote-iframe>Local-iframe: midi disabled');
assert_false(data.allowedfeatures.includes('vr'),
'Top-level>Remote-iframe>Local-iframe: vr disabled');
frame_count = frame_count + 1;
}
if (data.frame === 'remote') {
assert_false(data.allowedfeatures.includes('payment'),
'Top-level>Remote-iframe>Remote-iframe: payment disabled');
assert_false(data.allowedfeatures.includes('fullscreen'),
'Top-level>Remote-iframe>Remote-iframe: fullscreen disabled');
assert_false(data.allowedfeatures.includes('camera'),
'Top-level>Remote-iframe>Remote-iframe: camera disabled');
assert_true(data.allowedfeatures.includes('accelerometer'),
'Top-level>Remote-iframe>Remote-iframe: accelerometer enabled');
assert_false(data.allowedfeatures.includes('usb'),
'Top-level>Remote-iframe>Remote-iframe: usb disabled');
assert_false(data.allowedfeatures.includes('midi'),
'Top-level>Remote-iframe>Remote-iframe: midi disabled');
assert_false(data.allowedfeatures.includes('vr'),
'Top-level>Remote-iframe>Remote-iframe: vr disabled');
frame_count = frame_count + 1;
}
}
if (frame_count >= 4) {
window.removeEventListener('message', handler);
t.done();
}
}));

document.body.appendChild(local_frame);
document.body.appendChild(remote_frame);
}, 'Feature Policy nested test');

</script>
</body>
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
Feature-Policy: midi 'none'; payment 'self'; camera *; usb 'self'; vr *; fullscreen https://{{domains[www]}}:{{ports[https][0]}}; accelerometer https://{{domains[www]}}:{{ports[https][0]}};
7 changes: 7 additions & 0 deletions feature-policy/resources/feature-policy-allowedfeatures.html
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
<script>
'use strict';

window.onload = function() {
parent.postMessage(document.policy.allowedFeatures(), '*');
}
</script>
Original file line number Diff line number Diff line change
@@ -0,0 +1,28 @@
<!DOCTYPE html>
<body>
<script>
'use strict';
var same_origin = 'https://{{domains[]}}:{{ports[https][0]}}';
var cross_origin = 'https://{{domains[www1]}}:{{ports[https][0]}}';
var same_origin_src = '/feature-policy/resources/feature-policy-subframe-policy.https.sub.html';
var cross_origin_src = cross_origin + same_origin_src;

let local_frame = document.createElement('iframe');
let remote_frame = document.createElement('iframe');
local_frame.src = same_origin_src;
remote_frame.src = cross_origin_src;

window.addEventListener('message', function(evt) {
if (evt.source === local_frame.contentWindow) {
parent.postMessage({frame: 'local', allowedfeatures: evt.data}, '*');
}
else if (evt.source === remote_frame.contentWindow) {
parent.postMessage({frame: 'remote', allowedfeatures: evt.data}, '*');
}
});

document.body.appendChild(local_frame);
document.body.appendChild(remote_frame);
</script>
</body>

Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
Feature-Policy: midi *; payment 'self'; camera 'self'; usb *; vr 'none'; fullscreen 'self'; accelerometer *;
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
<script>
'use strict';

window.onload = function() {
parent.postMessage(document.policy.allowedFeatures(), '*');
}
</script>
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
Feature-Policy: midi *; payment 'self'; camera *; usb 'self'; vr *; fullscreen 'self'; accelerometer *;
51 changes: 51 additions & 0 deletions feature-policy/resources/featurepolicy.js
Original file line number Diff line number Diff line change
Expand Up @@ -247,3 +247,54 @@ function run_all_fp_tests_allow_all(
'Feature policy "' + feature_name +
'" can be disabled in cross-origin iframes using "allow" attribute.');
}

// This function tests that a given policy allows each feature for the correct
// list of origins specified by the |expected_policy|.
// Arguments:
// expected_policy: A list of {feature, allowlist} pairs where the feature is
// enabled for every origin in the allowlist, in the |policy|.
// policy: Either a document.policy or a iframe.policy to be tested.
// message: A short description of what policy is being tested.
function test_allowlists(expected_policy, policy, message) {
for (var allowlist of allowlists) {
test(function() {
assert_array_equals(
policy.getAllowlistForFeature(allowlist.feature),
allowlist.allowlist);
}, message + ' for feature ' + allowlist.feature);
}
}

// This function tests that a frame's policy allows and disallows features
// correctly. A feature is allowed in a frame either through inherited policy
// or specified by iframe allow attribute.
// Arguments:
// test: test created by testharness. Examples: async_test, promise_test.
// allowed_features: A list of features that should be allowed in the frame.
// disallowed_features: A list of features that should be disallowed in the
// frame.
// src: the URL to load in the frame.
// allow: the allow attribute (container policy) of the iframe
function test_allowed_features_for_subframe(
test, allowed_features, disallowed_features, src, allow) {
let frame = document.createElement('iframe');
if (typeof allow !== 'undefined') {
frame.allow = allow;
}
frame.src = src;

window.addEventListener('message', test.step_func(function handler(evt) {
if (evt.source === frame.contentWindow) {
for (var feature of allowed_features) {
assert_true(evt.data.includes(feature), feature);
}
for (var feature of disallowed_features) {
assert_false(evt.data.includes(feature), feature);
}
window.removeEventListener('message', handler);
test.done();
}
}));

document.body.appendChild(frame);
}

0 comments on commit dadaf1a

Please sign in to comment.