Coverage Report - org.owasp.dependencycheck.analyzer.NexusAnalyzer
 
Classes in this File Line Coverage Branch Coverage Complexity
NexusAnalyzer
20%
14/70
4%
1/24
3.375
 
 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) 2014 Jeremy Long. All Rights Reserved.
 17  
  */
 18  
 package org.owasp.dependencycheck.analyzer;
 19  
 
 20  
 import java.io.File;
 21  
 import java.io.FileNotFoundException;
 22  
 import java.io.IOException;
 23  
 import java.net.MalformedURLException;
 24  
 import java.net.URL;
 25  
 import java.util.Set;
 26  
 import java.util.logging.Level;
 27  
 import java.util.logging.Logger;
 28  
 import org.apache.commons.io.FileUtils;
 29  
 import org.owasp.dependencycheck.Engine;
 30  
 import org.owasp.dependencycheck.analyzer.exception.AnalysisException;
 31  
 import org.owasp.dependencycheck.data.nexus.MavenArtifact;
 32  
 import org.owasp.dependencycheck.data.nexus.NexusSearch;
 33  
 import org.owasp.dependencycheck.dependency.Confidence;
 34  
 import org.owasp.dependencycheck.dependency.Dependency;
 35  
 import org.owasp.dependencycheck.dependency.Evidence;
 36  
 import org.owasp.dependencycheck.jaxb.pom.PomUtils;
 37  
 import org.owasp.dependencycheck.utils.InvalidSettingException;
 38  
 import org.owasp.dependencycheck.utils.DownloadFailedException;
 39  
 import org.owasp.dependencycheck.utils.Downloader;
 40  
 import org.owasp.dependencycheck.utils.Settings;
 41  
 
 42  
 /**
 43  
  * Analyzer which will attempt to locate a dependency on a Nexus service by SHA-1 digest of the dependency.
 44  
  *
 45  
  * There are two settings which govern this behavior:
 46  
  *
 47  
  * <ul>
 48  
  * <li>{@link org.owasp.dependencycheck.utils.Settings.KEYS#ANALYZER_NEXUS_ENABLED} determines whether this analyzer is
 49  
  * even enabled. This can be overridden by setting the system property.</li>
 50  
  * <li>{@link org.owasp.dependencycheck.utils.Settings.KEYS#ANALYZER_NEXUS_URL} the URL to a Nexus service to search by
 51  
  * SHA-1. There is an expected <code>%s</code> in this where the SHA-1 will get entered.</li>
 52  
  * </ul>
 53  
  *
 54  
  * @author colezlaw
 55  
  */
 56  2
 public class NexusAnalyzer extends AbstractFileTypeAnalyzer {
 57  
 
 58  
     /**
 59  
      * The default URL - this will be used by the CentralAnalyzer to determine whether to enable this.
 60  
      */
 61  
     public static final String DEFAULT_URL = "https://repository.sonatype.org/service/local/";
 62  
 
 63  
     /**
 64  
      * The logger.
 65  
      */
 66  1
     private static final Logger LOGGER = Logger.getLogger(NexusAnalyzer.class.getName());
 67  
 
 68  
     /**
 69  
      * The name of the analyzer.
 70  
      */
 71  
     private static final String ANALYZER_NAME = "Nexus Analyzer";
 72  
 
 73  
     /**
 74  
      * The phase in which the analyzer runs.
 75  
      */
 76  1
     private static final AnalysisPhase ANALYSIS_PHASE = AnalysisPhase.INFORMATION_COLLECTION;
 77  
 
 78  
     /**
 79  
      * The types of files on which this will work.
 80  
      */
 81  1
     private static final Set<String> SUPPORTED_EXTENSIONS = newHashSet("jar");
 82  
 
 83  
     /**
 84  
      * The Nexus Search to be set up for this analyzer.
 85  
      */
 86  
     private NexusSearch searcher;
 87  
 
 88  
     /**
 89  
      * Field indicating if the analyzer is enabled.
 90  
      */
 91  2
     private final boolean enabled = checkEnabled();
 92  
     /**
 93  
      * Field for doing POM work
 94  
      */
 95  2
     private final PomUtils pomUtil = new PomUtils();
 96  
 
 97  
     /**
 98  
      * Determines if this analyzer is enabled
 99  
      *
 100  
      * @return <code>true</code> if the analyzer is enabled; otherwise <code>false</code>
 101  
      */
 102  
     private boolean checkEnabled() {
 103  
         /* Enable this analyzer ONLY if the Nexus URL has been set to something
 104  
          other than the default one (if it's the default one, we'll use the
 105  
          central one) and it's enabled by the user.
 106  
          */
 107  2
         boolean retval = false;
 108  
         try {
 109  2
             if ((!DEFAULT_URL.equals(Settings.getString(Settings.KEYS.ANALYZER_NEXUS_URL)))
 110  
                     && Settings.getBoolean(Settings.KEYS.ANALYZER_NEXUS_ENABLED)) {
 111  0
                 LOGGER.info("Enabling Nexus analyzer");
 112  0
                 retval = true;
 113  
             } else {
 114  2
                 LOGGER.fine("Nexus analyzer disabled, using Central instead");
 115  
             }
 116  0
         } catch (InvalidSettingException ise) {
 117  0
             LOGGER.warning("Invalid setting. Disabling Nexus analyzer");
 118  2
         }
 119  
 
 120  2
         return retval;
 121  
     }
 122  
 
 123  
     /**
 124  
      * Determine whether to enable this analyzer or not.
 125  
      *
 126  
      * @return whether the analyzer should be enabled
 127  
      */
 128  
     @Override
 129  
     public boolean isEnabled() {
 130  0
         return enabled;
 131  
     }
 132  
 
 133  
     /**
 134  
      * Initializes the analyzer once before any analysis is performed.
 135  
      *
 136  
      * @throws Exception if there's an error during initialization
 137  
      */
 138  
     @Override
 139  
     public void initializeFileTypeAnalyzer() throws Exception {
 140  0
         LOGGER.fine("Initializing Nexus Analyzer");
 141  0
         LOGGER.fine(String.format("Nexus Analyzer enabled: %s", isEnabled()));
 142  0
         if (isEnabled()) {
 143  0
             final String searchUrl = Settings.getString(Settings.KEYS.ANALYZER_NEXUS_URL);
 144  0
             LOGGER.fine(String.format("Nexus Analyzer URL: %s", searchUrl));
 145  
             try {
 146  0
                 searcher = new NexusSearch(new URL(searchUrl));
 147  0
                 if (!searcher.preflightRequest()) {
 148  0
                     LOGGER.warning("There was an issue getting Nexus status. Disabling analyzer.");
 149  0
                     setEnabled(false);
 150  
                 }
 151  0
             } catch (MalformedURLException mue) {
 152  
                 // I know that initialize can throw an exception, but we'll
 153  
                 // just disable the analyzer if the URL isn't valid
 154  0
                 LOGGER.warning(String.format("Property %s not a valid URL. Nexus Analyzer disabled", searchUrl));
 155  0
                 setEnabled(false);
 156  0
             }
 157  
         }
 158  0
     }
 159  
 
 160  
     /**
 161  
      * Returns the analyzer's name.
 162  
      *
 163  
      * @return the name of the analyzer
 164  
      */
 165  
     @Override
 166  
     public String getName() {
 167  4
         return ANALYZER_NAME;
 168  
     }
 169  
 
 170  
     /**
 171  
      * Returns the key used in the properties file to reference the analyzer's enabled property.
 172  
      *
 173  
      * @return the analyzer's enabled property setting key
 174  
      */
 175  
     @Override
 176  
     protected String getAnalyzerEnabledSettingKey() {
 177  2
         return Settings.KEYS.ANALYZER_NEXUS_ENABLED;
 178  
     }
 179  
 
 180  
     /**
 181  
      * Returns the analysis phase under which the analyzer runs.
 182  
      *
 183  
      * @return the phase under which this analyzer runs
 184  
      */
 185  
     @Override
 186  
     public AnalysisPhase getAnalysisPhase() {
 187  1
         return ANALYSIS_PHASE;
 188  
     }
 189  
 
 190  
     /**
 191  
      * Returns the extensions for which this Analyzer runs.
 192  
      *
 193  
      * @return the extensions for which this Analyzer runs
 194  
      */
 195  
     @Override
 196  
     public Set<String> getSupportedExtensions() {
 197  0
         return SUPPORTED_EXTENSIONS;
 198  
     }
 199  
 
 200  
     /**
 201  
      * Performs the analysis.
 202  
      *
 203  
      * @param dependency the dependency to analyze
 204  
      * @param engine the engine
 205  
      * @throws AnalysisException when there's an exception during analysis
 206  
      */
 207  
     @Override
 208  
     public void analyzeFileType(Dependency dependency, Engine engine) throws AnalysisException {
 209  0
         if (!isEnabled()) {
 210  0
             return;
 211  
         }
 212  
         try {
 213  0
             final MavenArtifact ma = searcher.searchSha1(dependency.getSha1sum());
 214  0
             dependency.addAsEvidence("nexus", ma, Confidence.HIGH);
 215  0
             boolean pomAnalyzed = false;
 216  0
             LOGGER.fine("POM URL " + ma.getPomUrl());
 217  0
             for (Evidence e : dependency.getVendorEvidence()) {
 218  0
                 if ("pom".equals(e.getSource())) {
 219  0
                     pomAnalyzed = true;
 220  0
                     break;
 221  
                 }
 222  0
             }
 223  0
             if (!pomAnalyzed && ma.getPomUrl() != null) {
 224  0
                 File pomFile = null;
 225  
                 try {
 226  0
                     final File baseDir = Settings.getTempDirectory();
 227  0
                     pomFile = File.createTempFile("pom", ".xml", baseDir);
 228  0
                     if (!pomFile.delete()) {
 229  0
                         final String msg = String.format("Unable to fetch pom.xml for %s from Nexus repository; "
 230  
                                 + "this could result in undetected CPE/CVEs.", dependency.getFileName());
 231  0
                         LOGGER.warning(msg);
 232  0
                         LOGGER.fine("Unable to delete temp file");
 233  
                     }
 234  0
                     LOGGER.fine(String.format("Downloading %s", ma.getPomUrl()));
 235  0
                     Downloader.fetchFile(new URL(ma.getPomUrl()), pomFile);
 236  0
                     pomUtil.analyzePOM(dependency, pomFile);
 237  0
                 } catch (DownloadFailedException ex) {
 238  0
                     final String msg = String.format("Unable to download pom.xml for %s from Nexus repository; "
 239  
                             + "this could result in undetected CPE/CVEs.", dependency.getFileName());
 240  0
                     LOGGER.warning(msg);
 241  
                 } finally {
 242  0
                     if (pomFile != null && !FileUtils.deleteQuietly(pomFile)) {
 243  0
                         pomFile.deleteOnExit();
 244  
                     }
 245  
                 }
 246  
             }
 247  0
         } catch (IllegalArgumentException iae) {
 248  
             //dependency.addAnalysisException(new AnalysisException("Invalid SHA-1"));
 249  0
             LOGGER.info(String.format("invalid sha-1 hash on %s", dependency.getFileName()));
 250  0
         } catch (FileNotFoundException fnfe) {
 251  
             //dependency.addAnalysisException(new AnalysisException("Artifact not found on repository"));
 252  0
             LOGGER.fine(String.format("Artifact not found in repository '%s'", dependency.getFileName()));
 253  0
             LOGGER.log(Level.FINE, fnfe.getMessage(), fnfe);
 254  0
         } catch (IOException ioe) {
 255  
             //dependency.addAnalysisException(new AnalysisException("Could not connect to repository", ioe));
 256  0
             LOGGER.log(Level.FINE, "Could not connect to nexus repository", ioe);
 257  0
         }
 258  0
     }
 259  
 }