View Javadoc
1   /*
2    * This file is part of dependency-check-core.
3    *
4    * Licensed under the Apache License, Version 2.0 (the "License");
5    * you may not use this file except in compliance with the License.
6    * You may obtain a copy of the License at
7    *
8    *     http://www.apache.org/licenses/LICENSE-2.0
9    *
10   * Unless required by applicable law or agreed to in writing, software
11   * distributed under the License is distributed on an "AS IS" BASIS,
12   * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13   * See the License for the specific language governing permissions and
14   * limitations under the License.
15   *
16   * Copyright (c) 2016 Jeremy Long. All Rights Reserved.
17   */
18  package org.owasp.dependencycheck.utils;
19  
20  import java.io.InputStream;
21  import javax.xml.XMLConstants;
22  import javax.xml.parsers.DocumentBuilder;
23  import javax.xml.parsers.DocumentBuilderFactory;
24  import javax.xml.parsers.ParserConfigurationException;
25  import javax.xml.parsers.SAXParser;
26  import javax.xml.parsers.SAXParserFactory;
27  import org.xml.sax.SAXException;
28  import org.xml.sax.SAXNotRecognizedException;
29  import org.xml.sax.SAXNotSupportedException;
30  import org.xml.sax.SAXParseException;
31  
32  /**
33   * Collection of XML related code.
34   *
35   * @author Jeremy Long
36   */
37  public final class XmlUtils {
38  
39      /**
40       * JAXP Schema Language. Source:
41       * http://docs.oracle.com/javase/tutorial/jaxp/sax/validation.html
42       */
43      public static final String JAXP_SCHEMA_LANGUAGE = "http://java.sun.com/xml/jaxp/properties/schemaLanguage";
44      /**
45       * W3C XML Schema. Source:
46       * http://docs.oracle.com/javase/tutorial/jaxp/sax/validation.html
47       */
48      public static final String W3C_XML_SCHEMA = "http://www.w3.org/2001/XMLSchema";
49      /**
50       * JAXP Schema Source. Source:
51       * http://docs.oracle.com/javase/tutorial/jaxp/sax/validation.html
52       */
53      public static final String JAXP_SCHEMA_SOURCE = "http://java.sun.com/xml/jaxp/properties/schemaSource";
54  
55      /**
56       * Private constructor for a utility class.
57       */
58      private XmlUtils() {
59      }
60  
61      /**
62       * Constructs a validating secure SAX Parser.
63       *
64       * @param schemaStream the schema to validate the XML against
65       * @return a SAX Parser
66       * @throws ParserConfigurationException is thrown if there is a parser
67       * configuration exception
68       * @throws SAXNotRecognizedException thrown if there is an unrecognized
69       * feature
70       * @throws SAXNotSupportedException thrown if there is a non-supported
71       * feature
72       * @throws SAXException is thrown if there is a SAXException
73       */
74      public static SAXParser buildSecureSaxParser(InputStream schemaStream) throws ParserConfigurationException,
75              SAXNotRecognizedException, SAXNotSupportedException, SAXException {
76          final SAXParserFactory factory = SAXParserFactory.newInstance();
77          factory.setNamespaceAware(true);
78          factory.setValidating(true);
79          factory.setFeature("http://apache.org/xml/features/disallow-doctype-decl", true);
80          factory.setFeature("http://xml.org/sax/features/external-general-entities", false);
81          //setting the following unfortunately breaks reading the old suppression files (version 1).
82          //factory.setFeature(XMLConstants.FEATURE_SECURE_PROCESSING, true);
83  
84          final SAXParser saxParser = factory.newSAXParser();
85          saxParser.setProperty(JAXP_SCHEMA_LANGUAGE, W3C_XML_SCHEMA);
86          saxParser.setProperty(JAXP_SCHEMA_SOURCE, schemaStream);
87          return saxParser;
88      }
89  
90      /**
91       * Constructs a secure SAX Parser.
92       *
93       * @return a SAX Parser
94       * @throws ParserConfigurationException thrown if there is a parser
95       * configuration exception
96       * @throws SAXNotRecognizedException thrown if there is an unrecognized
97       * feature
98       * @throws SAXNotSupportedException thrown if there is a non-supported
99       * feature
100      * @throws SAXException is thrown if there is a SAXException
101      */
102     public static SAXParser buildSecureSaxParser() throws ParserConfigurationException,
103             SAXNotRecognizedException, SAXNotSupportedException, SAXException {
104         final SAXParserFactory factory = SAXParserFactory.newInstance();
105         factory.setFeature("http://apache.org/xml/features/disallow-doctype-decl", true);
106         factory.setFeature("http://xml.org/sax/features/external-general-entities", false);
107         factory.setFeature(XMLConstants.FEATURE_SECURE_PROCESSING, true);
108         return factory.newSAXParser();
109     }
110 
111     /**
112      * Constructs a new document builder with security features enabled.
113      *
114      * @return a new document builder
115      * @throws ParserConfigurationException thrown if there is a parser
116      * configuration exception
117      */
118     public static DocumentBuilder buildSecureDocumentBuilder() throws ParserConfigurationException {
119         final DocumentBuilderFactory factory = DocumentBuilderFactory.newInstance();
120         factory.setFeature("http://apache.org/xml/features/disallow-doctype-decl", true);
121         factory.setFeature("http://xml.org/sax/features/external-general-entities", false);
122         factory.setFeature(XMLConstants.FEATURE_SECURE_PROCESSING, true);
123         final DocumentBuilder db = factory.newDocumentBuilder();
124         return db;
125     }
126 
127     /**
128      * Builds a prettier exception message.
129      *
130      * @param ex the SAXParseException
131      * @return an easier to read exception message
132      */
133     public static String getPrettyParseExceptionInfo(SAXParseException ex) {
134 
135         final StringBuilder sb = new StringBuilder();
136 
137         if (ex.getSystemId() != null) {
138             sb.append("systemId=").append(ex.getSystemId()).append(", ");
139         }
140         if (ex.getPublicId() != null) {
141             sb.append("publicId=").append(ex.getPublicId()).append(", ");
142         }
143         if (ex.getLineNumber() > 0) {
144             sb.append("Line=").append(ex.getLineNumber());
145         }
146         if (ex.getColumnNumber() > 0) {
147             sb.append(", Column=").append(ex.getColumnNumber());
148         }
149         sb.append(": ").append(ex.getMessage());
150 
151         return sb.toString();
152     }
153 }