Merged V4.1-BUG-FIX to HEAD

39828: Merged V4.1 to V4.1-BUG-FIX
      39827: Merged PATCHES/V4.0.2 to V4.1
         39825: ALF-13453 / ALF-13844: Merged V3.4-BUG-FIX to PATCHES/V4.0.2
            39823: ALF-13552, ALF-13978: Reverse merged the following revisions - won't fix due to regressions and not a serious vulnerability
               35341: ALF-13552: Merged V4.0 to V3.4
                  35296: ALF-13453: Merged V4.0-BUG-FIX to V4.0
                     35295: Fix for ALF-13453: Remote Code Execution (can create reverse shell)
                  35304: ALF-13453: Extra fix to ensure xalan namespace isn't declared with global scope and can't be hijacked by an input stylesheet
                  35307: ALF-13453: Duplicated extra fix to duplicate code in XSLTRenderingEngine!
               36101: ALF-13978: Merged V4.0-BUG-FIX to V3.4
                  36014: ALF-13844: XSLT Filtering Not 100% Secure
                     - added more namespaces to the security filter.
                     - verified that include/import uses the security filter.
               36108: ALF-13978: Fixed compilation errors
            39824: ALF-13552, ALF-13978: Fixed compilation errors


git-svn-id: https://svn.alfresco.com/repos/alfresco-enterprise/alfresco/HEAD/root@39829 c4b6b30b-aa2e-2d43-bbcb-ca4b014f7261
This commit is contained in:
Dave Ward
2012-07-26 15:50:56 +00:00
parent 05bcd40a17
commit faa9ba7118
4 changed files with 22 additions and 441 deletions

View File

@@ -19,17 +19,7 @@
package org.alfresco.util;
import java.io.CharArrayReader;
import java.io.File;
import java.io.FileInputStream;
import java.io.FileWriter;
import java.io.IOException;
import java.io.InputStream;
import java.io.Reader;
import java.io.StringWriter;
import java.io.Writer;
import java.util.LinkedList;
import java.util.List;
import java.io.*;
import javax.xml.parsers.DocumentBuilder;
import javax.xml.parsers.DocumentBuilderFactory;
@@ -38,33 +28,18 @@ import javax.xml.transform.OutputKeys;
import javax.xml.transform.Transformer;
import javax.xml.transform.TransformerException;
import javax.xml.transform.TransformerFactory;
import javax.xml.transform.dom.DOMResult;
import javax.xml.transform.dom.DOMSource;
import javax.xml.transform.sax.SAXTransformerFactory;
import javax.xml.transform.sax.TransformerHandler;
import javax.xml.transform.stream.StreamResult;
import org.alfresco.model.ContentModel;
import org.alfresco.service.cmr.avm.AVMService;
import org.alfresco.service.cmr.repository.ContentReader;
import org.alfresco.service.cmr.repository.ContentService;
import org.alfresco.service.cmr.repository.NodeRef;
import org.apache.commons.lang.StringUtils;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import org.w3c.dom.Attr;
import org.w3c.dom.Document;
import org.w3c.dom.Element;
import org.w3c.dom.Node;
import org.w3c.dom.NodeList;
import org.w3c.dom.Text;
import org.xml.sax.Attributes;
import org.w3c.dom.*;
import org.xml.sax.InputSource;
import org.xml.sax.SAXException;
import org.xml.sax.XMLFilter;
import org.xml.sax.XMLReader;
import org.xml.sax.helpers.XMLFilterImpl;
import org.xml.sax.helpers.XMLReaderFactory;
/**
* XML utility functions.
@@ -139,229 +114,75 @@ public class XMLUtil
}
/** utility function for parsing xml */
public static Document parse(final String source, final XMLFilter... filters)
public static Document parse(final String source)
throws SAXException,
IOException
{
return XMLUtil.parse(new CharArrayReader(source.toCharArray()), filters);
}
public static Document secureParseXSL (final String source, final XMLFilter... filters)
throws SAXException,
IOException
{
return parse(new CharArrayReader(source.toCharArray()), addSecurityFilter(filters));
return XMLUtil.parse(new ByteArrayInputStream(source.getBytes("UTF-8")));
}
/** utility function for parsing xml */
public static Document parse(final NodeRef nodeRef,
final ContentService contentService,
final XMLFilter... filters)
final ContentService contentService)
throws SAXException,
IOException
{
final ContentReader contentReader =
contentService.getReader(nodeRef, ContentModel.TYPE_CONTENT);
final InputStream in = contentReader.getContentInputStream();
return XMLUtil.parse(in, filters);
return XMLUtil.parse(in);
}
public static Document secureParseXSL(final NodeRef nodeRef,
final ContentService contentService,
final XMLFilter... filters)
throws SAXException,
IOException
{
final ContentReader contentReader =
contentService.getReader(nodeRef, ContentModel.TYPE_CONTENT);
final InputStream in = contentReader.getContentInputStream();
return parse(in, addSecurityFilter(filters));
}
/** utility function for parsing xml */
public static Document parse(final int version,
final String path,
final AVMService avmService,
final XMLFilter...filters)
final AVMService avmService)
throws SAXException,
IOException
{
return XMLUtil.parse(avmService.getFileInputStream(version, path), filters);
}
public static Document secureParseXSL(final int version,
final String path,
final AVMService avmService,
final XMLFilter... filters)
throws SAXException,
IOException
{
return parse(avmService.getFileInputStream(version, path), addSecurityFilter(filters));
return XMLUtil.parse(avmService.getFileInputStream(version, path));
}
/** utility function for parsing xml */
public static Document parse(final File source,
final XMLFilter... filters)
public static Document parse(final File source)
throws SAXException,
IOException
{
return XMLUtil.parse(new FileInputStream(source), filters);
}
public static Document secureParseXSL(final File source,
final XMLFilter... filters)
throws SAXException,
IOException
{
return parse(new FileInputStream(source), addSecurityFilter(filters));
}
private static Document parseWithXMLFilters(final InputSource source,
final XMLFilter... filters)
throws SAXException,
IOException
{
return parseWithXMLFilters(source, false, filters);
}
private static Document parseWithXMLFilters(final InputSource source,
final boolean validating,
final XMLFilter... filters)
throws SAXException,
IOException
{
TransformerFactory tf = TransformerFactory.newInstance();
// Check to make sure this is a SAX TransformerFactory
if (!tf.getFeature(SAXTransformerFactory.FEATURE))
{
throw new SAXException("SAX Transformation factory not found.");
}
// Cast to appropriate factory class
SAXTransformerFactory stf = (SAXTransformerFactory) tf;
final DocumentBuilder db = XMLUtil.getDocumentBuilder(true, validating);
if (filters == null || filters.length == 0)
{
// No filters. Process this as normal.
return db.parse(source);
}
else
{
// Process with filters
try
{
final Document doc = db.newDocument();
final TransformerHandler th = stf.newTransformerHandler();
// Specify transformation to DOMResult with empty Node container (Document)
th.setResult(new DOMResult(doc));
XMLReader reader = XMLReaderFactory.createXMLReader();
//emulate what the document builder parser supports
//all readers are required to support namespaces and namespace-prefixes
reader.setFeature("http://xml.org/sax/features/namespaces", db.isNamespaceAware());
reader.setFeature("http://xml.org/sax/features/namespace-prefixes", db.isNamespaceAware() ? true : false);
// Chain multiple filters together
int i = 0;
XMLFilter filter = null;
for (XMLFilter f : filters)
{
// there can be no null in the filter list
if (f == null)
throw new SAXException("Nulls are not allowed in XML filter list.");
// if first item then set new reader
if (i == 0)
f.setParent(reader);
else
// set parent filter to previous element in the array
f.setParent(filters[i - 1]);
filter = f;
i++;
}
//not sure how filter could be null
if (filter != null)
{
filter.setContentHandler(th);
filter.parse(source);
try
{
//try to activate/deactivate validation
filter.setFeature("http://xml.org/sax/features/validation", db.isValidating());
}
catch (SAXException se)
{
LOGGER.warn("XML reader does not support validation feature.", se);
}
}
else
{
//not sure how we could get here
throw new SAXException("No XML filters available to process this request.");
}
if (LOGGER.isDebugEnabled()) {
StringWriter writer = new StringWriter();
XMLUtil.print(doc, writer);
LOGGER.debug(writer);
}
return doc;
}
catch (TransformerException tce)
{
throw new SAXException(tce);
}
}
return XMLUtil.parse(new FileInputStream(source));
}
/** utility function for parsing xml */
public static Document parse(final InputStream source, final XMLFilter... filters)
public static Document parse(final InputStream source)
throws SAXException,
IOException
{
try
{
return parseWithXMLFilters(new InputSource(source), filters);
final DocumentBuilder db = XMLUtil.getDocumentBuilder();
return db.parse(source);
}
finally
{
source.close();
}
}
/** secure parse for InputStream source */
public static Document secureParseXSL(final InputStream source,
final XMLFilter... filters)
throws SAXException,
IOException
{
return parse(source, addSecurityFilter(filters));
}
/** utility function for parsing xml */
public static Document parse(final Reader source,
final XMLFilter... filters)
public static Document parse(final Reader source)
throws SAXException,
IOException
{
try
{
return parseWithXMLFilters(new InputSource(source), filters);
final DocumentBuilder db = XMLUtil.getDocumentBuilder();
return db.parse(new InputSource(source));
}
finally
{
source.close();
}
}
/** secure parse for Reader source **/
public static Document secureParseXSL(final Reader source,
final XMLFilter... filters)
throws SAXException,
IOException
{
return parse(source, addSecurityFilter(filters));
}
/** provides a document builder that is namespace aware but not validating by default */
public static DocumentBuilder getDocumentBuilder()
{
@@ -472,81 +293,4 @@ public class XMLUtil
}
};
}
/**
* returns a new array of filters with the security filter at the head of the array
*/
private static XMLFilter[] addSecurityFilter(XMLFilter...filters) {
if (filters == null || filters.length == 0) {
return new XMLFilter[] {new FastFailSecureXMLFilter()};
} else {
XMLFilter[] xmlfilters = new XMLFilter[filters.length + 1];
xmlfilters[0] = new FastFailSecureXMLFilter();
System.arraycopy(filters, 0, xmlfilters, 1, filters.length);
return xmlfilters;
}
}
/**
* XMLFilter that throws an exception when it comes across any insecure namespaces
*/
private static class FastFailSecureXMLFilter extends XMLFilterImpl
{
private static final List<String> insecureURIs = new LinkedList<String>()
{
private static final long serialVersionUID = 1L;
{
add("xalan://");
add("http://exslt.org/");
add("http://xml.apache.org/xalan/PipeDocument");
add("http://xml.apache.org/xalan/sql");
add("http://xml.apache.org/xalan/redirect");
add("http://xml.apache.org/xalan/xsltc/java");
add("http://xml.apache.org/xalan/java");
add("http://xml.apache.org/xslt");
add("http://xml.apache.org/java");
}
};
public FastFailSecureXMLFilter()
{
};
public void startPrefixMapping(String prefix, String uri)
throws SAXException
{
if (isInsecureURI(uri))
{
throw new SAXException("Insecure namespace: " + uri);
}
super.startPrefixMapping(prefix, uri);
}
public void startElement (String uri,
String localName,
String qName,
final Attributes atts)
throws SAXException
{
if (isInsecureURI(uri))
{
throw new SAXException("Insecure namespace: " + uri);
}
super.startElement(uri, localName, qName, atts);
}
private boolean isInsecureURI(String uri)
{
for (String insecureURI : insecureURIs)
{
if (StringUtils.startsWithIgnoreCase(uri, insecureURI)) return true;
}
return false;
}
}
}