This is an automated email from the ASF dual-hosted git repository. lukaszlenart pushed a commit to branch fix/WW-5501-dmi-s7 in repository https://gitbox.apache.org/repos/asf/struts.git
commit bdd29ac7322dbf0743abc3db494124492d18b842 Author: Lukasz Lenart <lukaszlen...@apache.org> AuthorDate: Sun Feb 2 13:56:03 2025 +0100 WW-5501 Ignores DMI related action field --- .../multipart/AbstractMultiPartRequest.java | 18 ++++-- .../multipart/JakartaMultiPartRequest.java | 12 ++++ .../multipart/JakartaStreamMultiPartRequest.java | 12 ++++ .../AbstractMultiPartRequestWithDMITest.java | 69 ++++++++++++++++++++++ .../JakartaMultiPartRequestWithDMITest.java | 28 +++++++++ .../JakartaStreamMultiPartRequestWithDMITest.java | 28 +++++++++ 6 files changed, 161 insertions(+), 6 deletions(-) diff --git a/core/src/main/java/org/apache/struts2/dispatcher/multipart/AbstractMultiPartRequest.java b/core/src/main/java/org/apache/struts2/dispatcher/multipart/AbstractMultiPartRequest.java index cceef2cab..7f848a56d 100644 --- a/core/src/main/java/org/apache/struts2/dispatcher/multipart/AbstractMultiPartRequest.java +++ b/core/src/main/java/org/apache/struts2/dispatcher/multipart/AbstractMultiPartRequest.java @@ -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); + } } /** diff --git a/core/src/main/java/org/apache/struts2/dispatcher/multipart/JakartaMultiPartRequest.java b/core/src/main/java/org/apache/struts2/dispatcher/multipart/JakartaMultiPartRequest.java index 737ba23f8..341900eb8 100644 --- a/core/src/main/java/org/apache/struts2/dispatcher/multipart/JakartaMultiPartRequest.java +++ b/core/src/main/java/org/apache/struts2/dispatcher/multipart/JakartaMultiPartRequest.java @@ -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); diff --git a/core/src/main/java/org/apache/struts2/dispatcher/multipart/JakartaStreamMultiPartRequest.java b/core/src/main/java/org/apache/struts2/dispatcher/multipart/JakartaStreamMultiPartRequest.java index 2d2b67c68..f8b01f312 100644 --- a/core/src/main/java/org/apache/struts2/dispatcher/multipart/JakartaStreamMultiPartRequest.java +++ b/core/src/main/java/org/apache/struts2/dispatcher/multipart/JakartaStreamMultiPartRequest.java @@ -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. * diff --git a/core/src/test/java/org/apache/struts2/dispatcher/multipart/AbstractMultiPartRequestWithDMITest.java b/core/src/test/java/org/apache/struts2/dispatcher/multipart/AbstractMultiPartRequestWithDMITest.java new file mode 100644 index 000000000..fcec29ddf --- /dev/null +++ b/core/src/test/java/org/apache/struts2/dispatcher/multipart/AbstractMultiPartRequestWithDMITest.java @@ -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"); + } + +} diff --git a/core/src/test/java/org/apache/struts2/dispatcher/multipart/JakartaMultiPartRequestWithDMITest.java b/core/src/test/java/org/apache/struts2/dispatcher/multipart/JakartaMultiPartRequestWithDMITest.java new file mode 100644 index 000000000..6aecba01b --- /dev/null +++ b/core/src/test/java/org/apache/struts2/dispatcher/multipart/JakartaMultiPartRequestWithDMITest.java @@ -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()); + } + +} diff --git a/core/src/test/java/org/apache/struts2/dispatcher/multipart/JakartaStreamMultiPartRequestWithDMITest.java b/core/src/test/java/org/apache/struts2/dispatcher/multipart/JakartaStreamMultiPartRequestWithDMITest.java new file mode 100644 index 000000000..f93d42f33 --- /dev/null +++ b/core/src/test/java/org/apache/struts2/dispatcher/multipart/JakartaStreamMultiPartRequestWithDMITest.java @@ -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()); + } + +}