Merge pull request #1 from exabrial/TRIBESTRM_3972_CVE_2016_8739 [Tribestrm-3972] cve-2016-8739
Project: http://git-wip-us.apache.org/repos/asf/cxf/repo Commit: http://git-wip-us.apache.org/repos/asf/cxf/commit/73963a76 Tree: http://git-wip-us.apache.org/repos/asf/cxf/tree/73963a76 Diff: http://git-wip-us.apache.org/repos/asf/cxf/diff/73963a76 Branch: refs/heads/2.6.x-fixes Commit: 73963a760286eeacc425f4cd366b7dd8dbf20795 Parents: 6caf791 Author: Tod Bookless <tbookl...@tomitribe.com> Authored: Thu Jun 1 10:26:13 2017 -0700 Committer: Jonathan S. Fisher <jfis...@tomitribe.com> Committed: Wed Jun 7 15:11:55 2017 -0500 ---------------------------------------------------------------------- .../provider/atom/AbstractAtomProvider.java | 21 +- .../jaxrs/provider/atom/AtomPojoProvider.java | 38 ++-- .../provider/atom/AtomPojoProviderTest.java | 202 ++++++++++++++----- 3 files changed, 187 insertions(+), 74 deletions(-) ---------------------------------------------------------------------- http://git-wip-us.apache.org/repos/asf/cxf/blob/73963a76/rt/rs/extensions/providers/src/main/java/org/apache/cxf/jaxrs/provider/atom/AbstractAtomProvider.java ---------------------------------------------------------------------- diff --git a/rt/rs/extensions/providers/src/main/java/org/apache/cxf/jaxrs/provider/atom/AbstractAtomProvider.java b/rt/rs/extensions/providers/src/main/java/org/apache/cxf/jaxrs/provider/atom/AbstractAtomProvider.java index ba65698..203e6ed 100644 --- a/rt/rs/extensions/providers/src/main/java/org/apache/cxf/jaxrs/provider/atom/AbstractAtomProvider.java +++ b/rt/rs/extensions/providers/src/main/java/org/apache/cxf/jaxrs/provider/atom/AbstractAtomProvider.java @@ -31,6 +31,7 @@ import javax.ws.rs.core.MediaType; import javax.ws.rs.core.MultivaluedMap; import javax.ws.rs.ext.MessageBodyReader; import javax.ws.rs.ext.MessageBodyWriter; +import javax.xml.stream.XMLStreamReader; import org.apache.abdera.Abdera; import org.apache.abdera.model.Document; @@ -39,28 +40,29 @@ import org.apache.abdera.parser.Parser; import org.apache.abdera.parser.ParserOptions; import org.apache.abdera.writer.Writer; import org.apache.cxf.common.logging.LogUtils; +import org.apache.cxf.staxutils.StaxUtils; -public abstract class AbstractAtomProvider<T extends Element> +public abstract class AbstractAtomProvider<T extends Element> implements MessageBodyWriter<T>, MessageBodyReader<T> { private static final Logger LOG = LogUtils.getL7dLogger(AbstractAtomProvider.class); private static final Abdera ATOM_ENGINE = new Abdera(); private boolean autodetectCharset; private boolean formattedOutput; - + public long getSize(T element, Class<?> type, Type genericType, Annotation[] annotations, MediaType mt) { return -1; } - public void writeTo(T element, Class<?> clazz, Type type, Annotation[] a, - MediaType mt, MultivaluedMap<String, Object> headers, OutputStream os) + public void writeTo(T element, Class<?> clazz, Type type, Annotation[] a, + MediaType mt, MultivaluedMap<String, Object> headers, OutputStream os) throws IOException { if (MediaType.APPLICATION_JSON_TYPE.isCompatible(mt)) { Writer w = createWriter("json"); if (w == null) { throw new WebApplicationException(415); } - element.writeTo(w, os); + element.writeTo(w, os); } else if (formattedOutput) { Writer w = createWriter("prettyxml"); if (w != null) { @@ -80,9 +82,9 @@ public abstract class AbstractAtomProvider<T extends Element> } return w; } - - public T readFrom(Class<T> clazz, Type t, Annotation[] a, MediaType mt, - MultivaluedMap<String, String> headers, InputStream is) + + public T readFrom(Class<T> clazz, Type t, Annotation[] a, MediaType mt, + MultivaluedMap<String, String> headers, InputStream is) throws IOException { Parser parser = ATOM_ENGINE.getParser(); synchronized (parser) { @@ -91,7 +93,8 @@ public abstract class AbstractAtomProvider<T extends Element> options.setAutodetectCharset(autodetectCharset); } } - Document<T> doc = parser.parse(is); + XMLStreamReader reader = StaxUtils.createXMLStreamReader(is); + Document<T> doc = parser.parse(reader); return doc.getRoot(); } http://git-wip-us.apache.org/repos/asf/cxf/blob/73963a76/rt/rs/extensions/providers/src/main/java/org/apache/cxf/jaxrs/provider/atom/AtomPojoProvider.java ---------------------------------------------------------------------- diff --git a/rt/rs/extensions/providers/src/main/java/org/apache/cxf/jaxrs/provider/atom/AtomPojoProvider.java b/rt/rs/extensions/providers/src/main/java/org/apache/cxf/jaxrs/provider/atom/AtomPojoProvider.java index bfb5a78..dcb870b 100644 --- a/rt/rs/extensions/providers/src/main/java/org/apache/cxf/jaxrs/provider/atom/AtomPojoProvider.java +++ b/rt/rs/extensions/providers/src/main/java/org/apache/cxf/jaxrs/provider/atom/AtomPojoProvider.java @@ -558,8 +558,8 @@ public class AtomPojoProvider extends AbstractConfigurableProvider reportError(message, ex, 500); } - private boolean isFeedRequested(MediaType mt) { - if ("entry".equals(mt.getParameters().get("type"))) { + protected boolean isFeedRequested(MediaType mt) { + if ("entry".equalsIgnoreCase(mt.getParameters().get("type"))) { return false; } return true; @@ -600,25 +600,29 @@ public class AtomPojoProvider extends AbstractConfigurableProvider boolean isFeed = isFeedRequested(mt); if (isFeed) { - return readFromFeed(cls, mt, headers, is); + return readFromFeedOrEntry(cls, mt, headers, is); } else { AtomEntryProvider p = new AtomEntryProvider(); p.setAutodetectCharset(autodetectCharset); Entry entry = p.readFrom(Entry.class, Entry.class, new Annotation[]{}, mt, headers, is); - return readFromEntry(entry, cls, mt, headers, is); + return readFromEntry(entry, cls); } } @SuppressWarnings("unchecked") - private Object readFromFeed(Class<Object> cls, MediaType mt, + private Object readFromFeedOrEntry(Class<Object> cls, MediaType mt, MultivaluedMap<String, String> headers, InputStream is) throws IOException { AtomFeedProvider p = new AtomFeedProvider(); p.setAutodetectCharset(autodetectCharset); - Feed feed = p.readFrom(Feed.class, Feed.class, new Annotation[]{}, mt, headers, is); - + Object atomObject = p.readFrom(Feed.class, Feed.class, new Annotation[]{}, mt, headers, is); + if (atomObject instanceof Entry) { + return this.readFromEntry((Entry)atomObject, cls); + } + + Feed feed = (Feed)atomObject; AtomElementReader<?, ?> reader = getAtomReader(cls); if (reader != null) { return ((AtomElementReader<Feed, Object>)reader).readFrom(feed); @@ -631,7 +635,7 @@ public class AtomPojoProvider extends AbstractConfigurableProvider = (Class<Object>)InjectionUtils.getActualType(m.getGenericParameterTypes()[0]); List<Object> objects = new ArrayList<Object>(); for (Entry e : feed.getEntries()) { - objects.add(readFromEntry(e, realCls, mt, headers, is)); + objects.add(readFromEntry(e, realCls)); } instance = cls.newInstance(); m.invoke(instance, new Object[]{objects}); @@ -643,20 +647,22 @@ public class AtomPojoProvider extends AbstractConfigurableProvider } @SuppressWarnings("unchecked") - private Object readFromEntry(Entry entry, Class<Object> cls, MediaType mt, - MultivaluedMap<String, String> headers, InputStream is) + private Object readFromEntry(Entry entry, Class<Object> cls) throws IOException { AtomElementReader<?, ?> reader = getAtomReader(cls); if (reader != null) { return ((AtomElementReader<Entry, Object>)reader).readFrom(entry); } - try { - Unmarshaller um = - jaxbProvider.getJAXBContext(cls, cls).createUnmarshaller(); - return cls.cast(um.unmarshal(new StringReader(entry.getContent()))); - } catch (Exception ex) { - reportError("Object of type " + cls.getName() + " can not be deserialized from Entry", ex, 400); + String entryContent = entry.getContent(); + if (entryContent != null) { + try { + Unmarshaller um = + jaxbProvider.getJAXBContext(cls, cls).createUnmarshaller(); + return cls.cast(um.unmarshal(new StringReader(entryContent))); + } catch (Exception ex) { + reportError("Object of type " + cls.getName() + " can not be deserialized from Entry", ex, 400); + } } return null; } http://git-wip-us.apache.org/repos/asf/cxf/blob/73963a76/rt/rs/extensions/providers/src/test/java/org/apache/cxf/jaxrs/provider/atom/AtomPojoProviderTest.java ---------------------------------------------------------------------- diff --git a/rt/rs/extensions/providers/src/test/java/org/apache/cxf/jaxrs/provider/atom/AtomPojoProviderTest.java b/rt/rs/extensions/providers/src/test/java/org/apache/cxf/jaxrs/provider/atom/AtomPojoProviderTest.java index b214ae9..1d0fb79 100644 --- a/rt/rs/extensions/providers/src/test/java/org/apache/cxf/jaxrs/provider/atom/AtomPojoProviderTest.java +++ b/rt/rs/extensions/providers/src/test/java/org/apache/cxf/jaxrs/provider/atom/AtomPojoProviderTest.java @@ -22,6 +22,7 @@ import java.io.ByteArrayInputStream; import java.io.ByteArrayOutputStream; import java.io.StringReader; import java.lang.annotation.Annotation; +import java.nio.charset.Charset; import java.util.ArrayList; import java.util.List; @@ -31,6 +32,7 @@ import javax.xml.bind.annotation.XmlRootElement; import org.apache.abdera.model.Entry; import org.apache.abdera.model.Feed; +import org.apache.cxf.jaxrs.impl.MetadataMap; import org.apache.cxf.jaxrs.provider.JAXBElementProvider; import org.junit.Assert; @@ -39,25 +41,24 @@ import org.junit.Test; import org.springframework.context.support.ClassPathXmlApplicationContext; - public class AtomPojoProviderTest extends Assert { private ClassPathXmlApplicationContext ctx; - + @Before public void setUp() { - ctx = + ctx = new ClassPathXmlApplicationContext( new String[] {"/org/apache/cxf/jaxrs/provider/atom/servers.xml"}); } - + @Test public void testWriteFeedWithBuilders() throws Exception { AtomPojoProvider provider = (AtomPojoProvider)ctx.getBean("atom"); assertNotNull(provider); provider.setFormattedOutput(true); ByteArrayOutputStream bos = new ByteArrayOutputStream(); - + Books books = new Books(); List<Book> bs = new ArrayList<Book>(); bs.add(new Book("a")); @@ -67,20 +68,20 @@ public class AtomPojoProviderTest extends Assert { MediaType.valueOf("application/atom+xml"), null, bos); ByteArrayInputStream bis = new ByteArrayInputStream(bos.toByteArray()); Feed feed = new AtomFeedProvider().readFrom(Feed.class, null, null, null, null, bis); - assertEquals("Books", feed.getTitle()); + assertEquals("Books", feed.getTitle()); List<Entry> entries = feed.getEntries(); assertEquals(2, entries.size()); verifyEntry(getEntry(entries, "a"), "a"); verifyEntry(getEntry(entries, "b"), "b"); } - + @Test public void testWriteFeedWithBuildersNoJaxb() throws Exception { AtomPojoProvider provider = (AtomPojoProvider)ctx.getBean("atomNoJaxb"); assertNotNull(provider); provider.setFormattedOutput(true); ByteArrayOutputStream bos = new ByteArrayOutputStream(); - + Books books = new Books(); List<Book> bs = new ArrayList<Book>(); bs.add(new Book("a")); @@ -90,23 +91,23 @@ public class AtomPojoProviderTest extends Assert { MediaType.valueOf("application/atom+xml"), null, bos); ByteArrayInputStream bis = new ByteArrayInputStream(bos.toByteArray()); Feed feed = new AtomFeedProvider().readFrom(Feed.class, null, null, null, null, bis); - assertEquals("Books", feed.getTitle()); + assertEquals("Books", feed.getTitle()); List<Entry> entries = feed.getEntries(); assertEquals(2, entries.size()); - + Entry entryA = getEntry(entries, "a"); verifyEntry(entryA, "a"); String entryAContent = entryA.getContent(); assertTrue("<a/>".equals(entryAContent) || "<a><a/>".equals(entryAContent) || "<a xmlns=\"\"/>".equals(entryAContent)); - + Entry entryB = getEntry(entries, "b"); verifyEntry(entryB, "b"); String entryBContent = entryB.getContent(); assertTrue("<b/>".equals(entryBContent) || "<b><b/>".equals(entryBContent) || "<b xmlns=\"\"/>".equals(entryBContent)); } - + @Test public void testWriteEntryWithBuilders() throws Exception { AtomPojoProvider provider = (AtomPojoProvider)ctx.getBean("atom2"); @@ -118,21 +119,21 @@ public class AtomPojoProviderTest extends Assert { ByteArrayInputStream bis = new ByteArrayInputStream(bos.toByteArray()); Entry entry = new AtomEntryProvider().readFrom(Entry.class, null, null, null, null, bis); verifyEntry(entry, "a"); - + } - + @Test public void testReadEntryWithBuilders() throws Exception { AtomPojoProvider provider = (AtomPojoProvider)ctx.getBean("atom3"); assertNotNull(provider); doTestReadEntry(provider); } - + @Test public void testReadEntryWithoutBuilders() throws Exception { doTestReadEntry(new AtomPojoProvider()); } - + private void doTestReadEntry(AtomPojoProvider provider) throws Exception { provider.setFormattedOutput(true); ByteArrayOutputStream bos = new ByteArrayOutputStream(); @@ -140,19 +141,38 @@ public class AtomPojoProviderTest extends Assert { provider.writeTo(new Book("a"), Book.class, Book.class, new Annotation[]{}, mt, null, bos); ByteArrayInputStream bis = new ByteArrayInputStream(bos.toByteArray()); @SuppressWarnings({"unchecked", "rawtypes" }) - Book book = (Book)provider.readFrom((Class)Book.class, Book.class, + Book book = (Book)provider.readFrom((Class)Book.class, Book.class, + new Annotation[]{}, mt, null, bis); + assertEquals("a", book.getName()); + } + @Test + public void testReadEntryNoBuilders2() throws Exception { + final String entry = + "<!DOCTYPE entry SYSTEM \"entry://entry\"><entry xmlns=\"http://www.w3.org/2005/Atom\">" + + "<title type=\"text\">a</title>" + + "<content type=\"application/xml\">" + + "<book xmlns=\"\">" + + "<name>a</name>" + + "</book>" + + "</content>" + + "</entry>"; + AtomPojoProvider provider = new AtomPojoProvider(); + ByteArrayInputStream bis = new ByteArrayInputStream(entry.getBytes()); + MediaType mt = MediaType.valueOf("application/atom+xml;type=entry"); + @SuppressWarnings({"unchecked", "rawtypes" }) + Book book = (Book)provider.readFrom((Class)Book.class, Book.class, new Annotation[]{}, mt, null, bis); assertEquals("a", book.getName()); } - - + + @Test public void testReadFeedWithBuilders() throws Exception { AtomPojoProvider provider = (AtomPojoProvider)ctx.getBean("atom4"); assertNotNull(provider); doTestReadFeed(provider); } - + @Test public void testReadFeedWithoutBuilders() throws Exception { AtomPojoProvider provider = new AtomPojoProvider(); @@ -170,14 +190,98 @@ public class AtomPojoProviderTest extends Assert { provider.writeTo(books, Books.class, Books.class, new Annotation[]{}, mt, null, bos); ByteArrayInputStream bis = new ByteArrayInputStream(bos.toByteArray()); @SuppressWarnings({"unchecked", "rawtypes" }) - Books books2 = (Books)provider.readFrom((Class)Books.class, Books.class, + Books books2 = (Books)provider.readFrom((Class)Books.class, Books.class, new Annotation[]{}, mt, null, bis); List<Book> list = books2.getBooks(); assertEquals(2, list.size()); assertTrue("a".equals(list.get(0).getName()) || "a".equals(list.get(1).getName())); - assertTrue("b".equals(list.get(0).getName()) || "b".equals(list.get(1).getName())); + assertTrue("b".equals(list.get(0).getName()) || "b".equals(list.get(1).getName())); + } + + @Test + public void testReadFeedWithoutBuilders2() throws Exception { + AtomPojoProvider provider = new AtomPojoProvider(); + final String feed = + "<!DOCTYPE feed SYSTEM \"feed://feed\"><feed xmlns=\"http://www.w3.org/2005/Atom\">" + + "<entry><content type=\"application/xml\"><book xmlns=\"\"><name>a</name></book></content></entry>" + + "<entry><content type=\"application/xml\"><book xmlns=\"\"><name>b</name></book></content></entry>" + + "</feed>"; + MediaType mt = MediaType.valueOf("application/atom+xml;type=feed"); + ByteArrayInputStream bis = new ByteArrayInputStream(feed.getBytes()); + @SuppressWarnings({"unchecked", "rawtypes" }) + Books books2 = (Books)provider.readFrom((Class)Books.class, Books.class, + new Annotation[]{}, mt, null, bis); + List<Book> list = books2.getBooks(); + assertEquals(2, list.size()); + assertTrue("a".equals(list.get(0).getName()) || "a".equals(list.get(1).getName())); + assertTrue("b".equals(list.get(0).getName()) || "b".equals(list.get(1).getName())); + } + + @Test + public void testReadEntryNoContent() throws Exception { + /** A sample entry without content. */ + final String entryNoContent = + "<?xml version='1.0' encoding='UTF-8'?>\n" + + "<entry xmlns=\"http://www.w3.org/2005/Atom\">\n" + + " <id>84297856</id>\n" + + "</entry>"; + + AtomPojoProvider atomPojoProvider = new AtomPojoProvider(); + @SuppressWarnings({ + "rawtypes", "unchecked" + }) + JaxbDataType type = (JaxbDataType)atomPojoProvider.readFrom((Class)JaxbDataType.class, + JaxbDataType.class, + new Annotation[0], + MediaType.valueOf("application/atom+xml;type=entry"), + new MetadataMap<String, String>(), + new ByteArrayInputStream(entryNoContent.getBytes(Charset.forName("UTF-8")))); + assertNull(type); + } + + @Test + public void testReadEntryWithUpperCaseTypeParam() throws Exception { + doReadEntryWithContent("application/atom+xml;type=ENTRY"); + } + + @Test + public void testReadEntryNoTypeParam() throws Exception { + doReadEntryWithContent("application/atom+xml"); } - + + private void doReadEntryWithContent(String mediaType) throws Exception { + final String entryWithContent = + "<?xml version='1.0' encoding='UTF-8'?>\n" + + "<entry xmlns=\"http://www.w3.org/2005/Atom\">\n" + + " <id>84297856</id>\n" + + " <content type=\"application/xml\">\n" + + " <jaxbDataType xmlns=\"\">\n" + + " </jaxbDataType>\n" + + " </content>\n" + + "</entry>"; + + AtomPojoProvider atomPojoProvider = new AtomPojoProvider(); + @SuppressWarnings({ + "rawtypes", "unchecked" + }) + JaxbDataType type = (JaxbDataType)atomPojoProvider.readFrom((Class)JaxbDataType.class, + JaxbDataType.class, + new Annotation[0], + MediaType.valueOf(mediaType), + new MetadataMap<String, String>(), + new ByteArrayInputStream(entryWithContent.getBytes(Charset.forName("UTF-8")))); + assertNotNull(type); + } + + /** + * A sample JAXB data-type to read data into. + */ + @XmlRootElement + public static class JaxbDataType { + // no data + } + + private Entry getEntry(List<Entry> entries, String title) { for (Entry e : entries) { if (title.equals(e.getTitle())) { @@ -186,35 +290,35 @@ public class AtomPojoProviderTest extends Assert { } return null; } - + private void verifyEntry(Entry e, String title) { assertNotNull(e); assertEquals(title, e.getTitle()); } - + public static class CustomFeedWriter implements AtomElementWriter<Feed, Books> { public void writeTo(Feed feed, Books pojoFeed) { feed.setTitle("Books"); } - + } - + public static class CustomEntryWriter implements AtomElementWriter<Entry, Book> { public void writeTo(Entry entry, Book pojoEntry) { entry.setTitle(pojoEntry.getName()); } - + } - + public static class CustomEntryReader implements AtomElementReader<Entry, Book> { public Book readFrom(Entry element) { try { String s = element.getContent(); - - Unmarshaller um = + + Unmarshaller um = new JAXBElementProvider<Book>().getJAXBContext(Book.class, Book.class) .createUnmarshaller(); return (Book)um.unmarshal(new StringReader(s)); @@ -223,9 +327,9 @@ public class AtomPojoProviderTest extends Assert { } return null; } - + } - + public static class CustomFeedReader implements AtomElementReader<Feed, Books> { public Books readFrom(Feed element) { @@ -238,36 +342,36 @@ public class AtomPojoProviderTest extends Assert { books.setBooks(list); return books; } - + } - + public static class CustomFeedBuilder extends AbstractFeedBuilder<Books> { @Override public String getBaseUri(Books books) { return "http://books"; } } - + public static class CustomEntryBuilder extends AbstractEntryBuilder<Book> { @Override public String getBaseUri(Book books) { return "http://book"; } } - - + + @XmlRootElement public static class Book { private String name = "Book"; public Book() { - + } - + public Book(String name) { this.name = name; } - + public void setName(String name) { this.name = name; } @@ -275,26 +379,26 @@ public class AtomPojoProviderTest extends Assert { public String getName() { return name; } - + public String getXMLContent() { return "<" + name + "/>"; } - + } - + @XmlRootElement public static class Books { - + private List<Book> books; - + public Books() { - + } - + public List<Book> getBooks() { return books; } - + public void setBooks(List<Book> list) { books = list; }