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