blob: 9a358ea7b62ab5c69b1d4486af1079f879ee2df6 [file] [log] [blame]
/*
* Licensed to the Apache Software Foundation (ASF) under one or more
* contributor license agreements. See the NOTICE file distributed with
* this work for additional information regarding copyright ownership.
* The ASF licenses this file to You under the Apache License, Version 2.0
* (the "License"); you may not use this file except in compliance with
* the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package jaxp;
import java.io.IOException;
import javax.xml.XMLConstants;
import javax.xml.parsers.DocumentBuilder;
import javax.xml.parsers.DocumentBuilderFactory;
import javax.xml.parsers.SAXParserFactory;
import javax.xml.validation.SchemaFactory;
import junit.framework.TestCase;
import org.w3c.dom.Document;
import org.w3c.dom.Element;
import org.w3c.dom.Node;
import org.w3c.dom.NodeList;
import org.xml.sax.Attributes;
import org.xml.sax.ContentHandler;
import org.xml.sax.EntityResolver;
import org.xml.sax.InputSource;
import org.xml.sax.Locator;
import org.xml.sax.SAXException;
import org.xml.sax.SAXParseException;
import org.xml.sax.XMLReader;
/**
* Tests for JAXP secure processing features.
*
* @author Michael Glavassevich, IBM
* @version $Id$
*/
public class JAXPSecureProcessingTest extends TestCase {
private static final String ENTITY_EXPANSION_LIMIT_PROPERTY_NAME = "jdk.xml.entityExpansionLimit";
private static final String MAX_OCCUR_LIMIT_PROPERTY_NAME = "jdk.xml.maxOccur";
private static final String TOTAL_ENTITY_SIZE_LIMIT_PROPERTY_NAME = "jdk.xml.totalEntitySizeLimit";
private static final String MAX_GENERAL_ENTITY_SIZE_LIMIT_PROPERTY_NAME = "jdk.xml.maxGeneralEntitySizeLimit";
private static final String MAX_PARAMETER_ENTITY_SIZE_LIMIT_PROPERTY_NAME = "jdk.xml.maxParameterEntitySizeLimit";
private static final String RESOLVE_EXTERNAL_ENTITIES_PROPERTY_NAME = "jdk.xml.resolveExternalEntities";
protected void setUp() throws Exception {
super.setUp();
System.setProperty("javax.xml.parsers.SAXParserFactory", "org.apache.xerces.jaxp.SAXParserFactoryImpl");
System.setProperty("javax.xml.parsers.DocumentBuilderFactory", "org.apache.xerces.jaxp.DocumentBuilderFactoryImpl");
System.setProperty("javax.xml.validation.SchemaFactory:" + XMLConstants.W3C_XML_SCHEMA_NS_URI,
"org.apache.xerces.jaxp.validation.XMLSchemaFactory");
System.setProperty("org.apache.xerces.xni.parser.XMLParserConfiguration",
"org.apache.xerces.parsers.SecureProcessingConfiguration");
System.setProperty(ENTITY_EXPANSION_LIMIT_PROPERTY_NAME, "0");
System.setProperty(MAX_OCCUR_LIMIT_PROPERTY_NAME, "0");
System.setProperty(TOTAL_ENTITY_SIZE_LIMIT_PROPERTY_NAME, "0");
System.setProperty(MAX_GENERAL_ENTITY_SIZE_LIMIT_PROPERTY_NAME, "0");
System.setProperty(MAX_PARAMETER_ENTITY_SIZE_LIMIT_PROPERTY_NAME, "0");
System.setProperty(RESOLVE_EXTERNAL_ENTITIES_PROPERTY_NAME, "true");
}
protected void tearDown() throws Exception {
super.tearDown();
}
public void testSAXEntityExpansionLimitSG() throws Exception {
System.setProperty(ENTITY_EXPANSION_LIMIT_PROPERTY_NAME, "10000");
XMLReader reader = newSecureXMLReader();
try {
reader.parse(new InputData("gEntitySP.xml"));
fail("Expected SAXParseException");
}
catch (SAXParseException se) {
assertTrue(se.getMessage().indexOf("\"10,000\"") != -1);
}
}
public void testSAXEntityExpansionLimitSP() throws Exception {
System.setProperty(ENTITY_EXPANSION_LIMIT_PROPERTY_NAME, "20000");
XMLReader reader = newSecureXMLReader();
try {
reader.parse(new InputData("pEntitySP.xml"));
fail("Expected SAXParseException");
}
catch (SAXParseException se) {
assertTrue(se.getMessage().indexOf("\"20,000\"") != -1);
}
}
public void testSAXEntityExpansionLimitDG() throws Exception {
System.setProperty(ENTITY_EXPANSION_LIMIT_PROPERTY_NAME, "30000");
XMLReader reader = newDefaultXMLReader();
try {
reader.parse(new InputData("gEntitySP.xml"));
fail("Expected SAXParseException");
}
catch (SAXParseException se) {
assertTrue(se.getMessage().indexOf("\"30,000\"") != -1);
}
}
public void testSAXEntityExpansionLimitDP() throws Exception {
System.setProperty(ENTITY_EXPANSION_LIMIT_PROPERTY_NAME, "40000");
XMLReader reader = newDefaultXMLReader();
try {
reader.parse(new InputData("pEntitySP.xml"));
fail("Expected SAXParseException");
}
catch (SAXParseException se) {
assertTrue(se.getMessage().indexOf("\"40,000\"") != -1);
}
}
public void testDOMEntityExpansionLimitSG() throws Exception {
System.setProperty(ENTITY_EXPANSION_LIMIT_PROPERTY_NAME, "50000");
DocumentBuilder reader = newSecureDocumentBuilder();
try {
reader.parse(new InputData("gEntitySP.xml"));
fail("Expected SAXParseException");
}
catch (SAXParseException se) {
assertTrue(se.getMessage().indexOf("\"50,000\"") != -1);
}
}
public void testDOMEntityExpansionLimitSP() throws Exception {
System.setProperty(ENTITY_EXPANSION_LIMIT_PROPERTY_NAME, "60000");
DocumentBuilder reader = newSecureDocumentBuilder();
try {
reader.parse(new InputData("pEntitySP.xml"));
fail("Expected SAXParseException");
}
catch (SAXParseException se) {
assertTrue(se.getMessage().indexOf("\"60,000\"") != -1);
}
}
public void testDOMEntityExpansionLimitDG() throws Exception {
System.setProperty(ENTITY_EXPANSION_LIMIT_PROPERTY_NAME, "70000");
DocumentBuilder reader = newDefaultDocumentBuilder();
try {
reader.parse(new InputData("gEntitySP.xml"));
fail("Expected SAXParseException");
}
catch (SAXParseException se) {
assertTrue(se.getMessage().indexOf("\"70,000\"") != -1);
}
}
public void testDOMEntityExpansionLimitDP() throws Exception {
System.setProperty(ENTITY_EXPANSION_LIMIT_PROPERTY_NAME, "80000");
DocumentBuilder reader = newDefaultDocumentBuilder();
try {
reader.parse(new InputData("pEntitySP.xml"));
fail("Expected SAXParseException");
}
catch (SAXParseException se) {
assertTrue(se.getMessage().indexOf("\"80,000\"") != -1);
}
}
public void testSAXTotalEntitySizeLimitSG() throws Exception {
System.setProperty(TOTAL_ENTITY_SIZE_LIMIT_PROPERTY_NAME, "1");
XMLReader reader = newSecureXMLReader();
try {
reader.parse(new InputData("gEntitySP.xml"));
fail("Expected SAXParseException");
}
catch (SAXParseException se) {
assertTrue(se.getMessage().indexOf("\"1\"") != -1);
}
}
public void testSAXTotalEntitySizeLimitSP() throws Exception {
System.setProperty(TOTAL_ENTITY_SIZE_LIMIT_PROPERTY_NAME, "10000");
XMLReader reader = newSecureXMLReader();
try {
reader.parse(new InputData("pEntitySP.xml"));
fail("Expected SAXParseException");
}
catch (SAXParseException se) {
assertTrue(se.getMessage().indexOf("\"10,000\"") != -1);
}
}
public void testSAXTotalEntitySizeLimitDG() throws Exception {
System.setProperty(TOTAL_ENTITY_SIZE_LIMIT_PROPERTY_NAME, "2");
XMLReader reader = newDefaultXMLReader();
try {
reader.parse(new InputData("gEntitySP.xml"));
fail("Expected SAXParseException");
}
catch (SAXParseException se) {
assertTrue(se.getMessage().indexOf("\"2\"") != -1);
}
}
public void testSAXTotalEntitySizeLimitDP() throws Exception {
System.setProperty(TOTAL_ENTITY_SIZE_LIMIT_PROPERTY_NAME, "20000");
XMLReader reader = newDefaultXMLReader();
try {
reader.parse(new InputData("pEntitySP.xml"));
fail("Expected SAXParseException");
}
catch (SAXParseException se) {
assertTrue(se.getMessage().indexOf("\"20,000\"") != -1);
}
}
public void testDOMTotalEntitySizeLimitSG() throws Exception {
System.setProperty(TOTAL_ENTITY_SIZE_LIMIT_PROPERTY_NAME, "3");
DocumentBuilder reader = newSecureDocumentBuilder();
try {
reader.parse(new InputData("gEntitySP.xml"));
fail("Expected SAXParseException");
}
catch (SAXParseException se) {
assertTrue(se.getMessage().indexOf("\"3\"") != -1);
}
}
public void testDOMTotalEntitySizeLimitSP() throws Exception {
System.setProperty(TOTAL_ENTITY_SIZE_LIMIT_PROPERTY_NAME, "30000");
DocumentBuilder reader = newSecureDocumentBuilder();
try {
reader.parse(new InputData("pEntitySP.xml"));
fail("Expected SAXParseException");
}
catch (SAXParseException se) {
assertTrue(se.getMessage().indexOf("\"30,000\"") != -1);
}
}
public void testDOMTotalEntitySizeLimitDG() throws Exception {
System.setProperty(TOTAL_ENTITY_SIZE_LIMIT_PROPERTY_NAME, "4");
DocumentBuilder reader = newDefaultDocumentBuilder();
try {
reader.parse(new InputData("gEntitySP.xml"));
fail("Expected SAXParseException");
}
catch (SAXParseException se) {
assertTrue(se.getMessage().indexOf("\"4\"") != -1);
}
}
public void testDOMTotalEntitySizeLimitDP() throws Exception {
System.setProperty(TOTAL_ENTITY_SIZE_LIMIT_PROPERTY_NAME, "40000");
DocumentBuilder reader = newDefaultDocumentBuilder();
try {
reader.parse(new InputData("pEntitySP.xml"));
fail("Expected SAXParseException");
}
catch (SAXParseException se) {
assertTrue(se.getMessage().indexOf("\"40,000\"") != -1);
}
}
public void testSAXEntitySizeLimitSG() throws Exception {
System.setProperty(MAX_GENERAL_ENTITY_SIZE_LIMIT_PROPERTY_NAME, "1");
XMLReader reader = newSecureXMLReader();
try {
reader.parse(new InputData("gEntitySP.xml"));
fail("Expected SAXParseException");
}
catch (SAXParseException se) {
assertTrue(se.getMessage().indexOf("\"1\"") != -1);
}
}
public void testSAXEntitySizeLimitSP() throws Exception {
System.setProperty(MAX_PARAMETER_ENTITY_SIZE_LIMIT_PROPERTY_NAME, "10000");
XMLReader reader = newSecureXMLReader();
try {
reader.parse(new InputData("pEntitySP.xml"));
fail("Expected SAXParseException");
}
catch (SAXParseException se) {
assertTrue(se.getMessage().indexOf("\"10,000\"") != -1);
}
}
public void testSAXEntitySizeLimitDG() throws Exception {
System.setProperty(MAX_GENERAL_ENTITY_SIZE_LIMIT_PROPERTY_NAME, "2");
XMLReader reader = newDefaultXMLReader();
try {
reader.parse(new InputData("gEntitySP.xml"));
fail("Expected SAXParseException");
}
catch (SAXParseException se) {
assertTrue(se.getMessage().indexOf("\"2\"") != -1);
}
}
public void testSAXEntitySizeLimitDP() throws Exception {
System.setProperty(MAX_PARAMETER_ENTITY_SIZE_LIMIT_PROPERTY_NAME, "20000");
XMLReader reader = newDefaultXMLReader();
try {
reader.parse(new InputData("pEntitySP.xml"));
fail("Expected SAXParseException");
}
catch (SAXParseException se) {
assertTrue(se.getMessage().indexOf("\"20,000\"") != -1);
}
}
public void testDOMEntitySizeLimitSG() throws Exception {
System.setProperty(MAX_GENERAL_ENTITY_SIZE_LIMIT_PROPERTY_NAME, "3");
DocumentBuilder reader = newSecureDocumentBuilder();
try {
reader.parse(new InputData("gEntitySP.xml"));
fail("Expected SAXParseException");
}
catch (SAXParseException se) {
assertTrue(se.getMessage().indexOf("\"3\"") != -1);
}
}
public void testDOMEntitySizeLimitSP() throws Exception {
System.setProperty(MAX_PARAMETER_ENTITY_SIZE_LIMIT_PROPERTY_NAME, "30000");
DocumentBuilder reader = newSecureDocumentBuilder();
try {
reader.parse(new InputData("pEntitySP.xml"));
fail("Expected SAXParseException");
}
catch (SAXParseException se) {
assertTrue(se.getMessage().indexOf("\"30,000\"") != -1);
}
}
public void testDOMEntitySizeLimitDG() throws Exception {
System.setProperty(MAX_GENERAL_ENTITY_SIZE_LIMIT_PROPERTY_NAME, "4");
DocumentBuilder reader = newDefaultDocumentBuilder();
try {
reader.parse(new InputData("gEntitySP.xml"));
fail("Expected SAXParseException");
}
catch (SAXParseException se) {
assertTrue(se.getMessage().indexOf("\"4\"") != -1);
}
}
public void testDOMEntitySizeLimitDP() throws Exception {
System.setProperty(MAX_PARAMETER_ENTITY_SIZE_LIMIT_PROPERTY_NAME, "40000");
DocumentBuilder reader = newDefaultDocumentBuilder();
try {
reader.parse(new InputData("pEntitySP.xml"));
fail("Expected SAXParseException");
}
catch (SAXParseException se) {
assertTrue(se.getMessage().indexOf("\"40,000\"") != -1);
}
}
public void testSAXMaxOccursLimit() throws Exception {
System.setProperty(MAX_OCCUR_LIMIT_PROPERTY_NAME, "2500");
XMLReader reader = newSecureSchemaAwareXMLReader();
try {
reader.parse(new InputData("maxOccursSP.xml"));
fail("Expected SAXParseException");
}
catch (SAXParseException se) {
assertTrue(se.getMessage().indexOf("2,500") != -1);
}
}
public void testDOMMaxOccursLimit() throws Exception {
System.setProperty(MAX_OCCUR_LIMIT_PROPERTY_NAME, "3500");
DocumentBuilder reader = newSecureSchemaAwareDocumentBuilder();
try {
reader.parse(new InputData("maxOccursSP.xml"));
fail("Expected SAXParseException");
}
catch (SAXParseException se) {
assertTrue(se.getMessage().indexOf("3,500") != -1);
}
}
public void testSAXEnableExternalEntityResolution() throws Exception {
System.setProperty(RESOLVE_EXTERNAL_ENTITIES_PROPERTY_NAME, "true");
XMLReader reader = newSecureXMLReader();
reader.setEntityResolver(new EntityResolver() {
public InputSource resolveEntity(String publicId, String systemId)
throws SAXException, IOException {
assertEquals("xerces:///x:/this/does/not/exist.xml", systemId);
return null;
}
});
try {
reader.parse(new InputData("badExternalEntity.xml"));
fail("Expected IOException");
}
catch (IOException ioe) {}
}
public void testDOMEnableExternalEntityResolution() throws Exception {
System.setProperty(RESOLVE_EXTERNAL_ENTITIES_PROPERTY_NAME, "true");
DocumentBuilder reader = newSecureDocumentBuilder();
reader.setEntityResolver(new EntityResolver() {
public InputSource resolveEntity(String publicId, String systemId)
throws SAXException, IOException {
assertEquals("xerces:///x:/this/does/not/exist.xml", systemId);
return null;
}
});
try {
reader.parse(new InputData("badExternalEntity.xml"));
fail("Expected IOException");
}
catch (IOException ioe) {}
}
public void testSAXDisableExternalEntityResolution() throws Exception {
System.setProperty(RESOLVE_EXTERNAL_ENTITIES_PROPERTY_NAME, "false");
XMLReader reader = newSecureXMLReader();
reader.setEntityResolver(new EntityResolver() {
public InputSource resolveEntity(String publicId, String systemId)
throws SAXException, IOException {
fail("resolveEntity call not expected.");
return null;
}
});
reader.setContentHandler(new ContentHandler() {
final int START_DOCUMENT = 0;
final int START_ELEMENT = 1;
final int SKIPPED_ENTITY = 2;
final int END_ELEMENT = 3;
final int END_DOCUMENT = 4;
int state = START_DOCUMENT;
public void startPrefixMapping(String prefix, String uri) {
fail("startPrefixMapping not expected.");
}
public void startElement(String uri, String localName,
String qName, Attributes atts) throws SAXException {
assertEquals(START_ELEMENT, state);
assertEquals("root", localName);
state = SKIPPED_ENTITY;
}
public void startDocument() throws SAXException {
assertEquals(START_DOCUMENT, state);
state = START_ELEMENT;
}
public void skippedEntity(String name) throws SAXException {
assertEquals(SKIPPED_ENTITY, state);
assertEquals("badEntity", name);
state = END_ELEMENT;
}
public void setDocumentLocator(Locator locator) {
// NO-OP
}
public void processingInstruction(String target, String data)
throws SAXException {
fail("processingInstruction not expected.");
}
public void ignorableWhitespace(char[] ch, int start, int length)
throws SAXException {
fail("ignorableWhitespace not expected.");
}
public void endPrefixMapping(String arg0) throws SAXException {
fail("endPrefixMapping not expected.");
}
public void endElement(String uri, String localName, String qName)
throws SAXException {
assertEquals(END_ELEMENT, state);
assertEquals("root", localName);
state = END_DOCUMENT;
}
public void endDocument() throws SAXException {
assertEquals(END_DOCUMENT, state);
}
public void characters(char[] ch, int start, int length) throws SAXException {
fail("characters not expected.");
}
});
reader.parse(new InputData("badExternalEntity.xml"));
}
public void testDOMDisableExternalEntityResolution() throws Exception {
System.setProperty(RESOLVE_EXTERNAL_ENTITIES_PROPERTY_NAME, "false");
DocumentBuilder reader = newSecureDocumentBuilder();
reader.setEntityResolver(new EntityResolver() {
public InputSource resolveEntity(String publicId, String systemId)
throws SAXException, IOException {
fail("resolveEntity call not expected.");
return null;
}
});
Document doc = reader.parse(new InputData("badExternalEntity.xml"));
Element e = doc.getDocumentElement();
assertEquals("root", e.getLocalName());
NodeList nl = e.getChildNodes();
assertEquals(1, nl.getLength());
Node n = nl.item(0);
assertEquals(Node.ENTITY_REFERENCE_NODE, n.getNodeType());
assertEquals("badEntity", n.getNodeName());
assertEquals(0, n.getChildNodes().getLength());
}
private static XMLReader newSecureXMLReader() throws Exception {
SAXParserFactory spf = SAXParserFactory.newInstance();
spf.setNamespaceAware(true);
spf.setFeature(XMLConstants.FEATURE_SECURE_PROCESSING, true);
return spf.newSAXParser().getXMLReader();
}
private static XMLReader newSecureSchemaAwareXMLReader() throws Exception {
SchemaFactory sf = SchemaFactory.newInstance(XMLConstants.W3C_XML_SCHEMA_NS_URI);
sf.setFeature(XMLConstants.FEATURE_SECURE_PROCESSING, true);
SAXParserFactory spf = SAXParserFactory.newInstance();
spf.setNamespaceAware(true);
spf.setSchema(sf.newSchema());
spf.setFeature(XMLConstants.FEATURE_SECURE_PROCESSING, true);
return spf.newSAXParser().getXMLReader();
}
private static XMLReader newDefaultXMLReader() throws Exception {
SAXParserFactory spf = SAXParserFactory.newInstance();
spf.setNamespaceAware(true);
return spf.newSAXParser().getXMLReader();
}
private static DocumentBuilder newSecureDocumentBuilder() throws Exception {
DocumentBuilderFactory dbf = DocumentBuilderFactory.newInstance();
dbf.setNamespaceAware(true);
dbf.setExpandEntityReferences(false);
dbf.setFeature(XMLConstants.FEATURE_SECURE_PROCESSING, true);
return dbf.newDocumentBuilder();
}
private static DocumentBuilder newSecureSchemaAwareDocumentBuilder() throws Exception {
SchemaFactory sf = SchemaFactory.newInstance(XMLConstants.W3C_XML_SCHEMA_NS_URI);
sf.setFeature(XMLConstants.FEATURE_SECURE_PROCESSING, true);
DocumentBuilderFactory dbf = DocumentBuilderFactory.newInstance();
dbf.setNamespaceAware(true);
dbf.setExpandEntityReferences(false);
dbf.setSchema(sf.newSchema());
dbf.setFeature(XMLConstants.FEATURE_SECURE_PROCESSING, true);
return dbf.newDocumentBuilder();
}
private static DocumentBuilder newDefaultDocumentBuilder() throws Exception {
DocumentBuilderFactory dbf = DocumentBuilderFactory.newInstance();
dbf.setNamespaceAware(true);
dbf.setExpandEntityReferences(false);
return dbf.newDocumentBuilder();
}
}