Skip to content

Commit b90c193

Browse files
committed
Bug 1978940 [wpt PR 53937] - Create WPT for allowed_refresh_initiators, a=testonly
Automatic update from web-platform-tests Create WPT for allowed_refresh_initiators (#53937) This requires some significant work to setup cookies and requests initiated by third parties, then confirms that only initiators listed in `allowed_refresh_initiators` can actually initiate refreshes. Fixed: 401184805 Change-Id: Id773859758153dd47ae10db378ce1f6141ed5e75 Reviewed-on: https://chromium-review.googlesource.com/c/chromium/src/+/6777966 Commit-Queue: Daniel Rubery <druberychromium.org> Reviewed-by: thefrog <thefrogchromium.org> Reviewed-by: Koji Ishii <kojiichromium.org> Cr-Commit-Position: refs/heads/main{#1491069} Co-authored-by: Daniel Rubery <druberychromium.org> -- wpt-commits: 30380f06ed2b3d4c60f52a0bdc3a8ef80ed7440d wpt-pr: 53937 UltraBlame original commit: b5622511a733164045b7bf2a7f23912489b470c1
1 parent c54a205 commit b90c193

File tree

7 files changed

+113
-8
lines changed

7 files changed

+113
-8
lines changed

testing/web-platform/tests/common/get-host-info.sub.js

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -20,6 +20,7 @@ function get_host_info() {
2020
var REMOTE_HOST = (ORIGINAL_HOST === 'localhost') ? '127.0.0.1' : ('www1.' + ORIGINAL_HOST);
2121
var OTHER_HOST = '{{domains[www2]}}';
2222
var NOTSAMESITE_HOST = (ORIGINAL_HOST === 'localhost') ? '127.0.0.1' : ('{{hosts[alt][]}}');
23+
var OTHER_NOTSAMESITE_HOST = '{{hosts[alt][www2]}}';
2324

2425
return {
2526
HTTP_PORT: HTTP_PORT,
@@ -45,6 +46,7 @@ function get_host_info() {
4546
HTTPS_REMOTE_ORIGIN: 'https://' + REMOTE_HOST + HTTPS_PORT_ELIDED,
4647
HTTPS_REMOTE_ORIGIN_WITH_CREDS: 'https://foo:bar@' + REMOTE_HOST + HTTPS_PORT_ELIDED,
4748
HTTPS_NOTSAMESITE_ORIGIN: 'https://' + NOTSAMESITE_HOST + HTTPS_PORT_ELIDED,
49+
HTTPS_OTHER_NOTSAMESITE_ORIGIN: 'https://' + OTHER_NOTSAMESITE_HOST + HTTPS_PORT_ELIDED,
4850
UNAUTHENTICATED_ORIGIN: 'http://' + OTHER_HOST + HTTP_PORT_ELIDED,
4951
AUTHENTICATED_ORIGIN: 'https://' + OTHER_HOST + HTTPS_PORT_ELIDED
5052
};
Lines changed: 77 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,77 @@
1+
<!DOCTYPE html>
2+
<meta charset="utf-8">
3+
<title>DBSC session with varied initiators</title>
4+
<script src="/resources/testharness.js"></script>
5+
<script src="/resources/testharnessreport.js"></script>
6+
<script src="/common/get-host-info.sub.js"></script>
7+
<script src="helper.js" type="module"></script>
8+
9+
<script type="module">
10+
import { expireCookie, documentHasCookie, waitForCookie, addCookieAndSessionCleanup, setupShardedServerState, configureServer } from "./helper.js";
11+
12+
// Create an iframe that fetches URLs on demand via postMessage.
13+
async function createFrame(url) {
14+
const frame = document.createElement('iframe');
15+
const promise = new Promise((resolve, reject) => {
16+
frame.onload = () => resolve(frame);
17+
frame.onerror = () => {
18+
reject();
19+
};
20+
});
21+
frame.src = url;
22+
document.body.appendChild(frame);
23+
return promise;
24+
}
25+
26+
async function crossSiteFetch(frame, url) {
27+
let promise = new Promise((resolve) => {
28+
const listener = (event) => {
29+
window.removeEventListener("message", listener);
30+
resolve(event.data);
31+
};
32+
window.addEventListener("message", listener);
33+
});
34+
frame.contentWindow.postMessage(url, "*");
35+
return promise;
36+
}
37+
38+
async function runTest(t, origin, refresh_expected) {
39+
await setupShardedServerState({crossSite: true});
40+
const expectedCookieAndValue = "auth_cookie=abcdef0123";
41+
// Override the attributes to be SameSite=None.
42+
const expectedCookieAttributes = `Domain=${location.hostname};Path=/device-bound-session-credentials;SameSite=None;Secure`;
43+
const expectedCookieAndAttributes = `${expectedCookieAndValue};${expectedCookieAttributes}`;
44+
addCookieAndSessionCleanup(t);
45+
46+
configureServer({ allowedRefreshInitiators: [get_host_info().NOTSAMESITE_HOST],
47+
cookieDetails: [ {attributes: expectedCookieAttributes} ],
48+
});
49+
50+
// Prompt starting a session, and wait until registration completes.
51+
const loginResponse = await fetch('login.py');
52+
assert_equals(loginResponse.status, 200);
53+
await waitForCookie(expectedCookieAndValue, /*expectCookie=*/true);
54+
55+
const frame = await createFrame(`${origin}/device-bound-session-credentials/url_fetcher.html`);
56+
57+
// Expire the cookie, and check whether a refresh has occurred.
58+
expireCookie(expectedCookieAndAttributes);
59+
assert_false(documentHasCookie(expectedCookieAndValue));
60+
61+
const authStatusAfterExpiry = await crossSiteFetch(frame, `${location.protocol}//${location.host}/device-bound-session-credentials/verify_authenticated.py`);
62+
assert_equals(authStatusAfterExpiry, refresh_expected ? 200 : 401);
63+
assert_equals(documentHasCookie(expectedCookieAndValue), refresh_expected);
64+
}
65+
66+
promise_test(async t => {
67+
await runTest(t, location.origin, /*refresh_expected=*/true);
68+
}, "An established session refreshes when initated by the owning site");
69+
70+
promise_test(async t => {
71+
await runTest(t, get_host_info().HTTPS_NOTSAMESITE_ORIGIN, /*refresh_expected=*/true);
72+
}, "An established session refreshes when initated by a host in allowed_refresh_initiators");
73+
74+
promise_test(async t => {
75+
await runTest(t, get_host_info().HTTPS_OTHER_NOTSAMESITE_ORIGIN, /*refresh_expected=*/false);
76+
}, "An established session does not refresh when initated by a host not in allowed_refresh_initiators");
77+
</script>

testing/web-platform/tests/device-bound-session-credentials/clear-site-data.https.html

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -23,7 +23,7 @@
2323
const endSessionResponse = await fetch('end_session_via_clear_site_data.py');
2424
assert_equals(endSessionResponse.status, 200);
2525
// Need to set up the state again because all cookies were cleared.
26-
await setupShardedServerState(testId);
26+
await setupShardedServerState({testId});
2727

2828
// Expire the cookie, and confirm it does not get refreshed.
2929
expireCookie(expectedCookieAndAttributes);
@@ -48,7 +48,7 @@
4848
const endSessionResponse = await fetch('end_session_via_clear_site_data.py', {method: 'POST', body: '"storage"'});
4949
assert_equals(endSessionResponse.status, 200);
5050
// Need to set up the state again because all cookies were cleared.
51-
await setupShardedServerState(testId);
51+
await setupShardedServerState({testId});
5252

5353
// Expire the cookie, and confirm it does not get refreshed.
5454
expireCookie(expectedCookieAndAttributes);

testing/web-platform/tests/device-bound-session-credentials/helper.js

Lines changed: 3 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -49,10 +49,9 @@ export async function configureServer(obj) {
4949
assert_equals(response.status, 200);
5050
}
5151

52-
export async function setupShardedServerState(testId) {
53-
const obj = {};
54-
if (testId !== undefined) {
55-
obj.testId = testId;
52+
export async function setupShardedServerState(obj) {
53+
if (obj === undefined) {
54+
obj = {};
5655
}
5756
const response = await fetch('setup_sharded_server_state.py', {
5857
method: 'POST',

testing/web-platform/tests/device-bound-session-credentials/session_manager.py

Lines changed: 7 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -46,6 +46,7 @@ def __init__(self):
4646
self.include_site = True
4747
self.refresh_endpoint_unavailable = False
4848
self.response_session_id_override = None
49+
self.allowed_refresh_initiators = ["*"]
4950

5051
def next_session_id(self):
5152
return len(self.session_to_key_map)
@@ -127,6 +128,10 @@ def configure_state_for_test(self, configuration):
127128
if response_session_id_override is not None:
128129
self.response_session_id_override = response_session_id_override
129130

131+
allowed_refresh_initiators = configuration.get("allowedRefreshInitiators")
132+
if allowed_refresh_initiators is not None:
133+
self.allowed_refresh_initiators = allowed_refresh_initiators
134+
130135
def get_should_refresh_end_session(self):
131136
return self.should_refresh_end_session
132137

@@ -198,7 +203,8 @@ def get_session_instructions_response(self, session_id, request):
198203
{ "type": "exclude", "domain": request.url_parts.hostname, "path": "/device-bound-session-credentials/set_cookie.py" },
199204
]
200205
},
201-
"credentials": self.get_sessions_instructions_response_credentials(session_id, request)
206+
"credentials": self.get_sessions_instructions_response_credentials(session_id, request),
207+
"allowed_refresh_initiators": self.allowed_refresh_initiators,
202208
}
203209
headers = self.get_session_instructions_response_set_cookie_headers(session_id, request) + [
204210
("Content-Type", "application/json"),

testing/web-platform/tests/device-bound-session-credentials/setup_sharded_server_state.py

Lines changed: 10 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -9,4 +9,13 @@ def main(request, response):
99
if test_id is None:
1010
test_id = session_manager.initialize_test()
1111

12-
return (200, [("Set-Cookie", f"test_id={test_id}")], "")
12+
headers = [("Set-Cookie", f"test_id={test_id}")]
13+
14+
15+
16+
17+
cross_site = request_body.get("crossSite")
18+
if cross_site is not None and cross_site:
19+
headers = [("Set-Cookie", f"test_id={test_id};SameSite=None;Secure")]
20+
21+
return (200, headers, "")
Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,12 @@
1+
<!DOCTYPE html>
2+
<meta charset="utf-8">
3+
<body>
4+
<script>
5+
'use strict';
6+
7+
window.addEventListener("message", async (event) => {
8+
const response = await fetch(event.data, {credentials: "include"});
9+
event.source.postMessage(response.status, "*");
10+
});
11+
</script>
12+
</body>

0 commit comments

Comments
 (0)