From 5ff6ff57a82015b56d06fa6de9077fd48f71bb38 Mon Sep 17 00:00:00 2001 From: rmartinc Date: Fri, 6 Aug 2021 14:37:38 +0200 Subject: [PATCH] [KEYCLOAK-18535] KeycloakSanitizerMethod causes java.lang.IndexOutOfBoundsException when there is more then one href in a sanitized message --- .../theme/KeycloakSanitizerMethod.java | 25 +++++++++++------- .../keycloak/theme/KeycloakSanitizerTest.java | 26 ++++++++++++++++--- 2 files changed, 38 insertions(+), 13 deletions(-) diff --git a/services/src/main/java/org/keycloak/theme/KeycloakSanitizerMethod.java b/services/src/main/java/org/keycloak/theme/KeycloakSanitizerMethod.java index b05ef66e06..bf2d6068d6 100644 --- a/services/src/main/java/org/keycloak/theme/KeycloakSanitizerMethod.java +++ b/services/src/main/java/org/keycloak/theme/KeycloakSanitizerMethod.java @@ -34,6 +34,8 @@ import org.owasp.html.PolicyFactory; public class KeycloakSanitizerMethod implements TemplateMethodModelEx { private static final PolicyFactory KEYCLOAK_POLICY = KeycloakSanitizerPolicy.POLICY_DEFINITION; + + private static final Pattern HREF_PATTERN = Pattern.compile("\\s+href=\"([^\"]*)\""); @Override public Object exec(List list) throws TemplateModelException { @@ -48,16 +50,19 @@ public class KeycloakSanitizerMethod implements TemplateMethodModelEx { } private String fixURLs(String msg) { - Pattern hrefs = Pattern.compile("href=\"([^\"]*)\""); - Matcher matcher = hrefs.matcher(msg); - int count = 0; - while(matcher.find()) { - count++; - String original = matcher.group(count); - String href = original.replaceAll("=", "=") - .replaceAll("\\.\\.", ".") - .replaceAll("&", "&"); - msg = msg.replace(original, href); + Matcher matcher = HREF_PATTERN.matcher(msg); + if (matcher.find()) { + int last = 0; + StringBuilder result = new StringBuilder(msg.length()); + do { + String href = matcher.group(1).replaceAll("=", "=") + .replaceAll("\\.\\.", ".") + .replaceAll("&", "&"); + result.append(msg.substring(last, matcher.start(1))).append(href); + last = matcher.end(1); + } while (matcher.find()); + result.append(msg.substring(last)); + return result.toString(); } return msg; } diff --git a/services/src/test/java/org/keycloak/theme/KeycloakSanitizerTest.java b/services/src/test/java/org/keycloak/theme/KeycloakSanitizerTest.java index 9e503f5b4a..878995610c 100644 --- a/services/src/test/java/org/keycloak/theme/KeycloakSanitizerTest.java +++ b/services/src/test/java/org/keycloak/theme/KeycloakSanitizerTest.java @@ -30,11 +30,11 @@ import static org.junit.Assert.fail; * @author Stan Silvert */ public class KeycloakSanitizerTest { - private KeycloakSanitizerMethod kcEscape = new KeycloakSanitizerMethod(); + private final KeycloakSanitizerMethod kcEscape = new KeycloakSanitizerMethod(); @Test public void testEscapes() throws Exception { - List html = new ArrayList(); + List html = new ArrayList<>(); html.add("
Keycloak
"); String expectedResult = "
Keycloak
"; @@ -59,7 +59,27 @@ public class KeycloakSanitizerTest { expectedResult = ""; assertResult(expectedResult, html); } - + + @Test + public void testUrls() throws Exception { + List html = new ArrayList<>(); + + html.add("

link

"); + assertResult("

link

", html); + + html.set(0, "

link

"); + assertResult("

link

", html); + + html.set(0, "

link

"); + assertResult("

link

", html); + + html.set(0, "

link

"); + assertResult("

link

", html); + + html.set(0, "

link1link2

"); + assertResult("

link1link2

", html); + } + private void assertResult(String expectedResult, List html) throws Exception { String result = kcEscape.exec(html).toString(); assertEquals(expectedResult, result);