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( ...@@ -993,6 +993,11 @@ void FillNavigationParamsOriginPolicy(
if (head.origin_policy.has_value() && head.origin_policy.value().contents) { if (head.origin_policy.has_value() && head.origin_policy.value().contents) {
navigation_params->origin_policy = blink::WebOriginPolicy(); 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 = const base::Optional<std::string>& feature_policy =
head.origin_policy.value().contents->feature_policy; head.origin_policy.value().contents->feature_policy;
if (feature_policy) { if (feature_policy) {
......
...@@ -126,6 +126,7 @@ IPC_ENUM_TRAITS_MAX_VALUE(network::IsolationOptInHints, ...@@ -126,6 +126,7 @@ IPC_ENUM_TRAITS_MAX_VALUE(network::IsolationOptInHints,
network::IsolationOptInHints::ALL_HINTS_ACTIVE) network::IsolationOptInHints::ALL_HINTS_ACTIVE)
IPC_STRUCT_TRAITS_BEGIN(network::OriginPolicyContents) IPC_STRUCT_TRAITS_BEGIN(network::OriginPolicyContents)
IPC_STRUCT_TRAITS_MEMBER(ids)
IPC_STRUCT_TRAITS_MEMBER(feature_policy) IPC_STRUCT_TRAITS_MEMBER(feature_policy)
IPC_STRUCT_TRAITS_MEMBER(content_security_policies) IPC_STRUCT_TRAITS_MEMBER(content_security_policies)
IPC_STRUCT_TRAITS_MEMBER(content_security_policies_report_only) IPC_STRUCT_TRAITS_MEMBER(content_security_policies_report_only)
......
...@@ -16,6 +16,9 @@ namespace blink { ...@@ -16,6 +16,9 @@ namespace blink {
// Origin Policy spec: https://wicg.github.io/origin-policy/ // Origin Policy spec: https://wicg.github.io/origin-policy/
struct BLINK_EXPORT WebOriginPolicy { 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. // The feature policy that is dictated by the origin policy, if any.
// https://w3c.github.io/webappsec-feature-policy/ // https://w3c.github.io/webappsec-feature-policy/
WebString feature_policy; WebString feature_policy;
......
...@@ -1490,6 +1490,14 @@ void LocalDOMWindow::queueMicrotask(V8VoidFunction* callback) { ...@@ -1490,6 +1490,14 @@ void LocalDOMWindow::queueMicrotask(V8VoidFunction* callback) {
WrapPersistent(callback), nullptr)); 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, int LocalDOMWindow::requestIdleCallback(V8IdleRequestCallback* callback,
const IdleRequestOptions* options) { const IdleRequestOptions* options) {
if (Document* document = this->document()) { if (Document* document = this->document()) {
......
...@@ -272,6 +272,10 @@ class CORE_EXPORT LocalDOMWindow final : public DOMWindow, ...@@ -272,6 +272,10 @@ class CORE_EXPORT LocalDOMWindow final : public DOMWindow,
// https://html.spec.whatwg.org/C/#windoworworkerglobalscope-mixin // https://html.spec.whatwg.org/C/#windoworworkerglobalscope-mixin
void queueMicrotask(V8VoidFunction*); 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 // Idle callback extensions
int requestIdleCallback(V8IdleRequestCallback*, const IdleRequestOptions*); int requestIdleCallback(V8IdleRequestCallback*, const IdleRequestOptions*);
void cancelIdleCallback(int id); void cancelIdleCallback(int id);
...@@ -412,6 +416,8 @@ class CORE_EXPORT LocalDOMWindow final : public DOMWindow, ...@@ -412,6 +416,8 @@ class CORE_EXPORT LocalDOMWindow final : public DOMWindow,
String status_; String status_;
String default_status_; String default_status_;
Vector<String> origin_policy_ids_;
mutable Member<ApplicationCache> application_cache_; mutable Member<ApplicationCache> application_cache_;
scoped_refptr<SerializedScriptValue> pending_state_object_; scoped_refptr<SerializedScriptValue> pending_state_object_;
......
...@@ -89,8 +89,10 @@ ...@@ -89,8 +89,10 @@
// WindowOrWorkerGlobalScope mixin // WindowOrWorkerGlobalScope mixin
// https://html.spec.whatwg.org/C/#windoworworkerglobalscope-mixin // https://html.spec.whatwg.org/C/#windoworworkerglobalscope-mixin
// https://wicg.github.io/origin-policy/#monkeypatch-html-windoworworkerglobalscope
[Replaceable] readonly attribute DOMString origin; [Replaceable] readonly attribute DOMString origin;
void queueMicrotask(VoidFunction callback); void queueMicrotask(VoidFunction callback);
[RuntimeEnabled=OriginPolicy, SameObject, SaveSameObject] readonly attribute FrozenArray<DOMString> originPolicyIds;
// AnimationFrameProvider mixin // AnimationFrameProvider mixin
// https://html.spec.whatwg.org/C/#animation-frames // https://html.spec.whatwg.org/C/#animation-frames
......
...@@ -109,6 +109,7 @@ ...@@ -109,6 +109,7 @@
#include "third_party/blink/renderer/platform/wtf/text/string_builder.h" #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/string_utf8_adaptor.h"
#include "third_party/blink/renderer/platform/wtf/text/wtf_string.h" #include "third_party/blink/renderer/platform/wtf/text/wtf_string.h"
#include "third_party/blink/renderer/platform/wtf/vector.h"
namespace blink { namespace blink {
...@@ -1551,6 +1552,15 @@ void DocumentLoader::InstallNewDocument( ...@@ -1551,6 +1552,15 @@ void DocumentLoader::InstallNewDocument(
if (frame_->GetDocument()) if (frame_->GetDocument())
frame_->GetDocument()->RemoveAllEventListenersRecursively(); frame_->GetDocument()->RemoveAllEventListenersRecursively();
frame_->SetDOMWindow(MakeGarbageCollected<LocalDOMWindow>(*frame_)); 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_) 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(() => { test(() => {
assert_equals(location.protocol, "https:"); assert_equals(location.protocol, "https:");
}, "Prerequisite check: running on HTTPS"); }, "Prerequisite check: running on HTTPS");
...@@ -12,6 +12,8 @@ window.runTestsInSubframe = ({ hostname, testJS }) => { ...@@ -12,6 +12,8 @@ window.runTestsInSubframe = ({ hostname, testJS }) => {
// to themselves. // to themselves.
url.searchParams.append("test", new URL(testJS, document.baseURI).pathname); url.searchParams.append("test", new URL(testJS, document.baseURI).pathname);
url.searchParams.append("expectedIds", JSON.stringify(expectedIds));
const iframe = document.createElement("iframe"); const iframe = document.createElement("iframe");
iframe.src = url.href; iframe.src = url.href;
......
...@@ -9,10 +9,12 @@ def main(request, response): ...@@ -9,10 +9,12 @@ def main(request, response):
""" """
test_file = request.GET.first("test") test_file = request.GET.first("test")
expected_ids = request.GET.first("expectedIds")
response.headers.set("Origin-Policy", "allowed=(latest)") response.headers.set("Origin-Policy", "allowed=(latest)")
response.headers.set("Content-Type", "text/html") response.headers.set("Content-Type", "text/html")
return """ ret_val = """
<!DOCTYPE html> <!DOCTYPE html>
<meta charset="utf-8"> <meta charset="utf-8">
<title>Origin policy subframe</title> <title>Origin policy subframe</title>
...@@ -24,3 +26,14 @@ def main(request, response): ...@@ -24,3 +26,14 @@ def main(request, response):
<script type="module" src="%s"></script> <script type="module" src="%s"></script>
""" % test_file """ % 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 ...@@ -11766,6 +11766,7 @@ interface webkitURL
getter onwebkittransitionend getter onwebkittransitionend
getter onwheel getter onwheel
getter origin getter origin
getter originPolicyIds
getter outerHeight getter outerHeight
getter outerWidth getter outerWidth
getter pageXOffset 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