Bug 1837476 [wpt PR 40455] - [FedCM] Move getUserInfo() tests to its own file, a...
[gecko.git] / testing / web-platform / tests / credential-management / fedcm-network-requests.https.html
blob0084c8b0cfee064aea748b51a7758b37d4f91d1f
1 <!DOCTYPE html>
2 <title>Federated Credential Management API network request tests.</title>
3 <link rel="help" href="https://fedidcg.github.io/FedCM">
4 <script src="/resources/testharness.js"></script>
5 <script src="/resources/testharnessreport.js"></script>
6 <script src="/service-workers/service-worker/resources/test-helpers.sub.js"></script>
8 <body>
10 <script type="module">
11 import {request_options_with_mediation_required,
12 alt_request_options_with_mediation_required,
13 request_options_with_mediation_optional,
14 fedcm_test,
15 select_manifest,
16 set_fedcm_cookie} from './support/fedcm-helper.sub.js';
18 function loadUrlInIframe(url) {
19 let iframe = document.createElement("iframe");
20 return new Promise(resolve => {
21 iframe.src = url;
22 iframe.onload = function() { resolve(iframe); };
23 document.body.appendChild(iframe);
24 });
27 fedcm_test(async t => {
28 const cred = await navigator.credentials.get(request_options_with_mediation_required());
29 assert_equals(cred.token, "token");
30 }, "Successfully obtaining token should resolve the promise.");
32 fedcm_test(async t => {
33 const first = navigator.credentials.get(request_options_with_mediation_required());
34 const second = navigator.credentials.get(alt_request_options_with_mediation_required());
36 // We have to call promise_rejects_dom here, because if we call it after
37 // the promise gets rejected, the unhandled rejection event handler is called
38 // and fails the test even if we handle the rejection later.
39 const rej = promise_rejects_dom(t, 'AbortError', second);
41 const first_cred = await first;
42 assert_equals(first_cred.token, "token");
44 return rej;
46 "When there's a pending request, a second `get` call should be rejected. ");
48 fedcm_test(async t => {
49 let test_options = request_options_with_mediation_required();
50 test_options.identity.providers = [];
51 const cred = navigator.credentials.get(test_options);
52 return promise_rejects_js(t, TypeError, cred);
53 }, "Reject when provider list is empty");
55 fedcm_test(async t => {
56 let test_options = request_options_with_mediation_required();
57 delete test_options.identity.providers[0].configURL;
58 const cred = navigator.credentials.get(test_options);
59 return promise_rejects_js(t, TypeError, cred);
60 }, "Reject when configURL is missing" );
62 fedcm_test(async t => {
63 let test_options = request_options_with_mediation_required();
64 test_options.identity.providers[0].configURL = 'test';
65 const cred = navigator.credentials.get(test_options);
66 return promise_rejects_dom(t, "InvalidStateError", cred);
67 }, "Reject when configURL is invalid");
69 fedcm_test(async t => {
70 let test_options = request_options_with_mediation_required();
71 test_options.identity.providers[0].clientId = '';
72 const cred = navigator.credentials.get(test_options);
73 return promise_rejects_dom(t, "InvalidStateError", cred);
74 }, "Reject when clientId is empty");
76 fedcm_test(async t => {
77 let test_options = request_options_with_mediation_required();
78 assert_true("nonce" in test_options.identity.providers[0]);
79 delete test_options.identity.providers[0].nonce;
80 const cred = await navigator.credentials.get(test_options);
81 assert_equals(cred.token, "token");
82 }, "nonce is not required in FederatedIdentityProvider.");
84 fedcm_test(async t => {
85 let test_options = request_options_with_mediation_required();
86 delete test_options.identity.providers[0].clientId;
87 const cred = navigator.credentials.get(test_options);
88 return promise_rejects_js(t, TypeError, cred);
89 }, "Reject when clientId is missing" );
91 fedcm_test(async t => {
92 let controller = new AbortController();
93 let test_options = request_options_with_mediation_required();
94 test_options.signal = controller.signal;
95 const cred = navigator.credentials.get(test_options);
96 controller.abort();
97 return promise_rejects_dom(t, 'AbortError', cred);
98 }, "Test the abort signal");
100 fedcm_test(async t => {
101 let controller = new AbortController();
102 let test_options = request_options_with_mediation_required();
103 test_options.signal = controller.signal;
104 const first_cred = navigator.credentials.get(test_options);
105 controller.abort();
106 await promise_rejects_dom(t, 'AbortError', first_cred);
108 const second_cred = await navigator.credentials.get(request_options_with_mediation_required());
109 assert_equals(second_cred.token, "token");
110 }, "Get after abort should work");
112 fedcm_test(async t => {
113 let test_options = request_options_with_mediation_required('manifest-not-in-list.json');
114 const cred = navigator.credentials.get(test_options);
115 return promise_rejects_dom(t, 'NetworkError', cred);
116 }, 'Test that the promise is rejected if the manifest is not in the manifest list');
118 fedcm_test(async t => {
119 let test_options = request_options_with_mediation_required("manifest_redirect_accounts.json");
120 await select_manifest(t, test_options);
122 const cred = navigator.credentials.get(test_options);
123 return promise_rejects_dom(t, 'NetworkError', cred);
124 }, 'Test that promise is rejected if accounts endpoint redirects');
125 // A malicious site might impersonate an IDP, redirecting the accounts endpoint to a
126 // legitimate IDP in order to get the list of user accounts.
128 fedcm_test(async t => {
129 let test_options = request_options_with_mediation_required("manifest_redirect_token.json");
130 await select_manifest(t, test_options);
132 const cred = navigator.credentials.get(test_options);
133 return promise_rejects_dom(t, 'NetworkError', cred);
134 }, 'Test that token endpoint does not follow redirects');
135 // The token endpoint should not follow redirects because the user has not consented
136 // to share their identity with the redirect destination.
138 fedcm_test(async t => {
139 // Reset the client_metadata fetch count.
140 const clear_metadata_count_path = `support/fedcm/client_metadata_clear_count.py`;
141 await fetch(clear_metadata_count_path);
143 const cred = await navigator.credentials.get(request_options_with_mediation_required());
144 assert_equals(cred.token, "token");
146 await new Promise(resolve => {
147 let popup_window = window.open('support/fedcm/client_metadata.py?skip_checks=1');
148 const popup_window_load_handler = (event) => {
149 popup_window.removeEventListener('load', popup_window_load_handler);
150 popup_window.close();
151 resolve();
153 popup_window.addEventListener('load', popup_window_load_handler);
156 const client_metadata_counter = await fetch(clear_metadata_count_path);
157 const client_metadata_counter_text = await client_metadata_counter.text()
158 assert_equals(client_metadata_counter_text, "2");
159 }, 'Test client_metadata request');
160 // Test:
161 // - Headers sent to client metadata endpoint. (Counter is not incremented if the headers are
162 // wrong.)
163 // - That the client metadata response is not cached. If the client metadata response were
164 // cached, when the user visits the IDP as a first party, the IDP would be able to determine the
165 // last RP the user visited regardless of whether the user granted consent via the FedCM prompt.
167 fedcm_test(async t => {
168 const service_worker_url = 'support/fedcm/intercept_service_worker.js';
169 const sw_scope_url = '/credential-management/support/fedcm/';
170 // URL for querying number of page loads observed by service worker.
171 const query_sw_intercepts_url = 'support/fedcm/query_service_worker_intercepts.html';
172 const page_in_sw_scope_url = 'support/fedcm/simple.html';
174 const sw_registration = await service_worker_unregister_and_register(
175 t, service_worker_url, sw_scope_url);
176 t.add_cleanup(() => service_worker_unregister(t, sw_scope_url));
177 await wait_for_state(t, sw_registration.installing, 'activated');
179 // Verify that service worker works.
180 await loadUrlInIframe(page_in_sw_scope_url);
181 let query_sw_iframe = await loadUrlInIframe(query_sw_intercepts_url);
182 assert_equals(query_sw_iframe.contentDocument.body.textContent, "1");
184 await set_fedcm_cookie();
185 const cred = await navigator.credentials.get(request_options_with_mediation_required());
186 assert_equals(cred.token, "token");
188 // Use cache buster query parameter to avoid cached response.
189 let query_sw_iframe2 = await loadUrlInIframe(query_sw_intercepts_url + "?2");
190 assert_equals(query_sw_iframe2.contentDocument.body.textContent, "1");
191 }, 'Test that service worker cannot observe fetches performed by FedCM API');
193 fedcm_test(async t => {
194 let test_options = request_options_with_mediation_optional("manifest_with_single_account.json");
195 await select_manifest(t, test_options);
197 // Signs in john_doe so that they will be a returning user
198 let cred = await navigator.credentials.get(test_options);
199 assert_equals(cred.token, "account_id=john_doe");
201 test_options = request_options_with_mediation_optional("manifest_with_two_accounts.json");
202 await select_manifest(t, test_options);
204 // There are two accounts "Jane" and "John" returned in that order. Without
205 // auto re-authn, the first account "Jane" would be selected and an token
206 // would be issued to that account. However, since "John" is returning and
207 // "Jane" is a new user, the second account "John" will be selected.
208 cred = await navigator.credentials.get(test_options);
209 assert_equals(cred.token, "account_id=john_doe");
210 }, "Test that the returning account from the two accounts will be auto re-authenticated.");
212 </script>