Issue #5029 Relative Redirection (#5038)

* Issue #5029 Relative Redirection

Provide option to allow relative redirection

* Issue #5029 Relative Redirection

Fixed checkstyle

* rename from review
This commit is contained in:
Greg Wilkins 2020-07-15 23:14:26 +02:00 committed by GitHub
parent 6b57654b03
commit 5c1dda3f7c
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
5 changed files with 103 additions and 2 deletions

View File

@ -74,6 +74,7 @@
<Set name="requestCookieCompliance"><Call class="org.eclipse.jetty.http.CookieCompliance" name="valueOf"><Arg><Property name="jetty.httpConfig.requestCookieCompliance" deprecated="jetty.httpConfig.cookieCompliance" default="RFC6265"/></Arg></Call></Set> <Set name="requestCookieCompliance"><Call class="org.eclipse.jetty.http.CookieCompliance" name="valueOf"><Arg><Property name="jetty.httpConfig.requestCookieCompliance" deprecated="jetty.httpConfig.cookieCompliance" default="RFC6265"/></Arg></Call></Set>
<Set name="responseCookieCompliance"><Call class="org.eclipse.jetty.http.CookieCompliance" name="valueOf"><Arg><Property name="jetty.httpConfig.responseCookieCompliance" default="RFC6265"/></Arg></Call></Set> <Set name="responseCookieCompliance"><Call class="org.eclipse.jetty.http.CookieCompliance" name="valueOf"><Arg><Property name="jetty.httpConfig.responseCookieCompliance" default="RFC6265"/></Arg></Call></Set>
<Set name="multiPartFormDataCompliance"><Call class="org.eclipse.jetty.server.MultiPartFormDataCompliance" name="valueOf"><Arg><Property name="jetty.httpConfig.multiPartFormDataCompliance" default="RFC7578"/></Arg></Call></Set> <Set name="multiPartFormDataCompliance"><Call class="org.eclipse.jetty.server.MultiPartFormDataCompliance" name="valueOf"><Arg><Property name="jetty.httpConfig.multiPartFormDataCompliance" default="RFC7578"/></Arg></Call></Set>
<Set name="relativeRedirectAllowed"><Property name="jetty.httpConfig.relativeRedirectAllowed" default="false"/></Set>
</New> </New>
<!-- =========================================================== --> <!-- =========================================================== -->

View File

@ -72,6 +72,9 @@ patch-module: servlet.api=lib/jetty-schemas-3.1.jar
## multipart/form-data compliance mode of: LEGACY(slow), RFC7578(fast) ## multipart/form-data compliance mode of: LEGACY(slow), RFC7578(fast)
# jetty.httpConfig.multiPartFormDataCompliance=LEGACY # jetty.httpConfig.multiPartFormDataCompliance=LEGACY
## Relative Redirect Locations allowed
# jetty.httpConfig.relativeRedirectAllowed=false
### Server configuration ### Server configuration
## Whether ctrl+c on the console gracefully stops the Jetty server ## Whether ctrl+c on the console gracefully stops the Jetty server
# jetty.server.stopAtShutdown=true # jetty.server.stopAtShutdown=true

View File

@ -76,6 +76,7 @@ public class HttpConfiguration implements Dumpable
private CookieCompliance _responseCookieCompliance = CookieCompliance.RFC6265; private CookieCompliance _responseCookieCompliance = CookieCompliance.RFC6265;
private MultiPartFormDataCompliance _multiPartCompliance = MultiPartFormDataCompliance.LEGACY; // TODO change default in jetty-10 private MultiPartFormDataCompliance _multiPartCompliance = MultiPartFormDataCompliance.LEGACY; // TODO change default in jetty-10
private boolean _notifyRemoteAsyncErrors = true; private boolean _notifyRemoteAsyncErrors = true;
private boolean _relativeRedirectAllowed;
/** /**
* <p>An interface that allows a request object to be customized * <p>An interface that allows a request object to be customized
@ -142,6 +143,7 @@ public class HttpConfiguration implements Dumpable
_responseCookieCompliance = config._responseCookieCompliance; _responseCookieCompliance = config._responseCookieCompliance;
_multiPartCompliance = config._multiPartCompliance; _multiPartCompliance = config._multiPartCompliance;
_notifyRemoteAsyncErrors = config._notifyRemoteAsyncErrors; _notifyRemoteAsyncErrors = config._notifyRemoteAsyncErrors;
_relativeRedirectAllowed = config._relativeRedirectAllowed;
} }
/** /**
@ -642,6 +644,23 @@ public class HttpConfiguration implements Dumpable
return _notifyRemoteAsyncErrors; return _notifyRemoteAsyncErrors;
} }
/**
* @param allowed True if relative redirection locations are allowed
*/
public void setRelativeRedirectAllowed(boolean allowed)
{
_relativeRedirectAllowed = allowed;
}
/**
* @return True if relative redirection locations are allowed
*/
@ManagedAttribute("Whether relative redirection locations are allowed")
public boolean isRelativeRedirectAllowed()
{
return _relativeRedirectAllowed;
}
@Override @Override
public String dump() public String dump()
{ {
@ -673,7 +692,8 @@ public class HttpConfiguration implements Dumpable
"minResponseDataRate=" + _minResponseDataRate, "minResponseDataRate=" + _minResponseDataRate,
"cookieCompliance=" + _requestCookieCompliance, "cookieCompliance=" + _requestCookieCompliance,
"setRequestCookieCompliance=" + _responseCookieCompliance, "setRequestCookieCompliance=" + _responseCookieCompliance,
"notifyRemoteAsyncErrors=" + _notifyRemoteAsyncErrors "notifyRemoteAsyncErrors=" + _notifyRemoteAsyncErrors,
"relativeRedirectAllowed=" + _relativeRedirectAllowed
); );
} }

View File

@ -506,7 +506,9 @@ public class Response implements HttpServletResponse
if (!URIUtil.hasScheme(location)) if (!URIUtil.hasScheme(location))
{ {
StringBuilder buf = _channel.getRequest().getRootURL(); StringBuilder buf = _channel.getHttpConfiguration().isRelativeRedirectAllowed()
? new StringBuilder()
: _channel.getRequest().getRootURL();
if (location.startsWith("/")) if (location.startsWith("/"))
{ {
// absolute in context // absolute in context

View File

@ -858,6 +858,81 @@ public class ResponseTest
} }
} }
@Test
public void testSendRedirectRelative()
throws Exception
{
String[][] tests = {
// No cookie
{
"http://myhost:8888/other/location;jsessionid=12345?name=value",
"http://myhost:8888/other/location;jsessionid=12345?name=value"
},
{"/other/location;jsessionid=12345?name=value", "/other/location;jsessionid=12345?name=value"},
{"./location;jsessionid=12345?name=value", "/path/location;jsessionid=12345?name=value"},
// From cookie
{"/other/location", "/other/location"},
{"/other/l%20cation", "/other/l%20cation"},
{"location", "/path/location"},
{"./location", "/path/location"},
{"../location", "/location"},
{"/other/l%20cation", "/other/l%20cation"},
{"l%20cation", "/path/l%20cation"},
{"./l%20cation", "/path/l%20cation"},
{"../l%20cation", "/l%20cation"},
{"../locati%C3%abn", "/locati%C3%abn"},
{"../other%2fplace", "/other%2fplace"},
{"http://somehost.com/other/location", "http://somehost.com/other/location"},
};
int[] ports = new int[]{8080, 80};
String[] hosts = new String[]{null, "myhost", "192.168.0.1", "0::1"};
for (int port : ports)
{
for (String host : hosts)
{
for (int i = 0; i < tests.length; i++)
{
// System.err.printf("%s %d %s%n",host,port,tests[i][0]);
Response response = getResponse();
Request request = response.getHttpChannel().getRequest();
request.getHttpChannel().getHttpConfiguration().setRelativeRedirectAllowed(true);
request.setScheme("http");
if (host != null)
request.setAuthority(host, port);
request.setURIPathQuery("/path/info;param;jsessionid=12345?query=0&more=1#target");
request.setContextPath("/path");
request.setRequestedSessionId("12345");
request.setRequestedSessionIdFromCookie(i > 2);
SessionHandler handler = new SessionHandler();
NullSessionDataStore ds = new NullSessionDataStore();
DefaultSessionCache ss = new DefaultSessionCache(handler);
handler.setSessionCache(ss);
ss.setSessionDataStore(ds);
DefaultSessionIdManager idMgr = new DefaultSessionIdManager(_server);
idMgr.setWorkerName(null);
handler.setSessionIdManager(idMgr);
request.setSessionHandler(handler);
request.setSession(new TestSession(handler, "12345"));
handler.setCheckingRemoteSessionIdEncoding(false);
response.sendRedirect(tests[i][0]);
String location = response.getHeader("Location");
String expected = tests[i][1]
.replace("@HOST@", host == null ? request.getLocalAddr() : (host.contains(":") ? ("[" + host + "]") : host))
.replace("@PORT@", host == null ? ":8888" : (port == 80 ? "" : (":" + port)));
assertEquals(expected, location, "test-" + i + " " + host + ":" + port);
}
}
}
}
@Test @Test
public void testInvalidSendRedirect() throws Exception public void testInvalidSendRedirect() throws Exception
{ {