Coverage Report - org.owasp.dependencycheck.analyzer.AssemblyAnalyzer
 
Classes in this File Line Coverage Branch Coverage Complexity
AssemblyAnalyzer
69%
64/92
46%
15/32
4.75
 
 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.FileOutputStream;
 22  
 import java.io.IOException;
 23  
 import java.io.InputStream;
 24  
 import java.util.ArrayList;
 25  
 import java.util.List;
 26  
 import java.util.Set;
 27  
 import java.util.logging.Level;
 28  
 import java.util.logging.Logger;
 29  
 import javax.xml.parsers.DocumentBuilder;
 30  
 import javax.xml.parsers.DocumentBuilderFactory;
 31  
 import javax.xml.xpath.XPath;
 32  
 import javax.xml.xpath.XPathExpressionException;
 33  
 import javax.xml.xpath.XPathFactory;
 34  
 import org.owasp.dependencycheck.Engine;
 35  
 import org.owasp.dependencycheck.analyzer.exception.AnalysisException;
 36  
 import org.owasp.dependencycheck.dependency.Confidence;
 37  
 import org.owasp.dependencycheck.dependency.Dependency;
 38  
 import org.owasp.dependencycheck.dependency.Evidence;
 39  
 import org.owasp.dependencycheck.utils.Settings;
 40  
 import org.w3c.dom.Document;
 41  
 import org.xml.sax.SAXException;
 42  
 
 43  
 /**
 44  
  * Analyzer for getting company, product, and version information from a .NET assembly.
 45  
  *
 46  
  * @author colezlaw
 47  
  *
 48  
  */
 49  
 public class AssemblyAnalyzer extends AbstractAnalyzer {
 50  
 
 51  
     /**
 52  
      * The analyzer name
 53  
      */
 54  
     private static final String ANALYZER_NAME = "Assembly Analyzer";
 55  
     /**
 56  
      * The analysis phase
 57  
      */
 58  1
     private static final AnalysisPhase ANALYSIS_PHASE = AnalysisPhase.INFORMATION_COLLECTION;
 59  
     /**
 60  
      * The list of supported extensions
 61  
      */
 62  1
     private static final Set<String> SUPORTED_EXTENSIONS = newHashSet("dll", "exe");
 63  
     /**
 64  
      * The temp value for GrokAssembly.exe
 65  
      */
 66  
     private File grokAssemblyExe;
 67  
     /**
 68  
      * The DocumentBuilder for parsing the XML
 69  
      */
 70  
     private DocumentBuilder builder;
 71  
     /**
 72  
      * Logger
 73  
      */
 74  1
     private static final Logger LOG = Logger.getLogger(AbstractAnalyzer.class.getName());
 75  
 
 76  
     /**
 77  
      * Builds the beginnings of a List for ProcessBuilder
 78  
      *
 79  
      * @return the list of arguments to begin populating the ProcessBuilder
 80  
      */
 81  
     private List<String> buildArgumentList() {
 82  
         // Use file.separator as a wild guess as to whether this is Windows
 83  11
         final List<String> args = new ArrayList<String>();
 84  11
         if (!"\\".equals(System.getProperty("file.separator"))) {
 85  0
             if (Settings.getString(Settings.KEYS.ANALYZER_ASSEMBLY_MONO_PATH) != null) {
 86  0
                 args.add(Settings.getString(Settings.KEYS.ANALYZER_ASSEMBLY_MONO_PATH));
 87  
             } else {
 88  0
                 args.add("mono");
 89  
             }
 90  
         }
 91  11
         args.add(grokAssemblyExe.getPath());
 92  
 
 93  11
         return args;
 94  
     }
 95  
 
 96  
     /**
 97  
      * Performs the analysis on a single Dependency.
 98  
      *
 99  
      * @param dependency the dependency to analyze
 100  
      * @param engine the engine to perform the analysis under
 101  
      * @throws AnalysisException if anything goes sideways
 102  
      */
 103  
     @Override
 104  
     public void analyze(Dependency dependency, Engine engine)
 105  
             throws AnalysisException {
 106  3
         if (grokAssemblyExe == null) {
 107  0
             LOG.warning("GrokAssembly didn't get deployed");
 108  0
             return;
 109  
         }
 110  
 
 111  3
         final List<String> args = buildArgumentList();
 112  3
         args.add(dependency.getActualFilePath());
 113  3
         final ProcessBuilder pb = new ProcessBuilder(args);
 114  
         try {
 115  3
             final Process proc = pb.start();
 116  3
             final Document doc = builder.parse(proc.getInputStream());
 117  3
             final XPath xpath = XPathFactory.newInstance().newXPath();
 118  
 
 119  
             // First, see if there was an error
 120  3
             final String error = xpath.evaluate("/assembly/error", doc);
 121  3
             if (error != null && !"".equals(error)) {
 122  1
                 throw new AnalysisException(error);
 123  
             }
 124  
 
 125  2
             final String version = xpath.evaluate("/assembly/version", doc);
 126  2
             if (version != null) {
 127  2
                 dependency.getVersionEvidence().addEvidence(new Evidence("grokassembly", "version",
 128  
                         version, Confidence.HIGHEST));
 129  
             }
 130  
 
 131  2
             final String vendor = xpath.evaluate("/assembly/company", doc);
 132  2
             if (vendor != null) {
 133  2
                 dependency.getVendorEvidence().addEvidence(new Evidence("grokassembly", "vendor",
 134  
                         vendor, Confidence.HIGH));
 135  
             }
 136  
 
 137  2
             final String product = xpath.evaluate("/assembly/product", doc);
 138  2
             if (product != null) {
 139  2
                 dependency.getProductEvidence().addEvidence(new Evidence("grokassembly", "product",
 140  
                         product, Confidence.HIGH));
 141  
             }
 142  
 
 143  0
         } catch (IOException ioe) {
 144  0
             throw new AnalysisException(ioe);
 145  0
         } catch (SAXException saxe) {
 146  0
             throw new AnalysisException("Couldn't parse GrokAssembly result", saxe);
 147  0
         } catch (XPathExpressionException xpe) {
 148  
             // This shouldn't happen
 149  0
             throw new AnalysisException(xpe);
 150  2
         }
 151  2
     }
 152  
 
 153  
     /**
 154  
      * Initialize the analyzer. In this case, extract GrokAssembly.exe to a temporary location.
 155  
      *
 156  
      * @throws Exception if anything goes wrong
 157  
      */
 158  
     @Override
 159  
     public void initialize() throws Exception {
 160  8
         super.initialize();
 161  8
         final File tempFile = File.createTempFile("GKA", ".exe");
 162  8
         FileOutputStream fos = null;
 163  8
         InputStream is = null;
 164  
         try {
 165  8
             fos = new FileOutputStream(tempFile);
 166  8
             is = AssemblyAnalyzer.class.getClassLoader().getResourceAsStream("GrokAssembly.exe");
 167  8
             final byte[] buff = new byte[4096];
 168  8
             int bread = -1;
 169  24
             while ((bread = is.read(buff)) >= 0) {
 170  16
                 fos.write(buff, 0, bread);
 171  
             }
 172  8
             grokAssemblyExe = tempFile;
 173  
             // Set the temp file to get deleted when we're done
 174  8
             grokAssemblyExe.deleteOnExit();
 175  8
             LOG.log(Level.FINE, "Extracted GrokAssembly.exe to {0}", grokAssemblyExe.getPath());
 176  0
         } catch (IOException ioe) {
 177  0
             LOG.log(Level.WARNING, "Could not extract GrokAssembly.exe: {0}", ioe.getMessage());
 178  0
             throw new AnalysisException("Could not extract GrokAssembly.exe", ioe);
 179  
         } finally {
 180  8
             if (fos != null) {
 181  
                 try {
 182  8
                     fos.close();
 183  0
                 } catch (Throwable e) {
 184  0
                     LOG.fine("Error closing output stream");
 185  8
                 }
 186  
             }
 187  8
             if (is != null) {
 188  
                 try {
 189  8
                     is.close();
 190  0
                 } catch (Throwable e) {
 191  0
                     LOG.fine("Error closing input stream");
 192  8
                 }
 193  
             }
 194  
         }
 195  
 
 196  
         // Now, need to see if GrokAssembly actually runs from this location.
 197  8
         final List<String> args = buildArgumentList();
 198  
         try {
 199  8
             final Process p = new ProcessBuilder(args).start();
 200  8
             final Document doc = DocumentBuilderFactory.newInstance().newDocumentBuilder().parse(p.getInputStream());
 201  8
             final XPath xpath = XPathFactory.newInstance().newXPath();
 202  8
             final String error = xpath.evaluate("/assembly/error", doc);
 203  8
             if (p.waitFor() != 1 || error == null || "".equals(error)) {
 204  0
                 LOG.warning("An error occured with the .NET AssemblyAnalyzer, please see the log for more details.");
 205  0
                 LOG.fine("GrokAssembly.exe is not working properly");
 206  0
                 grokAssemblyExe = null;
 207  0
                 throw new AnalysisException("Could not execute .NET AssemblyAnalyzer");
 208  
             }
 209  0
         } catch (Throwable e) {
 210  0
             LOG.warning("An error occured with the .NET AssemblyAnalyzer; "
 211  
                     + "this can be ignored unless you are scanning .NET dlls. Please see the log for more details.");
 212  0
             LOG.log(Level.FINE, "Could not execute GrokAssembly {0}", e.getMessage());
 213  0
             throw new AnalysisException("An error occured with the .NET AssemblyAnalyzer", e);
 214  8
         }
 215  
 
 216  8
         builder = DocumentBuilderFactory.newInstance().newDocumentBuilder();
 217  8
     }
 218  
 
 219  
     @Override
 220  
     public void close() throws Exception {
 221  8
         super.close();
 222  
         try {
 223  8
             grokAssemblyExe.delete();
 224  0
         } catch (SecurityException se) {
 225  0
             LOG.fine("Can't delete temporary GrokAssembly.exe");
 226  8
         }
 227  8
     }
 228  
 
 229  
     /**
 230  
      * Gets the set of extensions supported by this analyzer.
 231  
      *
 232  
      * @return the list of supported extensions
 233  
      */
 234  
     @Override
 235  
     public Set<String> getSupportedExtensions() {
 236  138
         return SUPORTED_EXTENSIONS;
 237  
     }
 238  
 
 239  
     /**
 240  
      * Gets this analyzer's name.
 241  
      *
 242  
      * @return the analyzer name
 243  
      */
 244  
     @Override
 245  
     public String getName() {
 246  10
         return ANALYZER_NAME;
 247  
     }
 248  
 
 249  
     /**
 250  
      * Gets whether the analyzer supports the provided extension.
 251  
      *
 252  
      * @param extension the extension to check
 253  
      * @return whether the analyzer supports the extension
 254  
      */
 255  
     @Override
 256  
     public boolean supportsExtension(String extension) {
 257  134
         return SUPORTED_EXTENSIONS.contains(extension);
 258  
     }
 259  
 
 260  
     /**
 261  
      * Returns the phase this analyzer runs under.
 262  
      *
 263  
      * @return the phase this runs under
 264  
      */
 265  
     @Override
 266  
     public AnalysisPhase getAnalysisPhase() {
 267  6
         return ANALYSIS_PHASE;
 268  
     }
 269  
 }