Skip to main content
aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorGreg Wilkins2014-08-02 02:58:24 +0000
committerGreg Wilkins2014-08-02 02:58:24 +0000
commitaaa2e5c6c1d6d34f8068dc9a056a6b446fd05603 (patch)
tree2db8c5be4c3750e5d6b16a82064cf95cce72e758
parent1873b306b37616252b989bca44b36209ab40a08a (diff)
downloadorg.eclipse.jetty.project-aaa2e5c6c1d6d34f8068dc9a056a6b446fd05603.tar.gz
org.eclipse.jetty.project-aaa2e5c6c1d6d34f8068dc9a056a6b446fd05603.tar.xz
org.eclipse.jetty.project-aaa2e5c6c1d6d34f8068dc9a056a6b446fd05603.zip
refined PathResource alias handling
-rw-r--r--jetty-quickstart/src/main/java/org/eclipse/jetty/quickstart/QuickStartConfiguration.java2
-rw-r--r--jetty-server/src/main/java/org/eclipse/jetty/server/handler/AllowSymLinkAliasChecker.java67
-rw-r--r--jetty-server/src/main/java/org/eclipse/jetty/server/handler/ContextHandler.java2
-rw-r--r--jetty-server/src/main/java/org/eclipse/jetty/server/handler/ResourceHandler.java2
-rw-r--r--jetty-server/src/test/java/org/eclipse/jetty/server/handler/ContextHandlerGetResourceTest.java5
-rw-r--r--jetty-util/src/main/java/org/eclipse/jetty/util/resource/PathResource.java51
-rw-r--r--jetty-util/src/main/java/org/eclipse/jetty/util/resource/Resource.java6
-rw-r--r--jetty-util/src/test/java/org/eclipse/jetty/util/resource/FileSystemResourceTest.java44
-rw-r--r--jetty-webapp/src/main/java/org/eclipse/jetty/webapp/WebInfConfiguration.java2
9 files changed, 124 insertions, 57 deletions
diff --git a/jetty-quickstart/src/main/java/org/eclipse/jetty/quickstart/QuickStartConfiguration.java b/jetty-quickstart/src/main/java/org/eclipse/jetty/quickstart/QuickStartConfiguration.java
index 85f95dcb6a..88552d660a 100644
--- a/jetty-quickstart/src/main/java/org/eclipse/jetty/quickstart/QuickStartConfiguration.java
+++ b/jetty-quickstart/src/main/java/org/eclipse/jetty/quickstart/QuickStartConfiguration.java
@@ -57,7 +57,7 @@ public class QuickStartConfiguration extends WebInfConfiguration
Resource webApp = context.newResource(war);
// Accept aliases for WAR files
- if (webApp.getAlias() != null)
+ if (webApp.isAlias())
{
LOG.debug(webApp + " anti-aliased to " + webApp.getAlias());
webApp = context.newResource(webApp.getAlias());
diff --git a/jetty-server/src/main/java/org/eclipse/jetty/server/handler/AllowSymLinkAliasChecker.java b/jetty-server/src/main/java/org/eclipse/jetty/server/handler/AllowSymLinkAliasChecker.java
index 427c5b0592..5a402ec7d9 100644
--- a/jetty-server/src/main/java/org/eclipse/jetty/server/handler/AllowSymLinkAliasChecker.java
+++ b/jetty-server/src/main/java/org/eclipse/jetty/server/handler/AllowSymLinkAliasChecker.java
@@ -26,6 +26,7 @@ import java.nio.file.Path;
import org.eclipse.jetty.server.handler.ContextHandler.AliasCheck;
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;
@@ -41,56 +42,52 @@ public class AllowSymLinkAliasChecker implements AliasCheck
private static final Logger LOG = Log.getLogger(AllowSymLinkAliasChecker.class);
@Override
- public boolean check(String path, Resource resource)
+ public boolean check(String uri, Resource resource)
{
+ // Only support PathResource alias checking
+ if (!(resource instanceof PathResource))
+ return false;
+
+ PathResource pathResource = (PathResource)resource;
+
try
{
- File file =resource.getFile();
- if (file==null)
- return false;
+ Path path = pathResource.getPath();
- // If the file exists
- if (file.exists())
+ // is the file itself a symlink?
+ if (Files.isSymbolicLink(path) && Files.isSameFile(path,pathResource.getAliasPath()))
{
- // we can use the real path method to check the symlinks resolve to the alias
- URI real = file.toPath().toRealPath().toUri();
- if (real.equals(resource.getAlias()))
- {
- if (LOG.isDebugEnabled())
- LOG.debug("Allow symlink {} --> {}",resource,real);
- return true;
- }
+ if (LOG.isDebugEnabled())
+ LOG.debug("Allow symlink {} --> {}",resource,pathResource.getAliasPath());
+ return true;
}
- else
+
+ // No, so let's check each element ourselves
+ Path d = path.getRoot();
+ for (Path e:path)
{
- // file does not exists, so we have to walk the path and links ourselves.
- Path p = file.toPath().toAbsolutePath();
- File d = p.getRoot().toFile();
- for (Path e:p)
+ d=d.resolve(e);
+
+ while (Files.exists(d) && Files.isSymbolicLink(d))
{
- d=new File(d,e.toString());
-
- while (d.exists() && Files.isSymbolicLink(d.toPath()))
- {
- Path link=Files.readSymbolicLink(d.toPath());
- if (!link.isAbsolute())
- link=link.resolve(d.toPath());
- d=link.toFile().getAbsoluteFile().getCanonicalFile();
- }
- }
- if (resource.getAlias().equals(d.toURI()))
- {
- if (LOG.isDebugEnabled())
- LOG.debug("Allow symlink {} --> {}",resource,d);
- return true;
+ Path link=Files.readSymbolicLink(d);
+ if (!link.isAbsolute())
+ link=d.resolve(link);
+ d=link;
}
}
+ if (pathResource.getAliasPath().equals(d))
+ {
+ if (LOG.isDebugEnabled())
+ LOG.debug("Allow path symlink {} --> {}",resource,d);
+ return true;
+ }
}
catch(Exception e)
{
- e.printStackTrace();
LOG.ignore(e);
}
+
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 8208110f8d..9dc9794fa4 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
@@ -1668,7 +1668,7 @@ public class ContextHandler extends ScopedHandler implements Attributes, Gracefu
public boolean checkAlias(String path, Resource resource)
{
// Is the resource aliased?
- if (resource.getAlias() != null)
+ if (resource.isAlias())
{
if (LOG.isDebugEnabled())
LOG.debug("Aliased resource: " + resource + "~=" + resource.getAlias());
diff --git a/jetty-server/src/main/java/org/eclipse/jetty/server/handler/ResourceHandler.java b/jetty-server/src/main/java/org/eclipse/jetty/server/handler/ResourceHandler.java
index 80375a47f5..2f95f6cc02 100644
--- a/jetty-server/src/main/java/org/eclipse/jetty/server/handler/ResourceHandler.java
+++ b/jetty-server/src/main/java/org/eclipse/jetty/server/handler/ResourceHandler.java
@@ -315,7 +315,7 @@ public class ResourceHandler extends HandlerWrapper
{
path=URIUtil.canonicalPath(path);
Resource r = base.addPath(path);
- if (r!=null && r.getAlias()!=null && !_context.checkAlias(path, r))
+ if (r!=null && r.isAlias() && !_context.checkAlias(path, r))
return null;
return r;
}
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 1f5cddd74e..aace3e7779 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
@@ -33,6 +33,7 @@ import org.eclipse.jetty.toolchain.test.MavenTestingUtils;
import org.eclipse.jetty.toolchain.test.OS;
import org.eclipse.jetty.util.resource.Resource;
import org.junit.AfterClass;
+import org.junit.Assert;
import org.junit.Assume;
import org.junit.BeforeClass;
import org.junit.Test;
@@ -352,8 +353,8 @@ public class ContextHandlerGetResourceTest
@Test
public void testSymlinkKnown() throws Exception
{
- if (!OS.IS_UNIX)
- return;
+ Assume.assumeTrue(OS.IS_UNIX);
+
try
{
allowSymlinks.set(true);
diff --git a/jetty-util/src/main/java/org/eclipse/jetty/util/resource/PathResource.java b/jetty-util/src/main/java/org/eclipse/jetty/util/resource/PathResource.java
index da48349e71..c7da550de8 100644
--- a/jetty-util/src/main/java/org/eclipse/jetty/util/resource/PathResource.java
+++ b/jetty-util/src/main/java/org/eclipse/jetty/util/resource/PathResource.java
@@ -50,36 +50,41 @@ import org.eclipse.jetty.util.log.Logger;
public class PathResource extends Resource
{
private static final Logger LOG = Log.getLogger(PathResource.class);
- private final static LinkOption NO_FOLLOW_OPTIONS[] = new LinkOption[] { LinkOption.NOFOLLOW_LINKS };
+ private final static LinkOption NO_FOLLOW_LINKS[] = new LinkOption[] { LinkOption.NOFOLLOW_LINKS };
+ private final static LinkOption FOLLOW_LINKS[] = new LinkOption[] {};
private final Path path;
- private final URI alias;
+ private final Path alias;
private final URI uri;
- private static final URI toAliasUri(final Path path)
+ private static final Path checkAliasPath(final Path path)
{
Path abs = path;
if (!abs.isAbsolute())
{
abs = path.toAbsolutePath();
}
- URI providedUri = abs.toUri();
+
try
{
- URI realUri = abs.toRealPath().toUri();
- if (!providedUri.equals(realUri))
+ if (Files.isSymbolicLink(path))
+ return Files.readSymbolicLink(path);
+ if (Files.exists(path))
{
- return realUri;
+ Path real = abs.toRealPath(FOLLOW_LINKS);
+ if (!abs.equals(real))
+ return real;
}
}
catch (NoSuchFileException e)
{
// Ignore
}
- catch (IOException e)
+ catch (Exception e)
{
// TODO: reevaluate severity level
LOG.warn("bad alias ({}) for {}", e.getClass().getName(), e.getMessage());
+ return abs;
}
return null;
}
@@ -93,7 +98,7 @@ public class PathResource extends Resource
{
this.path = path.toAbsolutePath();
this.uri = this.path.toUri();
- this.alias = toAliasUri(path);
+ this.alias = checkAliasPath(path);
}
public PathResource(URI uri) throws IOException
@@ -129,7 +134,7 @@ public class PathResource extends Resource
this.path = path.toAbsolutePath();
this.uri = path.toUri();
- this.alias = toAliasUri(path);
+ this.alias = checkAliasPath(path);
}
public PathResource(URL url) throws IOException, URISyntaxException
@@ -211,7 +216,7 @@ public class PathResource extends Resource
@Override
public boolean exists()
{
- return Files.exists(path,NO_FOLLOW_OPTIONS);
+ return Files.exists(path,NO_FOLLOW_LINKS);
}
@Override
@@ -220,6 +225,11 @@ public class PathResource extends Resource
return path.toFile();
}
+ public Path getPath() throws IOException
+ {
+ return path;
+ }
+
@Override
public InputStream getInputStream() throws IOException
{
@@ -276,7 +286,7 @@ public class PathResource extends Resource
@Override
public boolean isDirectory()
{
- return Files.isDirectory(path,NO_FOLLOW_OPTIONS);
+ return Files.isDirectory(path,NO_FOLLOW_LINKS);
}
@Override
@@ -284,7 +294,7 @@ public class PathResource extends Resource
{
try
{
- FileTime ft = Files.getLastModifiedTime(path,NO_FOLLOW_OPTIONS);
+ FileTime ft = Files.getLastModifiedTime(path,NO_FOLLOW_LINKS);
return ft.toMillis();
}
catch (IOException e)
@@ -309,10 +319,21 @@ public class PathResource extends Resource
}
@Override
- public URI getAlias()
+ public boolean isAlias()
+ {
+ return this.alias!=null;
+ }
+
+ public Path getAliasPath()
{
return this.alias;
}
+
+ @Override
+ public URI getAlias()
+ {
+ return this.alias==null?null:this.alias.toUri();
+ }
@Override
public String[] list()
@@ -354,7 +375,7 @@ public class PathResource extends Resource
try
{
Path result = Files.move(path,destRes.path);
- return Files.exists(result,NO_FOLLOW_OPTIONS);
+ return Files.exists(result,NO_FOLLOW_LINKS);
}
catch (IOException e)
{
diff --git a/jetty-util/src/main/java/org/eclipse/jetty/util/resource/Resource.java b/jetty-util/src/main/java/org/eclipse/jetty/util/resource/Resource.java
index 4762444176..cf62cf3ed3 100644
--- a/jetty-util/src/main/java/org/eclipse/jetty/util/resource/Resource.java
+++ b/jetty-util/src/main/java/org/eclipse/jetty/util/resource/Resource.java
@@ -475,6 +475,12 @@ public abstract class Resource implements ResourceFactory, Closeable
{
_associate=o;
}
+
+ /* ------------------------------------------------------------ */
+ public boolean isAlias()
+ {
+ return getAlias()!=null;
+ }
/* ------------------------------------------------------------ */
/**
diff --git a/jetty-util/src/test/java/org/eclipse/jetty/util/resource/FileSystemResourceTest.java b/jetty-util/src/test/java/org/eclipse/jetty/util/resource/FileSystemResourceTest.java
index 5b65894a3d..ec4cc2b8f6 100644
--- a/jetty-util/src/test/java/org/eclipse/jetty/util/resource/FileSystemResourceTest.java
+++ b/jetty-util/src/test/java/org/eclipse/jetty/util/resource/FileSystemResourceTest.java
@@ -134,7 +134,7 @@ public class FileSystemResourceTest
public boolean matches(Object item)
{
final Resource res = (Resource)item;
- return res.getAlias() == null;
+ return !res.isAlias();
}
@Override
@@ -497,6 +497,48 @@ public class FileSystemResourceTest
assertThat("file.alias", newResource(resBar.getFile()), isAliasFor(resFoo));
}
}
+
+ @Test
+ public void testNonExistantSymlink() throws Exception
+ {
+ File dir = testdir.getDir();
+
+ Path foo = new File(dir, "foo").toPath();
+ Path bar = new File(dir, "bar").toPath();
+
+ try
+ {
+ Files.createSymbolicLink(bar,foo);
+ }
+ catch (UnsupportedOperationException | FileSystemException e)
+ {
+ // if unable to create symlink, no point testing the rest
+ // this is the path that Microsoft Windows takes.
+ assumeNoException(e);
+ }
+
+ try (Resource base = newResource(testdir.getDir()))
+ {
+ // FileResource does not pass this test!
+ assumeFalse(base instanceof FileResource);
+
+ Resource resFoo = base.addPath("foo");
+ Resource resBar = base.addPath("bar");
+
+ assertThat("resFoo.uri", resFoo.getURI(), is(foo.toUri()));
+
+ // Access to the same resource, but via a symlink means that they are not equivalent
+ assertThat("foo.equals(bar)", resFoo.equals(resBar), is(false));
+
+ assertThat("resource.alias", resFoo, hasNoAlias());
+ assertThat("resource.uri.alias", newResource(resFoo.getURI()), hasNoAlias());
+ assertThat("resource.file.alias", newResource(resFoo.getFile()), hasNoAlias());
+
+ assertThat("alias", resBar, isAliasFor(resFoo));
+ assertThat("uri.alias", newResource(resBar.getURI()), isAliasFor(resFoo));
+ assertThat("file.alias", newResource(resBar.getFile()), isAliasFor(resFoo));
+ }
+ }
@Test
diff --git a/jetty-webapp/src/main/java/org/eclipse/jetty/webapp/WebInfConfiguration.java b/jetty-webapp/src/main/java/org/eclipse/jetty/webapp/WebInfConfiguration.java
index 1e4096c19c..39821a5577 100644
--- a/jetty-webapp/src/main/java/org/eclipse/jetty/webapp/WebInfConfiguration.java
+++ b/jetty-webapp/src/main/java/org/eclipse/jetty/webapp/WebInfConfiguration.java
@@ -402,7 +402,7 @@ public class WebInfConfiguration extends AbstractConfiguration
throw new IllegalStateException("No resourceBase or war set for context");
// Accept aliases for WAR files
- if (web_app.getAlias() != null)
+ if (web_app.isAlias())
{
LOG.debug(web_app + " anti-aliased to " + web_app.getAlias());
web_app = context.newResource(web_app.getAlias());

Back to the top