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