Merged V4.0-BUG-FIX to HEAD

35224: ALF-12038: Remove trailing JSON comma causing IE7 script error
   35226: ALF-13401 - Saving PowerPoint (mac 2011) via CIFS fails in Mac OS X Lion
   35239: ALF-13409: Further fix to deal with concurrent deletion of a user's site invitations in background
   35245: ALF-13281: Enabled use of autocomplete in IE for forms runtime. This change also allows multiple events to be attached per validation handler
   35253: ALF-13640: Fixed issues with updating task associations + added new test + fixed existing activiti-component-tests
   35271: Translation updates (fixes: ALF-13434) - based on EN r35212. (Dutch still to follow)
   35281: ALF-13227: Fix CSS for Wiki layout of nested lists
   35284: SPANISH: Update from Gloria
   35290: More debug + unit test for mac powerpoint shuffle.
   35291: Added isTemporary method
   35295: ALF-13453	: Remote Code Execution (can create reverse shell).
   - Added ability for XMLUtil parse callers to provide an  optional array of XMLFilterImpl to be used while parsing. 
   -Added secureParseXSL methods that automatically install an XMLFilterImpl that causes a parse failure if any insecure namespaces are encountered.
   35303: Fix for ALF-12444 Node Browser improvement: Index single node and remove single node from indexes
   Part of ALF-13723 SOLR does not include the same query unit tests as lucene
   35305: ALF-13723 SOLR does not include the same query unit tests as lucene
   - test template
   35306: ALF-13723 SOLR does not include the same query unit tests as lucene
   - template for creating test cores
   35323: ALF-13420: Natural sort on form option labels and improvement for CSS - specifically to address transform action in document details.
   35328: ALF-13409: Avoid concurrency issues in unit test tear downs by deleting users before sites. User deletion deletes invitations synchronously. Site deletion deletes invitations concurrently to avoid UI timeouts. The potential to access invitations that are being concurrently deleted still exists, but always did!
   35331: ALF-12126: Ensure that DND upload is disabled for users with only consumer access
   35335: ALF-13708: Merged V3.4-BUG-FIX (3.4.10) to V4.0-BUG-FIX (4.0.2)
      35235: ALF-13673: Amp-loaded duplicated mimetypes should be handled
         - Modified code to allow duplicates to replace parts of the existing mimetype definitions.
         - A warning is logged each time. 
   35336: Spanish and Dutch updates from Gloria, based on EN r35212
   35355: Merged V3.4-BUG-FIX to V4.0-BUG-FIX
      35213: ALF-13686: Merged PATCHES/V3.4.8 to V3.4-BUG-FIX
         34943: ALF-13121: Option to create users either as user1 or user1@domain.com after kerberos authentication
         - New Kerberos subsystem parameter kerberos.authentication.stripUsernameSuffix introduced
         - When true (the default) the @domain sufix will be stripped from Kerberos authenticated usernames in CIFS, SPP, WebDAV and the Web Client
         - When false, should enable a multi-domain customer to use Alfresco (says Mr Gninot)
         35096: ALF-13121: Added missing stripKerberosUsernameSuffix property to sharepointAuthenticationHandler
      35215: ALF-13065: Ensure Wiki new page save button is available on HTML edit action
      35219: ALF-11898: Fixed TinyMCE create HTML content problem for Explorer client
      35261: Translation updates based on EN r35144
      35339: AD 2008 R2, user import via LDAP fails with over 1000 users
      - Problem discovered by Community user with simple workaround
      https://forums.alfresco.com/en/viewtopic.php?f=57&t=43960&sid=5569e5cfbccb3776e11ef4a8e9d50378&p=129664#p129664
      35353: Merged V3.4 to V3.4-BUG-FIX
         35279: ALF-13713: Merged PATCHES/V3.4.8 to V3.4
            35146: Merged DEV to PATCHES/V3.4.8
               35130: ALF-13472: Webdav Does not allow a user to access spaces without read permission on parent spaces
                  Receiving of indirect lock is wrapped into AuthenticationUtil.runAs() invocation to provide a possibility of getting indirect lock for users with appropriate access rights for requested resource
         35280: ALF-10353: Internet Explorer hangs when using the object picker with a larger number of documents
         - reviewed by DD
         35318: ALF-13715: Merged HEAD to V3.4
            31743: Fixed ALF-10157: Web Form Details page for the "Selected Web Content Forms": script error appears on help button click: container.jsp (line 382)
         35341: ALF-13552: Merged V4.0 to V3.4
            35296: ALF-13453: Remote Code Execution (can create reverse shell) - Fix by Shane
            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!
      35354: Merged V3.4 to V3.4-BUG-FIX (RECORD ONLY)
         35266: Merged V3.4-BUG-FIX to V3.4
            35261: Translation updates based on EN r35144
         35334: Merged V3.4-BUG-FIX to V3.4
            35235: ALF-13673: Amp-loaded duplicated mimetypes should be handled
               - Modified code to allow duplicates to replace parts of the existing mimetype definitions.
               - A warning is logged each time. 
   35356: Merged V4.0 to V4.0-BUG-FIX
      35292: ALF-13721: Merged PATCHES/V4.0.0 to V4.0
         35240: Fix for ALF-13685 The SOLr textContent webscript is not protected by authentication and permission checks.
         35242: Fix for ALF-13685 The SOLr textContent webscript is not protected by authentication and permission checks.
         - /wcs/api/solr and /wcservice/api/solr
      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!
   35357: Merged V4.0 to V4.0-BUG-FIX (RECORD ONLY)
      35048: Merged V4.0-BUG-FIX to V4.0
         35031: Fix for ALF-12309: Script errors on site pages
      35293: Merged V4.0-BUG-FIX to V4.0
         35172: ALF-13626: category.put.json.ftl has wrong bracket
      35296: Merged V4.0-BUG-FIX to V4.0
         35295: ALF-13453: Remote Code Execution (can create reverse shell)
           - Fix by Shane


git-svn-id: https://svn.alfresco.com/repos/alfresco-enterprise/alfresco/HEAD/root@35359 c4b6b30b-aa2e-2d43-bbcb-ca4b014f7261
This commit is contained in:
Dave Ward
2012-04-18 09:42:39 +00:00
parent 21b5d8a41f
commit e31ea91e51
20 changed files with 789 additions and 49 deletions

View File

@@ -19,7 +19,18 @@
package org.alfresco.util;
import java.io.*;
import java.io.ByteArrayInputStream;
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 javax.xml.parsers.DocumentBuilder;
import javax.xml.parsers.DocumentBuilderFactory;
@@ -28,8 +39,12 @@ 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;
@@ -37,9 +52,19 @@ import org.alfresco.service.cmr.repository.ContentService;
import org.alfresco.service.cmr.repository.NodeRef;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import org.w3c.dom.*;
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.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.
@@ -114,75 +139,229 @@ public class XMLUtil
}
/** utility function for parsing xml */
public static Document parse(final String source)
public static Document parse(final String source, final XMLFilter... filters)
throws SAXException,
IOException
{
return XMLUtil.parse(new ByteArrayInputStream(source.getBytes("UTF-8")));
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));
}
/** utility function for parsing xml */
public static Document parse(final NodeRef nodeRef,
final ContentService contentService)
final ContentService contentService,
final XMLFilter... filters)
throws SAXException,
IOException
{
final ContentReader contentReader =
contentService.getReader(nodeRef, ContentModel.TYPE_CONTENT);
final InputStream in = contentReader.getContentInputStream();
return XMLUtil.parse(in);
return XMLUtil.parse(in, filters);
}
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 AVMService avmService,
final XMLFilter...filters)
throws SAXException,
IOException
{
return XMLUtil.parse(avmService.getFileInputStream(version, path));
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));
}
/** utility function for parsing xml */
public static Document parse(final File source)
public static Document parse(final File source,
final XMLFilter... filters)
throws SAXException,
IOException
{
return XMLUtil.parse(new FileInputStream(source));
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);
}
}
}
/** utility function for parsing xml */
public static Document parse(final InputStream source)
public static Document parse(final InputStream source, final XMLFilter... filters)
throws SAXException,
IOException
{
try
{
final DocumentBuilder db = XMLUtil.getDocumentBuilder();
return db.parse(source);
return parseWithXMLFilters(new InputSource(source), filters);
}
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)
public static Document parse(final Reader source,
final XMLFilter... filters)
throws SAXException,
IOException
{
try
{
final DocumentBuilder db = XMLUtil.getDocumentBuilder();
return db.parse(new InputSource(source));
return parseWithXMLFilters(new InputSource(source), filters);
}
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()
{
@@ -293,4 +472,76 @@ 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://xml.apache.org/xalan/java");
add("http://xml.apache.org/xslt/java");
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 (uri.startsWith(insecureURI)) return true;
}
return false;
}
}
}