8000 Improve session polling to prevent accidental redirects by jonkoops · Pull Request #35143 · keycloak/keycloak · GitHub
[go: up one dir, main page]

Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion themes/src/main/resources/theme/base/login/register.ftl
Original file line number Diff line number Diff line change
Expand Up @@ -91,7 +91,7 @@
<#if recaptchaRequired?? && !(recaptchaVisible!false)>
<script>
function onSubmitRecaptcha(token) {
document.getElementById("kc-register-form").submit();
document.getElementById("kc-register-form").requestSubmit();
}
</script>
<div id="kc-form-buttons" class="${properties.kcFormButtonsClass!}">
Expand Down
Original file line number Diff line number Diff line change
@@ -1,19 +1,24 @@
const CHECK_INTERVAL_MILLISECS = 2000;
const SESSION_POLLING_INTERVAL = 2000;
const AUTH_SESSION_TIMEOUT_MILLISECS = 1000;
const initialSession = getSession();

const forms = Array.from(document.forms);
let timeout;

// Remove the timeout when unloading to avoid execution of the
// checkCookiesAndSetTimer when the page is already submitted
addEventListener("beforeunload", () => {
if (timeout) {
clearTimeout(timeout);
timeout = undefined;
}
});
// Stop polling for a session when a form is submitted to prevent unexpected redirects.
// This is required as Safari does not support the 'beforeunload' event properly.
// See: https://bugs.webkit.org/show_bug.cgi?id=219102
forms.forEach((form) =>
form.addEventListener("submit", () => stopSessionPolling()),
);

// Stop polling for a session when the page is unloaded to prevent unexpected redirects.
globalThis.addEventListener("beforeunload", () => stopSessionPolling());

export function checkCookiesAndSetTimer(loginRestartUrl) {
/**
* Starts polling to check if a new session was started in another context (e.g. a tab or window), and redirects to the specified URL if a session is detected.
* @param {string} redirectUrl - The URL to redirect to if a new session is detected.
*/
export function startSessionPolling(redirectUrl) {
if (initialSession) {
// We started with a session, so there is nothing to do, exit.
return;
Expand All @@ -22,21 +27,35 @@ export function checkCookiesAndSetTimer(loginRestartUrl) {
const session = getSession();

if (!session) {
// The session is not present, check again later.
// No new session detected, check again later.
timeout = setTimeout(
() => checkCookiesAndSetTimer(loginRestartUrl),
CHECK_INTERVAL_MILLISECS,
() => startSessionPolling(redirectUrl),
SESSION_POLLING_INTERVAL,
);
} else {
// Redirect to the login restart URL. This can typically automatically login user due the SSO
location.href = loginRestartUrl;
// A new session was detected, redirect to the specified URL and stop polling.
location.href = redirectUrl;
stopSessionPolling();
Comment thread
jonkoops marked this conversation as resolved.
Resolved
}
}

/**
* Stops polling the session.
*/
function stopSessionPolling() {
if (timeout) {
clearTimeout(timeout);
timeout = undefined;
}
}

export function checkAuthSession(pageAuthSessionHash) {
setTimeout(() => {
const cookieAuthSessionHash = getKcAuthSessionHash();
if (cookieAuthSessionHash && cookieAuthSessionHash !== pageAuthSessionHash) {
if (
cookieAuthSessionHash &&
cookieAuthSessionHash !== pageAuthSessionHash
) {
location.reload();
}
}, AUTH_SESSION_TIMEOUT_MILLISECS);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -73,10 +73,10 @@ export function returnSuccess(result) {
if (result.response.userHandle) {
document.getElementById("userHandle").value = base64url.stringify(new Uint8Array(result.response.userHandle), { pad: false });
}
document.getElementById("webauth").submit();
document.getElementById("webauth").requestSubmit();
}

export function returnFailure(err) {
document.getElementById("error").value = err;
document.getElementById("webauth").submit();
}
document.getElementById("webauth").requestSubmit();
}
Original file line number Diff line number Diff line change
Expand Up @@ -131,10 +131,10 @@ function returnSuccess(result, initLabel, initLabelPrompt) {
}
document.getElementById("authenticatorLabel").value = labelResult;

document.getElementById("register").submit();
document.getElementById("register").requestSubmit();
}

function returnFailure(err) {
document.getElementById("error").value = err;
document.getElementById("register").submit();
document.getElementById("register").requestSubmit();
}
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@
<#if section = "header">
${msg("saml.post-form.title")}
<#elseif section = "form">
<script>window. {document.forms[0].submit()};</script>
<script>window. {document.forms[0].requestSubmit()};</script>
<p>${msg("saml.post-form.message")}</p>
<form name="saml-post-binding" method="post" action="${samlPost.url}">
<#if samlPost.SAMLRequest??>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,7 @@
<#list user.organizations as organization>
<li>
<a id="organization-${organization.alias}" class="${properties.kcFormSocialAccountListButtonClass!} <#if user.organizations?size gt 3>${properties.kcFormSocialAccountGridItem!}</#if>"
type="button" = '${organization.alias}'; document.forms[0].submit()">
type="button" = '${organization.alias}'; document.forms[0].requestSubmit()">
<span class="${properties.kcFormSocialAccountNameClass!}">${organization.name!}</span>
</a>
</li>
Expand Down
6 changes: 3 additions & 3 deletions themes/src/main/resources/theme/base/login/template.ftl
Original file line number Diff line number Diff line change
Expand Up @@ -44,9 +44,9 @@
</#list>
</#if>
<script type="module">
import { checkCookiesAndSetTimer } from "${url.resourcesPath}/js/authChecker.js";
import { startSessionPolling } from "${url.resourcesPath}/js/authChecker.js";

checkCookiesAndSetTimer(
startSessionPolling(
"${url.ssoLoginInOtherTabsUrl?no_esc}"
);
</script>
Expand Down Expand Up @@ -157,7 +157,7 @@
<div class="${properties.kcFormGroupClass!}">
<input type="hidden" name="tryAnotherWay" value="on"/>
<a href="#" id="try-another-way"
class="x x-first x-last">submit();return false;">${msg("doTryAnotherWay")}</a>
class="x x-first x-last">requestSubmit();return false;">${msg("doTryAnotherWay")}</a>
</div>
</form>
</#if>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,7 @@
refreshPage = () => {
document.getElementById('isSetRetry').value = 'retry';
document.getElementById('executionValue').value = '${execution}';
document.getElementById('kc-error-credential-form').submit();
document.getElementById('kc-error-credential-form').requestSubmit();
}
</script>

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,7 @@
<form id="kc-select-credential-form" class="${properties.kcFormClass!}" action="${url.loginAction}" method="post">
<input type="hidden" name="authenticationExecution" value="${authenticationSelection.authExecId}">
</form>
<div class="${properties.kcSelectAuthListItemClass!}" class="x x-first x-last">submit()">
<div class="${properties.kcSelectAuthListItemClass!}" class="x x-first x-last">requestSubmit()">
<div class="pf-v5-c-data-list__item-content">
<div class="${properties.kcSelectAuthListItemIconClass!}">
<i class="${properties['${authenticationSelection.iconCssClass}']!authenticationSelection.iconCssClass} ${properties.kcSelectAuthListItemIconPropertyClass!}"></i>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -86,9 +86,9 @@
</#if>
<script type="module" src="${url.resourcesPath}/js/passwordVisibility.js"></script>
<script type="module">
import { checkCookiesAndSetTimer } from "${url.resourcesPath}/js/authChecker.js";
import { startSessionPolling } from "${url.resourcesPath}/js/authChecker.js";

checkCookiesAndSetTimer(
startSessionPolling(
"${url.ssoLoginInOtherTabsUrl?no_esc}"
);
</script>
Expand Down Expand Up @@ -207,7 +207,7 @@
<#if auth?has_content && auth.showTryAnotherWayLink()>
<form id="kc-select-try-another-way-form" action="${url.loginAction}" method="post" novalidate="novalidate">
<input type="hidden" name="tryAnotherWay" value="on"/>
<a id="try-another-way" href="javascript:document.forms['kc-select-try-another-way-form'].submit()"
<a id="try-another-way" href="javascript:document.forms['kc-select-try-another-way-form'].requestSubmit()"
class="${properties.kcButtonSecondaryClass} ${properties.kcButtonBlockClass} ${properties.kcMarginTopClass}">
${kcSanitize(msg("doTryAnotherWay"))?no_esc}
</a>
Expand Down
0