From a5b08e3a9dc63d20890835dff7ba83df2ee31e90 Mon Sep 17 00:00:00 2001
From: Lachlan Roberts
Date: Thu, 15 Jul 2021 14:53:22 +1000
Subject: [PATCH] Issue #6277 - add replacement Symlink AliasChecker
Signed-off-by: Lachlan Roberts
---
.../gcloud/session/GCloudSessionTester.java | 4 +-
.../server/AllowedResourceAliasChecker.java | 91 +++++++++++++------
.../jetty/server/SameFileAliasChecker.java | 2 +
.../SymlinkAllowedResourceAliasChecker.java | 74 +++++++++++++++
.../jetty/server/handler/ContextHandler.java | 12 ++-
.../handler/AllowSymLinkAliasCheckerTest.java | 3 +-
.../ContextHandlerGetResourceTest.java | 4 +-
.../jetty/servlet/DefaultServletTest.java | 9 +-
.../jetty/test/AliasCheckerSymlinkTest.java | 44 +++++++--
9 files changed, 188 insertions(+), 55 deletions(-)
create mode 100644 jetty-server/src/main/java/org/eclipse/jetty/server/SymlinkAllowedResourceAliasChecker.java
diff --git a/jetty-gcloud/jetty-gcloud-session-manager/src/test/java/org/eclipse/jetty/gcloud/session/GCloudSessionTester.java b/jetty-gcloud/jetty-gcloud-session-manager/src/test/java/org/eclipse/jetty/gcloud/session/GCloudSessionTester.java
index 5f4460aa7490..0d9908cc3101 100644
--- a/jetty-gcloud/jetty-gcloud-session-manager/src/test/java/org/eclipse/jetty/gcloud/session/GCloudSessionTester.java
+++ b/jetty-gcloud/jetty-gcloud-session-manager/src/test/java/org/eclipse/jetty/gcloud/session/GCloudSessionTester.java
@@ -20,7 +20,7 @@
import org.eclipse.jetty.security.HashLoginService;
import org.eclipse.jetty.server.Server;
-import org.eclipse.jetty.server.handler.AllowSymLinkAliasChecker;
+import org.eclipse.jetty.server.SymlinkAllowedResourceAliasChecker;
import org.eclipse.jetty.server.session.DefaultSessionCache;
import org.eclipse.jetty.server.session.DefaultSessionIdManager;
import org.eclipse.jetty.webapp.WebAppContext;
@@ -47,7 +47,7 @@ public static void main(String[] args) throws Exception
WebAppContext webapp = new WebAppContext();
webapp.setContextPath("/");
webapp.setWar("../../jetty-distribution/target/distribution/demo-base/webapps/test.war");
- webapp.addAliasCheck(new AllowSymLinkAliasChecker());
+ webapp.addAliasCheck(new SymlinkAllowedResourceAliasChecker(webapp));
GCloudSessionDataStore ds = new GCloudSessionDataStore();
DefaultSessionCache ss = new DefaultSessionCache(webapp.getSessionHandler());
diff --git a/jetty-server/src/main/java/org/eclipse/jetty/server/AllowedResourceAliasChecker.java b/jetty-server/src/main/java/org/eclipse/jetty/server/AllowedResourceAliasChecker.java
index 12221e50deac..d36ccec5985c 100644
--- a/jetty-server/src/main/java/org/eclipse/jetty/server/AllowedResourceAliasChecker.java
+++ b/jetty-server/src/main/java/org/eclipse/jetty/server/AllowedResourceAliasChecker.java
@@ -23,28 +23,36 @@
import java.nio.file.Files;
import java.nio.file.LinkOption;
import java.nio.file.Path;
+import java.util.Objects;
import org.eclipse.jetty.server.handler.ContextHandler;
import org.eclipse.jetty.util.StringUtil;
import org.eclipse.jetty.util.log.Log;
import org.eclipse.jetty.util.log.Logger;
+import org.eclipse.jetty.util.resource.PathResource;
import org.eclipse.jetty.util.resource.Resource;
/**
- * This will approve an alias to any resource which is not a protected target.
- * Except symlinks...
+ * This will approve any alias to anything inside of the {@link ContextHandler}s resource base which
+ * is not protected by {@link ContextHandler#isProtectedTarget(String)}.
+ * This will approve symlinks to outside of the resource base. This can be optionally configured to check that the
+ * target of the symlinks is also inside of the resource base and is not a protected target.
+ * Aliases approved by this may still be able to bypass SecurityConstraints, so this class would need to be extended
+ * to enforce any additional security constraints that are required.
*/
public class AllowedResourceAliasChecker implements ContextHandler.AliasCheck
{
private static final Logger LOG = Log.getLogger(AllowedResourceAliasChecker.class);
+ private static final LinkOption[] FOLLOW_LINKS = new LinkOption[0];
+ private static final LinkOption[] NO_FOLLOW_LINKS = new LinkOption[]{LinkOption.NOFOLLOW_LINKS};
+
private final ContextHandler _contextHandler;
private final boolean _checkSymlinkTargets;
- public AllowedResourceAliasChecker(ContextHandler contextHandler)
- {
- this(contextHandler, false);
- }
-
+ /**
+ * @param contextHandler the context handler to use.
+ * @param checkSymlinkTargets true to check that the target of the symlink is an allowed resource.
+ */
public AllowedResourceAliasChecker(ContextHandler contextHandler, boolean checkSymlinkTargets)
{
_contextHandler = contextHandler;
@@ -54,20 +62,22 @@ public AllowedResourceAliasChecker(ContextHandler contextHandler, boolean checkS
@Override
public boolean check(String uri, Resource resource)
{
+ // The existence check resolves the symlinks.
+ if (!resource.exists())
+ return false;
+
+ Path resourcePath = getPath(resource);
+ if (resourcePath == null)
+ return false;
+
try
{
- if (!resource.exists())
- return false;
-
- Path resourcePath = resource.getFile().toPath();
- Path realPath = resourcePath.toRealPath(LinkOption.NOFOLLOW_LINKS);
- if (isProtectedPath(realPath, false))
+ if (isProtectedPath(resourcePath, NO_FOLLOW_LINKS))
return false;
if (_checkSymlinkTargets && hasSymbolicLink(resourcePath))
{
- realPath = resourcePath.toRealPath();
- if (isProtectedPath(realPath, true))
+ if (isProtectedPath(resourcePath, FOLLOW_LINKS))
return false;
}
}
@@ -80,34 +90,40 @@ public boolean check(String uri, Resource resource)
return true;
}
- private boolean isProtectedPath(Path path, boolean followLinks) throws IOException
+ protected boolean isProtectedPath(Path resourcePath, LinkOption[] linkOptions) throws IOException
{
- String basePath = followLinks ? _contextHandler.getBaseResource().getFile().toPath().toRealPath().toString()
- : _contextHandler.getBaseResource().getFile().toPath().toRealPath(LinkOption.NOFOLLOW_LINKS).toString();
- String targetPath = path.toString();
+ String basePath = Objects.requireNonNull(getPath(_contextHandler.getBaseResource())).toRealPath(linkOptions).toString();
+ String targetPath = resourcePath.toRealPath(linkOptions).toString();
if (!targetPath.startsWith(basePath))
return true;
- for (String s : _contextHandler.getProtectedTargets())
+ String[] protectedTargets = _contextHandler.getProtectedTargets();
+ if (protectedTargets != null)
{
- String protectedTarget = new File(basePath, s).getCanonicalPath();
- if (StringUtil.startsWithIgnoreCase(targetPath, protectedTarget))
+ for (String s : protectedTargets)
{
- if (targetPath.length() == protectedTarget.length())
- return true;
-
- // Check that the target prefix really is a path segment.
- char c = targetPath.charAt(protectedTarget.length());
- if (c == File.separatorChar)
- return true;
+ // TODO: we are always following links f or the base resource.
+ // We cannot use toRealPath(linkOptions) here as it throws if file does not exist,
+ // and the protected targets do not have to always exist.
+ String protectedTarget = new File(basePath, s).getCanonicalPath();
+ if (StringUtil.startsWithIgnoreCase(targetPath, protectedTarget))
+ {
+ if (targetPath.length() == protectedTarget.length())
+ return true;
+
+ // Check that the target prefix really is a path segment.
+ char c = targetPath.charAt(protectedTarget.length());
+ if (c == File.separatorChar)
+ return true;
+ }
}
}
return false;
}
- private boolean hasSymbolicLink(Path path)
+ protected boolean hasSymbolicLink(Path path)
{
// Is file itself a symlink?
if (Files.isSymbolicLink(path))
@@ -125,6 +141,21 @@ private boolean hasSymbolicLink(Path path)
return false;
}
+ private Path getPath(Resource resource)
+ {
+ try
+ {
+ if (resource instanceof PathResource)
+ return ((PathResource)resource).getPath();
+ return resource.getFile().toPath();
+ }
+ catch (Throwable t)
+ {
+ LOG.ignore(t);
+ return null;
+ }
+ }
+
@Override
public String toString()
{
diff --git a/jetty-server/src/main/java/org/eclipse/jetty/server/SameFileAliasChecker.java b/jetty-server/src/main/java/org/eclipse/jetty/server/SameFileAliasChecker.java
index 5f7009e96a3b..50eb3e84faa7 100644
--- a/jetty-server/src/main/java/org/eclipse/jetty/server/SameFileAliasChecker.java
+++ b/jetty-server/src/main/java/org/eclipse/jetty/server/SameFileAliasChecker.java
@@ -44,7 +44,9 @@
* or Linux on XFS) the the actual file could be stored using UTF-16,
* but be accessed using NFD UTF-8 or NFC UTF-8 for the same file.
*
+ * @deprecated use {@link org.eclipse.jetty.server.AllowedResourceAliasChecker} instead.
*/
+@Deprecated
public class SameFileAliasChecker implements AliasCheck
{
private static final Logger LOG = Log.getLogger(SameFileAliasChecker.class);
diff --git a/jetty-server/src/main/java/org/eclipse/jetty/server/SymlinkAllowedResourceAliasChecker.java b/jetty-server/src/main/java/org/eclipse/jetty/server/SymlinkAllowedResourceAliasChecker.java
new file mode 100644
index 000000000000..2917b54a642f
--- /dev/null
+++ b/jetty-server/src/main/java/org/eclipse/jetty/server/SymlinkAllowedResourceAliasChecker.java
@@ -0,0 +1,74 @@
+//
+// ========================================================================
+// Copyright (c) 1995-2021 Mort Bay Consulting Pty Ltd and others.
+// ------------------------------------------------------------------------
+// All rights reserved. This program and the accompanying materials
+// are made available under the terms of the Eclipse Public License v1.0
+// and Apache License v2.0 which accompanies this distribution.
+//
+// The Eclipse Public License is available at
+// http://www.eclipse.org/legal/epl-v10.html
+//
+// The Apache License v2.0 is available at
+// http://www.opensource.org/licenses/apache2.0.php
+//
+// You may elect to redistribute this code under either of these licenses.
+// ========================================================================
+//
+
+package org.eclipse.jetty.server;
+
+import java.io.IOException;
+import java.nio.file.Files;
+import java.nio.file.Path;
+
+import org.eclipse.jetty.server.handler.ContextHandler;
+import org.eclipse.jetty.util.log.Log;
+import org.eclipse.jetty.util.log.Logger;
+import org.eclipse.jetty.util.resource.Resource;
+
+/**
+ * An extension of {@link AllowedResourceAliasChecker} which only allows resources if they are symlinks.
+ */
+public class SymlinkAllowedResourceAliasChecker extends AllowedResourceAliasChecker
+{
+ private static final Logger LOG = Log.getLogger(SymlinkAllowedResourceAliasChecker.class);
+ private final ContextHandler _contextHandler;
+
+ /**
+ * @param contextHandler the context handler to use.
+ */
+ public SymlinkAllowedResourceAliasChecker(ContextHandler contextHandler)
+ {
+ super(contextHandler, false);
+ _contextHandler = contextHandler;
+ }
+
+ @Override
+ public boolean check(String uri, Resource resource)
+ {
+ try
+ {
+ // Check the resource is allowed to be accessed.
+ if (!super.check(uri, resource))
+ return false;
+
+ // Only approve resource if it is accessed by a symbolic link.
+ Path resourcePath = resource.getFile().toPath();
+ if (Files.isSymbolicLink(resourcePath))
+ return true;
+
+ // TODO: If base resource contains symlink then this will always return true.
+ // But we don't want to deny all paths if the resource base is symbolically linked.
+ if (super.hasSymbolicLink(resourcePath))
+ return true;
+ }
+ catch (IOException e)
+ {
+ LOG.ignore(e);
+ return false;
+ }
+
+ return false;
+ }
+}
diff --git a/jetty-server/src/main/java/org/eclipse/jetty/server/handler/ContextHandler.java b/jetty-server/src/main/java/org/eclipse/jetty/server/handler/ContextHandler.java
index 97ef7e7442cd..222bcf14db3b 100644
--- a/jetty-server/src/main/java/org/eclipse/jetty/server/handler/ContextHandler.java
+++ b/jetty-server/src/main/java/org/eclipse/jetty/server/handler/ContextHandler.java
@@ -68,6 +68,7 @@
import org.eclipse.jetty.http.HttpURI;
import org.eclipse.jetty.http.MimeTypes;
+import org.eclipse.jetty.server.AllowedResourceAliasChecker;
import org.eclipse.jetty.server.ClassLoaderDump;
import org.eclipse.jetty.server.Connector;
import org.eclipse.jetty.server.Dispatcher;
@@ -75,6 +76,7 @@
import org.eclipse.jetty.server.HandlerContainer;
import org.eclipse.jetty.server.Request;
import org.eclipse.jetty.server.Server;
+import org.eclipse.jetty.server.SymlinkAllowedResourceAliasChecker;
import org.eclipse.jetty.util.Attributes;
import org.eclipse.jetty.util.AttributesMap;
import org.eclipse.jetty.util.FutureCallback;
@@ -108,8 +110,8 @@
* The executor is made available via a context attributed {@code org.eclipse.jetty.server.Executor}.
*
*
- * By default, the context is created with alias checkers for {@link AllowSymLinkAliasChecker} (unix only) and {@link ApproveNonExistentDirectoryAliases}. If
- * these alias checkers are not required, then {@link #clearAliasChecks()} or {@link #setAliasChecks(List)} should be called.
+ * By default, the context is created with the {@link AllowedResourceAliasChecker} which is configured to allow symlinks. If
+ * this alias checker is not required, then {@link #clearAliasChecks()} or {@link #setAliasChecks(List)} should be called.
*
*/
@ManagedObject("URI Context")
@@ -264,9 +266,8 @@ private ContextHandler(Context context, HandlerContainer parent, String contextP
_scontext = context == null ? new Context() : context;
_attributes = new AttributesMap();
_initParams = new HashMap<>();
- addAliasCheck(new ApproveNonExistentDirectoryAliases());
if (File.separatorChar == '/')
- addAliasCheck(new AllowSymLinkAliasChecker());
+ addAliasCheck(new SymlinkAllowedResourceAliasChecker(this));
if (contextPath != null)
setContextPath(contextPath);
@@ -2970,7 +2971,9 @@ public interface AliasCheck
/**
* Approve all aliases.
+ * @deprecated use {@link org.eclipse.jetty.server.AllowedResourceAliasChecker} instead.
*/
+ @Deprecated
public static class ApproveAliases implements AliasCheck
{
@Override
@@ -2983,6 +2986,7 @@ public boolean check(String path, Resource resource)
/**
* Approve Aliases of a non existent directory. If a directory "/foobar/" does not exist, then the resource is aliased to "/foobar". Accept such aliases.
*/
+ @Deprecated
public static class ApproveNonExistentDirectoryAliases implements AliasCheck
{
@Override
diff --git a/jetty-server/src/test/java/org/eclipse/jetty/server/handler/AllowSymLinkAliasCheckerTest.java b/jetty-server/src/test/java/org/eclipse/jetty/server/handler/AllowSymLinkAliasCheckerTest.java
index 91c201b36735..8dc13acb416c 100644
--- a/jetty-server/src/test/java/org/eclipse/jetty/server/handler/AllowSymLinkAliasCheckerTest.java
+++ b/jetty-server/src/test/java/org/eclipse/jetty/server/handler/AllowSymLinkAliasCheckerTest.java
@@ -32,6 +32,7 @@
import org.eclipse.jetty.http.HttpTester;
import org.eclipse.jetty.server.LocalConnector;
import org.eclipse.jetty.server.Server;
+import org.eclipse.jetty.server.SymlinkAllowedResourceAliasChecker;
import org.eclipse.jetty.toolchain.test.FS;
import org.eclipse.jetty.toolchain.test.MavenTestingUtils;
import org.eclipse.jetty.util.BufferUtil;
@@ -184,7 +185,7 @@ private void setupServer() throws Exception
fileResourceContext.setBaseResource(new PathResource(rootPath));
fileResourceContext.clearAliasChecks();
- fileResourceContext.addAliasCheck(new AllowSymLinkAliasChecker());
+ fileResourceContext.addAliasCheck(new SymlinkAllowedResourceAliasChecker(fileResourceContext));
server.setHandler(fileResourceContext);
server.start();
diff --git a/jetty-server/src/test/java/org/eclipse/jetty/server/handler/ContextHandlerGetResourceTest.java b/jetty-server/src/test/java/org/eclipse/jetty/server/handler/ContextHandlerGetResourceTest.java
index a82c14a07e8d..e083bc002184 100644
--- a/jetty-server/src/test/java/org/eclipse/jetty/server/handler/ContextHandlerGetResourceTest.java
+++ b/jetty-server/src/test/java/org/eclipse/jetty/server/handler/ContextHandlerGetResourceTest.java
@@ -24,6 +24,7 @@
import java.nio.file.Files;
import java.util.concurrent.atomic.AtomicBoolean;
+import org.eclipse.jetty.server.AllowedResourceAliasChecker;
import org.eclipse.jetty.server.Server;
import org.eclipse.jetty.toolchain.test.FS;
import org.eclipse.jetty.toolchain.test.MavenTestingUtils;
@@ -109,11 +110,10 @@ public static void beforeClass() throws Exception
server = new Server();
context = new ContextHandler("/");
context.clearAliasChecks();
- context.addAliasCheck(new ContextHandler.ApproveNonExistentDirectoryAliases());
context.setBaseResource(Resource.newResource(docroot));
context.addAliasCheck(new ContextHandler.AliasCheck()
{
- final AllowSymLinkAliasChecker symlinkcheck = new AllowSymLinkAliasChecker();
+ final AllowedResourceAliasChecker symlinkcheck = new AllowedResourceAliasChecker(context, false);
@Override
public boolean check(String path, Resource resource)
diff --git a/jetty-servlet/src/test/java/org/eclipse/jetty/servlet/DefaultServletTest.java b/jetty-servlet/src/test/java/org/eclipse/jetty/servlet/DefaultServletTest.java
index 85ac1d39fe91..fb9184ef7640 100644
--- a/jetty-servlet/src/test/java/org/eclipse/jetty/servlet/DefaultServletTest.java
+++ b/jetty-servlet/src/test/java/org/eclipse/jetty/servlet/DefaultServletTest.java
@@ -52,13 +52,12 @@
import org.eclipse.jetty.http.HttpHeader;
import org.eclipse.jetty.http.HttpStatus;
import org.eclipse.jetty.http.HttpTester;
+import org.eclipse.jetty.server.AllowedResourceAliasChecker;
import org.eclipse.jetty.server.HttpConfiguration;
import org.eclipse.jetty.server.LocalConnector;
import org.eclipse.jetty.server.ResourceContentFactory;
import org.eclipse.jetty.server.ResourceService;
-import org.eclipse.jetty.server.SameFileAliasChecker;
import org.eclipse.jetty.server.Server;
-import org.eclipse.jetty.server.handler.AllowSymLinkAliasChecker;
import org.eclipse.jetty.toolchain.test.FS;
import org.eclipse.jetty.toolchain.test.MavenTestingUtils;
import org.eclipse.jetty.toolchain.test.jupiter.WorkDir;
@@ -1097,8 +1096,6 @@ public void testSymLinks() throws Exception
response = HttpTester.parseResponse(rawResponse);
assertThat(response.toString(), response.getStatus(), is(HttpStatus.NOT_FOUND_404));
- context.addAliasCheck(new AllowSymLinkAliasChecker());
-
rawResponse = connector.getResponse("GET /context/dir/link.txt HTTP/1.0\r\n\r\n");
response = HttpTester.parseResponse(rawResponse);
assertThat(response.toString(), response.getStatus(), is(HttpStatus.OK_200));
@@ -2070,7 +2067,7 @@ public void testGetUtf8NfcFile() throws Exception
FS.ensureEmpty(docRoot);
context.addServlet(DefaultServlet.class, "/");
- context.addAliasCheck(new SameFileAliasChecker());
+ context.addAliasCheck(new AllowedResourceAliasChecker(context, true));
// Create file with UTF-8 NFC format
String filename = "swedish-" + new String(TypeUtil.fromHexString("C3A5"), UTF_8) + ".txt";
@@ -2110,7 +2107,7 @@ public void testGetUtf8NfdFile() throws Exception
FS.ensureEmpty(docRoot);
context.addServlet(DefaultServlet.class, "/");
- context.addAliasCheck(new SameFileAliasChecker());
+ context.addAliasCheck(new AllowedResourceAliasChecker(context, true));
// Create file with UTF-8 NFD format
String filename = "swedish-a" + new String(TypeUtil.fromHexString("CC8A"), UTF_8) + ".txt";
diff --git a/tests/test-integration/src/test/java/org/eclipse/jetty/test/AliasCheckerSymlinkTest.java b/tests/test-integration/src/test/java/org/eclipse/jetty/test/AliasCheckerSymlinkTest.java
index a19c98d90b31..05cb240bd1fd 100644
--- a/tests/test-integration/src/test/java/org/eclipse/jetty/test/AliasCheckerSymlinkTest.java
+++ b/tests/test-integration/src/test/java/org/eclipse/jetty/test/AliasCheckerSymlinkTest.java
@@ -31,6 +31,7 @@
import org.eclipse.jetty.server.AllowedResourceAliasChecker;
import org.eclipse.jetty.server.Server;
import org.eclipse.jetty.server.ServerConnector;
+import org.eclipse.jetty.server.SymlinkAllowedResourceAliasChecker;
import org.eclipse.jetty.server.handler.AllowSymLinkAliasChecker;
import org.eclipse.jetty.server.handler.ContextHandler;
import org.eclipse.jetty.servlet.DefaultServlet;
@@ -39,6 +40,7 @@
import org.eclipse.jetty.util.resource.PathResource;
import org.junit.jupiter.api.AfterAll;
import org.junit.jupiter.api.BeforeAll;
+import org.junit.jupiter.api.Test;
import org.junit.jupiter.params.ParameterizedTest;
import org.junit.jupiter.params.provider.Arguments;
import org.junit.jupiter.params.provider.MethodSource;
@@ -109,13 +111,19 @@ public static void beforeAll() throws Exception
delete(webInfSymlink);
Files.createSymbolicLink(webInfSymlink, webRootPath.resolve("WEB-INF")).toFile().deleteOnExit();
+ // External symlink to webroot.
+ Path webrootSymlink = webRootPath.resolve("../webrootSymlink");
+ delete(webrootSymlink);
+ Files.createSymbolicLink(webrootSymlink, webRootPath).toFile().deleteOnExit();
+
// Create and start Server and Client.
_server = new Server();
_connector = new ServerConnector(_server);
+ _connector.setPort(8080);
_server.addConnector(_connector);
_context = new ServletContextHandler();
_context.setContextPath("/");
- _context.setBaseResource(new PathResource(webRootPath));
+ _context.setBaseResource(new PathResource(webrootSymlink));
_context.setWelcomeFiles(new String[]{"index.html"});
_context.setProtectedTargets(new String[]{"/web-inf", "/meta-inf"});
_context.getMimeTypes().addMimeMapping("txt", "text/plain;charset=utf-8");
@@ -134,10 +142,17 @@ public static void afterAll() throws Exception
_server.stop();
}
+ @Test
+ public void test() throws Exception
+ {
+ _server.join();
+ }
+
public static Stream testCases()
{
- AllowedResourceAliasChecker allowedResource = new AllowedResourceAliasChecker(_context);
- AllowedResourceAliasChecker allowedResourceSymlinks = new AllowedResourceAliasChecker(_context, true);
+ AllowedResourceAliasChecker allowedResource = new AllowedResourceAliasChecker(_context, false);
+ AllowedResourceAliasChecker allowedResourceTarget = new AllowedResourceAliasChecker(_context, true);
+ SymlinkAllowedResourceAliasChecker symlinkAllowedResource = new SymlinkAllowedResourceAliasChecker(_context);
AllowSymLinkAliasChecker allowSymlinks = new AllowSymLinkAliasChecker();
ContextHandler.ApproveAliases approveAliases = new ContextHandler.ApproveAliases();
@@ -152,13 +167,22 @@ public static Stream testCases()
Arguments.of(allowedResource, "/webInfSymlink/web.xml", HttpStatus.OK_200, "This is the web.xml file."),
// AllowedResourceAliasChecker that checks the target of symlinks.
- Arguments.of(allowedResourceSymlinks, "/symlinkFile", HttpStatus.OK_200, "This file is inside webroot."),
- Arguments.of(allowedResourceSymlinks, "/symlinkExternalFile", HttpStatus.NOT_FOUND_404, null),
- Arguments.of(allowedResourceSymlinks, "/symlinkDir/file", HttpStatus.OK_200, "This file is inside webroot/documents."),
- Arguments.of(allowedResourceSymlinks, "/symlinkParentDir/webroot/file", HttpStatus.OK_200, "This file is inside webroot."),
- Arguments.of(allowedResourceSymlinks, "/symlinkParentDir/webroot/WEB-INF/web.xml", HttpStatus.NOT_FOUND_404, null),
- Arguments.of(allowedResourceSymlinks, "/symlinkSiblingDir/file", HttpStatus.NOT_FOUND_404, null),
- Arguments.of(allowedResourceSymlinks, "/webInfSymlink/web.xml", HttpStatus.NOT_FOUND_404, null),
+ Arguments.of(allowedResourceTarget, "/symlinkFile", HttpStatus.OK_200, "This file is inside webroot."),
+ Arguments.of(allowedResourceTarget, "/symlinkExternalFile", HttpStatus.NOT_FOUND_404, null),
+ Arguments.of(allowedResourceTarget, "/symlinkDir/file", HttpStatus.OK_200, "This file is inside webroot/documents."),
+ Arguments.of(allowedResourceTarget, "/symlinkParentDir/webroot/file", HttpStatus.OK_200, "This file is inside webroot."),
+ Arguments.of(allowedResourceTarget, "/symlinkParentDir/webroot/WEB-INF/web.xml", HttpStatus.NOT_FOUND_404, null),
+ Arguments.of(allowedResourceTarget, "/symlinkSiblingDir/file", HttpStatus.NOT_FOUND_404, null),
+ Arguments.of(allowedResourceTarget, "/webInfSymlink/web.xml", HttpStatus.NOT_FOUND_404, null),
+
+ // SymlinkAllowedResourceAliasChecker that does not check the target of symlinks, but only approves files obtained through a symlink.
+ Arguments.of(allowedResource, "/symlinkFile", HttpStatus.OK_200, "This file is inside webroot."),
+ Arguments.of(allowedResource, "/symlinkExternalFile", HttpStatus.OK_200, "This file is outside webroot."),
+ Arguments.of(allowedResource, "/symlinkDir/file", HttpStatus.OK_200, "This file is inside webroot/documents."),
+ Arguments.of(allowedResource, "/symlinkParentDir/webroot/file", HttpStatus.OK_200, "This file is inside webroot."),
+ Arguments.of(allowedResource, "/symlinkParentDir/webroot/WEB-INF/web.xml", HttpStatus.OK_200, "This is the web.xml file."),
+ Arguments.of(allowedResource, "/symlinkSiblingDir/file", HttpStatus.OK_200, "This file is inside a sibling dir to webroot."),
+ Arguments.of(allowedResource, "/webInfSymlink/web.xml", HttpStatus.OK_200, "This is the web.xml file."),
// The AllowSymLinkAliasChecker.
Arguments.of(allowSymlinks, "/symlinkFile", HttpStatus.OK_200, "This file is inside webroot."),