VYPR
High severityNVD Advisory· Published Jun 15, 2021· Updated Aug 3, 2024

Opencast vulnerable to billion laughs attack (XML bomb)

CVE-2021-32623

Description

Opencast is a free and open source solution for automated video capture and distribution. Versions of Opencast prior to 9.6 are vulnerable to the billion laughs attack, which allows an attacker to easily execute a (seemingly permanent) denial of service attack, essentially taking down Opencast using a single HTTP request. To exploit this, users need to have ingest privileges, limiting the group of potential attackers The problem has been fixed in Opencast 9.6. There is no known workaround for this issue.

Affected packages

Versions sourced from the GitHub Security Advisory.

PackageAffected versionsPatched versions
org.opencastproject:opencast-kernelMaven
< 9.69.6

Affected products

1

Patches

2
8ae27da5a6f6

Clarifies debug options in setenv file (#2735)

https://github.com/opencast/opencastMaximiliano Lira Del CantoJun 15, 2021via ghsa
1 file changed · +5 1
  • assemblies/resources/bin/setenv+5 1 modified
    @@ -31,8 +31,12 @@
     # export KARAF_BASE        # Karaf base folder
     # export KARAF_ETC         # Karaf etc  folder
     # export KARAF_OPTS        # Additional Karaf options
    -# export KARAF_DEBUG       # Enable debug mode
     # export KARAF_REDIRECT    # Enable/set the std/err redirection when using bin/start
    +#
    +# Debug options
    +# export KARAF_DEBUG       # Enable debug mode
    +# export JAVA_DEBUG_PORT   # Set debug port (defaults to 5005)
    +
     
     export EXTRA_JAVA_OPTS="${EXTRA_JAVA_OPTS} -Dorg.eclipse.jetty.server.Request.maxFormContentSize=1500000 -Dfile.encoding=UTF-8"
     export JAVA_MAX_MEM="${JAVA_MAX_MEM:-1G}"
    
16b0d641713f

Merge pull request from GHSA-9gwx-9cwp-5c2m

https://github.com/opencast/opencastLars KiesowJun 14, 2021via ghsa
59 files changed · +859 165
  • docs/checkstyle/opencast-checkstyle.xml+75 0 modified
    @@ -218,6 +218,81 @@
           <property name="severity" value="error" />
         </module>
     
    +    <!-- Check for use of unsecured xml parsing           -->
    +    <module name="Regexp">
    +      <property name="format" value="TransformerFactory[.\s]+(?:newInstance|newDefaultInstance|newTransformer|newTemplates)" />
    +      <property name="message"
    +        value="Use the methods provided by the XmlSafeParser class for creating xml parsers, which are guarded against xxe and other attacks." />
    +      <property name="illegalPattern" value="true" />
    +      <property name="ignoreComments" value="true" />
    +      <property name="severity" value="error" />
    +    </module>
    +    <module name="Regexp">
    +      <property name="format" value="DocumentBuilderFactory[.\s]+(?:newInstance|newDefaultInstance)" />
    +      <property name="message"
    +        value="Use the methods provided by the XmlSafeParser class for creating xml parsers, which are guarded against xxe and other attacks." />
    +      <property name="illegalPattern" value="true" />
    +      <property name="ignoreComments" value="true" />
    +      <property name="severity" value="error" />
    +    </module>
    +    <module name="Regexp">
    +      <property name="format" value="SAXParserFactory[.\s]+(?:newInstance|newDefaultInstance)" />
    +      <property name="message"
    +        value="Use the methods provided by the XmlSafeParser class for creating xml parsers, which are guarded against xxe and other attacks." />
    +      <property name="illegalPattern" value="true" />
    +      <property name="ignoreComments" value="true" />
    +      <property name="severity" value="error" />
    +    </module>
    +    <module name="Regexp">
    +      <property name="format" value="new\s+SAXBuilder" />
    +      <property name="message"
    +        value="Use the methods provided by the XmlSafeParser class for creating xml parsers, which are guarded against xxe and other attacks." />
    +      <property name="illegalPattern" value="true" />
    +      <property name="ignoreComments" value="true" />
    +      <property name="severity" value="error" />
    +    </module>
    +    <module name="Regexp">
    +      <property name="format" value="\.\s*unmarshal\s*\(\s*(?!XmlSafeParser)" />
    +      <property name="message"
    +        value="Use the parse method provided by the XmlSafeParser class to guard against xxe, e.g.: .unmarshal(XmlSafeParser.parse(input))." />
    +      <property name="illegalPattern" value="true" />
    +      <property name="ignoreComments" value="true" />
    +      <property name="severity" value="error" />
    +    </module>
    +    <!-- Additional parser                               -->
    +    <module name="Regexp">
    +      <property name="format" value="(?:XMLInputFactory|SAXReader|XPathExpressionFactory|XMLDecoder|ParserAdapter|XMLReaderAdapter|DOMParser|SAXTransformerFactory|XMLReaderFactory)" />
    +      <property name="message"
    +        value="It seems like an XmlParser has been added that is not protected against xxe by default. Please consider using one of the pre-existing secured parsers provided by the XmlSafeParser class in the common module, or add a securely configured version of your parser to this class." />
    +      <property name="illegalPattern" value="true" />
    +      <property name="ignoreComments" value="true" />
    +      <property name="severity" value="error" />
    +    </module>
    +    <module name="Regexp">
    +      <property name="format" value="new\s+SAXParser" />
    +      <property name="message"
    +        value="It seems like an XmlParser has been added that is not protected against xxe by default. Please consider using one of the pre-existing secured parsers provided by the XmlSafeParser class in the common module, or add a securely configured version of your parser to this class." />
    +      <property name="illegalPattern" value="true" />
    +      <property name="ignoreComments" value="true" />
    +      <property name="severity" value="error" />
    +    </module>
    +    <module name="Regexp">
    +      <property name="format" value="SchemaFactory[.\s]+newInstance" />
    +      <property name="message"
    +        value="It seems like an XmlParser has been added that is not protected against xxe by default. Please consider using one of the pre-existing secured parsers provided by the XmlSafeParser class in the common module, or add a securely configured version of your parser to this class." />
    +      <property name="illegalPattern" value="true" />
    +      <property name="ignoreComments" value="true" />
    +      <property name="severity" value="error" />
    +    </module>
    +    <module name="Regexp">
    +      <property name="format" value="createLSParser" />
    +      <property name="message"
    +        value="It seems like an XmlParser has been added that is not protected against xxe by default. Please consider using one of the pre-existing secured parsers provided by the XmlSafeParser class in the common module, or add a securely configured version of your parser to this class." />
    +      <property name="illegalPattern" value="true" />
    +      <property name="ignoreComments" value="true" />
    +      <property name="severity" value="error" />
    +    </module>
    +
         <!-- Miscellaneous other checks.                   -->
         <!-- See http://checkstyle.sf.net/config_misc.html -->
         <module name="ArrayTypeStyle">
    
  • modules/authorization-manager/src/test/java/org/opencastproject/authorization/xacml/manager/impl/AclScannerTest.java+3 4 modified
    @@ -43,14 +43,13 @@
     import org.easymock.EasyMock;
     import org.junit.Before;
     import org.junit.Test;
    +import org.xml.sax.SAXParseException;
     
     import java.io.File;
     import java.util.ArrayList;
     import java.util.HashMap;
     import java.util.List;
     
    -import javax.xml.bind.UnmarshalException;
    -
     public class AclScannerTest {
     
       private AclDb aclDb;
    @@ -120,7 +119,7 @@ public void testCorruptedFileInstall() throws Exception {
           aclScanner.install(file);
           fail("Should not be parsed.");
         } catch (XACMLParsingException e) {
    -      assertTrue("The file can not be parsed.", e.getCause() instanceof UnmarshalException);
    +      assertTrue("The file can not be parsed.", e.getCause() instanceof SAXParseException);
         }
       }
     
    @@ -171,7 +170,7 @@ public void testCorruptedFileUpdate() throws Exception {
           aclScanner.update(file);
           fail("Should not be parsed.");
         } catch (XACMLParsingException e) {
    -      assertTrue("The file can not be parsed.", e.getCause() instanceof UnmarshalException);
    +      assertTrue("The file can not be parsed.", e.getCause() instanceof SAXParseException);
         }
       }
     
    
  • modules/authorization-xacml/src/main/java/org/opencastproject/authorization/xacml/XACMLUtils.java+2 1 modified
    @@ -24,6 +24,7 @@
     import org.opencastproject.mediapackage.MediaPackage;
     import org.opencastproject.security.api.AccessControlEntry;
     import org.opencastproject.security.api.AccessControlList;
    +import org.opencastproject.util.XmlSafeParser;
     
     import org.jboss.security.xacml.core.model.policy.ActionMatchType;
     import org.jboss.security.xacml.core.model.policy.ActionType;
    @@ -114,7 +115,7 @@ public static AccessControlList parseXacml(InputStream xacml) throws XACMLParsin
           @SuppressWarnings("unchecked")
           final AccessControlList acl = new AccessControlList();
           final List<AccessControlEntry> entries = acl.getEntries();
    -      final PolicyType policy = ((JAXBElement<PolicyType>) XACMLUtils.jBossXacmlJaxbContext.createUnmarshaller().unmarshal(xacml)).getValue();
    +      final PolicyType policy = ((JAXBElement<PolicyType>) XACMLUtils.jBossXacmlJaxbContext.createUnmarshaller().unmarshal(XmlSafeParser.parse(xacml))).getValue();
           for (Object object : policy.getCombinerParametersOrRuleCombinerParametersOrVariableDefinition()) {
     
             if (!(object instanceof RuleType)) {
    
  • modules/caption-impl/src/main/java/org/opencastproject/caption/converters/DFXPCaptionConverter.java+5 7 modified
    @@ -31,6 +31,7 @@
     import org.opencastproject.caption.util.TimeUtil;
     import org.opencastproject.mediapackage.MediaPackageElement;
     import org.opencastproject.mediapackage.MediaPackageElement.Type;
    +import org.opencastproject.util.XmlSafeParser;
     
     import org.apache.commons.io.IOUtils;
     import org.slf4j.Logger;
    @@ -52,7 +53,6 @@
     import java.util.List;
     
     import javax.xml.parsers.DocumentBuilder;
    -import javax.xml.parsers.DocumentBuilderFactory;
     import javax.xml.parsers.ParserConfigurationException;
     import javax.xml.parsers.SAXParser;
     import javax.xml.parsers.SAXParserFactory;
    @@ -89,8 +89,7 @@ public List<Caption> importCaption(InputStream in, String language) throws Capti
     
         Document doc;
         try {
    -      DocumentBuilderFactory factory = DocumentBuilderFactory.newInstance();
    -      DocumentBuilder builder = factory.newDocumentBuilder();
    +      DocumentBuilder builder = XmlSafeParser.newDocumentBuilderFactory().newDocumentBuilder();
           doc = builder.parse(in);
           doc.getDocumentElement().normalize();
         } catch (ParserConfigurationException e) {
    @@ -206,11 +205,10 @@ private String getTextCore(Node p) {
       @Override
       public void exportCaption(OutputStream outputStream, List<Caption> captions, String language) throws IOException {
         // get document builder factory and parse template
    -    DocumentBuilderFactory factory = DocumentBuilderFactory.newInstance();
         Document doc = null;
         InputStream is = null;
         try {
    -      DocumentBuilder builder = factory.newDocumentBuilder();
    +      DocumentBuilder builder = XmlSafeParser.newDocumentBuilderFactory().newDocumentBuilder();
           // load dfxp template from file
           is = DFXPCaptionConverter.class.getResourceAsStream("/templates/template.dfxp.xml");
           doc = builder.parse(is);
    @@ -254,7 +252,7 @@ public void exportCaption(OutputStream outputStream, List<Caption> captions, Str
         OutputStreamWriter osw = new OutputStreamWriter(outputStream, "UTF-8");
         StreamResult result = new StreamResult(osw);
         DOMSource source = new DOMSource(doc);
    -    TransformerFactory tfactory = TransformerFactory.newInstance();
    +    TransformerFactory tfactory = XmlSafeParser.newTransformerFactory();
         Transformer transformer;
         try {
           transformer = tfactory.newTransformer();
    @@ -283,7 +281,7 @@ public String[] getLanguageList(InputStream input) throws CaptionConverterExcept
         final List<String> langList = new LinkedList<String>();
     
         // get SAX parser
    -    SAXParserFactory factory = SAXParserFactory.newInstance();
    +    SAXParserFactory factory = XmlSafeParser.newSAXParserFactory();
         try {
           SAXParser parser = factory.newSAXParser();
           // create handler
    
  • modules/caption-impl/src/main/java/org/opencastproject/caption/converters/Mpeg7CaptionConverter.java+2 2 modified
    @@ -42,6 +42,7 @@
     import org.opencastproject.metadata.mpeg7.Mpeg7CatalogImpl;
     import org.opencastproject.metadata.mpeg7.TemporalDecomposition;
     import org.opencastproject.metadata.mpeg7.TextAnnotation;
    +import org.opencastproject.util.XmlSafeParser;
     
     import org.slf4j.Logger;
     import org.slf4j.LoggerFactory;
    @@ -61,7 +62,6 @@
     import javax.xml.transform.Transformer;
     import javax.xml.transform.TransformerConfigurationException;
     import javax.xml.transform.TransformerException;
    -import javax.xml.transform.TransformerFactory;
     import javax.xml.transform.TransformerFactoryConfigurationError;
     import javax.xml.transform.dom.DOMSource;
     import javax.xml.transform.stream.StreamResult;
    @@ -219,7 +219,7 @@ public void exportCaption(OutputStream outputStream, List<Caption> captions, Str
     
         Transformer tf = null;
         try {
    -      tf = TransformerFactory.newInstance().newTransformer();
    +      tf = XmlSafeParser.newTransformerFactory().newTransformer();
           DOMSource xmlSource = new DOMSource(mpeg7.toXml());
           tf.transform(xmlSource, new StreamResult(outputStream));
         } catch (TransformerConfigurationException e) {
    
  • modules/caption-impl/src/main/java/org/opencastproject/caption/endpoint/CaptionServiceRestEndpoint.java+3 5 modified
    @@ -30,6 +30,7 @@
     import org.opencastproject.mediapackage.MediaPackageElementParser;
     import org.opencastproject.rest.AbstractJobProducerEndpoint;
     import org.opencastproject.serviceregistry.api.ServiceRegistry;
    +import org.opencastproject.util.XmlSafeParser;
     import org.opencastproject.util.doc.rest.RestParameter;
     import org.opencastproject.util.doc.rest.RestQuery;
     import org.opencastproject.util.doc.rest.RestResponse;
    @@ -52,9 +53,7 @@
     import javax.ws.rs.core.MediaType;
     import javax.ws.rs.core.Response;
     import javax.xml.parsers.DocumentBuilder;
    -import javax.xml.parsers.DocumentBuilderFactory;
     import javax.xml.transform.Transformer;
    -import javax.xml.transform.TransformerFactory;
     import javax.xml.transform.dom.DOMSource;
     import javax.xml.transform.stream.StreamResult;
     
    @@ -192,7 +191,7 @@ public Response languages(@FormParam("input") String inputType, @FormParam("capt
           String[] languageArray = service.getLanguageList((Catalog) element, inputType);
     
           // build response
    -      DocumentBuilder docBuilder = DocumentBuilderFactory.newInstance().newDocumentBuilder();
    +      DocumentBuilder docBuilder = XmlSafeParser.newDocumentBuilderFactory().newDocumentBuilder();
           Document doc = docBuilder.newDocument();
           Element root = doc.createElement("languages");
           root.setAttribute("type", inputType);
    @@ -206,8 +205,7 @@ public Response languages(@FormParam("input") String inputType, @FormParam("capt
           DOMSource domSource = new DOMSource(root);
           StringWriter writer = new StringWriter();
           StreamResult result = new StreamResult(writer);
    -      Transformer transformer;
    -      transformer = TransformerFactory.newInstance().newTransformer();
    +      Transformer transformer = XmlSafeParser.newTransformerFactory().newTransformer();
           transformer.transform(domSource, result);
     
           return Response.status(Response.Status.OK).entity(writer.toString()).build();
    
  • modules/caption-remote/src/main/java/org/opencastproject/caption/remote/CaptionServiceRemoteImpl.java+2 3 modified
    @@ -30,6 +30,7 @@
     import org.opencastproject.mediapackage.MediaPackageElementParser;
     import org.opencastproject.mediapackage.MediaPackageException;
     import org.opencastproject.serviceregistry.api.RemoteBase;
    +import org.opencastproject.util.XmlSafeParser;
     
     import org.apache.commons.lang3.StringUtils;
     import org.apache.http.HttpResponse;
    @@ -46,8 +47,6 @@
     import java.util.ArrayList;
     import java.util.List;
     
    -import javax.xml.parsers.DocumentBuilderFactory;
    -
     /**
      * Proxies a set of remote composer services for use as a JVM-local service. Remote services are selected at random.
      */
    @@ -127,7 +126,7 @@ public String[] getLanguageList(MediaPackageElement input, String format)
           response = getResponse(post);
           if (response != null) {
             List<String> langauges = new ArrayList<String>();
    -        Document doc = DocumentBuilderFactory.newInstance().newDocumentBuilder()
    +        Document doc = XmlSafeParser.newDocumentBuilderFactory().newDocumentBuilder()
                     .parse(EntityUtils.toString(response.getEntity(), "UTF-8"));
             NodeList languages = doc.getElementsByTagName("languages");
             for (int i = 0; i < languages.getLength(); i++) {
    
  • modules/common/pom.xml+6 1 modified
    @@ -109,7 +109,6 @@
         <dependency>
           <groupId>org.slf4j</groupId>
           <artifactId>slf4j-api</artifactId>
    -      <scope>provided</scope>
         </dependency>
         <!-- REST test environment -->
         <dependency>
    @@ -137,6 +136,12 @@
           <artifactId>hamcrest</artifactId>
           <scope>test</scope>
         </dependency>
    +    <dependency>
    +      <groupId>net.sf.saxon</groupId>
    +      <artifactId>Saxon-HE</artifactId>
    +      <version>9.6.0-4</version>
    +      <scope>test</scope>
    +    </dependency>
         <!--
         - Parameterized tests for JUnit
         - https://github.com/Pragmatists/JUnitParams
    
  • modules/common/src/main/java/org/opencastproject/job/api/JobParser.java+4 3 modified
    @@ -21,6 +21,8 @@
     
     package org.opencastproject.job.api;
     
    +import org.opencastproject.util.XmlSafeParser;
    +
     import org.apache.commons.io.IOUtils;
     
     import java.io.IOException;
    @@ -32,7 +34,6 @@
     import javax.xml.bind.JAXBException;
     import javax.xml.bind.Marshaller;
     import javax.xml.bind.Unmarshaller;
    -import javax.xml.transform.stream.StreamSource;
     
     /**
      * Marshals and unmarshals {@link Job}s.
    @@ -76,7 +77,7 @@ public static Job parseJob(InputStream in) throws IOException {
         Unmarshaller unmarshaller;
         try {
           unmarshaller = jaxbContext.createUnmarshaller();
    -      return unmarshaller.unmarshal(new StreamSource(in), JaxbJob.class).getValue().toJob();
    +      return unmarshaller.unmarshal(XmlSafeParser.parse(in), JaxbJob.class).getValue().toJob();
         } catch (Exception e) {
           throw new IOException(e);
         } finally {
    @@ -126,7 +127,7 @@ public static JaxbJobList parseJobList(InputStream in) throws IOException {
         Unmarshaller unmarshaller;
         try {
           unmarshaller = jaxbContext.createUnmarshaller();
    -      return unmarshaller.unmarshal(new StreamSource(in), JaxbJobList.class).getValue();
    +      return unmarshaller.unmarshal(XmlSafeParser.parse(in), JaxbJobList.class).getValue();
         } catch (Exception e) {
           throw new IOException(e);
         } finally {
    
  • modules/common/src/main/java/org/opencastproject/mediapackage/AbstractMediaPackageElement.java+3 0 modified
    @@ -562,7 +562,10 @@ public Object clone() {
           marshaller.marshal(this, out);
           Unmarshaller unmarshaller = MediaPackageImpl.context.createUnmarshaller();
           in = new ByteArrayInputStream(out.toByteArray());
    +      // CHECKSTYLE:OFF
    +      // in was already parsed and is therefore save
           return unmarshaller.unmarshal(in);
    +      // CHECKSTYLE:ON
         } catch (JAXBException e) {
           throw new RuntimeException(e.getLinkedException() != null ? e.getLinkedException() : e);
         } finally {
    
  • modules/common/src/main/java/org/opencastproject/mediapackage/MediaPackageElementParser.java+6 2 modified
    @@ -23,10 +23,12 @@
     
     import static org.apache.commons.io.IOUtils.toInputStream;
     
    +import org.opencastproject.util.XmlSafeParser;
     import org.opencastproject.util.data.Function;
     
    -import org.xml.sax.InputSource;
    +import org.xml.sax.SAXException;
     
    +import java.io.IOException;
     import java.io.StringWriter;
     import java.util.Collection;
     import java.util.Iterator;
    @@ -95,9 +97,11 @@ public static MediaPackageElement getFromXml(String xml) throws MediaPackageExce
         Unmarshaller m = null;
         try {
           m = MediaPackageImpl.context.createUnmarshaller();
    -      return (MediaPackageElement) m.unmarshal(new InputSource(toInputStream(xml)));
    +      return (MediaPackageElement) m.unmarshal(XmlSafeParser.parse(toInputStream(xml)));
         } catch (JAXBException e) {
           throw new MediaPackageException(e.getLinkedException() != null ? e.getLinkedException() : e);
    +    } catch (IOException | SAXException e) {
    +      throw new MediaPackageException(e);
         }
       }
     
    
  • modules/common/src/main/java/org/opencastproject/mediapackage/MediaPackageImpl.java+9 1 modified
    @@ -30,6 +30,7 @@
     import org.opencastproject.mediapackage.identifier.IdImpl;
     import org.opencastproject.util.DateTimeSupport;
     import org.opencastproject.util.IoSupport;
    +import org.opencastproject.util.XmlSafeParser;
     
     import org.apache.commons.io.IOUtils;
     import org.apache.commons.lang3.StringUtils;
    @@ -40,6 +41,7 @@
     import org.w3c.dom.ls.DOMImplementationLS;
     import org.w3c.dom.ls.LSOutput;
     import org.w3c.dom.ls.LSSerializer;
    +import org.xml.sax.SAXException;
     
     import java.io.ByteArrayInputStream;
     import java.io.ByteArrayOutputStream;
    @@ -1201,9 +1203,11 @@ public MediaPackage unmarshal(MediaPackageImpl mp) throws Exception {
       public static MediaPackageImpl valueOf(InputStream xml) throws MediaPackageException {
         try {
           Unmarshaller unmarshaller = context.createUnmarshaller();
    -      return unmarshaller.unmarshal(new StreamSource(xml), MediaPackageImpl.class).getValue();
    +      return unmarshaller.unmarshal(XmlSafeParser.parse(xml), MediaPackageImpl.class).getValue();
         } catch (JAXBException e) {
           throw new MediaPackageException(e.getLinkedException() != null ? e.getLinkedException() : e);
    +    } catch (IOException | SAXException e) {
    +      throw new MediaPackageException(e);
         } finally {
           IoSupport.closeQuietly(xml);
         }
    @@ -1228,10 +1232,14 @@ public static MediaPackageImpl valueOf(Node xml) throws MediaPackageException {
           LSOutput output = impl.createLSOutput();
           output.setEncoding("UTF-8");
           output.setByteStream(out);
    +      // This is safe because the Node was already parsed
           serializer.write(xml, output);
     
           try (InputStream in = new ByteArrayInputStream(out.toByteArray())) {
    +        // CHECKSTYLE:OFF
    +        // in was already parsed, therefore this is save
             return unmarshaller.unmarshal(new StreamSource(in), MediaPackageImpl.class).getValue();
    +        // CHECKSTYLE:ON
           }
         } catch (Exception e) {
           throw new MediaPackageException("Error deserializing media package node", e);
    
  • modules/common/src/main/java/org/opencastproject/mediapackage/MediaPackageParser.java+3 2 modified
    @@ -24,6 +24,7 @@
     import static org.opencastproject.util.data.functions.Misc.chuck;
     
     import org.opencastproject.util.DateTimeSupport;
    +import org.opencastproject.util.XmlSafeParser;
     
     import org.apache.commons.lang3.StringUtils;
     import org.codehaus.jettison.mapped.Configuration;
    @@ -138,7 +139,7 @@ public static Document getAsXmlDocument(MediaPackage mp) {
     
       /** Create a new DOM document. */
       private static Document newDocument() {
    -    final DocumentBuilderFactory docBuilderFactory = DocumentBuilderFactory.newInstance();
    +    final DocumentBuilderFactory docBuilderFactory = XmlSafeParser.newDocumentBuilderFactory();
         docBuilderFactory.setNamespaceAware(true);
         try {
           return docBuilderFactory.newDocumentBuilder().newDocument();
    @@ -164,7 +165,7 @@ private static Document newDocument() {
        */
       public static Document getAsXml(MediaPackage mediaPackage, MediaPackageSerializer serializer)
               throws MediaPackageException {
    -    DocumentBuilderFactory docBuilderFactory = DocumentBuilderFactory.newInstance();
    +    DocumentBuilderFactory docBuilderFactory = XmlSafeParser.newDocumentBuilderFactory();
         docBuilderFactory.setNamespaceAware(true);
     
         DocumentBuilder docBuilder = null;
    
  • modules/common/src/main/java/org/opencastproject/mediapackage/XMLCatalogImpl.java+2 1 modified
    @@ -32,6 +32,7 @@
     import org.opencastproject.util.RequireUtil;
     import org.opencastproject.util.XmlNamespaceBinding;
     import org.opencastproject.util.XmlNamespaceContext;
    +import org.opencastproject.util.XmlSafeParser;
     
     import com.entwinemedia.fn.Fn;
     import com.entwinemedia.fn.Fns;
    @@ -456,7 +457,7 @@ protected boolean equal(Object a, Object b) {
        *           If the xml parser environment is not correctly configured
        */
       protected Document newDocument() throws ParserConfigurationException {
    -    DocumentBuilderFactory docBuilderFactory = DocumentBuilderFactory.newInstance();
    +    DocumentBuilderFactory docBuilderFactory = XmlSafeParser.newDocumentBuilderFactory();
         docBuilderFactory.setNamespaceAware(true);
         DocumentBuilder docBuilder = docBuilderFactory.newDocumentBuilder();
         return docBuilder.newDocument();
    
  • modules/common/src/main/java/org/opencastproject/security/api/AccessControlParser.java+3 2 modified
    @@ -23,6 +23,8 @@
     
     import static org.opencastproject.util.data.functions.Misc.chuck;
     
    +import org.opencastproject.util.XmlSafeParser;
    +
     import org.apache.commons.io.IOUtils;
     import org.json.simple.JSONArray;
     import org.json.simple.JSONObject;
    @@ -39,7 +41,6 @@
     import javax.xml.bind.JAXBException;
     import javax.xml.bind.Marshaller;
     import javax.xml.bind.Unmarshaller;
    -import javax.xml.transform.stream.StreamSource;
     
     /**
      * Marshals and unmarshals {@link AccessControlList}s to/from XML.
    @@ -185,7 +186,7 @@ private static AccessControlList parseXml(InputStream in) throws IOException, Ac
         Unmarshaller unmarshaller;
         try {
           unmarshaller = jaxbContext.createUnmarshaller();
    -      return unmarshaller.unmarshal(new StreamSource(in), AccessControlList.class).getValue();
    +      return unmarshaller.unmarshal(XmlSafeParser.parse(in), AccessControlList.class).getValue();
         } catch (Exception e) {
           if (e instanceof IOException) {
             throw (IOException) e;
    
  • modules/common/src/main/java/org/opencastproject/security/api/OrganizationParser.java+7 2 modified
    @@ -21,8 +21,12 @@
     
     package org.opencastproject.security.api;
     
    +import org.opencastproject.util.XmlSafeParser;
    +
     import org.apache.commons.io.IOUtils;
    +import org.xml.sax.SAXException;
     
    +import java.io.IOException;
     import java.io.InputStream;
     import java.io.StringWriter;
     import java.io.Writer;
    @@ -31,7 +35,6 @@
     import javax.xml.bind.JAXBException;
     import javax.xml.bind.Marshaller;
     import javax.xml.bind.Unmarshaller;
    -import javax.xml.transform.stream.StreamSource;
     
     /**
      * Marshals and unmarshalls {@link Organization}s to/from XML.
    @@ -60,9 +63,11 @@ public static Organization fromXml(String xml) {
         try {
           in = IOUtils.toInputStream(xml);
           Unmarshaller unmarshaller = jaxbContext.createUnmarshaller();
    -      return unmarshaller.unmarshal(new StreamSource(in), JaxbOrganization.class).getValue();
    +      return unmarshaller.unmarshal(XmlSafeParser.parse(in), JaxbOrganization.class).getValue();
         } catch (JAXBException e) {
           throw new IllegalStateException(e.getLinkedException() != null ? e.getLinkedException() : e);
    +    } catch (IOException | SAXException e) {
    +      throw new IllegalStateException(e);
         } finally {
           IOUtils.closeQuietly(in);
         }
    
  • modules/common/src/main/java/org/opencastproject/security/api/UserParser.java+7 2 modified
    @@ -21,8 +21,12 @@
     
     package org.opencastproject.security.api;
     
    +import org.opencastproject.util.XmlSafeParser;
    +
     import org.apache.commons.io.IOUtils;
    +import org.xml.sax.SAXException;
     
    +import java.io.IOException;
     import java.io.InputStream;
     import java.io.StringWriter;
     import java.io.Writer;
    @@ -31,7 +35,6 @@
     import javax.xml.bind.JAXBException;
     import javax.xml.bind.Marshaller;
     import javax.xml.bind.Unmarshaller;
    -import javax.xml.transform.stream.StreamSource;
     
     /**
      * Marshals and unmarshalls {@link User}s to/from XML.
    @@ -59,9 +62,11 @@ public static User fromXml(String xml) {
         try {
           in = IOUtils.toInputStream(xml);
           Unmarshaller unmarshaller = jaxbContext.createUnmarshaller();
    -      return unmarshaller.unmarshal(new StreamSource(in), JaxbUser.class).getValue();
    +      return unmarshaller.unmarshal(XmlSafeParser.parse(in), JaxbUser.class).getValue();
         } catch (JAXBException e) {
           throw new IllegalStateException(e.getLinkedException() != null ? e.getLinkedException() : e);
    +    } catch (IOException | SAXException e) {
    +      throw new IllegalStateException((Throwable) e);
         } finally {
           IOUtils.closeQuietly(in);
         }
    
  • modules/common/src/main/java/org/opencastproject/util/jaxb/JaxbParser.java+3 2 modified
    @@ -23,6 +23,8 @@
     
     import static org.opencastproject.util.data.functions.Misc.chuck;
     
    +import org.opencastproject.util.XmlSafeParser;
    +
     import org.apache.commons.io.IOUtils;
     
     import java.io.IOException;
    @@ -34,7 +36,6 @@
     import javax.xml.bind.JAXBException;
     import javax.xml.bind.Marshaller;
     import javax.xml.bind.Unmarshaller;
    -import javax.xml.transform.stream.StreamSource;
     
     /** Base class for JAXB parser classes. */
     public abstract class JaxbParser {
    @@ -65,7 +66,7 @@ public JAXBContext getCtx() {
       public <A> A unmarshal(Class<A> dtoClass, InputStream source) throws IOException {
         try {
           final Unmarshaller unmarshaller = ctx.createUnmarshaller();
    -      return unmarshaller.unmarshal(new StreamSource(source), dtoClass).getValue();
    +      return unmarshaller.unmarshal(XmlSafeParser.parse(source), dtoClass).getValue();
         } catch (Exception e) {
           throw new IOException(e);
         } finally {
    
  • modules/common/src/main/java/org/opencastproject/util/MimeTypes.java+1 3 modified
    @@ -50,7 +50,6 @@
     
     import javax.xml.parsers.ParserConfigurationException;
     import javax.xml.parsers.SAXParser;
    -import javax.xml.parsers.SAXParserFactory;
     
     /**
      * This class represents the mime type registry that is responsible for providing resolving mime types through all
    @@ -122,8 +121,7 @@ private MimeTypes() {
     
         // initialize from file
         try {
    -      SAXParserFactory parserFactory = SAXParserFactory.newInstance();
    -      SAXParser parser = parserFactory.newSAXParser();
    +      SAXParser parser = XmlSafeParser.newSAXParserFactory().newSAXParser();
           DefaultHandler handler = new MimeTypeParser(mimeTypes);
     
           try (InputStream inputStream = MimeTypes.class.getResourceAsStream(DEFINITION_FILE)) {
    
  • modules/common/src/main/java/org/opencastproject/util/XmlSafeParser.java+190 0 added
    @@ -0,0 +1,190 @@
    +/**
    + * Licensed to The Apereo Foundation under one or more contributor license
    + * agreements. See the NOTICE file distributed with this work for additional
    + * information regarding copyright ownership.
    + *
    + *
    + * The Apereo Foundation licenses this file to you under the Educational
    + * Community License, Version 2.0 (the "License"); you may not use this file
    + * except in compliance with the License. You may obtain a copy of the License
    + * at:
    + *
    + *   http://opensource.org/licenses/ecl2.txt
    + *
    + * Unless required by applicable law or agreed to in writing, software
    + * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
    + * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.  See the
    + * License for the specific language governing permissions and limitations under
    + * the License.
    + *
    + */
    +
    +package org.opencastproject.util;
    +
    +import org.slf4j.Logger;
    +import org.slf4j.LoggerFactory;
    +import org.w3c.dom.Document;
    +import org.xml.sax.InputSource;
    +import org.xml.sax.SAXException;
    +
    +import java.io.IOException;
    +import java.io.InputStream;
    +
    +import javax.xml.XMLConstants;
    +import javax.xml.parsers.DocumentBuilder;
    +import javax.xml.parsers.DocumentBuilderFactory;
    +import javax.xml.parsers.SAXParserFactory;
    +import javax.xml.transform.TransformerFactory;
    +
    +
    +/** Preconfigured XML parsers, which are safeguarded against XXE and billion laugh attacks. */
    +public final class XmlSafeParser {
    +
    +  private static final Logger logger = LoggerFactory.getLogger(XmlSafeParser.class);
    +
    +  private XmlSafeParser() {
    +  }
    +
    +  /**
    +   * Creates a preconfigured DocumentBuilderFactory, which is guarded against XXE and billion laugh attacks.
    +   * @return the preconfigured DocumentBuilderFactory
    +   */
    +  public static DocumentBuilderFactory newDocumentBuilderFactory() {
    +    // CHECKSTYLE:OFF
    +    DocumentBuilderFactory f = DocumentBuilderFactory.newInstance();
    +    // CHECKSTYLE:ON
    +    // prevent XXE see
    +    // https://cheatsheetseries.owasp.org/cheatsheets/XML_External_Entity_Prevention_Cheat_Sheet.html
    +    // for more information
    +    try {
    +      f.setFeature("http://apache.org/xml/features/disallow-doctype-decl", true);
    +      f.setFeature("http://xml.org/sax/features/external-general-entities", false);
    +      f.setFeature("http://xml.org/sax/features/external-parameter-entities", false);
    +      f.setFeature("http://apache.org/xml/features/nonvalidating/load-external-dtd", false);
    +      f.setXIncludeAware(false);
    +      f.setExpandEntityReferences(false);
    +    }
    +    catch (Exception e) {
    +      // this shouldn't occur
    +      logger.error("Failed to configure safe DocumentBuilderFactory to prevent XXE.");
    +      throw new AssertionError("Failed to configure safe DocumentBuilderFactory to prevent XXE.", e);
    +    }
    +
    +    return f;
    +  }
    +
    +  /**
    +   * Creates a preconfigured SAXParserFactory, which is guarded against XXE and billion laugh attacks.
    +   * @return the preconfigured SAXParserFactory
    +   */
    +  public static SAXParserFactory newSAXParserFactory() {
    +    // CHECKSTYLE:OFF
    +    SAXParserFactory f = SAXParserFactory.newInstance();
    +    // CHECKSTYLE:ON
    +
    +    try {
    +      f.setFeature("http://xml.org/sax/features/external-general-entities", false);
    +      f.setFeature("http://xml.org/sax/features/external-parameter-entities", false);
    +      f.setFeature("http://apache.org/xml/features/nonvalidating/load-external-dtd", false);
    +      f.setFeature("http://apache.org/xml/features/disallow-doctype-decl", true);
    +    }
    +    catch (Exception e) {
    +      // this shouldn't occur
    +      logger.error("Failed to configure safe SAXParserFactory to prevent XXE.");
    +      throw new AssertionError("Failed to configure safe SAXParserFactory to prevent XXE.", e);
    +    }
    +
    +    return f;
    +  }
    +
    +  /**
    +   * Creates a preconfigured default TransformerFactory, which is guarded against XXE and billion laugh attacks.
    +   * @return the preconfigured TransformerFactory
    +   */
    +  // CHECKSTYLE:OFF
    +  public static TransformerFactory newTransformerFactory() {
    +    return configureTransformerFactory(TransformerFactory.newInstance("com.sun.org.apache.xalan.internal.xsltc.trax.TransformerFactoryImpl", null));
    +  }
    +  // CHECKSTYLE:ON
    +
    +  /**
    +   * Configures a TransformerFactory, to guard it against XXE and billion laugh attacks.
    +   * Supports the default Transformer and the Saxon Transformer.
    +   * The returned TransformerFactory is the same as the passed TranformerFactory.
    +   * @param f the TransformerFactory to configure
    +   * @return the configured Factory
    +   */
    +  public static TransformerFactory configureTransformerFactory(TransformerFactory f) {
    +    try {
    +      if (f.getClass() == com.sun.org.apache.xalan.internal.xsltc.trax.TransformerFactoryImpl.class) {
    +        f.setFeature(XMLConstants.FEATURE_SECURE_PROCESSING, true);
    +        f.setAttribute(XMLConstants.ACCESS_EXTERNAL_DTD, "");
    +        f.setAttribute(XMLConstants.ACCESS_EXTERNAL_STYLESHEET, "");
    +        f.setAttribute("http://www.oracle.com/xml/jaxp/properties/entityExpansionLimit", "1");
    +      }
    +      else if (f.getClass().getName().equals("net.sf.saxon.TransformerFactoryImpl")) {
    +        f.setAttribute("http://saxon.sf.net/feature/parserFeature?uri=http://apache.org/xml/features/disallow-doctype-decl", true);
    +      }
    +      else {
    +        throw new AssertionError("Unknown TransformerFactory " + f.getClass().getName());
    +      }
    +    }
    +    catch (Exception e) {
    +      // this shouldn't occur
    +      logger.error("Failed to configure safe TransformerFactory to prevent XXE.");
    +      throw new AssertionError("Failed to configure safe TransformerFactory to prevent XXE.", e);
    +    }
    +
    +    return f;
    +  }
    +
    +  /**
    +   * Parse a XML Document with a parser, which is guarded against XXE and billion laugh attacks.
    +   * The parsing is namespace aware.
    +   * Designed for checking documents for XXE and billion laugh attacks before further parsing
    +   * the returned document with the Unmarshaller, which can't be safely configured.
    +   * @param in the document to parse
    +   * @return the parsed document
    +   */
    +  public static Document parse(InputStream in) throws IOException, SAXException {
    +    return parse(new InputSource(in));
    +  }
    +
    +  /**
    +   * The DocumentBuilder for the parse methods.
    +   * Creating a DocumentBuilder is quite expensive and DocumentBuilder is not thread-safe,
    +   * therefore we create a DocumentBuilder for each Thread.
    +   */
    +  private static ThreadLocal<DocumentBuilder> db = new ThreadLocal<DocumentBuilder>() {
    +          @Override
    +          protected DocumentBuilder initialValue() {
    +            DocumentBuilderFactory dbf = newDocumentBuilderFactory();
    +            DocumentBuilder d = null;
    +            try {
    +              dbf.setNamespaceAware(true);
    +              d = dbf.newDocumentBuilder();
    +            }
    +            catch (Exception e) {
    +              // this shouldn't occur
    +              logger.error("Failed to configure safe DocumentBuilder to prevent XXE.");
    +              throw new AssertionError("Failed to configure safe DocumentBuilder to prevent XXE.", e);
    +            }
    +
    +            return d;
    +          }
    +  };
    +
    +  /**
    +   * Parse a XML Document with a parser, which is guarded against XXE and billion laugh attacks.
    +   * The parsing is namespace aware.
    +   * Designed for checking documents for XXE and billion laugh attacks before further parsing
    +   * the returned document with the Unmarshaller, which can't be safely configured.
    +   * @param s the document to parse
    +   * @return the parsed document
    +   */
    +  public static Document parse(InputSource s) throws IOException, SAXException {
    +    // Use ThreadLocal DocumentBuilder to avoid building a new DocumentBuilder on each call.
    +    return db.get().parse(s);
    +  }
    +
    +}
    
  • modules/common/src/main/java/org/opencastproject/util/XmlUtil.java+4 4 modified
    @@ -43,7 +43,6 @@
     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.DOMSource;
     import javax.xml.transform.stream.StreamResult;
     
    @@ -53,10 +52,10 @@ public final class XmlUtil {
       private static final DocumentBuilderFactory dbf;
     
       static {
    -    nsDbf = DocumentBuilderFactory.newInstance();
    +    nsDbf = XmlSafeParser.newDocumentBuilderFactory();
         nsDbf.setNamespaceAware(true);
         //
    -    dbf = DocumentBuilderFactory.newInstance();
    +    dbf = XmlSafeParser.newDocumentBuilderFactory();
         dbf.setNamespaceAware(false);
       }
     
    @@ -92,7 +91,8 @@ public static void toXml(Document doc, OutputStream out) throws IOException {
         try {
           DOMSource domSource = new DOMSource(doc);
           StreamResult result = new StreamResult(out);
    -      Transformer transformer = TransformerFactory.newInstance().newTransformer();
    +      Transformer transformer = XmlSafeParser.newTransformerFactory()
    +              .newTransformer();
           transformer.setOutputProperty(OutputKeys.VERSION, doc.getXmlVersion());
           transformer.transform(domSource, result);
         } catch (TransformerException e) {
    
  • modules/common/src/test/java/org/opencastproject/mediapackage/MediaPackageBuilderTest.java+2 2 modified
    @@ -28,6 +28,7 @@
     
     import org.opencastproject.util.MimeType;
     import org.opencastproject.util.MimeTypes;
    +import org.opencastproject.util.XmlSafeParser;
     
     import org.apache.commons.io.IOUtils;
     import org.junit.Test;
    @@ -38,7 +39,6 @@
     import java.net.URI;
     
     import javax.xml.parsers.DocumentBuilder;
    -import javax.xml.parsers.DocumentBuilderFactory;
     
     /**
      * Test case used to make sure the media package builder works as expected.
    @@ -110,7 +110,7 @@ public void testLoadPublicationElement() throws Exception {
        */
       @Test
       public void testLoadFromNode() throws Exception {
    -    DocumentBuilder docBuilder = DocumentBuilderFactory.newInstance().newDocumentBuilder();
    +    DocumentBuilder docBuilder = XmlSafeParser.newDocumentBuilderFactory().newDocumentBuilder();
         Document xml = docBuilder.parse(manifestFile);
         MediaPackage mediaPackage = mediaPackageBuilder.loadFromXml(xml);
     
    
  • modules/common/src/test/java/org/opencastproject/mediapackage/MediaPackageTest.java+2 2 modified
    @@ -34,6 +34,7 @@
     
     import org.opencastproject.mediapackage.MediaPackageElement.Type;
     import org.opencastproject.util.ConfigurationException;
    +import org.opencastproject.util.XmlSafeParser;
     
     import org.junit.Test;
     import org.slf4j.Logger;
    @@ -49,7 +50,6 @@
     import java.util.Set;
     
     import javax.xml.parsers.DocumentBuilder;
    -import javax.xml.parsers.DocumentBuilderFactory;
     import javax.xml.parsers.ParserConfigurationException;
     import javax.xml.xpath.XPath;
     import javax.xml.xpath.XPathExpressionException;
    @@ -84,7 +84,7 @@ public void testElementUrls() throws ParserConfigurationException, SAXException,
     
           // Test url
           String xmlString = MediaPackageParser.getAsXml(mediaPackage);
    -      DocumentBuilder docBuilder = DocumentBuilderFactory.newInstance().newDocumentBuilder();
    +      DocumentBuilder docBuilder = XmlSafeParser.newDocumentBuilderFactory().newDocumentBuilder();
           Document xml = docBuilder.parse(new ByteArrayInputStream(xmlString.getBytes()));
           String expected = dcFile.toURI().toURL().toExternalForm();
           assertEquals(expected, xPath.evaluate("//url", xml));
    
  • modules/common/src/test/java/org/opencastproject/mediapackage/track/AdaptivePlaylistTest.java+13 13 modified
    @@ -41,6 +41,7 @@
     import org.opencastproject.util.Checksum;
     import org.opencastproject.util.IoSupport;
     import org.opencastproject.util.MimeType;
    +import org.opencastproject.util.XmlSafeParser;
     import org.opencastproject.util.data.Function2;
     
     import org.apache.commons.io.FileUtils;
    @@ -53,6 +54,7 @@
     import org.junit.Test;
     import org.junit.rules.TemporaryFolder;
     import org.w3c.dom.Document;
    +import org.xml.sax.SAXException;
     
     import java.io.ByteArrayInputStream;
     import java.io.File;
    @@ -78,8 +80,6 @@
     import javax.xml.bind.Marshaller;
     import javax.xml.bind.Unmarshaller;
     import javax.xml.parsers.DocumentBuilder;
    -import javax.xml.parsers.DocumentBuilderFactory;
    -import javax.xml.transform.stream.StreamSource;
     
     /**
      * Test case to Test the implementation of {@link AdaptivePlaylistImpl}.
    @@ -152,14 +152,14 @@ public void setUp() throws Exception {
         FileUtils.copyURLToFile(this.getClass().getResource("/" + hls_mp_raw), mpxml);
       }
     
    -  public Track makeTrack(URI uri, String logicalName) throws JAXBException {
    +  public Track makeTrack(URI uri, String logicalName) throws JAXBException, IOException, SAXException {
         String xml = "<oc:track xmlns:oc=\"http://mediapackage.opencastproject.org\" type=\"presentation/source\"><oc:tags/><oc:url>"
                 + uri + "</oc:url><oc:duration>1</oc:duration><oc:logicalname>" + logicalName
                 + "</oc:logicalname></oc:track>";
         InputStream inputStream = new ByteArrayInputStream(xml.getBytes(StandardCharsets.UTF_8));
         TrackImpl track;
         try {
    -      track = unmarshaller.unmarshal(new StreamSource(inputStream), TrackImpl.class).getValue();
    +      track = unmarshaller.unmarshal(XmlSafeParser.parse(inputStream), TrackImpl.class).getValue();
         } finally {
           IoSupport.closeQuietly(inputStream);
         }
    @@ -337,7 +337,7 @@ public void testFlavorMarshalling() throws Exception {
         Unmarshaller unmarshaller = context.createUnmarshaller();
         InputStream inputStream = new ByteArrayInputStream(writer.toString().getBytes(StandardCharsets.UTF_8));
         try {
    -      TrackImpl t1 = unmarshaller.unmarshal(new StreamSource(inputStream), TrackImpl.class)
    +      TrackImpl t1 = unmarshaller.unmarshal(XmlSafeParser.parse(inputStream), TrackImpl.class)
                   .getValue();
           Assert.assertEquals(MediaPackageElements.PRESENTATION_SOURCE, t1.getFlavor());
           // Assert.assertTrue(t1.isMaster());
    @@ -350,7 +350,7 @@ public void testFlavorMarshalling() throws Exception {
                 + hlsUrl.toString() + "</oc:url><oc:master>true</oc:master><oc:duration>-1</oc:duration></oc:track>";
         inputStream = new ByteArrayInputStream(xml.getBytes(StandardCharsets.UTF_8));
         try {
    -      TrackImpl t2 = unmarshaller.unmarshal(new StreamSource(inputStream), TrackImpl.class).getValue();
    +      TrackImpl t2 = unmarshaller.unmarshal(XmlSafeParser.parse(inputStream), TrackImpl.class).getValue();
           Assert.assertEquals(MediaPackageElements.PRESENTATION_SOURCE, t2.getFlavor());
           Assert.assertEquals(hlsUrl, t2.getURI());
         } finally {
    @@ -362,7 +362,7 @@ public void testFlavorMarshalling() throws Exception {
         Assert.assertTrue(xmlFromTrack.contains(MediaPackageElements.PRESENTATION_SOURCE.toString()));
     
         // And finally, using the element builder
    -    DocumentBuilder docBuilder = DocumentBuilderFactory.newInstance().newDocumentBuilder();
    +    DocumentBuilder docBuilder = XmlSafeParser.newDocumentBuilderFactory().newDocumentBuilder();
         Document doc = docBuilder.parse(new ByteArrayInputStream(xml.getBytes(StandardCharsets.UTF_8)));
     
         Track t3 = (Track) MediaPackageElementBuilderFactory.newInstance().newElementBuilder()
    @@ -386,7 +386,7 @@ public void testLogicalNameMarshalling() throws Exception {
         Unmarshaller unmarshaller = context.createUnmarshaller();
         InputStream inputStream = IOUtils.toInputStream(writer.toString(), "UTF-8");
         try {
    -      TrackImpl t1 = unmarshaller.unmarshal(new StreamSource(inputStream), TrackImpl.class).getValue();
    +      TrackImpl t1 = unmarshaller.unmarshal(XmlSafeParser.parse(inputStream), TrackImpl.class).getValue();
           Assert.assertEquals(MediaPackageElements.PRESENTATION_SOURCE, t1.getFlavor());
           Assert.assertEquals(logicalName, t1.getLogicalName());
         } finally {
    @@ -399,7 +399,7 @@ public void testLogicalNameMarshalling() throws Exception {
                 + "</oc:logicalname></oc:track>";
         inputStream = new ByteArrayInputStream(xml.getBytes(StandardCharsets.UTF_8));
         try {
    -      TrackImpl t2 = unmarshaller.unmarshal(new StreamSource(inputStream), TrackImpl.class).getValue();
    +      TrackImpl t2 = unmarshaller.unmarshal(XmlSafeParser.parse(inputStream), TrackImpl.class).getValue();
           Assert.assertEquals(MediaPackageElements.PRESENTATION_SOURCE, t2.getFlavor());
           Assert.assertEquals(fmp4Url, t2.getURI());
           Assert.assertEquals(logicalName, t2.getLogicalName());
    @@ -413,7 +413,7 @@ public void testLogicalNameMarshalling() throws Exception {
         Assert.assertTrue(xmlFromTrack.replaceAll("\\b+", "").contains("<logicalname>" + logicalName + "</logicalname>"));
     
         // And finally, using the element builder
    -    DocumentBuilder docBuilder = DocumentBuilderFactory.newInstance().newDocumentBuilder();
    +    DocumentBuilder docBuilder = XmlSafeParser.newDocumentBuilderFactory().newDocumentBuilder();
         Document doc = docBuilder.parse(new ByteArrayInputStream(xml.getBytes(StandardCharsets.UTF_8)));
     
         Track t3 = (Track) MediaPackageElementBuilderFactory.newInstance().newElementBuilder()
    @@ -438,7 +438,7 @@ public void testMasterMarshalling() throws Exception {
         Unmarshaller unmarshaller = context.createUnmarshaller();
         InputStream inputStream = IOUtils.toInputStream(writer.toString(), "UTF-8");
         try {
    -      TrackImpl t1 = unmarshaller.unmarshal(new StreamSource(inputStream), TrackImpl.class)
    +      TrackImpl t1 = unmarshaller.unmarshal(XmlSafeParser.parse(inputStream), TrackImpl.class)
                   .getValue();
           Assert.assertEquals(MediaPackageElements.PRESENTATION_SOURCE, t1.getFlavor());
           Assert.assertEquals(logicalName, t1.getLogicalName());
    @@ -452,7 +452,7 @@ public void testMasterMarshalling() throws Exception {
                 + "</oc:logicalname><oc:master>true</oc:master><oc:duration>-1</oc:duration><oc:live>true</oc:live></oc:track>";
         inputStream = new ByteArrayInputStream(xml.getBytes(StandardCharsets.UTF_8));
         try {
    -      TrackImpl t2 = unmarshaller.unmarshal(new StreamSource(inputStream), TrackImpl.class)
    +      TrackImpl t2 = unmarshaller.unmarshal(XmlSafeParser.parse(inputStream), TrackImpl.class)
                   .getValue();
           Assert.assertEquals(MediaPackageElements.PRESENTATION_SOURCE, t2.getFlavor());
           Assert.assertEquals("http://downloads.opencastproject.org/media/movie.m3u8", t2.getURI().toString());
    @@ -469,7 +469,7 @@ public void testMasterMarshalling() throws Exception {
         Assert.assertTrue(xmlFromTrack.replaceAll("\\b+", "").contains("<master>true</master>"));
     
         // And finally, using the element builder
    -    DocumentBuilder docBuilder = DocumentBuilderFactory.newInstance().newDocumentBuilder();
    +    DocumentBuilder docBuilder = XmlSafeParser.newDocumentBuilderFactory().newDocumentBuilder();
         Document doc = docBuilder.parse(new ByteArrayInputStream(xml.getBytes(StandardCharsets.UTF_8)));
     
         Track t3 = (Track) MediaPackageElementBuilderFactory.newInstance().newElementBuilder()
    
  • modules/common/src/test/java/org/opencastproject/mediapackage/track/TrackTest.java+7 8 modified
    @@ -32,6 +32,7 @@
     import org.opencastproject.mediapackage.Track;
     import org.opencastproject.mediapackage.elementbuilder.TrackBuilderPlugin;
     import org.opencastproject.util.IoSupport;
    +import org.opencastproject.util.XmlSafeParser;
     
     import org.apache.commons.io.IOUtils;
     import org.junit.Assert;
    @@ -47,8 +48,6 @@
     import javax.xml.bind.Marshaller;
     import javax.xml.bind.Unmarshaller;
     import javax.xml.parsers.DocumentBuilder;
    -import javax.xml.parsers.DocumentBuilderFactory;
    -import javax.xml.transform.stream.StreamSource;
     
     /**
      * Test case to Test the implementation of {@link TrackImpl}.
    @@ -123,7 +122,7 @@ public void testFlavorMarshalling() throws Exception {
         Unmarshaller unmarshaller = context.createUnmarshaller();
         InputStream inputStream = IOUtils.toInputStream(writer.toString(), "UTF-8");
         try {
    -      TrackImpl t1 = unmarshaller.unmarshal(new StreamSource(inputStream), TrackImpl.class).getValue();
    +      TrackImpl t1 = unmarshaller.unmarshal(XmlSafeParser.parse(inputStream), TrackImpl.class).getValue();
           Assert.assertEquals(MediaPackageElements.PRESENTATION_SOURCE, t1.getFlavor());
         } finally {
           IoSupport.closeQuietly(inputStream);
    @@ -133,7 +132,7 @@ public void testFlavorMarshalling() throws Exception {
         String xml = "<oc:track xmlns:oc=\"http://mediapackage.opencastproject.org\" type=\"presentation/source\"><oc:tags/><oc:url>http://downloads.opencastproject.org/media/movie.m4v</oc:url><oc:duration>-1</oc:duration></oc:track>";
         inputStream = IOUtils.toInputStream(xml);
         try {
    -      TrackImpl t2 = unmarshaller.unmarshal(new StreamSource(inputStream), TrackImpl.class).getValue();
    +      TrackImpl t2 = unmarshaller.unmarshal(XmlSafeParser.parse(inputStream), TrackImpl.class).getValue();
           Assert.assertEquals(MediaPackageElements.PRESENTATION_SOURCE, t2.getFlavor());
           Assert.assertEquals("http://downloads.opencastproject.org/media/movie.m4v", t2.getURI().toString());
         } finally {
    @@ -145,7 +144,7 @@ public void testFlavorMarshalling() throws Exception {
         Assert.assertTrue(xmlFromTrack.contains(MediaPackageElements.PRESENTATION_SOURCE.toString()));
     
         // And finally, using the element builder
    -    DocumentBuilder docBuilder = DocumentBuilderFactory.newInstance().newDocumentBuilder();
    +    DocumentBuilder docBuilder = XmlSafeParser.newDocumentBuilderFactory().newDocumentBuilder();
         Document doc = docBuilder.parse(IOUtils.toInputStream(xml));
     
         Track t3 = (Track) MediaPackageElementBuilderFactory.newInstance().newElementBuilder()
    @@ -167,7 +166,7 @@ public void testLiveMarshalling() throws Exception {
         Unmarshaller unmarshaller = context.createUnmarshaller();
         InputStream inputStream = IOUtils.toInputStream(writer.toString(), "UTF-8");
         try {
    -      TrackImpl t1 = unmarshaller.unmarshal(new StreamSource(inputStream), TrackImpl.class).getValue();
    +      TrackImpl t1 = unmarshaller.unmarshal(XmlSafeParser.parse(inputStream), TrackImpl.class).getValue();
           Assert.assertEquals(MediaPackageElements.PRESENTATION_SOURCE, t1.getFlavor());
           Assert.assertEquals(true, t1.isLive());
         } finally {
    @@ -178,7 +177,7 @@ public void testLiveMarshalling() throws Exception {
         String xml = "<oc:track xmlns:oc=\"http://mediapackage.opencastproject.org\" type=\"presentation/source\"><oc:tags/><oc:url>http://downloads.opencastproject.org/media/movie.m4v</oc:url><oc:duration>-1</oc:duration><oc:live>true</oc:live></oc:track>";
         inputStream = IOUtils.toInputStream(xml);
         try {
    -      TrackImpl t2 = unmarshaller.unmarshal(new StreamSource(inputStream), TrackImpl.class).getValue();
    +      TrackImpl t2 = unmarshaller.unmarshal(XmlSafeParser.parse(inputStream), TrackImpl.class).getValue();
           Assert.assertEquals(MediaPackageElements.PRESENTATION_SOURCE, t2.getFlavor());
           Assert.assertEquals("http://downloads.opencastproject.org/media/movie.m4v", t2.getURI().toString());
           Assert.assertEquals(true, t2.isLive());
    @@ -192,7 +191,7 @@ public void testLiveMarshalling() throws Exception {
         Assert.assertTrue(xmlFromTrack.replaceAll("\\b+", "").contains("<live>true</live>"));
     
         // And finally, using the element builder
    -    DocumentBuilder docBuilder = DocumentBuilderFactory.newInstance().newDocumentBuilder();
    +    DocumentBuilder docBuilder = XmlSafeParser.newDocumentBuilderFactory().newDocumentBuilder();
         Document doc = docBuilder.parse(IOUtils.toInputStream(xml));
     
         Track t3 = (Track) MediaPackageElementBuilderFactory.newInstance().newElementBuilder()
    
  • modules/common/src/test/java/org/opencastproject/security/api/OrganizationParsingTest.java+6 0 modified
    @@ -121,8 +121,10 @@ public void testMarshalOrganization() throws Exception {
         assertTrue("Organization XML not formed as expected", val);
     
         StreamSource streamSource = new StreamSource(new StringReader(producedOutput));
    +    // CHECKSTYLE:OFF
         JaxbOrganization organization = jaxbContext.createUnmarshaller().unmarshal(streamSource, JaxbOrganization.class)
                 .getValue();
    +    // CHECKSTYLE:ON
         compareOrgs(org, organization);
       }
     
    @@ -137,8 +139,10 @@ public void testMarshalOrganization2() throws Exception {
         assertTrue("Organization XML not formed as expected", val);
     
         StreamSource streamSource = new StreamSource(new StringReader(producedOutput));
    +    // CHECKSTYLE:OFF
         JaxbOrganization organization = jaxbContext.createUnmarshaller().unmarshal(streamSource, JaxbOrganization.class)
                 .getValue();
    +    // CHECKSTYLE:ON
         compareOrgs(org, organization);
       }
     
    @@ -147,8 +151,10 @@ public void testUnmarshalOrganization() throws Exception {
         Organization org = new DefaultOrganization();
     
         StreamSource streamSource = new StreamSource(getClass().getResourceAsStream(ORG_XML_FILE));
    +    // CHECKSTYLE:OFF
         JaxbOrganization organization = jaxbContext.createUnmarshaller().unmarshal(streamSource, JaxbOrganization.class)
                 .getValue();
    +    // CHECKSTYLE:ON
         compareOrgs(org, organization);
       }
     
    
  • modules/common/src/test/java/org/opencastproject/security/api/RoleParsingTest.java+5 3 modified
    @@ -23,17 +23,19 @@
     
     import static org.junit.Assert.assertEquals;
     
    +import org.opencastproject.util.XmlSafeParser;
    +
     import org.apache.commons.io.IOUtils;
     import org.custommonkey.xmlunit.Diff;
     import org.custommonkey.xmlunit.ElementNameAndTextQualifier;
     import org.custommonkey.xmlunit.XMLAssert;
     import org.junit.Before;
     import org.junit.Test;
     
    +import java.io.InputStream;
     import java.io.StringWriter;
     
     import javax.xml.bind.JAXBContext;
    -import javax.xml.transform.stream.StreamSource;
     
     /**
      * Tests JAXB un/marshalling of the role
    @@ -70,8 +72,8 @@ public void testMarshalUser() throws Exception {
       public void testUnmarshalUser() throws Exception {
         JaxbRole expectedRole = new JaxbRole("ROLE_TEST", ORGANIZATION, "This is a test role");
     
    -    StreamSource streamSource = new StreamSource(getClass().getResourceAsStream(ROLE_XML_FILE));
    -    JaxbRole role = jaxbContext.createUnmarshaller().unmarshal(streamSource, JaxbRole.class).getValue();
    +    InputStream is = getClass().getResourceAsStream(ROLE_XML_FILE);
    +    JaxbRole role = jaxbContext.createUnmarshaller().unmarshal(XmlSafeParser.parse(is), JaxbRole.class).getValue();
     
         assertEquals(expectedRole.getName(), role.getName());
         assertEquals(expectedRole.getDescription(), role.getDescription());
    
  • modules/common/src/test/java/org/opencastproject/security/api/UserParsingTest.java+4 3 modified
    @@ -24,6 +24,8 @@
     import static org.junit.Assert.assertEquals;
     import static org.junit.Assert.assertNull;
     
    +import org.opencastproject.util.XmlSafeParser;
    +
     import org.apache.commons.io.IOUtils;
     import org.junit.Before;
     import org.junit.Test;
    @@ -32,7 +34,6 @@
     import java.util.Set;
     
     import javax.xml.bind.JAXBContext;
    -import javax.xml.transform.stream.StreamSource;
     
     /**
      * Tests JAXB un/marshalling of the user
    @@ -59,8 +60,8 @@ public void testUnmarshalUser() throws Exception {
     
         JaxbUser expectedUser = new JaxbUser("admin", "123456", "test", ORGANIZATION, roles);
     
    -    StreamSource streamSource = new StreamSource(getClass().getResourceAsStream(USER_XML_FILE));
    -    JaxbUser user = jaxbContext.createUnmarshaller().unmarshal(streamSource, JaxbUser.class).getValue();
    +    JaxbUser user = jaxbContext.createUnmarshaller().unmarshal(XmlSafeParser.parse(
    +                            getClass().getResourceAsStream(USER_XML_FILE)), JaxbUser.class).getValue();
     
         assertEquals(expectedUser.getUsername(), user.getUsername());
         assertNull(user.getPassword());
    
  • modules/common/src/test/java/org/opencastproject/util/XmlSafeParserTest.java+300 0 added
    @@ -0,0 +1,300 @@
    +/**
    + * Licensed to The Apereo Foundation under one or more contributor license
    + * agreements. See the NOTICE file distributed with this work for additional
    + * information regarding copyright ownership.
    + *
    + *
    + * The Apereo Foundation licenses this file to you under the Educational
    + * Community License, Version 2.0 (the "License"); you may not use this file
    + * except in compliance with the License. You may obtain a copy of the License
    + * at:
    + *
    + *   http://opensource.org/licenses/ecl2.txt
    + *
    + * Unless required by applicable law or agreed to in writing, software
    + * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
    + * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.  See the
    + * License for the specific language governing permissions and limitations under
    + * the License.
    + *
    + */
    +
    +package org.opencastproject.util;
    +
    +import org.junit.Assert;
    +import org.junit.Test;
    +import org.w3c.dom.Document;
    +import org.xml.sax.InputSource;
    +import org.xml.sax.SAXException;
    +import org.xml.sax.SAXParseException;
    +import org.xml.sax.helpers.DefaultHandler;
    +
    +import java.io.IOException;
    +import java.io.InputStream;
    +import java.io.StringWriter;
    +
    +import javax.xml.parsers.DocumentBuilder;
    +import javax.xml.parsers.ParserConfigurationException;
    +import javax.xml.parsers.SAXParser;
    +import javax.xml.transform.Transformer;
    +import javax.xml.transform.TransformerConfigurationException;
    +import javax.xml.transform.TransformerException;
    +import javax.xml.transform.TransformerFactory;
    +import javax.xml.transform.stream.StreamResult;
    +import javax.xml.transform.stream.StreamSource;
    +
    +public class XmlSafeParserTest {
    +  @Test
    +  public void newDocumentBuilderFactoryTest() throws ParserConfigurationException, SAXException, IOException {
    +    InputStream xmlInput = XmlSafeParserTest.class.getResourceAsStream("/dublincore-safe.xml");
    +
    +    DocumentBuilder db = XmlSafeParser.newDocumentBuilderFactory().newDocumentBuilder();
    +    Document d = db.parse(xmlInput);
    +  }
    +
    +  @Test(expected = SAXParseException.class)
    +  public void newDocumentBuilderFactoryUnsafeTest() throws ParserConfigurationException, SAXException, IOException {
    +    InputStream xmlInput = XmlSafeParserTest.class.getResourceAsStream("/dublincore-unsafe.xml");
    +
    +    DocumentBuilder db = XmlSafeParser.newDocumentBuilderFactory().newDocumentBuilder();
    +    Document d = db.parse(xmlInput);
    +  }
    +
    +  @Test(expected = SAXParseException.class)
    +  public void newDocumentBuilderFactoryUnsafe2Test() throws ParserConfigurationException, SAXException, IOException {
    +    InputStream xmlInput = XmlSafeParserTest.class.getResourceAsStream("/dublincore-unsafe2.xml");
    +
    +    DocumentBuilder db = XmlSafeParser.newDocumentBuilderFactory().newDocumentBuilder();
    +    Document d = db.parse(xmlInput);
    +  }
    +
    +  @Test
    +  public void newSAXParserFactoryTest() throws ParserConfigurationException, SAXException, IOException {
    +    InputStream xmlInput = XmlSafeParserTest.class.getResourceAsStream("/dublincore-safe.xml");
    +
    +    SAXParser sp = XmlSafeParser.newSAXParserFactory().newSAXParser();
    +    sp.parse(xmlInput, new DefaultHandler());
    +  }
    +
    +  @Test
    +  public void newSAXParserFactoryTest2() throws ParserConfigurationException, SAXException, IOException {
    +    InputStream xmlInput = XmlSafeParserTest.class.getResourceAsStream("/dublincore-safe.xml");
    +
    +    SAXParser sp = XmlSafeParser.newSAXParserFactory().newSAXParser();
    +    sp.getXMLReader().parse(new InputSource(xmlInput));
    +  }
    +
    +  @Test(expected = SAXParseException.class)
    +  public void newSAXParserFactoryUnsafeTest() throws ParserConfigurationException, SAXException, IOException {
    +    InputStream xmlInput = XmlSafeParserTest.class.getResourceAsStream("/dublincore-unsafe.xml");
    +
    +    SAXParser sp = XmlSafeParser.newSAXParserFactory().newSAXParser();
    +    sp.parse(xmlInput, new DefaultHandler());
    +  }
    +
    +  @Test(expected = SAXParseException.class)
    +  public void newSAXParserFactoryUnsafe2Test() throws ParserConfigurationException, SAXException, IOException {
    +    InputStream xmlInput = XmlSafeParserTest.class.getResourceAsStream("/dublincore-unsafe2.xml");
    +
    +    SAXParser sp = XmlSafeParser.newSAXParserFactory().newSAXParser();
    +    sp.parse(xmlInput, new DefaultHandler());
    +  }
    +
    +  @Test(expected = SAXParseException.class)
    +  public void newSAXParserFactoryUnsafeTest2() throws ParserConfigurationException, SAXException, IOException {
    +    InputStream xmlInput = XmlSafeParserTest.class.getResourceAsStream("/dublincore-unsafe.xml");
    +
    +    SAXParser sp = XmlSafeParser.newSAXParserFactory().newSAXParser();
    +    sp.getXMLReader().parse(new InputSource(xmlInput));
    +  }
    +
    +  @Test(expected = SAXParseException.class)
    +  public void newSAXParserFactoryUnsafe2Test2() throws ParserConfigurationException, SAXException, IOException {
    +    InputStream xmlInput = XmlSafeParserTest.class.getResourceAsStream("/dublincore-unsafe2.xml");
    +
    +    SAXParser sp = XmlSafeParser.newSAXParserFactory().newSAXParser();
    +    sp.getXMLReader().parse(new InputSource(xmlInput));
    +  }
    +
    +  @Test
    +  public void newTransformerFactoryTest() throws TransformerException, TransformerConfigurationException {
    +    InputStream xmlInput = XmlSafeParserTest.class.getResourceAsStream("/dublincore-safe.xml");
    +
    +    Transformer tf = XmlSafeParser.newTransformerFactory().newTransformer();
    +    tf.transform(new StreamSource(xmlInput), new StreamResult(new StringWriter()));
    +  }
    +
    +  @Test(expected = TransformerException.class)
    +  public void newTransformerFactoryUnsafeTest() throws TransformerException, TransformerConfigurationException {
    +    InputStream xmlInput = XmlSafeParserTest.class.getResourceAsStream("/dublincore-unsafe.xml");
    +
    +    Transformer tf = XmlSafeParser.newTransformerFactory().newTransformer();
    +    tf.transform(new StreamSource(xmlInput), new StreamResult(new StringWriter()));
    +  }
    +
    +  @Test(expected = TransformerException.class)
    +  public void newTransformerFactoryUnsafe2Test() throws TransformerException, TransformerConfigurationException {
    +    InputStream xmlInput = XmlSafeParserTest.class.getResourceAsStream("/dublincore-unsafe2.xml");
    +
    +    Transformer tf = XmlSafeParser.newTransformerFactory().newTransformer();
    +    tf.transform(new StreamSource(xmlInput), new StreamResult(new StringWriter()));
    +  }
    +
    +  @Test
    +  public void configureTransformerFactoryTest() throws TransformerException, TransformerConfigurationException {
    +    InputStream xmlInput = XmlSafeParserTest.class.getResourceAsStream("/dublincore-safe.xml");
    +
    +    // CHECKSTYLE:OFF
    +    Transformer tf = XmlSafeParser.configureTransformerFactory(TransformerFactory.newInstance()).newTransformer();
    +    // CHECKSTLYE:ON
    +    tf.transform(new StreamSource(xmlInput), new StreamResult(new StringWriter()));
    +  }
    +
    +  @Test(expected = TransformerException.class)
    +  public void configureTransformerFactoryUnsafeTest() throws TransformerException, TransformerConfigurationException {
    +    InputStream xmlInput = XmlSafeParserTest.class.getResourceAsStream("/dublincore-unsafe.xml");
    +
    +    // CHECKSTYLE:OFF
    +    Transformer tf = XmlSafeParser.configureTransformerFactory(TransformerFactory.newInstance()).newTransformer();
    +    // CHECKSTLYE:ON
    +    tf.transform(new StreamSource(xmlInput), new StreamResult(new StringWriter()));
    +  }
    +
    +  @Test(expected = TransformerException.class)
    +  public void configureTransformerFactoryUnsafe2Test() throws TransformerException, TransformerConfigurationException {
    +    InputStream xmlInput = XmlSafeParserTest.class.getResourceAsStream("/dublincore-unsafe2.xml");
    +
    +    // CHECKSTYLE:OFF
    +    Transformer tf = XmlSafeParser.configureTransformerFactory(TransformerFactory.newInstance()).newTransformer();
    +    // CHECKSTLYE:ON
    +    tf.transform(new StreamSource(xmlInput), new StreamResult(new StringWriter()));
    +  }
    +
    +  @Test
    +  public void configureTransformerFactoryInbuiltTest() throws TransformerException, TransformerConfigurationException {
    +    InputStream xmlInput = XmlSafeParserTest.class.getResourceAsStream("/dublincore-safe.xml");
    +
    +    Transformer tf = XmlSafeParser.configureTransformerFactory(
    +      // CHECKSTYLE:OFF
    +      TransformerFactory.newInstance("com.sun.org.apache.xalan.internal.xsltc.trax.TransformerFactoryImpl", null)
    +      // CHECKSTLYE:ON
    +    ).newTransformer();
    +    tf.transform(new StreamSource(xmlInput), new StreamResult(new StringWriter()));
    +  }
    +
    +  @Test(expected = TransformerException.class)
    +  public void configureTransformerFactoryInbuiltUnsafeTest() throws TransformerException, TransformerConfigurationException {
    +    InputStream xmlInput = XmlSafeParserTest.class.getResourceAsStream("/dublincore-unsafe.xml");
    +
    +    Transformer tf = XmlSafeParser.configureTransformerFactory(
    +      // CHECKSTYLE:OFF
    +      TransformerFactory.newInstance("com.sun.org.apache.xalan.internal.xsltc.trax.TransformerFactoryImpl", null)
    +      // CHECKSTLYE:ON
    +    ).newTransformer();
    +    tf.transform(new StreamSource(xmlInput), new StreamResult(new StringWriter()));
    +  }
    +
    +  @Test(expected = TransformerException.class)
    +  public void configureTransformerFactoryInbuiltUnsafe2Test() throws TransformerException, TransformerConfigurationException {
    +    InputStream xmlInput = XmlSafeParserTest.class.getResourceAsStream("/dublincore-unsafe2.xml");
    +
    +    Transformer tf = XmlSafeParser.configureTransformerFactory(
    +      // CHECKSTYLE:OFF
    +      TransformerFactory.newInstance("com.sun.org.apache.xalan.internal.xsltc.trax.TransformerFactoryImpl", null)
    +      // CHECKSTLYE:ON
    +    ).newTransformer();
    +    tf.transform(new StreamSource(xmlInput), new StreamResult(new StringWriter()));
    +  }
    +
    +  @Test
    +  public void configureTransformerFactorySaxonTest() throws TransformerException, TransformerConfigurationException {
    +    InputStream xmlInput = XmlSafeParserTest.class.getResourceAsStream("/dublincore-safe.xml");
    +
    +    Transformer tf = XmlSafeParser.configureTransformerFactory(
    +      // CHECKSTYLE:OFF
    +      TransformerFactory.newInstance("net.sf.saxon.TransformerFactoryImpl", null)
    +      // CHECKSTLYE:ON
    +    ).newTransformer();
    +    tf.transform(new StreamSource(xmlInput), new StreamResult(new StringWriter()));
    +  }
    +
    +  @Test(expected = TransformerException.class)
    +  public void configureTransformerFactorySaxonUnsafeTest() throws TransformerException, TransformerConfigurationException {
    +    InputStream xmlInput = XmlSafeParserTest.class.getResourceAsStream("/dublincore-unsafe.xml");
    +
    +    Transformer tf = XmlSafeParser.configureTransformerFactory(
    +      // CHECKSTYLE:OFF
    +      TransformerFactory.newInstance("net.sf.saxon.TransformerFactoryImpl", null)
    +      // CHECKSTLYE:ON
    +    ).newTransformer();
    +    tf.transform(new StreamSource(xmlInput), new StreamResult(new StringWriter()));
    +  }
    +
    +  @Test(expected = TransformerException.class)
    +  public void configureTransformerFactorySaxonUnsafe2Test() throws TransformerException, TransformerConfigurationException {
    +    InputStream xmlInput = XmlSafeParserTest.class.getResourceAsStream("/dublincore-unsafe2.xml");
    +
    +    Transformer tf = XmlSafeParser.configureTransformerFactory(
    +      // CHECKSTYLE:OFF
    +      TransformerFactory.newInstance("net.sf.saxon.TransformerFactoryImpl", null)
    +      // CHECKSTLYE:ON
    +    ).newTransformer();
    +    tf.transform(new StreamSource(xmlInput), new StreamResult(new StringWriter()));
    +  }
    +
    +  @Test
    +  public void parseTest() throws SAXException, IOException {
    +    InputStream xmlInput = XmlSafeParserTest.class.getResourceAsStream("/dublincore-safe.xml");
    +
    +    Document d = XmlSafeParser.parse(xmlInput);
    +  }
    +
    +  @Test(expected = SAXParseException.class)
    +  public void parseUnsafeTest() throws SAXException, IOException {
    +    InputStream xmlInput = XmlSafeParserTest.class.getResourceAsStream("/dublincore-unsafe.xml");
    +
    +    Document d = XmlSafeParser.parse(xmlInput);
    +  }
    +
    +  @Test(expected = SAXParseException.class)
    +  public void parseUnsafe2Test() throws SAXException, IOException {
    +    InputStream xmlInput = XmlSafeParserTest.class.getResourceAsStream("/dublincore-unsafe2.xml");
    +
    +    Document d = XmlSafeParser.parse(xmlInput);
    +  }
    +
    +  @Test
    +  public void parseChain() throws SAXException, IOException {
    +    InputStream xmlInputSafe1 = XmlSafeParserTest.class.getResourceAsStream("/dublincore-safe.xml");
    +    InputStream xmlInputSafe2 = XmlSafeParserTest.class.getResourceAsStream("/dublincore-safe.xml");
    +    InputStream xmlInputUnsafe1 = XmlSafeParserTest.class.getResourceAsStream("/dublincore-unsafe.xml");
    +    InputStream xmlInputUnsafe2 = XmlSafeParserTest.class.getResourceAsStream("/dublincore-unsafe2.xml");
    +
    +    int catched = 0;
    +    Document d1;
    +    Document d2;
    +    Document d3;
    +    Document d4;
    +
    +    try {
    +      d1 = XmlSafeParser.parse(xmlInputUnsafe1);
    +    }
    +    catch(SAXParseException e) {
    +      catched++;
    +    };
    +
    +    d2 = XmlSafeParser.parse(xmlInputSafe1);
    +
    +    try {
    +      d3 = XmlSafeParser.parse(xmlInputUnsafe2);
    +    }
    +    catch(SAXParseException e) {
    +      catched++;
    +    };
    +
    +    Assert.assertEquals(catched, 2);
    +
    +    d4 = XmlSafeParser.parse(xmlInputSafe2);
    +  }
    +}
    +
    
  • modules/common/src/test/resources/dublincore-safe.xml+5 0 added
    @@ -0,0 +1,5 @@
    +<?xml version="1.0" encoding="UTF-8" standalone="no"?>
    +<dublincore xmlns="http://www.opencastproject.org/xsd/1.0/dublincore/" xmlns:dcterms="http://purl.org/dc/terms/" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance">
    + <dcterms:description>A normal description</dcterms:description>
    + <dcterms:title>Safe dublincore</dcterms:title>
    +</dublincore>
    
  • modules/common/src/test/resources/dublincore-unsafe2.xml+11 0 added
    @@ -0,0 +1,11 @@
    +<?xml version="1.0" encoding="UTF-8" standalone="no"?>
    +<!DOCTYPE foo [
    + <!ELEMENT lolz (#PCDATA)>
    + <!ENTITY lol1 "lol">
    + <!ENTITY lol "&lol1;&lol1;">
    +]>
    +<dublincore xmlns="http://www.opencastproject.org/xsd/1.0/dublincore/" xmlns:dcterms="http://purl.org/dc/terms/" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance">
    + <lolz>&lol;</lolz>
    + <dcterms:title>Unsafe dublincore</dcterms:title>
    +</dublincore>
    +
    
  • modules/common/src/test/resources/dublincore-unsafe.xml+7 0 added
    @@ -0,0 +1,7 @@
    +<?xml version="1.0" encoding="UTF-8" standalone="no"?>
    +<!DOCTYPE foo [ <!ENTITY xxe SYSTEM "file:///etc/passwd"> ]>
    +<dublincore xmlns="http://www.opencastproject.org/xsd/1.0/dublincore/" xmlns:dcterms="http://purl.org/dc/terms/" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance">
    + <dcterms:description>&xxe;</dcterms:description>
    + <dcterms:title>Unsafe dublincore</dcterms:title>
    +</dublincore>
    +
    
  • modules/composer-service-api/src/main/java/org/opencastproject/composer/api/EncodingProfileBuilder.java+4 3 modified
    @@ -21,14 +21,15 @@
     
     package org.opencastproject.composer.api;
     
    +import org.opencastproject.util.XmlSafeParser;
    +
     import org.apache.commons.io.IOUtils;
     
     import java.io.InputStream;
     
     import javax.xml.bind.JAXBContext;
     import javax.xml.bind.JAXBException;
     import javax.xml.bind.Unmarshaller;
    -import javax.xml.transform.stream.StreamSource;
     
     /**
      * Provides a mechanism to transform {@link EncodingProfile}s to and from xml.
    @@ -74,7 +75,7 @@ public static EncodingProfileBuilder getInstance() {
       public EncodingProfile parseProfile(InputStream in) throws Exception {
         Unmarshaller unmarshaller = jaxbContext.createUnmarshaller();
         try {
    -      return unmarshaller.unmarshal(new StreamSource(in), EncodingProfileImpl.class).getValue();
    +      return unmarshaller.unmarshal(XmlSafeParser.parse(in), EncodingProfileImpl.class).getValue();
         } finally {
           IOUtils.closeQuietly(in);
         }
    @@ -92,7 +93,7 @@ public EncodingProfile parseProfile(InputStream in) throws Exception {
       public EncodingProfileList parseProfileList(InputStream in) throws Exception {
         Unmarshaller unmarshaller = jaxbContext.createUnmarshaller();
         try {
    -      return unmarshaller.unmarshal(new StreamSource(in), EncodingProfileList.class).getValue();
    +      return unmarshaller.unmarshal(XmlSafeParser.parse(in), EncodingProfileList.class).getValue();
         } finally {
           IOUtils.closeQuietly(in);
         }
    
  • modules/cover-image-impl/src/main/java/org/opencastproject/coverimage/impl/AbstractCoverImageService.java+15 9 modified
    @@ -37,6 +37,7 @@
     import org.opencastproject.security.api.UserDirectoryService;
     import org.opencastproject.serviceregistry.api.ServiceRegistry;
     import org.opencastproject.serviceregistry.api.ServiceRegistryException;
    +import org.opencastproject.util.XmlSafeParser;
     import org.opencastproject.workspace.api.Workspace;
     
     import org.apache.batik.apps.rasterizer.DestinationType;
    @@ -65,15 +66,13 @@
     import javax.xml.parsers.DocumentBuilderFactory;
     import javax.xml.parsers.ParserConfigurationException;
     import javax.xml.transform.Result;
    -import javax.xml.transform.Source;
     import javax.xml.transform.Transformer;
     import javax.xml.transform.TransformerConfigurationException;
     import javax.xml.transform.TransformerException;
     import javax.xml.transform.TransformerFactory;
     import javax.xml.transform.TransformerFactoryConfigurationError;
     import javax.xml.transform.dom.DOMSource;
     import javax.xml.transform.stream.StreamResult;
    -import javax.xml.transform.stream.StreamSource;
     
     /**
      * Service for creating cover images
    @@ -166,7 +165,7 @@ protected Attachment generateCoverImageInternal(Job job, String xml, String xsl,
     
           // Load Metadata (from resources)
           xmlReader = new StringReader(xml);
    -      Source xmlSource = new StreamSource(xmlReader);
    +      InputSource xmlSource = new InputSource(xmlReader);
     
           // Transform XML metadata with stylesheet to SVG
           transformSvg(svg, xmlSource, xslDoc, width, height, posterImage);
    @@ -207,7 +206,8 @@ protected static Document parseXsl(String xsl) throws CoverImageException {
           throw new IllegalArgumentException("XSL string must not be empty");
         }
     
    -    DocumentBuilderFactory dbFactory = DocumentBuilderFactory.newInstance();
    +    DocumentBuilderFactory dbFactory = XmlSafeParser.newDocumentBuilderFactory();
    +
         dbFactory.setNamespaceAware(true);
         Document xslDoc;
         try {
    @@ -227,16 +227,20 @@ protected static Document parseXsl(String xsl) throws CoverImageException {
         return xslDoc;
       }
     
    -  protected static void transformSvg(Result svg, Source xmlSource, Document xslDoc, int width, int height,
    +  protected static void transformSvg(Result svg, InputSource xmlSource, Document xslDoc, int width, int height,
           String posterImage) throws TransformerFactoryConfigurationError, CoverImageException {
         if (svg == null || xmlSource == null || xslDoc == null) {
           throw new IllegalArgumentException("Neither svg nor xmlSource nor xslDoc must be null");
         }
     
    -    TransformerFactory factory = TransformerFactory.newInstance();
         Transformer transformer;
         try {
    -      transformer = factory.newTransformer(new DOMSource(xslDoc));
    +      // CHECKSTYLE:OFF
    +      // Xalan Transformer can't be configured safely
    +      // xslDoc is an already parsed Document
    +      transformer = TransformerFactory.newInstance()
    +              .newTransformer(new DOMSource(xslDoc));
    +      // CHECKSTYLE:ON
         } catch (TransformerConfigurationException e) {
           // this should never happen...
           throw new CoverImageException("The XSL transformer factory has serious configuration errors", e);
    @@ -252,8 +256,10 @@ protected static void transformSvg(Result svg, Source xmlSource, Document xslDoc
         thread.setContextClassLoader(AbstractCoverImageService.class.getClassLoader());
         try {
           log.debug("Transform XML source to SVG");
    -      transformer.transform(xmlSource, svg);
    -    } catch (TransformerException e) {
    +      // Xalan Transformer can't be configured safely
    +      // Preparsing the XML with a safe parser
    +      transformer.transform(new DOMSource(XmlSafeParser.parse(xmlSource)), svg);
    +    } catch (TransformerException | IOException | SAXException e) {
           log.warn("Error while transforming SVG to image: {}", e.getMessage());
           throw new CoverImageException("Error while transforming SVG to image", e);
         } finally {
    
  • modules/cover-image-impl/src/test/java/org/opencastproject/coverimage/impl/CoverImageServiceTest.java+4 4 modified
    @@ -32,6 +32,7 @@
     import org.dom4j.dom.DOMDocument;
     import org.junit.Test;
     import org.w3c.dom.Document;
    +import org.xml.sax.InputSource;
     import org.xmlmatchers.namespace.SimpleNamespaceContext;
     
     import java.io.InputStream;
    @@ -42,7 +43,6 @@
     import javax.xml.transform.Result;
     import javax.xml.transform.Source;
     import javax.xml.transform.stream.StreamResult;
    -import javax.xml.transform.stream.StreamSource;
     
     /**
      * Test class for {@link AbstractCoverImageService}
    @@ -98,7 +98,7 @@ public void testParseXsl() throws Exception {
        */
       @Test(expected = IllegalArgumentException.class)
       public void testTransformSvgNullSvg() throws Exception {
    -    AbstractCoverImageService.transformSvg(null, new StreamSource(), new DOMDocument(), 0, 0, null);
    +    AbstractCoverImageService.transformSvg(null, new InputSource(), new DOMDocument(), 0, 0, null);
       }
     
       /**
    @@ -114,7 +114,7 @@ public void testTransformSvgNullXmlSource() throws Exception {
        */
       @Test(expected = IllegalArgumentException.class)
       public void testTransformSvgNullXslDoc() throws Exception {
    -    AbstractCoverImageService.transformSvg(new StreamResult(), new StreamSource(), null, 0, 0, null);
    +    AbstractCoverImageService.transformSvg(new StreamResult(), new InputSource(), null, 0, 0, null);
       }
     
       /**
    @@ -126,7 +126,7 @@ public void testTransformSvg() throws Exception {
         Result svg = new StreamResult(svgWriter);
     
         InputStream isXml = CoverImageServiceTest.class.getResourceAsStream("/metadata.xml");
    -    Source xmlSource = new StreamSource(isXml);
    +    InputSource xmlSource = new InputSource(isXml);
     
         InputStream isXsl = CoverImageServiceTest.class.getResourceAsStream("/metadata2svg.xsl");
         Document xslDoc = AbstractCoverImageService.parseXsl(IOUtils.toString(isXsl));
    
  • modules/distribution-service-streaming-wowza/src/main/java/org/opencastproject/distribution/streaming/wowza/WowzaStreamingDistributionService.java+4 8 modified
    @@ -43,6 +43,7 @@
     import org.opencastproject.util.NotFoundException;
     import org.opencastproject.util.RequireUtil;
     import org.opencastproject.util.UrlSupport;
    +import org.opencastproject.util.XmlSafeParser;
     
     import com.google.gson.Gson;
     import com.google.gson.reflect.TypeToken;
    @@ -81,11 +82,9 @@
     
     import javax.ws.rs.core.UriBuilder;
     import javax.xml.parsers.DocumentBuilder;
    -import javax.xml.parsers.DocumentBuilderFactory;
     import javax.xml.parsers.ParserConfigurationException;
     import javax.xml.transform.Transformer;
     import javax.xml.transform.TransformerException;
    -import javax.xml.transform.TransformerFactory;
     import javax.xml.transform.dom.DOMSource;
     import javax.xml.transform.stream.StreamResult;
     
    @@ -590,8 +589,7 @@ private boolean isStreamingFormat(MediaPackageElement element) {
       private Document getSmilDocument(File smilFile) throws DistributionException {
         if (!smilFile.isFile()) {
           try {
    -        DocumentBuilderFactory docBuilderFactory = DocumentBuilderFactory.newInstance();
    -        DocumentBuilder docBuilder = docBuilderFactory.newDocumentBuilder();
    +        DocumentBuilder docBuilder = XmlSafeParser.newDocumentBuilderFactory().newDocumentBuilder();
             Document doc = docBuilder.newDocument();
             Element smil = doc.createElement("smil");
             doc.appendChild(smil);
    @@ -613,8 +611,7 @@ private Document getSmilDocument(File smilFile) throws DistributionException {
         }
     
         try {
    -      DocumentBuilderFactory docBuilderFactory = DocumentBuilderFactory.newInstance();
    -      DocumentBuilder docBuilder = docBuilderFactory.newDocumentBuilder();
    +      DocumentBuilder docBuilder = XmlSafeParser.newDocumentBuilderFactory().newDocumentBuilder();
           Document doc = docBuilder.parse(smilFile);
     
           if (!"smil".equalsIgnoreCase(doc.getDocumentElement().getNodeName())) {
    @@ -637,8 +634,7 @@ private Document getSmilDocument(File smilFile) throws DistributionException {
     
       private void saveSmilFile(File smilFile, Document doc) throws DistributionException {
         try {
    -      TransformerFactory transformerFactory = TransformerFactory.newInstance();
    -      Transformer transformer = transformerFactory.newTransformer();
    +      Transformer transformer = XmlSafeParser.newTransformerFactory().newTransformer();
           DOMSource source = new DOMSource(doc);
           StreamResult stream = new StreamResult(smilFile);
           transformer.transform(source, stream);
    
  • modules/dublincore/src/main/java/org/opencastproject/metadata/dublincore/DublinCoreCatalogList.java+5 6 modified
    @@ -22,6 +22,7 @@
     package org.opencastproject.metadata.dublincore;
     
     import org.opencastproject.util.IoSupport;
    +import org.opencastproject.util.XmlSafeParser;
     
     import org.apache.commons.io.IOUtils;
     import org.json.simple.JSONArray;
    @@ -49,7 +50,6 @@
     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.DOMSource;
     import javax.xml.transform.stream.StreamResult;
     import javax.xml.xpath.XPath;
    @@ -116,8 +116,7 @@ public long size() {
        */
       public String getResultsAsXML() throws IOException {
         try {
    -      DocumentBuilderFactory factory = DocumentBuilderFactory.newInstance();
    -      DocumentBuilder builder = factory.newDocumentBuilder();
    +      DocumentBuilder builder = XmlSafeParser.newDocumentBuilderFactory().newDocumentBuilder();
           DOMImplementation impl = builder.getDOMImplementation();
     
           Document doc = impl.createDocument(null, null, null);
    @@ -129,7 +128,7 @@ public String getResultsAsXML() throws IOException {
             root.appendChild(node);
           }
     
    -      Transformer tf = TransformerFactory.newInstance().newTransformer();
    +      Transformer tf = XmlSafeParser.newTransformerFactory().newTransformer();
           DOMSource xmlSource = new DOMSource(doc);
           StringWriter out = new StringWriter();
           tf.transform(xmlSource, new StreamResult(out));
    @@ -166,7 +165,7 @@ public static DublinCoreCatalogList parse(String dcString) throws IOException {
           // XML
           InputStream is = null;
           try {
    -        DocumentBuilderFactory docBuilderFactory = DocumentBuilderFactory.newInstance();
    +        DocumentBuilderFactory docBuilderFactory = XmlSafeParser.newDocumentBuilderFactory();
             docBuilderFactory.setNamespaceAware(true);
             DocumentBuilder docBuilder = docBuilderFactory.newDocumentBuilder();
             is = IOUtils.toInputStream(dcString, "UTF-8");
    @@ -206,7 +205,7 @@ public static DublinCoreCatalogList parse(String dcString) throws IOException {
       private static InputStream nodeToString(Node node) {
         ByteArrayOutputStream outputStream = new ByteArrayOutputStream();
         try {
    -      Transformer t = TransformerFactory.newInstance().newTransformer();
    +      Transformer t = XmlSafeParser.newTransformerFactory().newTransformer();
           t.setOutputProperty(OutputKeys.OMIT_XML_DECLARATION, "yes");
           t.setOutputProperty(OutputKeys.INDENT, "yes");
           t.transform(new DOMSource(node), new StreamResult(outputStream));
    
  • modules/dublincore/src/main/java/org/opencastproject/metadata/dublincore/DublinCoreXmlFormat.java+4 4 modified
    @@ -25,6 +25,7 @@
     import org.opencastproject.mediapackage.XMLCatalogImpl;
     import org.opencastproject.mediapackage.XMLCatalogImpl.CatalogEntry;
     import org.opencastproject.util.XmlNamespaceContext;
    +import org.opencastproject.util.XmlSafeParser;
     
     import com.entwinemedia.fn.data.Opt;
     
    @@ -57,7 +58,6 @@
     import javax.xml.transform.Result;
     import javax.xml.transform.Transformer;
     import javax.xml.transform.TransformerException;
    -import javax.xml.transform.TransformerFactory;
     import javax.xml.transform.dom.DOMSource;
     import javax.xml.transform.sax.SAXResult;
     
    @@ -210,7 +210,7 @@ public static Document writeDocument(DublinCoreCatalog dc)
         // Create the DOM document
         final Document doc;
         {
    -      final DocumentBuilderFactory docBuilderFactory = DocumentBuilderFactory.newInstance();
    +      final DocumentBuilderFactory docBuilderFactory = XmlSafeParser.newDocumentBuilderFactory();
           docBuilderFactory.setNamespaceAware(true);
           doc = docBuilderFactory.newDocumentBuilder().newDocument();
         }
    @@ -230,15 +230,15 @@ public static Document writeDocument(DublinCoreCatalog dc)
     
       private DublinCoreCatalog readImpl(Node node) throws TransformerException {
         final Result outputTarget = new SAXResult(this);
    -    final Transformer t = TransformerFactory.newInstance().newTransformer();
    +    final Transformer t = XmlSafeParser.newTransformerFactory().newTransformer();
         t.setOutputProperty(OutputKeys.OMIT_XML_DECLARATION, "yes");
         t.transform(new DOMSource(node), outputTarget);
         return dc;
       }
     
       private DublinCoreCatalog readImpl(InputSource in)
               throws ParserConfigurationException, SAXException, IOException {
    -    final SAXParserFactory factory = SAXParserFactory.newInstance();
    +    final SAXParserFactory factory = XmlSafeParser.newSAXParserFactory();
         // no DTD
         factory.setValidating(false);
         // namespaces!
    
  • modules/dublincore/src/test/java/org/opencastproject/metadata/dublincore/DublinCoreTest.java+2 1 modified
    @@ -54,6 +54,7 @@
     import org.opencastproject.util.MimeType;
     import org.opencastproject.util.UnknownFileTypeException;
     import org.opencastproject.util.XmlNamespaceContext;
    +import org.opencastproject.util.XmlSafeParser;
     import org.opencastproject.workspace.api.Workspace;
     
     import org.apache.commons.io.FileUtils;
    @@ -256,7 +257,7 @@ public void testNewInstance() {
           }
     
           // Store the catalog
    -      TransformerFactory transfac = TransformerFactory.newInstance();
    +      TransformerFactory transfac = XmlSafeParser.newTransformerFactory();
           Transformer trans = transfac.newTransformer();
           trans.setOutputProperty(OutputKeys.OMIT_XML_DECLARATION, "yes");
           trans.setOutputProperty(OutputKeys.METHOD, "xml");
    
  • modules/dublincore/src/test/java/org/opencastproject/metadata/dublincore/DublinCoreXmlFormatTest.java+2 1 modified
    @@ -31,6 +31,7 @@
     import org.opencastproject.util.IoSupport;
     import org.opencastproject.util.XmlNamespaceBinding;
     import org.opencastproject.util.XmlNamespaceContext;
    +import org.opencastproject.util.XmlSafeParser;
     import org.opencastproject.util.Xpath;
     
     import org.junit.Test;
    @@ -81,7 +82,7 @@ public void readFromStringWithoutXmlHeader() throws Exception {
     
       @Test
       public void readFromNode() throws Exception {
    -    final DocumentBuilderFactory dbf = DocumentBuilderFactory.newInstance();
    +    final DocumentBuilderFactory dbf = XmlSafeParser.newDocumentBuilderFactory();
         dbf.setNamespaceAware(true);
         final Document doc = dbf.newDocumentBuilder().parse(
             IoSupport.classPathResourceAsFile("/matterhorn-inlined-list-records-response.xml").get());
    
  • modules/event-comment/src/main/java/org/opencastproject/event/comment/EventCommentParser.java+5 4 modified
    @@ -28,6 +28,7 @@
     import org.opencastproject.security.api.User;
     import org.opencastproject.security.api.UserDirectoryService;
     import org.opencastproject.util.DateTimeSupport;
    +import org.opencastproject.util.XmlSafeParser;
     import org.opencastproject.util.data.Option;
     
     import org.apache.commons.io.IOUtils;
    @@ -45,7 +46,6 @@
     import javax.xml.parsers.DocumentBuilderFactory;
     import javax.xml.parsers.ParserConfigurationException;
     import javax.xml.transform.Transformer;
    -import javax.xml.transform.TransformerFactory;
     import javax.xml.transform.dom.DOMSource;
     import javax.xml.transform.stream.StreamResult;
     import javax.xml.xpath.XPath;
    @@ -80,7 +80,7 @@ private EventCommentParser() {
       public static EventComment getCommentFromXml(String xml, UserDirectoryService userDirectoryService)
               throws EventCommentException {
         try {
    -      Document doc = DocumentBuilderFactory.newInstance().newDocumentBuilder()
    +      Document doc = XmlSafeParser.newDocumentBuilderFactory().newDocumentBuilder()
                   .parse(IOUtils.toInputStream(xml, "UTF-8"));
           return commentFromManifest(doc.getDocumentElement(), userDirectoryService);
         } catch (Exception e) {
    @@ -370,7 +370,8 @@ private static Element getAuthorNode(User author, Document doc) {
       private static String serializeNode(Document xmlDocument) throws EventCommentException {
         // Serialize the document
         try {
    -      Transformer transformer = TransformerFactory.newInstance().newTransformer();
    +      Transformer transformer = XmlSafeParser.newTransformerFactory()
    +              .newTransformer();
           // transformer.setOutputProperty(OutputKeys.OMIT_XML_DECLARATION, "yes");
           StringWriter writer = new StringWriter();
           transformer.transform(new DOMSource(xmlDocument), new StreamResult(writer));
    @@ -382,7 +383,7 @@ private static String serializeNode(Document xmlDocument) throws EventCommentExc
     
       /** Create a new DOM document. */
       private static Document newDocument() {
    -    final DocumentBuilderFactory docBuilderFactory = DocumentBuilderFactory.newInstance();
    +    final DocumentBuilderFactory docBuilderFactory = XmlSafeParser.newDocumentBuilderFactory();
         docBuilderFactory.setNamespaceAware(true);
         try {
           return docBuilderFactory.newDocumentBuilder().newDocument();
    
  • modules/fileupload/src/main/java/org/opencastproject/fileupload/service/FileUploadServiceImpl.java+5 1 modified
    @@ -34,6 +34,7 @@
     import org.opencastproject.mediapackage.MediaPackageElementFlavor;
     import org.opencastproject.mediapackage.Track;
     import org.opencastproject.util.IoSupport;
    +import org.opencastproject.util.XmlSafeParser;
     import org.opencastproject.util.data.Function2;
     import org.opencastproject.util.data.Option;
     import org.opencastproject.util.data.functions.Functions;
    @@ -210,7 +211,10 @@ public FileUploadJob getJob(String id) throws FileUploadException {
           try { // try to load job from filesystem
             synchronized (this) {
               File jobFile = getJobFile(id);
    -          FileUploadJob job = (FileUploadJob) jobUnmarshaller.unmarshal(jobFile);
    +          FileUploadJob job = null;
    +          try (FileInputStream jobFileStream = new FileInputStream(jobFile)) {
    +            job = (FileUploadJob) jobUnmarshaller.unmarshal(XmlSafeParser.parse(jobFileStream));
    +          }
               job.setLastModified(jobFile.lastModified()); // get last modified time from job file
               return job;
             } // if loading from fs also fails
    
  • modules/index-service/src/main/java/org/opencastproject/index/service/impl/index/event/Event.java+9 3 modified
    @@ -25,6 +25,7 @@
     import org.opencastproject.mediapackage.Publication;
     import org.opencastproject.scheduler.api.RecordingState;
     import org.opencastproject.util.IoSupport;
    +import org.opencastproject.util.XmlSafeParser;
     import org.opencastproject.workflow.api.WorkflowInstance.WorkflowState;
     
     import org.apache.commons.lang3.StringUtils;
    @@ -36,6 +37,7 @@
     import org.codehaus.jettison.mapped.MappedXMLStreamWriter;
     import org.slf4j.Logger;
     import org.slf4j.LoggerFactory;
    +import org.xml.sax.SAXException;
     
     import java.io.BufferedReader;
     import java.io.IOException;
    @@ -60,7 +62,6 @@
     import javax.xml.stream.XMLStreamException;
     import javax.xml.stream.XMLStreamReader;
     import javax.xml.stream.XMLStreamWriter;
    -import javax.xml.transform.stream.StreamSource;
     
     /**
      * Object wrapper for a recording event.
    @@ -1065,9 +1066,11 @@ public static Event valueOf(InputStream xml, Unmarshaller unmarshaller) throws I
           if (context == null) {
             createJAXBContext();
           }
    -      return unmarshaller.unmarshal(new StreamSource(xml), Event.class).getValue();
    +      return unmarshaller.unmarshal(XmlSafeParser.parse(xml), Event.class).getValue();
         } catch (JAXBException e) {
           throw new IOException(e.getLinkedException() != null ? e.getLinkedException() : e);
    +    } catch (SAXException e) {
    +      throw new IOException(e);
         } finally {
           IoSupport.closeQuietly(xml);
         }
    @@ -1103,9 +1106,12 @@ public static Event valueOfJson(InputStream json)
         xmlToJsonNamespaces.put(IndexObject.INDEX_XML_NAMESPACE, "");
         config.setXmlToJsonNamespaces(xmlToJsonNamespaces);
         MappedNamespaceConvention con = new MappedNamespaceConvention(config);
    -    XMLStreamReader xmlStreamReader = new MappedXMLStreamReader(obj, con);
         Unmarshaller unmarshaller = context.createUnmarshaller();
    +    // CHECKSTYLE:OFF
    +    // the xml is parsed from json and should be safe
    +    XMLStreamReader xmlStreamReader = new MappedXMLStreamReader(obj, con);
         Event event = (Event) unmarshaller.unmarshal(xmlStreamReader);
    +    // CHECKSTYLE:ON
         return event;
       }
     
    
  • modules/index-service/src/main/java/org/opencastproject/index/service/impl/index/group/Group.java+6 2 modified
    @@ -24,6 +24,9 @@
     import org.opencastproject.index.service.impl.index.IndexObject;
     import org.opencastproject.security.api.JaxbGroup;
     import org.opencastproject.util.IoSupport;
    +import org.opencastproject.util.XmlSafeParser;
    +
    +import org.xml.sax.SAXException;
     
     import java.io.IOException;
     import java.io.InputStream;
    @@ -41,7 +44,6 @@
     import javax.xml.bind.annotation.XmlElementWrapper;
     import javax.xml.bind.annotation.XmlRootElement;
     import javax.xml.bind.annotation.XmlType;
    -import javax.xml.transform.stream.StreamSource;
     
     /**
      * Object wrapper for a group.
    @@ -250,9 +252,11 @@ public static Group valueOf(InputStream xml, Unmarshaller unmarshaller) throws I
           if (context == null) {
             createJAXBContext();
           }
    -      return unmarshaller.unmarshal(new StreamSource(xml), Group.class).getValue();
    +      return unmarshaller.unmarshal(XmlSafeParser.parse(xml), Group.class).getValue();
         } catch (JAXBException e) {
           throw new IOException(e.getLinkedException() != null ? e.getLinkedException() : e);
    +    } catch (SAXException e) {
    +      throw new IOException(e);
         } finally {
           IoSupport.closeQuietly(xml);
         }
    
  • modules/index-service/src/main/java/org/opencastproject/index/service/impl/index/series/Series.java+9 3 modified
    @@ -25,13 +25,15 @@
     import org.opencastproject.util.DateTimeSupport.UtcTimestampAdapter;
     import org.opencastproject.util.EqualsUtil;
     import org.opencastproject.util.IoSupport;
    +import org.opencastproject.util.XmlSafeParser;
     
     import org.codehaus.jettison.json.JSONException;
     import org.codehaus.jettison.json.JSONObject;
     import org.codehaus.jettison.mapped.Configuration;
     import org.codehaus.jettison.mapped.MappedNamespaceConvention;
     import org.codehaus.jettison.mapped.MappedXMLStreamReader;
     import org.codehaus.jettison.mapped.MappedXMLStreamWriter;
    +import org.xml.sax.SAXException;
     
     import java.io.BufferedReader;
     import java.io.IOException;
    @@ -58,7 +60,6 @@
     import javax.xml.stream.XMLStreamException;
     import javax.xml.stream.XMLStreamReader;
     import javax.xml.stream.XMLStreamWriter;
    -import javax.xml.transform.stream.StreamSource;
     
     /**
      * Object wrapper for a series.
    @@ -525,9 +526,11 @@ public static Series valueOf(InputStream xml, Unmarshaller unmarshaller) throws
           if (context == null) {
             createJAXBContext();
           }
    -      return unmarshaller.unmarshal(new StreamSource(xml), Series.class).getValue();
    +      return unmarshaller.unmarshal(XmlSafeParser.parse(xml), Series.class).getValue();
         } catch (JAXBException e) {
           throw new IOException(e.getLinkedException() != null ? e.getLinkedException() : e);
    +    } catch (SAXException e) {
    +      throw new IOException(e);
         } finally {
           IoSupport.closeQuietly(xml);
         }
    @@ -563,9 +566,12 @@ public static Series valueOfJson(InputStream json) throws IOException, JSONExcep
         xmlToJsonNamespaces.put(IndexObject.INDEX_XML_NAMESPACE, "");
         config.setXmlToJsonNamespaces(xmlToJsonNamespaces);
         MappedNamespaceConvention con = new MappedNamespaceConvention(config);
    -    XMLStreamReader xmlStreamReader = new MappedXMLStreamReader(obj, con);
         Unmarshaller unmarshaller = context.createUnmarshaller();
    +    // CHECKSTYLE:OFF
    +    // the xml is parsed from json and should be safe
    +    XMLStreamReader xmlStreamReader = new MappedXMLStreamReader(obj, con);
         Series event = (Series) unmarshaller.unmarshal(xmlStreamReader);
    +    // CHECKSTYLE:ON
         return event;
       }
     
    
  • modules/index-service/src/main/java/org/opencastproject/index/service/impl/index/theme/Theme.java+6 2 modified
    @@ -24,6 +24,9 @@
     import org.opencastproject.index.service.impl.index.IndexObject;
     import org.opencastproject.util.DateTimeSupport.UtcTimestampAdapter;
     import org.opencastproject.util.IoSupport;
    +import org.opencastproject.util.XmlSafeParser;
    +
    +import org.xml.sax.SAXException;
     
     import java.io.IOException;
     import java.io.InputStream;
    @@ -40,7 +43,6 @@
     import javax.xml.bind.annotation.XmlRootElement;
     import javax.xml.bind.annotation.XmlType;
     import javax.xml.bind.annotation.adapters.XmlJavaTypeAdapter;
    -import javax.xml.transform.stream.StreamSource;
     
     /**
      * Object wrapper for a theme.
    @@ -326,9 +328,11 @@ public static Theme valueOf(InputStream xml) throws IOException {
             createJAXBContext();
           }
           Unmarshaller unmarshaller = context.createUnmarshaller();
    -      return unmarshaller.unmarshal(new StreamSource(xml), Theme.class).getValue();
    +      return unmarshaller.unmarshal(XmlSafeParser.parse(xml), Theme.class).getValue();
         } catch (JAXBException e) {
           throw new IOException(e.getLinkedException() != null ? e.getLinkedException() : e);
    +    } catch (SAXException e) {
    +      throw new IOException(e);
         } finally {
           IoSupport.closeQuietly(xml);
         }
    
  • modules/mpeg7/src/main/java/org/opencastproject/metadata/mpeg7/Mpeg7CatalogImpl.java+3 2 modified
    @@ -22,6 +22,8 @@
     
     package org.opencastproject.metadata.mpeg7;
     
    +import org.opencastproject.util.XmlSafeParser;
    +
     import org.w3c.dom.Document;
     import org.w3c.dom.Element;
     
    @@ -32,7 +34,6 @@
     import java.util.Iterator;
     import java.util.List;
     
    -import javax.xml.parsers.DocumentBuilderFactory;
     import javax.xml.parsers.ParserConfigurationException;
     import javax.xml.transform.TransformerException;
     
    @@ -143,7 +144,7 @@ public Document toXml() throws ParserConfigurationException, TransformerExceptio
        * Create a DOM representation of the Mpeg-7.
        */
       private Document createDocument() throws ParserConfigurationException {
    -    Document doc = DocumentBuilderFactory.newInstance().newDocumentBuilder().newDocument();
    +    Document doc = XmlSafeParser.newDocumentBuilderFactory().newDocumentBuilder().newDocument();
         Element rootElement = doc.createElementNS("urn:mpeg:mpeg7:schema:2001", "Mpeg7");
         rootElement.setAttributeNS("http://www.w3.org/2000/xmlns/", "xmlns:mpeg7", "urn:mpeg7:schema:2001");
         rootElement.setAttributeNS("http://www.w3.org/2000/xmlns/", "xmlns:xsi",
    
  • modules/mpeg7/src/main/java/org/opencastproject/metadata/mpeg7/Mpeg7CatalogService.java+2 2 modified
    @@ -22,6 +22,7 @@
     package org.opencastproject.metadata.mpeg7;
     
     import org.opencastproject.metadata.api.CatalogService;
    +import org.opencastproject.util.XmlSafeParser;
     
     import org.apache.commons.io.output.ByteArrayOutputStream;
     
    @@ -30,7 +31,6 @@
     import java.io.InputStream;
     
     import javax.xml.transform.Transformer;
    -import javax.xml.transform.TransformerFactory;
     import javax.xml.transform.dom.DOMSource;
     import javax.xml.transform.stream.StreamResult;
     
    @@ -41,7 +41,7 @@ public class Mpeg7CatalogService implements CatalogService<Mpeg7Catalog> {
     
       public InputStream serialize(Mpeg7Catalog catalog) throws IOException {
         try {
    -      Transformer tf = TransformerFactory.newInstance().newTransformer();
    +      Transformer tf = XmlSafeParser.newTransformerFactory().newTransformer();
           DOMSource xmlSource = new DOMSource(catalog.toXml());
           ByteArrayOutputStream out = new ByteArrayOutputStream();
           tf.transform(xmlSource, new StreamResult(out));
    
  • modules/mpeg7/src/main/java/org/opencastproject/metadata/mpeg7/Mpeg7Parser.java+3 1 modified
    @@ -22,6 +22,8 @@
     
     package org.opencastproject.metadata.mpeg7;
     
    +import org.opencastproject.util.XmlSafeParser;
    +
     import org.slf4j.Logger;
     import org.slf4j.LoggerFactory;
     import org.xml.sax.Attributes;
    @@ -148,7 +150,7 @@ public Mpeg7Parser(Mpeg7CatalogImpl catalog) {
       public Mpeg7CatalogImpl parse(InputStream is) throws ParserConfigurationException, SAXException, IOException {
         if (mpeg7Doc == null)
           mpeg7Doc = new Mpeg7CatalogImpl();
    -    SAXParserFactory factory = SAXParserFactory.newInstance();
    +    SAXParserFactory factory = XmlSafeParser.newSAXParserFactory();
         // REPLAY does not use a DTD here
         factory.setValidating(false);
         factory.setNamespaceAware(true);
    
  • modules/oaipmh/pom.xml+6 0 modified
    @@ -132,6 +132,12 @@
           <artifactId>xml-matchers</artifactId>
           <version>1.0-RC1</version>
           <scope>test</scope>
    +      <exclusions>
    +        <exclusion>
    +          <groupId>net.sf.saxon</groupId>
    +          <artifactId>Saxon-HE</artifactId>
    +        </exclusion>
    +      </exclusions>
         </dependency>
         <dependency>
           <groupId>org.eclipse.persistence</groupId>
    
  • modules/oaipmh/src/main/java/org/opencastproject/oaipmh/harvester/OaiPmhRepositoryClient.java+3 1 modified
    @@ -24,6 +24,7 @@
     
     import org.opencastproject.oaipmh.Granularity;
     import org.opencastproject.oaipmh.OaiPmhConstants;
    +import org.opencastproject.util.XmlSafeParser;
     import org.opencastproject.util.data.Function;
     import org.opencastproject.util.data.Option;
     
    @@ -57,7 +58,8 @@ public final class OaiPmhRepositoryClient {
        */
       private OaiPmhRepositoryClient(String baseUrl) {
         this.baseUrl = baseUrl;
    -    this.builderFactory = DocumentBuilderFactory.newInstance();
    +    this.builderFactory = XmlSafeParser.newDocumentBuilderFactory();
    +
         this.builderFactory.setNamespaceAware(true);
         this.httpclient = new DefaultHttpClient();
       }
    
  • modules/oaipmh/src/main/java/org/opencastproject/oaipmh/util/XmlGen.java+3 4 modified
    @@ -26,6 +26,7 @@
     import static org.opencastproject.util.data.functions.Misc.chuck;
     
     import org.opencastproject.metadata.dublincore.DublinCore;
    +import org.opencastproject.util.XmlSafeParser;
     import org.opencastproject.util.data.Function;
     import org.opencastproject.util.data.Function0;
     import org.opencastproject.util.data.Option;
    @@ -54,7 +55,6 @@
     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.DOMSource;
     import javax.xml.transform.stream.StreamResult;
     
    @@ -78,7 +78,7 @@ public XmlGen(Option<String> defaultNamespace) {
     
       private Document createDocument() {
         try {
    -      DocumentBuilderFactory factory = DocumentBuilderFactory.newInstance();
    +      DocumentBuilderFactory factory = XmlSafeParser.newDocumentBuilderFactory();
           factory.setNamespaceAware(true);
           DocumentBuilder builder = factory.newDocumentBuilder();
           return builder.newDocument();
    @@ -89,8 +89,7 @@ private Document createDocument() {
     
       private void write(OutputStream out) {
         try {
    -      TransformerFactory transformerFactory = TransformerFactory.newInstance();
    -      Transformer transformer = transformerFactory.newTransformer();
    +      Transformer transformer = XmlSafeParser.newTransformerFactory().newTransformer();
           transformer.setOutputProperty(OutputKeys.METHOD, "xml");
           transformer.setOutputProperty(OutputKeys.ENCODING, "UTF-8");
           transformer.setOutputProperty(OutputKeys.INDENT, "yes");
    
  • modules/search-service-api/src/main/java/org/opencastproject/search/api/SearchResultImpl.java+7 4 modified
    @@ -22,8 +22,12 @@
     
     package org.opencastproject.search.api;
     
    +import org.opencastproject.util.XmlSafeParser;
    +
     import org.apache.commons.io.IOUtils;
    +import org.xml.sax.SAXException;
     
    +import java.io.IOException;
     import java.io.InputStream;
     import java.util.ArrayList;
     import java.util.List;
    @@ -37,8 +41,6 @@
     import javax.xml.bind.annotation.XmlElement;
     import javax.xml.bind.annotation.XmlRootElement;
     import javax.xml.bind.annotation.XmlType;
    -import javax.xml.transform.Source;
    -import javax.xml.transform.stream.StreamSource;
     
     /**
      * The search result represents a set of result items that has been compiled as a result for a search operation.
    @@ -69,10 +71,11 @@ public class SearchResultImpl implements SearchResult {
       public static SearchResultImpl valueOf(InputStream xml) {
         try {
           Unmarshaller unmarshaller = context.createUnmarshaller();
    -      Source source = new StreamSource(xml);
    -      return unmarshaller.unmarshal(source, SearchResultImpl.class).getValue();
    +      return unmarshaller.unmarshal(XmlSafeParser.parse(xml), SearchResultImpl.class).getValue();
         } catch (JAXBException e) {
           throw new IllegalStateException(e.getLinkedException() != null ? e.getLinkedException() : e);
    +    } catch (IOException | SAXException e) {
    +      throw new IllegalStateException(e);
         } finally {
           IOUtils.closeQuietly(xml);
         }
    
  • modules/silencedetection-api/src/main/java/org/opencastproject/silencedetection/api/MediaSegments.java+13 3 modified
    @@ -22,6 +22,12 @@
     
     package org.opencastproject.silencedetection.api;
     
    +import org.opencastproject.util.XmlSafeParser;
    +
    +import org.xml.sax.InputSource;
    +import org.xml.sax.SAXException;
    +
    +import java.io.IOException;
     import java.io.StringReader;
     import java.io.StringWriter;
     import java.util.List;
    @@ -110,11 +116,15 @@ public String toXml() throws JAXBException {
        * @throws JAXBException if an error occures
        */
       public static MediaSegments fromXml(String mediaSegmentsXml) throws JAXBException {
    -    StringReader sr = new StringReader(mediaSegmentsXml);
    +    MediaSegments mediaSegments = null;
         JAXBContext jctx = JAXBContext.newInstance(MediaSegments.class);
         Unmarshaller unmarshaller = jctx.createUnmarshaller();
    -    MediaSegments mediaSegments = (MediaSegments) unmarshaller.unmarshal(sr);
    -    sr.close();
    +    try (StringReader sr = new StringReader(mediaSegmentsXml)) {
    +      InputSource is = new InputSource(sr);
    +      mediaSegments = (MediaSegments) unmarshaller.unmarshal(XmlSafeParser.parse(is));
    +    } catch (IOException | SAXException e) {
    +      throw new JAXBException(e);
    +    }
         return mediaSegments;
       }
     }
    
  • modules/smil-impl/src/main/java/org/opencastproject/smil/entity/SmilImpl.java+15 2 modified
    @@ -27,10 +27,14 @@
     import org.opencastproject.smil.entity.api.SmilHead;
     import org.opencastproject.smil.entity.api.SmilObject;
     import org.opencastproject.smil.entity.media.element.api.SmilMediaElement;
    +import org.opencastproject.util.XmlSafeParser;
     
    +import org.xml.sax.InputSource;
     import org.xml.sax.SAXException;
     
     import java.io.File;
    +import java.io.FileInputStream;
    +import java.io.IOException;
     import java.io.StringReader;
     import java.io.StringWriter;
     import java.net.MalformedURLException;
    @@ -198,7 +202,12 @@ public String toXML() throws JAXBException, SAXException, MalformedURLException
       public static Smil fromXML(String xml) throws JAXBException {
         JAXBContext jctx = JAXBContext.newInstance(SmilImpl.class);
         Unmarshaller unmarshaller = jctx.createUnmarshaller();
    -    return (Smil) unmarshaller.unmarshal(new StringReader(xml));
    +    InputSource is = new InputSource(new StringReader(xml));
    +    try {
    +      return (Smil) unmarshaller.unmarshal(XmlSafeParser.parse(is));
    +    } catch (IOException | SAXException e) {
    +      throw new JAXBException(e);
    +    }
       }
     
       /**
    @@ -211,7 +220,11 @@ public static Smil fromXML(String xml) throws JAXBException {
       public static Smil fromXML(File xmlFile) throws JAXBException {
         JAXBContext jctx = JAXBContext.newInstance(SmilImpl.class);
         Unmarshaller unmarshaller = jctx.createUnmarshaller();
    -    return (Smil) unmarshaller.unmarshal(xmlFile);
    +    try (FileInputStream is = new FileInputStream(xmlFile)) {
    +      return (Smil) unmarshaller.unmarshal(XmlSafeParser.parse(is));
    +    } catch (IOException | SAXException e) {
    +      throw new JAXBException(e);
    +    }
       }
     
       /**
    
  • modules/smil-impl/src/main/java/org/opencastproject/smil/impl/SmilResponseImpl.java+8 1 modified
    @@ -27,9 +27,12 @@
     import org.opencastproject.smil.entity.SmilObjectImpl;
     import org.opencastproject.smil.entity.api.Smil;
     import org.opencastproject.smil.entity.api.SmilObject;
    +import org.opencastproject.util.XmlSafeParser;
     
     import org.apache.commons.io.IOUtils;
    +import org.xml.sax.SAXException;
     
    +import java.io.IOException;
     import java.io.InputStream;
     import java.io.StringWriter;
     
    @@ -191,7 +194,11 @@ public static SmilResponse fromXml(String smilResponseXml) throws JAXBException
       protected static SmilResponse fromXml(InputStream smilResponseXml) throws JAXBException {
         JAXBContext ctx = JAXBContext.newInstance(SmilResponseImpl.class);
         Unmarshaller unmarshaller = ctx.createUnmarshaller();
    -    return (SmilResponse) unmarshaller.unmarshal(smilResponseXml);
    +    try {
    +      return (SmilResponse) unmarshaller.unmarshal(XmlSafeParser.parse(smilResponseXml));
    +    } catch (IOException | SAXException e) {
    +      throw new JAXBException(e);
    +    }
     
       }
     
    
  • modules/userdirectory-sakai/src/main/java/org/opencastproject/userdirectory/sakai/SakaiUserProviderInstance.java+3 5 modified
    @@ -31,6 +31,7 @@
     import org.opencastproject.security.api.RoleProvider;
     import org.opencastproject.security.api.User;
     import org.opencastproject.security.api.UserProvider;
    +import org.opencastproject.util.XmlSafeParser;
     
     import com.google.common.cache.CacheBuilder;
     import com.google.common.cache.CacheLoader;
    @@ -69,7 +70,6 @@
     import javax.management.MBeanServer;
     import javax.management.ObjectName;
     import javax.xml.parsers.DocumentBuilder;
    -import javax.xml.parsers.DocumentBuilderFactory;
     
     /**
      * A UserProvider that reads user roles from Sakai.
    @@ -428,8 +428,7 @@ private String[] getRolesFromSakai(String userId) {
           String xml = IOUtils.toString(new BufferedInputStream(connection.getInputStream()));
           logger.debug(xml);
     
    -      DocumentBuilderFactory documentBuilderFactory = DocumentBuilderFactory.newInstance();
    -      DocumentBuilder parser = documentBuilderFactory.newDocumentBuilder();
    +      DocumentBuilder parser = XmlSafeParser.newDocumentBuilderFactory().newDocumentBuilder();
     
           Document document = parser.parse(new org.xml.sax.InputSource(new StringReader(xml)));
     
    @@ -487,8 +486,7 @@ private String[] getSakaiUser(String eid) {
           logger.debug(xml);
     
           // Parse the document
    -      DocumentBuilderFactory documentBuilderFactory = DocumentBuilderFactory.newInstance();
    -      DocumentBuilder parser = documentBuilderFactory.newDocumentBuilder();
    +      DocumentBuilder parser = XmlSafeParser.newDocumentBuilderFactory().newDocumentBuilder();
           Document document = parser.parse(new org.xml.sax.InputSource(new StringReader(xml)));
           Element root = document.getDocumentElement();
     
    
  • modules/userdirectory/src/test/java/org/opencastproject/userdirectory/GroupParsingTest.java+5 5 modified
    @@ -26,6 +26,7 @@
     import org.opencastproject.security.api.DefaultOrganization;
     import org.opencastproject.security.api.JaxbGroup;
     import org.opencastproject.security.api.JaxbRole;
    +import org.opencastproject.util.XmlSafeParser;
     
     import org.custommonkey.xmlunit.Diff;
     import org.custommonkey.xmlunit.ElementNameAndTextQualifier;
    @@ -38,7 +39,6 @@
     import java.util.Set;
     
     import javax.xml.bind.JAXBContext;
    -import javax.xml.transform.stream.StreamSource;
     
     /**
      * Tests JAXB un/marshalling of the group's
    @@ -72,8 +72,8 @@ public void testMarshalUser() throws Exception {
         JaxbGroup group = new JaxbGroup("admin", ORGANIZATION, "Admin", "Admin group", roles, members);
         jaxbContext.createMarshaller().marshal(group, writer);
     
    -    StreamSource streamSource = new StreamSource(getClass().getResourceAsStream(GROUP_XML_FILE));
    -    JaxbGroup groupFromFile = jaxbContext.createUnmarshaller().unmarshal(streamSource, JaxbGroup.class).getValue();
    +    JaxbGroup groupFromFile = jaxbContext.createUnmarshaller()
    +            .unmarshal(XmlSafeParser.parse(getClass().getResourceAsStream(GROUP_XML_FILE)), JaxbGroup.class).getValue();
         jaxbContext.createMarshaller().marshal(groupFromFile, writer2);
     
         Diff diff = new Diff(writer2.toString(), writer.toString());
    @@ -94,8 +94,8 @@ public void testUnmarshalUser() throws Exception {
     
         JaxbGroup expectedGroup = new JaxbGroup("admin", ORGANIZATION, "Admin", "Admin group", roles, members);
     
    -    StreamSource streamSource = new StreamSource(getClass().getResourceAsStream(GROUP_XML_FILE));
    -    JaxbGroup group = jaxbContext.createUnmarshaller().unmarshal(streamSource, JaxbGroup.class).getValue();
    +    JaxbGroup group = jaxbContext.createUnmarshaller()
    +            .unmarshal(XmlSafeParser.parse(getClass().getResourceAsStream(GROUP_XML_FILE)), JaxbGroup.class).getValue();
     
         assertEquals(expectedGroup.getGroupId(), group.getGroupId());
         assertEquals(expectedGroup.getName(), group.getName());
    
  • modules/workflow-service-api/src/main/java/org/opencastproject/workflow/api/WorkflowParser.java+6 6 modified
    @@ -22,6 +22,7 @@
     package org.opencastproject.workflow.api;
     
     import org.opencastproject.util.IoSupport;
    +import org.opencastproject.util.XmlSafeParser;
     
     import org.apache.commons.io.IOUtils;
     
    @@ -36,7 +37,6 @@
     import javax.xml.bind.JAXBException;
     import javax.xml.bind.Marshaller;
     import javax.xml.bind.Unmarshaller;
    -import javax.xml.transform.stream.StreamSource;
     
     /**
      * Provides a mechanism to un/marshall workflow instances and definitions to/from xml.
    @@ -69,7 +69,7 @@ private WorkflowParser() {
       public static List<WorkflowDefinition> parseWorkflowDefinitions(InputStream in) throws WorkflowParsingException {
         try {
           Unmarshaller unmarshaller = jaxbContext.createUnmarshaller();
    -      WorkflowDefinitionImpl[] impls = unmarshaller.unmarshal(new StreamSource(in), WorkflowDefinitionImpl[].class)
    +      WorkflowDefinitionImpl[] impls = unmarshaller.unmarshal(XmlSafeParser.parse(in), WorkflowDefinitionImpl[].class)
                   .getValue();
           List<WorkflowDefinition> list = new ArrayList<WorkflowDefinition>();
           for (WorkflowDefinitionImpl impl : impls) {
    @@ -95,7 +95,7 @@ public static List<WorkflowDefinition> parseWorkflowDefinitions(InputStream in)
       public static WorkflowDefinition parseWorkflowDefinition(InputStream in) throws WorkflowParsingException {
         try {
           Unmarshaller unmarshaller = jaxbContext.createUnmarshaller();
    -      return unmarshaller.unmarshal(new StreamSource(in), WorkflowDefinitionImpl.class).getValue();
    +      return unmarshaller.unmarshal(XmlSafeParser.parse(in), WorkflowDefinitionImpl.class).getValue();
         } catch (Exception e) {
           throw new WorkflowParsingException(e);
         } finally {
    @@ -132,7 +132,7 @@ public static WorkflowDefinition parseWorkflowDefinition(String in) throws Workf
       public static WorkflowInstanceImpl parseWorkflowInstance(InputStream in) throws WorkflowParsingException {
         try {
           Unmarshaller unmarshaller = jaxbContext.createUnmarshaller();
    -      WorkflowInstanceImpl workflow = unmarshaller.unmarshal(new StreamSource(in), WorkflowInstanceImpl.class)
    +      WorkflowInstanceImpl workflow = unmarshaller.unmarshal(XmlSafeParser.parse(in), WorkflowInstanceImpl.class)
                   .getValue();
           workflow.init();
           return workflow;
    @@ -172,7 +172,7 @@ public static WorkflowInstanceImpl parseWorkflowInstance(String in) throws Workf
       public static WorkflowStatistics parseWorkflowStatistics(InputStream in) throws WorkflowParsingException {
         try {
           Unmarshaller unmarshaller = jaxbContext.createUnmarshaller();
    -      return unmarshaller.unmarshal(new StreamSource(in), WorkflowStatistics.class).getValue();
    +      return unmarshaller.unmarshal(XmlSafeParser.parse(in), WorkflowStatistics.class).getValue();
         } catch (Exception e) {
           throw new WorkflowParsingException(e);
         } finally {
    @@ -192,7 +192,7 @@ public static WorkflowStatistics parseWorkflowStatistics(InputStream in) throws
       public static WorkflowSet parseWorkflowSet(InputStream in) throws WorkflowParsingException {
         try {
           Unmarshaller unmarshaller = jaxbContext.createUnmarshaller();
    -      return unmarshaller.unmarshal(new StreamSource(in), WorkflowSetImpl.class).getValue();
    +      return unmarshaller.unmarshal(XmlSafeParser.parse(in), WorkflowSetImpl.class).getValue();
         } catch (Exception e) {
           throw new WorkflowParsingException(e);
         } finally {
    

Vulnerability mechanics

Generated by null/stub on May 9, 2026. Inputs: CWE entries + fix-commit diffs from this CVE's patches. Citations validated against bundle.

References

5

News mentions

0

No linked articles in our index yet.