msrb pushed to springframework (f20). "Resolves: CVE-2014-0225"
notifications at fedoraproject.org
notifications at fedoraproject.org
Fri Apr 24 20:33:35 UTC 2015
>From d58174864c39aed04f6f913795758e06a580d889 Mon Sep 17 00:00:00 2001
From: Michal Srb <msrb at redhat.com>
Date: Fri, 24 Apr 2015 22:32:23 +0200
Subject: Resolves: CVE-2014-0225
diff --git a/springframework-3.1.4-Fix-CVE-2014-0225.patch b/springframework-3.1.4-Fix-CVE-2014-0225.patch
new file mode 100644
index 0000000..a14c3ae
--- /dev/null
+++ b/springframework-3.1.4-Fix-CVE-2014-0225.patch
@@ -0,0 +1,838 @@
+From 8cc22f2345ed8bcb1c3a3727db049448f77649d8 Mon Sep 17 00:00:00 2001
+From: Michal Srb <msrb at redhat.com>
+Date: Fri, 24 Apr 2015 22:01:13 +0200
+Subject: [PATCH] Fix CVE-2014-0225
+
+---
+ .../oxm/castor/CastorMarshaller.java | 5 +
+ .../springframework/oxm/jaxb/Jaxb2Marshaller.java | 71 ++++++
+ .../springframework/oxm/jibx/JibxMarshaller.java | 19 +-
+ .../oxm/support/AbstractMarshaller.java | 58 ++++-
+ .../oxm/xmlbeans/XmlBeansMarshaller.java | 4 +
+ .../oxm/xstream/XStreamMarshaller.java | 24 +-
+ .../xml/Jaxb2RootElementHttpMessageConverter.java | 54 +++++
+ .../converter/xml/SourceHttpMessageConverter.java | 251 +++++++++++++++++----
+ 8 files changed, 434 insertions(+), 52 deletions(-)
+
+diff --git a/org.springframework.oxm/src/main/java/org/springframework/oxm/castor/CastorMarshaller.java b/org.springframework.oxm/src/main/java/org/springframework/oxm/castor/CastorMarshaller.java
+index 6c2faa3..e9ffb1a 100644
+--- a/org.springframework.oxm/src/main/java/org/springframework/oxm/castor/CastorMarshaller.java
++++ b/org.springframework.oxm/src/main/java/org/springframework/oxm/castor/CastorMarshaller.java
+@@ -145,6 +145,11 @@ public class CastorMarshaller extends AbstractMarshaller implements Initializing
+ this.encoding = encoding;
+ }
+
++ @Override
++ protected String getDefaultEncoding() {
++ return this.encoding;
++ }
++
+ /**
+ * Set the locations of the Castor XML Mapping files.
+ */
+diff --git a/org.springframework.oxm/src/main/java/org/springframework/oxm/jaxb/Jaxb2Marshaller.java b/org.springframework.oxm/src/main/java/org/springframework/oxm/jaxb/Jaxb2Marshaller.java
+index a53bddf..eaa3dc4 100644
+--- a/org.springframework.oxm/src/main/java/org/springframework/oxm/jaxb/Jaxb2Marshaller.java
++++ b/org.springframework.oxm/src/main/java/org/springframework/oxm/jaxb/Jaxb2Marshaller.java
+@@ -21,6 +21,7 @@ import java.io.ByteArrayInputStream;
+ import java.io.IOException;
+ import java.io.InputStream;
+ import java.io.OutputStream;
++import java.io.StringReader;
+ import java.io.UnsupportedEncodingException;
+ import java.lang.reflect.GenericArrayType;
+ import java.lang.reflect.ParameterizedType;
+@@ -61,13 +62,16 @@ import javax.xml.stream.XMLStreamReader;
+ import javax.xml.stream.XMLStreamWriter;
+ import javax.xml.transform.Result;
+ import javax.xml.transform.Source;
++import javax.xml.transform.dom.DOMSource;
+ import javax.xml.transform.sax.SAXSource;
++import javax.xml.transform.stream.StreamSource;
+ import javax.xml.validation.Schema;
+ import javax.xml.validation.SchemaFactory;
+
+ import org.apache.commons.logging.Log;
+ import org.apache.commons.logging.LogFactory;
+ import org.w3c.dom.ls.LSResourceResolver;
++import org.xml.sax.EntityResolver;
+ import org.xml.sax.InputSource;
+ import org.xml.sax.SAXException;
+ import org.xml.sax.XMLReader;
+@@ -173,6 +177,7 @@ public class Jaxb2Marshaller
+
+ private Schema schema;
+
++ private boolean processExternalEntities = false;
+
+ /**
+ * Set multiple JAXB context paths. The given array of context paths is converted to a
+@@ -376,6 +381,26 @@ public class Jaxb2Marshaller
+ this.checkForXmlRootElement = checkForXmlRootElement;
+ }
+
++ /**
++ * Indicates whether external XML entities are processed when unmarshalling.
++ * <p>
++ * Default is {@code false}, meaning that external entities are not
++ * resolved. Note that processing of external entities will only be
++ * enabled/disabled when the {@code Source} passed to
++ * {@link #unmarshal(Source)} is a {@link SAXSource} or {@link StreamSource}
++ * . It has no effect for {@link DOMSource} or {@link StAXSource} instances.
++ */
++ public void setProcessExternalEntities(boolean processExternalEntities) {
++ this.processExternalEntities = processExternalEntities;
++ }
++
++ /**
++ * @return the configured value for whether XML external entities are allowed.
++ */
++ public boolean isProcessExternalEntities() {
++ return this.processExternalEntities;
++ }
++
+ public void setBeanClassLoader(ClassLoader classLoader) {
+ this.beanClassLoader = classLoader;
+ }
+@@ -699,6 +724,8 @@ public class Jaxb2Marshaller
+ }
+
+ public Object unmarshal(Source source, MimeContainer mimeContainer) throws XmlMappingException {
++ source = processSource(source);
++
+ try {
+ Unmarshaller unmarshaller = createUnmarshaller();
+ if (this.mtomEnabled && mimeContainer != null) {
+@@ -732,6 +759,43 @@ public class Jaxb2Marshaller
+ }
+ }
+
++ private Source processSource(Source source) {
++ if (StaxUtils.isStaxSource(source) || source instanceof DOMSource) {
++ return source;
++ }
++
++ XMLReader xmlReader = null;
++ InputSource inputSource = null;
++
++ if (source instanceof SAXSource) {
++ SAXSource saxSource = (SAXSource) source;
++ xmlReader = saxSource.getXMLReader();
++ inputSource = saxSource.getInputSource();
++ } else if (source instanceof StreamSource) {
++ StreamSource streamSource = (StreamSource) source;
++ if (streamSource.getInputStream() != null) {
++ inputSource = new InputSource(streamSource.getInputStream());
++ } else if (streamSource.getReader() != null) {
++ inputSource = new InputSource(streamSource.getReader());
++ }
++ }
++
++ try {
++ if (xmlReader == null) {
++ xmlReader = XMLReaderFactory.createXMLReader();
++ }
++ String name = "http://xml.org/sax/features/external-general-entities";
++ xmlReader.setFeature(name, isProcessExternalEntities());
++ if (!isProcessExternalEntities()) {
++ xmlReader.setEntityResolver(NO_OP_ENTITY_RESOLVER);
++ }
++ return new SAXSource(xmlReader, inputSource);
++ } catch (SAXException ex) {
++ logger.warn("Processing of external entities could not be disabled", ex);
++ return source;
++ }
++ }
++
+ /**
+ * Return a newly created JAXB unmarshaller.
+ * Note: JAXB unmarshallers are not necessarily thread-safe.
+@@ -932,4 +996,11 @@ public class Jaxb2Marshaller
+ }
+ }
+
++ private static final EntityResolver NO_OP_ENTITY_RESOLVER = new EntityResolver() {
++ @Override
++ public InputSource resolveEntity(String publicId, String systemId) {
++ return new InputSource(new StringReader(""));
++ }
++ };
++
+ }
+diff --git a/org.springframework.oxm/src/main/java/org/springframework/oxm/jibx/JibxMarshaller.java b/org.springframework.oxm/src/main/java/org/springframework/oxm/jibx/JibxMarshaller.java
+index f4e3336..f30b5e2 100644
+--- a/org.springframework.oxm/src/main/java/org/springframework/oxm/jibx/JibxMarshaller.java
++++ b/org.springframework.oxm/src/main/java/org/springframework/oxm/jibx/JibxMarshaller.java
+@@ -28,6 +28,7 @@ import javax.xml.stream.XMLEventWriter;
+ import javax.xml.stream.XMLStreamException;
+ import javax.xml.stream.XMLStreamReader;
+ import javax.xml.stream.XMLStreamWriter;
++import javax.xml.transform.OutputKeys;
+ import javax.xml.transform.Result;
+ import javax.xml.transform.Source;
+ import javax.xml.transform.Transformer;
+@@ -149,6 +150,11 @@ public class JibxMarshaller extends AbstractMarshaller implements InitializingBe
+ this.encoding = encoding;
+ }
+
++ @Override
++ protected String getDefaultEncoding() {
++ return this.encoding;
++ }
++
+ /**
+ * Set the document standalone flag for marshalling. By default, this flag is not present.
+ */
+@@ -331,7 +337,7 @@ public class JibxMarshaller extends AbstractMarshaller implements InitializingBe
+ }
+ catch (TransformerException ex) {
+ throw new MarshallingFailureException(
+- "Could not transform to [" + ClassUtils.getShortName(result.getClass()) + "]");
++ "Could not transform to [" + ClassUtils.getShortName(result.getClass()) + "]", ex);
+ }
+
+ }
+@@ -397,7 +403,7 @@ public class JibxMarshaller extends AbstractMarshaller implements InitializingBe
+ @Override
+ protected Object unmarshalDomNode(Node node) throws XmlMappingException {
+ try {
+- return transformAndUnmarshal(new DOMSource(node));
++ return transformAndUnmarshal(new DOMSource(node), null);
+ }
+ catch (IOException ex) {
+ throw new UnmarshallingFailureException("JiBX unmarshalling exception", ex);
+@@ -407,12 +413,15 @@ public class JibxMarshaller extends AbstractMarshaller implements InitializingBe
+ @Override
+ protected Object unmarshalSaxReader(XMLReader xmlReader, InputSource inputSource)
+ throws XmlMappingException, IOException {
+- return transformAndUnmarshal(new SAXSource(xmlReader, inputSource));
++ return transformAndUnmarshal(new SAXSource(xmlReader, inputSource), inputSource.getEncoding());
+ }
+
+- private Object transformAndUnmarshal(Source source) throws IOException {
++ private Object transformAndUnmarshal(Source source, String encoding) throws IOException {
+ try {
+ Transformer transformer = transformerFactory.newTransformer();
++ if (encoding != null) {
++ transformer.setOutputProperty(OutputKeys.ENCODING, encoding);
++ }
+ ByteArrayOutputStream os = new ByteArrayOutputStream();
+ transformer.transform(source, new StreamResult(os));
+ ByteArrayInputStream is = new ByteArrayInputStream(os.toByteArray());
+@@ -420,7 +429,7 @@ public class JibxMarshaller extends AbstractMarshaller implements InitializingBe
+ }
+ catch (TransformerException ex) {
+ throw new MarshallingFailureException(
+- "Could not transform from [" + ClassUtils.getShortName(source.getClass()) + "]");
++ "Could not transform from [" + ClassUtils.getShortName(source.getClass()) + "]", ex);
+ }
+ }
+
+diff --git a/org.springframework.oxm/src/main/java/org/springframework/oxm/support/AbstractMarshaller.java b/org.springframework.oxm/src/main/java/org/springframework/oxm/support/AbstractMarshaller.java
+index cee37bb..dd0ea39 100644
+--- a/org.springframework.oxm/src/main/java/org/springframework/oxm/support/AbstractMarshaller.java
++++ b/org.springframework.oxm/src/main/java/org/springframework/oxm/support/AbstractMarshaller.java
+@@ -20,6 +20,7 @@ import java.io.IOException;
+ import java.io.InputStream;
+ import java.io.OutputStream;
+ import java.io.Reader;
++import java.io.StringReader;
+ import java.io.Writer;
+ import javax.xml.parsers.DocumentBuilder;
+ import javax.xml.parsers.DocumentBuilderFactory;
+@@ -42,6 +43,7 @@ import org.apache.commons.logging.Log;
+ import org.apache.commons.logging.LogFactory;
+ import org.w3c.dom.Node;
+ import org.xml.sax.ContentHandler;
++import org.xml.sax.EntityResolver;
+ import org.xml.sax.InputSource;
+ import org.xml.sax.SAXException;
+ import org.xml.sax.XMLReader;
+@@ -73,6 +75,32 @@ public abstract class AbstractMarshaller implements Marshaller, Unmarshaller {
+
+ private final Object documentBuilderFactoryMonitor = new Object();
+
++ private boolean processExternalEntities = false;
++
++ /**
++ * Indicates whether external XML entities are processed when unmarshalling.
++ * <p>
++ * Default is {@code false}, meaning that external entities are not resolved. Note that
++ * processing of external entities will only be enabled/disabled when the {@code Source}
++ * passed to {@link #unmarshal(Source)} is a {@link SAXSource} or {@link StreamSource}. It
++ * has no effect for {@link DOMSource} or {@link StAXSource} instances.
++ */
++ public void setProcessExternalEntities(boolean processExternalEntities) {
++ this.processExternalEntities = processExternalEntities;
++ }
++
++ /**
++ * @return the configured value for whether XML external entities are allowed.
++ */
++ public boolean isProcessExternalEntities() {
++ return this.processExternalEntities;
++ }
++
++ /**
++ * @return the default encoding to use for marshalling or unmarshalling from a byte stream,
++ * or {@code null}.
++ */
++ abstract protected String getDefaultEncoding();
+
+ /**
+ * Marshals the object graph with the given root into the provided <code>javax.xml.transform.Result</code>.
+@@ -173,7 +201,12 @@ public abstract class AbstractMarshaller implements Marshaller, Unmarshaller {
+ * @throws SAXException if thrown by JAXP methods
+ */
+ protected XMLReader createXmlReader() throws SAXException {
+- return XMLReaderFactory.createXMLReader();
++ XMLReader xmlReader = XMLReaderFactory.createXMLReader();
++ xmlReader.setFeature("http://xml.org/sax/features/external-general-entities", isProcessExternalEntities());
++ if (!isProcessExternalEntities()) {
++ xmlReader.setEntityResolver(NO_OP_ENTITY_RESOLVER);
++ }
++ return xmlReader;
+ }
+
+
+@@ -365,13 +398,23 @@ public abstract class AbstractMarshaller implements Marshaller, Unmarshaller {
+ */
+ protected Object unmarshalStreamSource(StreamSource streamSource) throws XmlMappingException, IOException {
+ if (streamSource.getInputStream() != null) {
+- return unmarshalInputStream(streamSource.getInputStream());
++ if (isProcessExternalEntities()) {
++ return unmarshalInputStream(streamSource.getInputStream());
++ } else {
++ InputSource inputSource = new InputSource(streamSource.getInputStream());
++ inputSource.setEncoding(getDefaultEncoding());
++ return unmarshalSaxSource(new SAXSource(inputSource));
++ }
+ }
+ else if (streamSource.getReader() != null) {
+- return unmarshalReader(streamSource.getReader());
++ if (isProcessExternalEntities()) {
++ return unmarshalReader(streamSource.getReader());
++ } else {
++ return unmarshalSaxSource(new SAXSource(new InputSource(streamSource.getReader())));
++ }
+ }
+ else {
+- throw new IllegalArgumentException("StreamSource contains neither InputStream nor Reader");
++ return unmarshalSaxSource(new SAXSource(new InputSource(streamSource.getSystemId())));
+ }
+ }
+
+@@ -499,4 +542,11 @@ public abstract class AbstractMarshaller implements Marshaller, Unmarshaller {
+ protected abstract Object unmarshalSaxReader(XMLReader xmlReader, InputSource inputSource)
+ throws XmlMappingException, IOException;
+
++ private static final EntityResolver NO_OP_ENTITY_RESOLVER = new EntityResolver() {
++ @Override
++ public InputSource resolveEntity(String publicId, String systemId) {
++ return new InputSource(new StringReader(""));
++ }
++ };
++
+ }
+diff --git a/org.springframework.oxm/src/main/java/org/springframework/oxm/xmlbeans/XmlBeansMarshaller.java b/org.springframework.oxm/src/main/java/org/springframework/oxm/xmlbeans/XmlBeansMarshaller.java
+index eb5a6e6..2961ec0 100644
+--- a/org.springframework.oxm/src/main/java/org/springframework/oxm/xmlbeans/XmlBeansMarshaller.java
++++ b/org.springframework.oxm/src/main/java/org/springframework/oxm/xmlbeans/XmlBeansMarshaller.java
+@@ -116,6 +116,10 @@ public class XmlBeansMarshaller extends AbstractMarshaller {
+ return this.validating;
+ }
+
++ @Override
++ protected String getDefaultEncoding() {
++ return null;
++ }
+
+ /**
+ * This implementation returns true if the given class is an implementation of {@link XmlObject}.
+diff --git a/org.springframework.oxm/src/main/java/org/springframework/oxm/xstream/XStreamMarshaller.java b/org.springframework.oxm/src/main/java/org/springframework/oxm/xstream/XStreamMarshaller.java
+index 2b2b7ee..d8b2f68 100644
+--- a/org.springframework.oxm/src/main/java/org/springframework/oxm/xstream/XStreamMarshaller.java
++++ b/org.springframework.oxm/src/main/java/org/springframework/oxm/xstream/XStreamMarshaller.java
+@@ -26,11 +26,9 @@ import java.io.Writer;
+ import java.util.LinkedHashMap;
+ import java.util.List;
+ import java.util.Map;
+-import javax.xml.stream.XMLEventReader;
+-import javax.xml.stream.XMLEventWriter;
+-import javax.xml.stream.XMLStreamException;
+-import javax.xml.stream.XMLStreamReader;
+-import javax.xml.stream.XMLStreamWriter;
++import javax.xml.stream.*;
++import javax.xml.transform.stax.StAXSource;
++import javax.xml.transform.stream.StreamSource;
+
+ import com.thoughtworks.xstream.XStream;
+ import com.thoughtworks.xstream.converters.ConversionException;
+@@ -348,6 +346,11 @@ public class XStreamMarshaller extends AbstractMarshaller implements Initializin
+ this.encoding = encoding;
+ }
+
++ @Override
++ protected String getDefaultEncoding() {
++ return this.encoding;
++ }
++
+ /**
+ * Set the classes supported by this marshaller.
+ * <p>If this property is empty (the default), all classes are supported.
+@@ -472,6 +475,17 @@ public class XStreamMarshaller extends AbstractMarshaller implements Initializin
+ // Unmarshalling
+
+ @Override
++ protected Object unmarshalStreamSource(StreamSource streamSource) throws XmlMappingException, IOException {
++ if (streamSource.getInputStream() != null) {
++ return unmarshalInputStream(streamSource.getInputStream());
++ } else if (streamSource.getReader() != null) {
++ return unmarshalReader(streamSource.getReader());
++ } else {
++ throw new IllegalArgumentException("StreamSource contains neither InputStream nor Reader");
++ }
++ }
++
++ @Override
+ protected Object unmarshalDomNode(Node node) throws XmlMappingException {
+ HierarchicalStreamReader streamReader;
+ if (node instanceof Document) {
+diff --git a/org.springframework.web/src/main/java/org/springframework/http/converter/xml/Jaxb2RootElementHttpMessageConverter.java b/org.springframework.web/src/main/java/org/springframework/http/converter/xml/Jaxb2RootElementHttpMessageConverter.java
+index 89d5bd0..9a4cc88 100644
+--- a/org.springframework.web/src/main/java/org/springframework/http/converter/xml/Jaxb2RootElementHttpMessageConverter.java
++++ b/org.springframework.web/src/main/java/org/springframework/http/converter/xml/Jaxb2RootElementHttpMessageConverter.java
+@@ -17,6 +17,7 @@
+ package org.springframework.http.converter.xml;
+
+ import java.io.IOException;
++import java.io.StringReader;
+ import javax.xml.bind.JAXBElement;
+ import javax.xml.bind.JAXBException;
+ import javax.xml.bind.MarshalException;
+@@ -28,6 +29,9 @@ import javax.xml.bind.annotation.XmlRootElement;
+ import javax.xml.bind.annotation.XmlType;
+ import javax.xml.transform.Result;
+ import javax.xml.transform.Source;
++import javax.xml.transform.dom.DOMSource;
++import javax.xml.transform.sax.SAXSource;
++import javax.xml.transform.stream.StreamSource;
+
+ import org.springframework.core.annotation.AnnotationUtils;
+ import org.springframework.http.HttpHeaders;
+@@ -36,6 +40,12 @@ import org.springframework.http.converter.HttpMessageConversionException;
+ import org.springframework.http.converter.HttpMessageNotReadableException;
+ import org.springframework.http.converter.HttpMessageNotWritableException;
+ import org.springframework.util.ClassUtils;
++import org.xml.sax.EntityResolver;
++import org.springframework.util.xml.StaxUtils;
++import org.xml.sax.InputSource;
++import org.xml.sax.SAXException;
++import org.xml.sax.XMLReader;
++import org.xml.sax.helpers.XMLReaderFactory;
+
+ /**
+ * Implementation of {@link org.springframework.http.converter.HttpMessageConverter HttpMessageConverter} that can read
+@@ -49,6 +59,21 @@ import org.springframework.util.ClassUtils;
+ */
+ public class Jaxb2RootElementHttpMessageConverter extends AbstractJaxb2HttpMessageConverter<Object> {
+
++ private boolean processExternalEntities = false;
++
++ /**
++ * Indicates whether external XML entities are processed when converting to a Source.
++ * <p>
++ * Default is {@code false}, meaning that external entities are not resolved.
++ */
++ public void setProcessExternalEntities(boolean processExternalEntities) {
++ this.processExternalEntities = processExternalEntities;
++ }
++
++ public boolean isProcessExternalEntities() {
++ return this.processExternalEntities;
++ }
++
+ @Override
+ public boolean canRead(Class<?> clazz, MediaType mediaType) {
+ return (clazz.isAnnotationPresent(XmlRootElement.class) || clazz.isAnnotationPresent(XmlType.class)) &&
+@@ -69,6 +94,7 @@ public class Jaxb2RootElementHttpMessageConverter extends AbstractJaxb2HttpMessa
+ @Override
+ protected Object readFromSource(Class<?> clazz, HttpHeaders headers, Source source) throws IOException {
+ try {
++ source = processSource(source);
+ Unmarshaller unmarshaller = createUnmarshaller(clazz);
+ if (clazz.isAnnotationPresent(XmlRootElement.class)) {
+ return unmarshaller.unmarshal(source);
+@@ -87,6 +113,27 @@ public class Jaxb2RootElementHttpMessageConverter extends AbstractJaxb2HttpMessa
+ }
+ }
+
++ protected Source processSource(Source source) {
++ if (source instanceof StreamSource) {
++ StreamSource streamSource = (StreamSource) source;
++ InputSource inputSource = new InputSource(streamSource.getInputStream());
++ try {
++ XMLReader xmlReader = XMLReaderFactory.createXMLReader();
++ String featureName = "http://xml.org/sax/features/external-general-entities";
++ xmlReader.setFeature(featureName, isProcessExternalEntities());
++ if (!isProcessExternalEntities()) {
++ xmlReader.setEntityResolver(NO_OP_ENTITY_RESOLVER);
++ }
++ return new SAXSource(xmlReader, inputSource);
++ } catch (SAXException ex) {
++ logger.warn("Processing of external entities could not be disabled", ex);
++ return source;
++ }
++ } else {
++ return source;
++ }
++ }
++
+ @Override
+ protected void writeToResult(Object o, HttpHeaders headers, Result result) throws IOException {
+ try {
+@@ -109,4 +156,11 @@ public class Jaxb2RootElementHttpMessageConverter extends AbstractJaxb2HttpMessa
+ }
+ }
+
++ private static final EntityResolver NO_OP_ENTITY_RESOLVER = new EntityResolver() {
++ @Override
++ public InputSource resolveEntity(String publicId, String systemId) {
++ return new InputSource(new StringReader(""));
++ }
++ };
++
+ }
+diff --git a/org.springframework.web/src/main/java/org/springframework/http/converter/xml/SourceHttpMessageConverter.java b/org.springframework.web/src/main/java/org/springframework/http/converter/xml/SourceHttpMessageConverter.java
+index e949503..96cc290 100644
+--- a/org.springframework.web/src/main/java/org/springframework/http/converter/xml/SourceHttpMessageConverter.java
++++ b/org.springframework.web/src/main/java/org/springframework/http/converter/xml/SourceHttpMessageConverter.java
+@@ -1,5 +1,5 @@
+ /*
+- * Copyright 2002-2011 the original author or authors.
++ * Copyright 2002-2013 the original author or authors.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+@@ -19,71 +19,175 @@ package org.springframework.http.converter.xml;
+ import java.io.ByteArrayInputStream;
+ import java.io.ByteArrayOutputStream;
+ import java.io.IOException;
++import java.io.InputStream;
+ import java.io.OutputStream;
++import java.io.StringReader;
++import java.util.HashSet;
++import java.util.Set;
++
++import javax.xml.parsers.DocumentBuilder;
++import javax.xml.parsers.DocumentBuilderFactory;
++import javax.xml.parsers.ParserConfigurationException;
++import javax.xml.stream.XMLInputFactory;
++import javax.xml.stream.XMLResolver;
++import javax.xml.stream.XMLStreamException;
++import javax.xml.stream.XMLStreamReader;
+ import javax.xml.transform.Result;
+ import javax.xml.transform.Source;
+ import javax.xml.transform.TransformerException;
+-import javax.xml.transform.dom.DOMResult;
++import javax.xml.transform.TransformerFactory;
+ import javax.xml.transform.dom.DOMSource;
+ import javax.xml.transform.sax.SAXSource;
++import javax.xml.transform.stax.StAXSource;
+ import javax.xml.transform.stream.StreamResult;
+ import javax.xml.transform.stream.StreamSource;
+
++import org.w3c.dom.Document;
++import org.xml.sax.EntityResolver;
+ import org.xml.sax.InputSource;
+-
+-import org.springframework.http.HttpHeaders;
++import org.xml.sax.SAXException;
++import org.xml.sax.XMLReader;
++import org.xml.sax.helpers.XMLReaderFactory;
++import org.springframework.http.HttpInputMessage;
++import org.springframework.http.HttpOutputMessage;
+ import org.springframework.http.MediaType;
++import org.springframework.http.converter.AbstractHttpMessageConverter;
+ import org.springframework.http.converter.HttpMessageConversionException;
+ import org.springframework.http.converter.HttpMessageNotReadableException;
+ import org.springframework.http.converter.HttpMessageNotWritableException;
+
+ /**
+- * Implementation of {@link org.springframework.http.converter.HttpMessageConverter} that can read and write {@link
+- * Source} objects.
++ * Implementation of {@link org.springframework.http.converter.HttpMessageConverter}
++ * that can read and write {@link Source} objects.
+ *
+ * @author Arjen Poutsma
+ * @since 3.0
+ */
+-public class SourceHttpMessageConverter<T extends Source> extends AbstractXmlHttpMessageConverter<T> {
++public class SourceHttpMessageConverter<T extends Source> extends AbstractHttpMessageConverter<T> {
++
++ private static final Set<Class<?>> SUPPORTED_CLASSES = new HashSet<Class<?>>(5);
++
++ static {
++ SUPPORTED_CLASSES.add(DOMSource.class);
++ SUPPORTED_CLASSES.add(SAXSource.class);
++ SUPPORTED_CLASSES.add(StAXSource.class);
++ SUPPORTED_CLASSES.add(StreamSource.class);
++ SUPPORTED_CLASSES.add(Source.class);
++ }
++
++
++ private final TransformerFactory transformerFactory = TransformerFactory.newInstance();
++
++ private boolean processExternalEntities = false;
++
++
++ /**
++ * Sets the {@link #setSupportedMediaTypes(java.util.List) supportedMediaTypes}
++ * to {@code text/xml} and {@code application/xml}, and {@code application/*-xml}.
++ */
++ public SourceHttpMessageConverter() {
++ super(MediaType.APPLICATION_XML, MediaType.TEXT_XML, new MediaType("application", "*+xml"));
++ }
++
++
++ /**
++ * Indicates whether external XML entities are processed when converting to a Source.
++ * <p>Default is {@code false}, meaning that external entities are not resolved.
++ */
++ public void setProcessExternalEntities(boolean processExternalEntities) {
++ this.processExternalEntities = processExternalEntities;
++ }
++
++ /**
++ * @return the configured value for whether XML external entities are allowed.
++ */
++ public boolean isProcessExternalEntities() {
++ return this.processExternalEntities;
++ }
+
+ @Override
+ public boolean supports(Class<?> clazz) {
+- return DOMSource.class.equals(clazz) || SAXSource.class.equals(clazz) || StreamSource.class.equals(clazz) ||
+- Source.class.equals(clazz);
++ return SUPPORTED_CLASSES.contains(clazz);
+ }
+
+ @Override
+ @SuppressWarnings("unchecked")
+- protected T readFromSource(Class clazz, HttpHeaders headers, Source source) throws IOException {
++ protected T readInternal(Class<? extends T> clazz, HttpInputMessage inputMessage)
++ throws IOException, HttpMessageNotReadableException {
++
++ InputStream body = inputMessage.getBody();
++ if (DOMSource.class.equals(clazz)) {
++ return (T) readDOMSource(body);
++ }
++ else if (SAXSource.class.equals(clazz)) {
++ return (T) readSAXSource(body);
++ }
++ else if (StAXSource.class.equals(clazz)) {
++ return (T) readStAXSource(body);
++ }
++ else if (StreamSource.class.equals(clazz) || Source.class.equals(clazz)) {
++ return (T) readStreamSource(body);
++ }
++ else {
++ throw new HttpMessageConversionException("Could not read class [" + clazz +
++ "]. Only DOMSource, SAXSource, StAXSource, and StreamSource are supported.");
++ }
++ }
++
++ private DOMSource readDOMSource(InputStream body) throws IOException {
+ try {
+- if (DOMSource.class.equals(clazz)) {
+- DOMResult domResult = new DOMResult();
+- transform(source, domResult);
+- return (T) new DOMSource(domResult.getNode());
+- }
+- else if (SAXSource.class.equals(clazz)) {
+- ByteArrayInputStream bis = transformToByteArrayInputStream(source);
+- return (T) new SAXSource(new InputSource(bis));
++ DocumentBuilderFactory documentBuilderFactory = DocumentBuilderFactory.newInstance();
++ documentBuilderFactory.setNamespaceAware(true);
++ documentBuilderFactory.setFeature(
++ "http://xml.org/sax/features/external-general-entities", isProcessExternalEntities());
++ DocumentBuilder documentBuilder = documentBuilderFactory.newDocumentBuilder();
++ if (!isProcessExternalEntities()) {
++ documentBuilder.setEntityResolver(NO_OP_ENTITY_RESOLVER);
+ }
+- else if (StreamSource.class.equals(clazz) || Source.class.equals(clazz)) {
+- ByteArrayInputStream bis = transformToByteArrayInputStream(source);
+- return (T) new StreamSource(bis);
++ Document document = documentBuilder.parse(body);
++ return new DOMSource(document);
++ }
++ catch (ParserConfigurationException ex) {
++ throw new HttpMessageNotReadableException("Could not set feature: " + ex.getMessage(), ex);
++ }
++ catch (SAXException ex) {
++ throw new HttpMessageNotReadableException("Could not parse document: " + ex.getMessage(), ex);
++ }
++ }
++
++ private SAXSource readSAXSource(InputStream body) throws IOException {
++ try {
++ XMLReader reader = XMLReaderFactory.createXMLReader();
++ reader.setFeature("http://xml.org/sax/features/external-general-entities", isProcessExternalEntities());
++ byte[] bytes = StreamUtils.copyToByteArray(body);
++ if (!isProcessExternalEntities()) {
++ reader.setEntityResolver(NO_OP_ENTITY_RESOLVER);
+ }
+- else {
+- throw new HttpMessageConversionException("Could not read class [" + clazz +
+- "]. Only DOMSource, SAXSource, and StreamSource are supported.");
++ return new SAXSource(reader, new InputSource(new ByteArrayInputStream(bytes)));
++ }
++ catch (SAXException ex) {
++ throw new HttpMessageNotReadableException("Could not parse document: " + ex.getMessage(), ex);
++ }
++ }
++
++ private Source readStAXSource(InputStream body) {
++ try {
++ XMLInputFactory inputFactory = XMLInputFactory.newFactory();
++ inputFactory.setProperty(XMLInputFactory.IS_SUPPORTING_EXTERNAL_ENTITIES, isProcessExternalEntities());
++ if (!isProcessExternalEntities()) {
++ inputFactory.setXMLResolver(NO_OP_XML_RESOLVER);
+ }
++ XMLStreamReader streamReader = inputFactory.createXMLStreamReader(body);
++ return new StAXSource(streamReader);
+ }
+- catch (TransformerException ex) {
+- throw new HttpMessageNotReadableException("Could not transform from [" + source + "] to [" + clazz + "]",
+- ex);
++ catch (XMLStreamException ex) {
++ throw new HttpMessageNotReadableException("Could not parse document: " + ex.getMessage(), ex);
+ }
+ }
+
+- private ByteArrayInputStream transformToByteArrayInputStream(Source source) throws TransformerException {
+- ByteArrayOutputStream bos = new ByteArrayOutputStream();
+- transform(source, new StreamResult(bos));
+- return new ByteArrayInputStream(bos.toByteArray());
++ private StreamSource readStreamSource(InputStream body) throws IOException {
++ byte[] bytes = StreamUtils.copyToByteArray(body);
++ return new StreamSource(new ByteArrayInputStream(bytes));
+ }
+
+ @Override
+@@ -102,33 +206,104 @@ public class SourceHttpMessageConverter<T extends Source> extends AbstractXmlHtt
+ }
+
+ @Override
+- protected void writeToResult(T t, HttpHeaders headers, Result result) throws IOException {
++ protected void writeInternal(T t, HttpOutputMessage outputMessage)
++ throws IOException, HttpMessageNotWritableException {
+ try {
++ Result result = new StreamResult(outputMessage.getBody());
+ transform(t, result);
+ }
+ catch (TransformerException ex) {
+- throw new HttpMessageNotWritableException("Could not transform [" + t + "] to [" + result + "]", ex);
++ throw new HttpMessageNotWritableException("Could not transform [" + t + "] to output message", ex);
+ }
+ }
+
++ private void transform(Source source, Result result) throws TransformerException {
++ this.transformerFactory.newTransformer().transform(source, result);
++ }
++
++
+ private static class CountingOutputStream extends OutputStream {
+
+- private long count = 0;
++ long count = 0;
+
+ @Override
+ public void write(int b) throws IOException {
+- count++;
++ this.count++;
+ }
+
+ @Override
+ public void write(byte[] b) throws IOException {
+- count += b.length;
++ this.count += b.length;
+ }
+
+ @Override
+ public void write(byte[] b, int off, int len) throws IOException {
+- count += len;
++ this.count += len;
+ }
+ }
+
+-}
++ private static final EntityResolver NO_OP_ENTITY_RESOLVER = new EntityResolver() {
++ @Override
++ public InputSource resolveEntity(String publicId, String systemId) {
++ return new InputSource(new StringReader(""));
++ }
++ };
++
++ private static final XMLResolver NO_OP_XML_RESOLVER = new XMLResolver() {
++ @Override
++ public Object resolveEntity(String publicID, String systemID, String base, String ns) {
++ return new ByteArrayInputStream(new byte[0]);
++ }
++ };
++
++ private static class StreamUtils {
++
++ public static final int BUFFER_SIZE = 4096;
++
++
++ /**
++ * Copy the contents of the given InputStream into a new byte array.
++ * Leaves the stream open when done.
++ * @param in the stream to copy from
++ * @return the new byte array that has been copied to
++ * @throws IOException in case of I/O errors
++ */
++ public static byte[] copyToByteArray(InputStream in) throws IOException {
++ ByteArrayOutputStream out = new ByteArrayOutputStream(BUFFER_SIZE);
++ copy(in, out);
++ return out.toByteArray();
++ }
++
++ /**
++ * Copy the contents of the given InputStream to the given OutputStream. Leaves both
++ * streams open when done.
++ *
++ * @param in
++ * the InputStream to copy from
++ * @param out
++ * the OutputStream to copy to
++ * @return the number of bytes copied
++ * @throws IOException
++ * in case of I/O errors
++ */
++ public static int copy(InputStream in, OutputStream out) throws IOException {
++ if (in == null) {
++ throw new IllegalArgumentException("No InputStream specified");
++ }
++
++ if (out == null) {
++ throw new IllegalArgumentException("No OutputStream specified");
++ }
++
++ int byteCount = 0;
++ byte[] buffer = new byte[BUFFER_SIZE];
++ int bytesRead = -1;
++ while ((bytesRead = in.read(buffer)) != -1) {
++ out.write(buffer, 0, bytesRead);
++ byteCount += bytesRead;
++ }
++ out.flush();
++ return byteCount;
++ }
++ }
++}
+\ No newline at end of file
+--
+2.1.0
+
diff --git a/springframework.spec b/springframework.spec
index 1abaca3..cc938f9 100644
--- a/springframework.spec
+++ b/springframework.spec
@@ -2,7 +2,7 @@
%global namedversion %{version}%{?namedreltag}
Name: springframework
Version: 3.1.4
-Release: 2%{?dist}
+Release: 3%{?dist}
Summary: Spring Java Application Framework
Epoch: 0
License: ASL 2.0
@@ -54,6 +54,7 @@ Patch12: %{name}-3.1.4-dont-rebundle-asm.patch
Patch13: %{name}-3.1.4-fix-javax-apis.patch
# Remove some code which don't compile with Hibernate Validator 5.x
Patch14: %{name}-3.1.4-hibernate-validator5.patch
+Patch15: %{name}-3.1.4-Fix-CVE-2014-0225.patch
BuildRequires: hibernate3
BuildRequires: hibernate3-entitymanager
@@ -349,6 +350,7 @@ find -name "*.jar" -print -delete
%patch12 -p1
%patch13 -p1
%patch14 -p1
+%patch15 -p1
cp -p %{SOURCE1} pom.xml
@@ -544,6 +546,9 @@ cp -p build-spring-framework/resources/* .
%doc license.txt notice.txt
%changelog
+* Fri Apr 24 2015 Michal Srb <msrb at redhat.com> - 0:3.1.4-3
+- Resolves: CVE-2014-0225
+
* Fri Dec 06 2013 gil cattaneo <puntogil at libero.it> 0:3.1.4-2
- fix for rhbz: 993376, 953977
- switch to XMvn
--
cgit v0.10.2
http://pkgs.fedoraproject.org/cgit/springframework.git/commit/?h=f20&id=d58174864c39aed04f6f913795758e06a580d889
More information about the scm-commits
mailing list