From 1ed092fc5f53b3b26a560bf253a821f8cce720d5 Mon Sep 17 00:00:00 2001 From: strehle Date: Thu, 8 Jan 2026 10:47:45 +0100 Subject: [PATCH] Refactor: Create Login State Values Once If IdP selection is not active, but all IdP are listed in login page, then the state and PKCE values are generated with each request and stored in the current HTTP session. If there are parallel action, e.g. different browser tabs, then this can lead to login issues. Refactor so that these states are created once per Http session and re-use them in other requests, e.g. browser tabs --- .../oauth/ExternalOAuthProviderConfigurator.java | 8 +++----- .../identity/uaa/util/SessionUtils.java | 14 ++++++++++++-- 2 files changed, 15 insertions(+), 7 deletions(-) diff --git a/server/src/main/java/org/cloudfoundry/identity/uaa/provider/oauth/ExternalOAuthProviderConfigurator.java b/server/src/main/java/org/cloudfoundry/identity/uaa/provider/oauth/ExternalOAuthProviderConfigurator.java index 9950b7ca666..4ab07c84c14 100644 --- a/server/src/main/java/org/cloudfoundry/identity/uaa/provider/oauth/ExternalOAuthProviderConfigurator.java +++ b/server/src/main/java/org/cloudfoundry/identity/uaa/provider/oauth/ExternalOAuthProviderConfigurator.java @@ -82,8 +82,7 @@ public String getIdpAuthenticationUrl( var responseType = URLEncoder.encode(definition.getResponseType(), StandardCharsets.UTF_8); var relyingPartyId = definition.getRelyingPartyId(); - var state = generateStateParam(); - SessionUtils.setStateParam(request.getSession(), SessionUtils.stateParameterAttributeKeyForIdp(idpOriginKey), state); + var state = SessionUtils.setStateParam(request.getSession(), SessionUtils.stateParameterAttributeKeyForIdp(idpOriginKey), generateStateParam()); UriComponentsBuilder uriBuilder = UriComponentsBuilder .fromUriString(idpUrlBase) @@ -96,9 +95,8 @@ public String getIdpAuthenticationUrl( // https://docs.spring.io/spring-security/site/docs/5.3.1.RELEASE/reference/html5/#initiating-the-authorization-request if (isPkceNeeded(definition)) { var pkceVerifier = new S256PkceVerifier(); - var codeVerifier = generateCodeVerifier(); - var codeChallenge = pkceVerifier.compute(codeVerifier); - SessionUtils.setStateParam(request.getSession(), SessionUtils.codeVerifierParameterAttributeKeyForIdp(idpOriginKey), codeVerifier); + var codeVerifier = SessionUtils.setStateParam(request.getSession(), SessionUtils.codeVerifierParameterAttributeKeyForIdp(idpOriginKey), generateCodeVerifier()); + var codeChallenge = SessionUtils.setStateParam(request.getSession(), SessionUtils.codeChallengeParameterAttributeKeyForIdp(idpOriginKey), pkceVerifier.compute(codeVerifier)); uriBuilder.queryParam("code_challenge", codeChallenge); uriBuilder.queryParam("code_challenge_method", pkceVerifier.getCodeChallengeMethod()); } diff --git a/server/src/main/java/org/cloudfoundry/identity/uaa/util/SessionUtils.java b/server/src/main/java/org/cloudfoundry/identity/uaa/util/SessionUtils.java index 9d733ce4485..41a590ebc67 100644 --- a/server/src/main/java/org/cloudfoundry/identity/uaa/util/SessionUtils.java +++ b/server/src/main/java/org/cloudfoundry/identity/uaa/util/SessionUtils.java @@ -26,6 +26,7 @@ public final class SessionUtils { private static final String EXTERNAL_OAUTH_STATE_ATTRIBUTE_PREFIX = "external-oauth-state-"; private static final String EXTERNAL_OAUTH_CODE_VERIFIER_ATTRIBUTE_PREFIX = "external-oauth-verifier-"; + private static final String EXTERNAL_OAUTH_CODE_CHALLENGE_ATTRIBUTE_PREFIX = "external-oauth-challenge-"; private SessionUtils() { } @@ -56,8 +57,13 @@ public static UaaAuthentication getForcePasswordExpiredUser(HttpSession session) return (UaaAuthentication) session.getAttribute(FORCE_PASSWORD_EXPIRED_USER); } - public static void setStateParam(HttpSession session, String stateParamKey, String state) { - session.setAttribute(stateParamKey, state); + public static String setStateParam(HttpSession session, String stateParamKey, String state) { + if (session.isNew() || session.getAttribute(stateParamKey) == null) { + session.setAttribute(stateParamKey, state); + return state; + } else { + return session.getAttribute(stateParamKey) instanceof String existingState ? existingState : null; + } } public static Object getStateParam(HttpSession session, String stateParamKey) { @@ -87,4 +93,8 @@ public static String stateParameterAttributeKeyForIdp(String idpOriginKey) { public static String codeVerifierParameterAttributeKeyForIdp(String idpOriginKey) { return EXTERNAL_OAUTH_CODE_VERIFIER_ATTRIBUTE_PREFIX + idpOriginKey; } + + public static String codeChallengeParameterAttributeKeyForIdp(String idpOriginKey) { + return EXTERNAL_OAUTH_CODE_CHALLENGE_ATTRIBUTE_PREFIX + idpOriginKey; + } }