From 1153fabd01abe9d752fbd8527da4bc92d3646c1d Mon Sep 17 00:00:00 2001 From: Markus Strehle <11627201+strehle@users.noreply.github.com> Date: Mon, 2 Jun 2025 21:38:54 +0200 Subject: [PATCH 1/2] Potential fix for code scanning alert no. 44: HTTP response splitting Co-authored-by: Copilot Autofix powered by AI <62310815+github-advanced-security[bot]@users.noreply.github.com> --- .../org/cloudfoundry/identity/uaa/login/LoginInfoEndpoint.java | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/server/src/main/java/org/cloudfoundry/identity/uaa/login/LoginInfoEndpoint.java b/server/src/main/java/org/cloudfoundry/identity/uaa/login/LoginInfoEndpoint.java index e127c744e15..1d8183095df 100755 --- a/server/src/main/java/org/cloudfoundry/identity/uaa/login/LoginInfoEndpoint.java +++ b/server/src/main/java/org/cloudfoundry/identity/uaa/login/LoginInfoEndpoint.java @@ -624,7 +624,8 @@ private Map.Entry evaluateLoginHint( @RequestMapping(value = {"/delete_saved_account"}) public String deleteSavedAccount(HttpServletRequest request, HttpServletResponse response, String userId) { - Cookie cookie = new Cookie("Saved-Account-%s".formatted(userId), ""); + String sanitizedUserId = URLEncoder.encode(userId, UTF_8); + Cookie cookie = new Cookie("Saved-Account-%s".formatted(sanitizedUserId), ""); cookie.setMaxAge(0); cookie.setPath(request.getContextPath() + "/login"); response.addCookie(cookie); From 2055ed7ebeaed19a4c4cd99e211079d105db3c8f Mon Sep 17 00:00:00 2001 From: strehle Date: Sun, 22 Jun 2025 19:40:07 +0200 Subject: [PATCH 2/2] refactor cookie creation --- ...untSavingAuthenticationSuccessHandler.java | 17 ++--------------- .../identity/uaa/login/LoginInfoEndpoint.java | 4 ++-- .../identity/uaa/util/UaaUrlUtils.java | 19 +++++++++++++++++++ 3 files changed, 23 insertions(+), 17 deletions(-) diff --git a/server/src/main/java/org/cloudfoundry/identity/uaa/login/AccountSavingAuthenticationSuccessHandler.java b/server/src/main/java/org/cloudfoundry/identity/uaa/login/AccountSavingAuthenticationSuccessHandler.java index 09d9eecfe17..7afe8d428bd 100755 --- a/server/src/main/java/org/cloudfoundry/identity/uaa/login/AccountSavingAuthenticationSuccessHandler.java +++ b/server/src/main/java/org/cloudfoundry/identity/uaa/login/AccountSavingAuthenticationSuccessHandler.java @@ -15,7 +15,7 @@ import org.apache.tomcat.util.http.Rfc6265CookieProcessor; import org.cloudfoundry.identity.uaa.authentication.UaaPrincipal; -import org.cloudfoundry.identity.uaa.util.JsonUtils; +import org.cloudfoundry.identity.uaa.util.UaaUrlUtils; import org.cloudfoundry.identity.uaa.zone.IdentityZoneHolder; import org.slf4j.Logger; import org.slf4j.LoggerFactory; @@ -30,10 +30,7 @@ import javax.servlet.http.HttpServletRequest; import javax.servlet.http.HttpServletResponse; import java.io.IOException; -import java.io.UnsupportedEncodingException; -import java.net.URLEncoder; -import static java.nio.charset.StandardCharsets.UTF_8; import static org.springframework.http.HttpHeaders.SET_COOKIE; @Component @@ -71,7 +68,7 @@ public void setSavedAccountOptionCookie(HttpServletRequest request, HttpServletR savedAccountOption.setOrigin(uaaPrincipal.getOrigin()); savedAccountOption.setUserId(uaaPrincipal.getId()); savedAccountOption.setUsername(uaaPrincipal.getName()); - Cookie savedAccountCookie = new Cookie("Saved-Account-" + uaaPrincipal.getId(), encodeCookieValue(JsonUtils.writeValueAsString(savedAccountOption))); + Cookie savedAccountCookie = UaaUrlUtils.createSavedCookie(uaaPrincipal.getId(), savedAccountOption); savedAccountCookie.setPath(request.getContextPath() + "/login"); savedAccountCookie.setHttpOnly(true); savedAccountCookie.setSecure(request.isSecure()); @@ -90,14 +87,4 @@ public void setSavedAccountOptionCookie(HttpServletRequest request, HttpServletR String headerValue = rfc6265CookieProcessor.generateHeader(currentUserCookie); response.addHeader(SET_COOKIE, headerValue); } - - public static String encodeCookieValue(String inValue) throws IllegalArgumentException { - String out = null; - try { - out = URLEncoder.encode(inValue, UTF_8.name()); - } catch (UnsupportedEncodingException e) { - throw new IllegalArgumentException(e); - } - return out; - } } diff --git a/server/src/main/java/org/cloudfoundry/identity/uaa/login/LoginInfoEndpoint.java b/server/src/main/java/org/cloudfoundry/identity/uaa/login/LoginInfoEndpoint.java index c86c46dcb22..24d6f50b287 100755 --- a/server/src/main/java/org/cloudfoundry/identity/uaa/login/LoginInfoEndpoint.java +++ b/server/src/main/java/org/cloudfoundry/identity/uaa/login/LoginInfoEndpoint.java @@ -29,6 +29,7 @@ import org.cloudfoundry.identity.uaa.util.MapCollector; import org.cloudfoundry.identity.uaa.util.SessionUtils; import org.cloudfoundry.identity.uaa.util.UaaStringUtils; +import org.cloudfoundry.identity.uaa.util.UaaUrlUtils; import org.cloudfoundry.identity.uaa.web.UaaSavedRequestAwareAuthenticationSuccessHandler; import org.cloudfoundry.identity.uaa.zone.IdentityZone; import org.cloudfoundry.identity.uaa.zone.IdentityZoneConfiguration; @@ -624,8 +625,7 @@ private Map.Entry evaluateLoginHint( @RequestMapping(value = {"/delete_saved_account"}) public String deleteSavedAccount(HttpServletRequest request, HttpServletResponse response, String userId) { - String sanitizedUserId = URLEncoder.encode(userId, UTF_8); - Cookie cookie = new Cookie("Saved-Account-%s".formatted(sanitizedUserId), ""); + Cookie cookie = UaaUrlUtils.createSavedCookie(userId, null); cookie.setMaxAge(0); cookie.setPath(request.getContextPath() + "/login"); cookie.setSecure(true); diff --git a/server/src/main/java/org/cloudfoundry/identity/uaa/util/UaaUrlUtils.java b/server/src/main/java/org/cloudfoundry/identity/uaa/util/UaaUrlUtils.java index a08640db99d..84ce3de727f 100644 --- a/server/src/main/java/org/cloudfoundry/identity/uaa/util/UaaUrlUtils.java +++ b/server/src/main/java/org/cloudfoundry/identity/uaa/util/UaaUrlUtils.java @@ -11,11 +11,14 @@ import org.springframework.web.util.UriComponentsBuilder; import org.springframework.web.util.UriUtils; +import javax.servlet.http.Cookie; import javax.servlet.http.HttpServletRequest; +import java.io.UnsupportedEncodingException; import java.net.MalformedURLException; import java.net.URI; import java.net.URISyntaxException; import java.net.URL; +import java.net.URLEncoder; import java.nio.charset.StandardCharsets; import java.util.Collection; import java.util.HashMap; @@ -25,6 +28,7 @@ import java.util.StringTokenizer; import java.util.regex.Pattern; +import static java.nio.charset.StandardCharsets.UTF_8; import static java.util.Collections.emptyList; import static java.util.Optional.ofNullable; import static org.springframework.util.StringUtils.hasText; @@ -310,6 +314,21 @@ public static String normalizeUri(String uri) { return uriComponentsBuilder.build().toString(); } + public static String urlEncode(String inValue) throws IllegalArgumentException { + String out; + try { + out = URLEncoder.encode(inValue, UTF_8.name()); + } catch (UnsupportedEncodingException e) { + throw new IllegalArgumentException(e); + } + return out; + } + + public static Cookie createSavedCookie(String userId, Object value) { + String cookieValue = ObjectUtils.isEmpty(value) ? UaaStringUtils.EMPTY_STRING : urlEncode(JsonUtils.writeValueAsString(value)); + return new Cookie("Saved-Account-%s".formatted(urlEncode(userId)), cookieValue); + } + private static String decodeUriPath(final String path) { if (path == null) { return null;