diff --git a/dependency-check-core/src/main/java/org/owasp/dependencycheck/data/nexus/MavenArtifact.java b/dependency-check-core/src/main/java/org/owasp/dependencycheck/data/nexus/MavenArtifact.java new file mode 100644 index 000000000..943374088 --- /dev/null +++ b/dependency-check-core/src/main/java/org/owasp/dependencycheck/data/nexus/MavenArtifact.java @@ -0,0 +1,154 @@ +/* + * This file is part of dependency-check-core. + * + * Dependency-check-core is free software: you can redistribute it and/or modify it + * under the terms of the GNU General Public License as published by the Free + * Software Foundation, either version 3 of the License, or (at your option) any + * later version. + * + * Dependency-check-core is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more + * details. + * + * You should have received a copy of the GNU General Public License along with + * dependency-check-core. If not, see http://www.gnu.org/licenses/. + * + * Copyright (c) 2012 Jeremy Long. All Rights Reserved. + */ +package org.owasp.dependencycheck.data.nexus; + +/** + * Simple bean representing a Maven Artifact. + * + * @author colezlaw + */ +public class MavenArtifact { + /** + * The groupId + */ + private String groupId; + + /** + * The artifactId + */ + private String artifactId; + + /** + * The version + */ + private String version; + + /** + * The artifact url. This may change depending on which Nexus + * server the search took place. + */ + private String artifactUrl; + + + /** + * Creates an empty MavenArtifact. + */ + public MavenArtifact() { + } + + /** + * Creates a MavenArtifact with the given attributes. + * + * @param groupId the groupId + * @param artifactId the artifactId + * @param version the version + */ + public MavenArtifact(String groupId, String artifactId, String version) { + setGroupId(groupId); + setArtifactId(artifactId); + setVersion(version); + } + + /** + * Creates a MavenArtifact with the given attributes. + * + * @param groupId the groupId + * @param artifactId the artifactId + * @param version the version + * @param url the artifactLink url + */ + public MavenArtifact(String groupId, String artifactId, String version, String url) { + setGroupId(groupId); + setArtifactId(artifactId); + setVersion(version); + setArtifactUrl(url); + } + + /** + * Returns the Artifact coordinates as a String. + * + * @return the String representation of the artifact coordinates + */ + @Override + public String toString() { + return String.format("%s:%s:%s", groupId, artifactId, version); + } + + /** + * Sets the groupId. + * + * @param groupId the groupId + */ + public void setGroupId(String groupId) { this.groupId = groupId; } + + /** + * Gets the groupId. + * + * @return the groupId + */ + public String getGroupId() { return groupId; } + + /** + * Sets the artifactId. + * + * @param artifactId the artifactId + */ + public void setArtifactId(String artifactId) { this.artifactId = artifactId; } + + /** + * Gets the artifactId. + * + * @return the artifactId + */ + public String getArtifactId() { return artifactId; } + + /** + * Sets the version. + * + * @param version the version + */ + public void setVersion(String version) { this.version = version; } + + /** + * Gets the version. + * + * @return the version + */ + public String getVersion() { return version; } + + /** + * Sets the artifactUrl. + * + * @param artifactUrl the artifactUrl + */ + public void setArtifactUrl(String artifactUrl) { + this.artifactUrl = artifactUrl; + } + + /** + * Gets the artifactUrl. + * + * @return the artifactUrl + */ + public String getArtifactUrl() { + return artifactUrl; + } +} + +// vim: cc=120:sw=4:ts=4:sts=4 diff --git a/dependency-check-core/src/main/java/org/owasp/dependencycheck/data/nexus/NexusSearch.java b/dependency-check-core/src/main/java/org/owasp/dependencycheck/data/nexus/NexusSearch.java new file mode 100644 index 000000000..d8db3392d --- /dev/null +++ b/dependency-check-core/src/main/java/org/owasp/dependencycheck/data/nexus/NexusSearch.java @@ -0,0 +1,105 @@ +/* + * This file is part of dependency-check-core. + * + * Dependency-check-core is free software: you can redistribute it and/or modify it + * under the terms of the GNU General Public License as published by the Free + * Software Foundation, either version 3 of the License, or (at your option) any + * later version. + * + * Dependency-check-core is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more + * details. + * + * You should have received a copy of the GNU General Public License along with + * dependency-check-core. If not, see http://www.gnu.org/licenses/. + * + * Copyright (c) 2012 Jeremy Long. All Rights Reserved. + */ +package org.owasp.dependencycheck.data.nexus; + +import java.io.FileNotFoundException; +import java.io.IOException; +import java.net.URL; +import java.net.URLConnection; +import java.util.logging.Logger; +import javax.xml.parsers.DocumentBuilder; +import javax.xml.parsers.DocumentBuilderFactory; +import javax.xml.xpath.XPath; +import javax.xml.xpath.XPathFactory; +import org.w3c.dom.Document; + +/** + * Class of methods to search Nexus repositories. + * + * @author colezlaw + */ +public class NexusSearch { + /** + * The root URL for the Nexus repository service + */ + private final URL rootURL; + + /** + * Used for logging. + */ + private static final Logger LOGGER = Logger.getLogger(NexusSearch.class.getName()); + + /** + * Creates a NexusSearch for the given repository URL. + * + * @param rootURL the root URL of the repository on which searches should execute. + * full URL's are calculated relative to this URL, so it should end with a / + */ + public NexusSearch(URL rootURL) { + this.rootURL = rootURL; + } + + /** + * Searches the configured Nexus repository for the given sha1 + * hash. If the artifact is found, a MavenArtifact is populated + * with the coordinate information. + * + * @param sha1 The SHA-1 hash string for which to search + * @return the populated Maven coordinates + * @throws IOException if it's unable to connect to the specified repositor or + * if the specified artifact is not found. + */ + public MavenArtifact searchSha1(String sha1) throws IOException { + if (null == sha1 || !sha1.matches("^[0-9A-Fa-f]{40}$")) { + throw new IllegalArgumentException("Invalid SHA1 format"); + } + + final URL url = new URL(rootURL, String.format("identify/sha1/%s", sha1.toLowerCase())); + + LOGGER.fine(String.format("Searching Nexus url %s", url.toString())); + + final URLConnection conn = url.openConnection(); + conn.setDoOutput(true); + + // JSON would be more elegant, but there's not currently a dependency + // on JSON, so don't want to add one just for this + conn.addRequestProperty("Accept", "application/xml"); + conn.connect(); + + try { + final DocumentBuilder builder = DocumentBuilderFactory.newInstance().newDocumentBuilder(); + final Document doc = builder.parse(conn.getInputStream()); + final XPath xpath = XPathFactory.newInstance().newXPath(); + final String groupId = xpath.evaluate("/org.sonatype.nexus.rest.model.NexusArtifact/groupId", doc); + final String artifactId = xpath.evaluate("/org.sonatype.nexus.rest.model.NexusArtifact/artifactId", doc); + final String version = xpath.evaluate("/org.sonatype.nexus.rest.model.NexusArtifact/version", doc); + final String link = xpath.evaluate("/org.sonatype.nexus.rest.model.NexusArtifact/artifactLink", doc); + return new MavenArtifact(groupId, artifactId, version, link); + } catch (FileNotFoundException fnfe) { + // This is what we get when the SHA1 they sent doesn't exist in Nexus. This + // is useful upstream for recovery, so we just re-throw it + throw fnfe; + } catch (Exception e) { + // Anything else is jacked-up XML stuff that we really can't recover from well + throw new IOException(e.getMessage(), e); + } + } +} + +// vim: cc=120:sw=4:ts=4:sts=4 diff --git a/dependency-check-core/src/main/java/org/owasp/dependencycheck/data/nexus/package-info.java b/dependency-check-core/src/main/java/org/owasp/dependencycheck/data/nexus/package-info.java new file mode 100644 index 000000000..33f810a3a --- /dev/null +++ b/dependency-check-core/src/main/java/org/owasp/dependencycheck/data/nexus/package-info.java @@ -0,0 +1,12 @@ +/** + * + * + * org.owasp.dependencycheck.data.nexus + * + * + *

Contains classes related to searching a Nexus repository.

+ *

These are used to abstract Nexus searching away from + * OWASP Dependency Check so they can be reused elsewhere.

+ * + * + */ 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 26e4c2427..0ed6a16cb 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 @@ -7,4 +7,5 @@ org.owasp.dependencycheck.analyzer.FalsePositiveAnalyzer org.owasp.dependencycheck.analyzer.CpeSuppressionAnalyzer org.owasp.dependencycheck.analyzer.DependencyBundlingAnalyzer org.owasp.dependencycheck.analyzer.NvdCveAnalyzer -org.owasp.dependencycheck.analyzer.VulnerabilitySuppressionAnalyzer \ No newline at end of file +org.owasp.dependencycheck.analyzer.VulnerabilitySuppressionAnalyzer +org.owasp.dependencycheck.analyzer.NexusAnalyzer diff --git a/dependency-check-core/src/main/resources/dependencycheck.properties b/dependency-check-core/src/main/resources/dependencycheck.properties index 73629aa2b..3dbea7bed 100644 --- a/dependency-check-core/src/main/resources/dependencycheck.properties +++ b/dependency-check-core/src/main/resources/dependencycheck.properties @@ -46,3 +46,8 @@ cve.url-2.0.modified=http://static.nvd.nist.gov/feeds/xml/cve/nvdcve-2.0-modifie cve.startyear=2002 cve.url-2.0.base=http://static.nvd.nist.gov/feeds/xml/cve/nvdcve-2.0-%d.xml cve.url-1.2.base=http://nvd.nist.gov/download/nvdcve-%d.xml + +# the URL for searching Nexus for SHA-1 hashes and whether it's enabled +analyzer.nexus.enabled=true +analyzer.nexus.url=http://repository.sonatype.org/service/local/ + diff --git a/dependency-check-core/src/test/resources/dependencycheck.properties b/dependency-check-core/src/test/resources/dependencycheck.properties index 89d1279b7..37e5291dd 100644 --- a/dependency-check-core/src/test/resources/dependencycheck.properties +++ b/dependency-check-core/src/test/resources/dependencycheck.properties @@ -46,3 +46,7 @@ cve.url-2.0.modified=http://static.nvd.nist.gov/feeds/xml/cve/nvdcve-2.0-modifie cve.startyear=2013 cve.url-2.0.base=http://static.nvd.nist.gov/feeds/xml/cve/nvdcve-2.0-%d.xml cve.url-1.2.base=http://nvd.nist.gov/download/nvdcve-%d.xml + +# the URL for searching Nexus for SHA-1 hashes and whether it's enabled +analyzer.nexus.enabled=false +analyzer.nexus.url=http://repository.sonatype.org/service/local/