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 org.owasp.dependencycheck.utils.XmlUtils;
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       * The suppression schema file location.
51       */
52      public static final String SUPPRESSION_SCHEMA = "schema/dependency-suppression.1.1.xsd";
53      /**
54       * The old suppression schema file location.
55       */
56      private static final String OLD_SUPPRESSION_SCHEMA = "schema/suppression.xsd";
57  
58      /**
59       * Parses the given XML file and returns a list of the suppression rules
60       * contained.
61       *
62       * @param file an XML file containing suppression rules
63       * @return a list of suppression rules
64       * @throws SuppressionParseException thrown if the XML file cannot be parsed
65       */
66      public List<SuppressionRule> parseSuppressionRules(File file) throws SuppressionParseException {
67          FileInputStream fis = null;
68          try {
69              fis = new FileInputStream(file);
70              return parseSuppressionRules(fis);
71          } catch (IOException ex) {
72              LOGGER.debug("", ex);
73              throw new SuppressionParseException(ex);
74          } catch (SAXException ex) {
75              try {
76                  if (fis != null) {
77                      try {
78                          fis.close();
79                      } catch (IOException ex1) {
80                          LOGGER.debug("Unable to close stream", ex1);
81                      }
82                  }
83                  fis = new FileInputStream(file);
84              } catch (FileNotFoundException ex1) {
85                  throw new SuppressionParseException(ex);
86              }
87              try {
88                  return parseSuppressionRules(fis, OLD_SUPPRESSION_SCHEMA);
89              } catch (SAXException ex1) {
90                  throw new SuppressionParseException(ex);
91              }
92          } finally {
93              if (fis != null) {
94                  try {
95                      fis.close();
96                  } catch (IOException ex) {
97                      LOGGER.debug("Unable to close stream", ex);
98                  }
99              }
100         }
101     }
102 
103     /**
104      * Parses the given XML stream and returns a list of the suppression rules
105      * contained.
106      *
107      * @param inputStream an InputStream containing suppression rules
108      * @return a list of suppression rules
109      * @throws SuppressionParseException thrown if the XML cannot be parsed
110      * @throws SAXException thrown if the XML cannot be parsed
111      */
112     public List<SuppressionRule> parseSuppressionRules(InputStream inputStream) throws SuppressionParseException, SAXException {
113         return parseSuppressionRules(inputStream, SUPPRESSION_SCHEMA);
114     }
115 
116     /**
117      * Parses the given XML stream and returns a list of the suppression rules
118      * contained.
119      *
120      * @param inputStream an InputStream containing suppression rules
121      * @param schema the schema used to validate the XML stream
122      * @return a list of suppression rules
123      * @throws SuppressionParseException thrown if the XML cannot be parsed
124      * @throws SAXException thrown if the XML cannot be parsed
125      */
126     private List<SuppressionRule> parseSuppressionRules(InputStream inputStream, String schema) throws SuppressionParseException, SAXException {
127         InputStream schemaStream = null;
128         try {
129             schemaStream = this.getClass().getClassLoader().getResourceAsStream(schema);
130             final SuppressionHandler handler = new SuppressionHandler();
131             final SAXParser saxParser = XmlUtils.buildSecureSaxParser(schemaStream);
132             final XMLReader xmlReader = saxParser.getXMLReader();
133             xmlReader.setErrorHandler(new SuppressionErrorHandler());
134             xmlReader.setContentHandler(handler);
135             final Reader reader = new InputStreamReader(inputStream, "UTF-8");
136             final InputSource in = new InputSource(reader);
137             xmlReader.parse(in);
138             return handler.getSuppressionRules();
139         } catch (ParserConfigurationException ex) {
140             LOGGER.debug("", ex);
141             throw new SuppressionParseException(ex);
142         } catch (SAXException ex) {
143             if (ex.getMessage().contains("Cannot find the declaration of element 'suppressions'.")) {
144                 throw ex;
145             } else {
146                 LOGGER.debug("", ex);
147                 throw new SuppressionParseException(ex);
148             }
149         } catch (FileNotFoundException ex) {
150             LOGGER.debug("", ex);
151             throw new SuppressionParseException(ex);
152         } catch (IOException ex) {
153             LOGGER.debug("", ex);
154             throw new SuppressionParseException(ex);
155         } finally {
156             if (schemaStream != null) {
157                 try {
158                     schemaStream.close();
159                 } catch (IOException ex) {
160                     LOGGER.debug("Error closing suppression file stream", ex);
161                 }
162             }
163         }
164     }
165 }