This is an automated email from the ASF dual-hosted git repository. reta pushed a commit to branch 3.6.x-fixes in repository https://gitbox.apache.org/repos/asf/cxf.git
commit b279f743d3d766e1d017a33ce91224386af0e786 Author: Andriy Redko <[email protected]> AuthorDate: Thu Sep 10 18:39:41 2026 -0400 Add maxFormParameterSize contextual message parameter and bound form params processing to it (#3457) (cherry picked from commit c9f8dc497879b5a2eca2a51a6d21f80966d534a1) --- .../cxf/jaxrs/impl/HttpServletRequestFilter.java | 3 ++- .../java/org/apache/cxf/jaxrs/utils/FormUtils.java | 5 +++++ .../org/apache/cxf/jaxrs/utils/JAXRSUtils.java | 2 +- .../oauth2/client/ClientCodeRequestFilter.java | 7 +++++-- .../security/oidc/rp/OidcIdTokenRequestFilter.java | 7 +++++-- .../oidc/rp/OidcRpAuthenticationFilter.java | 7 +++++-- .../systest/jaxrs/JAXRSClientServerBookTest.java | 24 ++++++++++++++++++++++ 7 files changed, 47 insertions(+), 8 deletions(-) diff --git a/rt/frontend/jaxrs/src/main/java/org/apache/cxf/jaxrs/impl/HttpServletRequestFilter.java b/rt/frontend/jaxrs/src/main/java/org/apache/cxf/jaxrs/impl/HttpServletRequestFilter.java index 7b7eea6f3a0..754a62254b9 100644 --- a/rt/frontend/jaxrs/src/main/java/org/apache/cxf/jaxrs/impl/HttpServletRequestFilter.java +++ b/rt/frontend/jaxrs/src/main/java/org/apache/cxf/jaxrs/impl/HttpServletRequestFilter.java @@ -120,7 +120,8 @@ public class HttpServletRequestFilter extends HttpServletRequestWrapper { formParams = new MetadataMap<>(); MediaType mt = JAXRSUtils.toMediaType((String)m.get(Message.CONTENT_TYPE)); String enc = HttpUtils.getEncoding(mt, StandardCharsets.UTF_8.name()); - String body = FormUtils.readBody(m.getContent(InputStream.class), enc); + String body = FormUtils.readBody(m.getContent(InputStream.class), enc, + FormUtils.getMaxFormParamsSize(m)); FormUtils.populateMapFromString(formParams, m, body, enc, true); } } diff --git a/rt/frontend/jaxrs/src/main/java/org/apache/cxf/jaxrs/utils/FormUtils.java b/rt/frontend/jaxrs/src/main/java/org/apache/cxf/jaxrs/utils/FormUtils.java index a360717c664..f2dbb71c160 100644 --- a/rt/frontend/jaxrs/src/main/java/org/apache/cxf/jaxrs/utils/FormUtils.java +++ b/rt/frontend/jaxrs/src/main/java/org/apache/cxf/jaxrs/utils/FormUtils.java @@ -67,6 +67,7 @@ public final class FormUtils { private static final Logger LOG = LogUtils.getL7dLogger(FormUtils.class); private static final String MULTIPART_FORM_DATA_TYPE = "form-data"; private static final String MAX_FORM_PARAM_COUNT = "maxFormParameterCount"; + private static final String MAX_FORM_PARAM_SIZE = "maxFormParameterSize"; private static final String CONTENT_DISPOSITION_FILES_PARAM = "files"; private FormUtils() { @@ -316,4 +317,8 @@ public final class FormUtils { return MediaType.APPLICATION_FORM_URLENCODED.equals(m.get(Message.CONTENT_TYPE)) && HttpMethod.POST.equals(m.get(Message.HTTP_REQUEST_METHOD)); } + + public static int getMaxFormParamsSize(Message m) { + return MessageUtils.getContextualInteger(m, MAX_FORM_PARAM_SIZE, DEFAULT_FORM_PARAMS_MAX_SIZE); + } } diff --git a/rt/frontend/jaxrs/src/main/java/org/apache/cxf/jaxrs/utils/JAXRSUtils.java b/rt/frontend/jaxrs/src/main/java/org/apache/cxf/jaxrs/utils/JAXRSUtils.java index 3307d54b332..8a59b27cb12 100644 --- a/rt/frontend/jaxrs/src/main/java/org/apache/cxf/jaxrs/utils/JAXRSUtils.java +++ b/rt/frontend/jaxrs/src/main/java/org/apache/cxf/jaxrs/utils/JAXRSUtils.java @@ -1195,7 +1195,7 @@ public final class JAXRSUtils { if (mt == null || mt.isCompatible(MediaType.APPLICATION_FORM_URLENCODED_TYPE)) { InputStream entityStream = copyAndGetEntityStream(m); - String body = FormUtils.readBody(entityStream, enc); + String body = FormUtils.readBody(entityStream, enc, FormUtils.getMaxFormParamsSize(m)); // Do not decode unless the key is empty value, fe @FormParam("") FormUtils.populateMapFromStringOrHttpRequest(params, m, body, enc, StringUtils.isEmpty(key) && decode); } else { diff --git a/rt/rs/security/oauth-parent/oauth2/src/main/java/org/apache/cxf/rs/security/oauth2/client/ClientCodeRequestFilter.java b/rt/rs/security/oauth-parent/oauth2/src/main/java/org/apache/cxf/rs/security/oauth2/client/ClientCodeRequestFilter.java index f3261f26196..168747f7ec4 100644 --- a/rt/rs/security/oauth-parent/oauth2/src/main/java/org/apache/cxf/rs/security/oauth2/client/ClientCodeRequestFilter.java +++ b/rt/rs/security/oauth-parent/oauth2/src/main/java/org/apache/cxf/rs/security/oauth2/client/ClientCodeRequestFilter.java @@ -45,6 +45,7 @@ import org.apache.cxf.jaxrs.impl.MetadataMap; import org.apache.cxf.jaxrs.utils.ExceptionUtils; import org.apache.cxf.jaxrs.utils.FormUtils; import org.apache.cxf.jaxrs.utils.JAXRSUtils; +import org.apache.cxf.message.Message; import org.apache.cxf.rs.security.oauth2.common.ClientAccessToken; import org.apache.cxf.rs.security.oauth2.grants.code.AuthorizationCodeGrant; import org.apache.cxf.rs.security.oauth2.grants.code.CodeVerifierTransformer; @@ -312,8 +313,10 @@ public class ClientCodeRequestFilter implements ContainerRequestFilter { MultivaluedMap<String, String> requestState = new MetadataMap<>(); requestState.putAll(ui.getQueryParameters(decodeRequestParameters)); if (MediaType.APPLICATION_FORM_URLENCODED_TYPE.isCompatible(rc.getMediaType())) { - String body = FormUtils.readBody(rc.getEntityStream(), StandardCharsets.UTF_8.name()); - FormUtils.populateMapFromString(requestState, JAXRSUtils.getCurrentMessage(), body, + final Message currentMessage = JAXRSUtils.getCurrentMessage(); + String body = FormUtils.readBody(rc.getEntityStream(), StandardCharsets.UTF_8.name(), + FormUtils.getMaxFormParamsSize(currentMessage)); + FormUtils.populateMapFromString(requestState, currentMessage, body, StandardCharsets.UTF_8.name(), decodeRequestParameters); } return requestState; diff --git a/rt/rs/security/sso/oidc/src/main/java/org/apache/cxf/rs/security/oidc/rp/OidcIdTokenRequestFilter.java b/rt/rs/security/sso/oidc/src/main/java/org/apache/cxf/rs/security/oidc/rp/OidcIdTokenRequestFilter.java index 04126ce9614..123cb5b5c8b 100644 --- a/rt/rs/security/sso/oidc/src/main/java/org/apache/cxf/rs/security/oidc/rp/OidcIdTokenRequestFilter.java +++ b/rt/rs/security/sso/oidc/src/main/java/org/apache/cxf/rs/security/oidc/rp/OidcIdTokenRequestFilter.java @@ -32,6 +32,7 @@ import org.apache.cxf.common.util.StringUtils; import org.apache.cxf.jaxrs.impl.MetadataMap; import org.apache.cxf.jaxrs.utils.FormUtils; import org.apache.cxf.jaxrs.utils.JAXRSUtils; +import org.apache.cxf.message.Message; import org.apache.cxf.rs.security.oauth2.client.Consumer; import org.apache.cxf.rs.security.oidc.common.IdToken; @@ -61,8 +62,10 @@ public class OidcIdTokenRequestFilter implements ContainerRequestFilter { private MultivaluedMap<String, String> toFormData(ContainerRequestContext rc) { MultivaluedMap<String, String> requestState = new MetadataMap<>(); if (MediaType.APPLICATION_FORM_URLENCODED_TYPE.isCompatible(rc.getMediaType())) { - String body = FormUtils.readBody(rc.getEntityStream(), StandardCharsets.UTF_8.name()); - FormUtils.populateMapFromString(requestState, JAXRSUtils.getCurrentMessage(), body, + final Message currentMessage = JAXRSUtils.getCurrentMessage(); + String body = FormUtils.readBody(rc.getEntityStream(), StandardCharsets.UTF_8.name(), + FormUtils.getMaxFormParamsSize(currentMessage)); + FormUtils.populateMapFromString(requestState, currentMessage, body, StandardCharsets.UTF_8.name(), false); rc.setEntityStream(new ByteArrayInputStream(StringUtils.toBytesUTF8(body))); } diff --git a/rt/rs/security/sso/oidc/src/main/java/org/apache/cxf/rs/security/oidc/rp/OidcRpAuthenticationFilter.java b/rt/rs/security/sso/oidc/src/main/java/org/apache/cxf/rs/security/oidc/rp/OidcRpAuthenticationFilter.java index 28579c9645e..f9b443a048a 100644 --- a/rt/rs/security/sso/oidc/src/main/java/org/apache/cxf/rs/security/oidc/rp/OidcRpAuthenticationFilter.java +++ b/rt/rs/security/sso/oidc/src/main/java/org/apache/cxf/rs/security/oidc/rp/OidcRpAuthenticationFilter.java @@ -40,6 +40,7 @@ import org.apache.cxf.jaxrs.ext.MessageContextImpl; import org.apache.cxf.jaxrs.impl.MetadataMap; import org.apache.cxf.jaxrs.utils.FormUtils; import org.apache.cxf.jaxrs.utils.JAXRSUtils; +import org.apache.cxf.message.Message; import org.apache.cxf.rs.security.jose.jwt.JwtException; import org.apache.cxf.rs.security.jose.jwt.JwtUtils; import org.apache.cxf.rs.security.oauth2.client.ClientTokenContext; @@ -115,8 +116,10 @@ public class OidcRpAuthenticationFilter implements ContainerRequestFilter { MultivaluedMap<String, String> requestState = new MetadataMap<>(); requestState.putAll(rc.getUriInfo().getQueryParameters(true)); if (MediaType.APPLICATION_FORM_URLENCODED_TYPE.isCompatible(rc.getMediaType())) { - String body = FormUtils.readBody(rc.getEntityStream(), StandardCharsets.UTF_8.name()); - FormUtils.populateMapFromString(requestState, JAXRSUtils.getCurrentMessage(), body, + final Message currentMessage = JAXRSUtils.getCurrentMessage(); + String body = FormUtils.readBody(rc.getEntityStream(), StandardCharsets.UTF_8.name(), + FormUtils.getMaxFormParamsSize(currentMessage)); + FormUtils.populateMapFromString(requestState, currentMessage, body, StandardCharsets.UTF_8.name(), true); rc.setEntityStream(new ByteArrayInputStream(StringUtils.toBytesUTF8(body))); diff --git a/systests/jaxrs/src/test/java/org/apache/cxf/systest/jaxrs/JAXRSClientServerBookTest.java b/systests/jaxrs/src/test/java/org/apache/cxf/systest/jaxrs/JAXRSClientServerBookTest.java index 11c9d35c11e..a676202a52c 100644 --- a/systests/jaxrs/src/test/java/org/apache/cxf/systest/jaxrs/JAXRSClientServerBookTest.java +++ b/systests/jaxrs/src/test/java/org/apache/cxf/systest/jaxrs/JAXRSClientServerBookTest.java @@ -352,6 +352,17 @@ public class JAXRSClientServerBookTest extends AbstractBusClientServerTestBase { assertThat("max form params limit reached", r.getStatus(), equalTo(413)); } + @Test + public void testTooManyFormParamsUsingForm() throws Exception { + // Exceeding 500 limit + String params = IntStream.range(0, 501).mapToObj(i -> "id" + i + "=" + i).collect(Collectors.joining("&")); + String address = "http://localhost:" + PORT + "/bookstore/formParams/1"; + WebClient wc = WebClient.create(address); + wc.type(MediaType.APPLICATION_FORM_URLENCODED); + Response r = wc.post(new ByteArrayInputStream(params.getBytes(StandardCharsets.UTF_8))); + assertThat("max form params limit reached", r.getStatus(), equalTo(413)); + } + @Test public void testTooLargeFormParams() throws Exception { // Exceeding 100Mb limit @@ -365,6 +376,19 @@ public class JAXRSClientServerBookTest extends AbstractBusClientServerTestBase { assertThat("max form params limit reached", r.getStatus(), equalTo(500)); } + @Test + public void testTooLargeFormParamsUsingForm() throws Exception { + // Exceeding 100Mb limit + String params = IntStream.range(0, 150) + .mapToObj(i -> "id" + i + "=" + + new String(Integer.toString(i)).repeat(524800)).collect(Collectors.joining("&")); + String address = "http://localhost:" + PORT + "/bookstore/formParams/1"; + WebClient wc = WebClient.create(address); + wc.type(MediaType.APPLICATION_FORM_URLENCODED); + Response r = wc.post(new ByteArrayInputStream(params.getBytes(StandardCharsets.UTF_8))); + assertThat("max form params limit reached", r.getStatus(), equalTo(500)); + } + @Test public void testGetBookDescriptionHttpResponse() throws Exception { String address = "http://localhost:" + PORT + "/bookstore/httpresponse";
