Commit f21f4b76 authored by Domenic Denicola's avatar Domenic Denicola Committed by Commit Bot

Reland "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.

This is a re-land of
https://chromium-review.googlesource.com/c/chromium/src/+/2089994 which
was reverted in
https://chromium-review.googlesource.com/c/chromium/src/+/2093453. The
re-land adds MSAN test expectations per https://crbug.com/856601.

Bug: 1057123
Change-Id: I30053986f3dfc634399c8e0f3fc1578e062c67f0
Reviewed-on: https://chromium-review.googlesource.com/c/chromium/src/+/2095706
Auto-Submit: Domenic Denicola <domenic@chromium.org>
Commit-Queue: Kinuko Yasuda <kinuko@chromium.org>
Reviewed-by: default avatarKinuko Yasuda <kinuko@chromium.org>
Cr-Commit-Position: refs/heads/master@{#748551}
parent 9aaafe22
......@@ -1000,6 +1000,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;
......
......@@ -1307,6 +1307,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()) {
......
......@@ -224,6 +224,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);
......@@ -364,6 +368,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 {
......@@ -1564,6 +1565,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_)
......
......@@ -139,6 +139,10 @@ crbug.com/856601 [ Linux ] virtual/audio-service/external/wpt/mediacapture-strea
crbug.com/856601 [ Linux ] external/wpt/netinfo/idlharness.any.worker.html [ Pass Timeout ]
crbug.com/856601 [ Linux ] external/wpt/notifications/idlharness.https.any.html [ Pass Failure Timeout ]
crbug.com/856601 [ Linux ] external/wpt/notifications/idlharness.https.any.serviceworker.html [ Timeout Pass ]
crbug.com/856601 [ Linux ] external/wpt/origin-policy/idlharness.any.html [ Pass Timeout ]
crbug.com/856601 [ Linux ] external/wpt/origin-policy/idlharness.any.serviceworker.html [ Pass Timeout ]
crbug.com/856601 [ Linux ] external/wpt/origin-policy/idlharness.any.sharedworker.html [ Pass Timeout ]
crbug.com/856601 [ Linux ] external/wpt/origin-policy/idlharness.any.worker.html [ Pass Timeout ]
crbug.com/856601 [ Linux ] external/wpt/permissions/interfaces.any.worker.html [ Pass Timeout ]
crbug.com/856601 [ Linux ] external/wpt/pointerevents/idlharness.window.html [ Pass Timeout ]
crbug.com/856601 [ Linux ] external/wpt/presentation-api/controlling-ua/idlharness.https.html [ Pass Timeout ]
......
// 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.
......@@ -11780,6 +11780,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