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.analyzer;
19  
20  import java.io.File;
21  import java.io.IOException;
22  import java.io.InputStream;
23  import java.net.MalformedURLException;
24  import java.net.URL;
25  import java.util.List;
26  import java.util.Set;
27  import java.util.regex.Pattern;
28  import org.owasp.dependencycheck.exception.InitializationException;
29  import org.owasp.dependencycheck.xml.suppression.SuppressionParseException;
30  import org.owasp.dependencycheck.xml.suppression.SuppressionParser;
31  import org.owasp.dependencycheck.xml.suppression.SuppressionRule;
32  import org.owasp.dependencycheck.utils.DownloadFailedException;
33  import org.owasp.dependencycheck.utils.Downloader;
34  import org.owasp.dependencycheck.utils.FileUtils;
35  import org.owasp.dependencycheck.utils.Settings;
36  import org.slf4j.Logger;
37  import org.slf4j.LoggerFactory;
38  import org.xml.sax.SAXException;
39  
40  /**
41   * Abstract base suppression analyzer that contains methods for parsing the
42   * suppression xml file.
43   *
44   * @author Jeremy Long
45   */
46  public abstract class AbstractSuppressionAnalyzer extends AbstractAnalyzer {
47  
48      /**
49       * The Logger for use throughout the class
50       */
51      private static final Logger LOGGER = LoggerFactory.getLogger(AbstractSuppressionAnalyzer.class);
52  
53      //<editor-fold defaultstate="collapsed" desc="All standard implementation details of Analyzer">
54      /**
55       * Returns a list of file EXTENSIONS supported by this analyzer.
56       *
57       * @return a list of file EXTENSIONS supported by this analyzer.
58       */
59      public Set<String> getSupportedExtensions() {
60          return null;
61      }
62  
63      //</editor-fold>
64      /**
65       * The initialize method loads the suppression XML file.
66       *
67       * @throws InitializationException thrown if there is an exception
68       */
69      @Override
70      public void initialize() throws InitializationException {
71          super.initialize();
72          try {
73              loadSuppressionData();
74          } catch (SuppressionParseException ex) {
75              throw new InitializationException("Error initializing the suppression analyzer", ex);
76          }
77      }
78  
79      /**
80       * The list of suppression rules
81       */
82      private List<SuppressionRule> rules;
83  
84      /**
85       * Get the value of rules.
86       *
87       * @return the value of rules
88       */
89      public List<SuppressionRule> getRules() {
90          return rules;
91      }
92  
93      /**
94       * Set the value of rules.
95       *
96       * @param rules new value of rules
97       */
98      public void setRules(List<SuppressionRule> rules) {
99          this.rules = rules;
100     }
101 
102     /**
103      * Loads the suppression rules file.
104      *
105      * @throws SuppressionParseException thrown if the XML cannot be parsed.
106      */
107     private void loadSuppressionData() throws SuppressionParseException {
108         final SuppressionParser parser = new SuppressionParser();
109         File file = null;
110         try {
111             rules = parser.parseSuppressionRules(this.getClass().getClassLoader().getResourceAsStream("dependencycheck-base-suppression.xml"));
112         } catch (SAXException ex) {
113             throw new SuppressionParseException("Unable to parse the base suppression data file", ex);
114         }
115         final String suppressionFilePath = Settings.getString(Settings.KEYS.SUPPRESSION_FILE);
116         if (suppressionFilePath == null) {
117             return;
118         }
119         boolean deleteTempFile = false;
120         try {
121             final Pattern uriRx = Pattern.compile("^(https?|file)\\:.*", Pattern.CASE_INSENSITIVE);
122             if (uriRx.matcher(suppressionFilePath).matches()) {
123                 deleteTempFile = true;
124                 file = FileUtils.getTempFile("suppression", "xml");
125                 final URL url = new URL(suppressionFilePath);
126                 try {
127                     Downloader.fetchFile(url, file, false);
128                 } catch (DownloadFailedException ex) {
129                     Downloader.fetchFile(url, file, true);
130                 }
131             } else {
132                 file = new File(suppressionFilePath);
133                 InputStream suppressionsFromClasspath = null;
134                 if (!file.exists()) {
135                     try {
136                         suppressionsFromClasspath = this.getClass().getClassLoader().getResourceAsStream(suppressionFilePath);
137                         if (suppressionsFromClasspath != null) {
138                             deleteTempFile = true;
139                             file = FileUtils.getTempFile("suppression", "xml");
140                             try {
141                                 org.apache.commons.io.FileUtils.copyInputStreamToFile(suppressionsFromClasspath, file);
142                             } catch (IOException ex) {
143                                 throwSuppressionParseException("Unable to locate suppressions file in classpath", ex);
144                             }
145                         }
146                     } finally {
147                         if (suppressionsFromClasspath != null) {
148                             try {
149                                 suppressionsFromClasspath.close();
150                             } catch (IOException ex) {
151                                 LOGGER.debug("Failed to close stream", ex);
152                             }
153                         }
154                     }
155                 }
156             }
157             if (file != null) {
158                 try {
159                     rules.addAll(parser.parseSuppressionRules(file));
160                     LOGGER.debug("{} suppression rules were loaded.", rules.size());
161                 } catch (SuppressionParseException ex) {
162                     LOGGER.warn("Unable to parse suppression xml file '{}'", file.getPath());
163                     LOGGER.warn(ex.getMessage());
164                     throw ex;
165                 }
166             }
167         } catch (DownloadFailedException ex) {
168             throwSuppressionParseException("Unable to fetch the configured suppression file", ex);
169         } catch (MalformedURLException ex) {
170             throwSuppressionParseException("Configured suppression file has an invalid URL", ex);
171         } catch (IOException ex) {
172             throwSuppressionParseException("Unable to create temp file for suppressions", ex);
173         } finally {
174             if (deleteTempFile && file != null) {
175                 FileUtils.delete(file);
176             }
177         }
178     }
179 
180     /**
181      * Utility method to throw parse exceptions.
182      *
183      * @param message the exception message
184      * @param exception the cause of the exception
185      * @throws SuppressionParseException throws the generated
186      * SuppressionParseException
187      */
188     private void throwSuppressionParseException(String message, Exception exception) throws SuppressionParseException {
189         LOGGER.warn(message);
190         LOGGER.debug("", exception);
191         throw new SuppressionParseException(message, exception);
192     }
193 }