Skip to main content
summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorGreg Wilkins2013-01-07 12:45:38 +0000
committerGreg Wilkins2013-01-07 12:45:38 +0000
commit2aab780eba88b5f0c5943fa3943984848249b295 (patch)
tree13a6e8d5ab9a733099f182ed862f60c1e2be67c3
parent64df770b42e37eff1546a2a1e6b909b6025a92b3 (diff)
parent96fd7dc56294fcf93be12cffd0600942de750b05 (diff)
downloadorg.eclipse.jetty.project-2aab780eba88b5f0c5943fa3943984848249b295.tar.gz
org.eclipse.jetty.project-2aab780eba88b5f0c5943fa3943984848249b295.tar.xz
org.eclipse.jetty.project-2aab780eba88b5f0c5943fa3943984848249b295.zip
Merge remote-tracking branch 'origin/jetty-7' into jetty-8
Conflicts: jetty-server/src/main/java/org/eclipse/jetty/server/handler/ContextHandler.java tests/test-integration/src/test/java/org/eclipse/jetty/test/jsp/JspMatchingTest.java
-rw-r--r--jetty-server/src/main/java/org/eclipse/jetty/server/Request.java38
-rw-r--r--jetty-server/src/main/java/org/eclipse/jetty/server/handler/ContextHandler.java115
-rw-r--r--jetty-server/src/test/java/org/eclipse/jetty/server/handler/ContextHandlerAliasTest.java201
-rw-r--r--jetty-servlet/src/main/java/org/eclipse/jetty/servlet/DefaultServlet.java2
-rw-r--r--jetty-util/src/main/java/org/eclipse/jetty/util/resource/Resource.java14
-rw-r--r--jetty-webapp/src/test/java/org/eclipse/jetty/webapp/WebAppContextTest.java5
-rw-r--r--test-jetty-webapp/src/main/config/contexts/test.xml14
-rw-r--r--tests/test-integration/src/test/java/org/eclipse/jetty/test/jsp/JspMatchingTest.java6
8 files changed, 355 insertions, 40 deletions
diff --git a/jetty-server/src/main/java/org/eclipse/jetty/server/Request.java b/jetty-server/src/main/java/org/eclipse/jetty/server/Request.java
index 62dc7ab3b1..24796e989f 100644
--- a/jetty-server/src/main/java/org/eclipse/jetty/server/Request.java
+++ b/jetty-server/src/main/java/org/eclipse/jetty/server/Request.java
@@ -312,18 +312,42 @@ public class Request implements HttpServletRequest
maxFormContentSize = _context.getContextHandler().getMaxFormContentSize();
maxFormKeys = _context.getContextHandler().getMaxFormKeys();
}
- else
+
+ if (maxFormContentSize < 0)
+ {
+ Object obj = _connection.getConnector().getServer().getAttribute("org.eclipse.jetty.server.Request.maxFormContentSize");
+ if (obj == null)
+ maxFormContentSize = 200000;
+ else if (obj instanceof Number)
+ {
+ Number size = (Number)obj;
+ maxFormContentSize = size.intValue();
+ }
+ else if (obj instanceof String)
+ {
+ maxFormContentSize = Integer.valueOf((String)obj);
+ }
+ }
+
+ if (maxFormKeys < 0)
{
- Number size = (Number)_connection.getConnector().getServer()
- .getAttribute("org.eclipse.jetty.server.Request.maxFormContentSize");
- maxFormContentSize = size == null?200000:size.intValue();
- Number keys = (Number)_connection.getConnector().getServer().getAttribute("org.eclipse.jetty.server.Request.maxFormKeys");
- maxFormKeys = keys == null?1000:keys.intValue();
+ Object obj = _connection.getConnector().getServer().getAttribute("org.eclipse.jetty.server.Request.maxFormKeys");
+ if (obj == null)
+ maxFormKeys = 1000;
+ else if (obj instanceof Number)
+ {
+ Number keys = (Number)obj;
+ maxFormKeys = keys.intValue();
+ }
+ else if (obj instanceof String)
+ {
+ maxFormKeys = Integer.valueOf((String)obj);
+ }
}
if (content_length > maxFormContentSize && maxFormContentSize > 0)
{
- throw new IllegalStateException("Form too large" + content_length + ">" + maxFormContentSize);
+ throw new IllegalStateException("Form too large " + content_length + ">" + maxFormContentSize);
}
InputStream in = getInputStream();
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 10b9d1f186..551169088d 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
@@ -32,11 +32,12 @@ import java.util.Enumeration;
import java.util.EventListener;
import java.util.HashMap;
import java.util.HashSet;
+import java.util.Iterator;
import java.util.List;
import java.util.Locale;
import java.util.Map;
import java.util.Set;
-import java.util.EnumSet;
+import java.util.concurrent.CopyOnWriteArrayList;
import javax.servlet.DispatcherType;
import javax.servlet.RequestDispatcher;
@@ -139,8 +140,8 @@ public class ContextHandler extends ScopedHandler implements Attributes, Server.
private EventListener[] _eventListeners;
private Logger _logger;
private boolean _allowNullPathInfo;
- private int _maxFormKeys = Integer.getInteger("org.eclipse.jetty.server.Request.maxFormKeys",1000).intValue();
- private int _maxFormContentSize = Integer.getInteger("org.eclipse.jetty.server.Request.maxFormContentSize",200000).intValue();
+ private int _maxFormKeys = Integer.getInteger("org.eclipse.jetty.server.Request.maxFormKeys",-1).intValue();
+ private int _maxFormContentSize = Integer.getInteger("org.eclipse.jetty.server.Request.maxFormContentSize",-1).intValue();
private boolean _compactPath = false;
private boolean _aliases = false;
@@ -150,6 +151,7 @@ public class ContextHandler extends ScopedHandler implements Attributes, Server.
private Object _requestAttributeListeners;
private Map<String, Object> _managedAttributes;
private String[] _protectedTargets;
+ private final CopyOnWriteArrayList<AliasCheck> _aliasChecks = new CopyOnWriteArrayList<ContextHandler.AliasCheck>();
private boolean _shutdown = false;
private boolean _available = true;
@@ -168,6 +170,7 @@ public class ContextHandler extends ScopedHandler implements Attributes, Server.
_attributes = new AttributesMap();
_contextAttributes = new AttributesMap();
_initParams = new HashMap<String, String>();
+ addAliasCheck(new ApproveNonExistentDirectoryAliases());
}
/* ------------------------------------------------------------ */
@@ -181,6 +184,7 @@ public class ContextHandler extends ScopedHandler implements Attributes, Server.
_attributes = new AttributesMap();
_contextAttributes = new AttributesMap();
_initParams = new HashMap<String, String>();
+ addAliasCheck(new ApproveNonExistentDirectoryAliases());
}
/* ------------------------------------------------------------ */
@@ -1565,14 +1569,23 @@ public class ContextHandler extends ScopedHandler implements Attributes, Server.
path = URIUtil.canonicalPath(path);
Resource resource = _baseResource.addPath(path);
+ // Is the resource aliased?
if (!_aliases && resource.getAlias() != null)
{
- if (resource.exists())
- LOG.warn("Aliased resource: " + resource + "~=" + resource.getAlias());
- else if (path.endsWith("/") && resource.getAlias().toString().endsWith(path))
- return resource;
- else if (LOG.isDebugEnabled())
+ if (LOG.isDebugEnabled())
LOG.debug("Aliased resource: " + resource + "~=" + resource.getAlias());
+
+ // alias checks
+ for (Iterator<AliasCheck> i=_aliasChecks.iterator();i.hasNext();)
+ {
+ AliasCheck check = i.next();
+ if (check.check(path,resource))
+ {
+ if (LOG.isDebugEnabled())
+ LOG.debug("Aliased resource: " + resource + " approved by " + check);
+ return resource;
+ }
+ }
return null;
}
@@ -1653,6 +1666,25 @@ public class ContextHandler extends ScopedHandler implements Attributes, Server.
return host;
}
+
+ /* ------------------------------------------------------------ */
+ /**
+ * Add an AliasCheck instance to possibly permit aliased resources
+ * @param check The alias checker
+ */
+ public void addAliasCheck(AliasCheck check)
+ {
+ _aliasChecks.add(check);
+ }
+
+ /* ------------------------------------------------------------ */
+ /**
+ * @return Mutable list of Alias checks
+ */
+ public List<AliasCheck> getAliasChecks()
+ {
+ return _aliasChecks;
+ }
/* ------------------------------------------------------------ */
/**
@@ -2431,4 +2463,71 @@ public class ContextHandler extends ScopedHandler implements Attributes, Server.
}
}
+
+
+ /* ------------------------------------------------------------ */
+ /** Interface to check aliases
+ */
+ public interface AliasCheck
+ {
+ /* ------------------------------------------------------------ */
+ /** Check an alias
+ * @param path The path the aliased resource was created for
+ * @param resource The aliased resourced
+ * @return True if the resource is OK to be served.
+ */
+ boolean check(String path, Resource resource);
+ }
+
+
+ /* ------------------------------------------------------------ */
+ /** Approve Aliases with same suffix.
+ * Eg. a symbolic link from /foobar.html to /somewhere/wibble.html would be
+ * approved because both the resource and alias end with ".html".
+ */
+ public static class ApproveSameSuffixAliases implements AliasCheck
+ {
+ public boolean check(String path, Resource resource)
+ {
+ int dot = path.lastIndexOf('.');
+ if (dot<0)
+ return false;
+ String suffix=path.substring(dot);
+ return resource.getAlias().toString().endsWith(suffix);
+ }
+ }
+
+
+ /* ------------------------------------------------------------ */
+ /** Approve Aliases with a path prefix.
+ * Eg. a symbolic link from /dirA/foobar.html to /dirB/foobar.html would be
+ * approved because both the resource and alias end with "/foobar.html".
+ */
+ public static class ApprovePathPrefixAliases implements AliasCheck
+ {
+ public boolean check(String path, Resource resource)
+ {
+ int slash = path.lastIndexOf('/');
+ if (slash<0)
+ return false;
+ String suffix=path.substring(slash);
+ return resource.getAlias().toString().endsWith(suffix);
+ }
+ }
+ /* ------------------------------------------------------------ */
+ /** Approve Aliases of a non existent directory.
+ * If a directory "/foobar/" does not exist, then the resource is
+ * aliased to "/foobar". Accept such aliases.
+ */
+ public static class ApproveNonExistentDirectoryAliases implements AliasCheck
+ {
+ public boolean check(String path, Resource resource)
+ {
+ int slash = path.lastIndexOf('/');
+ if (slash<0)
+ return false;
+ String suffix=path.substring(slash);
+ return resource.getAlias().toString().endsWith(suffix);
+ }
+ }
}
diff --git a/jetty-server/src/test/java/org/eclipse/jetty/server/handler/ContextHandlerAliasTest.java b/jetty-server/src/test/java/org/eclipse/jetty/server/handler/ContextHandlerAliasTest.java
new file mode 100644
index 0000000000..1818f405e7
--- /dev/null
+++ b/jetty-server/src/test/java/org/eclipse/jetty/server/handler/ContextHandlerAliasTest.java
@@ -0,0 +1,201 @@
+//
+// ========================================================================
+// Copyright (c) 1995-2012 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.io.FilePermission;
+import java.io.IOException;
+import java.io.PrintWriter;
+import java.nio.file.Files;
+import java.nio.file.attribute.FileAttribute;
+import java.util.ArrayList;
+import java.util.Collections;
+import java.util.List;
+import javax.servlet.ServletException;
+import javax.servlet.http.HttpServletRequest;
+import javax.servlet.http.HttpServletResponse;
+
+import junit.framework.Assert;
+import org.eclipse.jetty.server.Connector;
+import org.eclipse.jetty.server.LocalConnector;
+import org.eclipse.jetty.server.Request;
+import org.eclipse.jetty.server.Server;
+import org.eclipse.jetty.util.IO;
+import org.eclipse.jetty.util.resource.FileResource;
+import org.eclipse.jetty.util.resource.Resource;
+import org.junit.After;
+import org.junit.Before;
+import org.junit.Test;
+
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertFalse;
+import static org.junit.Assert.assertTrue;
+
+/**
+ * @version $Revision$
+ */
+public class ContextHandlerAliasTest
+{
+ private Server _server;
+ private ContextHandler _ctx;
+ private File _tmp;
+ private File _dir;
+
+
+ @Before
+ public void before() throws Exception
+ {
+ _server=new Server();
+ _ctx = new ContextHandler();
+ _server.setHandler(_ctx);
+
+
+ _tmp = new File( System.getProperty( "basedir", "." ) + "/target/tmp/aliastests" ).getCanonicalFile();
+ if (_tmp.exists())
+ IO.delete(_tmp);
+ assertTrue(_tmp.mkdirs());
+
+ File root = new File(_tmp,getClass().getName());
+ assertTrue(root.mkdir());
+
+ File webInf = new File(root,"WEB-INF");
+ assertTrue(webInf.mkdir());
+
+ assertTrue(new File(webInf,"jsp").mkdir());
+ assertTrue(new File(webInf,"web.xml").createNewFile());
+ assertTrue(new File(root,"index.html").createNewFile());
+
+ _dir=root;
+ _ctx.setBaseResource(Resource.newResource(_dir));
+ _server.start();
+ }
+
+ @After
+ public void after() throws Exception
+ {
+ _server.stop();
+ if (_tmp!=null && _tmp.exists())
+ IO.delete(_tmp);
+ }
+
+ @Test
+ public void testGetResources() throws Exception
+ {
+ Resource r =_ctx.getResource("/index.html");
+ Assert.assertTrue(r.exists());
+ }
+
+ @Test
+ public void testJvmNullBugAlias() throws Exception
+ {
+ // JVM Files ignores null characters at end of name
+ String normal="/index.html";
+ String withnull="/index.html\u0000";
+
+ _ctx.setAliases(true);
+ Assert.assertTrue(_ctx.getResource(normal).exists());
+ Assert.assertTrue(_ctx.getResource(withnull).exists());
+ _ctx.setAliases(false);
+ Assert.assertTrue(_ctx.getResource(normal).exists());
+ Assert.assertNull(_ctx.getResource(withnull));
+ }
+
+ @Test
+ public void testSymLinkToContext() throws Exception
+ {
+ File symlink = new File(_tmp,"symlink");
+ try
+ {
+ Files.createSymbolicLink(symlink.toPath(),_dir.toPath());
+
+ _server.stop();
+ _ctx.setBaseResource(FileResource.newResource(symlink));
+ _ctx.setAliases(false);
+ _server.start();
+
+ Resource r =_ctx.getResource("/index.html");
+ Assert.assertTrue(r.exists());
+ }
+ finally
+ {
+ symlink.delete();
+ }
+ }
+
+ @Test
+ public void testSymLinkToContent() throws Exception
+ {
+ File symlink = new File(_dir,"link.html");
+ try
+ {
+ Files.createSymbolicLink(symlink.toPath(),new File(_dir,"index.html").toPath());
+
+ _ctx.setAliases(true);
+ Assert.assertTrue(_ctx.getResource("/index.html").exists());
+ Assert.assertTrue(_ctx.getResource("/link.html").exists());
+
+ _ctx.setAliases(false);
+ Assert.assertTrue(_ctx.getResource("/index.html").exists());
+ Assert.assertNull(_ctx.getResource("/link.html"));
+
+ }
+ finally
+ {
+ symlink.delete();
+ }
+ }
+
+ @Test
+ public void testSymLinkToContentWithSuffixCheck() throws Exception
+ {
+ File symlink = new File(_dir,"link.html");
+ try
+ {
+ Files.createSymbolicLink(symlink.toPath(),new File(_dir,"index.html").toPath());
+
+ _ctx.setAliases(false);
+ _ctx.addAliasCheck(new ContextHandler.ApproveSameSuffixAliases());
+ Assert.assertTrue(_ctx.getResource("/index.html").exists());
+ Assert.assertTrue(_ctx.getResource("/link.html").exists());
+ }
+ finally
+ {
+ symlink.delete();
+ }
+ }
+
+ @Test
+ public void testSymLinkToContentWithPathPrefixCheck() throws Exception
+ {
+ File symlink = new File(_dir,"dirlink");
+ try
+ {
+ Files.createSymbolicLink(symlink.toPath(),new File(_dir,".").toPath());
+
+ _ctx.setAliases(false);
+ _ctx.addAliasCheck(new ContextHandler.ApprovePathPrefixAliases());
+ Assert.assertTrue(_ctx.getResource("/index.html").exists());
+ Assert.assertTrue(_ctx.getResource("/dirlink/index.html").exists());
+ }
+ finally
+ {
+ symlink.delete();
+ }
+ }
+}
diff --git a/jetty-servlet/src/main/java/org/eclipse/jetty/servlet/DefaultServlet.java b/jetty-servlet/src/main/java/org/eclipse/jetty/servlet/DefaultServlet.java
index 7d87278e55..086e7a4f35 100644
--- a/jetty-servlet/src/main/java/org/eclipse/jetty/servlet/DefaultServlet.java
+++ b/jetty-servlet/src/main/java/org/eclipse/jetty/servlet/DefaultServlet.java
@@ -205,7 +205,7 @@ public class DefaultServlet extends HttpServlet implements ResourceFactory
if (!aliases && !FileResource.getCheckAliases())
throw new IllegalStateException("Alias checking disabled");
if (aliases)
- _servletContext.log("Aliases are enabled");
+ _servletContext.log("Aliases are enabled! Security constraints may be bypassed!!!");
_useFileMappedBuffer=getInitBoolean("useFileMappedBuffer",_useFileMappedBuffer);
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 d9c525b1f2..247150d9e0 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
@@ -189,20 +189,6 @@ public abstract class Resource implements ResourceFactory
}
}
- // Make sure that any special characters stripped really are ignorable.
- String nurl=url.toString();
- if (nurl.length()>0 && nurl.charAt(nurl.length()-1)!=resource.charAt(resource.length()-1))
- {
- if ((nurl.charAt(nurl.length()-1)!='/' ||
- nurl.charAt(nurl.length()-2)!=resource.charAt(resource.length()-1))
- &&
- (resource.charAt(resource.length()-1)!='/' ||
- resource.charAt(resource.length()-2)!=nurl.charAt(nurl.length()-1)
- ))
- {
- return new BadResource(url,"Trailing special characters stripped by URL in "+resource);
- }
- }
return newResource(url);
}
diff --git a/jetty-webapp/src/test/java/org/eclipse/jetty/webapp/WebAppContextTest.java b/jetty-webapp/src/test/java/org/eclipse/jetty/webapp/WebAppContextTest.java
index af27b996a5..cf1385975a 100644
--- a/jetty-webapp/src/test/java/org/eclipse/jetty/webapp/WebAppContextTest.java
+++ b/jetty-webapp/src/test/java/org/eclipse/jetty/webapp/WebAppContextTest.java
@@ -107,13 +107,8 @@ public class WebAppContextTest
server.setHandler(context);
server.start();
- // When
ServletContext ctx = context.getServletContext();
-
- // Then
- // This passes:
assertNotNull(ctx.getRealPath("/doesnotexist"));
- // This fails:
assertNotNull(ctx.getRealPath("/doesnotexist/"));
}
diff --git a/test-jetty-webapp/src/main/config/contexts/test.xml b/test-jetty-webapp/src/main/config/contexts/test.xml
index 32e5b40584..00372852e4 100644
--- a/test-jetty-webapp/src/main/config/contexts/test.xml
+++ b/test-jetty-webapp/src/main/config/contexts/test.xml
@@ -13,7 +13,6 @@ detected.
<Configure class="org.eclipse.jetty.webapp.WebAppContext">
-
<!-- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -->
<!-- Required minimal context configuration : -->
<!-- + contextPath -->
@@ -30,6 +29,19 @@ detected.
<Set name="defaultsDescriptor"><SystemProperty name="jetty.home" default="."/>/etc/webdefault.xml</Set>
<Set name="overrideDescriptor"><SystemProperty name="jetty.home" default="."/>/contexts/test.d/override-web.xml</Set>
+ <!-- Allow directory symbolic links -->
+ <Call name="addAliasCheck">
+ <Arg>
+ <New class="org.eclipse.jetty.server.handler.ContextHandler$ApprovePathPrefixAliases"/>
+ </Arg>
+ </Call>
+ <!-- Allow file symbolic links -->
+ <Call name="addAliasCheck">
+ <Arg>
+ <New class="org.eclipse.jetty.server.handler.ContextHandler$ApproveSameSuffixAliases"/>
+ </Arg>
+ </Call>
+
<!-- virtual hosts
<Set name="virtualHosts">
<Array type="String">
diff --git a/tests/test-integration/src/test/java/org/eclipse/jetty/test/jsp/JspMatchingTest.java b/tests/test-integration/src/test/java/org/eclipse/jetty/test/jsp/JspMatchingTest.java
index 74ed79309c..d5c19ae9fd 100644
--- a/tests/test-integration/src/test/java/org/eclipse/jetty/test/jsp/JspMatchingTest.java
+++ b/tests/test-integration/src/test/java/org/eclipse/jetty/test/jsp/JspMatchingTest.java
@@ -72,9 +72,10 @@ public class JspMatchingTest
URLClassLoader contextLoader = new URLClassLoader(new URL[]{}, Server.class.getClassLoader());
context.setClassLoader(contextLoader);
+
// add default servlet
ServletHolder defaultServHolder = context.addServlet(DefaultServlet.class,"/");
- defaultServHolder.setInitParameter("aliases","true"); // important!
+ defaultServHolder.setInitParameter("aliases","false"); // important!
// add jsp
ServletHolder jsp = context.addServlet(JspServlet.class,"*.jsp");
@@ -142,7 +143,6 @@ public class JspMatchingTest
}
}
- @Ignore("DefaultServlet + aliasing breaks this test ATM")
@Test
public void testGetBeanRefInvalid_nullx() throws Exception
{
@@ -163,7 +163,6 @@ public class JspMatchingTest
}
}
- @Ignore("DefaultServlet + aliasing breaks this test ATM")
@Test
public void testGetBeanRefInvalid_nullslash() throws Exception
{
@@ -184,7 +183,6 @@ public class JspMatchingTest
}
}
- @Ignore("DefaultServlet + aliasing breaks this test ATM")
@Test
public void testGetBeanRefInvalid_nullxslash() throws Exception
{

Back to the top