This is an automated email from the ASF dual-hosted git repository. coheigea pushed a commit to branch 3.2.x-fixes in repository https://gitbox.apache.org/repos/asf/cxf.git
commit 44473b051ea3b0ea11666070f50c16f018d9fa7d Author: Colm O hEigeartaigh <cohei...@apache.org> AuthorDate: Tue Sep 3 15:45:20 2019 +0100 Restrict the number of message attachments (cherry picked from commit 6c3990144b56097502aa9f3ec9c06f3031109022) (cherry picked from commit fd85803a73ad46f36816bcb55ed1c4f4b4c4312d) # Conflicts: # core/src/test/java/org/apache/cxf/attachment/AttachmentDeserializerTest.java --- .../cxf/attachment/AttachmentDeserializer.java | 17 ++- .../cxf/attachment/LazyAttachmentCollection.java | 9 +- .../cxf/attachment/AttachmentDeserializerTest.java | 116 +++++++++++++++++---- 3 files changed, 121 insertions(+), 21 deletions(-) diff --git a/core/src/main/java/org/apache/cxf/attachment/AttachmentDeserializer.java b/core/src/main/java/org/apache/cxf/attachment/AttachmentDeserializer.java index 7f46ec5..784bc3e 100644 --- a/core/src/main/java/org/apache/cxf/attachment/AttachmentDeserializer.java +++ b/core/src/main/java/org/apache/cxf/attachment/AttachmentDeserializer.java @@ -54,6 +54,11 @@ public class AttachmentDeserializer { public static final String ATTACHMENT_MAX_SIZE = "attachment-max-size"; /** + * The maximum number of attachments permitted in a message. The default is 50. + */ + public static final String ATTACHMENT_MAX_COUNT = "attachment-max-count"; + + /** * The maximum MIME Header Length. The default is 300. */ public static final String ATTACHMENT_MAX_HEADER_SIZE = "attachment-max-header-size"; @@ -109,7 +114,17 @@ public class AttachmentDeserializer { public void initializeAttachments() throws IOException { initializeRootMessage(); - attachments = new LazyAttachmentCollection(this); + Object maxCountProperty = message.getContextualProperty(AttachmentDeserializer.ATTACHMENT_MAX_COUNT); + int maxCount = 50; + if (maxCountProperty != null) { + if (maxCountProperty instanceof Integer) { + maxCount = (Integer)maxCountProperty; + } else { + maxCount = Integer.parseInt((String)maxCountProperty); + } + } + + attachments = new LazyAttachmentCollection(this, maxCount); message.setAttachments(attachments); } diff --git a/core/src/main/java/org/apache/cxf/attachment/LazyAttachmentCollection.java b/core/src/main/java/org/apache/cxf/attachment/LazyAttachmentCollection.java index c44ea21..d866029 100644 --- a/core/src/main/java/org/apache/cxf/attachment/LazyAttachmentCollection.java +++ b/core/src/main/java/org/apache/cxf/attachment/LazyAttachmentCollection.java @@ -37,10 +37,12 @@ public class LazyAttachmentCollection private AttachmentDeserializer deserializer; private final List<Attachment> attachments = new ArrayList<>(); + private final int maxAttachmentCount; - public LazyAttachmentCollection(AttachmentDeserializer deserializer) { + public LazyAttachmentCollection(AttachmentDeserializer deserializer, int maxAttachmentCount) { super(); this.deserializer = deserializer; + this.maxAttachmentCount = maxAttachmentCount; } public List<Attachment> getLoadedAttachments() { @@ -50,8 +52,13 @@ public class LazyAttachmentCollection private void loadAll() { try { Attachment a = deserializer.readNext(); + int count = 0; while (a != null) { attachments.add(a); + count++; + if (count > maxAttachmentCount) { + throw new IOException("The message contains more attachments than are permitted"); + } a = deserializer.readNext(); } } catch (IOException e) { diff --git a/core/src/test/java/org/apache/cxf/attachment/AttachmentDeserializerTest.java b/core/src/test/java/org/apache/cxf/attachment/AttachmentDeserializerTest.java index 51eb3b5..871ce3c 100644 --- a/core/src/test/java/org/apache/cxf/attachment/AttachmentDeserializerTest.java +++ b/core/src/test/java/org/apache/cxf/attachment/AttachmentDeserializerTest.java @@ -20,7 +20,6 @@ package org.apache.cxf.attachment; import java.io.ByteArrayInputStream; import java.io.ByteArrayOutputStream; -import java.io.IOException; import java.io.InputStream; import java.io.PushbackInputStream; import java.nio.charset.StandardCharsets; @@ -31,6 +30,7 @@ import java.util.Iterator; import java.util.List; import java.util.regex.Matcher; import java.util.regex.Pattern; +import java.util.stream.IntStream; import javax.activation.DataSource; import javax.xml.parsers.SAXParser; @@ -50,7 +50,13 @@ import org.junit.Assert; import org.junit.Before; import org.junit.Test; -public class AttachmentDeserializerTest extends Assert { +import static org.junit.Assert.assertEquals; +import static org.junit.Assert.assertFalse; +import static org.junit.Assert.assertNotNull; +import static org.junit.Assert.assertTrue; +import static org.junit.Assert.fail; + +public class AttachmentDeserializerTest { private MessageImpl msg; @@ -465,32 +471,17 @@ public class AttachmentDeserializerTest extends Assert { ad.initializeAttachments(); - String s = getString(message.getContent(InputStream.class)); + String s = IOUtils.toString(message.getContent(InputStream.class)); assertEquals("JJJJ", s.trim()); int count = 1; for (Attachment a : message.getAttachments()) { - s = getString(a.getDataHandler().getInputStream()); + s = IOUtils.toString(a.getDataHandler().getInputStream()); assertEquals("ABCD" + count++, s); } in.close(); } - private String getString(InputStream ins) throws Exception { - try (ByteArrayOutputStream bout = new ByteArrayOutputStream(100)) { - byte b[] = new byte[100]; - int i = ins.read(b); - while (i > 0) { - bout.write(b, 0, i); - i = ins.read(b); - } - if (i == 0) { - throw new IOException("Should not be 0"); - } - return bout.toString(); - } - } - @Test public void testCXF3383() throws Exception { String contentType = "multipart/related; type=\"application/xop+xml\";" @@ -676,5 +667,92 @@ public class AttachmentDeserializerTest extends Assert { assertEquals(-1, ins.read(new byte[1000], 100, 600)); ins.close(); } + + @Test + public void testManyAttachments() throws Exception { + StringBuilder sb = new StringBuilder(1000); + sb.append("SomeHeader: foo\n") + .append("------=_Part_34950_1098328613.1263781527359\n") + .append("Content-Type: text/xml; charset=UTF-8\n") + .append("Content-Transfer-Encoding: binary\n") + .append("Content-Id: <318731183421.1263781527359.IBM.WEBSERVICES@auhpap02>\n") + .append('\n') + .append("<envelope/>\n"); + + // Add many attachments + IntStream.range(0, 100000).forEach(i -> { + sb.append("------=_Part_34950_1098328613.1263781527359\n") + .append("Content-Type: text/xml\n") + .append("Content-Transfer-Encoding: binary\n") + .append("Content-Id: <b86a5f2d-e7af-4e5e-b71a-9f6f2307cab0>\n") + .append('\n') + .append("<message>\n") + .append("------=_Part_34950_1098328613.1263781527359--\n"); + }); + + msg = new MessageImpl(); + msg.setContent(InputStream.class, new ByteArrayInputStream(sb.toString().getBytes(StandardCharsets.UTF_8))); + msg.put(Message.CONTENT_TYPE, "multipart/related"); + AttachmentDeserializer ad = new AttachmentDeserializer(msg); + ad.initializeAttachments(); + + // Force it to load the attachments + try { + msg.getAttachments().size(); + fail("Failure expected on too many attachments"); + } catch (RuntimeException ex) { + // expected + } + } + + @Test + public void testChangingMaxAttachmentCount() throws Exception { + StringBuilder sb = new StringBuilder(1000); + sb.append("SomeHeader: foo\n") + .append("------=_Part_34950_1098328613.1263781527359\n") + .append("Content-Type: text/xml; charset=UTF-8\n") + .append("Content-Transfer-Encoding: binary\n") + .append("Content-Id: <318731183421.1263781527359.IBM.WEBSERVICES@auhpap02>\n") + .append('\n') + .append("<envelope/>\n"); + + // Add many attachments + IntStream.range(0, 40).forEach(i -> { + sb.append("------=_Part_34950_1098328613.1263781527359\n") + .append("Content-Type: text/xml\n") + .append("Content-Transfer-Encoding: binary\n") + .append("Content-Id: <b86a5f2d-e7af-4e5e-b71a-9f6f2307cab0>\n") + .append('\n') + .append("<message>\n") + .append("------=_Part_34950_1098328613.1263781527359--\n"); + }); + + msg = new MessageImpl(); + msg.put(AttachmentDeserializer.ATTACHMENT_MAX_COUNT, "30"); + msg.setContent(InputStream.class, new ByteArrayInputStream(sb.toString().getBytes(StandardCharsets.UTF_8))); + msg.put(Message.CONTENT_TYPE, "multipart/related"); + AttachmentDeserializer ad = new AttachmentDeserializer(msg); + ad.initializeAttachments(); + + // Force it to load the attachments + try { + msg.getAttachments().size(); + fail("Failure expected on too many attachments"); + } catch (RuntimeException ex) { + // expected + } + + // Now we'll allow it + msg = new MessageImpl(); + msg.put(AttachmentDeserializer.ATTACHMENT_MAX_COUNT, "60"); + msg.setContent(InputStream.class, new ByteArrayInputStream(sb.toString().getBytes(StandardCharsets.UTF_8))); + msg.put(Message.CONTENT_TYPE, "multipart/related"); + ad = new AttachmentDeserializer(msg); + ad.initializeAttachments(); + + // Force it to load the attachments + assertEquals(40, msg.getAttachments().size()); + } + }