Coverage Report - org.owasp.dependencycheck.analyzer.HintAnalyzer
 
Classes in this File Line Coverage Branch Coverage Complexity
HintAnalyzer
45%
49/107
60%
28/46
8.8
 
 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) 2012 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.ArrayList;
 26  
 import java.util.Iterator;
 27  
 import java.util.List;
 28  
 import java.util.regex.Pattern;
 29  
 import org.owasp.dependencycheck.Engine;
 30  
 import org.owasp.dependencycheck.analyzer.exception.AnalysisException;
 31  
 import org.owasp.dependencycheck.dependency.Dependency;
 32  
 import org.owasp.dependencycheck.dependency.Evidence;
 33  
 import org.owasp.dependencycheck.exception.InitializationException;
 34  
 import org.owasp.dependencycheck.xml.suppression.PropertyType;
 35  
 import org.owasp.dependencycheck.utils.DownloadFailedException;
 36  
 import org.owasp.dependencycheck.utils.Downloader;
 37  
 import org.owasp.dependencycheck.utils.FileUtils;
 38  
 import org.owasp.dependencycheck.utils.Settings;
 39  
 import org.owasp.dependencycheck.xml.hints.VendorDuplicatingHintRule;
 40  
 import org.owasp.dependencycheck.xml.hints.HintParseException;
 41  
 import org.owasp.dependencycheck.xml.hints.HintParser;
 42  
 import org.owasp.dependencycheck.xml.hints.HintRule;
 43  
 import org.owasp.dependencycheck.xml.hints.Hints;
 44  
 import org.slf4j.Logger;
 45  
 import org.slf4j.LoggerFactory;
 46  
 import org.xml.sax.SAXException;
 47  
 
 48  
 /**
 49  
  * This analyzer adds evidence to dependencies to enhance the accuracy of
 50  
  * library identification.
 51  
  *
 52  
  * @author Jeremy Long
 53  
  */
 54  9
 public class HintAnalyzer extends AbstractAnalyzer implements Analyzer {
 55  
 
 56  
     //<editor-fold defaultstate="collapsed" desc="All standard implementation details of Analyzer">
 57  
     /**
 58  
      * The name of the analyzer.
 59  
      */
 60  
     private static final String ANALYZER_NAME = "Hint Analyzer";
 61  
     /**
 62  
      * The phase that this analyzer is intended to run in.
 63  
      */
 64  1
     private static final AnalysisPhase ANALYSIS_PHASE = AnalysisPhase.PRE_IDENTIFIER_ANALYSIS;
 65  
 
 66  
     /**
 67  
      * Returns the name of the analyzer.
 68  
      *
 69  
      * @return the name of the analyzer.
 70  
      */
 71  
     @Override
 72  
     public String getName() {
 73  17
         return ANALYZER_NAME;
 74  
     }
 75  
 
 76  
     /**
 77  
      * Returns the phase that the analyzer is intended to run in.
 78  
      *
 79  
      * @return the phase that the analyzer is intended to run in.
 80  
      */
 81  
     @Override
 82  
     public AnalysisPhase getAnalysisPhase() {
 83  5
         return ANALYSIS_PHASE;
 84  
     }
 85  
 
 86  
     /**
 87  
      * The initialize method does nothing for this Analyzer.
 88  
      *
 89  
      * @throws InitializationException thrown if there is an exception
 90  
      */
 91  
     @Override
 92  
     public void initialize() throws InitializationException {
 93  
         try {
 94  2
             super.initialize();
 95  2
             loadHintRules();
 96  0
         } catch (HintParseException ex) {
 97  0
             LOGGER.debug("Unable to parse hint file", ex);
 98  0
             throw new InitializationException("Unable to parse the hint file", ex);
 99  2
         }
 100  2
     }
 101  
     //</editor-fold>
 102  
 
 103  
     /**
 104  
      * The Logger for use throughout the class
 105  
      */
 106  1
     private static final Logger LOGGER = LoggerFactory.getLogger(HintAnalyzer.class);
 107  
     /**
 108  
      * The name of the hint rule file
 109  
      */
 110  
     private static final String HINT_RULE_FILE_NAME = "dependencycheck-base-hint.xml";
 111  
     /**
 112  
      * The collection of hints.
 113  
      */
 114  
     private Hints hints;
 115  
 
 116  
     /**
 117  
      * The HintAnalyzer uses knowledge about a dependency to add additional
 118  
      * information to help in identification of identifiers or vulnerabilities.
 119  
      *
 120  
      * @param dependency The dependency being analyzed
 121  
      * @param engine The scanning engine
 122  
      * @throws AnalysisException is thrown if there is an exception analyzing
 123  
      * the dependency.
 124  
      */
 125  
     @Override
 126  
     public void analyze(Dependency dependency, Engine engine) throws AnalysisException {
 127  4
         for (HintRule hint : hints.getHintRules()) {
 128  28
             boolean shouldAdd = false;
 129  28
             for (Evidence given : hint.getGivenVendor()) {
 130  8
                 if (dependency.getVendorEvidence().getEvidence().contains(given)) {
 131  0
                     shouldAdd = true;
 132  0
                     break;
 133  
                 }
 134  8
             }
 135  28
             if (!shouldAdd) {
 136  28
                 for (Evidence given : hint.getGivenProduct()) {
 137  31
                     if (dependency.getProductEvidence().getEvidence().contains(given)) {
 138  1
                         shouldAdd = true;
 139  1
                         break;
 140  
                     }
 141  30
                 }
 142  
             }
 143  28
             if (!shouldAdd) {
 144  27
                 for (PropertyType pt : hint.getFilenames()) {
 145  4
                     if (pt.matches(dependency.getFileName())) {
 146  0
                         shouldAdd = true;
 147  
                     }
 148  4
                 }
 149  
             }
 150  28
             if (shouldAdd) {
 151  1
                 for (Evidence e : hint.getAddVendor()) {
 152  3
                     dependency.getVendorEvidence().addEvidence(e);
 153  3
                 }
 154  1
                 for (Evidence e : hint.getAddProduct()) {
 155  1
                     dependency.getProductEvidence().addEvidence(e);
 156  1
                 }
 157  
             }
 158  28
         }
 159  
 
 160  4
         final Iterator<Evidence> itr = dependency.getVendorEvidence().iterator();
 161  4
         final List<Evidence> newEntries = new ArrayList<Evidence>();
 162  29
         while (itr.hasNext()) {
 163  25
             final Evidence e = itr.next();
 164  25
             for (VendorDuplicatingHintRule dhr : hints.getVendorDuplicatingHintRules()) {
 165  50
                 if (dhr.getValue().equalsIgnoreCase(e.getValue(false))) {
 166  0
                     newEntries.add(new Evidence(e.getSource() + " (hint)",
 167  0
                             e.getName(), dhr.getDuplicate(), e.getConfidence()));
 168  
                 }
 169  50
             }
 170  25
         }
 171  4
         for (Evidence e : newEntries) {
 172  0
             dependency.getVendorEvidence().addEvidence(e);
 173  0
         }
 174  
 
 175  
         //<editor-fold defaultstate="collapsed" desc="Old implementation">
 176  
         /*
 177  
         final Evidence springTest1 = new Evidence("Manifest",
 178  
                 "Implementation-Title",
 179  
                 "Spring Framework",
 180  
                 Confidence.HIGH);
 181  
 
 182  
         final Evidence springTest2 = new Evidence("Manifest",
 183  
                 "Implementation-Title",
 184  
                 "org.springframework.core",
 185  
                 Confidence.HIGH);
 186  
 
 187  
         final Evidence springTest3 = new Evidence("Manifest",
 188  
                 "Implementation-Title",
 189  
                 "spring-core",
 190  
                 Confidence.HIGH);
 191  
 
 192  
         final Evidence springTest4 = new Evidence("jar",
 193  
                 "package name",
 194  
                 "springframework",
 195  
                 Confidence.LOW);
 196  
 
 197  
         final Evidence springSecurityTest1 = new Evidence("Manifest",
 198  
                 "Bundle-Name",
 199  
                 "Spring Security Core",
 200  
                 Confidence.MEDIUM);
 201  
 
 202  
         final Evidence springSecurityTest2 = new Evidence("pom",
 203  
                 "artifactid",
 204  
                 "spring-security-core",
 205  
                 Confidence.HIGH);
 206  
 
 207  
         final Evidence symfony = new Evidence("composer.lock",
 208  
             "vendor",
 209  
             "symfony",
 210  
             Confidence.HIGHEST);
 211  
 
 212  
         final Evidence zendframeworkVendor = new Evidence("composer.lock",
 213  
             "vendor",
 214  
             "zendframework",
 215  
             Confidence.HIGHEST);
 216  
 
 217  
         final Evidence zendframeworkProduct = new Evidence("composer.lock",
 218  
             "product",
 219  
             "zendframework",
 220  
             Confidence.HIGHEST);
 221  
 
 222  
         //springsource/vware problem
 223  
         final Set<Evidence> product = dependency.getProductEvidence().getEvidence();
 224  
         final Set<Evidence> vendor = dependency.getVendorEvidence().getEvidence();
 225  
 
 226  
         if (product.contains(springTest1) || product.contains(springTest2) || product.contains(springTest3)
 227  
                 || (dependency.getFileName().contains("spring") && product.contains(springTest4))) {
 228  
             dependency.getProductEvidence().addEvidence("hint analyzer", "product", "springsource spring framework", Confidence.HIGH);
 229  
             dependency.getVendorEvidence().addEvidence("hint analyzer", "vendor", "SpringSource", Confidence.HIGH);
 230  
             dependency.getVendorEvidence().addEvidence("hint analyzer", "vendor", "vmware", Confidence.HIGH);
 231  
             dependency.getVendorEvidence().addEvidence("hint analyzer", "vendor", "pivotal", Confidence.HIGH);
 232  
         }
 233  
 
 234  
         if (vendor.contains(springTest4)) {
 235  
             dependency.getProductEvidence().addEvidence("hint analyzer", "product", "springsource_spring_framework", Confidence.HIGH);
 236  
             dependency.getVendorEvidence().addEvidence("hint analyzer", "vendor", "vmware", Confidence.HIGH);
 237  
             dependency.getVendorEvidence().addEvidence("hint analyzer", "vendor", "pivotal", Confidence.HIGH);
 238  
         }
 239  
 
 240  
         if (product.contains(springSecurityTest1) || product.contains(springSecurityTest2)) {
 241  
             dependency.getProductEvidence().addEvidence("hint analyzer", "product", "springsource_spring_security", Confidence.HIGH);
 242  
             dependency.getVendorEvidence().addEvidence("hint analyzer", "vendor", "SpringSource", Confidence.HIGH);
 243  
             dependency.getVendorEvidence().addEvidence("hint analyzer", "vendor", "vmware", Confidence.HIGH);
 244  
         }
 245  
 
 246  
         if (vendor.contains(symfony)) {
 247  
             dependency.getVendorEvidence().addEvidence("hint analyzer", "vendor", "sensiolabs", Confidence.HIGHEST);
 248  
         }
 249  
 
 250  
         if (vendor.contains(zendframeworkVendor)) {
 251  
             dependency.getVendorEvidence().addEvidence("hint analyzer", "vendor", "zend", Confidence.HIGHEST);
 252  
         }
 253  
 
 254  
         if (product.contains(zendframeworkProduct)) {
 255  
             dependency.getProductEvidence().addEvidence("hint analyzer", "vendor", "zend_framework", Confidence.HIGHEST);
 256  
         }
 257  
 
 258  
         //sun/oracle problem
 259  
         final Iterator<Evidence> itr = dependency.getVendorEvidence().iterator();
 260  
         final List<Evidence> newEntries = new ArrayList<Evidence>();
 261  
         while (itr.hasNext()) {
 262  
             final Evidence e = itr.next();
 263  
             if ("sun".equalsIgnoreCase(e.getValue(false))) {
 264  
                 final Evidence newEvidence = new Evidence(e.getSource() + " (hint)", e.getName(), "oracle", e.getConfidence());
 265  
                 newEntries.add(newEvidence);
 266  
             } else if ("oracle".equalsIgnoreCase(e.getValue(false))) {
 267  
                 final Evidence newEvidence = new Evidence(e.getSource() + " (hint)", e.getName(), "sun", e.getConfidence());
 268  
                 newEntries.add(newEvidence);
 269  
             }
 270  
         }
 271  
         for (Evidence e : newEntries) {
 272  
             dependency.getVendorEvidence().addEvidence(e);
 273  
         }
 274  
          */
 275  
         //</editor-fold>
 276  4
     }
 277  
 
 278  
     /**
 279  
      * Loads the hint rules file.
 280  
      *
 281  
      * @throws HintParseException thrown if the XML cannot be parsed.
 282  
      */
 283  
     private void loadHintRules() throws HintParseException {
 284  2
         final HintParser parser = new HintParser();
 285  2
         File file = null;
 286  
         try {
 287  2
             hints = parser.parseHints(this.getClass().getClassLoader().getResourceAsStream(HINT_RULE_FILE_NAME));
 288  0
         } catch (HintParseException ex) {
 289  0
             LOGGER.error("Unable to parse the base hint data file");
 290  0
             LOGGER.debug("Unable to parse the base hint data file", ex);
 291  0
         } catch (SAXException ex) {
 292  0
             LOGGER.error("Unable to parse the base hint data file");
 293  0
             LOGGER.debug("Unable to parse the base hint data file", ex);
 294  2
         }
 295  2
         final String filePath = Settings.getString(Settings.KEYS.HINTS_FILE);
 296  2
         if (filePath == null) {
 297  2
             return;
 298  
         }
 299  0
         boolean deleteTempFile = false;
 300  
         try {
 301  0
             final Pattern uriRx = Pattern.compile("^(https?|file)\\:.*", Pattern.CASE_INSENSITIVE);
 302  0
             if (uriRx.matcher(filePath).matches()) {
 303  0
                 deleteTempFile = true;
 304  0
                 file = FileUtils.getTempFile("hint", "xml");
 305  0
                 final URL url = new URL(filePath);
 306  
                 try {
 307  0
                     Downloader.fetchFile(url, file, false);
 308  0
                 } catch (DownloadFailedException ex) {
 309  0
                     Downloader.fetchFile(url, file, true);
 310  0
                 }
 311  0
             } else {
 312  0
                 file = new File(filePath);
 313  0
                 if (!file.exists()) {
 314  0
                     final InputStream fromClasspath = this.getClass().getClassLoader().getResourceAsStream(filePath);
 315  0
                     if (fromClasspath != null) {
 316  0
                         deleteTempFile = true;
 317  0
                         file = FileUtils.getTempFile("hint", "xml");
 318  
                         try {
 319  0
                             org.apache.commons.io.FileUtils.copyInputStreamToFile(fromClasspath, file);
 320  0
                         } catch (IOException ex) {
 321  0
                             throw new HintParseException("Unable to locate suppressions file in classpath", ex);
 322  0
                         }
 323  
                     }
 324  
                 }
 325  
             }
 326  
 
 327  0
             if (file != null) {
 328  
                 try {
 329  0
                     final Hints newHints = parser.parseHints(file);
 330  0
                     hints.getHintRules().addAll(newHints.getHintRules());
 331  0
                     hints.getVendorDuplicatingHintRules().addAll(newHints.getVendorDuplicatingHintRules());
 332  0
                     LOGGER.debug("{} hint rules were loaded.", hints.getHintRules().size());
 333  0
                     LOGGER.debug("{} duplicating hint rules were loaded.", hints.getVendorDuplicatingHintRules().size());
 334  0
                 } catch (HintParseException ex) {
 335  0
                     LOGGER.warn("Unable to parse hint rule xml file '{}'", file.getPath());
 336  0
                     LOGGER.warn(ex.getMessage());
 337  0
                     LOGGER.debug("", ex);
 338  0
                     throw ex;
 339  0
                 }
 340  
             }
 341  0
         } catch (DownloadFailedException ex) {
 342  0
             throw new HintParseException("Unable to fetch the configured hint file", ex);
 343  0
         } catch (MalformedURLException ex) {
 344  0
             throw new HintParseException("Configured hint file has an invalid URL", ex);
 345  0
         } catch (IOException ex) {
 346  0
             throw new HintParseException("Unable to create temp file for hints", ex);
 347  
         } finally {
 348  0
             if (deleteTempFile && file != null) {
 349  0
                 FileUtils.delete(file);
 350  
             }
 351  
         }
 352  0
     }
 353  
 }