diff --git a/dependency-check-core/src/main/java/org/owasp/dependencycheck/analyzer/FileNameAnalyzer.java b/dependency-check-core/src/main/java/org/owasp/dependencycheck/analyzer/FileNameAnalyzer.java index d21f7b503..00bb66027 100644 --- a/dependency-check-core/src/main/java/org/owasp/dependencycheck/analyzer/FileNameAnalyzer.java +++ b/dependency-check-core/src/main/java/org/owasp/dependencycheck/analyzer/FileNameAnalyzer.java @@ -97,16 +97,16 @@ public class FileNameAnalyzer extends AbstractAnalyzer implements Analyzer { } //add as vendor and product evidence - if (fileName.contains("-")) { - dependency.getProductEvidence().addEvidence("file", "name", - fileName, Confidence.HIGHEST); - dependency.getVendorEvidence().addEvidence("file", "name", - fileName, Confidence.HIGHEST); - } else { +// if (fileName.contains("-")) { +// dependency.getProductEvidence().addEvidence("file", "name", +// fileName, Confidence.HIGHEST); +// dependency.getVendorEvidence().addEvidence("file", "name", +// fileName, Confidence.HIGHEST); +// } else { dependency.getProductEvidence().addEvidence("file", "name", fileName, Confidence.HIGH); dependency.getVendorEvidence().addEvidence("file", "name", fileName, Confidence.HIGH); - } +// } } } diff --git a/dependency-check-core/src/main/java/org/owasp/dependencycheck/analyzer/RubyBundleAuditAnalyzer.java b/dependency-check-core/src/main/java/org/owasp/dependencycheck/analyzer/RubyBundleAuditAnalyzer.java index a78838c11..b007d7220 100644 --- a/dependency-check-core/src/main/java/org/owasp/dependencycheck/analyzer/RubyBundleAuditAnalyzer.java +++ b/dependency-check-core/src/main/java/org/owasp/dependencycheck/analyzer/RubyBundleAuditAnalyzer.java @@ -181,21 +181,21 @@ public class RubyBundleAuditAnalyzer extends AbstractFileTypeAnalyzer { @Override protected void analyzeFileType(Dependency dependency, Engine engine) throws AnalysisException { - if (needToDisableGemspecAnalyzer) { - boolean failed = true; - final String className = RubyGemspecAnalyzer.class.getName(); - for (FileTypeAnalyzer analyzer : engine.getFileTypeAnalyzers()) { - if (analyzer instanceof RubyGemspecAnalyzer) { - ((RubyGemspecAnalyzer) analyzer).setEnabled(false); - LOGGER.info("Disabled " + className + " to avoid noisy duplicate results."); - failed = false; - } - } - if (failed) { - LOGGER.warn("Did not find" + className + '.'); - } - needToDisableGemspecAnalyzer = false; - } +// if (needToDisableGemspecAnalyzer) { +// boolean failed = true; +// final String className = RubyGemspecAnalyzer.class.getName(); +// for (FileTypeAnalyzer analyzer : engine.getFileTypeAnalyzers()) { +// if (analyzer instanceof RubyGemspecAnalyzer) { +// ((RubyGemspecAnalyzer) analyzer).setEnabled(false); +// LOGGER.info("Disabled " + className + " to avoid noisy duplicate results."); +// failed = false; +// } +// } +// if (failed) { +// LOGGER.warn("Did not find" + className + '.'); +// } +// needToDisableGemspecAnalyzer = false; +// } final File parentFile = dependency.getActualFile().getParentFile(); final Process process = launchBundleAudit(parentFile); try { @@ -229,6 +229,7 @@ public class RubyBundleAuditAnalyzer extends AbstractFileTypeAnalyzer { private void processBundlerAuditOutput(Dependency original, Engine engine, BufferedReader rdr) throws IOException { final String parentName = original.getActualFile().getParentFile().getName(); final String fileName = original.getFileName(); + final String filePath = original.getFilePath(); Dependency dependency = null; Vulnerability vulnerability = null; String gem = null; @@ -242,7 +243,7 @@ public class RubyBundleAuditAnalyzer extends AbstractFileTypeAnalyzer { appendToDescription = false; gem = nextLine.substring(NAME.length()); if (!map.containsKey(gem)) { - map.put(gem, createDependencyForGem(engine, parentName, fileName, gem)); + map.put(gem, createDependencyForGem(engine, parentName, fileName, filePath, gem)); } dependency = map.get(gem); LOGGER.debug(String.format("bundle-audit (%s): %s", parentName, nextLine)); @@ -329,13 +330,16 @@ public class RubyBundleAuditAnalyzer extends AbstractFileTypeAnalyzer { return vulnerability; } - private Dependency createDependencyForGem(Engine engine, String parentName, String fileName, String gem) throws IOException { - final File tempFile = File.createTempFile("Gemfile-" + gem, ".lock", Settings.getTempDirectory()); + private Dependency createDependencyForGem(Engine engine, String parentName, String fileName, String filePath, String gem) throws IOException { + final File gemFile = new File(Settings.getTempDirectory(), gem + "_Gemfile.lock"); + gemFile.createNewFile(); final String displayFileName = String.format("%s%c%s:%s", parentName, File.separatorChar, fileName, gem); - FileUtils.write(tempFile, displayFileName); // unique contents to avoid dependency bundling - final Dependency dependency = new Dependency(tempFile); + FileUtils.write(gemFile, displayFileName); // unique contents to avoid dependency bundling + final Dependency dependency = new Dependency(gemFile); dependency.getProductEvidence().addEvidence("bundler-audit", "Name", gem, Confidence.HIGHEST); dependency.setDisplayFileName(displayFileName); + dependency.setFileName(fileName); + dependency.setFilePath(filePath); engine.getDependencies().add(dependency); return dependency; } diff --git a/dependency-check-core/src/main/java/org/owasp/dependencycheck/analyzer/RubyGemspecAnalyzer.java b/dependency-check-core/src/main/java/org/owasp/dependencycheck/analyzer/RubyGemspecAnalyzer.java index 3b5fe9dbe..4ab52cf52 100644 --- a/dependency-check-core/src/main/java/org/owasp/dependencycheck/analyzer/RubyGemspecAnalyzer.java +++ b/dependency-check-core/src/main/java/org/owasp/dependencycheck/analyzer/RubyGemspecAnalyzer.java @@ -26,8 +26,14 @@ import org.owasp.dependencycheck.dependency.EvidenceCollection; import org.owasp.dependencycheck.utils.FileFilterBuilder; import org.owasp.dependencycheck.utils.Settings; +import java.io.BufferedReader; +import java.io.File; import java.io.FileFilter; +import java.io.FileNotFoundException; +import java.io.FileReader; +import java.io.FilenameFilter; import java.io.IOException; +import java.util.List; import java.util.regex.Matcher; import java.util.regex.Pattern; @@ -52,10 +58,12 @@ public class RubyGemspecAnalyzer extends AbstractFileTypeAnalyzer { private static final String GEMSPEC = "gemspec"; private static final FileFilter FILTER - = FileFilterBuilder.newInstance().addExtensions(GEMSPEC).addFilenames("Rakefile").build(); + = FileFilterBuilder.newInstance().addExtensions(GEMSPEC).build(); private static final String EMAIL = "email"; + private static final String VERSION_FILE_NAME = "VERSION"; + /** * @return a filter that accepts files named Rakefile or matching the glob pattern, *.gemspec */ @@ -133,7 +141,9 @@ public class RubyGemspecAnalyzer extends AbstractFileTypeAnalyzer { vendor.addEvidence(GEMSPEC, "name_project", name + "_project", Confidence.LOW); } addStringEvidence(product, contents, blockVariable, "summary", Confidence.LOW); - addStringEvidence(dependency.getVersionEvidence(), contents, blockVariable, "version", Confidence.HIGHEST); + String value = addStringEvidence(dependency.getVersionEvidence(), contents, blockVariable, "version", Confidence.HIGHEST); + if(value.length() < 1) + addEvidenceFromVersionFile(dependency.getActualFile(), dependency.getVersionEvidence()); } } @@ -158,4 +168,31 @@ public class RubyGemspecAnalyzer extends AbstractFileTypeAnalyzer { } return value; } + + private String addEvidenceFromVersionFile(File dependencyFile, EvidenceCollection versionEvidences) { + String value = null; + File parentDir = dependencyFile.getParentFile(); + if(parentDir != null) { + File[] matchingFiles = parentDir.listFiles(new FilenameFilter() { + public boolean accept(File dir, String name) { + return name.contains(VERSION_FILE_NAME); + } + }); + + for(int i = 0; i < matchingFiles.length; i++) { + try { + List lines = FileUtils.readLines(matchingFiles[i]); + if(lines.size() == 1) { //TODO other checking? + value = lines.get(0).trim(); + versionEvidences.addEvidence(GEMSPEC, "version", value, Confidence.HIGH); + } + + } catch (IOException e) { + e.printStackTrace(); + } + } + } + + return value; + } } diff --git a/dependency-check-core/src/test/java/org/owasp/dependencycheck/analyzer/RubyBundleAuditAnalyzerTest.java b/dependency-check-core/src/test/java/org/owasp/dependencycheck/analyzer/RubyBundleAuditAnalyzerTest.java index 8ef16ac40..0b3050e6c 100644 --- a/dependency-check-core/src/test/java/org/owasp/dependencycheck/analyzer/RubyBundleAuditAnalyzerTest.java +++ b/dependency-check-core/src/test/java/org/owasp/dependencycheck/analyzer/RubyBundleAuditAnalyzerTest.java @@ -22,6 +22,9 @@ import static org.junit.Assert.assertThat; import static org.junit.Assert.assertTrue; import java.io.File; +import java.util.Iterator; +import java.util.List; +import java.util.Set; import org.junit.After; import org.junit.Assume; @@ -32,6 +35,8 @@ import org.owasp.dependencycheck.Engine; import org.owasp.dependencycheck.analyzer.exception.AnalysisException; import org.owasp.dependencycheck.data.nvdcve.DatabaseException; import org.owasp.dependencycheck.dependency.Dependency; +import org.owasp.dependencycheck.dependency.Evidence; +import org.owasp.dependencycheck.dependency.Identifier; import org.owasp.dependencycheck.utils.Settings; import org.slf4j.Logger; import org.slf4j.LoggerFactory; @@ -99,17 +104,18 @@ public class RubyBundleAuditAnalyzerTest extends BaseTest { public void testAnalysis() throws AnalysisException, DatabaseException { try { analyzer.initialize(); - - final Dependency result = new Dependency(BaseTest.getResourceAsFile(this, - "ruby/vulnerable/gems/rails-4.1.15/Gemfile.lock")); + final String resource = "ruby/vulnerable/gems/rails-4.1.15/Gemfile.lock"; + final Dependency result = new Dependency(BaseTest.getResourceAsFile(this, resource)); final Engine engine = new Engine(); analyzer.analyze(result, engine); int size = engine.getDependencies().size(); - assertThat(size, is(1)); + assertTrue(size >= 1); Dependency dependency = engine.getDependencies().get(0); assertTrue(dependency.getProductEvidence().toString().toLowerCase().contains("redcarpet")); assertTrue(dependency.getVersionEvidence().toString().toLowerCase().contains("2.2.2")); + assertTrue(dependency.getFilePath().endsWith(resource)); + assertTrue(dependency.getFileName().equals("Gemfile.lock")); } catch (Exception e) { LOGGER.warn("Exception setting up RubyBundleAuditAnalyzer. Make sure Ruby gem bundle-audit is installed. You may also need to set property \"analyzer.bundle.audit.path\".", e); @@ -137,4 +143,55 @@ public class RubyBundleAuditAnalyzerTest extends BaseTest { LOGGER.info("phantom-bundle-audit is not available. Ruby Bundle Audit Analyzer is disabled as expected."); } } + + /** + * Test Ruby dependencies and their paths. + * + * @throws AnalysisException is thrown when an exception occurs. + */ + @Test + public void testDependenciesPath() throws AnalysisException, DatabaseException { + + final Engine engine = new Engine(); + engine.scan(BaseTest.getResourceAsFile(this, +// "ruby/vulnerable/gems/chef-12.8.4/")); + "ruby/vulnerable/gems/rails-4.1.15/")); +// "java")); + engine.analyzeDependencies(); + + List dependencies = engine.getDependencies(); + LOGGER.info(dependencies.size() + " dependencies found."); + Iterator dIterator = dependencies.iterator(); + while(dIterator.hasNext()) { + Dependency dept = dIterator.next(); + LOGGER.info("dept path: " + dept.getActualFilePath()); + + Set identifiers = dept.getIdentifiers(); + Iterator idIterator = identifiers.iterator(); + while(idIterator.hasNext()) { + Identifier id = idIterator.next(); + LOGGER.info(" Identifier: " + id.getValue() + ", type=" + id.getType() + ", url=" + id.getUrl() + ", conf="+ id.getConfidence()); + } + + Set prodEv = dept.getProductEvidence().getEvidence(); + Iterator it = prodEv.iterator(); + while(it.hasNext()) { + Evidence e = it.next(); + LOGGER.info(" prod: name=" + e.getName() + ", value=" + e.getValue() + ", source=" + e.getSource() + ", confidence=" + e.getConfidence()); + } + Set versionEv = dept.getVersionEvidence().getEvidence(); + Iterator vIt = versionEv.iterator(); + while(vIt.hasNext()) { + Evidence e = vIt.next(); + LOGGER.info(" version: name=" + e.getName() + ", value=" + e.getValue() + ", source=" + e.getSource() + ", confidence=" + e.getConfidence()); + } + + Set vendorEv = dept.getVendorEvidence().getEvidence(); + Iterator vendorIt = vendorEv.iterator(); + while(vendorIt.hasNext()) { + Evidence e = vendorIt.next(); + LOGGER.info(" vendor: name=" + e.getName() + ", value=" + e.getValue() + ", source=" + e.getSource() + ", confidence=" + e.getConfidence()); + } + } + } } diff --git a/dependency-check-core/src/test/java/org/owasp/dependencycheck/analyzer/RubyGemspecAnalyzerTest.java b/dependency-check-core/src/test/java/org/owasp/dependencycheck/analyzer/RubyGemspecAnalyzerTest.java index 23aabb135..6f4f7578b 100644 --- a/dependency-check-core/src/test/java/org/owasp/dependencycheck/analyzer/RubyGemspecAnalyzerTest.java +++ b/dependency-check-core/src/test/java/org/owasp/dependencycheck/analyzer/RubyGemspecAnalyzerTest.java @@ -79,7 +79,7 @@ public class RubyGemspecAnalyzerTest extends BaseTest { @Test public void testSupportsFiles() { assertThat(analyzer.accept(new File("test.gemspec")), is(true)); - assertThat(analyzer.accept(new File("Rakefile")), is(true)); +// assertThat(analyzer.accept(new File("Rakefile")), is(true)); } /** diff --git a/dependency-check-core/src/test/resources/dependencycheck.properties b/dependency-check-core/src/test/resources/dependencycheck.properties index e3862e8e7..8d4e7a035 100644 --- a/dependency-check-core/src/test/resources/dependencycheck.properties +++ b/dependency-check-core/src/test/resources/dependencycheck.properties @@ -101,4 +101,4 @@ analyzer.nexus.enabled=false analyzer.nexus.proxy=true #Use your own bundle-audit install directory. -#analyzer.bundle.audit.path=/usr/local/bin/bundle-audit +analyzer.bundle.audit.path=/usr/local/bin/bundle-audit