This is an automated email from the ASF dual-hosted git repository.

reta pushed a commit to branch 3.3.x-fixes
in repository https://gitbox.apache.org/repos/asf/cxf.git


The following commit(s) were added to refs/heads/3.3.x-fixes by this push:
     new 39e7972  CXF-8619 Prevent double URL-decoding for form parameters 
where the pa… (#878)
39e7972 is described below

commit 39e79722c33e7ae5499c81b9a039391d1ac98f40
Author: Jonathan Gallimore <[email protected]>
AuthorDate: Wed Dec 1 17:45:28 2021 +0000

    CXF-8619 Prevent double URL-decoding for form parameters where the pa… 
(#878)
    
    * CXF-8619 Prevent double URL-decoding for form parameters where the 
parameters are read from HttpServletRequest.getParameter()
    
    * Introduce contextual property to mark form params as encoded if they come 
from ServletRequest request parameters
    
    Co-authored-by: Andriy Redko <[email protected]>
---
 .../org/apache/cxf/jaxrs/utils/FormUtilsTest.java  |  2 +-
 .../org/apache/cxf/jaxrs/utils/JAXRSUtilsTest.java |  4 +-
 .../cxf/systest/jaxrs/form/FormReaderFilter.java   | 58 +++++++++++++++
 .../systest/jaxrs/form/FormWithFilterServer.java   | 85 ++++++++++++++++++++++
 .../cxf/systest/jaxrs/form/FormWithFilterTest.java | 75 +++++++++++++++++++
 5 files changed, 221 insertions(+), 3 deletions(-)

diff --git 
a/rt/frontend/jaxrs/src/test/java/org/apache/cxf/jaxrs/utils/FormUtilsTest.java 
b/rt/frontend/jaxrs/src/test/java/org/apache/cxf/jaxrs/utils/FormUtilsTest.java
index d712cbf..2db533e 100644
--- 
a/rt/frontend/jaxrs/src/test/java/org/apache/cxf/jaxrs/utils/FormUtilsTest.java
+++ 
b/rt/frontend/jaxrs/src/test/java/org/apache/cxf/jaxrs/utils/FormUtilsTest.java
@@ -97,7 +97,7 @@ public class FormUtilsTest {
         
EasyMock.expect(mockMessage.getContextualProperty(FormUtils.FORM_PARAMS_FROM_HTTP_PARAMS))
             .andReturn(formPropertyValue).anyTimes();
         EasyMock.expect(mockMessage.getExchange()).andReturn(null).anyTimes();
-
+        
         mockRequest = EasyMock.createMock(HttpServletRequest.class);
         String[] httpParamNames = {HTTP_PARAM1, HTTP_PARAM2};
         Enumeration<String> httpParamsEnum = 
Collections.enumeration(Arrays.asList(httpParamNames));
diff --git 
a/rt/frontend/jaxrs/src/test/java/org/apache/cxf/jaxrs/utils/JAXRSUtilsTest.java
 
b/rt/frontend/jaxrs/src/test/java/org/apache/cxf/jaxrs/utils/JAXRSUtilsTest.java
index 9638f37..50261e7 100644
--- 
a/rt/frontend/jaxrs/src/test/java/org/apache/cxf/jaxrs/utils/JAXRSUtilsTest.java
+++ 
b/rt/frontend/jaxrs/src/test/java/org/apache/cxf/jaxrs/utils/JAXRSUtilsTest.java
@@ -1572,7 +1572,7 @@ public class JAXRSUtilsTest {
         Class<?>[] argType = {String.class, List.class};
         Method m = Customer.class.getMethod("testFormParam", argType);
         Message messageImpl = createMessage();
-        String body = "p1=1&p2=2&p2=3";
+        String body = "p1=hello%2bworld&p2=2&p2=3";
         messageImpl.put(Message.REQUEST_URI, "/foo");
         MultivaluedMap<String, String> headers = new MetadataMap<>();
         if (useMediaType) {
@@ -1586,7 +1586,7 @@ public class JAXRSUtilsTest {
         assertEquals("2 form params should've been identified", 2, 
params.size());
 
         assertEquals("First Form Parameter not matched correctly",
-                     "1", params.get(0));
+                     "hello+world", params.get(0));
         List<String> list = (List<String>)params.get(1);
         assertEquals(2, list.size());
         assertEquals("2", list.get(0));
diff --git 
a/systests/jaxrs/src/test/java/org/apache/cxf/systest/jaxrs/form/FormReaderFilter.java
 
b/systests/jaxrs/src/test/java/org/apache/cxf/systest/jaxrs/form/FormReaderFilter.java
new file mode 100644
index 0000000..fb2f71a
--- /dev/null
+++ 
b/systests/jaxrs/src/test/java/org/apache/cxf/systest/jaxrs/form/FormReaderFilter.java
@@ -0,0 +1,58 @@
+/**
+ * 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.cxf.systest.jaxrs.form;
+
+
+import java.io.IOException;
+import java.util.logging.Logger;
+
+import javax.servlet.Filter;
+import javax.servlet.FilterChain;
+import javax.servlet.FilterConfig;
+import javax.servlet.ServletException;
+import javax.servlet.ServletRequest;
+import javax.servlet.ServletResponse;
+
+import org.apache.cxf.common.logging.LogUtils;
+
+public class FormReaderFilter implements Filter {
+
+    private static final Logger LOGGER = 
LogUtils.getL7dLogger(FormReaderFilter.class);
+
+    @Override
+    public void init(FilterConfig filterConfig) throws ServletException {
+
+    }
+
+    @Override
+    public void doFilter(final ServletRequest servletRequest,
+                         final ServletResponse servletResponse,
+                         final FilterChain filterChain) throws IOException, 
ServletException {
+
+        final String value = servletRequest.getParameter("value");
+        LOGGER.info("Seen value=" + value);
+
+        filterChain.doFilter(servletRequest, servletResponse);
+    }
+
+    @Override
+    public void destroy() {
+
+    }
+}
diff --git 
a/systests/jaxrs/src/test/java/org/apache/cxf/systest/jaxrs/form/FormWithFilterServer.java
 
b/systests/jaxrs/src/test/java/org/apache/cxf/systest/jaxrs/form/FormWithFilterServer.java
new file mode 100644
index 0000000..8f16155
--- /dev/null
+++ 
b/systests/jaxrs/src/test/java/org/apache/cxf/systest/jaxrs/form/FormWithFilterServer.java
@@ -0,0 +1,85 @@
+/**
+ * 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.cxf.systest.jaxrs.form;
+
+import org.apache.cxf.Bus;
+import org.apache.cxf.BusFactory;
+import org.apache.cxf.jaxrs.JAXRSServerFactoryBean;
+import org.apache.cxf.jaxrs.lifecycle.SingletonResourceProvider;
+import org.apache.cxf.testutil.common.AbstractBusTestServerBase;
+import org.apache.cxf.transport.servlet.CXFNonSpringServlet;
+import org.eclipse.jetty.server.Server;
+import org.eclipse.jetty.servlet.FilterHolder;
+import org.eclipse.jetty.servlet.FilterMapping;
+import org.eclipse.jetty.servlet.ServletHandler;
+import org.eclipse.jetty.servlet.ServletHolder;
+
+public class FormWithFilterServer extends AbstractBusTestServerBase {
+    public static final String PORT = allocatePort(FormWithFilterServer.class);
+
+    protected void run() {
+        String busFactory = 
System.getProperty(BusFactory.BUS_FACTORY_PROPERTY_NAME);
+        System.setProperty(BusFactory.BUS_FACTORY_PROPERTY_NAME, 
"org.apache.cxf.bus.CXFBusFactory");
+        try {
+            CXFNonSpringServlet cxf = new CXFNonSpringServlet();
+            httpServer(cxf).start();
+            serverFactory(cxf.getBus()).create();
+        } catch (Exception e) {
+            throw new RuntimeException(e);
+        } finally {
+            if (busFactory != null) {
+                System.setProperty(BusFactory.BUS_FACTORY_PROPERTY_NAME, 
busFactory);
+            } else {
+                System.clearProperty(BusFactory.BUS_FACTORY_PROPERTY_NAME);
+            }
+        }
+    }
+
+    private Server httpServer(CXFNonSpringServlet cxf) {
+        Server server = new Server(Integer.parseInt(PORT));
+        ServletHandler handler = new ServletHandler();
+        server.setHandler(handler);
+        handler.addServletWithMapping(new ServletHolder(cxf), "/*");
+        handler.addFilterWithMapping(new FilterHolder(new FormReaderFilter()), 
"/*", FilterMapping.ALL);
+        return server;
+    }
+
+    private JAXRSServerFactoryBean serverFactory(Bus bus) {
+        JAXRSServerFactoryBean sf = new JAXRSServerFactoryBean();
+        sf.setBus(bus);
+        sf.setResourceClasses(FormResource.class);
+        sf.setResourceProvider(FormResource.class,
+                               new SingletonResourceProvider(new 
FormResource()));
+        sf.setAddress("/");
+        return sf;
+    }
+
+    public static void main(String[] args) {
+        try {
+            FormWithFilterServer s = new FormWithFilterServer();
+            s.start();
+        } catch (Exception ex) {
+            ex.printStackTrace();
+            System.exit(-1);
+        } finally {
+            System.out.println("done!");
+        }
+    }
+}
diff --git 
a/systests/jaxrs/src/test/java/org/apache/cxf/systest/jaxrs/form/FormWithFilterTest.java
 
b/systests/jaxrs/src/test/java/org/apache/cxf/systest/jaxrs/form/FormWithFilterTest.java
new file mode 100644
index 0000000..7e7868f
--- /dev/null
+++ 
b/systests/jaxrs/src/test/java/org/apache/cxf/systest/jaxrs/form/FormWithFilterTest.java
@@ -0,0 +1,75 @@
+/**
+ * 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.cxf.systest.jaxrs.form;
+
+import java.util.ArrayList;
+import java.util.List;
+
+import org.apache.cxf.jaxrs.model.AbstractResourceInfo;
+import org.apache.cxf.testutil.common.AbstractBusClientServerTestBase;
+import org.apache.http.NameValuePair;
+import org.apache.http.client.entity.UrlEncodedFormEntity;
+import org.apache.http.client.methods.CloseableHttpResponse;
+import org.apache.http.client.methods.HttpPost;
+import org.apache.http.impl.client.CloseableHttpClient;
+import org.apache.http.impl.client.HttpClientBuilder;
+import org.apache.http.message.BasicNameValuePair;
+
+import org.junit.BeforeClass;
+import org.junit.Test;
+
+
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertTrue;
+
+public class FormWithFilterTest extends AbstractBusClientServerTestBase {
+    public static final String PORT = FormWithFilterServer.PORT;
+
+    @BeforeClass
+    public static void startServers() throws Exception {
+        AbstractResourceInfo.clearAllMaps();
+        createStaticBus();
+        assertTrue("server did not launch correctly",
+                   launchServer(FormWithFilterServer.class));
+    }
+
+    @Test
+    public void testEncodedURL() throws Exception {
+        CloseableHttpClient client = HttpClientBuilder.create().build();
+        HttpPost post = new HttpPost("http://localhost:"; + PORT + "/form");
+
+        List<NameValuePair> params = new ArrayList<NameValuePair>();
+        final String expected = "This%2Bis+a+test";
+        params.add(new BasicNameValuePair("value", expected));
+        post.setEntity(new UrlEncodedFormEntity(params));
+
+        try {
+            CloseableHttpResponse response = client.execute(post);
+            assertEquals("POST was not handled successfully",
+                         200, response.getStatusLine().getStatusCode());
+
+            assertEquals(expected, 
response.getFirstHeader("FromForm").getValue());
+            assertEquals(expected, 
response.getFirstHeader("FromFormParam").getValue());
+        } finally {
+            // Release current connection to the connection pool once you are 
done
+            post.releaseConnection();
+        }
+    }
+}

Reply via email to