From 0b9dd21b0a77eb42d451b3881ee7347cb9b0cfea Mon Sep 17 00:00:00 2001 From: Jon Koops Date: Mon, 27 Nov 2023 19:23:40 +0100 Subject: [PATCH] Attempt to request storage access for cookies (#25055) Closes #23872 Signed-off-by: Jon Koops --- js/libs/keycloak-js/src/keycloak.js | 6 +++--- .../oidc/endpoints/3p-cookies-step1.html | 20 ++++++++++++++++++- .../oidc/endpoints/login-status-iframe.html | 20 ++++++++++++++++++- 3 files changed, 41 insertions(+), 5 deletions(-) diff --git a/js/libs/keycloak-js/src/keycloak.js b/js/libs/keycloak-js/src/keycloak.js index d302c5f635..c0e76a071d 100755 --- a/js/libs/keycloak-js/src/keycloak.js +++ b/js/libs/keycloak-js/src/keycloak.js @@ -201,7 +201,7 @@ function Keycloak (config) { var ifrm = document.createElement("iframe"); var src = kc.createLoginUrl({prompt: 'none', redirectUri: kc.silentCheckSsoRedirectUri}); ifrm.setAttribute("src", src); - ifrm.setAttribute("sandbox", "allow-scripts allow-same-origin"); + ifrm.setAttribute("sandbox", "allow-storage-access-by-user-activation allow-scripts allow-same-origin"); ifrm.setAttribute("title", "keycloak-silent-check-sso"); ifrm.style.display = "none"; document.body.appendChild(ifrm); @@ -1197,7 +1197,7 @@ function Keycloak (config) { var src = kc.endpoints.checkSessionIframe(); iframe.setAttribute('src', src ); - iframe.setAttribute('sandbox', 'allow-scripts allow-same-origin'); + iframe.setAttribute('sandbox', 'allow-storage-access-by-user-activation allow-scripts allow-same-origin'); iframe.setAttribute('title', 'keycloak-session-iframe' ); iframe.style.display = 'none'; document.body.appendChild(iframe); @@ -1270,7 +1270,7 @@ function Keycloak (config) { if (loginIframe.enable || kc.silentCheckSsoRedirectUri) { var iframe = document.createElement('iframe'); iframe.setAttribute('src', kc.endpoints.thirdPartyCookiesIframe()); - iframe.setAttribute('sandbox', 'allow-scripts allow-same-origin'); + iframe.setAttribute('sandbox', 'allow-storage-access-by-user-activation allow-scripts allow-same-origin'); iframe.setAttribute('title', 'keycloak-3p-check-iframe' ); iframe.style.display = 'none'; document.body.appendChild(iframe); diff --git a/services/src/main/resources/org/keycloak/protocol/oidc/endpoints/3p-cookies-step1.html b/services/src/main/resources/org/keycloak/protocol/oidc/endpoints/3p-cookies-step1.html index ecaac339ef..4c08d0c8c1 100644 --- a/services/src/main/resources/org/keycloak/protocol/oidc/endpoints/3p-cookies-step1.html +++ b/services/src/main/resources/org/keycloak/protocol/oidc/endpoints/3p-cookies-step1.html @@ -20,12 +20,30 @@ } } + // See https://developer.mozilla.org/en-US/docs/Web/API/Storage_Access_API/Using#checking_and_requesting_storage_access async function hasStorageAccess() { + // Check if the Storage Access API is supported, if not, pretend we have access. + // This is for older browsers, where support can be determined using the test cookie. if (!("hasStorageAccess" in document)) { return true; } - return document.hasStorageAccess(); + // Check if we already have been granted storage access, if so, signal access. + if (await document.hasStorageAccess()) { + return true; + } + + try { + // Attempt to request storage access without a user interaction. + // This might fail, and if it does an exception will be thrown. + await document.requestStorageAccess(); + + // If no exceptions are thrown, then signal access. + return true; + } catch (error) { + // If an exception is thrown, then signal no access. + return false; + } } function attemptWithTestCookie() { diff --git a/services/src/main/resources/org/keycloak/protocol/oidc/endpoints/login-status-iframe.html b/services/src/main/resources/org/keycloak/protocol/oidc/endpoints/login-status-iframe.html index fa1ef95502..649c9f11f9 100755 --- a/services/src/main/resources/org/keycloak/protocol/oidc/endpoints/login-status-iframe.html +++ b/services/src/main/resources/org/keycloak/protocol/oidc/endpoints/login-status-iframe.html @@ -72,12 +72,30 @@ return "error"; } + // See https://developer.mozilla.org/en-US/docs/Web/API/Storage_Access_API/Using#checking_and_requesting_storage_access async function hasStorageAccess() { + // Check if the Storage Access API is supported, if not, pretend we have access. + // This is for older browsers, where support can be determined using the test cookie. if (!("hasStorageAccess" in document)) { return true; } - return document.hasStorageAccess(); + // Check if we already have been granted storage access, if so, signal access. + if (await document.hasStorageAccess()) { + return true; + } + + try { + // Attempt to request storage access without a user interaction. + // This might fail, and if it does an exception will be thrown. + await document.requestStorageAccess(); + + // If no exceptions are thrown, then signal access. + return true; + } catch (error) { + // If an exception is thrown, then signal no access. + return false; + } } function getSessionCookie() {