WW-5501 Ignores DMI related action field

This commit is contained in:
Lukasz Lenart
2025-02-02 13:56:03 +01:00
committed by Lukasz Lenart
parent 58b0d536e8
commit 21c7ecc105
6 changed files with 161 additions and 6 deletions
@@ -18,9 +18,6 @@
*/
package org.apache.struts2.dispatcher.multipart;
import org.apache.struts2.inject.Inject;
import org.apache.struts2.security.DefaultExcludedPatternsChecker;
import org.apache.struts2.security.ExcludedPatternsChecker;
import jakarta.servlet.http.HttpServletRequest;
import org.apache.commons.fileupload2.core.FileUploadByteCountLimitException;
import org.apache.commons.fileupload2.core.FileUploadContentTypeException;
@@ -28,11 +25,15 @@ import org.apache.commons.fileupload2.core.FileUploadException;
import org.apache.commons.fileupload2.core.FileUploadFileCountLimitException;
import org.apache.commons.fileupload2.core.FileUploadSizeException;
import org.apache.commons.fileupload2.jakarta.servlet6.JakartaServletDiskFileUpload;
import org.apache.commons.lang3.BooleanUtils;
import org.apache.commons.lang3.StringUtils;
import org.apache.logging.log4j.LogManager;
import org.apache.logging.log4j.Logger;
import org.apache.struts2.StrutsConstants;
import org.apache.struts2.dispatcher.LocalizedMessage;
import org.apache.struts2.inject.Inject;
import org.apache.struts2.security.DefaultExcludedPatternsChecker;
import org.apache.struts2.security.ExcludedPatternsChecker;
import java.io.IOException;
import java.nio.charset.Charset;
@@ -54,7 +55,8 @@ public abstract class AbstractMultiPartRequest implements MultiPartRequest {
private static final Logger LOG = LogManager.getLogger(AbstractMultiPartRequest.class);
private static final String EXCLUDED_FILE_PATTERN = ".*[<>&\"'|;\\\\/?*:]+.*|.*\\.\\..*";
private static final String EXCLUDED_FILE_PATTERN = "^(.*[<>&\"'|;\\\\/?*:]+.*|.*\\.\\..*)$";
private static final String EXCLUDED_FILE_PATTERN_WITH_DMI_SUPPORT = "^(?!action:[^<>&\"'|;\\\\/?*:]+(![^<>&\"'|;\\\\/?*:]+)?$)(.*[<>&\"'|;\\\\/?*:]+.*|.*\\.\\..*)$\n";
/**
* Defines the internal buffer size used during streaming operations.
@@ -114,9 +116,13 @@ public abstract class AbstractMultiPartRequest implements MultiPartRequest {
private final ExcludedPatternsChecker patternsChecker;
protected AbstractMultiPartRequest() {
protected AbstractMultiPartRequest(String dmiValue) {
patternsChecker = new DefaultExcludedPatternsChecker();
((DefaultExcludedPatternsChecker) patternsChecker).setAdditionalExcludePatterns(EXCLUDED_FILE_PATTERN);
if (BooleanUtils.toBoolean(dmiValue)) {
((DefaultExcludedPatternsChecker) patternsChecker).setAdditionalExcludePatterns(EXCLUDED_FILE_PATTERN_WITH_DMI_SUPPORT);
} else {
((DefaultExcludedPatternsChecker) patternsChecker).setAdditionalExcludePatterns(EXCLUDED_FILE_PATTERN);
}
}
/**
@@ -25,6 +25,8 @@ import org.apache.commons.fileupload2.jakarta.servlet6.JakartaServletDiskFileUpl
import org.apache.commons.lang3.StringUtils;
import org.apache.logging.log4j.LogManager;
import org.apache.logging.log4j.Logger;
import org.apache.struts2.StrutsConstants;
import org.apache.struts2.inject.Inject;
import java.io.IOException;
import java.nio.charset.Charset;
@@ -41,6 +43,16 @@ public class JakartaMultiPartRequest extends AbstractMultiPartRequest {
private static final Logger LOG = LogManager.getLogger(JakartaMultiPartRequest.class);
public JakartaMultiPartRequest() {
super(Boolean.FALSE.toString());
}
public JakartaMultiPartRequest(
@Inject(value = StrutsConstants.STRUTS_ENABLE_DYNAMIC_METHOD_INVOCATION, required = false) String dmiValue
) {
super(dmiValue);
}
@Override
protected void processUpload(HttpServletRequest request, String saveDir) throws IOException {
Charset charset = readCharsetEncoding(request);
@@ -26,7 +26,9 @@ import org.apache.commons.fileupload2.core.FileUploadSizeException;
import org.apache.commons.fileupload2.jakarta.servlet6.JakartaServletDiskFileUpload;
import org.apache.logging.log4j.LogManager;
import org.apache.logging.log4j.Logger;
import org.apache.struts2.StrutsConstants;
import org.apache.struts2.dispatcher.LocalizedMessage;
import org.apache.struts2.inject.Inject;
import java.io.BufferedOutputStream;
import java.io.ByteArrayOutputStream;
@@ -56,6 +58,16 @@ public class JakartaStreamMultiPartRequest extends AbstractMultiPartRequest {
private static final Logger LOG = LogManager.getLogger(JakartaStreamMultiPartRequest.class);
public JakartaStreamMultiPartRequest() {
super(Boolean.FALSE.toString());
}
public JakartaStreamMultiPartRequest(
@Inject(value = StrutsConstants.STRUTS_ENABLE_DYNAMIC_METHOD_INVOCATION, required = false) String dmiValue
) {
super(dmiValue);
}
/**
* Processes the upload.
*
@@ -0,0 +1,69 @@
/*
* Licensed to the Apache Software Foundation (ASF) under one
* or more contributor license agreements. See the NOTICE file
* distributed with this work for additional information
* regarding copyright ownership. The ASF licenses this file
* to you under the Apache License, Version 2.0 (the
* "License"); you may not use this file except in compliance
* with the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing,
* software distributed under the License is distributed on an
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
* KIND, either express or implied. See the License for the
* specific language governing permissions and limitations
* under the License.
*/
package org.apache.struts2.dispatcher.multipart;
import org.apache.commons.fileupload2.jakarta.servlet6.JakartaServletDiskFileUpload;
import org.junit.Test;
import java.io.IOException;
import java.nio.charset.StandardCharsets;
import static org.assertj.core.api.Assertions.assertThat;
abstract class AbstractMultiPartRequestWithDMITest extends AbstractMultiPartRequestTest {
@Test
public void actionField() throws IOException {
String content = formFile("file1", "test1.csv", "1,2,3,4") +
formField("action:myUploads", "") +
endline + "--" + boundary + "--";
mockRequest.setContent(content.getBytes(StandardCharsets.UTF_8));
assertThat(JakartaServletDiskFileUpload.isMultipartContent(mockRequest)).isTrue();
multiPart.parse(mockRequest, tempDir);
assertThat(multiPart.getErrors())
.isEmpty();
assertThat(multiPart.getParameterNames().asIterator()).toIterable()
.containsOnly("action:myUploads");
}
@Test
public void actionFieldWithBang() throws IOException {
String content = formFile("file1", "test1.csv", "1,2,3,4") +
formField("action:myUploads!upload", "") +
endline + "--" + boundary + "--";
mockRequest.setContent(content.getBytes(StandardCharsets.UTF_8));
assertThat(JakartaServletDiskFileUpload.isMultipartContent(mockRequest)).isTrue();
multiPart.parse(mockRequest, tempDir);
assertThat(multiPart.getErrors())
.isEmpty();
assertThat(multiPart.getParameterNames().asIterator()).toIterable()
.containsOnly("action:myUploads!upload");
}
}
@@ -0,0 +1,28 @@
/*
* Licensed to the Apache Software Foundation (ASF) under one
* or more contributor license agreements. See the NOTICE file
* distributed with this work for additional information
* regarding copyright ownership. The ASF licenses this file
* to you under the Apache License, Version 2.0 (the
* "License"); you may not use this file except in compliance
* with the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing,
* software distributed under the License is distributed on an
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
* KIND, either express or implied. See the License for the
* specific language governing permissions and limitations
* under the License.
*/
package org.apache.struts2.dispatcher.multipart;
public class JakartaMultiPartRequestWithDMITest extends AbstractMultiPartRequestWithDMITest {
@Override
protected AbstractMultiPartRequest createMultipartRequest() {
return new JakartaMultiPartRequest(Boolean.TRUE.toString());
}
}
@@ -0,0 +1,28 @@
/*
* Licensed to the Apache Software Foundation (ASF) under one
* or more contributor license agreements. See the NOTICE file
* distributed with this work for additional information
* regarding copyright ownership. The ASF licenses this file
* to you under the Apache License, Version 2.0 (the
* "License"); you may not use this file except in compliance
* with the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing,
* software distributed under the License is distributed on an
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
* KIND, either express or implied. See the License for the
* specific language governing permissions and limitations
* under the License.
*/
package org.apache.struts2.dispatcher.multipart;
public class JakartaStreamMultiPartRequestWithDMITest extends AbstractMultiPartRequestWithDMITest {
@Override
protected AbstractMultiPartRequest createMultipartRequest() {
return new JakartaStreamMultiPartRequest(Boolean.TRUE.toString());
}
}