diff --git a/dependency-check-core/src/main/java/org/owasp/dependencycheck/analyzer/SolrAnalyzer.java b/dependency-check-core/src/main/java/org/owasp/dependencycheck/analyzer/CentralAnalyzer.java similarity index 82% rename from dependency-check-core/src/main/java/org/owasp/dependencycheck/analyzer/SolrAnalyzer.java rename to dependency-check-core/src/main/java/org/owasp/dependencycheck/analyzer/CentralAnalyzer.java index 82aee8d66..76744b675 100644 --- a/dependency-check-core/src/main/java/org/owasp/dependencycheck/analyzer/SolrAnalyzer.java +++ b/dependency-check-core/src/main/java/org/owasp/dependencycheck/analyzer/CentralAnalyzer.java @@ -3,7 +3,7 @@ package org.owasp.dependencycheck.analyzer; import org.owasp.dependencycheck.Engine; import org.owasp.dependencycheck.analyzer.exception.AnalysisException; import org.owasp.dependencycheck.data.nexus.MavenArtifact; -import org.owasp.dependencycheck.data.solr.SolrSearch; +import org.owasp.dependencycheck.data.central.CentralSearch; import org.owasp.dependencycheck.dependency.Confidence; import org.owasp.dependencycheck.dependency.Dependency; import org.owasp.dependencycheck.utils.InvalidSettingException; @@ -12,6 +12,7 @@ import org.owasp.dependencycheck.utils.Settings; import java.io.FileNotFoundException; import java.io.IOException; import java.net.URL; +import java.util.List; import java.util.Set; import java.util.logging.Level; import java.util.logging.Logger; @@ -19,11 +20,11 @@ import java.util.logging.Logger; /** * Created by colezlaw on 10/9/14. */ -public class SolrAnalyzer extends AbstractFileTypeAnalyzer { +public class CentralAnalyzer extends AbstractFileTypeAnalyzer { /** * The logger. */ - private static final Logger LOGGER = Logger.getLogger(SolrAnalyzer.class.getName()); + private static final Logger LOGGER = Logger.getLogger(CentralAnalyzer.class.getName()); /** * The name of the analyzer. @@ -49,7 +50,7 @@ public class SolrAnalyzer extends AbstractFileTypeAnalyzer { /** * The searcher itself. */ - private SolrSearch searcher; + private CentralSearch searcher; /** * Determine whether to enable this analyzer or not. @@ -91,7 +92,7 @@ public class SolrAnalyzer extends AbstractFileTypeAnalyzer { if (isEnabled()) { final String searchUrl = Settings.getString(Settings.KEYS.ANALYZER_SOLR_URL); LOGGER.fine(String.format("Solr Analyzer URL: %s", searchUrl)); - searcher = new SolrSearch(new URL(searchUrl)); + searcher = new CentralSearch(new URL(searchUrl)); } } @@ -143,20 +144,16 @@ public class SolrAnalyzer extends AbstractFileTypeAnalyzer { */ @Override public void analyzeFileType(Dependency dependency, Engine engine) throws AnalysisException { - if (errorFlag) { + if (errorFlag || !isEnabled()) { return; } try { - final MavenArtifact ma = searcher.searchSha1(dependency.getSha1sum()); - if (ma.getGroupId() != null && !"".equals(ma.getGroupId())) { - dependency.getVendorEvidence().addEvidence("solr", "groupid", ma.getGroupId(), Confidence.HIGH); - } - if (ma.getArtifactId() != null && !"".equals(ma.getArtifactId())) { - dependency.getProductEvidence().addEvidence("solr", "artifactid", ma.getArtifactId(), Confidence.HIGH); - } - if (ma.getVersion() != null && !"".equals(ma.getVersion())) { - dependency.getVersionEvidence().addEvidence("solr", "version", ma.getVersion(), Confidence.HIGH); + final List mas = searcher.searchSha1(dependency.getSha1sum()); + final Confidence confidence = mas.size() > 1 ? Confidence.HIGH : Confidence.HIGHEST; + for (MavenArtifact ma : mas) { + LOGGER.fine(String.format("Central analyzer found artifact (%s) for dependency (%s)", ma.toString(), dependency.getFileName())); + dependency.addAsEvidence("central", ma, confidence); } } catch (IllegalArgumentException iae) { LOGGER.info(String.format("invalid sha1-hash on %s", dependency.getFileName())); diff --git a/dependency-check-core/src/main/java/org/owasp/dependencycheck/analyzer/NexusAnalyzer.java b/dependency-check-core/src/main/java/org/owasp/dependencycheck/analyzer/NexusAnalyzer.java index abc546955..2d9d608e5 100644 --- a/dependency-check-core/src/main/java/org/owasp/dependencycheck/analyzer/NexusAnalyzer.java +++ b/dependency-check-core/src/main/java/org/owasp/dependencycheck/analyzer/NexusAnalyzer.java @@ -90,7 +90,7 @@ public class NexusAnalyzer extends AbstractFileTypeAnalyzer { public boolean isEnabled() { /* Enable this analyzer ONLY if the Nexus URL has been set to something other than the default one (if it's the default one, we'll use the - solr one) and it's enabled by the user. + central one) and it's enabled by the user. */ boolean retval = false; try { diff --git a/dependency-check-core/src/main/java/org/owasp/dependencycheck/data/solr/SolrSearch.java b/dependency-check-core/src/main/java/org/owasp/dependencycheck/data/central/CentralSearch.java similarity index 77% rename from dependency-check-core/src/main/java/org/owasp/dependencycheck/data/solr/SolrSearch.java rename to dependency-check-core/src/main/java/org/owasp/dependencycheck/data/central/CentralSearch.java index fdf1758b0..4c55e47a1 100644 --- a/dependency-check-core/src/main/java/org/owasp/dependencycheck/data/solr/SolrSearch.java +++ b/dependency-check-core/src/main/java/org/owasp/dependencycheck/data/central/CentralSearch.java @@ -1,19 +1,23 @@ -package org.owasp.dependencycheck.data.solr; +package org.owasp.dependencycheck.data.central; import org.owasp.dependencycheck.data.nexus.MavenArtifact; import org.owasp.dependencycheck.utils.InvalidSettingException; import org.owasp.dependencycheck.utils.Settings; import org.owasp.dependencycheck.utils.URLConnectionFactory; import org.w3c.dom.Document; +import org.w3c.dom.NodeList; import javax.xml.parsers.DocumentBuilder; import javax.xml.parsers.DocumentBuilderFactory; import javax.xml.xpath.XPath; +import javax.xml.xpath.XPathConstants; import javax.xml.xpath.XPathFactory; import java.io.FileNotFoundException; import java.io.IOException; import java.net.HttpURLConnection; import java.net.URL; +import java.util.ArrayList; +import java.util.List; import java.util.logging.Logger; /** @@ -21,7 +25,7 @@ import java.util.logging.Logger; * * @author colezlaw */ -public class SolrSearch { +public class CentralSearch { /** * The URL for the Solr service */ @@ -35,7 +39,7 @@ public class SolrSearch { /** * Used for logging. */ - private static final Logger LOGGER = Logger.getLogger(SolrSearch.class.getName()); + private static final Logger LOGGER = Logger.getLogger(CentralSearch.class.getName()); /** * Determines whether we'll continue using the analyzer. If there's some sort @@ -49,7 +53,7 @@ public class SolrSearch { * @param rootURL the URL of the repository on which searches should execute. * Only parameters are added to this (so it should end in /select) */ - public SolrSearch(URL rootURL) { + public CentralSearch(URL rootURL) { this.rootURL = rootURL; try { if (null != Settings.getString(Settings.KEYS.PROXY_SERVER) @@ -74,7 +78,7 @@ public class SolrSearch { * @throws IOException if it's unable to connect to the specified repository or if * the specified artifact is not found. */ - public MavenArtifact searchSha1(String sha1) throws IOException { + public List searchSha1(String sha1) throws IOException { if (null == sha1 || !sha1.matches("^[0-9A-Fa-f]{40}$")) { throw new IllegalArgumentException("Invalid SHA1 format"); } @@ -107,13 +111,19 @@ public class SolrSearch { if ("0".equals(numFound)) { missing = true; } else { - final String g = xpath.evaluate("/response/result/doc[1]/str[@name='g']", doc); - LOGGER.finest(String.format("GroupId: %s", g)); - final String a = xpath.evaluate("/response/result/doc[1]/str[@name='a']", doc); - LOGGER.finest(String.format("ArtifactId: %s", a)); - final String v = xpath.evaluate("/response/result/doc[1]/str[@name='v']", doc); - LOGGER.finest(String.format("Version: %s", v)); - return new MavenArtifact(g, a, v); + ArrayList result = new ArrayList(); + NodeList docs = (NodeList)xpath.evaluate("/response/result/doc", doc, XPathConstants.NODESET); + for (int i = 0; i < docs.getLength(); i++) { + final String g = xpath.evaluate("./str[@name='g']", docs.item(i)); + LOGGER.finest(String.format("GroupId: %s", g)); + final String a = xpath.evaluate("./str[@name='a']", docs.item(i)); + LOGGER.finest(String.format("ArtifactId: %s", a)); + final String v = xpath.evaluate("./str[@name='v']", docs.item(i)); + LOGGER.finest(String.format("Version: %s", v)); + result.add(new MavenArtifact(g, a, v, url.toString())); + } + + return result; } } catch (Throwable e) { // Anything else is jacked up XML stuff that we really can't recover diff --git a/dependency-check-core/src/main/java/org/owasp/dependencycheck/dependency/Dependency.java b/dependency-check-core/src/main/java/org/owasp/dependencycheck/dependency/Dependency.java index ef1117148..2f72b3d84 100644 --- a/dependency-check-core/src/main/java/org/owasp/dependencycheck/dependency/Dependency.java +++ b/dependency-check-core/src/main/java/org/owasp/dependencycheck/dependency/Dependency.java @@ -341,10 +341,12 @@ public class Dependency implements Serializable, Comparable { found = true; i.setConfidence(Confidence.HIGHEST); i.setUrl(mavenArtifact.getArtifactUrl()); + LOGGER.fine(String.format("Already found identifier %s. Confidence set to highest", i.getValue())); break; } } if (!found) { + LOGGER.fine(String.format("Adding new maven identifier %s", mavenArtifact.toString())); this.addIdentifier("maven", mavenArtifact.toString(), mavenArtifact.getArtifactUrl(), Confidence.HIGHEST); } } diff --git a/dependency-check-core/src/main/resources/META-INF/services/org.owasp.dependencycheck.analyzer.Analyzer b/dependency-check-core/src/main/resources/META-INF/services/org.owasp.dependencycheck.analyzer.Analyzer index f98b34e8a..f2c4509c0 100644 --- a/dependency-check-core/src/main/resources/META-INF/services/org.owasp.dependencycheck.analyzer.Analyzer +++ b/dependency-check-core/src/main/resources/META-INF/services/org.owasp.dependencycheck.analyzer.Analyzer @@ -8,7 +8,7 @@ org.owasp.dependencycheck.analyzer.CpeSuppressionAnalyzer org.owasp.dependencycheck.analyzer.DependencyBundlingAnalyzer org.owasp.dependencycheck.analyzer.NvdCveAnalyzer org.owasp.dependencycheck.analyzer.VulnerabilitySuppressionAnalyzer -org.owasp.dependencycheck.analyzer.SolrAnalyzer +org.owasp.dependencycheck.analyzer.CentralAnalyzer org.owasp.dependencycheck.analyzer.NexusAnalyzer org.owasp.dependencycheck.analyzer.NuspecAnalyzer org.owasp.dependencycheck.analyzer.AssemblyAnalyzer \ No newline at end of file diff --git a/dependency-check-core/src/test/java/org/owasp/dependencycheck/data/solr/SolrSearchTest.java b/dependency-check-core/src/test/java/org/owasp/dependencycheck/data/central/CentralSearchTest.java similarity index 64% rename from dependency-check-core/src/test/java/org/owasp/dependencycheck/data/solr/SolrSearchTest.java rename to dependency-check-core/src/test/java/org/owasp/dependencycheck/data/central/CentralSearchTest.java index 937a6d849..ffcde235e 100644 --- a/dependency-check-core/src/test/java/org/owasp/dependencycheck/data/solr/SolrSearchTest.java +++ b/dependency-check-core/src/test/java/org/owasp/dependencycheck/data/central/CentralSearchTest.java @@ -1,6 +1,5 @@ -package org.owasp.dependencycheck.data.solr; +package org.owasp.dependencycheck.data.central; -import org.junit.Assume; import org.junit.Before; import org.junit.Test; import org.owasp.dependencycheck.BaseTest; @@ -9,23 +8,23 @@ import org.owasp.dependencycheck.utils.Settings; import java.io.FileNotFoundException; import java.net.URL; +import java.util.List; import java.util.logging.Logger; -import static org.junit.Assert.assertEquals; -import static org.junit.Assert.assertNotNull; +import static org.junit.Assert.*; /** * Created by colezlaw on 10/13/14. */ -public class SolrSearchTest extends BaseTest { - private static final Logger LOGGER = Logger.getLogger(SolrSearchTest.class.getName()); - private SolrSearch searcher; +public class CentralSearchTest extends BaseTest { + private static final Logger LOGGER = Logger.getLogger(CentralSearchTest.class.getName()); + private CentralSearch searcher; @Before public void setUp() throws Exception { String solrUrl = Settings.getString(Settings.KEYS.ANALYZER_SOLR_URL); LOGGER.fine(solrUrl); - searcher = new SolrSearch(new URL(solrUrl)); + searcher = new CentralSearch(new URL(solrUrl)); } @Test(expected = IllegalArgumentException.class) @@ -41,10 +40,10 @@ public class SolrSearchTest extends BaseTest { // test it anyway @Test public void testValidSha1() throws Exception { - MavenArtifact ma = searcher.searchSha1("9977a8d04e75609cf01badc4eb6a9c7198c4c5ea"); - assertEquals("Incorrect group", "org.apache.maven.plugins", ma.getGroupId()); - assertEquals("Incorrect artifact", "maven-compiler-plugin", ma.getArtifactId()); - assertEquals("Incorrect version", "3.1", ma.getVersion()); + List ma = searcher.searchSha1("9977a8d04e75609cf01badc4eb6a9c7198c4c5ea"); + assertEquals("Incorrect group", "org.apache.maven.plugins", ma.get(0).getGroupId()); + assertEquals("Incorrect artifact", "maven-compiler-plugin", ma.get(0).getArtifactId()); + assertEquals("Incorrect version", "3.1", ma.get(0).getVersion()); } // This test does generate network traffic and communicates with a host @@ -54,4 +53,11 @@ public class SolrSearchTest extends BaseTest { public void testMissingSha1() throws Exception { searcher.searchSha1("AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA"); } + + // This test should give us multiple results back from Solr + @Test + public void testMultipleReturns() throws Exception { + List ma = searcher.searchSha1("94A9CE681A42D0352B3AD22659F67835E560D107"); + assertTrue(ma.size() > 1); + } }