merged fix for WW-4628 (avoid double encoding of url parameters)

This commit is contained in:
cnenning
2016-08-01 13:50:23 +02:00
parent e8b48f8bb4
commit ae2840f183
2 changed files with 74 additions and 9 deletions
@@ -24,6 +24,18 @@ package org.apache.struts2.views.util;
import com.opensymphony.xwork2.inject.Inject;
import com.opensymphony.xwork2.util.logging.Logger;
import com.opensymphony.xwork2.util.logging.LoggerFactory;
import java.io.UnsupportedEncodingException;
import java.net.URLEncoder;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Iterator;
import java.util.LinkedHashMap;
import java.util.List;
import java.util.Map;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import org.apache.commons.lang3.StringEscapeUtils;
import org.apache.commons.lang3.StringUtils;
import org.apache.struts2.StrutsConstants;
@@ -178,10 +190,11 @@ public class DefaultUrlHelper implements UrlHelper {
}
//if the action was not explicitly set grab the params from the request
//always pass encode=false here as encoding might happen for complete URL later
if (escapeAmp) {
buildParametersString(params, link, AMP);
buildParametersString(params, link, AMP, false);
} else {
buildParametersString(params, link, "&");
buildParametersString(params, link, "&", false);
}
String result = link.toString();
@@ -202,6 +215,10 @@ public class DefaultUrlHelper implements UrlHelper {
}
public void buildParametersString(Map<String, Object> params, StringBuilder link, String paramSeparator) {
buildParametersString(params, link, paramSeparator, true);
}
public void buildParametersString(Map<String, Object> params, StringBuilder link, String paramSeparator, boolean encode) {
if ((params != null) && (params.size() > 0)) {
if (!link.toString().contains("?")) {
link.append("?");
@@ -219,7 +236,7 @@ public class DefaultUrlHelper implements UrlHelper {
if (value instanceof Iterable) {
for (Iterator iterator = ((Iterable) value).iterator(); iterator.hasNext();) {
Object paramValue = iterator.next();
link.append(buildParameterSubstring(name, paramValue != null ? paramValue.toString() : StringUtils.EMPTY));
link.append(buildParameterSubstring(name, paramValue != null ? paramValue.toString() : StringUtils.EMPTY, encode));
if (iterator.hasNext()) {
link.append(paramSeparator);
@@ -229,14 +246,14 @@ public class DefaultUrlHelper implements UrlHelper {
Object[] array = (Object[]) value;
for (int i = 0; i < array.length; i++) {
Object paramValue = array[i];
link.append(buildParameterSubstring(name, paramValue != null ? paramValue.toString() : StringUtils.EMPTY));
link.append(buildParameterSubstring(name, paramValue != null ? paramValue.toString() : StringUtils.EMPTY, encode));
if (i < array.length - 1) {
link.append(paramSeparator);
}
}
} else {
link.append(buildParameterSubstring(name, value != null ? value.toString() : StringUtils.EMPTY));
link.append(buildParameterSubstring(name, value != null ? value.toString() : StringUtils.EMPTY, encode));
}
if (iter.hasNext()) {
@@ -250,11 +267,11 @@ public class DefaultUrlHelper implements UrlHelper {
return HTTP_PROTOCOL.equals(scheme) || HTTPS_PROTOCOL.equals(scheme);
}
private String buildParameterSubstring(String name, String value) {
private String buildParameterSubstring(String name, String value, boolean encode) {
StringBuilder builder = new StringBuilder();
builder.append(encode(name));
builder.append(encode ? encode(name) : name);
builder.append('=');
builder.append(encode(value));
builder.append(encode ? encode(value) : value);
return builder.toString();
}
@@ -128,6 +128,33 @@ public class DefaultUrlHelperTest extends StrutsInternalTestCase {
expectedUrl, url.toString());
}
public void testBuildUrlWithJavaScriptInjected() throws Exception {
String expectedUrl = "http://localhost:8080/myContext/myPage.jsp?initParam=initValue&amp;param1=value1&amp;param2=value2&amp;param3%22%3Cscript+type%3D%22text%2Fjavascript%22%3Ealert%281%29%3B%3C%2Fscript%3E=value3";
// there is explicit escaping for EcmaScript before URL encoding
String expectedUrlBeforeEncoding = "http:\\/\\/localhost:8080\\/myContext\\/myPage.jsp?initParam=initValue&amp;param1=value1&amp;param2=value2&amp;param3\\\"<script type=\\\"text\\/javascript\\\">alert(1);<\\/script>=value3";
Mock mockHttpServletRequest = new Mock(HttpServletRequest.class);
mockHttpServletRequest.expectAndReturn("getScheme", "http");
mockHttpServletRequest.expectAndReturn("getServerName", "localhost");
mockHttpServletRequest.expectAndReturn("getContextPath", "/myContext");
mockHttpServletRequest.expectAndReturn("getServerPort", 8080);
Mock mockHttpServletResponse = new Mock(HttpServletResponse.class);
mockHttpServletResponse.expectAndReturn("encodeURL", expectedUrlBeforeEncoding, expectedUrl);
Map parameters = new LinkedHashMap();
parameters.put("param1", "value1");
parameters.put("param2", "value2");
parameters.put("param3\"<script type=\"text/javascript\">alert(1);</script>","value3");
String result = urlHelper.buildUrl("/myPage.jsp?initParam=initValue", (HttpServletRequest) mockHttpServletRequest.proxy(), (HttpServletResponse) mockHttpServletResponse.proxy(), parameters, "http", true, true, true);
assertEquals(
expectedUrl, result);
mockHttpServletRequest.verify();
}
public void testForceAddNullSchemeHostAndPort() throws Exception {
String expectedUrl = "http://localhost/contextPath/path1/path2/myAction.action";
@@ -393,7 +420,28 @@ public class DefaultUrlHelperTest extends StrutsInternalTestCase {
assertEquals(result, expectedResult);
}
public void testDontEncode() throws Exception {
String expectedUrl = "http://localhost/contextPath/myAction.action?param1=value+with+spaces";
Mock mockHttpServletRequest = new Mock(HttpServletRequest.class);
mockHttpServletRequest.expectAndReturn("getScheme", "http");
mockHttpServletRequest.expectAndReturn("getServerName", "localhost");
mockHttpServletRequest.expectAndReturn("getContextPath", "/contextPath");
mockHttpServletRequest.expectAndReturn("getServerPort", 80);
Mock mockHttpServletResponse = new Mock(HttpServletResponse.class);
Map parameters = new LinkedHashMap();
parameters.put("param1", "value+with+spaces");
String result = urlHelper.buildUrl("/myAction.action", (HttpServletRequest) mockHttpServletRequest.proxy(), (HttpServletResponse) mockHttpServletResponse.proxy(), parameters, "http", true, false, true);
assertEquals(
expectedUrl, result);
}
public void setUp() throws Exception {
super.setUp();
stubContainer = new StubContainer(container);