416103 Added AllowSymLinkAliasChecker.java

This commit is contained in:
Greg Wilkins 2013-08-29 16:17:15 +10:00
parent 35d379a335
commit 2b7462e9a9
3 changed files with 165 additions and 4 deletions

View File

@ -0,0 +1,87 @@
//
// ========================================================================
// Copyright (c) 1995-2013 Mort Bay Consulting Pty. Ltd.
// ------------------------------------------------------------------------
// 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.handler;
import java.io.File;
import java.net.URI;
import java.nio.file.Files;
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.Resource;
public class AllowSymLinkAliasChecker implements AliasCheck
{
private static final Logger LOG = Log.getLogger(AllowSymLinkAliasChecker.class);
@Override
public boolean check(String path, Resource resource)
{
try
{
File file =resource.getFile();
if (file==null)
return false;
// If the file exists
if (file.exists())
{
// 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().toURI()))
{
LOG.debug("Allow symlink {} --> {}",resource,real);
return true;
}
}
else
{
// 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=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().toURI().equals(d.toURI()))
{
LOG.debug("Allow symlink {} --> {}",resource,d);
return true;
}
}
}
catch(Exception e)
{
e.printStackTrace();
LOG.ignore(e);
}
return false;
}
}

View File

@ -40,6 +40,7 @@ import java.util.Map;
import java.util.Set;
import java.util.concurrent.CopyOnWriteArrayList;
import java.util.concurrent.Future;
import javax.servlet.DispatcherType;
import javax.servlet.Filter;
import javax.servlet.FilterRegistration;
@ -1297,7 +1298,7 @@ public class ContextHandler extends ScopedHandler implements Attributes, Gracefu
LOG.warn(this+" contextPath ends with /*");
contextPath=contextPath.substring(0,contextPath.length()-2);
}
else if (contextPath.endsWith("/"))
else if (contextPath.length()>1 && contextPath.endsWith("/"))
{
LOG.warn(this+" contextPath ends with /");
contextPath=contextPath.substring(0,contextPath.length()-1);
@ -2651,5 +2652,5 @@ public class ContextHandler extends ScopedHandler implements Attributes, Gracefu
return r.startsWith(a) && r.length()==a.length()+1 && r.endsWith("/");
}
}
}

View File

@ -44,7 +44,9 @@ public class ContextHandlerGetResourceTest
private static Server server;
private static ContextHandler context;
private static File docroot;
private static File otherroot;
private final static AtomicBoolean allowAliases= new AtomicBoolean(false);
private final static AtomicBoolean allowSymlinks= new AtomicBoolean(false);
@BeforeClass
public static void beforeClass() throws Exception
@ -60,12 +62,25 @@ public class ContextHandlerGetResourceTest
data.createNewFile();
File verylong = new File(sub,"TextFile.Long.txt");
verylong.createNewFile();
otherroot = new File("target/tests/otherroot").getCanonicalFile().getAbsoluteFile();
FS.ensureDirExists(otherroot);
FS.ensureEmpty(otherroot);
File other = new File(otherroot,"other.txt");
other.createNewFile();
if (!OS.IS_WINDOWS)
File transit = new File(docroot.getParentFile(),"transit");
System.err.println("transit "+transit);
transit.delete();
if (OS.IS_UNIX)
{
// Create alias as 8.3 name so same test will produce an alias on both windows an normal systems
File eightDotThree=new File(sub,"TEXTFI~1.TXT");
Files.createSymbolicLink(eightDotThree.toPath(),verylong.toPath());
Files.createSymbolicLink(new File(docroot,"other").toPath(),new File("../transit").toPath());
Files.createSymbolicLink(transit.toPath(),otherroot.toPath());
}
@ -74,13 +89,18 @@ public class ContextHandlerGetResourceTest
context.setBaseResource(Resource.newResource(docroot));
context.addAliasCheck(new ContextHandler.AliasCheck()
{
final AllowSymLinkAliasChecker symlinkcheck = new AllowSymLinkAliasChecker();
@Override
public boolean check(String path, Resource resource)
{
if (allowAliases.get())
return true;
if (allowSymlinks.get())
return symlinkcheck.check(path,resource);
return allowAliases.get();
}
});
server.setHandler(context);
server.start();
}
@ -308,4 +328,57 @@ public class ContextHandlerGetResourceTest
}
}
@Test
public void testSymlinkKnown() throws Exception
{
if (!OS.IS_UNIX)
return;
try
{
allowSymlinks.set(true);
final String path="/other/other.txt";
Resource resource=context.getResource(path);
assertNotNull(resource);
assertEquals("other.txt",resource.getFile().getName());
assertEquals(docroot,resource.getFile().getParentFile().getParentFile());
assertTrue(resource.exists());
URL url=context.getServletContext().getResource(path);
assertEquals(docroot,new File(url.toURI()).getParentFile().getParentFile());
}
finally
{
allowSymlinks.set(false);
}
}
@Test
public void testSymlinkUnknown() throws Exception
{
if (!OS.IS_UNIX)
return;
try
{
allowSymlinks.set(true);
final String path="/other/unknown.txt";
Resource resource=context.getResource(path);
assertNotNull(resource);
assertEquals("unknown.txt",resource.getFile().getName());
assertEquals(docroot,resource.getFile().getParentFile().getParentFile());
assertFalse(resource.exists());
URL url=context.getServletContext().getResource(path);
assertNull(url);
}
finally
{
allowSymlinks.set(false);
}
}
}