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 edu.umd.cs.findbugs.annotations.SuppressFBWarnings;
21  import java.io.File;
22  import java.io.FileInputStream;
23  import java.io.IOException;
24  import java.io.InputStream;
25  import java.io.InputStreamReader;
26  import java.io.Reader;
27  import java.nio.charset.StandardCharsets;
28  import java.util.List;
29  import javax.annotation.concurrent.ThreadSafe;
30  import javax.xml.parsers.ParserConfigurationException;
31  
32  import org.apache.commons.io.ByteOrderMark;
33  import org.apache.commons.io.input.BOMInputStream;
34  
35  import org.owasp.dependencycheck.utils.AutoCloseableInputSource;
36  import org.owasp.dependencycheck.utils.XmlUtils;
37  
38  import org.slf4j.Logger;
39  import org.slf4j.LoggerFactory;
40  import org.xml.sax.InputSource;
41  import org.xml.sax.SAXException;
42  import org.xml.sax.XMLReader;
43  
44  import static org.owasp.dependencycheck.utils.AutoCloseableInputSource.fromResource;
45  
46  /**
47   * A simple validating parser for XML Suppression Rules.
48   *
49   * @author Jeremy Long
50   */
51  @ThreadSafe
52  public class SuppressionParser {
53  
54      /**
55       * The logger.
56       */
57      private static final Logger LOGGER = LoggerFactory.getLogger(SuppressionParser.class);
58  
59      /**
60       * The suppression schema file location for v 1.4.
61       */
62      public static final String SUPPRESSION_SCHEMA_1_4 = "schema/dependency-suppression.1.4.xsd";
63      /**
64       * The suppression schema file location for v 1.3.
65       */
66      public static final String SUPPRESSION_SCHEMA_1_3 = "schema/dependency-suppression.1.3.xsd";
67      /**
68       * The suppression schema file location for v 1.2.
69       */
70      public static final String SUPPRESSION_SCHEMA_1_2 = "schema/dependency-suppression.1.2.xsd";
71      /**
72       * The suppression schema file location for v1.1.
73       */
74      public static final String SUPPRESSION_SCHEMA_1_1 = "schema/dependency-suppression.1.1.xsd";
75      /**
76       * The old suppression schema file location for v1.0.
77       */
78      private static final String SUPPRESSION_SCHEMA_1_0 = "schema/suppression.xsd";
79  
80      /**
81       * Parses the given XML file and returns a list of the suppression rules
82       * contained.
83       *
84       * @param file an XML file containing suppression rules
85       * @return a list of suppression rules
86       * @throws SuppressionParseException thrown if the XML file cannot be parsed
87       */
88      @SuppressFBWarnings(justification = "try with resource will clenaup the resources", value = {"OBL_UNSATISFIED_OBLIGATION"})
89      public List<SuppressionRule> parseSuppressionRules(File file) throws SuppressionParseException {
90          try (FileInputStream fis = new FileInputStream(file)) {
91              return parseSuppressionRules(fis);
92          } catch (SAXException | IOException ex) {
93              LOGGER.debug("", ex);
94              throw new SuppressionParseException(ex);
95          }
96      }
97  
98      /**
99       * Parses the given XML stream and returns a list of the suppression rules
100      * contained.
101      *
102      * @param inputStream an InputStream containing suppression rules
103      * @return a list of suppression rules
104      * @throws SuppressionParseException thrown if the XML cannot be parsed
105      * @throws SAXException thrown if the XML cannot be parsed
106      */
107     public List<SuppressionRule> parseSuppressionRules(InputStream inputStream)
108             throws SuppressionParseException, SAXException {
109         try (AutoCloseableInputSource schemaStream14 = fromResource(SUPPRESSION_SCHEMA_1_4);
110              AutoCloseableInputSource schemaStream13 = fromResource(SUPPRESSION_SCHEMA_1_3);
111              AutoCloseableInputSource schemaStream12 = fromResource(SUPPRESSION_SCHEMA_1_2);
112              AutoCloseableInputSource schemaStream11 = fromResource(SUPPRESSION_SCHEMA_1_1);
113              AutoCloseableInputSource schemaStream10 = fromResource(SUPPRESSION_SCHEMA_1_0)) {
114 
115             final BOMInputStream bomStream = BOMInputStream.builder().setInputStream(inputStream).get();
116             final ByteOrderMark bom = bomStream.getBOM();
117             final String defaultEncoding = StandardCharsets.UTF_8.name();
118             final String charsetName = bom == null ? defaultEncoding : bom.getCharsetName();
119 
120             final SuppressionHandler handler = new SuppressionHandler();
121             final XMLReader xmlReader = XmlUtils.buildSecureValidatingXmlReader(schemaStream14, schemaStream13, schemaStream12, schemaStream11, schemaStream10);
122             xmlReader.setErrorHandler(new SuppressionErrorHandler());
123             xmlReader.setContentHandler(handler);
124             try (Reader reader = new InputStreamReader(bomStream, charsetName)) {
125                 final InputSource in = new InputSource(reader);
126                 xmlReader.parse(in);
127                 return handler.getSuppressionRules();
128             }
129         } catch (ParserConfigurationException | IOException ex) {
130             LOGGER.debug("", ex);
131             throw new SuppressionParseException(ex);
132         } catch (SAXException ex) {
133             if (ex.getMessage().contains("Cannot find the declaration of element 'suppressions'.")) {
134                 throw ex;
135             } else {
136                 LOGGER.debug("", ex);
137                 throw new SuppressionParseException(ex);
138             }
139         }
140     }
141 
142 }