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());
+    }
+
+}

Reply via email to