third-party-registration.https.html (10474B)
1 <!DOCTYPE html> 2 <meta charset="utf-8"> 3 <script src="/resources/testharness.js"></script> 4 <script src="/resources/testharnessreport.js"></script> 5 <script src="/common/get-host-info.sub.js"></script> 6 <script src="helper.js" type="module"></script> 7 8 <script type="module"> 9 import { 10 expireCookie, 11 documentHasCookie, 12 waitForCookie, 13 addCookieAndSessionCleanup, 14 setupShardedServerState, 15 configureServer, 16 crossSiteFetch 17 } from "./helper.js"; 18 19 promise_test(async t => { 20 await setupShardedServerState({crossSite: true}); 21 const expectedCookieAndValue = "auth_cookie=abcdef0123"; 22 const expectedCookieAttributes = `Domain=${location.hostname};Path=/device-bound-session-credentials;SameSite=Lax`; 23 const expectedCookieAndAttributes = `${expectedCookieAndValue};${expectedCookieAttributes}`; 24 addCookieAndSessionCleanup(t); 25 26 configureServer({ 27 // Set cookie details in order to specify that we should only bind a SameSite=Lax cookie for this test. 28 cookieDetails: [ 29 { 30 nameAndValue: expectedCookieAndValue, 31 attributes: expectedCookieAttributes, 32 } 33 ], 34 // Since registration happens from a third-party context, we need 35 // a SameSite=None cookie to tell us that registration completed. 36 registrationExtraCookies: [ 37 { 38 nameAndValue: "get_session_instructions=done", 39 attributes: "SameSite=None;Secure", 40 } 41 ] 42 }); 43 44 // Prompt starting a session in a third-party context, and wait until registration completes. 45 const loginStatus = await crossSiteFetch(get_host_info().HTTPS_NOTSAMESITE_ORIGIN, `${location.protocol}//${location.host}/device-bound-session-credentials/login.py`, {credentials: "include"}); 46 assert_equals(loginStatus, 200); 47 await waitForCookie("get_session_instructions=done", /*expectCookie=*/true); 48 49 // Since all cookies in the session are first-party, registration 50 // from a third-party context should fail. 51 expireCookie(expectedCookieAndAttributes); 52 assert_false(documentHasCookie(expectedCookieAndValue)); 53 const authResponseAfterExpiry = await fetch('verify_authenticated.py'); 54 assert_equals(authResponseAfterExpiry.status, 403); 55 assert_false(documentHasCookie(expectedCookieAndValue)); 56 }, "Registration of first-party session not allowed in third-party context"); 57 58 promise_test(async t => { 59 await setupShardedServerState({crossSite: true}); 60 const expectedCookieAndValueSameSiteLax = "auth_cookie_lax=abcdef0123"; 61 const expectedCookieAttributesSameSiteLax = `Domain=${location.hostname};Path=/device-bound-session-credentials;SameSite=Lax`; 62 const expectedCookieAndAttributesSameSiteLax = `${expectedCookieAndValueSameSiteLax};${expectedCookieAttributesSameSiteLax}`; 63 64 const expectedCookieAndValueSameSiteNone = "auth_cookie=abcdef0123"; 65 const expectedCookieAttributesSameSiteNone = `Domain=${location.hostname};Path=/device-bound-session-credentials;SameSite=None;Secure`; 66 const expectedCookieAndAttributesSameSiteNone = `${expectedCookieAndValueSameSiteNone};${expectedCookieAttributesSameSiteNone}`; 67 addCookieAndSessionCleanup(t); 68 69 configureServer({ 70 // Configure the server to bind both a SameSite=Lax and SameSite=None cookie 71 cookieDetails: [ 72 { 73 nameAndValue: expectedCookieAndValueSameSiteLax, 74 attributes: expectedCookieAttributesSameSiteLax, 75 }, 76 { 77 nameAndValue: expectedCookieAndValueSameSiteNone, 78 attributes: expectedCookieAttributesSameSiteNone, 79 } 80 ], 81 // Since registration happens from a third-party context, we need 82 // a SameSite=None cookie to tell us that registration completed. 83 registrationExtraCookies: [ 84 { 85 nameAndValue: "get_session_instructions=done", 86 attributes: "SameSite=None;Secure", 87 } 88 ] 89 }); 90 91 // Prompt starting a session in a third-party context, and wait until registration completes. 92 const loginStatus = await crossSiteFetch(get_host_info().HTTPS_NOTSAMESITE_ORIGIN, `${location.protocol}//${location.host}/device-bound-session-credentials/login.py`, {credentials: "include"}); 93 assert_equals(loginStatus, 200); 94 await waitForCookie("get_session_instructions=done", /*expectCookie=*/true); 95 // Because registration is happenin from a third-party context, only the 96 // SameSite=None cookie will be set. 97 assert_false(documentHasCookie(expectedCookieAndValueSameSiteLax)); 98 assert_true(documentHasCookie(expectedCookieAndValueSameSiteNone)); 99 100 // Since one cookies in the session is third-party, registration 101 // from a third-party context should succeed. 102 expireCookie(expectedCookieAndAttributesSameSiteLax); 103 expireCookie(expectedCookieAndAttributesSameSiteNone); 104 assert_false(documentHasCookie(expectedCookieAndValueSameSiteLax)); 105 assert_false(documentHasCookie(expectedCookieAndValueSameSiteNone)); 106 const authResponseAfterExpiry = await fetch('verify_authenticated.py'); 107 assert_equals(authResponseAfterExpiry.status, 200); 108 // While the registration was from a third-party context, the 109 // refresh triggered by fetching verify_authenticated.py is 110 // happening in a first-party context. So we get both cookies from 111 // the refresh. 112 assert_true(documentHasCookie(expectedCookieAndValueSameSiteLax)); 113 assert_true(documentHasCookie(expectedCookieAndValueSameSiteNone)); 114 }, "Registration of session with third-party cookies allowed in third-party context"); 115 116 promise_test(async t => { 117 await setupShardedServerState({crossSite: true}); 118 const expectedCookieAndValue = "auth_cookie=abcdef0123"; 119 const expectedCookieAttributes = `Domain=${location.hostname};Path=/device-bound-session-credentials;SameSite=Lax`; 120 const expectedCookieAndAttributes = `${expectedCookieAndValue};${expectedCookieAttributes}`; 121 addCookieAndSessionCleanup(t); 122 123 configureServer({ 124 // Set cookie details in order to specify that we should only bind a SameSite=Lax cookie for this test. 125 cookieDetails: [ 126 { 127 nameAndValue: expectedCookieAndValue, 128 attributes: expectedCookieAttributes, 129 }, 130 ], 131 earlyChallengeForNextRegisteredSession: "early_challenge", 132 }); 133 134 // Prompt starting a session in a first-party context, and wait until registration completes. 135 const loginResponse = await fetch('login.py'); 136 assert_equals(loginResponse.status, 200); 137 await waitForCookie(expectedCookieAndValue, /*expectCookie=*/true); 138 139 // Try to set the challenge from a third-party context 140 const challengeStatus = await crossSiteFetch(get_host_info().HTTPS_NOTSAMESITE_ORIGIN, `${location.protocol}//${location.host}/device-bound-session-credentials/request_early_challenge.py`, {method: 'POST', body: JSON.stringify({ useSingleHeader: true}), credentials: "include"}); 141 assert_equals(challengeStatus, 200); 142 143 // Since all cookies in the session are first-party, our attempt to 144 // set a challenge from a third-party context should fail. This 145 // causes a challenge mismatch at registration time. 146 expireCookie(expectedCookieAndAttributes); 147 assert_false(documentHasCookie(expectedCookieAndValue)); 148 const authResponseAfterExpiry = await fetch('verify_authenticated.py'); 149 assert_equals(authResponseAfterExpiry.status, 403); 150 assert_false(documentHasCookie(expectedCookieAndValue)); 151 }, "Set challenge of first-party not allowed in third-party context"); 152 153 promise_test(async t => { 154 await setupShardedServerState({crossSite: true}); 155 const expectedCookieAndValueSameSiteLax = "auth_cookie_lax=abcdef0123"; 156 const expectedCookieAttributesSameSiteLax = `Domain=${location.hostname};Path=/device-bound-session-credentials;SameSite=Lax`; 157 const expectedCookieAndAttributesSameSiteLax = `${expectedCookieAndValueSameSiteLax};${expectedCookieAttributesSameSiteLax}`; 158 159 const expectedCookieAndValueSameSiteNone = "auth_cookie=abcdef0123"; 160 const expectedCookieAttributesSameSiteNone = `Domain=${location.hostname};Path=/device-bound-session-credentials;SameSite=None;Secure`; 161 const expectedCookieAndAttributesSameSiteNone = `${expectedCookieAndValueSameSiteNone};${expectedCookieAttributesSameSiteNone}`; 162 addCookieAndSessionCleanup(t); 163 164 configureServer({ 165 // Configure the server to bind both a SameSite=Lax and SameSite=None cookie 166 cookieDetails: [ 167 { 168 nameAndValue: expectedCookieAndValueSameSiteLax, 169 attributes: expectedCookieAttributesSameSiteLax, 170 }, 171 { 172 nameAndValue: expectedCookieAndValueSameSiteNone, 173 attributes: expectedCookieAttributesSameSiteNone, 174 } 175 ], 176 earlyChallengeForNextRegisteredSession: "early_challenge", 177 }); 178 179 // Prompt starting a session in a first-party context, and wait until registration completes. 180 const loginResponse = await fetch('login.py'); 181 assert_equals(loginResponse.status, 200); 182 await waitForCookie(expectedCookieAndValueSameSiteNone, /*expectCookie=*/true); 183 184 // Try to set the challenge from a third-party context 185 const challengeStatus = await crossSiteFetch(get_host_info().HTTPS_NOTSAMESITE_ORIGIN, `${location.protocol}//${location.host}/device-bound-session-credentials/request_early_challenge.py`, {method: 'POST', body: JSON.stringify({ useSingleHeader: true}), credentials: "include"}); 186 assert_equals(challengeStatus, 200); 187 188 // Since one cookie in the session is third-party, our attempt to 189 // set a challenge from a third-party context should succeed. 190 expireCookie(expectedCookieAndAttributesSameSiteLax); 191 expireCookie(expectedCookieAndAttributesSameSiteNone); 192 assert_false(documentHasCookie(expectedCookieAndValueSameSiteLax)); 193 assert_false(documentHasCookie(expectedCookieAndValueSameSiteNone)); 194 const authResponseAfterExpiry = await fetch('verify_authenticated.py'); 195 assert_equals(authResponseAfterExpiry.status, 200); 196 // While the challenge was set in a third-party context, the refresh 197 // triggered by fetching verify_authenticated.py is happening in a 198 // first-party context. So we get both cookies from the refresh. 199 assert_true(documentHasCookie(expectedCookieAndValueSameSiteLax)); 200 assert_true(documentHasCookie(expectedCookieAndValueSameSiteNone)); 201 }, "Set challenge of session with third-party cookies allowed in third-party context"); 202 </script>