Commit 10bfb977 authored by Domenic Denicola's avatar Domenic Denicola Committed by Commit Bot

Origin policy: implement window.originPolicyIds

This plumbs the origin policy IDs from the net-side OriginPolicyContents
through to the renderer, where they get exposed on Window. This does not
yet tackle WorkerGlobalScope, but it does add idlharness tests for it,
which fail for now.

Bug: 1057123
Change-Id: Ie611f03bab99ccdaa6221733d9305cf2323a129e
Reviewed-on: https://chromium-review.googlesource.com/c/chromium/src/+/2089994
Commit-Queue: Domenic Denicola <domenic@chromium.org>
Reviewed-by: default avatarDaniel Cheng <dcheng@chromium.org>
Reviewed-by: default avatarJames MacLean <wjmaclean@chromium.org>
Cr-Commit-Position: refs/heads/master@{#747893}
parent c23cd6ae
......@@ -993,6 +993,11 @@ void FillNavigationParamsOriginPolicy(
if (head.origin_policy.has_value() && head.origin_policy.value().contents) {
navigation_params->origin_policy = blink::WebOriginPolicy();
for (const auto& id : head.origin_policy.value().contents->ids) {
navigation_params->origin_policy->ids.emplace_back(
WebString::FromUTF8(id));
}
const base::Optional<std::string>& feature_policy =
head.origin_policy.value().contents->feature_policy;
if (feature_policy) {
......
......@@ -126,6 +126,7 @@ IPC_ENUM_TRAITS_MAX_VALUE(network::IsolationOptInHints,
network::IsolationOptInHints::ALL_HINTS_ACTIVE)
IPC_STRUCT_TRAITS_BEGIN(network::OriginPolicyContents)
IPC_STRUCT_TRAITS_MEMBER(ids)
IPC_STRUCT_TRAITS_MEMBER(feature_policy)
IPC_STRUCT_TRAITS_MEMBER(content_security_policies)
IPC_STRUCT_TRAITS_MEMBER(content_security_policies_report_only)
......
......@@ -16,6 +16,9 @@ namespace blink {
// Origin Policy spec: https://wicg.github.io/origin-policy/
struct BLINK_EXPORT WebOriginPolicy {
// https://wicg.github.io/origin-policy/#origin-policy-ids
WebVector<WebString> ids;
// The feature policy that is dictated by the origin policy, if any.
// https://w3c.github.io/webappsec-feature-policy/
WebString feature_policy;
......
......@@ -1490,6 +1490,14 @@ void LocalDOMWindow::queueMicrotask(V8VoidFunction* callback) {
WrapPersistent(callback), nullptr));
}
const Vector<String>& LocalDOMWindow::originPolicyIds() const {
return origin_policy_ids_;
}
void LocalDOMWindow::SetOriginPolicyIds(const Vector<String>& ids) {
origin_policy_ids_ = ids;
}
int LocalDOMWindow::requestIdleCallback(V8IdleRequestCallback* callback,
const IdleRequestOptions* options) {
if (Document* document = this->document()) {
......
......@@ -272,6 +272,10 @@ class CORE_EXPORT LocalDOMWindow final : public DOMWindow,
// https://html.spec.whatwg.org/C/#windoworworkerglobalscope-mixin
void queueMicrotask(V8VoidFunction*);
// https://wicg.github.io/origin-policy/#monkeypatch-html-windoworworkerglobalscope
const Vector<String>& originPolicyIds() const;
void SetOriginPolicyIds(const Vector<String>&);
// Idle callback extensions
int requestIdleCallback(V8IdleRequestCallback*, const IdleRequestOptions*);
void cancelIdleCallback(int id);
......@@ -412,6 +416,8 @@ class CORE_EXPORT LocalDOMWindow final : public DOMWindow,
String status_;
String default_status_;
Vector<String> origin_policy_ids_;
mutable Member<ApplicationCache> application_cache_;
scoped_refptr<SerializedScriptValue> pending_state_object_;
......
......@@ -89,8 +89,10 @@
// WindowOrWorkerGlobalScope mixin
// https://html.spec.whatwg.org/C/#windoworworkerglobalscope-mixin
// https://wicg.github.io/origin-policy/#monkeypatch-html-windoworworkerglobalscope
[Replaceable] readonly attribute DOMString origin;
void queueMicrotask(VoidFunction callback);
[RuntimeEnabled=OriginPolicy, SameObject, SaveSameObject] readonly attribute FrozenArray<DOMString> originPolicyIds;
// AnimationFrameProvider mixin
// https://html.spec.whatwg.org/C/#animation-frames
......
......@@ -109,6 +109,7 @@
#include "third_party/blink/renderer/platform/wtf/text/string_builder.h"
#include "third_party/blink/renderer/platform/wtf/text/string_utf8_adaptor.h"
#include "third_party/blink/renderer/platform/wtf/text/wtf_string.h"
#include "third_party/blink/renderer/platform/wtf/vector.h"
namespace blink {
......@@ -1551,6 +1552,15 @@ void DocumentLoader::InstallNewDocument(
if (frame_->GetDocument())
frame_->GetDocument()->RemoveAllEventListenersRecursively();
frame_->SetDOMWindow(MakeGarbageCollected<LocalDOMWindow>(*frame_));
if (origin_policy_.has_value()) {
// Convert from WebVector<WebString> to WTF::Vector<WTF::String>
Vector<String> ids;
for (const auto& id : origin_policy_->ids) {
ids.push_back(id);
}
frame_->DomWindow()->SetOriginPolicyIds(ids);
}
}
if (!loading_url_as_javascript_)
......
// META: global=window,worker
// META: script=/resources/WebIDLParser.js
// META: script=/resources/idlharness.js
'use strict';
idl_test(
['origin-policy'],
['html', 'dom'],
idl_array => {
if (self.Window) {
idl_array.add_objects({ Window: ['self'] });
} else {
idl_array.add_objects({ WorkerGlobalScope: ['self'] });
}
}
);
<!DOCTYPE HTML>
<meta charset="utf-8">
<title>Origin policy with empty-array "ids" member that occurs after a non-empty "ids" member must be ignored</title>
<script src="/resources/testharness.js"></script>
<script src="/resources/testharnessreport.js"></script>
<script src="../resources/origin-policy-test-runner.js"></script>
<div id="log"></div>
<script>
"use strict";
runTestsInSubframe({
hostname: "op13",
testJS: "../content-security/resources/allow-unsafe-eval.mjs",
expectedIds: []
});
</script>
<!DOCTYPE HTML>
<meta charset="utf-8">
<title>Origin policy with empty-array "ids" member must be ignored</title>
<script src="/resources/testharness.js"></script>
<script src="/resources/testharnessreport.js"></script>
<script src="../resources/origin-policy-test-runner.js"></script>
<div id="log"></div>
<script>
"use strict";
runTestsInSubframe({
hostname: "op12",
testJS: "../content-security/resources/allow-unsafe-eval.mjs",
expectedIds: []
});
</script>
<!DOCTYPE HTML>
<meta charset="utf-8">
<title>Origin policy must include valid IDs and exclude non-strings and invalid strings</title>
<script src="/resources/testharness.js"></script>
<script src="/resources/testharnessreport.js"></script>
<script src="../resources/origin-policy-test-runner.js"></script>
<div id="log"></div>
<script>
"use strict";
runTestsInSubframe({
hostname: "op15",
testJS: "../content-security/resources/disallow-unsafe-eval-disallow-images.mjs",
expectedIds: [
"my-policy-1",
"my-policy-2",
"~",
" ",
"!\"#$%&'()*+,-./:;<=>?@{|}~",
"azAZ",
"my~policy"
]
});
</script>
<!DOCTYPE HTML>
<meta charset="utf-8">
<title>Origin policy with no "ids" member must be ignored</title>
<script src="/resources/testharness.js"></script>
<script src="/resources/testharnessreport.js"></script>
<script src="../resources/origin-policy-test-runner.js"></script>
<div id="log"></div>
<script>
"use strict";
runTestsInSubframe({
hostname: "op11",
testJS: "../content-security/resources/allow-unsafe-eval.mjs",
expectedIds: []
});
</script>
<!DOCTYPE HTML>
<meta charset="utf-8">
<title>Origin policy a non-array "ids" member must be ignored</title>
<script src="/resources/testharness.js"></script>
<script src="/resources/testharnessreport.js"></script>
<script src="../resources/origin-policy-test-runner.js"></script>
<div id="log"></div>
<script>
"use strict";
runTestsInSubframe({
hostname: "op14",
testJS: "../content-security/resources/allow-unsafe-eval.mjs",
expectedIds: []
});
</script>
<!DOCTYPE HTML>
<meta charset="utf-8">
<title>originPolicyIds must return the same object each time</title>
<script src="/resources/testharness.js"></script>
<script src="/resources/testharnessreport.js"></script>
<script>
"use strict";
test(() => {
// Failing this test is a common failure mode for FrozenArray attributes,
// so let's be sure implementations get it right.
assert_equals(window.originPolicyIds, window.originPolicyIds);
});
</script>
<!DOCTYPE HTML>
<meta charset="utf-8">
<title>originPolicyIds must return an empty array in http: pages</title>
<script src="/resources/testharness.js"></script>
<script src="/resources/testharnessreport.js"></script>
<script>
"use strict";
test(() => {
assert_equals(location.protocol, "http:");
}, "Prerequisite check: running on HTTP, not HTTPS");
test(() => {
assert_array_equals(window.originPolicyIds, []);
}, "The attribute is still present and returns an empty frozen array");
</script>
<!DOCTYPE HTML>
<meta charset="utf-8">
<title>Origin policy second "ids" member must take precedence</title>
<script src="/resources/testharness.js"></script>
<script src="/resources/testharnessreport.js"></script>
<script src="../resources/origin-policy-test-runner.js"></script>
<div id="log"></div>
<script>
"use strict";
runTestsInSubframe({
hostname: "op16",
testJS: "../content-security/resources/disallow-unsafe-eval-disallow-images.mjs",
expectedIds: [
"3",
"4"
]
});
</script>
{
"content_security": {
"policies": [
"script-src 'self' 'unsafe-inline'"
]
}
}
{
"ids": [],
"content_security": {
"policies": [
"script-src 'self' 'unsafe-inline'"
]
}
}
{
"ids": [
"this should be overwritten by the subsequent one"
],
"ids": [],
"content_security": {
"policies": [
"script-src 'self' 'unsafe-inline'"
]
}
}
{
"ids": "this is not an array",
"content_security": {
"policies": [
"script-src 'self' 'unsafe-inline'"
]
}
}
{
"ids": [
"my-policy-1",
["my-policy-array"],
5,
null,
{ "id": "my-policy-object" },
"my-policy-2",
true,
"~",
" ",
"\u0000",
"\t",
"my\tpolicy",
"!\"#$%&'()*+,-./:;<=>?@{|}~",
"my\u007Fpolicy",
"azAZ",
"my\u0080policy",
"my~policy",
"my\u1234policy"
],
"content_security": {
"policies": [
"script-src 'self' 'unsafe-inline'",
"img-src 'none'"
]
}
}
{
"ids": [
"1",
"2"
],
"ids": [
"3",
"4"
],
"content_security": {
"policies": [
"script-src 'self' 'unsafe-inline'",
"img-src 'none'"
]
}
}
window.runTestsInSubframe = ({ hostname, testJS }) => {
window.runTestsInSubframe = ({ hostname, testJS, expectedIds }) => {
test(() => {
assert_equals(location.protocol, "https:");
}, "Prerequisite check: running on HTTPS");
......@@ -12,6 +12,8 @@ window.runTestsInSubframe = ({ hostname, testJS }) => {
// to themselves.
url.searchParams.append("test", new URL(testJS, document.baseURI).pathname);
url.searchParams.append("expectedIds", JSON.stringify(expectedIds));
const iframe = document.createElement("iframe");
iframe.src = url.href;
......
......@@ -9,10 +9,12 @@ def main(request, response):
"""
test_file = request.GET.first("test")
expected_ids = request.GET.first("expectedIds")
response.headers.set("Origin-Policy", "allowed=(latest)")
response.headers.set("Content-Type", "text/html")
return """
ret_val = """
<!DOCTYPE html>
<meta charset="utf-8">
<title>Origin policy subframe</title>
......@@ -24,3 +26,14 @@ def main(request, response):
<script type="module" src="%s"></script>
""" % test_file
if expected_ids != "undefined":
ret_val += """
<script type="module">
test(() => {
assert_array_equals(originPolicyIds, %s);
}, "Expected originPolicyIDs check");
</script>
""" % expected_ids
return ret_val
This is a testharness.js-based test.
PASS idl_test setup
PASS idl_test validation
PASS Partial interface mixin WindowOrWorkerGlobalScope: original interface mixin defined
PASS Partial interface mixin WindowOrWorkerGlobalScope: member names are unique
PASS Partial interface Window: member names are unique
PASS Window includes GlobalEventHandlers: member names are unique
PASS Window includes WindowEventHandlers: member names are unique
PASS Window includes WindowOrWorkerGlobalScope: member names are unique
PASS Window includes AnimationFrameProvider: member names are unique
PASS Window includes WindowSessionStorage: member names are unique
PASS Window includes WindowLocalStorage: member names are unique
PASS WorkerGlobalScope includes WindowOrWorkerGlobalScope: member names are unique
PASS Window interface: existence and properties of interface object
FAIL WorkerGlobalScope interface: attribute originPolicyIds assert_true: The prototype object must have a property "originPolicyIds" expected true got false
FAIL WorkerGlobalScope interface: self must inherit property "originPolicyIds" with the proper type assert_inherits: property "originPolicyIds" not found in prototype chain
Harness: the test ran to completion.
This is a testharness.js-based test.
PASS idl_test setup
PASS idl_test validation
PASS Partial interface mixin WindowOrWorkerGlobalScope: original interface mixin defined
PASS Partial interface mixin WindowOrWorkerGlobalScope: member names are unique
PASS Partial interface Window: member names are unique
PASS Window includes GlobalEventHandlers: member names are unique
PASS Window includes WindowEventHandlers: member names are unique
PASS Window includes WindowOrWorkerGlobalScope: member names are unique
PASS Window includes AnimationFrameProvider: member names are unique
PASS Window includes WindowSessionStorage: member names are unique
PASS Window includes WindowLocalStorage: member names are unique
PASS WorkerGlobalScope includes WindowOrWorkerGlobalScope: member names are unique
PASS Window interface: existence and properties of interface object
FAIL WorkerGlobalScope interface: attribute originPolicyIds assert_true: The prototype object must have a property "originPolicyIds" expected true got false
FAIL WorkerGlobalScope interface: self must inherit property "originPolicyIds" with the proper type assert_inherits: property "originPolicyIds" not found in prototype chain
Harness: the test ran to completion.
This is a testharness.js-based test.
PASS idl_test setup
PASS idl_test validation
PASS Partial interface mixin WindowOrWorkerGlobalScope: original interface mixin defined
PASS Partial interface mixin WindowOrWorkerGlobalScope: member names are unique
PASS Partial interface Window: member names are unique
PASS Window includes GlobalEventHandlers: member names are unique
PASS Window includes WindowEventHandlers: member names are unique
PASS Window includes WindowOrWorkerGlobalScope: member names are unique
PASS Window includes AnimationFrameProvider: member names are unique
PASS Window includes WindowSessionStorage: member names are unique
PASS Window includes WindowLocalStorage: member names are unique
PASS WorkerGlobalScope includes WindowOrWorkerGlobalScope: member names are unique
PASS Window interface: existence and properties of interface object
FAIL WorkerGlobalScope interface: attribute originPolicyIds assert_true: The prototype object must have a property "originPolicyIds" expected true got false
FAIL WorkerGlobalScope interface: self must inherit property "originPolicyIds" with the proper type assert_inherits: property "originPolicyIds" not found in prototype chain
Harness: the test ran to completion.
......@@ -11766,6 +11766,7 @@ interface webkitURL
getter onwebkittransitionend
getter onwheel
getter origin
getter originPolicyIds
getter outerHeight
getter outerWidth
getter pageXOffset
......
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