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) 2013 Jeremy Long. All Rights Reserved.
17   */
18  package org.owasp.dependencycheck.xml.suppression;
19  
20  import java.io.File;
21  import java.io.FileInputStream;
22  import java.io.FileNotFoundException;
23  import java.io.IOException;
24  import java.io.InputStream;
25  import java.io.InputStreamReader;
26  import java.io.Reader;
27  import java.util.List;
28  import javax.xml.parsers.ParserConfigurationException;
29  import javax.xml.parsers.SAXParser;
30  import javax.xml.parsers.SAXParserFactory;
31  
32  import org.slf4j.Logger;
33  import org.slf4j.LoggerFactory;
34  import org.xml.sax.InputSource;
35  import org.xml.sax.SAXException;
36  import org.xml.sax.XMLReader;
37  
38  /**
39   * A simple validating parser for XML Suppression Rules.
40   *
41   * @author Jeremy Long
42   */
43  public class SuppressionParser {
44  
45      /**
46       * The logger.
47       */
48      private static final Logger LOGGER = LoggerFactory.getLogger(SuppressionParser.class);
49      /**
50       * JAXP Schema Language. Source:
51       * http://docs.oracle.com/javase/tutorial/jaxp/sax/validation.html
52       */
53      public static final String JAXP_SCHEMA_LANGUAGE = "http://java.sun.com/xml/jaxp/properties/schemaLanguage";
54      /**
55       * W3C XML Schema. Source:
56       * http://docs.oracle.com/javase/tutorial/jaxp/sax/validation.html
57       */
58      public static final String W3C_XML_SCHEMA = "http://www.w3.org/2001/XMLSchema";
59      /**
60       * JAXP Schema Source. Source:
61       * http://docs.oracle.com/javase/tutorial/jaxp/sax/validation.html
62       */
63      public static final String JAXP_SCHEMA_SOURCE = "http://java.sun.com/xml/jaxp/properties/schemaSource";
64      /**
65       * The suppression schema file location.
66       */
67      private static final String SUPPRESSION_SCHEMA = "schema/dependency-suppression.1.1.xsd";
68      /**
69       * The old suppression schema file location.
70       */
71      private static final String OLD_SUPPRESSION_SCHEMA = "schema/suppression.xsd";
72  
73      /**
74       * Parses the given XML file and returns a list of the suppression rules
75       * contained.
76       *
77       * @param file an XML file containing suppression rules
78       * @return a list of suppression rules
79       * @throws SuppressionParseException thrown if the XML file cannot be parsed
80       */
81      public List<SuppressionRule> parseSuppressionRules(File file) throws SuppressionParseException {
82          FileInputStream fis = null;
83          try {
84              fis = new FileInputStream(file);
85              return parseSuppressionRules(fis);
86          } catch (IOException ex) {
87              LOGGER.debug("", ex);
88              throw new SuppressionParseException(ex);
89          } catch (SAXException ex) {
90              try {
91                  if (fis != null) {
92                      try {
93                          fis.close();
94                      } catch (IOException ex1) {
95                          LOGGER.debug("Unable to close stream", ex1);
96                      }
97                  }
98                  fis = new FileInputStream(file);
99              } catch (FileNotFoundException ex1) {
100                 throw new SuppressionParseException(ex);
101             }
102             return parseOldSuppressionRules(fis);
103         } finally {
104             if (fis != null) {
105                 try {
106                     fis.close();
107                 } catch (IOException ex) {
108                     LOGGER.debug("Unable to close stream", ex);
109                 }
110             }
111         }
112     }
113 
114     /**
115      * Parses the given XML stream and returns a list of the suppression rules
116      * contained.
117      *
118      * @param inputStream an InputStream containing suppression rules
119      * @return a list of suppression rules
120      * @throws SuppressionParseException thrown if the XML cannot be parsed
121      * @throws SAXException thrown if the XML cannot be parsed
122      */
123     public List<SuppressionRule> parseSuppressionRules(InputStream inputStream) throws SuppressionParseException, SAXException {
124         InputStream schemaStream = null;
125         try {
126             schemaStream = this.getClass().getClassLoader().getResourceAsStream(SUPPRESSION_SCHEMA);
127             final SuppressionHandler handler = new SuppressionHandler();
128             final SAXParserFactory factory = SAXParserFactory.newInstance();
129             factory.setNamespaceAware(true);
130             factory.setValidating(true);
131             final SAXParser saxParser = factory.newSAXParser();
132             saxParser.setProperty(SuppressionParser.JAXP_SCHEMA_LANGUAGE, SuppressionParser.W3C_XML_SCHEMA);
133             saxParser.setProperty(SuppressionParser.JAXP_SCHEMA_SOURCE, new InputSource(schemaStream));
134             final XMLReader xmlReader = saxParser.getXMLReader();
135             xmlReader.setErrorHandler(new SuppressionErrorHandler());
136             xmlReader.setContentHandler(handler);
137 
138             final Reader reader = new InputStreamReader(inputStream, "UTF-8");
139             final InputSource in = new InputSource(reader);
140             //in.setEncoding("UTF-8");
141 
142             xmlReader.parse(in);
143 
144             return handler.getSuppressionRules();
145         } catch (ParserConfigurationException ex) {
146             LOGGER.debug("", ex);
147             throw new SuppressionParseException(ex);
148         } catch (SAXException ex) {
149             if (ex.getMessage().contains("Cannot find the declaration of element 'suppressions'.")) {
150                 throw ex;
151             } else {
152                 LOGGER.debug("", ex);
153                 throw new SuppressionParseException(ex);
154             }
155         } catch (FileNotFoundException ex) {
156             LOGGER.debug("", ex);
157             throw new SuppressionParseException(ex);
158         } catch (IOException ex) {
159             LOGGER.debug("", ex);
160             throw new SuppressionParseException(ex);
161         } finally {
162             if (schemaStream != null) {
163                 try {
164                     schemaStream.close();
165                 } catch (IOException ex) {
166                     LOGGER.debug("Error closing suppression file stream", ex);
167                 }
168             }
169         }
170     }
171 
172     /**
173      * Parses the given XML stream and returns a list of the suppression rules
174      * contained.
175      *
176      * @param inputStream an InputStream containing suppression rues
177      * @return a list of suppression rules
178      * @throws SuppressionParseException if the XML cannot be parsed
179      */
180     private List<SuppressionRule> parseOldSuppressionRules(InputStream inputStream) throws SuppressionParseException {
181         InputStream schemaStream = null;
182         try {
183             schemaStream = this.getClass().getClassLoader().getResourceAsStream(OLD_SUPPRESSION_SCHEMA);
184             final SuppressionHandler handler = new SuppressionHandler();
185             final SAXParserFactory factory = SAXParserFactory.newInstance();
186             factory.setNamespaceAware(true);
187             factory.setValidating(true);
188             final SAXParser saxParser = factory.newSAXParser();
189             saxParser.setProperty(SuppressionParser.JAXP_SCHEMA_LANGUAGE, SuppressionParser.W3C_XML_SCHEMA);
190             saxParser.setProperty(SuppressionParser.JAXP_SCHEMA_SOURCE, new InputSource(schemaStream));
191             final XMLReader xmlReader = saxParser.getXMLReader();
192             xmlReader.setErrorHandler(new SuppressionErrorHandler());
193             xmlReader.setContentHandler(handler);
194 
195             final Reader reader = new InputStreamReader(inputStream, "UTF-8");
196             final InputSource in = new InputSource(reader);
197 
198             xmlReader.parse(in);
199 
200             return handler.getSuppressionRules();
201         } catch (ParserConfigurationException ex) {
202             LOGGER.debug("", ex);
203             throw new SuppressionParseException(ex);
204         } catch (SAXException ex) {
205             LOGGER.debug("", ex);
206             throw new SuppressionParseException(ex);
207         } catch (FileNotFoundException ex) {
208             LOGGER.debug("", ex);
209             throw new SuppressionParseException(ex);
210         } catch (IOException ex) {
211             LOGGER.debug("", ex);
212             throw new SuppressionParseException(ex);
213         } finally {
214             if (schemaStream != null) {
215                 try {
216                     schemaStream.close();
217                 } catch (IOException ex) {
218                     LOGGER.debug("Error closing old suppression file stream", ex);
219                 }
220             }
221         }
222     }
223 }