Skip to content
Merged
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
81 changes: 79 additions & 2 deletions src/share/org/apache/struts/util/RequestUtils.java
Original file line number Diff line number Diff line change
Expand Up @@ -74,6 +74,7 @@
import java.util.Iterator;
import java.util.Locale;
import java.util.Map;
import java.util.regex.Pattern;

import javax.servlet.ServletContext;
import javax.servlet.ServletException;
Expand Down Expand Up @@ -105,6 +106,7 @@
import org.apache.struts.config.ForwardConfig;
import org.apache.struts.config.ModuleConfig;
import org.apache.struts.taglib.html.Constants;
import org.apache.struts.upload.FormFile;
import org.apache.struts.upload.MultipartRequestHandler;
import org.apache.struts.upload.MultipartRequestWrapper;

Expand All @@ -128,6 +130,13 @@ public class RequestUtils {
*/
protected static Log log = LogFactory.getLog(RequestUtils.class);

/**
* <p>Pattern matching 'class' access.</p>
*/
protected static final Pattern CLASS_ACCESS_PATTERN = Pattern
.compile("(.*\\.|^|.*|\\[('|\"))class(\\.|('|\")]|\\[).*",
Pattern.CASE_INSENSITIVE);

/**
* The message resources for this package.
*/
Expand Down Expand Up @@ -1239,10 +1248,23 @@ public static void populate(
}
stripped = stripped.substring(0, stripped.length() - suffix.length());
}

Object parameterValue = null;
if (isMultipart) {
properties.put(stripped, multipartParameters.get(name));
parameterValue = multipartParameters.get(name);
parameterValue = rationalizeMultipleFileProperty(bean, name, parameterValue);
} else {
properties.put(stripped, request.getParameterValues(name));
parameterValue = request.getParameterValues(name);
}

/**
* Security fixes for Struts 1.1 Application
* stripped.startsWith("org.apache.struts.") - Fixes multiple CVE's and risks with multi-part file loading
* Don't populate struts attributes (e.g. 'org.apache.struts.action.CANCEL')
* CLASS_ACCESS_PATERN - fixes CVE-2014-0114 critical vulnerability with access for remote execution.
*/
if (!(stripped.startsWith("org.apache.struts.")) && !CLASS_ACCESS_PATTERN.matcher(stripped).matches()) {
properties.put(stripped, parameterValue);
}
}

Expand All @@ -1251,10 +1273,65 @@ public static void populate(
BeanUtils.populate(bean, properties);
} catch (Exception e) {
throw new ServletException("BeanUtils.populate", e);
} finally {
if (multipartHandler != null) {
// Set the multipart request handler for our ActionForm.
// If the bean isn't an ActionForm, an exception would have been
// thrown earlier, so it's safe to assume that our bean is
// in fact an ActionForm.
((ActionForm) bean).setMultipartRequestHandler(multipartHandler);
}
}

}

/**
* <p>If the given form bean can accept multiple FormFile objects but the user only uploaded a single, then
* the property will not match the form bean type. This method performs some simple checks to try to accommodate
* that situation.</p>
* @param bean
* @param name
* @param parameterValue
* @return
* @throws ServletException if the introspection has any errors.
*/
private static Object rationalizeMultipleFileProperty(Object bean, String name, Object parameterValue) throws ServletException {
if (!(parameterValue instanceof FormFile)) {
return parameterValue;
}

FormFile formFileValue = (FormFile) parameterValue;
try {
Class propertyType = PropertyUtils.getPropertyType(bean, name);

if (propertyType == null) {
return parameterValue;
}

if (List.class.isAssignableFrom(propertyType)) {
ArrayList list = new ArrayList(1);
list.add(formFileValue);
return list;
}

if (propertyType.isArray() && propertyType.getComponentType().equals(FormFile.class)) {
return new FormFile[] { formFileValue };
}

} catch (IllegalAccessException e) {
throw new ServletException(e);
} catch (InvocationTargetException e) {
throw new ServletException(e);
} catch (NoSuchMethodException e) {
throw new ServletException(e);
}

// no changes
return parameterValue;

}


/**
* Try to locate a multipart request handler for this request. First, look
* for a mapping-specific handler stored for us under an attribute. If one
Expand Down