This is an automated email from the ASF dual-hosted git repository. rzo1 pushed a commit to branch tomee-10.x in repository https://gitbox.apache.org/repos/asf/tomee.git
commit 556f723e4ce0451857e3265716cda8a5e03d9623 Author: Markus Jung <[email protected]> AuthorDate: Sat Aug 29 16:06:07 2026 +0200 improve openejb-http resource lookup (cherry picked from commit f0702bf07a6517694edad3f5ffbf58824a4a36fd) --- .../openejb/server/httpd/HttpListenerRegistry.java | 26 ++++++++++++++++++++-- .../apache/openejb/server/httpd/ResourcesTest.java | 20 +++++++++++++++++ 2 files changed, 44 insertions(+), 2 deletions(-) diff --git a/server/openejb-http/src/main/java/org/apache/openejb/server/httpd/HttpListenerRegistry.java b/server/openejb-http/src/main/java/org/apache/openejb/server/httpd/HttpListenerRegistry.java index 66f8686160..f1794753d8 100644 --- a/server/openejb-http/src/main/java/org/apache/openejb/server/httpd/HttpListenerRegistry.java +++ b/server/openejb-http/src/main/java/org/apache/openejb/server/httpd/HttpListenerRegistry.java @@ -192,7 +192,7 @@ public class HttpListenerRegistry implements HttpListener { } if (!found) { final String servletPath = request.getServletPath(); - if (servletPath != null) { + if (servletPath != null && !isForbiddenResourcePath(servletPath)) { URL url = SystemInstance.get().getComponent(ServletContext.class).getResource(servletPath); if (url != null) { serveResource(servletPath, response, url); @@ -205,7 +205,7 @@ public class HttpListenerRegistry implements HttpListener { } else if (resourceBases.length > 0) { for (final File f : resourceBases) { final File file = new File(f, pathWithoutSlash); - if (file.isFile()) { + if (file.isFile() && isContained(f, file)) { url = file.toURI().toURL(); serveResource(servletPath, response, url); break; @@ -240,6 +240,28 @@ public class HttpListenerRegistry implements HttpListener { } } + private static boolean isForbiddenResourcePath(final String path) { + if (path.indexOf('\0') >= 0 || path.indexOf('\\') >= 0) { + return true; + } + for (final String segment : path.split("/")) { + if ("..".equals(segment)) { + return true; + } + } + return false; + } + + private static boolean isContained(final File base, final File file) { + try { + final String basePath = base.getCanonicalPath(); + final String filePath = file.getCanonicalPath(); + return filePath.equals(basePath) || filePath.startsWith(basePath + File.separator); + } catch (final IOException ioe) { + return false; + } + } + private void serveResource(final String key, final HttpResponse response, final URL url) throws IOException { if (cacheResources) { byte[] value = cache.get(key); diff --git a/server/openejb-http/src/test/java/org/apache/openejb/server/httpd/ResourcesTest.java b/server/openejb-http/src/test/java/org/apache/openejb/server/httpd/ResourcesTest.java index 0ce1530b5d..f78ceda53a 100644 --- a/server/openejb-http/src/test/java/org/apache/openejb/server/httpd/ResourcesTest.java +++ b/server/openejb-http/src/test/java/org/apache/openejb/server/httpd/ResourcesTest.java @@ -27,8 +27,11 @@ import org.junit.Rule; import org.junit.Test; import java.io.IOException; +import java.io.InputStream; +import java.net.HttpURLConnection; import java.net.URL; +import static org.junit.Assert.assertFalse; import static org.junit.Assert.assertTrue; @EnableServices("http") @@ -53,4 +56,21 @@ public class ResourcesTest { assertTrue(IO.slurp(new URL(context.toExternalForm() + "openejb/bar.txt")).contains("from web")); assertTrue(IO.slurp(new URL(context.toExternalForm() + "openejb/sub/bar.txt")).contains("from web2")); } + + @Test + public void parentSegmentsAreNotServed() throws IOException { + // src/test/web/../../../pom.xml resolves to the module pom + final String body = slurpQuietly(new URL(context.toExternalForm() + "openejb/%2e%2e/%2e%2e/%2e%2e/pom.xml")); + assertFalse(body, body.contains("<project")); + } + + private static String slurpQuietly(final URL url) throws IOException { + final HttpURLConnection connection = HttpURLConnection.class.cast(url.openConnection()); + try { + final InputStream stream = connection.getResponseCode() < 400 ? connection.getInputStream() : connection.getErrorStream(); + return stream == null ? "" : IO.slurp(stream); + } finally { + connection.disconnect(); + } + } }
