1 /*
   2  * Copyright (c) 2014, 2016, Oracle and/or its affiliates. All rights reserved.
   3  * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
   4  *
   5  * This code is free software; you can redistribute it and/or modify it
   6  * under the terms of the GNU General Public License version 2 only, as
   7  * published by the Free Software Foundation.
   8  *
   9  * This code is distributed in the hope that it will be useful, but WITHOUT
  10  * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
  11  * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
  12  * version 2 for more details (a copy is included in the LICENSE file that
  13  * accompanied this code).
  14  *
  15  * You should have received a copy of the GNU General Public License version
  16  * 2 along with this work; if not, write to the Free Software Foundation,
  17  * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
  18  *
  19  * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
  20  * or visit www.oracle.com if you need additional information or have any
  21  * questions.
  22  */
  23 
  24 package parsers;
  25 
  26 import java.io.File;
  27 import java.io.FilePermission;
  28 import java.io.InputStream;
  29 
  30 import javax.xml.XMLConstants;
  31 import javax.xml.parsers.DocumentBuilder;
  32 import javax.xml.parsers.DocumentBuilderFactory;
  33 import javax.xml.parsers.SAXParser;
  34 import javax.xml.parsers.SAXParserFactory;
  35 
  36 import jaxp.library.JAXPTestUtilities;
  37 
  38 import org.testng.Assert;
  39 import org.testng.annotations.Test;
  40 import org.w3c.dom.Document;
  41 import org.xml.sax.SAXParseException;
  42 
  43 /*
  44  * @bug 6309988
  45  * @summary Test elementAttributeLimit, maxOccurLimit, entityExpansionLimit.
  46  */
  47 @Test(singleThreaded = true)
  48 public class Bug6309988 {
  49 
  50     DocumentBuilderFactory dbf = null;
  51 
  52     public void runWithSecurityManager() throws Exception {
  53         JAXPTestUtilities.tryRunWithPolicyManager(() -> test(),
  54                 new FilePermission(System.getProperty("test.src") + "/-", "read"));
  55     }
  56 
  57     public void runWithoutSecurityManager() throws Exception {
  58         test();
  59     }
  60     
  61     private void test() {
  62         testDOMParserElementAttributeLimit();
  63         testDOMNSParserElementAttributeLimit();
  64         testDOMNSParserElementAttributeLimitWithoutSecureProcessing();
  65         testSystemElementAttributeLimitWithoutSecureProcessing();
  66         testSystemElementAttributeLimitWithSecureProcessing();
  67         testDOMSecureProcessingDefaultValue();
  68         testSAXSecureProcessingDefaultValue();
  69         testSystemMaxOccurLimitWithoutSecureProcessing();
  70         testValidMaxOccurLimitWithOutSecureProcessing();
  71         testSystemEntityExpansionLimitWithOutSecureProcessing();
  72         testSystemEntityExpansionLimitWithSecureProcessing();
  73         testEntityExpansionLimitWithSecureProcessing();
  74         testEntityExpansionLimitWithOutSecureProcessing();
  75     }
  76 
  77     /*
  78      * Given XML document has more than 10000 attributes. Exception is expected
  79      */
  80     private void testDOMParserElementAttributeLimit() {
  81         try {
  82             dbf = DocumentBuilderFactory.newInstance();
  83             DocumentBuilder parser = dbf.newDocumentBuilder();
  84             Document doc = parser.parse(this.getClass().getResourceAsStream("DosTest.xml"));
  85             Assert.fail("SAXParserException is expected, as given XML document contains more than 10000 attributes");
  86         } catch (SAXParseException e) {
  87             System.out.println(e.getMessage());
  88         } catch (Exception e) {
  89             Assert.fail("Exception " + e.getMessage());
  90         }
  91     }
  92 
  93     /*
  94      * Given XML document has more than 10000 attributes. It should report an
  95      * error.
  96      */
  97     private void testDOMNSParserElementAttributeLimit() {
  98         try {
  99             dbf = DocumentBuilderFactory.newInstance();
 100             dbf.setNamespaceAware(true);
 101             DocumentBuilder parser = dbf.newDocumentBuilder();
 102             Document doc = parser.parse(this.getClass().getResourceAsStream("DosTest.xml"));
 103             Assert.fail("SAXParserException is expected, as given XML document contains more than 10000 attributes");
 104         } catch (SAXParseException e) {
 105             System.out.println(e.getMessage());
 106         } catch (Exception e) {
 107             Assert.fail("Exception " + e.getMessage());
 108         }
 109     }
 110 
 111     /*
 112      * Given XML document has more than 10000 attributes. Parsing this XML
 113      * document in non-secure mode, should not report any error.
 114      */
 115     private void testDOMNSParserElementAttributeLimitWithoutSecureProcessing() {
 116         if (isSecureMode())
 117             return; // jaxp secure feature can not be turned off when security
 118                     // manager is present
 119         try {
 120             dbf = DocumentBuilderFactory.newInstance();
 121             dbf.setFeature(XMLConstants.FEATURE_SECURE_PROCESSING, false);
 122             dbf.setNamespaceAware(true);
 123             DocumentBuilder parser = dbf.newDocumentBuilder();
 124             Document doc = parser.parse(this.getClass().getResourceAsStream("DosTest.xml"));
 125 
 126         } catch (SAXParseException e) {
 127             Assert.fail(e.getMessage());
 128         } catch (Exception e) {
 129             Assert.fail("Exception " + e.getMessage());
 130         }
 131     }
 132 
 133     /*
 134      * Before 8014530: Given XML document has 3 attributes and System property
 135      * is set to 2. Parsing this XML document in non-secure mode, should not
 136      * report an error.
 137      * After 8014530: System properties will override FSP, the result of this
 138      * test should be the same as
 139      * testSystemElementAttributeLimitWithSecureProcessing
 140      */
 141     private void testSystemElementAttributeLimitWithoutSecureProcessing() {
 142         if (isSecureMode())
 143             return; // jaxp secure feature can not be turned off when security
 144                     // manager is present
 145         try {
 146             dbf = DocumentBuilderFactory.newInstance();
 147             dbf.setFeature(XMLConstants.FEATURE_SECURE_PROCESSING, false);
 148             dbf.setNamespaceAware(true);
 149             System.setProperty("elementAttributeLimit", "2");
 150             DocumentBuilder parser = dbf.newDocumentBuilder();
 151             Document doc = parser.parse(this.getClass().getResourceAsStream("DosTest3.xml"));
 152 
 153             Assert.fail("SAXParserException is expected, as given XML document contains more than 2 attributes");
 154         } catch (Exception e) {
 155             String errMsg = e.getMessage();
 156             Throwable cause = e.getCause();
 157             if (cause != null) {
 158                 errMsg += cause.getMessage();
 159             }
 160             if (errMsg.contains("JAXP0001")) {
 161                 // expected
 162             } else {
 163                 Assert.fail("Unexpected error: " + e.getMessage());
 164             }
 165         } finally {
 166             System.clearProperty("elementAttributeLimit");
 167         }
 168     }
 169 
 170     /*
 171      * Given XML document has 3 attributes and System property is set to 2.
 172      * Parsing this XML document in secure mode, should report an error.
 173      */
 174     private void testSystemElementAttributeLimitWithSecureProcessing() {
 175         try {
 176             dbf = DocumentBuilderFactory.newInstance();
 177             dbf.setNamespaceAware(true);
 178             System.setProperty("elementAttributeLimit", "2");
 179             DocumentBuilder parser = dbf.newDocumentBuilder();
 180             Document doc = parser.parse(this.getClass().getResourceAsStream("DosTest3.xml"));
 181             Assert.fail("SAXParserException is expected, as given XML document contains more than 2 attributes");
 182         } catch (SAXParseException e) {
 183             System.out.println(e.getMessage());
 184         } catch (Exception e) {
 185             Assert.fail("Exception " + e.getMessage());
 186         } finally {
 187             System.setProperty("elementAttributeLimit", "");
 188         }
 189     }
 190 
 191     /*
 192      * Default value for secure processing feature should be true.
 193      */
 194     private void testDOMSecureProcessingDefaultValue() {
 195         try {
 196             dbf = DocumentBuilderFactory.newInstance();
 197             Assert.assertTrue(dbf.getFeature(XMLConstants.FEATURE_SECURE_PROCESSING), "Default value for secureProcessing feature should be true");
 198 
 199         } catch (Exception e) {
 200             Assert.fail("Exception " + e.getMessage());
 201         }
 202     }
 203 
 204     /*
 205      * Default value for secure processing feature should be true.
 206      */
 207     private void testSAXSecureProcessingDefaultValue() {
 208         try {
 209             SAXParserFactory spf = SAXParserFactory.newInstance();
 210             Assert.assertTrue(spf.getFeature(XMLConstants.FEATURE_SECURE_PROCESSING), "Default value for secureProcessing feature should be true");
 211 
 212         } catch (Exception e) {
 213             Assert.fail("Exception " + e.getMessage());
 214         }
 215     }
 216 
 217     /*
 218      * This method sets system property for maxOccurLimit=2 and secure process
 219      * feature is off. Given doument contains more than 2 elements and hence an
 220      * error should be reported.
 221      */
 222     private void testSystemMaxOccurLimitWithoutSecureProcessing() {
 223         if (isSecureMode())
 224             return; // jaxp secure feature can not be turned off when security
 225                     // manager is present
 226         try {
 227             SAXParserFactory spf = SAXParserFactory.newInstance();
 228             spf.setFeature(XMLConstants.FEATURE_SECURE_PROCESSING, false);
 229             spf.setValidating(true);
 230             System.setProperty("maxOccurLimit", "2");
 231             // Set the properties for Schema Validation
 232             String SCHEMA_LANG = "http://java.sun.com/xml/jaxp/properties/schemaLanguage";
 233             String SCHEMA_TYPE = "http://www.w3.org/2001/XMLSchema";
 234             // Get the Schema location as a File object
 235             File schemaFile = new File(this.getClass().getResource("toys.xsd").toURI());
 236             // Get the parser
 237             SAXParser parser = spf.newSAXParser();
 238             parser.setProperty(SCHEMA_LANG, SCHEMA_TYPE);
 239             parser.setProperty("http://java.sun.com/xml/jaxp/properties/schemaSource", schemaFile);
 240 
 241             InputStream is = this.getClass().getResourceAsStream("toys.xml");
 242             MyErrorHandler eh = new MyErrorHandler();
 243             parser.parse(is, eh);
 244             Assert.assertFalse(eh.errorOccured, "Not Expected Error");
 245             System.setProperty("maxOccurLimit", "");
 246         } catch (Exception e) {
 247             Assert.fail("Exception occured: " + e.getMessage());
 248         }
 249     }
 250 
 251     /*
 252      * This test will take longer time to execute( abt 120sec). This method
 253      * tries to validate a document. This document contains an element whose
 254      * maxOccur is '3002'. Since secure processing feature is off, document
 255      * should be parsed without any errors.
 256      */
 257     private void testValidMaxOccurLimitWithOutSecureProcessing() {
 258         if (isSecureMode())
 259             return; // jaxp secure feature can not be turned off when security
 260                     // manager is present
 261         try {
 262             SAXParserFactory spf = SAXParserFactory.newInstance();
 263             spf.setFeature(XMLConstants.FEATURE_SECURE_PROCESSING, false);
 264             spf.setValidating(true);
 265             // Set the properties for Schema Validation
 266             String SCHEMA_LANG = "http://java.sun.com/xml/jaxp/properties/schemaLanguage";
 267             String SCHEMA_TYPE = "http://www.w3.org/2001/XMLSchema";
 268             // Get the Schema location as a File object
 269             File schemaFile = new File(this.getClass().getResource("toys3002.xsd").toURI());
 270             // Get the parser
 271             SAXParser parser = spf.newSAXParser();
 272             parser.setProperty(SCHEMA_LANG, SCHEMA_TYPE);
 273             parser.setProperty("http://java.sun.com/xml/jaxp/properties/schemaSource", schemaFile);
 274 
 275             InputStream is = this.getClass().getResourceAsStream("toys.xml");
 276             MyErrorHandler eh = new MyErrorHandler();
 277             parser.parse(is, eh);
 278             Assert.assertFalse(eh.errorOccured, "Expected Error as maxOccurLimit is exceeded");
 279 
 280         } catch (Exception e) {
 281             Assert.fail("Exception occured: " + e.getMessage());
 282         }
 283     }
 284 
 285     /*
 286      * Before 8014530: System property is set to 2. Given XML document has more
 287      * than 2 entity references. Parsing this document in non-secure mode,
 288      * should *not* report an error.
 289      * After 8014530: System properties will override FSP, the result of this
 290      * test should be the same as
 291      * testSystemElementAttributeLimitWithSecureProcessing
 292      */
 293     private void testSystemEntityExpansionLimitWithOutSecureProcessing() {
 294         if (isSecureMode())
 295             return; // jaxp secure feature can not be turned off when security
 296                     // manager is present
 297         try {
 298             System.setProperty("entityExpansionLimit", "2");
 299             dbf = DocumentBuilderFactory.newInstance();
 300             dbf.setFeature(XMLConstants.FEATURE_SECURE_PROCESSING, false);
 301             dbf.setValidating(true);
 302             DocumentBuilder parser = dbf.newDocumentBuilder();
 303             Document doc = parser.parse(this.getClass().getResourceAsStream("entity.xml"));
 304             Assert.fail("SAXParserException is expected, as given XML document contains more 2 entity references");
 305         } catch (Exception e) {
 306             String errMsg = e.getMessage();
 307             Throwable cause = e.getCause();
 308             if (cause != null) {
 309                 errMsg += cause.getMessage();
 310             }
 311             if (errMsg.contains("JAXP0001")) {
 312                 // expected
 313             } else {
 314                 Assert.fail("Unexpected error: " + e.getMessage());
 315             }
 316         } finally {
 317             System.clearProperty("entityExpansionLimit");
 318         }
 319     }
 320 
 321     /*
 322      * System property is set to 2. Given XML document has more than 2 entity
 323      * references. Parsing this document in secure mode, should report an error.
 324      */
 325     private void testSystemEntityExpansionLimitWithSecureProcessing() {
 326         try {
 327             dbf = DocumentBuilderFactory.newInstance();
 328             dbf.setValidating(true);
 329             System.setProperty("entityExpansionLimit", "2");
 330             DocumentBuilder parser = dbf.newDocumentBuilder();
 331             Document doc = parser.parse(this.getClass().getResourceAsStream("entity.xml"));
 332             Assert.fail("SAXParserException is expected, as given XML document contains more 2 entity references");
 333 
 334         } catch (SAXParseException e) {
 335             System.out.println(e.getMessage());
 336         } catch (Exception e) {
 337             Assert.fail("Exception " + e.getMessage());
 338         } finally {
 339             System.setProperty("entityExpansionLimit", "");
 340         }
 341     }
 342 
 343     /*
 344      * Given XML document has more than 64000 entity references. Parsing this
 345      * document in secure mode, should report an error.
 346      */
 347     private void testEntityExpansionLimitWithSecureProcessing() {
 348         try {
 349             dbf = DocumentBuilderFactory.newInstance();
 350             dbf.setValidating(true);
 351             DocumentBuilder parser = dbf.newDocumentBuilder();
 352             Document doc = parser.parse(this.getClass().getResourceAsStream("entity64K.xml"));
 353             Assert.fail("SAXParserException is expected, as given XML document contains more 2 entity references");
 354 
 355         } catch (SAXParseException e) {
 356             System.out.println(e.getMessage());
 357         } catch (Exception e) {
 358             Assert.fail("Exception " + e.getMessage());
 359         } finally {
 360             System.setProperty("entityExpansionLimit", "");
 361         }
 362     }
 363 
 364     /*
 365      * Given XML document has more than 64000 entity references. Parsing this
 366      * document in non-secure mode, should not report any error.
 367      */
 368     private void testEntityExpansionLimitWithOutSecureProcessing() {
 369         if (isSecureMode())
 370             return; // jaxp secure feature can not be turned off when security
 371                     // manager is present
 372         try {
 373             dbf = DocumentBuilderFactory.newInstance();
 374             dbf.setFeature(XMLConstants.FEATURE_SECURE_PROCESSING, false);
 375             dbf.setValidating(true);
 376             DocumentBuilder parser = dbf.newDocumentBuilder();
 377             Document doc = parser.parse(this.getClass().getResourceAsStream("entity64K.xml"));
 378 
 379         } catch (SAXParseException e) {
 380             Assert.fail("Exception " + e.getMessage());
 381         } catch (Exception e) {
 382             Assert.fail("Exception " + e.getMessage());
 383         } finally {
 384             System.setProperty("entityExpansionLimit", "");
 385         }
 386     }
 387     
 388     private boolean isSecureMode() {
 389         return System.getSecurityManager() != null;
 390     }
 391 }