From dfd2264ca7862238425d77a17714f389489505ef Mon Sep 17 00:00:00 2001 From: rsigal Date: Wed, 17 Sep 2014 22:44:16 -0400 Subject: [PATCH] RESTEASY-1055: Apply security restrictions to XML processing. --- arquillian/RESTEASY-TEST-EAP6/pom.xml | 181 ++++ .../org/jboss/resteasy/resteasy1055/Bar.java | 14 + .../resteasy/resteasy1055/FavoriteMovie.java | 69 ++ .../FavoriteMovieXmlRootElement.java | 14 + .../resteasy1055/FavoriteMovieXmlType.java | 69 ++ .../resteasy/resteasy1055/ObjectFactory.java | 60 ++ .../resteasy1055/TestApplication.java | 25 + .../resteasy/resteasy1055/TestResource.java | 119 +++ .../jboss/resteasy/resteasy1055/external.dtd | 1 + .../org/jboss/resteasy/resteasy1055/movie.xsd | 10 + .../jboss/resteasy/resteasy1055/testpasswd | 1 + .../resteasy1055/TestSecureProcessing.java | 822 ++++++++++++++++++ .../src/test/resources/1055/external.dtd | 1 + .../src/test/resources/1055/web.xml | 27 + .../1055/web_default_default_default.xml | 37 + .../1055/web_default_default_false.xml | 37 + .../1055/web_default_default_true.xml | 37 + .../1055/web_default_false_default.xml | 37 + .../1055/web_default_false_false.xml | 37 + .../resources/1055/web_default_false_true.xml | 37 + .../1055/web_default_true_default.xml | 37 + .../resources/1055/web_default_true_false.xml | 37 + .../resources/1055/web_default_true_true.xml | 37 + .../1055/web_false_default_default.xml | 37 + .../1055/web_false_default_false.xml | 37 + .../resources/1055/web_false_default_true.xml | 37 + .../1055/web_false_false_default.xml | 37 + .../resources/1055/web_false_false_false.xml | 37 + .../resources/1055/web_false_false_true.xml | 37 + .../resources/1055/web_false_true_default.xml | 37 + .../resources/1055/web_false_true_false.xml | 37 + .../resources/1055/web_false_true_true.xml | 37 + .../1055/web_true_default_default.xml | 37 + .../resources/1055/web_true_default_false.xml | 37 + .../resources/1055/web_true_default_true.xml | 37 + .../resources/1055/web_true_false_default.xml | 37 + .../resources/1055/web_true_false_false.xml | 37 + .../resources/1055/web_true_false_true.xml | 37 + .../resources/1055/web_true_true_default.xml | 37 + .../resources/1055/web_true_true_false.xml | 37 + .../resources/1055/web_true_true_true.xml | 37 + .../src/test/resources/arquillian.xml | 23 + arquillian/pom.xml | 3 +- .../FastinfoSetElementProvider.java | 2 +- .../FastinfoSetXmlRootElementProvider.java | 2 +- .../FastinfoSetXmlSeeAlsoProvider.java | 2 +- .../FastinfoSetXmlTypeProvider.java | 2 +- .../providers/jaxb/AbstractJAXBProvider.java | 62 +- .../providers/jaxb/CollectionProvider.java | 59 +- .../providers/jaxb/JAXBElementProvider.java | 33 +- .../providers/jaxb/JAXBXmlTypeProvider.java | 37 +- .../plugins/providers/jaxb/MapProvider.java | 85 +- .../providers/jaxb/SecureUnmarshaller.java | 278 ++++++ .../test/xxe/TestSecureProcessingFeature.java | 659 ++++++++++++++ .../org/jboss/resteasy/test/xxe/TestXXE.java | 326 ++++--- .../test/xxe/TestXXESecureProcessing.java | 41 +- .../org/jboss/resteasy/test/xxe/external.dtd | 1 + .../jaxb/json/JettisonElementProvider.java | 2 +- .../json/JettisonXmlRootElementProvider.java | 2 +- .../jaxb/json/JettisonXmlSeeAlsoProvider.java | 2 +- .../jaxb/json/JettisonXmlTypeProvider.java | 2 +- .../test/xxe/TestSecureProcessing.java | 519 +++++++++++ .../plugins/providers/DocumentProvider.java | 23 + .../servlet/ResteasyContextParameters.java | 4 +- 64 files changed, 4394 insertions(+), 187 deletions(-) create mode 100755 arquillian/RESTEASY-TEST-EAP6/pom.xml create mode 100644 arquillian/RESTEASY-TEST-EAP6/src/main/java/org/jboss/resteasy/resteasy1055/Bar.java create mode 100644 arquillian/RESTEASY-TEST-EAP6/src/main/java/org/jboss/resteasy/resteasy1055/FavoriteMovie.java create mode 100644 arquillian/RESTEASY-TEST-EAP6/src/main/java/org/jboss/resteasy/resteasy1055/FavoriteMovieXmlRootElement.java create mode 100644 arquillian/RESTEASY-TEST-EAP6/src/main/java/org/jboss/resteasy/resteasy1055/FavoriteMovieXmlType.java create mode 100644 arquillian/RESTEASY-TEST-EAP6/src/main/java/org/jboss/resteasy/resteasy1055/ObjectFactory.java create mode 100644 arquillian/RESTEASY-TEST-EAP6/src/main/java/org/jboss/resteasy/resteasy1055/TestApplication.java create mode 100644 arquillian/RESTEASY-TEST-EAP6/src/main/java/org/jboss/resteasy/resteasy1055/TestResource.java create mode 100644 arquillian/RESTEASY-TEST-EAP6/src/main/java/org/jboss/resteasy/resteasy1055/external.dtd create mode 100644 arquillian/RESTEASY-TEST-EAP6/src/main/java/org/jboss/resteasy/resteasy1055/movie.xsd create mode 100644 arquillian/RESTEASY-TEST-EAP6/src/main/java/org/jboss/resteasy/resteasy1055/testpasswd create mode 100644 arquillian/RESTEASY-TEST-EAP6/src/test/java/org/jboss/resteasy/test/resteasy1055/TestSecureProcessing.java create mode 100644 arquillian/RESTEASY-TEST-EAP6/src/test/resources/1055/external.dtd create mode 100644 arquillian/RESTEASY-TEST-EAP6/src/test/resources/1055/web.xml create mode 100644 arquillian/RESTEASY-TEST-EAP6/src/test/resources/1055/web_default_default_default.xml create mode 100644 arquillian/RESTEASY-TEST-EAP6/src/test/resources/1055/web_default_default_false.xml create mode 100644 arquillian/RESTEASY-TEST-EAP6/src/test/resources/1055/web_default_default_true.xml create mode 100644 arquillian/RESTEASY-TEST-EAP6/src/test/resources/1055/web_default_false_default.xml create mode 100644 arquillian/RESTEASY-TEST-EAP6/src/test/resources/1055/web_default_false_false.xml create mode 100644 arquillian/RESTEASY-TEST-EAP6/src/test/resources/1055/web_default_false_true.xml create mode 100644 arquillian/RESTEASY-TEST-EAP6/src/test/resources/1055/web_default_true_default.xml create mode 100644 arquillian/RESTEASY-TEST-EAP6/src/test/resources/1055/web_default_true_false.xml create mode 100644 arquillian/RESTEASY-TEST-EAP6/src/test/resources/1055/web_default_true_true.xml create mode 100644 arquillian/RESTEASY-TEST-EAP6/src/test/resources/1055/web_false_default_default.xml create mode 100644 arquillian/RESTEASY-TEST-EAP6/src/test/resources/1055/web_false_default_false.xml create mode 100644 arquillian/RESTEASY-TEST-EAP6/src/test/resources/1055/web_false_default_true.xml create mode 100644 arquillian/RESTEASY-TEST-EAP6/src/test/resources/1055/web_false_false_default.xml create mode 100644 arquillian/RESTEASY-TEST-EAP6/src/test/resources/1055/web_false_false_false.xml create mode 100644 arquillian/RESTEASY-TEST-EAP6/src/test/resources/1055/web_false_false_true.xml create mode 100644 arquillian/RESTEASY-TEST-EAP6/src/test/resources/1055/web_false_true_default.xml create mode 100644 arquillian/RESTEASY-TEST-EAP6/src/test/resources/1055/web_false_true_false.xml create mode 100644 arquillian/RESTEASY-TEST-EAP6/src/test/resources/1055/web_false_true_true.xml create mode 100644 arquillian/RESTEASY-TEST-EAP6/src/test/resources/1055/web_true_default_default.xml create mode 100644 arquillian/RESTEASY-TEST-EAP6/src/test/resources/1055/web_true_default_false.xml create mode 100644 arquillian/RESTEASY-TEST-EAP6/src/test/resources/1055/web_true_default_true.xml create mode 100644 arquillian/RESTEASY-TEST-EAP6/src/test/resources/1055/web_true_false_default.xml create mode 100644 arquillian/RESTEASY-TEST-EAP6/src/test/resources/1055/web_true_false_false.xml create mode 100644 arquillian/RESTEASY-TEST-EAP6/src/test/resources/1055/web_true_false_true.xml create mode 100644 arquillian/RESTEASY-TEST-EAP6/src/test/resources/1055/web_true_true_default.xml create mode 100644 arquillian/RESTEASY-TEST-EAP6/src/test/resources/1055/web_true_true_false.xml create mode 100644 arquillian/RESTEASY-TEST-EAP6/src/test/resources/1055/web_true_true_true.xml create mode 100644 arquillian/RESTEASY-TEST-EAP6/src/test/resources/arquillian.xml create mode 100644 providers/jaxb/src/main/java/org/jboss/resteasy/plugins/providers/jaxb/SecureUnmarshaller.java create mode 100644 providers/jaxb/src/test/java/org/jboss/resteasy/test/xxe/TestSecureProcessingFeature.java create mode 100644 providers/jaxb/src/test/java/org/jboss/resteasy/test/xxe/external.dtd create mode 100644 resteasy-jaxrs-test/src/test/java/org/jboss/resteasy/test/xxe/TestSecureProcessing.java diff --git a/arquillian/RESTEASY-TEST-EAP6/pom.xml b/arquillian/RESTEASY-TEST-EAP6/pom.xml new file mode 100755 index 00000000000..2760fd530cd --- /dev/null +++ b/arquillian/RESTEASY-TEST-EAP6/pom.xml @@ -0,0 +1,181 @@ + + + 4.0.0 + + + org.jboss.resteasy + resteasy-jaxrs-all + 2.3.7.Final + ../../pom.xml + + + RESTEASY-TEST-EAP6 + jar + RESTEASY-TEST-EAP6 + http://maven.apache.org + + + UTF-8 + 7.4.0.Final-redhat-19 + 6.3 + + + + + + org.apache.maven.plugins + maven-compiler-plugin + 2.3.2 + + 1.6 + 1.6 + + + + maven-surefire-plugin + 2.12 + + + maven-dependency-plugin + + + unpack + process-test-classes + + unpack + + + + + org.jboss.as + jboss-as-dist + ${as-version} + zip + false + target + + + + + + + + org.apache.maven.plugins + maven-antrun-plugin + 1.6 + + + unpack resteasy + process-test-classes + + + + + + + run + + + + + + + + + + + org.jboss.arquillian + arquillian-bom + 1.0.3.Final + import + pom + + + + + + + org.jboss.spec + jboss-javaee-6.0 + 1.0.0.Final + pom + provided + + + junit + junit + 4.8.1 + test + + + org.jboss.arquillian.junit + arquillian-junit-container + test + + + org.jboss.as + jboss-as-arquillian-container-managed + 7.1.1.Final + test + + + org.jboss.arquillian.protocol + arquillian-protocol-servlet + test + + + org.jboss.resteasy + jaxrs-api + ${project.version} + + + org.jboss.resteasy + resteasy-jaxrs + ${project.version} + + + org.jboss.resteasy + resteasy-hibernatevalidator-provider + ${project.version} + + + javax.validation + validation-api + 1.1.0.Final + + + org.hibernate + hibernate-validator + 5.0.1.Final + + + javax.el + javax.el-api + 2.2.4 + + + org.glassfish.web + javax.el + 2.2.4 + + + org.jboss.spec.javax.xml.bind + jboss-jaxb-api_2.2_spec + 1.0.4.Final + + + org.jboss.resteasy + resteasy-jaxb-provider + ${project.version} + test + + + commons-logging + commons-logging + 1.1.0.jboss + test + + + diff --git a/arquillian/RESTEASY-TEST-EAP6/src/main/java/org/jboss/resteasy/resteasy1055/Bar.java b/arquillian/RESTEASY-TEST-EAP6/src/main/java/org/jboss/resteasy/resteasy1055/Bar.java new file mode 100644 index 00000000000..6bb6999c3e8 --- /dev/null +++ b/arquillian/RESTEASY-TEST-EAP6/src/main/java/org/jboss/resteasy/resteasy1055/Bar.java @@ -0,0 +1,14 @@ +package org.jboss.resteasy.resteasy1055; + +import javax.xml.bind.annotation.XmlRootElement; + +@XmlRootElement +public class Bar { + private String _s; + public String getS() { + return _s; + } + public void setS(String s) { + _s = s; + } +} diff --git a/arquillian/RESTEASY-TEST-EAP6/src/main/java/org/jboss/resteasy/resteasy1055/FavoriteMovie.java b/arquillian/RESTEASY-TEST-EAP6/src/main/java/org/jboss/resteasy/resteasy1055/FavoriteMovie.java new file mode 100644 index 00000000000..f338459d9a1 --- /dev/null +++ b/arquillian/RESTEASY-TEST-EAP6/src/main/java/org/jboss/resteasy/resteasy1055/FavoriteMovie.java @@ -0,0 +1,69 @@ +// +// This file was generated by the JavaTM Architecture for XML Binding(JAXB) Reference Implementation, vJAXB 2.1.10 in JDK 6 +// See http://java.sun.com/xml/jaxb +// Any modifications to this file will be lost upon recompilation of the source schema. +// Generated on: 2012.01.31 at 11:07:18 PM EST +// + + +package org.jboss.resteasy.resteasy1055; + +import javax.xml.bind.annotation.XmlAccessType; +import javax.xml.bind.annotation.XmlAccessorType; +import javax.xml.bind.annotation.XmlElement; +import javax.xml.bind.annotation.XmlType; + + +/** + *

Java class for FavoriteMovie complex type. + * + *

The following schema fragment specifies the expected content contained within this class. + * + *

+ * <complexType name="FavoriteMovie">
+ *   <complexContent>
+ *     <restriction base="{http://www.w3.org/2001/XMLSchema}anyType">
+ *       <sequence>
+ *         <element name="title" type="{http://www.w3.org/2001/XMLSchema}string"/>
+ *       </sequence>
+ *     </restriction>
+ *   </complexContent>
+ * </complexType>
+ * 
+ * + * + */ +@XmlAccessorType(XmlAccessType.FIELD) +@XmlType(name = "FavoriteMovie", propOrder = { + "title" +}) +public class FavoriteMovie { + + @XmlElement(required = true) + protected String title; + + /** + * Gets the value of the title property. + * + * @return + * possible object is + * {@link String } + * + */ + public String getTitle() { + return title; + } + + /** + * Sets the value of the title property. + * + * @param value + * allowed object is + * {@link String } + * + */ + public void setTitle(String value) { + this.title = value; + } + +} diff --git a/arquillian/RESTEASY-TEST-EAP6/src/main/java/org/jboss/resteasy/resteasy1055/FavoriteMovieXmlRootElement.java b/arquillian/RESTEASY-TEST-EAP6/src/main/java/org/jboss/resteasy/resteasy1055/FavoriteMovieXmlRootElement.java new file mode 100644 index 00000000000..7a5cacdd090 --- /dev/null +++ b/arquillian/RESTEASY-TEST-EAP6/src/main/java/org/jboss/resteasy/resteasy1055/FavoriteMovieXmlRootElement.java @@ -0,0 +1,14 @@ +package org.jboss.resteasy.resteasy1055; + +import javax.xml.bind.annotation.XmlRootElement; + +@XmlRootElement +public class FavoriteMovieXmlRootElement { + private String _title; + public String getTitle() { + return _title; + } + public void setTitle(String title) { + _title = title; + } +} diff --git a/arquillian/RESTEASY-TEST-EAP6/src/main/java/org/jboss/resteasy/resteasy1055/FavoriteMovieXmlType.java b/arquillian/RESTEASY-TEST-EAP6/src/main/java/org/jboss/resteasy/resteasy1055/FavoriteMovieXmlType.java new file mode 100644 index 00000000000..d9a00844a5a --- /dev/null +++ b/arquillian/RESTEASY-TEST-EAP6/src/main/java/org/jboss/resteasy/resteasy1055/FavoriteMovieXmlType.java @@ -0,0 +1,69 @@ +// +// This file was generated by the JavaTM Architecture for XML Binding(JAXB) Reference Implementation, vJAXB 2.1.10 in JDK 6 +// See http://java.sun.com/xml/jaxb +// Any modifications to this file will be lost upon recompilation of the source schema. +// Generated on: 2012.02.01 at 02:48:20 PM EST +// + + +package org.jboss.resteasy.resteasy1055; + +import javax.xml.bind.annotation.XmlAccessType; +import javax.xml.bind.annotation.XmlAccessorType; +import javax.xml.bind.annotation.XmlElement; +import javax.xml.bind.annotation.XmlType; + + +/** + *

Java class for favoriteMovieXmlType complex type. + * + *

The following schema fragment specifies the expected content contained within this class. + * + *

+ * <complexType name="favoriteMovieXmlType">
+ *   <complexContent>
+ *     <restriction base="{http://www.w3.org/2001/XMLSchema}anyType">
+ *       <sequence>
+ *         <element name="title" type="{http://www.w3.org/2001/XMLSchema}string"/>
+ *       </sequence>
+ *     </restriction>
+ *   </complexContent>
+ * </complexType>
+ * 
+ * + * + */ +@XmlAccessorType(XmlAccessType.FIELD) +@XmlType(name = "favoriteMovieXmlType", propOrder = { + "title" +}) +public class FavoriteMovieXmlType { + + @XmlElement(required = true) + protected String title; + + /** + * Gets the value of the title property. + * + * @return + * possible object is + * {@link String } + * + */ + public String getTitle() { + return title; + } + + /** + * Sets the value of the title property. + * + * @param value + * allowed object is + * {@link String } + * + */ + public void setTitle(String value) { + this.title = value; + } + +} diff --git a/arquillian/RESTEASY-TEST-EAP6/src/main/java/org/jboss/resteasy/resteasy1055/ObjectFactory.java b/arquillian/RESTEASY-TEST-EAP6/src/main/java/org/jboss/resteasy/resteasy1055/ObjectFactory.java new file mode 100644 index 00000000000..c0f7608df00 --- /dev/null +++ b/arquillian/RESTEASY-TEST-EAP6/src/main/java/org/jboss/resteasy/resteasy1055/ObjectFactory.java @@ -0,0 +1,60 @@ +// +// This file was generated by the JavaTM Architecture for XML Binding(JAXB) Reference Implementation, vJAXB 2.1.10 in JDK 6 +// See http://java.sun.com/xml/jaxb +// Any modifications to this file will be lost upon recompilation of the source schema. +// Generated on: 2012.02.01 at 02:48:20 PM EST +// + + +package org.jboss.resteasy.resteasy1055; + +import javax.xml.bind.JAXBElement; +import javax.xml.bind.annotation.XmlElementDecl; +import javax.xml.bind.annotation.XmlRegistry; +import javax.xml.namespace.QName; + + +/** + * This object contains factory methods for each + * Java content interface and Java element interface + * generated in the generated package. + *

An ObjectFactory allows you to programatically + * construct new instances of the Java representation + * for XML content. The Java representation of XML + * content can consist of schema derived interfaces + * and classes representing the binding of schema + * type definitions, element declarations and model + * groups. Factory methods for each of these are + * provided in this class. + * + */ +@XmlRegistry +public class ObjectFactory { + + private final static QName _FavoriteMovie_QNAME = new QName("", "favoriteMovie"); + + /** + * Create a new ObjectFactory that can be used to create new instances of schema derived classes for package: generated + * + */ + public ObjectFactory() { + } + + /** + * Create an instance of {@link FavoriteMovieXmlType } + * + */ + public FavoriteMovieXmlType createFavoriteMovieXmlType() { + return new FavoriteMovieXmlType(); + } + + /** + * Create an instance of {@link JAXBElement }{@code <}{@link FavoriteMovieXmlType }{@code >}} + * + */ + @XmlElementDecl(namespace = "", name = "favoriteMovie") + public JAXBElement createFavoriteMovie(FavoriteMovieXmlType value) { + return new JAXBElement(_FavoriteMovie_QNAME, FavoriteMovieXmlType.class, null, value); + } + +} diff --git a/arquillian/RESTEASY-TEST-EAP6/src/main/java/org/jboss/resteasy/resteasy1055/TestApplication.java b/arquillian/RESTEASY-TEST-EAP6/src/main/java/org/jboss/resteasy/resteasy1055/TestApplication.java new file mode 100644 index 00000000000..fecade13d66 --- /dev/null +++ b/arquillian/RESTEASY-TEST-EAP6/src/main/java/org/jboss/resteasy/resteasy1055/TestApplication.java @@ -0,0 +1,25 @@ +package org.jboss.resteasy.resteasy1055; + +import java.util.HashSet; +import java.util.Set; + +import javax.ws.rs.core.Application; +import javax.ws.rs.ext.Provider; + +/** + * + * @author Ron Sigal + * @version $Revision: 1.1 $ + * + * Copyright Sep 6, 2014 + */ +@Provider +public class TestApplication extends Application +{ + public Set> getClasses() + { + HashSet> classes = new HashSet>(); + classes.add(TestResource.class); + return classes; + } +} diff --git a/arquillian/RESTEASY-TEST-EAP6/src/main/java/org/jboss/resteasy/resteasy1055/TestResource.java b/arquillian/RESTEASY-TEST-EAP6/src/main/java/org/jboss/resteasy/resteasy1055/TestResource.java new file mode 100644 index 00000000000..460cae9f8ae --- /dev/null +++ b/arquillian/RESTEASY-TEST-EAP6/src/main/java/org/jboss/resteasy/resteasy1055/TestResource.java @@ -0,0 +1,119 @@ +package org.jboss.resteasy.resteasy1055; + +import java.util.Iterator; +import java.util.Map; +import java.util.Set; + +import javax.ws.rs.Consumes; +import javax.ws.rs.POST; +import javax.ws.rs.Path; +import javax.ws.rs.core.MediaType; +import javax.xml.bind.JAXBElement; + +@Path("/") +public class TestResource +{ + @POST + @Path("entityExpansion/xmlRootElement") + @Consumes({"application/xml"}) + public String addFavoriteMovie(FavoriteMovieXmlRootElement movie) + { + int len = Math.min(movie.getTitle().length(), 30); + System.out.println("TestResource(xmlRootElment): title = " + movie.getTitle().substring(0, len) + "..."); + System.out.println("foos: " + countFoos(movie.getTitle())); + return movie.getTitle(); + } + + @POST + @Path("entityExpansion/xmlType") + @Consumes({"application/xml"}) + public String addFavoriteMovie(FavoriteMovieXmlType movie) + { + int len = Math.min(movie.getTitle().length(), 30); + System.out.println("TestResource(xmlType): title = " + movie.getTitle().substring(0, len) + "..."); + System.out.println("foos: " + countFoos(movie.getTitle())); + return movie.getTitle(); + } + + @POST + @Path("entityExpansion/JAXBElement") + @Consumes("application/xml") + public String addFavoriteMovie(JAXBElement value) + { + int len = Math.min(value.getValue().getTitle().length(), 30); + System.out.println("TestResource(JAXBElement): title = " + value.getValue().getTitle().substring(0, len) + "..."); + System.out.println("foos: " + countFoos(value.getValue().getTitle())); + return value.getValue().getTitle(); + } + + @POST + @Path("entityExpansion/collection") + @Consumes("application/xml") + public String addFavoriteMovie(Set set) + { + String titles = ""; + Iterator it = set.iterator(); + while (it.hasNext()) + { + String title = it.next().getTitle(); + int len = Math.min(title.length(), 30); + System.out.println("TestResource(collection): title = " + title.substring(0, len) + "..."); + System.out.println("foos: " + countFoos(title)); + titles += title; + } + return titles; + } + + @POST + @Path("entityExpansion/map") + @Consumes("application/xml") + public String addFavoriteMovie(Map map) + { + String titles = ""; + Iterator it = map.keySet().iterator(); + while (it.hasNext()) + { + String title = map.get(it.next()).getTitle(); + int len = Math.min(title.length(), 30); + System.out.println("TestResource(map): title = " + title.substring(0, len) + "..."); + System.out.println("foos: " + countFoos(title)); + titles += title; + } + return titles; + } + + @POST + @Path("DTD") + @Consumes(MediaType.APPLICATION_XML) + public String DTD(Bar bar) + { + System.out.println("bar: " + bar.getS()); + return bar.getS(); + } + + @POST + @Path("maxAttributes") + @Consumes(MediaType.APPLICATION_XML) + public String maxAttributes(Bar bar) + { + System.out.println("bar: " + bar.getS()); + return bar.getS(); + } + + private int countFoos(String s) + { + int count = 0; + int pos = 0; + + while (pos >= 0) + { + pos = s.indexOf("foo", pos); + if (pos >= 0) + { + count++; + pos += 3; + } + } + return count; + } +} diff --git a/arquillian/RESTEASY-TEST-EAP6/src/main/java/org/jboss/resteasy/resteasy1055/external.dtd b/arquillian/RESTEASY-TEST-EAP6/src/main/java/org/jboss/resteasy/resteasy1055/external.dtd new file mode 100644 index 00000000000..7fc8b64ab2b --- /dev/null +++ b/arquillian/RESTEASY-TEST-EAP6/src/main/java/org/jboss/resteasy/resteasy1055/external.dtd @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/arquillian/RESTEASY-TEST-EAP6/src/main/java/org/jboss/resteasy/resteasy1055/movie.xsd b/arquillian/RESTEASY-TEST-EAP6/src/main/java/org/jboss/resteasy/resteasy1055/movie.xsd new file mode 100644 index 00000000000..7b55eefdb0d --- /dev/null +++ b/arquillian/RESTEASY-TEST-EAP6/src/main/java/org/jboss/resteasy/resteasy1055/movie.xsd @@ -0,0 +1,10 @@ + + + + + + + + + + diff --git a/arquillian/RESTEASY-TEST-EAP6/src/main/java/org/jboss/resteasy/resteasy1055/testpasswd b/arquillian/RESTEASY-TEST-EAP6/src/main/java/org/jboss/resteasy/resteasy1055/testpasswd new file mode 100644 index 00000000000..a823614d73b --- /dev/null +++ b/arquillian/RESTEASY-TEST-EAP6/src/main/java/org/jboss/resteasy/resteasy1055/testpasswd @@ -0,0 +1 @@ +xx:xx:xx:xx:xx:xx:xx \ No newline at end of file diff --git a/arquillian/RESTEASY-TEST-EAP6/src/test/java/org/jboss/resteasy/test/resteasy1055/TestSecureProcessing.java b/arquillian/RESTEASY-TEST-EAP6/src/test/java/org/jboss/resteasy/test/resteasy1055/TestSecureProcessing.java new file mode 100644 index 00000000000..f549d059b01 --- /dev/null +++ b/arquillian/RESTEASY-TEST-EAP6/src/test/java/org/jboss/resteasy/test/resteasy1055/TestSecureProcessing.java @@ -0,0 +1,822 @@ +package org.jboss.resteasy.test.resteasy1055; + +import java.util.HashMap; +import java.util.Map; + +import junit.framework.Assert; + +import org.jboss.arquillian.container.test.api.Deployment; +import org.jboss.arquillian.junit.Arquillian; +import org.jboss.resteasy.client.ClientRequest; +import org.jboss.resteasy.client.ClientResponse; +import org.jboss.resteasy.resteasy1055.Bar; +import org.jboss.resteasy.resteasy1055.FavoriteMovie; +import org.jboss.resteasy.resteasy1055.FavoriteMovieXmlRootElement; +import org.jboss.resteasy.resteasy1055.FavoriteMovieXmlType; +import org.jboss.resteasy.resteasy1055.ObjectFactory; +import org.jboss.resteasy.resteasy1055.TestApplication; +import org.jboss.resteasy.resteasy1055.TestResource; +import org.jboss.shrinkwrap.api.Archive; +import org.jboss.shrinkwrap.api.ShrinkWrap; +import org.jboss.shrinkwrap.api.asset.EmptyAsset; +import org.jboss.shrinkwrap.api.spec.WebArchive; +import org.junit.Test; +import org.junit.runner.RunWith; + +/** + * Unit tests for RESTEASY-1055. + * + * @author Ron Sigal + * @date September 1, 2014 + */ +@RunWith(Arquillian.class) +public class TestSecureProcessing +{ + protected static Map EMPTY_MAP = new HashMap(); + protected static enum MapInclusion {DEFAULT, FALSE, TRUE}; + + /////////////////////////////////////////////////////////////////////////////////////////////// + @Deployment(name="ddd", order=1) + public static Archive createTestArchive_ddd() + { + return createTestArchive("ddd", "default_default_default"); + } + + @Deployment(name="ddf", order=2) + public static Archive createTestArchive_ddf() + { + return createTestArchive("ddf", "default_default_false"); + } + + @Deployment(name="ddt", order=3) + public static Archive createTestArchive_ddt() + { + return createTestArchive("ddt", "default_default_true"); + } + + @Deployment(name="dfd", order=4) + public static Archive createTestArchive_dfd() + { + return createTestArchive("dfd", "default_false_default"); + } + + @Deployment(name="dff", order=5) + public static Archive createTestArchive_dff() + { + return createTestArchive("dff", "default_false_false"); + } + + @Deployment(name="dft", order=6) + public static Archive createTestArchive_dft() + { + return createTestArchive("dft", "default_false_true"); + } + + @Deployment(name="dtd", order=7) + public static Archive createTestArchive_dtd() + { + return createTestArchive("dtd", "default_true_default"); + } + + @Deployment(name="dtf", order=8) + public static Archive createTestArchive_dtf() + { + return createTestArchive("dtf", "default_true_false"); + } + + @Deployment(name="dtt", order=9) + public static Archive createTestArchive_dtt() + { + return createTestArchive("dtt", "default_true_true"); + } + + @Deployment(name="fdd", order=10) + public static Archive createTestArchive_fdd() + { + return createTestArchive("fdd", "false_default_default"); + } + + @Deployment(name="fdf", order=11) + public static Archive createTestArchive_fdf() + { + return createTestArchive("fdf", "false_default_false"); + } + + @Deployment(name="fdt", order=12) + public static Archive createTestArchive_fdt() + { + return createTestArchive("fdt", "false_default_true"); + } + + @Deployment(name="ffd", order=13) + public static Archive createTestArchive_ffd() + { + return createTestArchive("ffd", "false_false_default"); + } + + @Deployment(name="fff", order=14) + public static Archive createTestArchive_fff() + { + return createTestArchive("fff", "false_false_false"); + } + + @Deployment(name="fft", order=15) + public static Archive createTestArchive_fft() + { + return createTestArchive("fft", "false_false_true"); + } + /**/ + @Deployment(name="ftd", order=16) + public static Archive createTestArchive_ftd() + { + return createTestArchive("ftd", "false_true_default"); + } + + @Deployment(name="ftf", order=17) + public static Archive createTestArchive_ftf() + { + return createTestArchive("ftf", "false_true_false"); + } + + @Deployment(name="ftt", order=18) + public static Archive createTestArchive_ftt() + { + return createTestArchive("ftt", "false_true_true"); + } + + @Deployment(name="tdd", order=19) + public static Archive createTestArchive_tdd() + { + return createTestArchive("tdd", "true_default_default"); + } + + @Deployment(name="tdf", order=20) + public static Archive createTestArchive_tdf() + { + return createTestArchive("tdf", "true_default_false"); + } + + @Deployment(name="tdt", order=21) + public static Archive createTestArchive_tdt() + { + return createTestArchive("tdt", "true_default_true"); + } + + @Deployment(name="tfd", order=22) + public static Archive createTestArchive_tfd() + { + return createTestArchive("tfd", "true_false_default"); + } + + @Deployment(name="tff", order=23) + public static Archive createTestArchive_tff() + { + return createTestArchive("tff", "true_false_false"); + } + + @Deployment(name="tft", order=24) + public static Archive createTestArchive_tft() + { + return createTestArchive("tft", "true_false_true"); + } + + @Deployment(name="ttd", order=25) + public static Archive createTestArchive_ttd() + { + return createTestArchive("ttd", "true_true_default"); + } + + @Deployment(name="ttf", order=26) + public static Archive createTestArchive_ttf() + { + return createTestArchive("ttf", "true_true_false"); + } + + @Deployment(name="ttt", order=27) + public static Archive createTestArchive_ttt() + { + return createTestArchive("ttt", "true_true_true"); + } + + static Archive createTestArchive(String warExt, String webXmlExt) + { + WebArchive war = ShrinkWrap.create(WebArchive.class, "RESTEASY-1055-" + warExt + ".war") + .addClasses(TestApplication.class, TestResource.class) + .addClasses(Bar.class, FavoriteMovie.class, FavoriteMovieXmlRootElement.class) + .addClasses(FavoriteMovieXmlType.class, ObjectFactory.class) + .addAsWebInfResource("1055/external.dtd", "external.dtd") + .addAsWebInfResource("1055/web_" + webXmlExt + ".xml", "web.xml") + ; + System.out.println(war.toString(true)); + return war; + } + + /////////////////////////////////////////////////////////////////////////////////////////////// + String bigElementDoctype = + "" + + "" + + "" + + "" + + "" + + "" + + "" + + "]>"; + + String bigXmlRootElement = bigElementDoctype + "&foo6;"; + String bigXmlType = bigElementDoctype + "&foo6;"; + String bigJAXBElement = bigElementDoctype + "&foo6;"; + + String bigCollection = bigElementDoctype + + "" + + "&foo6;" + + "&foo6;" + + ""; + + String bigMap = bigElementDoctype + + "" + + "" + + "&foo6;" + + "" + + "" + + "&foo6;" + + "" + + ""; + + String bar = "junk"; + + String filename = "src/main/java/org/jboss/resteasy/resteasy1055/testpasswd"; + + String externalXmlRootElement = + "\r" + + "\r" + + "]>\r" + + "&xxe;"; + + String externalXmlType = + "\r" + + "\r" + + "]>\r" + + "&xxe;"; + + String externalJAXBElement = + "\r" + + "\r" + + "]>\r" + + "&xxe;"; + + String externalCollection = + "\r" + + "\r" + + "]>\r" + + "" + + " &xxe;" + + " &xxe;" + + ""; + + String externalMap = + "\r" + + "\r" + + "]>\r" + + "" + + "" + + "&xxe;" + + "" + + "" + + "&xxe;" + + "" + + ""; + + protected static String bigAttributeDoc; + + static + { + StringBuffer sb = new StringBuffer(); + sb.append("bar"); + bigAttributeDoc = sb.toString(); + } + + /////////////////////////////////////////////////////////////////////////////////////////////// + @Test + public void testSecurityDefaultDTDsDefaultExpansionDefault() throws Exception + { + doTestSkipFailsFailsSkip("ddd"); + } + + @Test + public void testSecurityDefaultDTDsDefaultExpansionFalse() throws Exception + { + doTestSkipFailsFailsSkip("ddf"); + } + + @Test + public void testSecurityDefaultDTDsDefaultExpansionTrue() throws Exception + { + doTestSkipFailsFailsSkip("ddt"); + } + + @Test + public void testSecurityDefaultDTDsFalseExpansionDefault() throws Exception + { + doTestFailsFailsPassesFails("dfd"); + } + + @Test + public void testSecurityDefaultDTDsFalseExpansionFalse() throws Exception + { + doTestFailsFailsPassesFails("dff"); + } + + @Test + public void testSecurityDefaultDTDsFalseExpansionTrue() throws Exception + { + doTestFailsFailsPassesPasses("dft"); + } + + @Test + public void testSecurityDefaultDTDsTrueExpansionDefault() throws Exception + { + doTestSkipFailsFailsSkip("dtd"); + } + + @Test + public void testSecurityDefaultDTDsTrueExpansionFalse() throws Exception + { + doTestSkipFailsFailsSkip("dtf"); + } + + @Test + public void testSecurityDefaultDTDsTrueExpansionTrue() throws Exception + { + doTestSkipFailsFailsSkip("dtt"); + } + + @Test + public void testSecurityFalseDTDsDefaultExpansionDefault() throws Exception + { + doTestSkipPassesFailsSkip("fdd"); + } + + @Test + public void testSecurityFalseDTDsDefaultExpansionFalse() throws Exception + { + doTestSkipPassesFailsSkip("fdf"); + } + + @Test + public void testSecurityFalseDTDsDefaultExpansionTrue() throws Exception + { + doTestSkipPassesFailsSkip("fdt"); + } + + @Test + public void testSecurityFalseDTDsFalseExpansionDefault() throws Exception + { + doTestPassesPassesPassesFails("ffd"); + } + + @Test + public void testSecurityFalseDTDsFalseExpansionFalse() throws Exception + { + doTestPassesPassesPassesFails("fff"); + } + + @Test + public void testSecurityFalseDTDsFalseExpansionTrue() throws Exception + { + doTestPassesPassesPassesPasses("fft"); + } + + @Test + public void testSecurityFalseDTDsTrueExpansionDefault() throws Exception + { + doTestSkipPassesFailsSkip("ftd"); + } + + @Test + public void testSecurityFalseDTDsTrueExpansionFalse() throws Exception + { + doTestSkipPassesFailsSkip("ftf"); + } + + @Test + public void testSecurityFalseDTDsTrueExpansionTrue() throws Exception + { + doTestSkipPassesFailsSkip("ftt"); + } + + @Test + public void testSecurityTrueDTDsDefaultExpansionDefault() throws Exception + { + doTestSkipFailsFailsSkip("tdd"); + } + + @Test + public void testSecurityTrueDTDsDefaultExpansionFalse() throws Exception + { + doTestSkipFailsFailsSkip("tdf"); + } + + @Test + public void testSecurityTrueDTDsDefaultExpansionTrue() throws Exception + { + doTestSkipFailsFailsSkip("tdt"); + } + + @Test + public void testSecurityTrueDTDsFalseExpansionDefault() throws Exception + { + doTestFailsFailsPassesFails("tfd"); + } + + @Test + public void testSecurityTrueDTDsFalseExpansionFalse() throws Exception + { + doTestFailsFailsPassesFails("tff"); + } + + @Test + public void testSecurityTrueDTDsFalseExpansionTrue() throws Exception + { + doTestFailsFailsPassesPasses("tft"); + } + + @Test + public void testSecurityTrueDTDsTrueExpansionDefault() throws Exception + { + doTestSkipFailsFailsSkip("ttd"); + } + + @Test + public void testSecurityTrueDTDsTrueExpansionFalse() throws Exception + { + doTestSkipFailsFailsSkip("ttf"); + } + + @Test + public void testSecurityTrueDTDsTrueExpansionTrue() throws Exception + { + doTestSkipFailsFailsSkip("ttt"); + } + + /////////////////////////////////////////////////////////////////////////////////////////////// + void doTestSkipFailsFailsSkip(String ext) throws Exception + { + doMaxAttributesFails(ext); + doDTDFails(ext); + } + + void doTestSkipPassesFailsSkip(String ext) throws Exception + { + doMaxAttributesPasses(ext); + doDTDFails(ext); + } + + void doTestFailsFailsPassesFails(String ext) throws Exception + { + doEntityExpansionFails(ext); + doMaxAttributesFails(ext); + doDTDPasses(ext); + doExternalEntityExpansionFails(ext); + } + + void doTestFailsFailsPassesPasses(String ext) throws Exception + { + doEntityExpansionFails(ext); + doMaxAttributesFails(ext); + doDTDPasses(ext); + doExternalEntityExpansionPasses(ext); + } + + void doTestPassesPassesPassesFails(String ext) throws Exception + { + doEntityExpansionPasses(ext); + doMaxAttributesPasses(ext); + doDTDPasses(ext); + doDTDPasses(ext); + doExternalEntityExpansionFails(ext); + } + + void doTestPassesPassesPassesPasses(String ext) throws Exception + { + doEntityExpansionPasses(ext); + doMaxAttributesPasses(ext); + doDTDPasses(ext); + doDTDPasses(ext); + doExternalEntityExpansionPasses(ext); + } + + void doEntityExpansionFails(String ext) throws Exception + { + System.out.println("entering doEntityExpansionFails(" + ext + ")"); + { + ClientRequest request = new ClientRequest("http://localhost:8080/RESTEASY-1055-" + ext + "/entityExpansion/xmlRootElement/"); + request.body("application/xml", bigXmlRootElement); + System.out.println("bigXmlRootElement: " + bigXmlRootElement); + ClientResponse response = request.post(); + System.out.println("status: " + response.getStatus()); + Assert.assertEquals(400, response.getStatus()); + String entity = response.getEntity(String.class); + System.out.println("doEntityExpansionFails() result: " + entity); + Assert.assertTrue(entity.contains("javax.xml.bind.UnmarshalException")); + } + { + ClientRequest request = new ClientRequest("http://localhost:8080/RESTEASY-1055-" + ext + "/entityExpansion/xmlType/"); + request.body("application/xml", bigXmlType); + ClientResponse response = request.post(); + System.out.println("status: " + response.getStatus()); + Assert.assertEquals(400, response.getStatus()); + String entity = response.getEntity(String.class); + System.out.println("doEntityExpansionFails() result: " + entity); + Assert.assertTrue(entity.contains("javax.xml.bind.UnmarshalException")); + } + { + ClientRequest request = new ClientRequest("http://localhost:8080/RESTEASY-1055-" + ext + "/entityExpansion/JAXBElement/"); + request.body("application/xml", bigJAXBElement); + ClientResponse response = request.post(); + System.out.println("status: " + response.getStatus()); + Assert.assertEquals(400, response.getStatus()); + String entity = response.getEntity(String.class); + System.out.println("doEntityExpansionFails() result: " + entity); + Assert.assertTrue(entity.contains("javax.xml.bind.UnmarshalException")); + } + { + ClientRequest request = new ClientRequest("http://localhost:8080/RESTEASY-1055-" + ext + "/entityExpansion/collection/"); + request.body("application/xml", bigCollection); + ClientResponse response = request.post(); + System.out.println("status: " + response.getStatus()); + Assert.assertEquals(400, response.getStatus()); + String entity = response.getEntity(String.class); + System.out.println("doEntityExpansionFails() result: " + entity); + Assert.assertTrue(entity.contains("javax.xml.bind.UnmarshalException")); + } + { + ClientRequest request = new ClientRequest("http://localhost:8080/RESTEASY-1055-" + ext + "/entityExpansion/map/"); + request.body("application/xml", bigMap); + ClientResponse response = request.post(); + System.out.println("status: " + response.getStatus()); + Assert.assertEquals(400, response.getStatus()); + String entity = response.getEntity(String.class); + System.out.println("doEntityExpansionFails() result: " + entity); + Assert.assertTrue(entity.contains("javax.xml.bind.UnmarshalException")); + } + } + + void doEntityExpansionPasses(String ext) throws Exception + { + System.out.println("entering doEntityExpansionFails(" + ext + ")"); + { + ClientRequest request = new ClientRequest("http://localhost:8080/RESTEASY-1055-" + ext + "/entityExpansion/xmlRootElement/"); + request.body("application/xml", bigXmlRootElement); + System.out.println("bigXmlRootElement: " + bigXmlRootElement); + ClientResponse response = request.post(); + System.out.println("status: " + response.getStatus()); + Assert.assertEquals(200, response.getStatus()); + String entity = response.getEntity(String.class); + int len = Math.min(entity.length(), 30); + System.out.println("doEntityExpansionPasses() result: " + entity.substring(0, len) + "..."); + Assert.assertEquals(1000000, countFoos(entity)); + } + { + ClientRequest request = new ClientRequest("http://localhost:8080/RESTEASY-1055-" + ext + "/entityExpansion/xmlType/"); + request.body("application/xml", bigXmlType); + ClientResponse response = request.post(); + System.out.println("status: " + response.getStatus()); + Assert.assertEquals(200, response.getStatus()); + String entity = response.getEntity(String.class); + int len = Math.min(entity.length(), 30); + System.out.println("doEntityExpansionPasses() result: " + entity.substring(0, len) + "..."); + Assert.assertEquals(1000000, countFoos(entity)); + } + { + ClientRequest request = new ClientRequest("http://localhost:8080/RESTEASY-1055-" + ext + "/entityExpansion/JAXBElement/"); + request.body("application/xml", bigJAXBElement); + ClientResponse response = request.post(); + System.out.println("status: " + response.getStatus()); + Assert.assertEquals(200, response.getStatus()); + String entity = response.getEntity(String.class); + int len = Math.min(entity.length(), 30); + System.out.println("doEntityExpansionPasses() result: " + entity.substring(0, len) + "..."); + Assert.assertEquals(1000000, countFoos(entity)); + } + { + ClientRequest request = new ClientRequest("http://localhost:8080/RESTEASY-1055-" + ext + "/entityExpansion/collection/"); + request.body("application/xml", bigCollection); + ClientResponse response = request.post(); + System.out.println("status: " + response.getStatus()); + Assert.assertEquals(200, response.getStatus()); + String entity = response.getEntity(String.class); + int len = Math.min(entity.length(), 30); + System.out.println("doEntityExpansionPasses() result: " + entity.substring(0, len) + "..."); + Assert.assertEquals(2000000, countFoos(entity)); + } + { + ClientRequest request = new ClientRequest("http://localhost:8080/RESTEASY-1055-" + ext + "/entityExpansion/map/"); + request.body("application/xml", bigMap); + ClientResponse response = request.post(); + System.out.println("status: " + response.getStatus()); + Assert.assertEquals(200, response.getStatus()); + String entity = response.getEntity(String.class); + int len = Math.min(entity.length(), 30); + System.out.println("doEntityExpansionPasses() result: " + entity.substring(0, len) + "..."); + Assert.assertEquals(2000000, countFoos(entity)); + } + } + + void doMaxAttributesFails(String ext) throws Exception + { + System.out.println("entering doMaxAttributesFails(" + ext + ")"); + ClientRequest request = new ClientRequest("http://localhost:8080/RESTEASY-1055-" + ext + "/maxAttributes/"); + request.body("application/xml", bigAttributeDoc); + ClientResponse response = request.post(); + System.out.println("doMaxAttributesFails() status: " + response.getStatus()); + String entity = response.getEntity(String.class); + System.out.println("doMaxAttributesFails() result: " + entity); +// Assert.assertEquals(400, response.getStatus()); +// Assert.assertTrue(entity.startsWith("javax.xml.bind.UnmarshalException")); +// Assert.assertTrue(entity.contains("has more than \"10,000\" attributes")); + } + + void doMaxAttributesPasses(String ext) throws Exception + { + System.out.println("entering doMaxAttributesPasses(" + ext + ")"); + ClientRequest request = new ClientRequest("http://localhost:8080/RESTEASY-1055-" + ext + "/maxAttributes/"); + request.body("application/xml", bigAttributeDoc); + ClientResponse response = request.post(); + System.out.println("doMaxAttributesPasses() status: " + response.getStatus()); + String entity = response.getEntity(String.class); + System.out.println("doMaxAttributesPasses() result: " + entity); + Assert.assertEquals(204, response.getStatus()); +// Assert.assertEquals("bar", entity); + } + + void doDTDFails(String ext) throws Exception + { + System.out.println("entering doDTDFails(" + ext + ")"); + ClientRequest request = new ClientRequest("http://localhost:8080/RESTEASY-1055-" + ext + "/DTD/"); + request.body("application/xml", bar); + ClientResponse response = request.post(); + System.out.println("status: " + response.getStatus()); + String entity = response.getEntity(String.class); + System.out.println("doDTDFails(): result: " + entity); + Assert.assertEquals(400, response.getStatus()); + Assert.assertTrue(entity.contains("org.xml.sax.SAXParseException")); + Assert.assertTrue(entity.contains("DOCTYPE is disallowed")); + } + + void doDTDPasses(String ext) throws Exception + { + System.out.println("entering doDTDPasses(" + ext + ")"); + ClientRequest request = new ClientRequest("http://localhost:8080/RESTEASY-1055-" + ext + "/DTD/"); + request.body("application/xml", bar); + ClientResponse response = request.post(); + System.out.println("status: " + response.getStatus()); + String entity = response.getEntity(String.class); + System.out.println("doDTDPasses() result: " + entity); + Assert.assertEquals(200, response.getStatus()); + Assert.assertEquals("junk", entity); + } + + void doExternalEntityExpansionFails(String ext) throws Exception + { + System.out.println("entering doExternalEntityExpansionFails(" + ext + ")"); + { + ClientRequest request = new ClientRequest("http://localhost:8080/RESTEASY-1055-" + ext + "/entityExpansion/xmlRootElement/"); + request.body("application/xml", externalXmlRootElement); + ClientResponse response = request.post(); + System.out.println("status: " + response.getStatus()); + String entity = response.getEntity(String.class); + System.out.println("doExternalEntityExpansionFails() result: " + entity); + Assert.assertEquals(200, response.getStatus()); + Assert.assertEquals("", entity); + } + { + ClientRequest request = new ClientRequest("http://localhost:8080/RESTEASY-1055-" + ext + "/entityExpansion/xmlType/"); + request.body("application/xml", externalXmlType); + ClientResponse response = request.post(); + System.out.println("status: " + response.getStatus()); + String entity = response.getEntity(String.class); + System.out.println("doExternalEntityExpansionFails() result: " + entity); + Assert.assertEquals(200, response.getStatus()); + Assert.assertEquals("", entity); + } + { + ClientRequest request = new ClientRequest("http://localhost:8080/RESTEASY-1055-" + ext + "/entityExpansion/JAXBElement/"); + request.body("application/xml", externalJAXBElement); + ClientResponse response = request.post(); + System.out.println("status: " + response.getStatus()); + String entity = response.getEntity(String.class); + System.out.println("doExternalEntityExpansionFails() result: " + entity); + Assert.assertEquals(200, response.getStatus()); + Assert.assertEquals("", entity);; + } + { + ClientRequest request = new ClientRequest("http://localhost:8080/RESTEASY-1055-" + ext + "/entityExpansion/collection/"); + request.body("application/xml", externalCollection); + ClientResponse response = request.post(); + System.out.println("status: " + response.getStatus()); + String entity = response.getEntity(String.class); + System.out.println("doExternalEntityExpansionFails() result: " + entity); + Assert.assertEquals(200, response.getStatus()); + Assert.assertEquals("", entity); + } + { + ClientRequest request = new ClientRequest("http://localhost:8080/RESTEASY-1055-" + ext + "/entityExpansion/map/"); + request.body("application/xml", externalMap); + ClientResponse response = request.post(); + String entity = response.getEntity(String.class); + System.out.println("doExternalEntityExpansionFails() result: " + entity); + System.out.println("status: " + response.getStatus()); + Assert.assertEquals(200, response.getStatus()); + Assert.assertEquals("", entity); + } + } + + void doExternalEntityExpansionPasses(String ext) throws Exception + { + System.out.println("entering doExternalEntityExpansionPasses(" + ext + ")"); + { + ClientRequest request = new ClientRequest("http://localhost:8080/RESTEASY-1055-" + ext + "/entityExpansion/xmlRootElement/"); + request.body("application/xml", externalXmlRootElement); + System.out.println("bigXmlRootElement: " + bigXmlRootElement); + ClientResponse response = request.post(); + System.out.println("status: " + response.getStatus()); + String entity = response.getEntity(String.class); + int len = Math.min(entity.length(), 30); + System.out.println("doExternalEntityExpansionPasses() result: " + entity.substring(0, len) + "..."); + Assert.assertEquals(200, response.getStatus()); + Assert.assertEquals("xx:xx:xx:xx:xx:xx:xx", entity); + } + { + ClientRequest request = new ClientRequest("http://localhost:8080/RESTEASY-1055-" + ext + "/entityExpansion/xmlType/"); + request.body("application/xml", externalXmlType); + ClientResponse response = request.post(); + System.out.println("status: " + response.getStatus()); + String entity = response.getEntity(String.class); + int len = Math.min(entity.length(), 30); + System.out.println("doExternalEntityExpansionPasses() result: " + entity.substring(0, len) + "..."); + Assert.assertEquals(200, response.getStatus()); + Assert.assertEquals("xx:xx:xx:xx:xx:xx:xx", entity); + } + { + ClientRequest request = new ClientRequest("http://localhost:8080/RESTEASY-1055-" + ext + "/entityExpansion/JAXBElement/"); + request.body("application/xml", externalJAXBElement); + ClientResponse response = request.post(); + System.out.println("status: " + response.getStatus()); + String entity = response.getEntity(String.class); + int len = Math.min(entity.length(), 30); + System.out.println("doExternalEntityExpansionPasses() result: " + entity.substring(0, len) + "..."); + Assert.assertEquals(200, response.getStatus()); + Assert.assertEquals("xx:xx:xx:xx:xx:xx:xx", entity); + } + { + ClientRequest request = new ClientRequest("http://localhost:8080/RESTEASY-1055-" + ext + "/entityExpansion/collection/"); + request.body("application/xml", externalCollection); + ClientResponse response = request.post(); + System.out.println("status: " + response.getStatus()); + String entity = response.getEntity(String.class); + int len = Math.min(entity.length(), 30); + System.out.println("doExternalEntityExpansionPasses() result: " + entity.substring(0, len) + "..."); + Assert.assertEquals(200, response.getStatus()); + Assert.assertEquals("xx:xx:xx:xx:xx:xx:xx" + "xx:xx:xx:xx:xx:xx:xx", entity); + } + { + ClientRequest request = new ClientRequest("http://localhost:8080/RESTEASY-1055-" + ext + "/entityExpansion/map/"); + request.body("application/xml", externalMap); + ClientResponse response = request.post(); + System.out.println("status: " + response.getStatus()); + String entity = response.getEntity(String.class); + int len = Math.min(entity.length(), 30); + System.out.println("doExternalEntityExpansionPasses() result: " + entity.substring(0, len) + "..."); + Assert.assertEquals(200, response.getStatus()); + Assert.assertEquals("xx:xx:xx:xx:xx:xx:xx" + "xx:xx:xx:xx:xx:xx:xx", entity); + } + } + + private int countFoos(String s) + { + int count = 0; + int pos = 0; + + while (pos >= 0) + { + pos = s.indexOf("foo", pos); + if (pos >= 0) + { + count++; + pos += 3; + } + } + return count; + } +} diff --git a/arquillian/RESTEASY-TEST-EAP6/src/test/resources/1055/external.dtd b/arquillian/RESTEASY-TEST-EAP6/src/test/resources/1055/external.dtd new file mode 100644 index 00000000000..7fc8b64ab2b --- /dev/null +++ b/arquillian/RESTEASY-TEST-EAP6/src/test/resources/1055/external.dtd @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/arquillian/RESTEASY-TEST-EAP6/src/test/resources/1055/web.xml b/arquillian/RESTEASY-TEST-EAP6/src/test/resources/1055/web.xml new file mode 100644 index 00000000000..54474f66b2c --- /dev/null +++ b/arquillian/RESTEASY-TEST-EAP6/src/test/resources/1055/web.xml @@ -0,0 +1,27 @@ + + + RESTEASY-1008 + + + + + + Resteasy + + + org.jboss.resteasy.plugins.server.servlet.HttpServletDispatcher + + + javax.ws.rs.Application + org.jboss.resteasy.resteasy1103.TestApplication + + + + + Resteasy + /* + + + \ No newline at end of file diff --git a/arquillian/RESTEASY-TEST-EAP6/src/test/resources/1055/web_default_default_default.xml b/arquillian/RESTEASY-TEST-EAP6/src/test/resources/1055/web_default_default_default.xml new file mode 100644 index 00000000000..4b3cf42b2d1 --- /dev/null +++ b/arquillian/RESTEASY-TEST-EAP6/src/test/resources/1055/web_default_default_default.xml @@ -0,0 +1,37 @@ + + + RESTEASY-1103 + + + + + + + Resteasy + + + org.jboss.resteasy.plugins.server.servlet.HttpServletDispatcher + + + javax.ws.rs.Application + org.jboss.resteasy.resteasy1055.TestApplication + + + + + Resteasy + /* + + + \ No newline at end of file diff --git a/arquillian/RESTEASY-TEST-EAP6/src/test/resources/1055/web_default_default_false.xml b/arquillian/RESTEASY-TEST-EAP6/src/test/resources/1055/web_default_default_false.xml new file mode 100644 index 00000000000..ce181b23039 --- /dev/null +++ b/arquillian/RESTEASY-TEST-EAP6/src/test/resources/1055/web_default_default_false.xml @@ -0,0 +1,37 @@ + + + RESTEASY-1103 + + + + + resteasy.document.expand.entity.references + false + + + + Resteasy + + + org.jboss.resteasy.plugins.server.servlet.HttpServletDispatcher + + + javax.ws.rs.Application + org.jboss.resteasy.resteasy1055.TestApplication + + + + + Resteasy + /* + + + \ No newline at end of file diff --git a/arquillian/RESTEASY-TEST-EAP6/src/test/resources/1055/web_default_default_true.xml b/arquillian/RESTEASY-TEST-EAP6/src/test/resources/1055/web_default_default_true.xml new file mode 100644 index 00000000000..b45ebc20a86 --- /dev/null +++ b/arquillian/RESTEASY-TEST-EAP6/src/test/resources/1055/web_default_default_true.xml @@ -0,0 +1,37 @@ + + + RESTEASY-1103 + + + + + resteasy.document.expand.entity.references + true + + + + Resteasy + + + org.jboss.resteasy.plugins.server.servlet.HttpServletDispatcher + + + javax.ws.rs.Application + org.jboss.resteasy.resteasy1055.TestApplication + + + + + Resteasy + /* + + + \ No newline at end of file diff --git a/arquillian/RESTEASY-TEST-EAP6/src/test/resources/1055/web_default_false_default.xml b/arquillian/RESTEASY-TEST-EAP6/src/test/resources/1055/web_default_false_default.xml new file mode 100644 index 00000000000..a6d696e1e0e --- /dev/null +++ b/arquillian/RESTEASY-TEST-EAP6/src/test/resources/1055/web_default_false_default.xml @@ -0,0 +1,37 @@ + + + RESTEASY-1103 + + + + resteasy.document.secure.disableDTDs + false + + + + + Resteasy + + + org.jboss.resteasy.plugins.server.servlet.HttpServletDispatcher + + + javax.ws.rs.Application + org.jboss.resteasy.resteasy1055.TestApplication + + + + + Resteasy + /* + + + \ No newline at end of file diff --git a/arquillian/RESTEASY-TEST-EAP6/src/test/resources/1055/web_default_false_false.xml b/arquillian/RESTEASY-TEST-EAP6/src/test/resources/1055/web_default_false_false.xml new file mode 100644 index 00000000000..b28e6b5303a --- /dev/null +++ b/arquillian/RESTEASY-TEST-EAP6/src/test/resources/1055/web_default_false_false.xml @@ -0,0 +1,37 @@ + + + RESTEASY-1103 + + + + resteasy.document.secure.disableDTDs + false + + + resteasy.document.expand.entity.references + false + + + + Resteasy + + + org.jboss.resteasy.plugins.server.servlet.HttpServletDispatcher + + + javax.ws.rs.Application + org.jboss.resteasy.resteasy1055.TestApplication + + + + + Resteasy + /* + + + \ No newline at end of file diff --git a/arquillian/RESTEASY-TEST-EAP6/src/test/resources/1055/web_default_false_true.xml b/arquillian/RESTEASY-TEST-EAP6/src/test/resources/1055/web_default_false_true.xml new file mode 100644 index 00000000000..2341bb54163 --- /dev/null +++ b/arquillian/RESTEASY-TEST-EAP6/src/test/resources/1055/web_default_false_true.xml @@ -0,0 +1,37 @@ + + + RESTEASY-1103 + + + + resteasy.document.secure.disableDTDs + false + + + resteasy.document.expand.entity.references + true + + + + Resteasy + + + org.jboss.resteasy.plugins.server.servlet.HttpServletDispatcher + + + javax.ws.rs.Application + org.jboss.resteasy.resteasy1055.TestApplication + + + + + Resteasy + /* + + + \ No newline at end of file diff --git a/arquillian/RESTEASY-TEST-EAP6/src/test/resources/1055/web_default_true_default.xml b/arquillian/RESTEASY-TEST-EAP6/src/test/resources/1055/web_default_true_default.xml new file mode 100644 index 00000000000..7c11a108f3f --- /dev/null +++ b/arquillian/RESTEASY-TEST-EAP6/src/test/resources/1055/web_default_true_default.xml @@ -0,0 +1,37 @@ + + + RESTEASY-1103 + + + + resteasy.document.secure.disableDTDs + true + + + + + Resteasy + + + org.jboss.resteasy.plugins.server.servlet.HttpServletDispatcher + + + javax.ws.rs.Application + org.jboss.resteasy.resteasy1055.TestApplication + + + + + Resteasy + /* + + + \ No newline at end of file diff --git a/arquillian/RESTEASY-TEST-EAP6/src/test/resources/1055/web_default_true_false.xml b/arquillian/RESTEASY-TEST-EAP6/src/test/resources/1055/web_default_true_false.xml new file mode 100644 index 00000000000..0c1d042b459 --- /dev/null +++ b/arquillian/RESTEASY-TEST-EAP6/src/test/resources/1055/web_default_true_false.xml @@ -0,0 +1,37 @@ + + + RESTEASY-1103 + + + + resteasy.document.secure.disableDTDs + true + + + resteasy.document.expand.entity.references + false + + + + Resteasy + + + org.jboss.resteasy.plugins.server.servlet.HttpServletDispatcher + + + javax.ws.rs.Application + org.jboss.resteasy.resteasy1055.TestApplication + + + + + Resteasy + /* + + + \ No newline at end of file diff --git a/arquillian/RESTEASY-TEST-EAP6/src/test/resources/1055/web_default_true_true.xml b/arquillian/RESTEASY-TEST-EAP6/src/test/resources/1055/web_default_true_true.xml new file mode 100644 index 00000000000..4e5b9cbdce7 --- /dev/null +++ b/arquillian/RESTEASY-TEST-EAP6/src/test/resources/1055/web_default_true_true.xml @@ -0,0 +1,37 @@ + + + RESTEASY-1103 + + + + resteasy.document.secure.disableDTDs + true + + + resteasy.document.expand.entity.references + true + + + + Resteasy + + + org.jboss.resteasy.plugins.server.servlet.HttpServletDispatcher + + + javax.ws.rs.Application + org.jboss.resteasy.resteasy1055.TestApplication + + + + + Resteasy + /* + + + \ No newline at end of file diff --git a/arquillian/RESTEASY-TEST-EAP6/src/test/resources/1055/web_false_default_default.xml b/arquillian/RESTEASY-TEST-EAP6/src/test/resources/1055/web_false_default_default.xml new file mode 100644 index 00000000000..a2ca5d3959b --- /dev/null +++ b/arquillian/RESTEASY-TEST-EAP6/src/test/resources/1055/web_false_default_default.xml @@ -0,0 +1,37 @@ + + + RESTEASY-1103 + + + resteasy.document.secure.processing.feature + false + + + + + + Resteasy + + + org.jboss.resteasy.plugins.server.servlet.HttpServletDispatcher + + + javax.ws.rs.Application + org.jboss.resteasy.resteasy1055.TestApplication + + + + + Resteasy + /* + + + \ No newline at end of file diff --git a/arquillian/RESTEASY-TEST-EAP6/src/test/resources/1055/web_false_default_false.xml b/arquillian/RESTEASY-TEST-EAP6/src/test/resources/1055/web_false_default_false.xml new file mode 100644 index 00000000000..89661d30625 --- /dev/null +++ b/arquillian/RESTEASY-TEST-EAP6/src/test/resources/1055/web_false_default_false.xml @@ -0,0 +1,37 @@ + + + RESTEASY-1103 + + + resteasy.document.secure.processing.feature + false + + + + resteasy.document.expand.entity.references + false + + + + Resteasy + + + org.jboss.resteasy.plugins.server.servlet.HttpServletDispatcher + + + javax.ws.rs.Application + org.jboss.resteasy.resteasy1055.TestApplication + + + + + Resteasy + /* + + + \ No newline at end of file diff --git a/arquillian/RESTEASY-TEST-EAP6/src/test/resources/1055/web_false_default_true.xml b/arquillian/RESTEASY-TEST-EAP6/src/test/resources/1055/web_false_default_true.xml new file mode 100644 index 00000000000..7e82d8aec95 --- /dev/null +++ b/arquillian/RESTEASY-TEST-EAP6/src/test/resources/1055/web_false_default_true.xml @@ -0,0 +1,37 @@ + + + RESTEASY-1103 + + + resteasy.document.secure.processing.feature + false + + + + resteasy.document.expand.entity.references + true + + + + Resteasy + + + org.jboss.resteasy.plugins.server.servlet.HttpServletDispatcher + + + javax.ws.rs.Application + org.jboss.resteasy.resteasy1055.TestApplication + + + + + Resteasy + /* + + + \ No newline at end of file diff --git a/arquillian/RESTEASY-TEST-EAP6/src/test/resources/1055/web_false_false_default.xml b/arquillian/RESTEASY-TEST-EAP6/src/test/resources/1055/web_false_false_default.xml new file mode 100644 index 00000000000..6974516fa15 --- /dev/null +++ b/arquillian/RESTEASY-TEST-EAP6/src/test/resources/1055/web_false_false_default.xml @@ -0,0 +1,37 @@ + + + RESTEASY-1103 + + + resteasy.document.secure.processing.feature + false + + + resteasy.document.secure.disableDTDs + false + + + + + Resteasy + + + org.jboss.resteasy.plugins.server.servlet.HttpServletDispatcher + + + javax.ws.rs.Application + org.jboss.resteasy.resteasy1055.TestApplication + + + + + Resteasy + /* + + + \ No newline at end of file diff --git a/arquillian/RESTEASY-TEST-EAP6/src/test/resources/1055/web_false_false_false.xml b/arquillian/RESTEASY-TEST-EAP6/src/test/resources/1055/web_false_false_false.xml new file mode 100644 index 00000000000..96ce02dc4f2 --- /dev/null +++ b/arquillian/RESTEASY-TEST-EAP6/src/test/resources/1055/web_false_false_false.xml @@ -0,0 +1,37 @@ + + + RESTEASY-1103 + + + resteasy.document.secure.processing.feature + false + + + resteasy.document.secure.disableDTDs + false + + + resteasy.document.expand.entity.references + false + + + + Resteasy + + + org.jboss.resteasy.plugins.server.servlet.HttpServletDispatcher + + + javax.ws.rs.Application + org.jboss.resteasy.resteasy1055.TestApplication + + + + + Resteasy + /* + + + \ No newline at end of file diff --git a/arquillian/RESTEASY-TEST-EAP6/src/test/resources/1055/web_false_false_true.xml b/arquillian/RESTEASY-TEST-EAP6/src/test/resources/1055/web_false_false_true.xml new file mode 100644 index 00000000000..d7670b198d7 --- /dev/null +++ b/arquillian/RESTEASY-TEST-EAP6/src/test/resources/1055/web_false_false_true.xml @@ -0,0 +1,37 @@ + + + RESTEASY-1103 + + + resteasy.document.secure.processing.feature + false + + + resteasy.document.secure.disableDTDs + false + + + resteasy.document.expand.entity.references + true + + + + Resteasy + + + org.jboss.resteasy.plugins.server.servlet.HttpServletDispatcher + + + javax.ws.rs.Application + org.jboss.resteasy.resteasy1055.TestApplication + + + + + Resteasy + /* + + + \ No newline at end of file diff --git a/arquillian/RESTEASY-TEST-EAP6/src/test/resources/1055/web_false_true_default.xml b/arquillian/RESTEASY-TEST-EAP6/src/test/resources/1055/web_false_true_default.xml new file mode 100644 index 00000000000..7727248606a --- /dev/null +++ b/arquillian/RESTEASY-TEST-EAP6/src/test/resources/1055/web_false_true_default.xml @@ -0,0 +1,37 @@ + + + RESTEASY-1103 + + + resteasy.document.secure.processing.feature + false + + + resteasy.document.secure.disableDTDs + true + + + + + Resteasy + + + org.jboss.resteasy.plugins.server.servlet.HttpServletDispatcher + + + javax.ws.rs.Application + org.jboss.resteasy.resteasy1055.TestApplication + + + + + Resteasy + /* + + + \ No newline at end of file diff --git a/arquillian/RESTEASY-TEST-EAP6/src/test/resources/1055/web_false_true_false.xml b/arquillian/RESTEASY-TEST-EAP6/src/test/resources/1055/web_false_true_false.xml new file mode 100644 index 00000000000..d674555e28f --- /dev/null +++ b/arquillian/RESTEASY-TEST-EAP6/src/test/resources/1055/web_false_true_false.xml @@ -0,0 +1,37 @@ + + + RESTEASY-1103 + + + resteasy.document.secure.processing.feature + false + + + resteasy.document.secure.disableDTDs + true + + + resteasy.document.expand.entity.references + false + + + + Resteasy + + + org.jboss.resteasy.plugins.server.servlet.HttpServletDispatcher + + + javax.ws.rs.Application + org.jboss.resteasy.resteasy1055.TestApplication + + + + + Resteasy + /* + + + \ No newline at end of file diff --git a/arquillian/RESTEASY-TEST-EAP6/src/test/resources/1055/web_false_true_true.xml b/arquillian/RESTEASY-TEST-EAP6/src/test/resources/1055/web_false_true_true.xml new file mode 100644 index 00000000000..76686ba8d36 --- /dev/null +++ b/arquillian/RESTEASY-TEST-EAP6/src/test/resources/1055/web_false_true_true.xml @@ -0,0 +1,37 @@ + + + RESTEASY-1103 + + + resteasy.document.secure.processing.feature + false + + + resteasy.document.secure.disableDTDs + true + + + resteasy.document.expand.entity.references + true + + + + Resteasy + + + org.jboss.resteasy.plugins.server.servlet.HttpServletDispatcher + + + javax.ws.rs.Application + org.jboss.resteasy.resteasy1055.TestApplication + + + + + Resteasy + /* + + + \ No newline at end of file diff --git a/arquillian/RESTEASY-TEST-EAP6/src/test/resources/1055/web_true_default_default.xml b/arquillian/RESTEASY-TEST-EAP6/src/test/resources/1055/web_true_default_default.xml new file mode 100644 index 00000000000..8855dc58263 --- /dev/null +++ b/arquillian/RESTEASY-TEST-EAP6/src/test/resources/1055/web_true_default_default.xml @@ -0,0 +1,37 @@ + + + RESTEASY-1103 + + + resteasy.document.secure.processing.feature + true + + + + + + Resteasy + + + org.jboss.resteasy.plugins.server.servlet.HttpServletDispatcher + + + javax.ws.rs.Application + org.jboss.resteasy.resteasy1055.TestApplication + + + + + Resteasy + /* + + + \ No newline at end of file diff --git a/arquillian/RESTEASY-TEST-EAP6/src/test/resources/1055/web_true_default_false.xml b/arquillian/RESTEASY-TEST-EAP6/src/test/resources/1055/web_true_default_false.xml new file mode 100644 index 00000000000..3d6ab405849 --- /dev/null +++ b/arquillian/RESTEASY-TEST-EAP6/src/test/resources/1055/web_true_default_false.xml @@ -0,0 +1,37 @@ + + + RESTEASY-1103 + + + resteasy.document.secure.processing.feature + true + + + + resteasy.document.expand.entity.references + false + + + + Resteasy + + + org.jboss.resteasy.plugins.server.servlet.HttpServletDispatcher + + + javax.ws.rs.Application + org.jboss.resteasy.resteasy1055.TestApplication + + + + + Resteasy + /* + + + \ No newline at end of file diff --git a/arquillian/RESTEASY-TEST-EAP6/src/test/resources/1055/web_true_default_true.xml b/arquillian/RESTEASY-TEST-EAP6/src/test/resources/1055/web_true_default_true.xml new file mode 100644 index 00000000000..a491c790f55 --- /dev/null +++ b/arquillian/RESTEASY-TEST-EAP6/src/test/resources/1055/web_true_default_true.xml @@ -0,0 +1,37 @@ + + + RESTEASY-1103 + + + resteasy.document.secure.processing.feature + true + + + + resteasy.document.expand.entity.references + true + + + + Resteasy + + + org.jboss.resteasy.plugins.server.servlet.HttpServletDispatcher + + + javax.ws.rs.Application + org.jboss.resteasy.resteasy1055.TestApplication + + + + + Resteasy + /* + + + \ No newline at end of file diff --git a/arquillian/RESTEASY-TEST-EAP6/src/test/resources/1055/web_true_false_default.xml b/arquillian/RESTEASY-TEST-EAP6/src/test/resources/1055/web_true_false_default.xml new file mode 100644 index 00000000000..f0f8fbbafaa --- /dev/null +++ b/arquillian/RESTEASY-TEST-EAP6/src/test/resources/1055/web_true_false_default.xml @@ -0,0 +1,37 @@ + + + RESTEASY-1103 + + + resteasy.document.secure.processing.feature + true + + + resteasy.document.secure.disableDTDs + false + + + + + Resteasy + + + org.jboss.resteasy.plugins.server.servlet.HttpServletDispatcher + + + javax.ws.rs.Application + org.jboss.resteasy.resteasy1055.TestApplication + + + + + Resteasy + /* + + + \ No newline at end of file diff --git a/arquillian/RESTEASY-TEST-EAP6/src/test/resources/1055/web_true_false_false.xml b/arquillian/RESTEASY-TEST-EAP6/src/test/resources/1055/web_true_false_false.xml new file mode 100644 index 00000000000..469df0c164c --- /dev/null +++ b/arquillian/RESTEASY-TEST-EAP6/src/test/resources/1055/web_true_false_false.xml @@ -0,0 +1,37 @@ + + + RESTEASY-1103 + + + resteasy.document.secure.processing.feature + true + + + resteasy.document.secure.disableDTDs + false + + + resteasy.document.expand.entity.references + false + + + + Resteasy + + + org.jboss.resteasy.plugins.server.servlet.HttpServletDispatcher + + + javax.ws.rs.Application + org.jboss.resteasy.resteasy1055.TestApplication + + + + + Resteasy + /* + + + \ No newline at end of file diff --git a/arquillian/RESTEASY-TEST-EAP6/src/test/resources/1055/web_true_false_true.xml b/arquillian/RESTEASY-TEST-EAP6/src/test/resources/1055/web_true_false_true.xml new file mode 100644 index 00000000000..f800dfe94e9 --- /dev/null +++ b/arquillian/RESTEASY-TEST-EAP6/src/test/resources/1055/web_true_false_true.xml @@ -0,0 +1,37 @@ + + + RESTEASY-1103 + + + resteasy.document.secure.processing.feature + true + + + resteasy.document.secure.disableDTDs + false + + + resteasy.document.expand.entity.references + true + + + + Resteasy + + + org.jboss.resteasy.plugins.server.servlet.HttpServletDispatcher + + + javax.ws.rs.Application + org.jboss.resteasy.resteasy1055.TestApplication + + + + + Resteasy + /* + + + \ No newline at end of file diff --git a/arquillian/RESTEASY-TEST-EAP6/src/test/resources/1055/web_true_true_default.xml b/arquillian/RESTEASY-TEST-EAP6/src/test/resources/1055/web_true_true_default.xml new file mode 100644 index 00000000000..692f9fd8ba1 --- /dev/null +++ b/arquillian/RESTEASY-TEST-EAP6/src/test/resources/1055/web_true_true_default.xml @@ -0,0 +1,37 @@ + + + RESTEASY-1103 + + + resteasy.document.secure.processing.feature + true + + + resteasy.document.secure.disableDTDs + true + + + + + Resteasy + + + org.jboss.resteasy.plugins.server.servlet.HttpServletDispatcher + + + javax.ws.rs.Application + org.jboss.resteasy.resteasy1055.TestApplication + + + + + Resteasy + /* + + + \ No newline at end of file diff --git a/arquillian/RESTEASY-TEST-EAP6/src/test/resources/1055/web_true_true_false.xml b/arquillian/RESTEASY-TEST-EAP6/src/test/resources/1055/web_true_true_false.xml new file mode 100644 index 00000000000..8549d6eb0a3 --- /dev/null +++ b/arquillian/RESTEASY-TEST-EAP6/src/test/resources/1055/web_true_true_false.xml @@ -0,0 +1,37 @@ + + + RESTEASY-1103 + + + resteasy.document.secure.processing.feature + true + + + resteasy.document.secure.disableDTDs + true + + + resteasy.document.expand.entity.references + false + + + + Resteasy + + + org.jboss.resteasy.plugins.server.servlet.HttpServletDispatcher + + + javax.ws.rs.Application + org.jboss.resteasy.resteasy1055.TestApplication + + + + + Resteasy + /* + + + \ No newline at end of file diff --git a/arquillian/RESTEASY-TEST-EAP6/src/test/resources/1055/web_true_true_true.xml b/arquillian/RESTEASY-TEST-EAP6/src/test/resources/1055/web_true_true_true.xml new file mode 100644 index 00000000000..6ba0c1df22e --- /dev/null +++ b/arquillian/RESTEASY-TEST-EAP6/src/test/resources/1055/web_true_true_true.xml @@ -0,0 +1,37 @@ + + + RESTEASY-1103 + + + resteasy.document.secure.processing.feature + true + + + resteasy.document.secure.disableDTDs + true + + + resteasy.document.expand.entity.references + true + + + + Resteasy + + + org.jboss.resteasy.plugins.server.servlet.HttpServletDispatcher + + + javax.ws.rs.Application + org.jboss.resteasy.resteasy1055.TestApplication + + + + + Resteasy + /* + + + \ No newline at end of file diff --git a/arquillian/RESTEASY-TEST-EAP6/src/test/resources/arquillian.xml b/arquillian/RESTEASY-TEST-EAP6/src/test/resources/arquillian.xml new file mode 100644 index 00000000000..0d1f29144c1 --- /dev/null +++ b/arquillian/RESTEASY-TEST-EAP6/src/test/resources/arquillian.xml @@ -0,0 +1,23 @@ + + + + + + + target/deployments + + + + + target/jboss-eap-6.3 + standalone-full.xml + -Xmx4096m -XX:MaxPermSize=1024m + + + + + diff --git a/arquillian/pom.xml b/arquillian/pom.xml index 557733aa9cf..9ab7e18d938 100644 --- a/arquillian/pom.xml +++ b/arquillian/pom.xml @@ -19,6 +19,7 @@ RESTEASY-800 RESTEASY-802 RESTEASY-1043 + RESTEASY-TEST-EAP6 - \ No newline at end of file + diff --git a/providers/fastinfoset/src/main/java/org/jboss/resteasy/plugins/providers/jaxb/fastinfoset/FastinfoSetElementProvider.java b/providers/fastinfoset/src/main/java/org/jboss/resteasy/plugins/providers/jaxb/fastinfoset/FastinfoSetElementProvider.java index 688dfe63e16..69f3bc223dd 100644 --- a/providers/fastinfoset/src/main/java/org/jboss/resteasy/plugins/providers/jaxb/fastinfoset/FastinfoSetElementProvider.java +++ b/providers/fastinfoset/src/main/java/org/jboss/resteasy/plugins/providers/jaxb/fastinfoset/FastinfoSetElementProvider.java @@ -16,7 +16,7 @@ public class FastinfoSetElementProvider extends JAXBElementProvider { @Override - protected boolean suppressExpandEntityExpansion() + protected boolean needsSecurity() { return false; } diff --git a/providers/fastinfoset/src/main/java/org/jboss/resteasy/plugins/providers/jaxb/fastinfoset/FastinfoSetXmlRootElementProvider.java b/providers/fastinfoset/src/main/java/org/jboss/resteasy/plugins/providers/jaxb/fastinfoset/FastinfoSetXmlRootElementProvider.java index bdc2f638819..273da29d231 100644 --- a/providers/fastinfoset/src/main/java/org/jboss/resteasy/plugins/providers/jaxb/fastinfoset/FastinfoSetXmlRootElementProvider.java +++ b/providers/fastinfoset/src/main/java/org/jboss/resteasy/plugins/providers/jaxb/fastinfoset/FastinfoSetXmlRootElementProvider.java @@ -16,7 +16,7 @@ public class FastinfoSetXmlRootElementProvider extends JAXBXmlRootElementProvider { @Override - protected boolean suppressExpandEntityExpansion() + protected boolean needsSecurity() { return false; } diff --git a/providers/fastinfoset/src/main/java/org/jboss/resteasy/plugins/providers/jaxb/fastinfoset/FastinfoSetXmlSeeAlsoProvider.java b/providers/fastinfoset/src/main/java/org/jboss/resteasy/plugins/providers/jaxb/fastinfoset/FastinfoSetXmlSeeAlsoProvider.java index ac06073642b..912d6055869 100644 --- a/providers/fastinfoset/src/main/java/org/jboss/resteasy/plugins/providers/jaxb/fastinfoset/FastinfoSetXmlSeeAlsoProvider.java +++ b/providers/fastinfoset/src/main/java/org/jboss/resteasy/plugins/providers/jaxb/fastinfoset/FastinfoSetXmlSeeAlsoProvider.java @@ -16,7 +16,7 @@ public class FastinfoSetXmlSeeAlsoProvider extends JAXBXmlSeeAlsoProvider { @Override - protected boolean suppressExpandEntityExpansion() + protected boolean needsSecurity() { return false; } diff --git a/providers/fastinfoset/src/main/java/org/jboss/resteasy/plugins/providers/jaxb/fastinfoset/FastinfoSetXmlTypeProvider.java b/providers/fastinfoset/src/main/java/org/jboss/resteasy/plugins/providers/jaxb/fastinfoset/FastinfoSetXmlTypeProvider.java index 0ec41799d1e..7543f950049 100644 --- a/providers/fastinfoset/src/main/java/org/jboss/resteasy/plugins/providers/jaxb/fastinfoset/FastinfoSetXmlTypeProvider.java +++ b/providers/fastinfoset/src/main/java/org/jboss/resteasy/plugins/providers/jaxb/fastinfoset/FastinfoSetXmlTypeProvider.java @@ -16,7 +16,7 @@ public class FastinfoSetXmlTypeProvider extends JAXBXmlTypeProvider { @Override - protected boolean suppressExpandEntityExpansion() + protected boolean needsSecurity() { return false; } diff --git a/providers/jaxb/src/main/java/org/jboss/resteasy/plugins/providers/jaxb/AbstractJAXBProvider.java b/providers/jaxb/src/main/java/org/jboss/resteasy/plugins/providers/jaxb/AbstractJAXBProvider.java index 9a2083c85b7..8e217b5d37a 100644 --- a/providers/jaxb/src/main/java/org/jboss/resteasy/plugins/providers/jaxb/AbstractJAXBProvider.java +++ b/providers/jaxb/src/main/java/org/jboss/resteasy/plugins/providers/jaxb/AbstractJAXBProvider.java @@ -38,9 +38,11 @@ public abstract class AbstractJAXBProvider extends AbstractEntityProvider { @Context protected Providers providers; - - private boolean expandEntityReferences = false; + private boolean disableExternalEntities = true; + private boolean enableSecureProcessingFeature = true; + private boolean disableDTDs = true; + public AbstractJAXBProvider() { ResteasyConfiguration context = ResteasyProviderFactory.getContextData(ResteasyConfiguration.class); @@ -49,7 +51,17 @@ public AbstractJAXBProvider() String s = context.getParameter("resteasy.document.expand.entity.references"); if (s != null) { - setExpandEntityReferences(Boolean.parseBoolean(s)); + setDisableExternalEntities(!Boolean.parseBoolean(s)); + } + s = context.getParameter("resteasy.document.secure.processing.feature"); + if (s != null) + { + setEnableSecureProcessingFeature(Boolean.parseBoolean(s)); + } + s = context.getParameter("resteasy.document.secure.disableDTDs"); + if (s != null) + { + setDisableDTDs(Boolean.parseBoolean(s)); } } } @@ -111,9 +123,9 @@ public T readFrom(Class type, Unmarshaller unmarshaller = jaxb.createUnmarshaller(); unmarshaller = decorateUnmarshaller(type, annotations, mediaType, unmarshaller); - if (suppressExpandEntityExpansion()) + if (needsSecurity()) { - return processWithoutEntityExpansion(unmarshaller, entityStream, getCharset(mediaType)); + return processWithSecureProcessing(unmarshaller, entityStream, getCharset(mediaType)); } if (getCharset(mediaType) == null) @@ -247,25 +259,45 @@ public static String getCharset(final MediaType mediaType) } return null; } + + public boolean isDisableExternalEntities() + { + return disableExternalEntities; + } - public boolean isExpandEntityReferences() + public void setDisableExternalEntities(boolean disableExternalEntities) { - return expandEntityReferences; + this.disableExternalEntities = disableExternalEntities; } - public void setExpandEntityReferences(boolean expandEntityReferences) + public boolean isEnableSecureProcessingFeature() { - this.expandEntityReferences = expandEntityReferences; + return enableSecureProcessingFeature; } - - protected boolean suppressExpandEntityExpansion() + + public void setEnableSecureProcessingFeature(boolean enableSecureProcessingFeature) { - return !isExpandEntityReferences(); + this.enableSecureProcessingFeature = enableSecureProcessingFeature; } - - protected T processWithoutEntityExpansion(Unmarshaller unmarshaller, InputStream entityStream, String charset) throws JAXBException + + public boolean isDisableDTDs() + { + return disableDTDs; + } + + public void setDisableDTDs(boolean disableDTDs) { - unmarshaller = new ExternalEntityUnmarshaller(unmarshaller); + this.disableDTDs = disableDTDs; + } + + protected boolean needsSecurity() + { + return true; + } + + protected T processWithSecureProcessing(Unmarshaller unmarshaller, InputStream entityStream, String charset) throws JAXBException + { + unmarshaller = new SecureUnmarshaller(unmarshaller, disableExternalEntities, enableSecureProcessingFeature, disableDTDs); if (charset == null) { InputSource is = new InputSource(entityStream); diff --git a/providers/jaxb/src/main/java/org/jboss/resteasy/plugins/providers/jaxb/CollectionProvider.java b/providers/jaxb/src/main/java/org/jboss/resteasy/plugins/providers/jaxb/CollectionProvider.java index 0ef3ba7ef76..3adf17e541f 100644 --- a/providers/jaxb/src/main/java/org/jboss/resteasy/plugins/providers/jaxb/CollectionProvider.java +++ b/providers/jaxb/src/main/java/org/jboss/resteasy/plugins/providers/jaxb/CollectionProvider.java @@ -57,7 +57,10 @@ public class CollectionProvider implements MessageBodyReader, MessageBod { @Context protected Providers providers; - private boolean expandEntityReferences = false; + + private boolean disableExternalEntities = true; + private boolean enableSecureProcessingFeature = true; + private boolean disableDTDs = true; public CollectionProvider() { @@ -67,7 +70,17 @@ public CollectionProvider() String s = context.getParameter("resteasy.document.expand.entity.references"); if (s != null) { - setExpandEntityReferences(Boolean.parseBoolean(s)); + setDisableExternalEntities(!Boolean.parseBoolean(s)); + } + s = context.getParameter("resteasy.document.secure.processing.feature"); + if (s != null) + { + setEnableSecureProcessingFeature(Boolean.parseBoolean(s)); + } + s = context.getParameter("resteasy.document.secure.disableDTDs"); + if (s != null) + { + setDisableDTDs(Boolean.parseBoolean(s)); } } } @@ -115,7 +128,7 @@ public Object readFrom(Class type, Type genericType, Annotation[] annota { JAXBElement ele = null; - if (suppressExpandEntityExpansion()) + if (needsSecurity()) { SAXSource source = null; if (getCharset(mediaType) == null) @@ -128,7 +141,7 @@ public Object readFrom(Class type, Type genericType, Annotation[] annota } JAXBContext ctx = finder.findCachedContext(JaxbCollection.class, mediaType, annotations); Unmarshaller unmarshaller = ctx.createUnmarshaller(); - unmarshaller = new ExternalEntityUnmarshaller(unmarshaller); + unmarshaller = new SecureUnmarshaller(unmarshaller, disableExternalEntities, enableSecureProcessingFeature, disableDTDs); ele = unmarshaller.unmarshal(source, JaxbCollection.class); } else @@ -275,22 +288,37 @@ public void writeTo(Object entry, Class type, Type genericType, Annotation[] throw new JAXBMarshalException(e); } } - - public boolean isExpandEntityReferences() + + public boolean isDisableExternalEntities() { - return expandEntityReferences; + return disableExternalEntities; } - public void setExpandEntityReferences(boolean expandEntityReferences) + public void setDisableExternalEntities(boolean disableExternalEntities) { - this.expandEntityReferences = expandEntityReferences; + this.disableExternalEntities = disableExternalEntities; } - - protected boolean suppressExpandEntityExpansion() + + public boolean isEnableSecureProcessingFeature() { - return !isExpandEntityReferences(); + return enableSecureProcessingFeature; } - + + public void setEnableSecureProcessingFeature(boolean enableSecureProcessingFeature) + { + this.enableSecureProcessingFeature = enableSecureProcessingFeature; + } + + public boolean isDisableDTDs() + { + return disableDTDs; + } + + public void setDisableDTDs(boolean disableDTDs) + { + this.disableDTDs = disableDTDs; + } + public static String getCharset(final MediaType mediaType) { if (mediaType != null) @@ -299,4 +327,9 @@ public static String getCharset(final MediaType mediaType) } return null; } + + protected boolean needsSecurity() + { + return true; + } } \ No newline at end of file diff --git a/providers/jaxb/src/main/java/org/jboss/resteasy/plugins/providers/jaxb/JAXBElementProvider.java b/providers/jaxb/src/main/java/org/jboss/resteasy/plugins/providers/jaxb/JAXBElementProvider.java index 1f009ee0c8a..30265af5f63 100644 --- a/providers/jaxb/src/main/java/org/jboss/resteasy/plugins/providers/jaxb/JAXBElementProvider.java +++ b/providers/jaxb/src/main/java/org/jboss/resteasy/plugins/providers/jaxb/JAXBElementProvider.java @@ -17,6 +17,7 @@ import javax.xml.transform.stream.StreamSource; import java.io.IOException; import java.io.InputStream; +import java.io.InputStreamReader; import java.io.OutputStream; import java.lang.annotation.Annotation; import java.lang.reflect.Type; @@ -78,17 +79,37 @@ public JAXBElement readFrom(Class> type, { Unmarshaller unmarshaller = jaxb.createUnmarshaller(); unmarshaller = decorateUnmarshaller(type, annotations, mediaType, unmarshaller); - if (suppressExpandEntityExpansion()) + + if (needsSecurity()) { - unmarshaller = new ExternalEntityUnmarshaller(unmarshaller); - SAXSource source = new SAXSource(new InputSource(entityStream)); + unmarshaller = new SecureUnmarshaller(unmarshaller, isDisableExternalEntities(), isEnableSecureProcessingFeature(), isDisableDTDs()); + SAXSource source = null; + if (getCharset(mediaType) == null) + { + source = new SAXSource(new InputSource(new InputStreamReader(entityStream, "UTF-8"))); + } + else + { + source = new SAXSource(new InputSource(entityStream)); + } result = unmarshaller.unmarshal(source, (Class) typeArg); } else { - JAXBElement e = unmarshaller.unmarshal(new StreamSource(entityStream), (Class) typeArg); - result = e; - } + if (getCharset(mediaType) == null) + { + InputSource is = new InputSource(entityStream); + is.setEncoding("UTF-8"); + StreamSource source = new StreamSource(new InputStreamReader(entityStream, "UTF-8")); + source.setInputStream(entityStream); + result = unmarshaller.unmarshal(source, (Class) typeArg); + } + else + { + JAXBElement e = unmarshaller.unmarshal(new StreamSource(entityStream), (Class) typeArg); + result = e; + } + }; } catch (JAXBException e) { diff --git a/providers/jaxb/src/main/java/org/jboss/resteasy/plugins/providers/jaxb/JAXBXmlTypeProvider.java b/providers/jaxb/src/main/java/org/jboss/resteasy/plugins/providers/jaxb/JAXBXmlTypeProvider.java index 4c233e9fe0d..c7c736b81e6 100644 --- a/providers/jaxb/src/main/java/org/jboss/resteasy/plugins/providers/jaxb/JAXBXmlTypeProvider.java +++ b/providers/jaxb/src/main/java/org/jboss/resteasy/plugins/providers/jaxb/JAXBXmlTypeProvider.java @@ -2,6 +2,7 @@ import org.jboss.resteasy.annotations.providers.jaxb.DoNotUseJAXBProvider; import org.jboss.resteasy.util.FindAnnotation; +import org.xml.sax.InputSource; import javax.ws.rs.Consumes; import javax.ws.rs.Produces; @@ -16,8 +17,12 @@ import javax.xml.bind.annotation.XmlRegistry; import javax.xml.bind.annotation.XmlRootElement; import javax.xml.bind.annotation.XmlType; +import javax.xml.transform.sax.SAXSource; +import javax.xml.transform.stream.StreamSource; + import java.io.IOException; import java.io.InputStream; +import java.io.InputStreamReader; import java.io.OutputStream; import java.lang.annotation.Annotation; import java.lang.reflect.InvocationTargetException; @@ -88,11 +93,37 @@ public Object readFrom(Class type, Type genericType, Annotation[] annota JAXBContext jaxb = finder.findCacheXmlTypeContext(mediaType, annotations, type); Unmarshaller unmarshaller = jaxb.createUnmarshaller(); unmarshaller = decorateUnmarshaller(type, annotations, mediaType, unmarshaller); - if (suppressExpandEntityExpansion()) + + Object obj = null; + if (needsSecurity()) + { + SAXSource source = null; + if (getCharset(mediaType) == null) + { + source = new SAXSource(new InputSource(new InputStreamReader(entityStream, "UTF-8"))); + } + else + { + source = new SAXSource(new InputSource(entityStream)); + } + unmarshaller = new SecureUnmarshaller(unmarshaller, isDisableExternalEntities(), isEnableSecureProcessingFeature(), isDisableDTDs()); + obj = unmarshaller.unmarshal(source); + } + else { - unmarshaller = new ExternalEntityUnmarshaller(unmarshaller); + if (getCharset(mediaType) == null) + { + InputSource is = new InputSource(entityStream); + is.setEncoding("UTF-8"); + StreamSource source = new StreamSource(new InputStreamReader(entityStream, "UTF-8")); + source.setInputStream(entityStream); + obj = unmarshaller.unmarshal(source); + } + else + { + obj = unmarshaller.unmarshal(new StreamSource(entityStream)); + } } - Object obj = unmarshaller.unmarshal(entityStream); if (obj instanceof JAXBElement) { JAXBElement element = (JAXBElement) obj; diff --git a/providers/jaxb/src/main/java/org/jboss/resteasy/plugins/providers/jaxb/MapProvider.java b/providers/jaxb/src/main/java/org/jboss/resteasy/plugins/providers/jaxb/MapProvider.java index 5baa2b494fc..45d33d200fc 100644 --- a/providers/jaxb/src/main/java/org/jboss/resteasy/plugins/providers/jaxb/MapProvider.java +++ b/providers/jaxb/src/main/java/org/jboss/resteasy/plugins/providers/jaxb/MapProvider.java @@ -35,6 +35,7 @@ import javax.xml.transform.stream.StreamSource; import java.io.IOException; import java.io.InputStream; +import java.io.InputStreamReader; import java.io.OutputStream; import java.lang.annotation.Annotation; import java.lang.reflect.Type; @@ -52,7 +53,9 @@ public class MapProvider implements MessageBodyReader, MessageBodyWriter { @Context protected Providers providers; - private boolean expandEntityReferences = false; + private boolean disableExternalEntities = true; + private boolean enableSecureProcessingFeature = true; + private boolean disableDTDs = true; public MapProvider() { @@ -62,7 +65,17 @@ public MapProvider() String s = context.getParameter("resteasy.document.expand.entity.references"); if (s != null) { - setExpandEntityReferences(Boolean.parseBoolean(s)); + setDisableExternalEntities(!Boolean.parseBoolean(s)); + } + s = context.getParameter("resteasy.document.secure.processing.feature"); + if (s != null) + { + setEnableSecureProcessingFeature(Boolean.parseBoolean(s)); + } + s = context.getParameter("resteasy.document.secure.disableDTDs"); + if (s != null) + { + setDisableDTDs(Boolean.parseBoolean(s)); } } } @@ -115,16 +128,33 @@ public Object readFrom(Class type, Type genericType, Annotation[] annota try { JAXBContext ctx = finder.findCacheContext(mediaType, annotations, JaxbMap.class, JaxbMap.Entry.class, valueType); - if (suppressExpandEntityExpansion()) + if (needsSecurity()) { - SAXSource source = new SAXSource(new InputSource(entityStream)); + SAXSource source = null; + if (getCharset(mediaType) == null) + { + source = new SAXSource(new InputSource(new InputStreamReader(entityStream, "UTF-8"))); + } + else + { + source = new SAXSource(new InputSource(entityStream)); + } Unmarshaller unmarshaller = ctx.createUnmarshaller(); - unmarshaller = new ExternalEntityUnmarshaller(unmarshaller); + unmarshaller = new SecureUnmarshaller(unmarshaller, disableExternalEntities, enableSecureProcessingFeature, disableDTDs); ele = unmarshaller.unmarshal(source, JaxbMap.class); } else { - StreamSource source = new StreamSource(entityStream); + StreamSource source = null; + if (getCharset(mediaType) == null) + { + source = new StreamSource(new InputStreamReader(entityStream, "UTF-8")); + } + else + { + source = new StreamSource(entityStream); + } + ele = ctx.createUnmarshaller().unmarshal(source, JaxbMap.class); } WrappedMap wrapped = FindAnnotation.findAnnotation(annotations, WrappedMap.class); @@ -242,19 +272,48 @@ public void writeTo(Object target, Class type, Type genericType, Annotation[] throw new JAXBMarshalException(e); } } - - public boolean isExpandEntityReferences() + + public boolean isDisableExternalEntities() { - return expandEntityReferences; + return disableExternalEntities; } - public void setExpandEntityReferences(boolean expandEntityReferences) + public void setDisableExternalEntities(boolean disableExternalEntities) { - this.expandEntityReferences = expandEntityReferences; + this.disableExternalEntities = disableExternalEntities; + } + + public boolean isEnableSecureProcessingFeature() + { + return enableSecureProcessingFeature; + } + + public void setEnableSecureProcessingFeature(boolean enableSecureProcessingFeature) + { + this.enableSecureProcessingFeature = enableSecureProcessingFeature; + } + + public boolean isDisableDTDs() + { + return disableDTDs; + } + + public void setDisableDTDs(boolean disableDTDs) + { + this.disableDTDs = disableDTDs; + } + + public static String getCharset(final MediaType mediaType) + { + if (mediaType != null) + { + return mediaType.getParameters().get("charset"); + } + return null; } - protected boolean suppressExpandEntityExpansion() + protected boolean needsSecurity() { - return !isExpandEntityReferences(); + return true; } } \ No newline at end of file diff --git a/providers/jaxb/src/main/java/org/jboss/resteasy/plugins/providers/jaxb/SecureUnmarshaller.java b/providers/jaxb/src/main/java/org/jboss/resteasy/plugins/providers/jaxb/SecureUnmarshaller.java new file mode 100644 index 00000000000..e2322837f08 --- /dev/null +++ b/providers/jaxb/src/main/java/org/jboss/resteasy/plugins/providers/jaxb/SecureUnmarshaller.java @@ -0,0 +1,278 @@ +package org.jboss.resteasy.plugins.providers.jaxb; + +import java.io.File; +import java.io.InputStream; +import java.io.Reader; +import java.net.URL; + +import javax.xml.XMLConstants; +import javax.xml.bind.JAXBElement; +import javax.xml.bind.JAXBException; +import javax.xml.bind.PropertyException; +import javax.xml.bind.Unmarshaller; +import javax.xml.bind.UnmarshallerHandler; +import javax.xml.bind.ValidationEventHandler; +import javax.xml.bind.annotation.adapters.XmlAdapter; +import javax.xml.bind.attachment.AttachmentUnmarshaller; +import javax.xml.parsers.ParserConfigurationException; +import javax.xml.parsers.SAXParser; +import javax.xml.parsers.SAXParserFactory; +import javax.xml.stream.XMLEventReader; +import javax.xml.stream.XMLInputFactory; +import javax.xml.stream.XMLStreamReader; +import javax.xml.transform.Source; +import javax.xml.transform.sax.SAXSource; +import javax.xml.validation.Schema; + +import org.jboss.resteasy.logging.Logger; +import org.w3c.dom.Node; +import org.xml.sax.InputSource; +import org.xml.sax.SAXException; +import org.xml.sax.SAXNotRecognizedException; +import org.xml.sax.SAXNotSupportedException; +import org.xml.sax.XMLReader; + +/** + * + * @author Ron Sigal + * + * @version $Revision: 1.1 $ + * Created Feb 1, 2012 + */ +public class SecureUnmarshaller implements Unmarshaller { + final static Logger log = Logger.getLogger(SecureUnmarshaller.class); + + private Unmarshaller delegate; + boolean disableExternalEntities; + boolean enableSecureProcessingFeature; + boolean disableDTDs; + + public SecureUnmarshaller(Unmarshaller delegate, boolean disableExternalEntities, boolean enableSecureProcessingFeature, boolean disableDTDs) { + this.delegate = delegate; + this.disableExternalEntities = disableExternalEntities; + this.enableSecureProcessingFeature = enableSecureProcessingFeature; + this.disableDTDs = disableDTDs; + } + + @SuppressWarnings("unchecked") + public A getAdapter(Class type) { + return delegate.getAdapter(type); + } + + public AttachmentUnmarshaller getAttachmentUnmarshaller() { + return delegate.getAttachmentUnmarshaller(); + } + + public ValidationEventHandler getEventHandler() throws JAXBException { + return delegate.getEventHandler(); + } + + public Listener getListener() { + return delegate.getListener(); + } + + public Object getProperty(String name) throws PropertyException { + return delegate.getProperty(name); + } + + public Schema getSchema() { + return delegate.getSchema(); + } + + public UnmarshallerHandler getUnmarshallerHandler() { + return delegate.getUnmarshallerHandler(); + } + + /** + * @deprecated since 2.0 + */ + @Deprecated + public boolean isValidating() throws JAXBException { + return delegate.isValidating(); + } + + /** + * @deprecated since 2.0 + */ + @Deprecated + @SuppressWarnings("unchecked") + public void setAdapter(XmlAdapter adapter) { + delegate.setAdapter(adapter); + } + + @SuppressWarnings("unchecked") + public void setAdapter(Class type, A adapter) { + delegate.setAdapter(adapter); + } + + public void setAttachmentUnmarshaller(AttachmentUnmarshaller au) { + delegate.setAttachmentUnmarshaller(au); + } + + public void setEventHandler(ValidationEventHandler handler)throws JAXBException { + delegate.setEventHandler(handler); + } + + public void setListener(Listener listener) { + delegate.setListener(listener); + } + + public void setProperty(String name, Object value) throws PropertyException { + delegate.setProperty(name, value); + } + + public void setSchema(Schema schema) { + delegate.setSchema(schema); + } + + /** + * @deprecated since 2.0 + */ + @Deprecated + public void setValidating(boolean validating) throws JAXBException { + delegate.setValidating(validating); + } + + public Object unmarshal(File f) throws JAXBException { + throw new UnsupportedOperationException(errorMessage("File")); + } + + /** + * Turns off expansion of external entities. + */ + public Object unmarshal(InputStream is) throws JAXBException { + return unmarshal(new InputSource(is)); + } + + public Object unmarshal(Reader reader) throws JAXBException { + throw new UnsupportedOperationException(errorMessage("Reader")); + } + + public Object unmarshal(URL url) throws JAXBException { + throw new UnsupportedOperationException(errorMessage("URL")); + } + + /** + * Turns off expansion of external entities. + */ + public Object unmarshal(InputSource source) throws JAXBException + { + try + { + SAXParserFactory spf = SAXParserFactory.newInstance(); + configureParserFactory(spf); + SAXParser sp = spf.newSAXParser(); + XMLReader xmlReader = sp.getXMLReader(); + SAXSource saxSource = new SAXSource(xmlReader, source); + return delegate.unmarshal(saxSource); + } + catch (SAXException e) + { + throw new JAXBException(e); + } + catch (ParserConfigurationException e) + { + throw new JAXBException(e); + } + } + + public Object unmarshal(Node node) throws JAXBException { + return delegate.unmarshal(node); + } + + public Object unmarshal(Source source) throws JAXBException { + if(source instanceof SAXSource) + { + try + { + SAXParserFactory spf = SAXParserFactory.newInstance(); + configureParserFactory(spf); + SAXParser sp = spf.newSAXParser(); + XMLReader xmlReader = sp.getXMLReader(); + ((SAXSource) source).setXMLReader(xmlReader); + return delegate.unmarshal(source); + } + catch (SAXException e) + { + throw new JAXBException(e); + } + catch (ParserConfigurationException e) + { + throw new JAXBException(e); + } + } + + throw new UnsupportedOperationException(errorMessage("Source, Class")); + } + + public Object unmarshal(XMLStreamReader reader) throws JAXBException { + throw new UnsupportedOperationException(errorMessage("XMLStreamReader")); + } + + public Object unmarshal(XMLEventReader reader) throws JAXBException { + throw new UnsupportedOperationException(errorMessage("XMLEventReader")); + } + + public JAXBElement unmarshal(Node node, Class declaredType) throws JAXBException { + throw new UnsupportedOperationException(errorMessage("Node, Class")); + } + + public JAXBElement unmarshal(Source source, Class declaredType) throws JAXBException + { + if(source instanceof SAXSource) + { + try + { + SAXParserFactory spf = SAXParserFactory.newInstance(); + configureParserFactory(spf); + SAXParser sp = spf.newSAXParser(); + XMLReader xmlReader = sp.getXMLReader(); + ((SAXSource) source).setXMLReader(xmlReader); + return delegate.unmarshal(source, declaredType); + } + catch (SAXException e) + { + throw new JAXBException(e); + } + catch (ParserConfigurationException e) + { + throw new JAXBException(e); + } + } + + throw new UnsupportedOperationException(errorMessage("Source, Class")); + } + + public JAXBElement unmarshal(XMLStreamReader reader, Class declaredType) throws JAXBException { + throw new UnsupportedOperationException(errorMessage("XMLStreamReader, Class")); + } + + public JAXBElement unmarshal(XMLEventReader reader, Class declaredType) throws JAXBException { + throw new UnsupportedOperationException(errorMessage("XMLEventReader, Class")); + } + + public Unmarshaller getDelegate() + { + return delegate; + } + + public void setDelegate(Unmarshaller delegate) + { + this.delegate = delegate; + } + + protected void configureParserFactory(SAXParserFactory factory) throws ParserConfigurationException, SAXNotRecognizedException, SAXNotSupportedException + { + factory.setFeature("http://xml.org/sax/features/validation", false); + factory.setFeature("http://xml.org/sax/features/namespaces", true); + factory.setFeature("http://xml.org/sax/features/external-general-entities", !disableExternalEntities); + factory.setFeature("http://xml.org/sax/features/external-parameter-entities", !disableExternalEntities); + factory.setFeature(XMLConstants.FEATURE_SECURE_PROCESSING, enableSecureProcessingFeature); + factory.setFeature("http://apache.org/xml/features/disallow-doctype-decl", disableDTDs); + } + + private String errorMessage(String s) + { + return "ExternalEntityUnmarshallerWrapper: unexpected use of unmarshal(" + s + ")"; + } +} diff --git a/providers/jaxb/src/test/java/org/jboss/resteasy/test/xxe/TestSecureProcessingFeature.java b/providers/jaxb/src/test/java/org/jboss/resteasy/test/xxe/TestSecureProcessingFeature.java new file mode 100644 index 00000000000..cb9eae3ad73 --- /dev/null +++ b/providers/jaxb/src/test/java/org/jboss/resteasy/test/xxe/TestSecureProcessingFeature.java @@ -0,0 +1,659 @@ +package org.jboss.resteasy.test.xxe; + +import static org.jboss.resteasy.test.TestPortProvider.generateURL; + +import java.util.HashMap; +import java.util.Hashtable; +import java.util.Iterator; +import java.util.Map; +import java.util.Set; + +import javax.ws.rs.Consumes; +import javax.ws.rs.POST; +import javax.ws.rs.Path; +import javax.ws.rs.core.MediaType; +import javax.xml.bind.JAXBElement; +import javax.xml.bind.annotation.XmlRootElement; + +import junit.framework.Assert; + +import org.jboss.resteasy.client.ClientRequest; +import org.jboss.resteasy.client.ClientResponse; +import org.jboss.resteasy.core.Dispatcher; +import org.jboss.resteasy.spi.ResteasyDeployment; +import org.jboss.resteasy.test.EmbeddedContainer; +import org.junit.After; +import org.junit.Test; + +/**b + * Unit tests for RESTEASY-1103. + * + * @author Ron Sigal + * @date September 1, 2014 + */ +public class TestSecureProcessingFeature +{ + @XmlRootElement + public static class Bar { + private String _s; + public String getS() { + return _s; + } + public void setS(String s) { + _s = s; + } + } + + @XmlRootElement + public static class FavoriteMovieXmlRootElement { + private String _title; + public String getTitle() { + return _title; + } + public void setTitle(String title) { + _title = title; + } + } + + protected static ResteasyDeployment deployment; + protected static Dispatcher dispatcher; + protected static Map EMPTY_MAP = new HashMap(); + protected static enum MapInclusion {DEFAULT, FALSE, TRUE}; + + protected static String bigAttributeDoc; + + static + { + StringBuffer sb = new StringBuffer(); + sb.append(""); + bigAttributeDoc = sb.toString(); + } + + protected static String bigElementDoctype = + "" + + "" + + "" + + "" + + "" + + "" + + "" + + "]>"; + + protected static String bigXmlRootElement = bigElementDoctype + "&foo5;"; + protected static String bigXmlType = bigElementDoctype + "&foo5;"; + protected static String bigJAXBElement = bigElementDoctype + "&foo5;"; + + protected static String bigCollection = + bigElementDoctype + + "" + + "&foo5;" + + "&foo5;" + + ""; + + protected static String bigMap = + bigElementDoctype + + "" + + "" + + "&foo5;" + + "" + + "" + + "&foo5;" + + "" + + ""; + + String bar = "junk"; + + @Path("/") + public static class TestResource + { + @POST + @Path("entityExpansion/xmlRootElement") + @Consumes({"application/xml"}) + public String addFavoriteMovie(FavoriteMovieXmlRootElement movie) + { + System.out.println("TestResource(xmlRootElment): title = " + movie.getTitle().substring(0, 30)); + return movie.getTitle(); + } + + @POST + @Path("entityExpansion/xmlType") + @Consumes({"application/xml"}) + public String addFavoriteMovie(FavoriteMovieXmlType movie) + { + System.out.println("TestResource(xmlType): title = " + movie.getTitle().substring(0, 30)); + return movie.getTitle(); + } + + @POST + @Path("entityExpansion/JAXBElement") + @Consumes("application/xml") + public String addFavoriteMovie(JAXBElement value) + { + System.out.println("TestResource(JAXBElement): title = " + value.getValue().getTitle().substring(0, 30)); + return value.getValue().getTitle(); + } + + @POST + @Path("entityExpansion/collection") + @Consumes("application/xml") + public String addFavoriteMovie(Set set) + { + String titles = ""; + Iterator it = set.iterator(); + while (it.hasNext()) + { + String title = it.next().getTitle(); + System.out.println("TestResource(collection): title = " + title.substring(0, 30)); + titles += title; + } + return titles; + } + + @POST + @Path("entityExpansion/map") + @Consumes("application/xml") + public String addFavoriteMovie(Map map) + { + String titles = ""; + Iterator it = map.keySet().iterator(); + while (it.hasNext()) + { + String title = map.get(it.next()).getTitle(); + System.out.println("TestResource(map): title = " + title.substring(0, 30)); + titles += title; + } + return titles; + } + + @POST + @Path("DTD") + @Consumes(MediaType.APPLICATION_XML) + public String DTD(Bar bar) + { + System.out.println("bar: " + bar.getS()); + return bar.getS(); + } + + @POST + @Path("maxAttributes") + @Consumes(MediaType.APPLICATION_XML) + public String maxAttributes(Bar bar) + { + System.out.println("bar: " + bar.getS()); + return "bar"; + } + } + + public static void before(Hashtable contextParams) throws Exception + { + Hashtable initParams = new Hashtable(); + deployment = EmbeddedContainer.start(initParams, contextParams); + dispatcher = deployment.getDispatcher(); + deployment.getRegistry().addPerRequestResource(TestResource.class); + } + + @After + public void after() throws Exception + { + EmbeddedContainer.stop(); + dispatcher = null; + deployment = null; + } + + @Test + public void testSecurityDefaultDTDsDefaultExpansionDefault() throws Exception + { + before(getParameterMap(MapInclusion.DEFAULT, MapInclusion.DEFAULT, MapInclusion.DEFAULT)); + doDTDFails(); + doMaxAttributesFails(); + } + + @Test + public void testSecurityDefaultDTDsDefaultExpansionFalse() throws Exception + { + before(getParameterMap(MapInclusion.DEFAULT, MapInclusion.DEFAULT, MapInclusion.FALSE)); + doDTDFails(); + doMaxAttributesFails(); + } + + @Test + public void testSecurityDefaultDTDsDefaultExpansionTrue() throws Exception + { + before(getParameterMap(MapInclusion.DEFAULT, MapInclusion.DEFAULT, MapInclusion.TRUE)); + doDTDFails(); + doMaxAttributesFails(); + } + + @Test + public void testSecurityDefaultDTDsFalseExpansionDefault() throws Exception + { + before(getParameterMap(MapInclusion.DEFAULT, MapInclusion.FALSE, MapInclusion.DEFAULT)); + doDTDPasses(); + doMaxEntitiesFails(); + doMaxAttributesFails(); + } + + @Test + public void testSecurityDefaultDTDsFalseExpansionFalse() throws Exception + { + before(getParameterMap(MapInclusion.DEFAULT, MapInclusion.FALSE, MapInclusion.FALSE)); + doDTDPasses(); + doMaxEntitiesFails(); + doMaxAttributesFails(); + } + + @Test + public void testSecurityDefaultDTDsFalseExpansionTrue() throws Exception + { + before(getParameterMap(MapInclusion.DEFAULT, MapInclusion.FALSE, MapInclusion.TRUE)); + doDTDPasses(); + doMaxEntitiesFails(); + doMaxAttributesFails(); + } + + @Test + public void testSecurityDefaultDTDsTrueExpansionDefault() throws Exception + { + before(getParameterMap(MapInclusion.DEFAULT, MapInclusion.TRUE, MapInclusion.DEFAULT)); + doDTDFails(); + doMaxAttributesFails(); + } + + @Test + public void testSecurityDefaultDTDsTrueExpansionFalse() throws Exception + { + before(getParameterMap(MapInclusion.DEFAULT, MapInclusion.TRUE, MapInclusion.FALSE)); + doDTDFails(); + doMaxAttributesFails(); + } + + @Test + public void testSecurityDefaultDTDsTrueExpansionTrue() throws Exception + { + before(getParameterMap(MapInclusion.DEFAULT, MapInclusion.TRUE, MapInclusion.TRUE)); + doDTDFails(); + doMaxAttributesFails(); + } + + @Test + public void testSecurityFalseDTDsDefaultExpansionDefault() throws Exception + { + before(getParameterMap(MapInclusion.FALSE, MapInclusion.DEFAULT, MapInclusion.DEFAULT)); + doDTDFails(); + doMaxAttributesPasses(); + } + + @Test + public void testSecurityFalseDTDsDefaultExpansionFalse() throws Exception + { + before(getParameterMap(MapInclusion.FALSE, MapInclusion.DEFAULT, MapInclusion.FALSE)); + doDTDFails(); + doMaxAttributesPasses(); + } + + @Test + public void testSecurityFalseDTDsDefaultExpansionTrue() throws Exception + { + before(getParameterMap(MapInclusion.FALSE, MapInclusion.DEFAULT, MapInclusion.TRUE)); + doDTDFails(); + doMaxAttributesPasses(); + } + + @Test + public void testSecurityFalseDTDsFalseExpansionDefault() throws Exception + { + before(getParameterMap(MapInclusion.FALSE, MapInclusion.FALSE, MapInclusion.DEFAULT)); + doDTDPasses(); + doMaxEntitiesPasses(); + doMaxAttributesPasses(); + } + + @Test + public void testSecurityFalseDTDsFalseExpansionFalse() throws Exception + { + before(getParameterMap(MapInclusion.FALSE, MapInclusion.FALSE, MapInclusion.FALSE)); + doDTDPasses(); + doMaxEntitiesPasses(); + doMaxAttributesPasses(); + } + + @Test + public void testSecurityFalseDTDsFalseExpansionTrue() throws Exception + { + before(getParameterMap(MapInclusion.FALSE, MapInclusion.FALSE, MapInclusion.TRUE)); + doDTDPasses(); + doMaxEntitiesPasses(); + doMaxAttributesPasses(); + } + + @Test + public void testSecurityFalseDTDsTrueExpansionDefault() throws Exception + { + before(getParameterMap(MapInclusion.FALSE, MapInclusion.TRUE, MapInclusion.DEFAULT)); + doDTDFails(); + doMaxAttributesPasses(); + } + + @Test + public void testSecurityFalseDTDsTrueExpansionFalse() throws Exception + { + before(getParameterMap(MapInclusion.FALSE, MapInclusion.TRUE, MapInclusion.FALSE)); + doDTDFails(); + doMaxAttributesPasses(); + } + + @Test + public void testSecurityFalseDTDsTrueExpansionTrue() throws Exception + { + before(getParameterMap(MapInclusion.FALSE, MapInclusion.TRUE, MapInclusion.TRUE)); + doDTDFails(); + doMaxAttributesPasses(); + } + + @Test + public void testSecurityTrueDTDsDefaultExpansionDefault() throws Exception + { + before(getParameterMap(MapInclusion.TRUE, MapInclusion.DEFAULT, MapInclusion.DEFAULT)); + doDTDFails(); + doMaxAttributesFails(); + } + + @Test + public void testSecurityTrueDTDsDefaultExpansionFalse() throws Exception + { + before(getParameterMap(MapInclusion.TRUE, MapInclusion.DEFAULT, MapInclusion.FALSE)); + doDTDFails(); + doMaxAttributesFails(); + } + + @Test + public void testSecurityTrueDTDsDefaultExpansionTrue() throws Exception + { + before(getParameterMap(MapInclusion.TRUE, MapInclusion.DEFAULT, MapInclusion.TRUE)); + doDTDFails(); + doMaxAttributesFails(); + } + + @Test + public void testSecurityTrueDTDsFalseExpansionDefault() throws Exception + { + before(getParameterMap(MapInclusion.TRUE, MapInclusion.FALSE, MapInclusion.DEFAULT)); + doDTDPasses(); + doMaxEntitiesFails(); + doMaxAttributesFails(); + } + + @Test + public void testSecurityTrueDTDsFalseExpansionFalse() throws Exception + { + before(getParameterMap(MapInclusion.TRUE, MapInclusion.FALSE, MapInclusion.FALSE)); + doDTDPasses(); + doMaxEntitiesFails(); + doMaxAttributesFails(); + } + + @Test + public void testSecurityTrueDTDsFalseExpansionTrue() throws Exception + { + before(getParameterMap(MapInclusion.TRUE, MapInclusion.FALSE, MapInclusion.TRUE)); + doDTDPasses(); + doMaxEntitiesFails(); + doMaxAttributesFails(); + } + + @Test + public void testSecurityTrueDTDsTrueExpansionDefault() throws Exception + { + before(getParameterMap(MapInclusion.TRUE, MapInclusion.TRUE, MapInclusion.DEFAULT)); + doDTDFails(); + doMaxAttributesFails(); + } + + @Test + public void testSecurityTrueDTDsTrueExpansionFalse() throws Exception + { + before(getParameterMap(MapInclusion.TRUE, MapInclusion.TRUE, MapInclusion.FALSE)); + doDTDFails(); + doMaxAttributesFails(); + } + + @Test + public void testSecurityTrueDTDsTrueExpansionTrue() throws Exception + { + before(getParameterMap(MapInclusion.TRUE, MapInclusion.TRUE, MapInclusion.TRUE)); + doDTDFails(); + doMaxAttributesFails(); + } + + void doDTDFails() throws Exception + { + ClientRequest request = new ClientRequest(generateURL("/DTD")); + request.body("application/xml", bar); + ClientResponse response = request.post(); + System.out.println("status: " + response.getStatus()); + String entity = response.getEntity(String.class); + System.out.println("doExternalDTDFails(): result: " + entity); + Assert.assertEquals(400, response.getStatus()); + Assert.assertTrue(entity.contains("javax.xml.bind.UnmarshalException")); + Assert.assertTrue(entity.contains("DOCTYPE is disallowed")); + } + + void doDTDPasses() throws Exception + { + ClientRequest request = new ClientRequest(generateURL("/DTD")); + request.body("application/xml", bar); + ClientResponse response = request.post(); + System.out.println("status: " + response.getStatus()); + String entity = response.getEntity(String.class); + System.out.println("doExternalDTDPasses() result: " + entity); + Assert.assertEquals(200, response.getStatus()); + Assert.assertEquals("junk", entity); + } + + void doMaxEntitiesFails() throws Exception + { + { + ClientRequest request = new ClientRequest(generateURL("/entityExpansion/xmlRootElement")); + request.body("application/xml", bigXmlRootElement); + ClientResponse response = request.post(); + System.out.println("status: " + response.getStatus()); + String entity = response.getEntity(String.class); + System.out.println("doMaxEntitiesFails() result: " + entity); + Assert.assertEquals(400, response.getStatus()); + Assert.assertTrue(entity.contains("javax.xml.bind.UnmarshalException")); + } + { + ClientRequest request = new ClientRequest(generateURL("/entityExpansion/xmlType")); + request.body("application/xml", bigXmlType); + ClientResponse response = request.post(); + System.out.println("status: " + response.getStatus()); + String entity = response.getEntity(String.class); + System.out.println("doMaxEntitiesFails() result: " + entity); + Assert.assertEquals(400, response.getStatus()); + Assert.assertTrue(entity.contains("javax.xml.bind.UnmarshalException")); + } + { + ClientRequest request = new ClientRequest(generateURL("/entityExpansion/JAXBElement")); + request.body("application/xml", bigJAXBElement); + ClientResponse response = request.post(); + System.out.println("status: " + response.getStatus()); + String entity = response.getEntity(String.class); + System.out.println("doMaxEntitiesFails() result: " + entity); + Assert.assertEquals(400, response.getStatus()); + Assert.assertTrue(entity.contains("javax.xml.bind.UnmarshalException")); + } + { + ClientRequest request = new ClientRequest(generateURL("/entityExpansion/collection")); + request.body("application/xml", bigCollection); + ClientResponse response = request.post(); + System.out.println("status: " + response.getStatus()); + String entity = response.getEntity(String.class); + System.out.println("doMaxEntitiesFails() result: " + entity); + Assert.assertEquals(400, response.getStatus()); + Assert.assertTrue(entity.contains("javax.xml.bind.UnmarshalException")); + } + { + ClientRequest request = new ClientRequest(generateURL("/entityExpansion/map")); + request.body("application/xml", bigMap); + ClientResponse response = request.post(); + System.out.println("status: " + response.getStatus()); + String entity = response.getEntity(String.class); + System.out.println("doMaxEntitiesFails() result: " + entity); + Assert.assertEquals(400, response.getStatus()); + Assert.assertTrue(entity.contains("javax.xml.bind.UnmarshalException")); + } + } + + void doMaxEntitiesPasses() throws Exception + { + System.out.println("entering doEntityExpansionPasses()"); + { + ClientRequest request = new ClientRequest(generateURL("/entityExpansion/xmlRootElement")); + request.body("application/xml", bigXmlRootElement); + ClientResponse response = request.post(); + System.out.println("status: " + response.getStatus()); + String entity = response.getEntity(String.class); + System.out.println("doMaxEntitiesPasses() result: " + entity.substring(0, 30) + "..."); + Assert.assertEquals(200, response.getStatus()); + Assert.assertEquals(100000, countFoos(entity)); + } + { + ClientRequest request = new ClientRequest(generateURL("/entityExpansion/xmlType")); + request.body("application/xml", bigXmlType); + ClientResponse response = request.post(); + System.out.println("status: " + response.getStatus()); + String entity = response.getEntity(String.class); + System.out.println("doMaxEntitiesPasses() result: " + entity.substring(0, 30) + "..."); + Assert.assertEquals(200, response.getStatus()); + Assert.assertEquals(100000, countFoos(entity)); + } + { + ClientRequest request = new ClientRequest(generateURL("/entityExpansion/JAXBElement")); + request.body("application/xml", bigJAXBElement); + ClientResponse response = request.post(); + System.out.println("status: " + response.getStatus()); + String entity = response.getEntity(String.class); + System.out.println("doMaxEntitiesPasses() result: " + entity.substring(0, 30) + "..."); + Assert.assertEquals(200, response.getStatus()); + Assert.assertEquals(100000, countFoos(entity)); + } + { + ClientRequest request = new ClientRequest(generateURL("/entityExpansion/collection")); + request.body("application/xml", bigCollection); + ClientResponse response = request.post(); + System.out.println("status: " + response.getStatus()); + String entity = response.getEntity(String.class); + System.out.println("doMaxEntitiesPasses() result: " + entity.substring(0, 30) + "..."); + Assert.assertEquals(200, response.getStatus()); + Assert.assertEquals(200000, countFoos(entity)); + } + { + ClientRequest request = new ClientRequest(generateURL("/entityExpansion/map")); + request.body("application/xml", bigMap); + ClientResponse response = request.post(); + System.out.println("status: " + response.getStatus()); + String entity = response.getEntity(String.class); + System.out.println("doEntityExpansionPasses() result: " + entity.substring(0, 30) + "..."); + Assert.assertEquals(200, response.getStatus()); + Assert.assertEquals(200000, countFoos(entity)); + } + } + + void doMaxAttributesFails() throws Exception + { + ClientRequest request = new ClientRequest(generateURL("/maxAttributes")); + request.body("application/xml", bigAttributeDoc); + ClientResponse response = request.post(); + System.out.println("status: " + response.getStatus()); + String entity = response.getEntity(String.class); + System.out.println("doMaxAttributesFails() result: " + entity); + Assert.assertEquals(400, response.getStatus()); + Assert.assertTrue(entity.contains("javax.xml.bind.UnmarshalException")); + Assert.assertTrue(entity.contains("has more than")); + int pos = entity.indexOf("has more than"); + Assert.assertTrue(entity.substring(pos).contains("10,00")); + pos = entity.indexOf("10,00", pos); + Assert.assertTrue(entity.substring(pos).contains("attributes")); + } + + void doMaxAttributesPasses() throws Exception + { + ClientRequest request = new ClientRequest(generateURL("/maxAttributes")); + request.body("application/xml", bigAttributeDoc); + ClientResponse response = request.post(); + System.out.println("status: " + response.getStatus()); + String entity = response.getEntity(String.class); + System.out.println("doMaxAttributesPasses() result: " + entity); + Assert.assertEquals(200, response.getStatus()); + Assert.assertEquals("bar", entity); + } + + private Hashtable getParameterMap(MapInclusion securityFeature, MapInclusion disableDTDs, MapInclusion expandEntities) + { + Hashtable map = new Hashtable(); + switch (securityFeature) + { + case DEFAULT: + break; + + case FALSE: + map.put("resteasy.document.secure.processing.feature", "false"); + break; + + case TRUE: + map.put("resteasy.document.secure.processing.feature", "true"); + break; + } + switch (disableDTDs) + { + case DEFAULT: + break; + + case FALSE: + map.put("resteasy.document.secure.disableDTDs", "false"); + break; + + case TRUE: + map.put("resteasy.document.secure.disableDTDs", "true"); + break; + } + switch (expandEntities) + { + case DEFAULT: + break; + + case FALSE: + map.put("resteasy.document.expand.entity.references", "false"); + break; + + case TRUE: + map.put("resteasy.document.expand.entity.references", "true"); + break; + } + return map; + } + + + private int countFoos(String s) + { + int count = 0; + int pos = 0; + + while (pos >= 0) + { + pos = s.indexOf("foo", pos); + if (pos >= 0) + { + count++; + pos += 3; + } + } + return count; + } +} diff --git a/providers/jaxb/src/test/java/org/jboss/resteasy/test/xxe/TestXXE.java b/providers/jaxb/src/test/java/org/jboss/resteasy/test/xxe/TestXXE.java index 72b6ce8ac9f..db2657ef41d 100644 --- a/providers/jaxb/src/test/java/org/jboss/resteasy/test/xxe/TestXXE.java +++ b/providers/jaxb/src/test/java/org/jboss/resteasy/test/xxe/TestXXE.java @@ -1,42 +1,40 @@ package org.jboss.resteasy.test.xxe; -import static org.jboss.resteasy.test.TestPortProvider.*; +import junit.framework.Assert; +import org.jboss.resteasy.client.ClientRequest; +import org.jboss.resteasy.client.ClientResponse; +import org.jboss.resteasy.core.Dispatcher; +import org.jboss.resteasy.spi.ResteasyDeployment; +import org.jboss.resteasy.test.EmbeddedContainer; +import org.junit.After; +import org.junit.Test; -import java.io.File; +import javax.ws.rs.Consumes; +import javax.ws.rs.POST; +import javax.ws.rs.Path; +import javax.xml.bind.JAXBElement; +import javax.xml.bind.annotation.XmlRootElement; import java.util.Hashtable; import java.util.Iterator; import java.util.List; import java.util.Map; import java.util.Set; -import javax.ws.rs.Consumes; -import javax.ws.rs.POST; -import javax.ws.rs.Path; -import javax.xml.bind.JAXBElement; - -import junit.framework.Assert; - -import org.jboss.resteasy.client.ClientRequest; -import org.jboss.resteasy.client.ClientResponse; -import org.jboss.resteasy.test.BaseResourceTest; -import org.junit.Before; -import org.junit.Test; +import static org.jboss.resteasy.test.TestPortProvider.generateURL; /** * Unit tests for RESTEASY-647. - * - * Idea for test comes from Tim McCune: + * + * Idea for test comes from Tim McCune: * http://jersey.576304.n2.nabble.com/Jersey-vulnerable-to-XXE-attack-td3214584.html * + * @author Ron Sigal + * @date Jan 6, 2012 */ -public class TestXXE extends BaseResourceTest +public class TestXXE { - @Override - @Before - public void before() throws Exception { - manualStart = true; - super.before(); - } + protected static ResteasyDeployment deployment; + protected static Dispatcher dispatcher; @Path("/") public static class MovieResource @@ -49,7 +47,7 @@ public String addFavoriteMovie(FavoriteMovieXmlRootElement movie) System.out.println("MovieResource(xmlRootElment): title = " + movie.getTitle()); return movie.getTitle(); } - + @POST @Path("xmlType") @Consumes({"application/xml"}) @@ -58,7 +56,7 @@ public String addFavoriteMovie(FavoriteMovieXmlType movie) System.out.println("MovieResource(xmlType): title = " + movie.getTitle()); return movie.getTitle(); } - + @POST @Path("JAXBElement") @Consumes("application/xml") @@ -67,7 +65,7 @@ public String addFavoriteMovie(JAXBElement value) System.out.println("MovieResource(JAXBElement): title = " + value.getValue().getTitle()); return value.getValue().getTitle(); } - + @POST @Path("list") @Consumes("application/xml") @@ -83,7 +81,7 @@ public String addFavoriteMovie(List list) } return titles; } - + @POST @Path("set") @Consumes("application/xml") @@ -99,7 +97,7 @@ public String addFavoriteMovie(Set set) } return titles; } - + @POST @Path("array") @Consumes("application/xml") @@ -114,7 +112,7 @@ public String addFavoriteMovie(FavoriteMovieXmlRootElement[] array) } return titles; } - + @POST @Path("map") @Consumes("application/xml") @@ -132,38 +130,66 @@ public String addFavoriteMovie(Map map) } } - public void before(String expandEntityReferences) throws Exception + @XmlRootElement + public static class FavoriteMovieXmlRootElement { + private String _title; + public String getTitle() { + return _title; + } + public void setTitle(String title) { + _title = title; + } + } + + public static void before(String expandEntityReferences, String enableSecurityFeature) throws Exception { Hashtable initParams = new Hashtable(); Hashtable contextParams = new Hashtable(); + contextParams.put("resteasy.document.secure.processing.feature", enableSecurityFeature); + contextParams.put("resteasy.document.secure.disableDTDs", "false"); contextParams.put("resteasy.document.expand.entity.references", expandEntityReferences); - createContainer(initParams, contextParams); - addPerRequestResource(MovieResource.class, FavoriteMovieXmlRootElement.class, FavoriteMovieXmlType.class, FavoriteMovie.class, ObjectFactory.class); - startContainer(); + deployment = EmbeddedContainer.start(initParams, contextParams); + dispatcher = deployment.getDispatcher(); + deployment.getRegistry().addPerRequestResource(MovieResource.class); } - public void beforeStart() throws Exception + public static void before(String enableSecurityFeature) throws Exception { Hashtable initParams = new Hashtable(); Hashtable contextParams = new Hashtable(); - createContainer(initParams, contextParams); - addPerRequestResource(MovieResource.class, FavoriteMovieXmlRootElement.class, FavoriteMovieXmlType.class, FavoriteMovie.class, FavoriteMovie.class, ObjectFactory.class); - startContainer(); + contextParams.put("resteasy.document.secure.processing.feature", enableSecurityFeature); + contextParams.put("resteasy.document.secure.disableDTDs", "false"); + deployment = EmbeddedContainer.start(initParams, contextParams); + dispatcher = deployment.getDispatcher(); + deployment.getRegistry().addPerRequestResource(MovieResource.class); + } + +// @After + public void after() throws Exception + { + EmbeddedContainer.stop(); + dispatcher = null; + deployment = null; } - @Test public void testXmlRootElementDefault() throws Exception { - beforeStart(); + doTestXmlRootElementDefault("false"); + doTestXmlRootElementDefault("true"); + } + + void doTestXmlRootElementDefault(String enableSecurityFeature) throws Exception + { + before(enableSecurityFeature); ClientRequest request = new ClientRequest(generateURL("/xmlRootElement")); String filename = "src/test/java/org/jboss/resteasy/test/xxe/testpasswd"; String str = "\r" + "\r" + - "]>\r" + + "[\r" + + "]>\r" + "&xxe;"; - + System.out.println(str); request.body("application/xml", str); ClientResponse response = request.post(); @@ -171,20 +197,27 @@ public void testXmlRootElementDefault() throws Exception String entity = response.getEntity(String.class); System.out.println("Result: " + entity); Assert.assertTrue(entity.indexOf("xx:xx:xx:xx:xx:xx:xx") < 0); + after(); } - + @Test public void testXmlRootElementWithoutExpansion() throws Exception { - before("false"); + doTestXmlRootElementWithoutExpansion("false"); + doTestXmlRootElementWithoutExpansion("true"); + } + + void doTestXmlRootElementWithoutExpansion(String enableSecurityFeature) throws Exception + { + before("false", enableSecurityFeature); ClientRequest request = new ClientRequest(generateURL("/xmlRootElement")); String filename = "src/test/java/org/jboss/resteasy/test/xxe/testpasswd"; String str = "\r" + "\r" + - "]>\r" + + "[\r" + + "]>\r" + "&xxe;"; - + System.out.println(str); request.body("application/xml", str); ClientResponse response = request.post(); @@ -192,19 +225,25 @@ public void testXmlRootElementWithoutExpansion() throws Exception String entity = response.getEntity(String.class); System.out.println("Result: " + entity); Assert.assertTrue(entity.indexOf("xx:xx:xx:xx:xx:xx:xx") < 0); + after(); } - - @Test + @Test public void testXmlRootElementWithExpansion() throws Exception { - before("true"); + doTestXmlRootElementWithExpansion("false"); + doTestXmlRootElementWithExpansion("true"); + } + + void doTestXmlRootElementWithExpansion(String enableSecurityFeature) throws Exception + { + before("true", enableSecurityFeature); ClientRequest request = new ClientRequest(generateURL("/xmlRootElement")); String filename = "src/test/java/org/jboss/resteasy/test/xxe/testpasswd"; String str = "\r" + "\r" + - "]>\r" + + "[\r" + + "]>\r" + "&xxe;"; System.out.println(str); @@ -214,20 +253,27 @@ public void testXmlRootElementWithExpansion() throws Exception String entity = response.getEntity(String.class); System.out.println("result: " + entity); Assert.assertTrue(entity.indexOf("xx:xx:xx:xx:xx:xx:xx") >= 0); + after(); } @Test public void testXmlTypeDefault() throws Exception { - beforeStart(); + doTestXmlTypeDefault("false"); + doTestXmlTypeDefault("true"); + } + + void doTestXmlTypeDefault(String enableSecurityFeature) throws Exception + { + before(enableSecurityFeature); ClientRequest request = new ClientRequest(generateURL("/xmlType")); String filename = "src/test/java/org/jboss/resteasy/test/xxe/testpasswd"; String str = "\r" + "\r" + - "]>\r" + + "[\r" + + "]>\r" + "&xxe;"; - + System.out.println(str); request.body("application/xml", str); ClientResponse response = request.post(); @@ -235,20 +281,27 @@ public void testXmlTypeDefault() throws Exception String entity = response.getEntity(String.class); System.out.println("Result: " + entity); Assert.assertTrue(entity.indexOf("xx:xx:xx:xx:xx:xx:xx") < 0); + after(); } - + @Test public void testXmlTypeWithoutExpansion() throws Exception { - before("false"); + doTestXmlTypeWithoutExpansion("false"); + doTestXmlTypeWithoutExpansion("true"); + } + + void doTestXmlTypeWithoutExpansion(String enableSecurityFeature) throws Exception + { + before("false", enableSecurityFeature); ClientRequest request = new ClientRequest(generateURL("/xmlType")); String filename = "src/test/java/org/jboss/resteasy/test/xxe/testpasswd"; String str = "\r" + "\r" + - "]>\r" + + "[\r" + + "]>\r" + "&xxe;"; - + System.out.println(str); request.body("application/xml", str); ClientResponse response = request.post(); @@ -256,18 +309,25 @@ public void testXmlTypeWithoutExpansion() throws Exception String entity = response.getEntity(String.class); System.out.println("Result: " + entity); Assert.assertTrue(entity.indexOf("xx:xx:xx:xx:xx:xx:xx") < 0); + after(); } @Test public void testXmlTypeWithExpansion() throws Exception { - before("true"); + doTestXmlTypeWithExpansion("false"); + doTestXmlTypeWithExpansion("true"); + } + + void doTestXmlTypeWithExpansion(String enableSecurityFeature) throws Exception + { + before("true", enableSecurityFeature); ClientRequest request = new ClientRequest(generateURL("/xmlType")); String filename = "src/test/java/org/jboss/resteasy/test/xxe/testpasswd"; String str = "\r" + "\r" + - "]>\r" + + "[\r" + + "]>\r" + "&xxe;"; System.out.println(str); @@ -276,21 +336,28 @@ public void testXmlTypeWithExpansion() throws Exception Assert.assertEquals(200, response.getStatus()); String entity = response.getEntity(String.class); System.out.println("result: " + entity); - Assert.assertTrue(entity.indexOf("xx:xx:xx:xx:xx:xx:xx") >= 0); + Assert.assertTrue(entity.indexOf("xx:xx:xx:xx:xx:xx:xx") >= 0); + after(); } - + @Test public void testJAXBElementDefault() throws Exception { - beforeStart(); + doTestJAXBElementDefault("false"); + doTestJAXBElementDefault("true"); + } + + void doTestJAXBElementDefault(String enableSecurityFeature) throws Exception + { + before(enableSecurityFeature); ClientRequest request = new ClientRequest(generateURL("/JAXBElement")); String filename = "src/test/java/org/jboss/resteasy/test/xxe/testpasswd"; String str = "\r" + "\r" + - "]>\r" + + "[\r" + + "]>\r" + "&xxe;"; - + System.out.println(str); request.body("application/xml", str); ClientResponse response = request.post(); @@ -298,20 +365,27 @@ public void testJAXBElementDefault() throws Exception String entity = response.getEntity(String.class); System.out.println("Result: " + entity); Assert.assertTrue(entity.indexOf("xx:xx:xx:xx:xx:xx:xx") < 0); + after(); } - + @Test public void testJAXBElementWithoutExpansion() throws Exception { - before("false"); + doTestJAXBElementWithoutExpansion("false"); + doTestJAXBElementWithoutExpansion("true"); + } + + void doTestJAXBElementWithoutExpansion(String enableSecurityFeature) throws Exception + { + before("false", enableSecurityFeature); ClientRequest request = new ClientRequest(generateURL("/JAXBElement")); String filename = "src/test/java/org/jboss/resteasy/test/xxe/testpasswd"; String str = "\r" + "\r" + - "]>\r" + + "[\r" + + "]>\r" + "&xxe;"; - + System.out.println(str); request.body("application/xml", str); ClientResponse response = request.post(); @@ -319,123 +393,143 @@ public void testJAXBElementWithoutExpansion() throws Exception String entity = response.getEntity(String.class); System.out.println("Result: " + entity); Assert.assertTrue(entity.indexOf("xx:xx:xx:xx:xx:xx:xx") < 0); + after(); } - + @Test public void testJAXBElementWithExpansion() throws Exception { - before("true"); + doTestJAXBElementWithExpansion("false"); + doTestJAXBElementWithExpansion("true"); + } + + void doTestJAXBElementWithExpansion(String enableSecurityFeature) throws Exception + { + before("true", enableSecurityFeature); ClientRequest request = new ClientRequest(generateURL("/JAXBElement")); String filename = "src/test/java/org/jboss/resteasy/test/xxe/testpasswd"; String str = "\r" + "\r" + - "]>\r" + + "[\r" + + "]>\r" + "&xxe;"; - + System.out.println(str); request.body("application/xml", str); ClientResponse response = request.post(); Assert.assertEquals(200, response.getStatus()); String entity = response.getEntity(String.class); System.out.println("Result: " + entity); - Assert.assertTrue(entity.indexOf("xx:xx:xx:xx:xx:xx:xx") >= 0); + Assert.assertTrue(entity.indexOf("xx:xx:xx:xx:xx:xx:xx") >= 0); + after(); } - + @Test public void testListDefault() throws Exception { - doCollectionTest(null, "list"); + doCollectionTest(false, null, "list"); + doCollectionTest(true, null, "list"); } - + @Test public void testListWithoutExpansion() throws Exception { - doCollectionTest(false, "list"); + doCollectionTest(false, false, "list"); + doCollectionTest(true, false, "list"); } @Test public void testListWithExpansion() throws Exception { - doCollectionTest(true, "list"); + doCollectionTest(false, true, "list"); + doCollectionTest(true, true, "list"); } - + @Test public void testSetDefault() throws Exception { - doCollectionTest(null, "set"); + doCollectionTest(false, null, "set"); + doCollectionTest(false, null, "set"); } - + @Test public void testSetWithoutExpansion() throws Exception { - doCollectionTest(false, "set"); + doCollectionTest(false, false, "set"); + doCollectionTest(true, false, "set"); } @Test public void testSetWithExpansion() throws Exception { - doCollectionTest(true, "set"); + doCollectionTest(false, true, "set"); + doCollectionTest(true, true, "set"); } - + @Test public void testArrayDefault() throws Exception { - doCollectionTest(null, "array"); + doCollectionTest(false, null, "array"); + doCollectionTest(true, null, "array"); } - + @Test public void testArrayWithoutExpansion() throws Exception { - doCollectionTest(false, "array"); + doCollectionTest(false, false, "array"); + doCollectionTest(true, false, "array"); } @Test public void testArrayWithExpansion() throws Exception { - doCollectionTest(true, "array"); + doCollectionTest(false, true, "array"); + doCollectionTest(true, true, "array"); } @Test public void testMapDefault() throws Exception { - doMapTest(null); + doMapTest(false, null); + doMapTest(true, null); } - + @Test public void testMapWithoutExpansion() throws Exception { - doMapTest(false); + doMapTest(false, false); + doMapTest(true, false); } - + @Test public void testMapWithExpansion() throws Exception { - doMapTest(true); + doMapTest(false, true); + doMapTest(true, true); } - - void doCollectionTest(Boolean expand, String path) throws Exception + + void doCollectionTest(Boolean enableSecurityFeature, Boolean expand, String path) throws Exception { if (expand == null) { - beforeStart(); + before(Boolean.toString(enableSecurityFeature)); expand = false; } else { - before(Boolean.toString(expand)); + before(Boolean.toString(expand), Boolean.toString(enableSecurityFeature)); } ClientRequest request = new ClientRequest(generateURL("/" + path)); String filename = "src/test/java/org/jboss/resteasy/test/xxe/testpasswd"; String str = "\r" + "\r" + - "]>\r" + + "[\r" + + "]>\r" + "" + "&xxe;" + "Le Regle de Jeu" + ""; - + System.out.println(str); request.body("application/xml", str); ClientResponse response = request.post(); @@ -450,25 +544,26 @@ void doCollectionTest(Boolean expand, String path) throws Exception { Assert.assertTrue(entity.indexOf("xx:xx:xx:xx:xx:xx:xx") < 0); } + after(); } - - void doMapTest(Boolean expand) throws Exception + + void doMapTest(boolean enableSecurityFeature, Boolean expand) throws Exception { if (expand == null) { - beforeStart(); + before(Boolean.toString(enableSecurityFeature)); expand = false; } else { - before(Boolean.toString(expand)); + before(Boolean.toString(expand), Boolean.toString(enableSecurityFeature)); } ClientRequest request = new ClientRequest(generateURL("/map")); String filename = "src/test/java/org/jboss/resteasy/test/xxe/testpasswd"; String str = "\r" + "\r" + - "]>\r" + + "[\r" + + "]>\r" + "" + "" + "&xxe;" + @@ -477,7 +572,7 @@ void doMapTest(Boolean expand) throws Exception "La Regle de Jeu" + "" + ""; - + System.out.println(str); request.body("application/xml", str); ClientResponse response = request.post(); @@ -492,5 +587,6 @@ void doMapTest(Boolean expand) throws Exception { Assert.assertTrue(entity.indexOf("xx:xx:xx:xx:xx:xx:xx") < 0); } + after(); } } diff --git a/providers/jaxb/src/test/java/org/jboss/resteasy/test/xxe/TestXXESecureProcessing.java b/providers/jaxb/src/test/java/org/jboss/resteasy/test/xxe/TestXXESecureProcessing.java index da0d12f4d57..22816dc909e 100644 --- a/providers/jaxb/src/test/java/org/jboss/resteasy/test/xxe/TestXXESecureProcessing.java +++ b/providers/jaxb/src/test/java/org/jboss/resteasy/test/xxe/TestXXESecureProcessing.java @@ -12,7 +12,11 @@ import org.jboss.resteasy.client.ClientRequest; import org.jboss.resteasy.client.ClientResponse; +import org.jboss.resteasy.core.Dispatcher; +import org.jboss.resteasy.spi.ResteasyDeployment; import org.jboss.resteasy.test.BaseResourceTest; +import org.jboss.resteasy.test.EmbeddedContainer; +import org.junit.After; import org.junit.Test; /** @@ -21,8 +25,11 @@ * @author Ron Sigal * @date August 16, 2013 */ -public class TestXXESecureProcessing extends BaseResourceTest +public class TestXXESecureProcessing { + protected static ResteasyDeployment deployment; + protected static Dispatcher dispatcher; + String doctype = "" + @@ -58,25 +65,35 @@ public void before(String expandEntityReferences) throws Exception { Hashtable initParams = new Hashtable(); Hashtable contextParams = new Hashtable(); - if (expandEntityReferences != null) - contextParams.put("resteasy.document.expand.entity.references", expandEntityReferences); - - createContainer(initParams, contextParams); - addPerRequestResource(MovieResource.class, FavoriteMovieXmlRootElement.class, MovieResource.class, FavoriteMovieXmlRootElement.class); - startContainer(); + contextParams.put("resteasy.document.secure.disableDTDs", "false"); + contextParams.put("resteasy.document.expand.entity.references", expandEntityReferences); + deployment = EmbeddedContainer.start(initParams, contextParams); + dispatcher = deployment.getDispatcher(); + deployment.getRegistry().addPerRequestResource(MovieResource.class); } - @Override public void before() throws Exception + { + Hashtable initParams = new Hashtable(); + Hashtable contextParams = new Hashtable(); + contextParams.put("resteasy.document.secure.disableDTDs", "false"); + deployment = EmbeddedContainer.start(initParams, contextParams); + dispatcher = deployment.getDispatcher(); + deployment.getRegistry().addPerRequestResource(MovieResource.class); + } + + @After + public void after() throws Exception { - manualStart = true; - super.before(); + EmbeddedContainer.stop(); + dispatcher = null; + deployment = null; } @Test public void testXmlRootElementDefaultSmall() throws Exception { - before(null); + before(); ClientRequest request = new ClientRequest(generateURL("/xmlRootElement")); request.body("application/xml", small); ClientResponse response = request.post(); @@ -91,7 +108,7 @@ public void testXmlRootElementDefaultSmall() throws Exception @Test public void testXmlRootElementDefaultBig() throws Exception { - before(null); + before(); ClientRequest request = new ClientRequest(generateURL("/xmlRootElement")); request.body("application/xml", big); ClientResponse response = request.post(); diff --git a/providers/jaxb/src/test/java/org/jboss/resteasy/test/xxe/external.dtd b/providers/jaxb/src/test/java/org/jboss/resteasy/test/xxe/external.dtd new file mode 100644 index 00000000000..7fc8b64ab2b --- /dev/null +++ b/providers/jaxb/src/test/java/org/jboss/resteasy/test/xxe/external.dtd @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/providers/jettison/src/main/java/org/jboss/resteasy/plugins/providers/jaxb/json/JettisonElementProvider.java b/providers/jettison/src/main/java/org/jboss/resteasy/plugins/providers/jaxb/json/JettisonElementProvider.java index af752254f5c..1cf96e27e51 100644 --- a/providers/jettison/src/main/java/org/jboss/resteasy/plugins/providers/jaxb/json/JettisonElementProvider.java +++ b/providers/jettison/src/main/java/org/jboss/resteasy/plugins/providers/jaxb/json/JettisonElementProvider.java @@ -16,7 +16,7 @@ public class JettisonElementProvider extends JAXBElementProvider { @Override - protected boolean suppressExpandEntityExpansion() + protected boolean needsSecurity() { return false; } diff --git a/providers/jettison/src/main/java/org/jboss/resteasy/plugins/providers/jaxb/json/JettisonXmlRootElementProvider.java b/providers/jettison/src/main/java/org/jboss/resteasy/plugins/providers/jaxb/json/JettisonXmlRootElementProvider.java index 16ca37a6e63..fe4297369dd 100644 --- a/providers/jettison/src/main/java/org/jboss/resteasy/plugins/providers/jaxb/json/JettisonXmlRootElementProvider.java +++ b/providers/jettison/src/main/java/org/jboss/resteasy/plugins/providers/jaxb/json/JettisonXmlRootElementProvider.java @@ -16,7 +16,7 @@ public class JettisonXmlRootElementProvider extends JAXBXmlRootElementProvider { @Override - protected boolean suppressExpandEntityExpansion() + protected boolean needsSecurity() { return false; } diff --git a/providers/jettison/src/main/java/org/jboss/resteasy/plugins/providers/jaxb/json/JettisonXmlSeeAlsoProvider.java b/providers/jettison/src/main/java/org/jboss/resteasy/plugins/providers/jaxb/json/JettisonXmlSeeAlsoProvider.java index f0d7f936d04..4f6e3b671d9 100644 --- a/providers/jettison/src/main/java/org/jboss/resteasy/plugins/providers/jaxb/json/JettisonXmlSeeAlsoProvider.java +++ b/providers/jettison/src/main/java/org/jboss/resteasy/plugins/providers/jaxb/json/JettisonXmlSeeAlsoProvider.java @@ -16,7 +16,7 @@ public class JettisonXmlSeeAlsoProvider extends JAXBXmlSeeAlsoProvider { @Override - protected boolean suppressExpandEntityExpansion() + protected boolean needsSecurity() { return false; } diff --git a/providers/jettison/src/main/java/org/jboss/resteasy/plugins/providers/jaxb/json/JettisonXmlTypeProvider.java b/providers/jettison/src/main/java/org/jboss/resteasy/plugins/providers/jaxb/json/JettisonXmlTypeProvider.java index ccb6b0a86a2..430cf335dcb 100644 --- a/providers/jettison/src/main/java/org/jboss/resteasy/plugins/providers/jaxb/json/JettisonXmlTypeProvider.java +++ b/providers/jettison/src/main/java/org/jboss/resteasy/plugins/providers/jaxb/json/JettisonXmlTypeProvider.java @@ -16,7 +16,7 @@ public class JettisonXmlTypeProvider extends JAXBXmlTypeProvider { @Override - protected boolean suppressExpandEntityExpansion() + protected boolean needsSecurity() { return false; } diff --git a/resteasy-jaxrs-test/src/test/java/org/jboss/resteasy/test/xxe/TestSecureProcessing.java b/resteasy-jaxrs-test/src/test/java/org/jboss/resteasy/test/xxe/TestSecureProcessing.java new file mode 100644 index 00000000000..26309dee88e --- /dev/null +++ b/resteasy-jaxrs-test/src/test/java/org/jboss/resteasy/test/xxe/TestSecureProcessing.java @@ -0,0 +1,519 @@ +package org.jboss.resteasy.test.xxe; + +import static org.jboss.resteasy.test.TestPortProvider.generateURL; + +import java.util.Hashtable; + +import javax.ws.rs.Consumes; +import javax.ws.rs.POST; +import javax.ws.rs.Path; + +import junit.framework.Assert; + +import org.jboss.resteasy.client.ClientRequest; +import org.jboss.resteasy.client.ClientResponse; +import org.jboss.resteasy.core.Dispatcher; +import org.jboss.resteasy.spi.ResteasyDeployment; +import org.jboss.resteasy.test.EmbeddedContainer; +import org.junit.After; +import org.junit.Test; +import org.w3c.dom.Document; +import org.w3c.dom.Node; +import org.w3c.dom.NodeList; + +/** + * Unit tests for RESTEASY-1103. + * + * @author Ron Sigal + * @date September 1, 2014 + */ +public class TestSecureProcessing +{ + protected static ResteasyDeployment deployment; + protected static Dispatcher dispatcher; + protected static enum MapInclusion {DEFAULT, FALSE, TRUE}; + + /////////////////////////////////////////////////////////////////////////////////////////////// + protected static String bigExpansionDoc = + "" + + "" + + "" + + "" + + "" + + "" + + "" + + "]>" + + "&foo5;"; + + protected static String bigAttributeDoc; + static + { + StringBuffer sb = new StringBuffer(); + sb.append("bar"); + bigAttributeDoc = sb.toString(); + } + + String smallDtd = "]>bar"; + + protected static String filename = "src/test/java/org/jboss/resteasy/test/xxe/testpasswd"; + protected static String externalEntityDoc = + "\r" + + "\r" + + "]>\r" + + "&xxe;"; + + /////////////////////////////////////////////////////////////////////////////////////////////// + @Path("/") + public static class TestResource + { + @Consumes("application/xml") + @POST + @Path("test") + public String doPost(Document doc) + { + Node node = doc.getDocumentElement(); + System.out.println("name: " + node.getNodeName()); + NodeList children = doc.getDocumentElement().getChildNodes(); + node = children.item(0); + System.out.println("name: " + node.getNodeName()); + String text = node.getTextContent(); + int len = Math.min(text.length(), 30); + System.out.println("text: " + text.substring(0, len)); + return text; + } + } + + /////////////////////////////////////////////////////////////////////////////////////////////// + public static void before(Hashtable contextParams) throws Exception + { + Hashtable initParams = new Hashtable(); + deployment = EmbeddedContainer.start(initParams, contextParams); + dispatcher = deployment.getDispatcher(); + deployment.getRegistry().addPerRequestResource(TestResource.class); + } + + @After + public void after() throws Exception + { + EmbeddedContainer.stop(); + dispatcher = null; + deployment = null; + } + + /////////////////////////////////////////////////////////////////////////////////////////////// + @Test + public void testSecurityDefaultDTDsDefaultExpansionDefault() throws Exception + { + before(getParameterMap(MapInclusion.DEFAULT, MapInclusion.DEFAULT, MapInclusion.DEFAULT)); + doTestSkipFailsFailsSkip(); + } + + @Test + public void testSecurityDefaultDTDsDefaultExpansionFalse() throws Exception + { + before(getParameterMap(MapInclusion.DEFAULT, MapInclusion.DEFAULT, MapInclusion.FALSE)); + doTestSkipFailsFailsSkip(); + } + + @Test + public void testSecurityDefaultDTDsDefaultExpansionTrue() throws Exception + { + before(getParameterMap(MapInclusion.DEFAULT, MapInclusion.DEFAULT, MapInclusion.TRUE)); + doTestSkipFailsFailsSkip(); + } + + @Test + public void testSecurityDefaultDTDsFalseExpansionDefault() throws Exception + { + before(getParameterMap(MapInclusion.DEFAULT, MapInclusion.FALSE, MapInclusion.DEFAULT)); + doTestFailsFailsPassesFails(); + } + + @Test + public void testSecurityDefaultDTDsFalseExpansionFalse() throws Exception + { + before(getParameterMap(MapInclusion.DEFAULT, MapInclusion.FALSE, MapInclusion.FALSE)); + doTestFailsFailsPassesFails(); + } + + @Test + public void testSecurityDefaultDTDsFalseExpansionTrue() throws Exception + { + before(getParameterMap(MapInclusion.DEFAULT, MapInclusion.FALSE, MapInclusion.TRUE)); + doTestFailsFailsPassesPasses(); + } + + @Test + public void testSecurityDefaultDTDsTrueExpansionDefault() throws Exception + { + before(getParameterMap(MapInclusion.DEFAULT, MapInclusion.TRUE, MapInclusion.DEFAULT)); + doTestSkipFailsFailsSkip(); + } + + @Test + public void testSecurityDefaultDTDsTrueExpansionFalse() throws Exception + { + before(getParameterMap(MapInclusion.DEFAULT, MapInclusion.TRUE, MapInclusion.FALSE)); + doTestSkipFailsFailsSkip(); + } + + @Test + public void testSecurityDefaultDTDsTrueExpansionTrue() throws Exception + { + before(getParameterMap(MapInclusion.DEFAULT, MapInclusion.TRUE, MapInclusion.TRUE)); + doTestSkipFailsFailsSkip(); + } + + @Test + public void testSecurityFalseDTDsDefaultExpansionDefault() throws Exception + { + before(getParameterMap(MapInclusion.FALSE, MapInclusion.DEFAULT, MapInclusion.DEFAULT)); + doTestSkipPassesFailsSkip(); + } + + @Test + public void testSecurityFalseDTDsDefaultExpansionFalse() throws Exception + { + before(getParameterMap(MapInclusion.FALSE, MapInclusion.DEFAULT, MapInclusion.FALSE)); + doTestSkipPassesFailsSkip(); + } + + @Test + public void testSecurityFalseDTDsDefaultExpansionTrue() throws Exception + { + before(getParameterMap(MapInclusion.FALSE, MapInclusion.DEFAULT, MapInclusion.TRUE)); + doTestSkipPassesFailsSkip(); + } + + @Test + public void testSecurityFalseDTDsFalseExpansionDefault() throws Exception + { + before(getParameterMap(MapInclusion.FALSE, MapInclusion.FALSE, MapInclusion.DEFAULT)); + doTestPassesPassesPassesFails(); + } + + @Test + public void testSecurityFalseDTDsFalseExpansionFalse() throws Exception + { + before(getParameterMap(MapInclusion.FALSE, MapInclusion.FALSE, MapInclusion.FALSE)); + doTestPassesPassesPassesFails(); + } + + @Test + public void testSecurityFalseDTDsFalseExpansionTrue() throws Exception + { + before(getParameterMap(MapInclusion.FALSE, MapInclusion.FALSE, MapInclusion.TRUE)); + doTestPassesPassesPassesPasses(); + } + + @Test + public void testSecurityFalseDTDsTrueExpansionDefault() throws Exception + { + before(getParameterMap(MapInclusion.FALSE, MapInclusion.TRUE, MapInclusion.DEFAULT)); + doTestSkipPassesFailsSkip(); + } + + @Test + public void testSecurityFalseDTDsTrueExpansionFalse() throws Exception + { + before(getParameterMap(MapInclusion.FALSE, MapInclusion.TRUE, MapInclusion.FALSE)); + doTestSkipPassesFailsSkip(); + } + + @Test + public void testSecurityFalseDTDsTrueExpansionTrue() throws Exception + { + before(getParameterMap(MapInclusion.FALSE, MapInclusion.TRUE, MapInclusion.TRUE)); + doTestSkipPassesFailsSkip(); + } + + @Test + public void testSecurityTrueDTDsDefaultExpansionDefault() throws Exception + { + before(getParameterMap(MapInclusion.TRUE, MapInclusion.DEFAULT, MapInclusion.DEFAULT)); + doTestSkipFailsFailsSkip(); + } + + @Test + public void testSecurityTrueDTDsDefaultExpansionFalse() throws Exception + { + before(getParameterMap(MapInclusion.TRUE, MapInclusion.DEFAULT, MapInclusion.FALSE)); + doTestSkipFailsFailsSkip(); + } + + @Test + public void testSecurityTrueDTDsDefaultExpansionTrue() throws Exception + { + before(getParameterMap(MapInclusion.TRUE, MapInclusion.DEFAULT, MapInclusion.TRUE)); + doTestSkipFailsFailsSkip(); + } + + @Test + public void testSecurityTrueDTDsFalseExpansionDefault() throws Exception + { + before(getParameterMap(MapInclusion.TRUE, MapInclusion.FALSE, MapInclusion.DEFAULT)); + doTestFailsFailsPassesFails(); + } + + @Test + public void testSecurityTrueDTDsFalseExpansionFalse() throws Exception + { + before(getParameterMap(MapInclusion.TRUE, MapInclusion.FALSE, MapInclusion.FALSE)); + doTestFailsFailsPassesFails(); + } + + @Test + public void testSecurityTrueDTDsFalseExpansionTrue() throws Exception + { + before(getParameterMap(MapInclusion.TRUE, MapInclusion.FALSE, MapInclusion.TRUE)); + doTestFailsFailsPassesPasses(); + } + + @Test + public void testSecurityTrueDTDsTrueExpansionDefault() throws Exception + { + before(getParameterMap(MapInclusion.TRUE, MapInclusion.TRUE, MapInclusion.DEFAULT)); + doTestSkipFailsFailsSkip(); + } + + @Test + public void testSecurityTrueDTDsTrueExpansionFalse() throws Exception + { + before(getParameterMap(MapInclusion.TRUE, MapInclusion.TRUE, MapInclusion.FALSE)); + doTestSkipFailsFailsSkip(); + } + + @Test + public void testSecurityTrueDTDsTrueExpansionTrue() throws Exception + { + before(getParameterMap(MapInclusion.TRUE, MapInclusion.TRUE, MapInclusion.TRUE)); + doTestSkipFailsFailsSkip(); + } + + /////////////////////////////////////////////////////////////////////////////////////////////// + void doTestSkipFailsFailsSkip() throws Exception + { + doMaxAttributesFails(); + doDTDFails(); + } + + void doTestSkipPassesFailsSkip() throws Exception + { + doMaxAttributesPasses(); + doDTDFails(); + } + + void doTestFailsFailsPassesFails() throws Exception + { + doEntityExpansionFails(); + doMaxAttributesFails(); + doDTDPasses(); + doExternalEntityExpansionFails(); + } + + void doTestFailsFailsPassesPasses() throws Exception + { + doEntityExpansionFails(); + doMaxAttributesFails(); + doDTDPasses(); + doExternalEntityExpansionPasses(); + } + + void doTestPassesPassesPassesFails() throws Exception + { + doEntityExpansionPasses(); + doMaxAttributesPasses(); + doDTDPasses(); + doDTDPasses(); + doExternalEntityExpansionFails(); + } + + void doTestPassesPassesPassesPasses() throws Exception + { + doEntityExpansionPasses(); + doMaxAttributesPasses(); + doDTDPasses(); + doDTDPasses(); + doExternalEntityExpansionPasses(); + } + + void doEntityExpansionFails() throws Exception + { + System.out.println("entering doEntityExpansionFails()"); + ClientRequest request = new ClientRequest(generateURL("/test")); + request.body("application/xml", bigExpansionDoc); + ClientResponse response = request.post(); + System.out.println("status: " + response.getStatus()); + String entity = response.getEntity(String.class); + System.out.println("doEntityExpansionFails() result: " + entity); + Assert.assertEquals(400, response.getStatus()); + Assert.assertTrue(entity.contains("org.xml.sax.SAXParseException")); + } + + void doEntityExpansionPasses() throws Exception + { + System.out.println("entering doEntityExpansionFails()"); + ClientRequest request = new ClientRequest(generateURL("/test")); + request.body("application/xml", bigExpansionDoc); + ClientResponse response = request.post(); + System.out.println("status: " + response.getStatus()); + String entity = response.getEntity(String.class); + int len = Math.min(entity.length(), 30); + System.out.println("doEntityExpansionPasses() result: " + entity.substring(0, len) + "..."); + Assert.assertEquals(200, response.getStatus()); + Assert.assertTrue(countFoos(entity) > 64000); + } + + void doMaxAttributesFails() throws Exception + { + System.out.println("entering doMaxAttributesFails()"); + ClientRequest request = new ClientRequest(generateURL("/test")); + request.body("application/xml", bigAttributeDoc); + ClientResponse response = request.post(); + System.out.println("doMaxAttributesFails() status: " + response.getStatus()); + String entity = response.getEntity(String.class); + System.out.println("doMaxAttributesFails() result: " + entity); + Assert.assertEquals(400, response.getStatus()); + Assert.assertTrue(entity.contains("org.xml.sax.SAXParseException")); + Assert.assertTrue(entity.contains("has more than \"10,00")); + int pos = entity.indexOf("has more than \"10,00"); + Assert.assertTrue(entity.substring(pos).contains("attributes")); + } + + void doMaxAttributesPasses() throws Exception + { + System.out.println("entering doMaxAttributesPasses()"); + ClientRequest request = new ClientRequest(generateURL("/test")); + request.body("application/xml", bigAttributeDoc); + ClientResponse response = request.post(); + System.out.println("doMaxAttributesPasses() status: " + response.getStatus()); + String entity = response.getEntity(String.class); + System.out.println("doMaxAttributesPasses() result: " + entity); + Assert.assertEquals(200, response.getStatus()); + Assert.assertEquals("bar", entity); + } + + void doDTDFails() throws Exception + { + System.out.println("entering doDTDFails()"); + ClientRequest request = new ClientRequest(generateURL("/test")); + request.body("application/xml", smallDtd); + ClientResponse response = request.post(); + System.out.println("status: " + response.getStatus()); + String entity = response.getEntity(String.class); + System.out.println("doDTDFails(): result: " + entity); + Assert.assertEquals(400, response.getStatus()); + Assert.assertTrue(entity.contains("org.xml.sax.SAXParseException")); + Assert.assertTrue(entity.contains("DOCTYPE is disallowed")); + } + + void doDTDPasses() throws Exception + { + System.out.println("entering doDTDPasses()"); + ClientRequest request = new ClientRequest(generateURL("/test")); + request.body("application/xml", smallDtd); + ClientResponse response = request.post(); + System.out.println("status: " + response.getStatus()); + String entity = response.getEntity(String.class); + System.out.println("doDTDPasses() result: " + entity); + Assert.assertEquals(200, response.getStatus()); + Assert.assertEquals("bar", entity); + } + + void doExternalEntityExpansionFails() throws Exception + { + System.out.println("entering doExternalEntityExpansionFails()"); + ClientRequest request = new ClientRequest(generateURL("/test")); + request.body("application/xml", externalEntityDoc); + ClientResponse response = request.post(); + System.out.println("status: " + response.getStatus()); + String entity = response.getEntity(String.class); + System.out.println("doExternalEntityExpansionFails() result: " + entity); + Assert.assertEquals(200, response.getStatus()); + Assert.assertEquals("", entity); + } + + void doExternalEntityExpansionPasses() throws Exception + { + System.out.println("entering doExternalEntityExpansionPasses()"); + ClientRequest request = new ClientRequest(generateURL("/test")); + request.body("application/xml", externalEntityDoc); + ClientResponse response = request.post(); + System.out.println("status: " + response.getStatus()); + String entity = response.getEntity(String.class); + int len = Math.min(entity.length(), 30); + System.out.println("doExternalEntityExpansionPasses() result: " + entity.substring(0, len) + "..."); + Assert.assertEquals(200, response.getStatus()); + Assert.assertEquals("xx:xx:xx:xx:xx:xx:xx", entity); + } + + /////////////////////////////////////////////////////////////////////////////////////////////// + private static Hashtable getParameterMap(MapInclusion securityFeature, MapInclusion disableDTDs, MapInclusion expandEntities) + { + Hashtable map = new Hashtable(); + switch (securityFeature) + { + case DEFAULT: + break; + + case FALSE: + map.put("resteasy.document.secure.processing.feature", "false"); + break; + + case TRUE: + map.put("resteasy.document.secure.processing.feature", "true"); + break; + } + switch (disableDTDs) + { + case DEFAULT: + break; + + case FALSE: + map.put("resteasy.document.secure.disableDTDs", "false"); + break; + + case TRUE: + map.put("resteasy.document.secure.disableDTDs", "true"); + break; + } + switch (expandEntities) + { + case DEFAULT: + break; + + case FALSE: + map.put("resteasy.document.expand.entity.references", "false"); + break; + + case TRUE: + map.put("resteasy.document.expand.entity.references", "true"); + break; + } + return map; + } + + private static int countFoos(String s) + { + int count = 0; + int pos = 0; + + while (pos >= 0) + { + pos = s.indexOf("foo", pos); + if (pos >= 0) + { + count++; + pos += 3; + } + } + return count; + } +} diff --git a/resteasy-jaxrs/src/main/java/org/jboss/resteasy/plugins/providers/DocumentProvider.java b/resteasy-jaxrs/src/main/java/org/jboss/resteasy/plugins/providers/DocumentProvider.java index f51d01923b6..76f9d0d2a71 100644 --- a/resteasy-jaxrs/src/main/java/org/jboss/resteasy/plugins/providers/DocumentProvider.java +++ b/resteasy-jaxrs/src/main/java/org/jboss/resteasy/plugins/providers/DocumentProvider.java @@ -14,6 +14,7 @@ import javax.ws.rs.core.MediaType; import javax.ws.rs.core.MultivaluedMap; import javax.ws.rs.ext.Provider; +import javax.xml.XMLConstants; import javax.xml.parsers.DocumentBuilderFactory; import javax.xml.transform.TransformerException; import javax.xml.transform.TransformerFactory; @@ -41,6 +42,8 @@ public class DocumentProvider extends AbstractEntityProvider private final TransformerFactory transformerFactory; private final DocumentBuilderFactory documentBuilder; private boolean expandEntityReferences = false; + private boolean enableSecureProcessingFeature = true; + private boolean disableDTDs = true; public DocumentProvider(@Context ResteasyConfiguration config) { @@ -55,6 +58,24 @@ public DocumentProvider(@Context ResteasyConfiguration config) { logger.debug("Unable to retrieve config: expandEntityReferences defaults to false"); } + try + { + String s = config.getParameter(ResteasyContextParameters.RESTEASY_SECURE_PROCESSING_FEATURE); + enableSecureProcessingFeature = (s == null ? true : Boolean.parseBoolean(s)); + } + catch (Exception e) + { + logger.debug("Unable to retrieve config: enableSecureProcessingFeature defaults to true"); + } + try + { + String s = config.getParameter(ResteasyContextParameters.RESTEASY_DISABLE_DTDS); + disableDTDs = (s == null ? true : Boolean.parseBoolean(s)); + } + catch (Exception e) + { + logger.debug("Unable to retrieve config: disableDTDs defaults to true"); + } } public boolean isReadable(Class clazz, Type type, @@ -71,6 +92,8 @@ public Document readFrom(Class clazz, Type type, try { documentBuilder.setExpandEntityReferences(expandEntityReferences); + documentBuilder.setFeature(XMLConstants.FEATURE_SECURE_PROCESSING, enableSecureProcessingFeature); + documentBuilder.setFeature("http://apache.org/xml/features/disallow-doctype-decl", disableDTDs); return documentBuilder.newDocumentBuilder().parse(input); } catch (Exception e) diff --git a/resteasy-jaxrs/src/main/java/org/jboss/resteasy/plugins/server/servlet/ResteasyContextParameters.java b/resteasy-jaxrs/src/main/java/org/jboss/resteasy/plugins/server/servlet/ResteasyContextParameters.java index de94ebf4d4f..db1497af1b5 100644 --- a/resteasy-jaxrs/src/main/java/org/jboss/resteasy/plugins/server/servlet/ResteasyContextParameters.java +++ b/resteasy-jaxrs/src/main/java/org/jboss/resteasy/plugins/server/servlet/ResteasyContextParameters.java @@ -32,7 +32,9 @@ public interface ResteasyContextParameters String RESTEASY_JNDI_COMPONENT_RESOURCES = "resteasy.jndi.component.resources"; String RESTEASY_UNWRAPPED_EXCEPTIONS = "resteasy.unwrapped.exceptions"; String RESTEASY_EXPAND_ENTITY_REFERENCES = "resteasy.document.expand.entity.references"; - + String RESTEASY_SECURE_PROCESSING_FEATURE = "resteasy.document.secure.processing.feature"; + String RESTEASY_DISABLE_DTDS = "resteasy.document.secure.disableDTDs"; + // these scanned variables are provided by a deployer String RESTEASY_SCANNED_RESOURCES = "resteasy.scanned.resources"; String RESTEASY_SCANNED_PROVIDERS = "resteasy.scanned.providers";