Commit 6252427a authored by Luna Lu's avatar Luna Lu Committed by Commit Bot

Add WPT tests for feature policy

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 <loonybear@chromium.org>
Reviewed-by: default avatarIan Clelland <iclelland@chromium.org>
Cr-Commit-Position: refs/heads/master@{#531698}
parent 44583396
<!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>
Feature-Policy: fullscreen *; payment 'self'; midi 'none'; camera 'self' https://{{domains[www]}}:{{ports[https][0]}} https://www.example.com; geolocation 'self'
<!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>
Feature-Policy: midi 'none'; payment 'self'; camera *; usb 'self'; vr *; fullscreen https://{{domains[www]}}:{{ports[https][0]}}; accelerometer https://{{domains[www]}}:{{ports[https][0]}};
<script>
'use strict';
window.onload = function() {
parent.postMessage(document.policy.allowedFeatures(), '*');
}
</script>
<!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>
Feature-Policy: midi *; payment 'self'; camera 'self'; usb *; vr 'none'; fullscreen 'self'; accelerometer *;
<script>
'use strict';
window.onload = function() {
parent.postMessage(document.policy.allowedFeatures(), '*');
}
</script>
Feature-Policy: midi *; payment 'self'; camera *; usb 'self'; vr *; fullscreen 'self'; accelerometer *;
......@@ -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);
}
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment