From 5fe916861df60a8791b14d84474eaa517ca97c81 Mon Sep 17 00:00:00 2001 From: rmartinc Date: Wed, 11 Sep 2024 13:15:28 +0200 Subject: [PATCH] Return 404 on invalid theme type Closes #32798 Signed-off-by: rmartinc --- .../services/resources/ThemeResource.java | 31 +++++++++++++------ .../theme/ThemeResourceProviderTest.java | 15 +++++++++ 2 files changed, 36 insertions(+), 10 deletions(-) diff --git a/services/src/main/java/org/keycloak/services/resources/ThemeResource.java b/services/src/main/java/org/keycloak/services/resources/ThemeResource.java index a8ce7363c4..707efd6d6c 100644 --- a/services/src/main/java/org/keycloak/services/resources/ThemeResource.java +++ b/services/src/main/java/org/keycloak/services/resources/ThemeResource.java @@ -46,6 +46,7 @@ import java.util.ArrayList; import java.util.List; import java.util.Locale; import java.util.Map; +import java.util.Optional; import java.util.Properties; import java.util.Set; @@ -67,26 +68,28 @@ public class ThemeResource { /** * Get theme content * - * @param themType + * @param version + * @param themeType * @param themeName * @param path * @return */ @GET @Path("/{version}/{themeType}/{themeName}/{path:.*}") - public Response getResource(@PathParam("version") String version, @PathParam("themeType") String themType, @PathParam("themeName") String themeName, @PathParam("path") String path) { - if (!version.equals(Version.RESOURCES_VERSION)) { + public Response getResource(@PathParam("version") String version, @PathParam("themeType") String themeType, @PathParam("themeName") String themeName, @PathParam("path") String path) { + final Optional type = getThemeType(themeType); + if (!version.equals(Version.RESOURCES_VERSION) || type.isEmpty()) { return Response.status(Response.Status.NOT_FOUND).build(); } try { String contentType = MimeTypeUtil.getContentType(path); - Theme theme = session.theme().getTheme(themeName, Theme.Type.valueOf(themType.toUpperCase())); + Theme theme = session.theme().getTheme(themeName, type.get()); ResourceEncodingProvider encodingProvider = session.theme().isCacheEnabled() ? ResourceEncodingHelper.getResourceEncodingProvider(session, contentType) : null; InputStream resource; if (encodingProvider != null) { - resource = encodingProvider.getEncodedStream(() -> theme.getResourceAsStream(path), themType, themeName, path.replace('/', File.separatorChar)); + resource = encodingProvider.getEncodedStream(() -> theme.getResourceAsStream(path), themeType, themeName, path.replace('/', File.separatorChar)); } else { resource = theme.getResourceAsStream(path); } @@ -119,18 +122,18 @@ public class ThemeResource { @PathParam("locale") String localeString, @PathParam("themeType") String themeType, @QueryParam("source") boolean showSource) throws IOException { final RealmModel realm = session.realms().getRealmByName(realmName); - if (realm == null) { + final Optional type = getThemeType(themeType); + if (realm == null || type.isEmpty()) { return Response.status(Response.Status.NOT_FOUND).build(); } session.getContext().setRealm(realm); List result; Theme theTheme; - final Theme.Type type = Theme.Type.valueOf(themeType.toUpperCase()); if (theme == null) { - theTheme = session.theme().getTheme(type); + theTheme = session.theme().getTheme(type.get()); } else { - theTheme = session.theme().getTheme(theme, type); + theTheme = session.theme().getTheme(theme, type.get()); } final Locale locale = Locale.forLanguageTag(localeString); @@ -153,6 +156,14 @@ public class ThemeResource { return Cors.builder().allowedOrigins("*").auth().add(Response.ok(result)); } + + private static Optional getThemeType(String themeType) { + try { + return Optional.of(Theme.Type.valueOf(themeType.toUpperCase())); + } catch (IllegalArgumentException iae) { + return Optional.empty(); + } + } } enum Source { @@ -186,4 +197,4 @@ class KeySource { public Source getSource() { return source; } -} \ No newline at end of file +} diff --git a/testsuite/integration-arquillian/tests/base/src/test/java/org/keycloak/testsuite/theme/ThemeResourceProviderTest.java b/testsuite/integration-arquillian/tests/base/src/test/java/org/keycloak/testsuite/theme/ThemeResourceProviderTest.java index edfd7a8087..47b4ec394d 100644 --- a/testsuite/integration-arquillian/tests/base/src/test/java/org/keycloak/testsuite/theme/ThemeResourceProviderTest.java +++ b/testsuite/integration-arquillian/tests/base/src/test/java/org/keycloak/testsuite/theme/ThemeResourceProviderTest.java @@ -136,6 +136,21 @@ public class ThemeResourceProviderTest extends AbstractTestRealmKeycloakTest { }); } + @Test + public void notFoundOnInvalidThemeType() throws IOException { + final String resourcesVersion = testingClient.server().fetch(session -> Version.RESOURCES_VERSION, String.class); + assertNotFound(suiteContext.getAuthServerInfo().getContextRoot().toString() + "/auth/resources/" + resourcesVersion + "/invalid-theme-type/keycloak/css/welcome.css"); + } + + private void assertNotFound(String url) throws IOException { + try (CloseableHttpClient httpClient = HttpClientBuilder.create().build()) { + HttpGet get = new HttpGet(url); + try (CloseableHttpResponse response = httpClient.execute(get)) { + assertEquals(404, response.getStatusLine().getStatusCode()); + } + } + } + private void assertEncoded(String url, String expectedContent) throws IOException { try (CloseableHttpClient httpClient = HttpClientBuilder.create().disableContentCompression().build()) { HttpGet get = new HttpGet(url);