416103 Added AllowSymLinkAliasChecker.java
This commit is contained in:
parent
35d379a335
commit
2b7462e9a9
|
@ -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;
|
||||
}
|
||||
|
||||
}
|
|
@ -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("/");
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
|
|
|
@ -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);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
Loading…
Reference in New Issue